162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2013 Intel Corporation. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * This file contains all of the code that is specific to the SerDes 3662306a36Sopenharmony_ci * on the QLogic_IB 7220 chip. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <linux/pci.h> 4062306a36Sopenharmony_ci#include <linux/delay.h> 4162306a36Sopenharmony_ci#include <linux/module.h> 4262306a36Sopenharmony_ci#include <linux/firmware.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include "qib.h" 4562306a36Sopenharmony_ci#include "qib_7220.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define SD7220_FW_NAME "qlogic/sd7220.fw" 4862306a36Sopenharmony_ciMODULE_FIRMWARE(SD7220_FW_NAME); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * Same as in qib_iba7220.c, but just the registers needed here. 5262306a36Sopenharmony_ci * Could move whole set to qib_7220.h, but decided better to keep 5362306a36Sopenharmony_ci * local. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci#define KREG_IDX(regname) (QIB_7220_##regname##_OFFS / sizeof(u64)) 5662306a36Sopenharmony_ci#define kr_hwerrclear KREG_IDX(HwErrClear) 5762306a36Sopenharmony_ci#define kr_hwerrmask KREG_IDX(HwErrMask) 5862306a36Sopenharmony_ci#define kr_hwerrstatus KREG_IDX(HwErrStatus) 5962306a36Sopenharmony_ci#define kr_ibcstatus KREG_IDX(IBCStatus) 6062306a36Sopenharmony_ci#define kr_ibserdesctrl KREG_IDX(IBSerDesCtrl) 6162306a36Sopenharmony_ci#define kr_scratch KREG_IDX(Scratch) 6262306a36Sopenharmony_ci#define kr_xgxs_cfg KREG_IDX(XGXSCfg) 6362306a36Sopenharmony_ci/* these are used only here, not in qib_iba7220.c */ 6462306a36Sopenharmony_ci#define kr_ibsd_epb_access_ctrl KREG_IDX(ibsd_epb_access_ctrl) 6562306a36Sopenharmony_ci#define kr_ibsd_epb_transaction_reg KREG_IDX(ibsd_epb_transaction_reg) 6662306a36Sopenharmony_ci#define kr_pciesd_epb_transaction_reg KREG_IDX(pciesd_epb_transaction_reg) 6762306a36Sopenharmony_ci#define kr_pciesd_epb_access_ctrl KREG_IDX(pciesd_epb_access_ctrl) 6862306a36Sopenharmony_ci#define kr_serdes_ddsrxeq0 KREG_IDX(SerDes_DDSRXEQ0) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * The IBSerDesMappTable is a memory that holds values to be stored in 7262306a36Sopenharmony_ci * various SerDes registers by IBC. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci#define kr_serdes_maptable KREG_IDX(IBSerDesMappTable) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * Below used for sdnum parameter, selecting one of the two sections 7862306a36Sopenharmony_ci * used for PCIe, or the single SerDes used for IB. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci#define PCIE_SERDES0 0 8162306a36Sopenharmony_ci#define PCIE_SERDES1 1 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * The EPB requires addressing in a particular form. EPB_LOC() is intended 8562306a36Sopenharmony_ci * to make #definitions a little more readable. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci#define EPB_ADDR_SHF 8 8862306a36Sopenharmony_ci#define EPB_LOC(chn, elt, reg) \ 8962306a36Sopenharmony_ci (((elt & 0xf) | ((chn & 7) << 4) | ((reg & 0x3f) << 9)) << \ 9062306a36Sopenharmony_ci EPB_ADDR_SHF) 9162306a36Sopenharmony_ci#define EPB_IB_QUAD0_CS_SHF (25) 9262306a36Sopenharmony_ci#define EPB_IB_QUAD0_CS (1U << EPB_IB_QUAD0_CS_SHF) 9362306a36Sopenharmony_ci#define EPB_IB_UC_CS_SHF (26) 9462306a36Sopenharmony_ci#define EPB_PCIE_UC_CS_SHF (27) 9562306a36Sopenharmony_ci#define EPB_GLOBAL_WR (1U << (EPB_ADDR_SHF + 8)) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* Forward declarations. */ 9862306a36Sopenharmony_cistatic int qib_sd7220_reg_mod(struct qib_devdata *dd, int sdnum, u32 loc, 9962306a36Sopenharmony_ci u32 data, u32 mask); 10062306a36Sopenharmony_cistatic int ibsd_mod_allchnls(struct qib_devdata *dd, int loc, int val, 10162306a36Sopenharmony_ci int mask); 10262306a36Sopenharmony_cistatic int qib_sd_trimdone_poll(struct qib_devdata *dd); 10362306a36Sopenharmony_cistatic void qib_sd_trimdone_monitor(struct qib_devdata *dd, const char *where); 10462306a36Sopenharmony_cistatic int qib_sd_setvals(struct qib_devdata *dd); 10562306a36Sopenharmony_cistatic int qib_sd_early(struct qib_devdata *dd); 10662306a36Sopenharmony_cistatic int qib_sd_dactrim(struct qib_devdata *dd); 10762306a36Sopenharmony_cistatic int qib_internal_presets(struct qib_devdata *dd); 10862306a36Sopenharmony_ci/* Tweak the register (CMUCTRL5) that contains the TRIMSELF controls */ 10962306a36Sopenharmony_cistatic int qib_sd_trimself(struct qib_devdata *dd, int val); 11062306a36Sopenharmony_cistatic int epb_access(struct qib_devdata *dd, int sdnum, int claim); 11162306a36Sopenharmony_cistatic int qib_sd7220_ib_load(struct qib_devdata *dd, 11262306a36Sopenharmony_ci const struct firmware *fw); 11362306a36Sopenharmony_cistatic int qib_sd7220_ib_vfy(struct qib_devdata *dd, 11462306a36Sopenharmony_ci const struct firmware *fw); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* 11762306a36Sopenharmony_ci * Below keeps track of whether the "once per power-on" initialization has 11862306a36Sopenharmony_ci * been done, because uC code Version 1.32.17 or higher allows the uC to 11962306a36Sopenharmony_ci * be reset at will, and Automatic Equalization may require it. So the 12062306a36Sopenharmony_ci * state of the reset "pin", is no longer valid. Instead, we check for the 12162306a36Sopenharmony_ci * actual uC code having been loaded. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_cistatic int qib_ibsd_ucode_loaded(struct qib_pportdata *ppd, 12462306a36Sopenharmony_ci const struct firmware *fw) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct qib_devdata *dd = ppd->dd; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (!dd->cspec->serdes_first_init_done && 12962306a36Sopenharmony_ci qib_sd7220_ib_vfy(dd, fw) > 0) 13062306a36Sopenharmony_ci dd->cspec->serdes_first_init_done = 1; 13162306a36Sopenharmony_ci return dd->cspec->serdes_first_init_done; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* repeat #define for local use. "Real" #define is in qib_iba7220.c */ 13562306a36Sopenharmony_ci#define QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR 0x0000004000000000ULL 13662306a36Sopenharmony_ci#define IB_MPREG5 (EPB_LOC(6, 0, 0xE) | (1L << EPB_IB_UC_CS_SHF)) 13762306a36Sopenharmony_ci#define IB_MPREG6 (EPB_LOC(6, 0, 0xF) | (1U << EPB_IB_UC_CS_SHF)) 13862306a36Sopenharmony_ci#define UC_PAR_CLR_D 8 13962306a36Sopenharmony_ci#define UC_PAR_CLR_M 0xC 14062306a36Sopenharmony_ci#define IB_CTRL2(chn) (EPB_LOC(chn, 7, 3) | EPB_IB_QUAD0_CS) 14162306a36Sopenharmony_ci#define START_EQ1(chan) EPB_LOC(chan, 7, 0x27) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_civoid qib_sd7220_clr_ibpar(struct qib_devdata *dd) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci int ret; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* clear, then re-enable parity errs */ 14862306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 14962306a36Sopenharmony_ci UC_PAR_CLR_D, UC_PAR_CLR_M); 15062306a36Sopenharmony_ci if (ret < 0) { 15162306a36Sopenharmony_ci qib_dev_err(dd, "Failed clearing IBSerDes Parity err\n"); 15262306a36Sopenharmony_ci goto bail; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0, 15562306a36Sopenharmony_ci UC_PAR_CLR_M); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 15862306a36Sopenharmony_ci udelay(4); 15962306a36Sopenharmony_ci qib_write_kreg(dd, kr_hwerrclear, 16062306a36Sopenharmony_ci QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); 16162306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 16262306a36Sopenharmony_cibail: 16362306a36Sopenharmony_ci return; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * After a reset or other unusual event, the epb interface may need 16862306a36Sopenharmony_ci * to be re-synchronized, between the host and the uC. 16962306a36Sopenharmony_ci * returns <0 for failure to resync within IBSD_RESYNC_TRIES (not expected) 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci#define IBSD_RESYNC_TRIES 3 17262306a36Sopenharmony_ci#define IB_PGUDP(chn) (EPB_LOC((chn), 2, 1) | EPB_IB_QUAD0_CS) 17362306a36Sopenharmony_ci#define IB_CMUDONE(chn) (EPB_LOC((chn), 7, 0xF) | EPB_IB_QUAD0_CS) 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int qib_resync_ibepb(struct qib_devdata *dd) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci int ret, pat, tries, chn; 17862306a36Sopenharmony_ci u32 loc; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = -1; 18162306a36Sopenharmony_ci chn = 0; 18262306a36Sopenharmony_ci for (tries = 0; tries < (4 * IBSD_RESYNC_TRIES); ++tries) { 18362306a36Sopenharmony_ci loc = IB_PGUDP(chn); 18462306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0); 18562306a36Sopenharmony_ci if (ret < 0) { 18662306a36Sopenharmony_ci qib_dev_err(dd, "Failed read in resync\n"); 18762306a36Sopenharmony_ci continue; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci if (ret != 0xF0 && ret != 0x55 && tries == 0) 19062306a36Sopenharmony_ci qib_dev_err(dd, "unexpected pattern in resync\n"); 19162306a36Sopenharmony_ci pat = ret ^ 0xA5; /* alternate F0 and 55 */ 19262306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, pat, 0xFF); 19362306a36Sopenharmony_ci if (ret < 0) { 19462306a36Sopenharmony_ci qib_dev_err(dd, "Failed write in resync\n"); 19562306a36Sopenharmony_ci continue; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0); 19862306a36Sopenharmony_ci if (ret < 0) { 19962306a36Sopenharmony_ci qib_dev_err(dd, "Failed re-read in resync\n"); 20062306a36Sopenharmony_ci continue; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci if (ret != pat) { 20362306a36Sopenharmony_ci qib_dev_err(dd, "Failed compare1 in resync\n"); 20462306a36Sopenharmony_ci continue; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci loc = IB_CMUDONE(chn); 20762306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, 0, 0); 20862306a36Sopenharmony_ci if (ret < 0) { 20962306a36Sopenharmony_ci qib_dev_err(dd, "Failed CMUDONE rd in resync\n"); 21062306a36Sopenharmony_ci continue; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci if ((ret & 0x70) != ((chn << 4) | 0x40)) { 21362306a36Sopenharmony_ci qib_dev_err(dd, "Bad CMUDONE value %02X, chn %d\n", 21462306a36Sopenharmony_ci ret, chn); 21562306a36Sopenharmony_ci continue; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci if (++chn == 4) 21862306a36Sopenharmony_ci break; /* Success */ 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci return (ret > 0) ? 0 : ret; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* 22462306a36Sopenharmony_ci * Localize the stuff that should be done to change IB uC reset 22562306a36Sopenharmony_ci * returns <0 for errors. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_cistatic int qib_ibsd_reset(struct qib_devdata *dd, int assert_rst) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci u64 rst_val; 23062306a36Sopenharmony_ci int ret = 0; 23162306a36Sopenharmony_ci unsigned long flags; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci rst_val = qib_read_kreg64(dd, kr_ibserdesctrl); 23462306a36Sopenharmony_ci if (assert_rst) { 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * Vendor recommends "interrupting" uC before reset, to 23762306a36Sopenharmony_ci * minimize possible glitches. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci spin_lock_irqsave(&dd->cspec->sdepb_lock, flags); 24062306a36Sopenharmony_ci epb_access(dd, IB_7220_SERDES, 1); 24162306a36Sopenharmony_ci rst_val |= 1ULL; 24262306a36Sopenharmony_ci /* Squelch possible parity error from _asserting_ reset */ 24362306a36Sopenharmony_ci qib_write_kreg(dd, kr_hwerrmask, 24462306a36Sopenharmony_ci dd->cspec->hwerrmask & 24562306a36Sopenharmony_ci ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); 24662306a36Sopenharmony_ci qib_write_kreg(dd, kr_ibserdesctrl, rst_val); 24762306a36Sopenharmony_ci /* flush write, delay to ensure it took effect */ 24862306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 24962306a36Sopenharmony_ci udelay(2); 25062306a36Sopenharmony_ci /* once it's reset, can remove interrupt */ 25162306a36Sopenharmony_ci epb_access(dd, IB_7220_SERDES, -1); 25262306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags); 25362306a36Sopenharmony_ci } else { 25462306a36Sopenharmony_ci /* 25562306a36Sopenharmony_ci * Before we de-assert reset, we need to deal with 25662306a36Sopenharmony_ci * possible glitch on the Parity-error line. 25762306a36Sopenharmony_ci * Suppress it around the reset, both in chip-level 25862306a36Sopenharmony_ci * hwerrmask and in IB uC control reg. uC will allow 25962306a36Sopenharmony_ci * it again during startup. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci u64 val; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci rst_val &= ~(1ULL); 26462306a36Sopenharmony_ci qib_write_kreg(dd, kr_hwerrmask, 26562306a36Sopenharmony_ci dd->cspec->hwerrmask & 26662306a36Sopenharmony_ci ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci ret = qib_resync_ibepb(dd); 26962306a36Sopenharmony_ci if (ret < 0) 27062306a36Sopenharmony_ci qib_dev_err(dd, "unable to re-sync IB EPB\n"); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* set uC control regs to suppress parity errs */ 27362306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG5, 1, 1); 27462306a36Sopenharmony_ci if (ret < 0) 27562306a36Sopenharmony_ci goto bail; 27662306a36Sopenharmony_ci /* IB uC code past Version 1.32.17 allow suppression of wdog */ 27762306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80, 27862306a36Sopenharmony_ci 0x80); 27962306a36Sopenharmony_ci if (ret < 0) { 28062306a36Sopenharmony_ci qib_dev_err(dd, "Failed to set WDOG disable\n"); 28162306a36Sopenharmony_ci goto bail; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci qib_write_kreg(dd, kr_ibserdesctrl, rst_val); 28462306a36Sopenharmony_ci /* flush write, delay for startup */ 28562306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 28662306a36Sopenharmony_ci udelay(1); 28762306a36Sopenharmony_ci /* clear, then re-enable parity errs */ 28862306a36Sopenharmony_ci qib_sd7220_clr_ibpar(dd); 28962306a36Sopenharmony_ci val = qib_read_kreg64(dd, kr_hwerrstatus); 29062306a36Sopenharmony_ci if (val & QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR) { 29162306a36Sopenharmony_ci qib_dev_err(dd, "IBUC Parity still set after RST\n"); 29262306a36Sopenharmony_ci dd->cspec->hwerrmask &= 29362306a36Sopenharmony_ci ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci qib_write_kreg(dd, kr_hwerrmask, 29662306a36Sopenharmony_ci dd->cspec->hwerrmask); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cibail: 30062306a36Sopenharmony_ci return ret; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void qib_sd_trimdone_monitor(struct qib_devdata *dd, 30462306a36Sopenharmony_ci const char *where) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci int ret, chn, baduns; 30762306a36Sopenharmony_ci u64 val; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (!where) 31062306a36Sopenharmony_ci where = "?"; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* give time for reset to settle out in EPB */ 31362306a36Sopenharmony_ci udelay(2); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci ret = qib_resync_ibepb(dd); 31662306a36Sopenharmony_ci if (ret < 0) 31762306a36Sopenharmony_ci qib_dev_err(dd, "not able to re-sync IB EPB (%s)\n", where); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Do "sacrificial read" to get EPB in sane state after reset */ 32062306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_CTRL2(0), 0, 0); 32162306a36Sopenharmony_ci if (ret < 0) 32262306a36Sopenharmony_ci qib_dev_err(dd, "Failed TRIMDONE 1st read, (%s)\n", where); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Check/show "summary" Trim-done bit in IBCStatus */ 32562306a36Sopenharmony_ci val = qib_read_kreg64(dd, kr_ibcstatus); 32662306a36Sopenharmony_ci if (!(val & (1ULL << 11))) 32762306a36Sopenharmony_ci qib_dev_err(dd, "IBCS TRIMDONE clear (%s)\n", where); 32862306a36Sopenharmony_ci /* 32962306a36Sopenharmony_ci * Do "dummy read/mod/wr" to get EPB in sane state after reset 33062306a36Sopenharmony_ci * The default value for MPREG6 is 0. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci udelay(2); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80, 0x80); 33562306a36Sopenharmony_ci if (ret < 0) 33662306a36Sopenharmony_ci qib_dev_err(dd, "Failed Dummy RMW, (%s)\n", where); 33762306a36Sopenharmony_ci udelay(10); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci baduns = 0; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci for (chn = 3; chn >= 0; --chn) { 34262306a36Sopenharmony_ci /* Read CTRL reg for each channel to check TRIMDONE */ 34362306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, 34462306a36Sopenharmony_ci IB_CTRL2(chn), 0, 0); 34562306a36Sopenharmony_ci if (ret < 0) 34662306a36Sopenharmony_ci qib_dev_err(dd, 34762306a36Sopenharmony_ci "Failed checking TRIMDONE, chn %d (%s)\n", 34862306a36Sopenharmony_ci chn, where); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (!(ret & 0x10)) { 35162306a36Sopenharmony_ci int probe; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci baduns |= (1 << chn); 35462306a36Sopenharmony_ci qib_dev_err(dd, 35562306a36Sopenharmony_ci "TRIMDONE cleared on chn %d (%02X). (%s)\n", 35662306a36Sopenharmony_ci chn, ret, where); 35762306a36Sopenharmony_ci probe = qib_sd7220_reg_mod(dd, IB_7220_SERDES, 35862306a36Sopenharmony_ci IB_PGUDP(0), 0, 0); 35962306a36Sopenharmony_ci qib_dev_err(dd, "probe is %d (%02X)\n", 36062306a36Sopenharmony_ci probe, probe); 36162306a36Sopenharmony_ci probe = qib_sd7220_reg_mod(dd, IB_7220_SERDES, 36262306a36Sopenharmony_ci IB_CTRL2(chn), 0, 0); 36362306a36Sopenharmony_ci qib_dev_err(dd, "re-read: %d (%02X)\n", 36462306a36Sopenharmony_ci probe, probe); 36562306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, 36662306a36Sopenharmony_ci IB_CTRL2(chn), 0x10, 0x10); 36762306a36Sopenharmony_ci if (ret < 0) 36862306a36Sopenharmony_ci qib_dev_err(dd, 36962306a36Sopenharmony_ci "Err on TRIMDONE rewrite1\n"); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci for (chn = 3; chn >= 0; --chn) { 37362306a36Sopenharmony_ci /* Read CTRL reg for each channel to check TRIMDONE */ 37462306a36Sopenharmony_ci if (baduns & (1 << chn)) { 37562306a36Sopenharmony_ci qib_dev_err(dd, 37662306a36Sopenharmony_ci "Resetting TRIMDONE on chn %d (%s)\n", 37762306a36Sopenharmony_ci chn, where); 37862306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, 37962306a36Sopenharmony_ci IB_CTRL2(chn), 0x10, 0x10); 38062306a36Sopenharmony_ci if (ret < 0) 38162306a36Sopenharmony_ci qib_dev_err(dd, 38262306a36Sopenharmony_ci "Failed re-setting TRIMDONE, chn %d (%s)\n", 38362306a36Sopenharmony_ci chn, where); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/* 38962306a36Sopenharmony_ci * Below is portion of IBA7220-specific bringup_serdes() that actually 39062306a36Sopenharmony_ci * deals with registers and memory within the SerDes itself. 39162306a36Sopenharmony_ci * Post IB uC code version 1.32.17, was_reset being 1 is not really 39262306a36Sopenharmony_ci * informative, so we double-check. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ciint qib_sd7220_init(struct qib_devdata *dd) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci const struct firmware *fw; 39762306a36Sopenharmony_ci int ret = 1; /* default to failure */ 39862306a36Sopenharmony_ci int first_reset, was_reset; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* SERDES MPU reset recorded in D0 */ 40162306a36Sopenharmony_ci was_reset = (qib_read_kreg64(dd, kr_ibserdesctrl) & 1); 40262306a36Sopenharmony_ci if (!was_reset) { 40362306a36Sopenharmony_ci /* entered with reset not asserted, we need to do it */ 40462306a36Sopenharmony_ci qib_ibsd_reset(dd, 1); 40562306a36Sopenharmony_ci qib_sd_trimdone_monitor(dd, "Driver-reload"); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = request_firmware(&fw, SD7220_FW_NAME, &dd->pcidev->dev); 40962306a36Sopenharmony_ci if (ret) { 41062306a36Sopenharmony_ci qib_dev_err(dd, "Failed to load IB SERDES image\n"); 41162306a36Sopenharmony_ci goto done; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Substitute our deduced value for was_reset */ 41562306a36Sopenharmony_ci ret = qib_ibsd_ucode_loaded(dd->pport, fw); 41662306a36Sopenharmony_ci if (ret < 0) 41762306a36Sopenharmony_ci goto bail; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci first_reset = !ret; /* First reset if IBSD uCode not yet loaded */ 42062306a36Sopenharmony_ci /* 42162306a36Sopenharmony_ci * Alter some regs per vendor latest doc, reset-defaults 42262306a36Sopenharmony_ci * are not right for IB. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci ret = qib_sd_early(dd); 42562306a36Sopenharmony_ci if (ret < 0) { 42662306a36Sopenharmony_ci qib_dev_err(dd, "Failed to set IB SERDES early defaults\n"); 42762306a36Sopenharmony_ci goto bail; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci /* 43062306a36Sopenharmony_ci * Set DAC manual trim IB. 43162306a36Sopenharmony_ci * We only do this once after chip has been reset (usually 43262306a36Sopenharmony_ci * same as once per system boot). 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci if (first_reset) { 43562306a36Sopenharmony_ci ret = qib_sd_dactrim(dd); 43662306a36Sopenharmony_ci if (ret < 0) { 43762306a36Sopenharmony_ci qib_dev_err(dd, "Failed IB SERDES DAC trim\n"); 43862306a36Sopenharmony_ci goto bail; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * Set various registers (DDS and RXEQ) that will be 44362306a36Sopenharmony_ci * controlled by IBC (in 1.2 mode) to reasonable preset values 44462306a36Sopenharmony_ci * Calling the "internal" version avoids the "check for needed" 44562306a36Sopenharmony_ci * and "trimdone monitor" that might be counter-productive. 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci ret = qib_internal_presets(dd); 44862306a36Sopenharmony_ci if (ret < 0) { 44962306a36Sopenharmony_ci qib_dev_err(dd, "Failed to set IB SERDES presets\n"); 45062306a36Sopenharmony_ci goto bail; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci ret = qib_sd_trimself(dd, 0x80); 45362306a36Sopenharmony_ci if (ret < 0) { 45462306a36Sopenharmony_ci qib_dev_err(dd, "Failed to set IB SERDES TRIMSELF\n"); 45562306a36Sopenharmony_ci goto bail; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Load image, then try to verify */ 45962306a36Sopenharmony_ci ret = 0; /* Assume success */ 46062306a36Sopenharmony_ci if (first_reset) { 46162306a36Sopenharmony_ci int vfy; 46262306a36Sopenharmony_ci int trim_done; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci ret = qib_sd7220_ib_load(dd, fw); 46562306a36Sopenharmony_ci if (ret < 0) { 46662306a36Sopenharmony_ci qib_dev_err(dd, "Failed to load IB SERDES image\n"); 46762306a36Sopenharmony_ci goto bail; 46862306a36Sopenharmony_ci } else { 46962306a36Sopenharmony_ci /* Loaded image, try to verify */ 47062306a36Sopenharmony_ci vfy = qib_sd7220_ib_vfy(dd, fw); 47162306a36Sopenharmony_ci if (vfy != ret) { 47262306a36Sopenharmony_ci qib_dev_err(dd, "SERDES PRAM VFY failed\n"); 47362306a36Sopenharmony_ci goto bail; 47462306a36Sopenharmony_ci } /* end if verified */ 47562306a36Sopenharmony_ci } /* end if loaded */ 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * Loaded and verified. Almost good... 47962306a36Sopenharmony_ci * hold "success" in ret 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci ret = 0; 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * Prev steps all worked, continue bringup 48462306a36Sopenharmony_ci * De-assert RESET to uC, only in first reset, to allow 48562306a36Sopenharmony_ci * trimming. 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci * Since our default setup sets START_EQ1 to 48862306a36Sopenharmony_ci * PRESET, we need to clear that for this very first run. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, START_EQ1(0), 0, 0x38); 49162306a36Sopenharmony_ci if (ret < 0) { 49262306a36Sopenharmony_ci qib_dev_err(dd, "Failed clearing START_EQ1\n"); 49362306a36Sopenharmony_ci goto bail; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci qib_ibsd_reset(dd, 0); 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * If this is not the first reset, trimdone should be set 49962306a36Sopenharmony_ci * already. We may need to check about this. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci trim_done = qib_sd_trimdone_poll(dd); 50262306a36Sopenharmony_ci /* 50362306a36Sopenharmony_ci * Whether or not trimdone succeeded, we need to put the 50462306a36Sopenharmony_ci * uC back into reset to avoid a possible fight with the 50562306a36Sopenharmony_ci * IBC state-machine. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci qib_ibsd_reset(dd, 1); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (!trim_done) { 51062306a36Sopenharmony_ci qib_dev_err(dd, "No TRIMDONE seen\n"); 51162306a36Sopenharmony_ci goto bail; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci /* 51462306a36Sopenharmony_ci * DEBUG: check each time we reset if trimdone bits have 51562306a36Sopenharmony_ci * gotten cleared, and re-set them. 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci qib_sd_trimdone_monitor(dd, "First-reset"); 51862306a36Sopenharmony_ci /* Remember so we do not re-do the load, dactrim, etc. */ 51962306a36Sopenharmony_ci dd->cspec->serdes_first_init_done = 1; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * setup for channel training and load values for 52362306a36Sopenharmony_ci * RxEq and DDS in tables used by IBC in IB1.2 mode 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci ret = 0; 52662306a36Sopenharmony_ci if (qib_sd_setvals(dd) >= 0) 52762306a36Sopenharmony_ci goto done; 52862306a36Sopenharmony_cibail: 52962306a36Sopenharmony_ci ret = 1; 53062306a36Sopenharmony_cidone: 53162306a36Sopenharmony_ci /* start relock timer regardless, but start at 1 second */ 53262306a36Sopenharmony_ci set_7220_relock_poll(dd, -1); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci release_firmware(fw); 53562306a36Sopenharmony_ci return ret; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci#define EPB_ACC_REQ 1 53962306a36Sopenharmony_ci#define EPB_ACC_GNT 0x100 54062306a36Sopenharmony_ci#define EPB_DATA_MASK 0xFF 54162306a36Sopenharmony_ci#define EPB_RD (1ULL << 24) 54262306a36Sopenharmony_ci#define EPB_TRANS_RDY (1ULL << 31) 54362306a36Sopenharmony_ci#define EPB_TRANS_ERR (1ULL << 30) 54462306a36Sopenharmony_ci#define EPB_TRANS_TRIES 5 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/* 54762306a36Sopenharmony_ci * query, claim, release ownership of the EPB (External Parallel Bus) 54862306a36Sopenharmony_ci * for a specified SERDES. 54962306a36Sopenharmony_ci * the "claim" parameter is >0 to claim, <0 to release, 0 to query. 55062306a36Sopenharmony_ci * Returns <0 for errors, >0 if we had ownership, else 0. 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_cistatic int epb_access(struct qib_devdata *dd, int sdnum, int claim) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci u16 acc; 55562306a36Sopenharmony_ci u64 accval; 55662306a36Sopenharmony_ci int owned = 0; 55762306a36Sopenharmony_ci u64 oct_sel = 0; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci switch (sdnum) { 56062306a36Sopenharmony_ci case IB_7220_SERDES: 56162306a36Sopenharmony_ci /* 56262306a36Sopenharmony_ci * The IB SERDES "ownership" is fairly simple. A single each 56362306a36Sopenharmony_ci * request/grant. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci acc = kr_ibsd_epb_access_ctrl; 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci case PCIE_SERDES0: 56962306a36Sopenharmony_ci case PCIE_SERDES1: 57062306a36Sopenharmony_ci /* PCIe SERDES has two "octants", need to select which */ 57162306a36Sopenharmony_ci acc = kr_pciesd_epb_access_ctrl; 57262306a36Sopenharmony_ci oct_sel = (2 << (sdnum - PCIE_SERDES0)); 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci default: 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* Make sure any outstanding transaction was seen */ 58062306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 58162306a36Sopenharmony_ci udelay(15); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci accval = qib_read_kreg32(dd, acc); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci owned = !!(accval & EPB_ACC_GNT); 58662306a36Sopenharmony_ci if (claim < 0) { 58762306a36Sopenharmony_ci /* Need to release */ 58862306a36Sopenharmony_ci u64 pollval; 58962306a36Sopenharmony_ci /* 59062306a36Sopenharmony_ci * The only writable bits are the request and CS. 59162306a36Sopenharmony_ci * Both should be clear 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci u64 newval = 0; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci qib_write_kreg(dd, acc, newval); 59662306a36Sopenharmony_ci /* First read after write is not trustworthy */ 59762306a36Sopenharmony_ci pollval = qib_read_kreg32(dd, acc); 59862306a36Sopenharmony_ci udelay(5); 59962306a36Sopenharmony_ci pollval = qib_read_kreg32(dd, acc); 60062306a36Sopenharmony_ci if (pollval & EPB_ACC_GNT) 60162306a36Sopenharmony_ci owned = -1; 60262306a36Sopenharmony_ci } else if (claim > 0) { 60362306a36Sopenharmony_ci /* Need to claim */ 60462306a36Sopenharmony_ci u64 pollval; 60562306a36Sopenharmony_ci u64 newval = EPB_ACC_REQ | oct_sel; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci qib_write_kreg(dd, acc, newval); 60862306a36Sopenharmony_ci /* First read after write is not trustworthy */ 60962306a36Sopenharmony_ci pollval = qib_read_kreg32(dd, acc); 61062306a36Sopenharmony_ci udelay(5); 61162306a36Sopenharmony_ci pollval = qib_read_kreg32(dd, acc); 61262306a36Sopenharmony_ci if (!(pollval & EPB_ACC_GNT)) 61362306a36Sopenharmony_ci owned = -1; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci return owned; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci/* 61962306a36Sopenharmony_ci * Lemma to deal with race condition of write..read to epb regs 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_cistatic int epb_trans(struct qib_devdata *dd, u16 reg, u64 i_val, u64 *o_vp) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci int tries; 62462306a36Sopenharmony_ci u64 transval; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci qib_write_kreg(dd, reg, i_val); 62762306a36Sopenharmony_ci /* Throw away first read, as RDY bit may be stale */ 62862306a36Sopenharmony_ci transval = qib_read_kreg64(dd, reg); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci for (tries = EPB_TRANS_TRIES; tries; --tries) { 63162306a36Sopenharmony_ci transval = qib_read_kreg32(dd, reg); 63262306a36Sopenharmony_ci if (transval & EPB_TRANS_RDY) 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci udelay(5); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci if (transval & EPB_TRANS_ERR) 63762306a36Sopenharmony_ci return -1; 63862306a36Sopenharmony_ci if (tries > 0 && o_vp) 63962306a36Sopenharmony_ci *o_vp = transval; 64062306a36Sopenharmony_ci return tries; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/** 64462306a36Sopenharmony_ci * qib_sd7220_reg_mod - modify SERDES register 64562306a36Sopenharmony_ci * @dd: the qlogic_ib device 64662306a36Sopenharmony_ci * @sdnum: which SERDES to access 64762306a36Sopenharmony_ci * @loc: location - channel, element, register, as packed by EPB_LOC() macro. 64862306a36Sopenharmony_ci * @wd: Write Data - value to set in register 64962306a36Sopenharmony_ci * @mask: ones where data should be spliced into reg. 65062306a36Sopenharmony_ci * 65162306a36Sopenharmony_ci * Basic register read/modify/write, with un-needed acesses elided. That is, 65262306a36Sopenharmony_ci * a mask of zero will prevent write, while a mask of 0xFF will prevent read. 65362306a36Sopenharmony_ci * returns current (presumed, if a write was done) contents of selected 65462306a36Sopenharmony_ci * register, or <0 if errors. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_cistatic int qib_sd7220_reg_mod(struct qib_devdata *dd, int sdnum, u32 loc, 65762306a36Sopenharmony_ci u32 wd, u32 mask) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci u16 trans; 66062306a36Sopenharmony_ci u64 transval; 66162306a36Sopenharmony_ci int owned; 66262306a36Sopenharmony_ci int tries, ret; 66362306a36Sopenharmony_ci unsigned long flags; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci switch (sdnum) { 66662306a36Sopenharmony_ci case IB_7220_SERDES: 66762306a36Sopenharmony_ci trans = kr_ibsd_epb_transaction_reg; 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci case PCIE_SERDES0: 67162306a36Sopenharmony_ci case PCIE_SERDES1: 67262306a36Sopenharmony_ci trans = kr_pciesd_epb_transaction_reg; 67362306a36Sopenharmony_ci break; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci default: 67662306a36Sopenharmony_ci return -1; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * All access is locked in software (vs other host threads) and 68162306a36Sopenharmony_ci * hardware (vs uC access). 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci spin_lock_irqsave(&dd->cspec->sdepb_lock, flags); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci owned = epb_access(dd, sdnum, 1); 68662306a36Sopenharmony_ci if (owned < 0) { 68762306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags); 68862306a36Sopenharmony_ci return -1; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci for (tries = EPB_TRANS_TRIES; tries; --tries) { 69162306a36Sopenharmony_ci transval = qib_read_kreg32(dd, trans); 69262306a36Sopenharmony_ci if (transval & EPB_TRANS_RDY) 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci udelay(5); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (tries > 0) { 69862306a36Sopenharmony_ci tries = 1; /* to make read-skip work */ 69962306a36Sopenharmony_ci if (mask != 0xFF) { 70062306a36Sopenharmony_ci /* 70162306a36Sopenharmony_ci * Not a pure write, so need to read. 70262306a36Sopenharmony_ci * loc encodes chip-select as well as address 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_ci transval = loc | EPB_RD; 70562306a36Sopenharmony_ci tries = epb_trans(dd, trans, transval, &transval); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci if (tries > 0 && mask != 0) { 70862306a36Sopenharmony_ci /* 70962306a36Sopenharmony_ci * Not a pure read, so need to write. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_ci wd = (wd & mask) | (transval & ~mask); 71262306a36Sopenharmony_ci transval = loc | (wd & EPB_DATA_MASK); 71362306a36Sopenharmony_ci tries = epb_trans(dd, trans, transval, &transval); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci /* else, failed to see ready, what error-handling? */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * Release bus. Failure is an error. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci if (epb_access(dd, sdnum, -1) < 0) 72262306a36Sopenharmony_ci ret = -1; 72362306a36Sopenharmony_ci else 72462306a36Sopenharmony_ci ret = transval & EPB_DATA_MASK; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags); 72762306a36Sopenharmony_ci if (tries <= 0) 72862306a36Sopenharmony_ci ret = -1; 72962306a36Sopenharmony_ci return ret; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci#define EPB_ROM_R (2) 73362306a36Sopenharmony_ci#define EPB_ROM_W (1) 73462306a36Sopenharmony_ci/* 73562306a36Sopenharmony_ci * Below, all uC-related, use appropriate UC_CS, depending 73662306a36Sopenharmony_ci * on which SerDes is used. 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_ci#define EPB_UC_CTL EPB_LOC(6, 0, 0) 73962306a36Sopenharmony_ci#define EPB_MADDRL EPB_LOC(6, 0, 2) 74062306a36Sopenharmony_ci#define EPB_MADDRH EPB_LOC(6, 0, 3) 74162306a36Sopenharmony_ci#define EPB_ROMDATA EPB_LOC(6, 0, 4) 74262306a36Sopenharmony_ci#define EPB_RAMDATA EPB_LOC(6, 0, 5) 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci/* Transfer date to/from uC Program RAM of IB or PCIe SerDes */ 74562306a36Sopenharmony_cistatic int qib_sd7220_ram_xfer(struct qib_devdata *dd, int sdnum, u32 loc, 74662306a36Sopenharmony_ci u8 *buf, int cnt, int rd_notwr) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci u16 trans; 74962306a36Sopenharmony_ci u64 transval; 75062306a36Sopenharmony_ci u64 csbit; 75162306a36Sopenharmony_ci int owned; 75262306a36Sopenharmony_ci int tries; 75362306a36Sopenharmony_ci int sofar; 75462306a36Sopenharmony_ci int addr; 75562306a36Sopenharmony_ci int ret; 75662306a36Sopenharmony_ci unsigned long flags; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Pick appropriate transaction reg and "Chip select" for this serdes */ 75962306a36Sopenharmony_ci switch (sdnum) { 76062306a36Sopenharmony_ci case IB_7220_SERDES: 76162306a36Sopenharmony_ci csbit = 1ULL << EPB_IB_UC_CS_SHF; 76262306a36Sopenharmony_ci trans = kr_ibsd_epb_transaction_reg; 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci case PCIE_SERDES0: 76662306a36Sopenharmony_ci case PCIE_SERDES1: 76762306a36Sopenharmony_ci /* PCIe SERDES has uC "chip select" in different bit, too */ 76862306a36Sopenharmony_ci csbit = 1ULL << EPB_PCIE_UC_CS_SHF; 76962306a36Sopenharmony_ci trans = kr_pciesd_epb_transaction_reg; 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci default: 77362306a36Sopenharmony_ci return -1; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci spin_lock_irqsave(&dd->cspec->sdepb_lock, flags); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci owned = epb_access(dd, sdnum, 1); 77962306a36Sopenharmony_ci if (owned < 0) { 78062306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags); 78162306a36Sopenharmony_ci return -1; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* 78562306a36Sopenharmony_ci * In future code, we may need to distinguish several address ranges, 78662306a36Sopenharmony_ci * and select various memories based on this. For now, just trim 78762306a36Sopenharmony_ci * "loc" (location including address and memory select) to 78862306a36Sopenharmony_ci * "addr" (address within memory). we will only support PRAM 78962306a36Sopenharmony_ci * The memory is 8KB. 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_ci addr = loc & 0x1FFF; 79262306a36Sopenharmony_ci for (tries = EPB_TRANS_TRIES; tries; --tries) { 79362306a36Sopenharmony_ci transval = qib_read_kreg32(dd, trans); 79462306a36Sopenharmony_ci if (transval & EPB_TRANS_RDY) 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci udelay(5); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci sofar = 0; 80062306a36Sopenharmony_ci if (tries > 0) { 80162306a36Sopenharmony_ci /* 80262306a36Sopenharmony_ci * Every "memory" access is doubly-indirect. 80362306a36Sopenharmony_ci * We set two bytes of address, then read/write 80462306a36Sopenharmony_ci * one or mores bytes of data. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* First, we set control to "Read" or "Write" */ 80862306a36Sopenharmony_ci transval = csbit | EPB_UC_CTL | 80962306a36Sopenharmony_ci (rd_notwr ? EPB_ROM_R : EPB_ROM_W); 81062306a36Sopenharmony_ci tries = epb_trans(dd, trans, transval, &transval); 81162306a36Sopenharmony_ci while (tries > 0 && sofar < cnt) { 81262306a36Sopenharmony_ci if (!sofar) { 81362306a36Sopenharmony_ci /* Only set address at start of chunk */ 81462306a36Sopenharmony_ci int addrbyte = (addr + sofar) >> 8; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci transval = csbit | EPB_MADDRH | addrbyte; 81762306a36Sopenharmony_ci tries = epb_trans(dd, trans, transval, 81862306a36Sopenharmony_ci &transval); 81962306a36Sopenharmony_ci if (tries <= 0) 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci addrbyte = (addr + sofar) & 0xFF; 82262306a36Sopenharmony_ci transval = csbit | EPB_MADDRL | addrbyte; 82362306a36Sopenharmony_ci tries = epb_trans(dd, trans, transval, 82462306a36Sopenharmony_ci &transval); 82562306a36Sopenharmony_ci if (tries <= 0) 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (rd_notwr) 83062306a36Sopenharmony_ci transval = csbit | EPB_ROMDATA | EPB_RD; 83162306a36Sopenharmony_ci else 83262306a36Sopenharmony_ci transval = csbit | EPB_ROMDATA | buf[sofar]; 83362306a36Sopenharmony_ci tries = epb_trans(dd, trans, transval, &transval); 83462306a36Sopenharmony_ci if (tries <= 0) 83562306a36Sopenharmony_ci break; 83662306a36Sopenharmony_ci if (rd_notwr) 83762306a36Sopenharmony_ci buf[sofar] = transval & EPB_DATA_MASK; 83862306a36Sopenharmony_ci ++sofar; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci /* Finally, clear control-bit for Read or Write */ 84162306a36Sopenharmony_ci transval = csbit | EPB_UC_CTL; 84262306a36Sopenharmony_ci tries = epb_trans(dd, trans, transval, &transval); 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci ret = sofar; 84662306a36Sopenharmony_ci /* Release bus. Failure is an error */ 84762306a36Sopenharmony_ci if (epb_access(dd, sdnum, -1) < 0) 84862306a36Sopenharmony_ci ret = -1; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags); 85162306a36Sopenharmony_ci if (tries <= 0) 85262306a36Sopenharmony_ci ret = -1; 85362306a36Sopenharmony_ci return ret; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci#define PROG_CHUNK 64 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, 85962306a36Sopenharmony_ci const u8 *img, int len, int offset) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci int cnt, sofar, req; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci sofar = 0; 86462306a36Sopenharmony_ci while (sofar < len) { 86562306a36Sopenharmony_ci req = len - sofar; 86662306a36Sopenharmony_ci if (req > PROG_CHUNK) 86762306a36Sopenharmony_ci req = PROG_CHUNK; 86862306a36Sopenharmony_ci cnt = qib_sd7220_ram_xfer(dd, sdnum, offset + sofar, 86962306a36Sopenharmony_ci (u8 *)img + sofar, req, 0); 87062306a36Sopenharmony_ci if (cnt < req) { 87162306a36Sopenharmony_ci sofar = -1; 87262306a36Sopenharmony_ci break; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci sofar += req; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci return sofar; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci#define VFY_CHUNK 64 88062306a36Sopenharmony_ci#define SD_PRAM_ERROR_LIMIT 42 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum, 88362306a36Sopenharmony_ci const u8 *img, int len, int offset) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci int cnt, sofar, req, idx, errors; 88662306a36Sopenharmony_ci unsigned char readback[VFY_CHUNK]; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci errors = 0; 88962306a36Sopenharmony_ci sofar = 0; 89062306a36Sopenharmony_ci while (sofar < len) { 89162306a36Sopenharmony_ci req = len - sofar; 89262306a36Sopenharmony_ci if (req > VFY_CHUNK) 89362306a36Sopenharmony_ci req = VFY_CHUNK; 89462306a36Sopenharmony_ci cnt = qib_sd7220_ram_xfer(dd, sdnum, sofar + offset, 89562306a36Sopenharmony_ci readback, req, 1); 89662306a36Sopenharmony_ci if (cnt < req) { 89762306a36Sopenharmony_ci /* failed in read itself */ 89862306a36Sopenharmony_ci sofar = -1; 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci for (idx = 0; idx < cnt; ++idx) { 90262306a36Sopenharmony_ci if (readback[idx] != img[idx+sofar]) 90362306a36Sopenharmony_ci ++errors; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci sofar += cnt; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci return errors ? -errors : sofar; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic int 91162306a36Sopenharmony_ciqib_sd7220_ib_load(struct qib_devdata *dd, const struct firmware *fw) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci return qib_sd7220_prog_ld(dd, IB_7220_SERDES, fw->data, fw->size, 0); 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int 91762306a36Sopenharmony_ciqib_sd7220_ib_vfy(struct qib_devdata *dd, const struct firmware *fw) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci return qib_sd7220_prog_vfy(dd, IB_7220_SERDES, fw->data, fw->size, 0); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/* 92362306a36Sopenharmony_ci * IRQ not set up at this point in init, so we poll. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_ci#define IB_SERDES_TRIM_DONE (1ULL << 11) 92662306a36Sopenharmony_ci#define TRIM_TMO (15) 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic int qib_sd_trimdone_poll(struct qib_devdata *dd) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci int trim_tmo, ret; 93162306a36Sopenharmony_ci uint64_t val; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* 93462306a36Sopenharmony_ci * Default to failure, so IBC will not start 93562306a36Sopenharmony_ci * without IB_SERDES_TRIM_DONE. 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_ci ret = 0; 93862306a36Sopenharmony_ci for (trim_tmo = 0; trim_tmo < TRIM_TMO; ++trim_tmo) { 93962306a36Sopenharmony_ci val = qib_read_kreg64(dd, kr_ibcstatus); 94062306a36Sopenharmony_ci if (val & IB_SERDES_TRIM_DONE) { 94162306a36Sopenharmony_ci ret = 1; 94262306a36Sopenharmony_ci break; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci msleep(20); 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci if (trim_tmo >= TRIM_TMO) { 94762306a36Sopenharmony_ci qib_dev_err(dd, "No TRIMDONE in %d tries\n", trim_tmo); 94862306a36Sopenharmony_ci ret = 0; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci return ret; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci#define TX_FAST_ELT (9) 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci/* 95662306a36Sopenharmony_ci * Set the "negotiation" values for SERDES. These are used by the IB1.2 95762306a36Sopenharmony_ci * link negotiation. Macros below are attempt to keep the values a 95862306a36Sopenharmony_ci * little more human-editable. 95962306a36Sopenharmony_ci * First, values related to Drive De-emphasis Settings. 96062306a36Sopenharmony_ci */ 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci#define NUM_DDS_REGS 6 96362306a36Sopenharmony_ci#define DDS_REG_MAP 0x76A910 /* LSB-first list of regs (in elt 9) to mod */ 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci#define DDS_VAL(amp_d, main_d, ipst_d, ipre_d, amp_s, main_s, ipst_s, ipre_s) \ 96662306a36Sopenharmony_ci { { ((amp_d & 0x1F) << 1) | 1, ((amp_s & 0x1F) << 1) | 1, \ 96762306a36Sopenharmony_ci (main_d << 3) | 4 | (ipre_d >> 2), \ 96862306a36Sopenharmony_ci (main_s << 3) | 4 | (ipre_s >> 2), \ 96962306a36Sopenharmony_ci ((ipst_d & 0xF) << 1) | ((ipre_d & 3) << 6) | 0x21, \ 97062306a36Sopenharmony_ci ((ipst_s & 0xF) << 1) | ((ipre_s & 3) << 6) | 0x21 } } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic struct dds_init { 97362306a36Sopenharmony_ci uint8_t reg_vals[NUM_DDS_REGS]; 97462306a36Sopenharmony_ci} dds_init_vals[] = { 97562306a36Sopenharmony_ci /* DDR(FDR) SDR(HDR) */ 97662306a36Sopenharmony_ci /* Vendor recommends below for 3m cable */ 97762306a36Sopenharmony_ci#define DDS_3M 0 97862306a36Sopenharmony_ci DDS_VAL(31, 19, 12, 0, 29, 22, 9, 0), 97962306a36Sopenharmony_ci DDS_VAL(31, 12, 15, 4, 31, 15, 15, 1), 98062306a36Sopenharmony_ci DDS_VAL(31, 13, 15, 3, 31, 16, 15, 0), 98162306a36Sopenharmony_ci DDS_VAL(31, 14, 15, 2, 31, 17, 14, 0), 98262306a36Sopenharmony_ci DDS_VAL(31, 15, 15, 1, 31, 18, 13, 0), 98362306a36Sopenharmony_ci DDS_VAL(31, 16, 15, 0, 31, 19, 12, 0), 98462306a36Sopenharmony_ci DDS_VAL(31, 17, 14, 0, 31, 20, 11, 0), 98562306a36Sopenharmony_ci DDS_VAL(31, 18, 13, 0, 30, 21, 10, 0), 98662306a36Sopenharmony_ci DDS_VAL(31, 20, 11, 0, 28, 23, 8, 0), 98762306a36Sopenharmony_ci DDS_VAL(31, 21, 10, 0, 27, 24, 7, 0), 98862306a36Sopenharmony_ci DDS_VAL(31, 22, 9, 0, 26, 25, 6, 0), 98962306a36Sopenharmony_ci DDS_VAL(30, 23, 8, 0, 25, 26, 5, 0), 99062306a36Sopenharmony_ci DDS_VAL(29, 24, 7, 0, 23, 27, 4, 0), 99162306a36Sopenharmony_ci /* Vendor recommends below for 1m cable */ 99262306a36Sopenharmony_ci#define DDS_1M 13 99362306a36Sopenharmony_ci DDS_VAL(28, 25, 6, 0, 21, 28, 3, 0), 99462306a36Sopenharmony_ci DDS_VAL(27, 26, 5, 0, 19, 29, 2, 0), 99562306a36Sopenharmony_ci DDS_VAL(25, 27, 4, 0, 17, 30, 1, 0) 99662306a36Sopenharmony_ci}; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci/* 99962306a36Sopenharmony_ci * Now the RXEQ section of the table. 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci/* Hardware packs an element number and register address thus: */ 100262306a36Sopenharmony_ci#define RXEQ_INIT_RDESC(elt, addr) (((elt) & 0xF) | ((addr) << 4)) 100362306a36Sopenharmony_ci#define RXEQ_VAL(elt, adr, val0, val1, val2, val3) \ 100462306a36Sopenharmony_ci {RXEQ_INIT_RDESC((elt), (adr)), {(val0), (val1), (val2), (val3)} } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci#define RXEQ_VAL_ALL(elt, adr, val) \ 100762306a36Sopenharmony_ci {RXEQ_INIT_RDESC((elt), (adr)), {(val), (val), (val), (val)} } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci#define RXEQ_SDR_DFELTH 0 101062306a36Sopenharmony_ci#define RXEQ_SDR_TLTH 0 101162306a36Sopenharmony_ci#define RXEQ_SDR_G1CNT_Z1CNT 0x11 101262306a36Sopenharmony_ci#define RXEQ_SDR_ZCNT 23 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic struct rxeq_init { 101562306a36Sopenharmony_ci u16 rdesc; /* in form used in SerDesDDSRXEQ */ 101662306a36Sopenharmony_ci u8 rdata[4]; 101762306a36Sopenharmony_ci} rxeq_init_vals[] = { 101862306a36Sopenharmony_ci /* Set Rcv Eq. to Preset node */ 101962306a36Sopenharmony_ci RXEQ_VAL_ALL(7, 0x27, 0x10), 102062306a36Sopenharmony_ci /* Set DFELTHFDR/HDR thresholds */ 102162306a36Sopenharmony_ci RXEQ_VAL(7, 8, 0, 0, 0, 0), /* FDR, was 0, 1, 2, 3 */ 102262306a36Sopenharmony_ci RXEQ_VAL(7, 0x21, 0, 0, 0, 0), /* HDR */ 102362306a36Sopenharmony_ci /* Set TLTHFDR/HDR theshold */ 102462306a36Sopenharmony_ci RXEQ_VAL(7, 9, 2, 2, 2, 2), /* FDR, was 0, 2, 4, 6 */ 102562306a36Sopenharmony_ci RXEQ_VAL(7, 0x23, 2, 2, 2, 2), /* HDR, was 0, 1, 2, 3 */ 102662306a36Sopenharmony_ci /* Set Preamp setting 2 (ZFR/ZCNT) */ 102762306a36Sopenharmony_ci RXEQ_VAL(7, 0x1B, 12, 12, 12, 12), /* FDR, was 12, 16, 20, 24 */ 102862306a36Sopenharmony_ci RXEQ_VAL(7, 0x1C, 12, 12, 12, 12), /* HDR, was 12, 16, 20, 24 */ 102962306a36Sopenharmony_ci /* Set Preamp DC gain and Setting 1 (GFR/GHR) */ 103062306a36Sopenharmony_ci RXEQ_VAL(7, 0x1E, 16, 16, 16, 16), /* FDR, was 16, 17, 18, 20 */ 103162306a36Sopenharmony_ci RXEQ_VAL(7, 0x1F, 16, 16, 16, 16), /* HDR, was 16, 17, 18, 20 */ 103262306a36Sopenharmony_ci /* Toggle RELOCK (in VCDL_CTRL0) to lock to data */ 103362306a36Sopenharmony_ci RXEQ_VAL_ALL(6, 6, 0x20), /* Set D5 High */ 103462306a36Sopenharmony_ci RXEQ_VAL_ALL(6, 6, 0), /* Set D5 Low */ 103562306a36Sopenharmony_ci}; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci/* There are 17 values from vendor, but IBC only accesses the first 16 */ 103862306a36Sopenharmony_ci#define DDS_ROWS (16) 103962306a36Sopenharmony_ci#define RXEQ_ROWS ARRAY_SIZE(rxeq_init_vals) 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic int qib_sd_setvals(struct qib_devdata *dd) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci int idx, midx; 104462306a36Sopenharmony_ci int min_idx; /* Minimum index for this portion of table */ 104562306a36Sopenharmony_ci uint32_t dds_reg_map; 104662306a36Sopenharmony_ci u64 __iomem *taddr, *iaddr; 104762306a36Sopenharmony_ci uint64_t data; 104862306a36Sopenharmony_ci uint64_t sdctl; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci taddr = dd->kregbase + kr_serdes_maptable; 105162306a36Sopenharmony_ci iaddr = dd->kregbase + kr_serdes_ddsrxeq0; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* 105462306a36Sopenharmony_ci * Init the DDS section of the table. 105562306a36Sopenharmony_ci * Each "row" of the table provokes NUM_DDS_REG writes, to the 105662306a36Sopenharmony_ci * registers indicated in DDS_REG_MAP. 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_ci sdctl = qib_read_kreg64(dd, kr_ibserdesctrl); 105962306a36Sopenharmony_ci sdctl = (sdctl & ~(0x1f << 8)) | (NUM_DDS_REGS << 8); 106062306a36Sopenharmony_ci sdctl = (sdctl & ~(0x1f << 13)) | (RXEQ_ROWS << 13); 106162306a36Sopenharmony_ci qib_write_kreg(dd, kr_ibserdesctrl, sdctl); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* 106462306a36Sopenharmony_ci * Iterate down table within loop for each register to store. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci dds_reg_map = DDS_REG_MAP; 106762306a36Sopenharmony_ci for (idx = 0; idx < NUM_DDS_REGS; ++idx) { 106862306a36Sopenharmony_ci data = ((dds_reg_map & 0xF) << 4) | TX_FAST_ELT; 106962306a36Sopenharmony_ci writeq(data, iaddr + idx); 107062306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 107162306a36Sopenharmony_ci dds_reg_map >>= 4; 107262306a36Sopenharmony_ci for (midx = 0; midx < DDS_ROWS; ++midx) { 107362306a36Sopenharmony_ci u64 __iomem *daddr = taddr + ((midx << 4) + idx); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci data = dds_init_vals[midx].reg_vals[idx]; 107662306a36Sopenharmony_ci writeq(data, daddr); 107762306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 107862306a36Sopenharmony_ci } /* End inner for (vals for this reg, each row) */ 107962306a36Sopenharmony_ci } /* end outer for (regs to be stored) */ 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* 108262306a36Sopenharmony_ci * Init the RXEQ section of the table. 108362306a36Sopenharmony_ci * This runs in a different order, as the pattern of 108462306a36Sopenharmony_ci * register references is more complex, but there are only 108562306a36Sopenharmony_ci * four "data" values per register. 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci min_idx = idx; /* RXEQ indices pick up where DDS left off */ 108862306a36Sopenharmony_ci taddr += 0x100; /* RXEQ data is in second half of table */ 108962306a36Sopenharmony_ci /* Iterate through RXEQ register addresses */ 109062306a36Sopenharmony_ci for (idx = 0; idx < RXEQ_ROWS; ++idx) { 109162306a36Sopenharmony_ci int didx; /* "destination" */ 109262306a36Sopenharmony_ci int vidx; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* didx is offset by min_idx to address RXEQ range of regs */ 109562306a36Sopenharmony_ci didx = idx + min_idx; 109662306a36Sopenharmony_ci /* Store the next RXEQ register address */ 109762306a36Sopenharmony_ci writeq(rxeq_init_vals[idx].rdesc, iaddr + didx); 109862306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 109962306a36Sopenharmony_ci /* Iterate through RXEQ values */ 110062306a36Sopenharmony_ci for (vidx = 0; vidx < 4; vidx++) { 110162306a36Sopenharmony_ci data = rxeq_init_vals[idx].rdata[vidx]; 110262306a36Sopenharmony_ci writeq(data, taddr + (vidx << 6) + idx); 110362306a36Sopenharmony_ci qib_read_kreg32(dd, kr_scratch); 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci } /* end outer for (Reg-writes for RXEQ) */ 110662306a36Sopenharmony_ci return 0; 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci#define CMUCTRL5 EPB_LOC(7, 0, 0x15) 111062306a36Sopenharmony_ci#define RXHSCTRL0(chan) EPB_LOC(chan, 6, 0) 111162306a36Sopenharmony_ci#define VCDL_DAC2(chan) EPB_LOC(chan, 6, 5) 111262306a36Sopenharmony_ci#define VCDL_CTRL0(chan) EPB_LOC(chan, 6, 6) 111362306a36Sopenharmony_ci#define VCDL_CTRL2(chan) EPB_LOC(chan, 6, 8) 111462306a36Sopenharmony_ci#define START_EQ2(chan) EPB_LOC(chan, 7, 0x28) 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci/* 111762306a36Sopenharmony_ci * Repeat a "store" across all channels of the IB SerDes. 111862306a36Sopenharmony_ci * Although nominally it inherits the "read value" of the last 111962306a36Sopenharmony_ci * channel it modified, the only really useful return is <0 for 112062306a36Sopenharmony_ci * failure, >= 0 for success. The parameter 'loc' is assumed to 112162306a36Sopenharmony_ci * be the location in some channel of the register to be modified 112262306a36Sopenharmony_ci * The caller can specify use of the "gang write" option of EPB, 112362306a36Sopenharmony_ci * in which case we use the specified channel data for any fields 112462306a36Sopenharmony_ci * not explicitely written. 112562306a36Sopenharmony_ci */ 112662306a36Sopenharmony_cistatic int ibsd_mod_allchnls(struct qib_devdata *dd, int loc, int val, 112762306a36Sopenharmony_ci int mask) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci int ret = -1; 113062306a36Sopenharmony_ci int chnl; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (loc & EPB_GLOBAL_WR) { 113362306a36Sopenharmony_ci /* 113462306a36Sopenharmony_ci * Our caller has assured us that we can set all four 113562306a36Sopenharmony_ci * channels at once. Trust that. If mask is not 0xFF, 113662306a36Sopenharmony_ci * we will read the _specified_ channel for our starting 113762306a36Sopenharmony_ci * value. 113862306a36Sopenharmony_ci */ 113962306a36Sopenharmony_ci loc |= (1U << EPB_IB_QUAD0_CS_SHF); 114062306a36Sopenharmony_ci chnl = (loc >> (4 + EPB_ADDR_SHF)) & 7; 114162306a36Sopenharmony_ci if (mask != 0xFF) { 114262306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, 114362306a36Sopenharmony_ci loc & ~EPB_GLOBAL_WR, 0, 0); 114462306a36Sopenharmony_ci if (ret < 0) { 114562306a36Sopenharmony_ci int sloc = loc >> EPB_ADDR_SHF; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci qib_dev_err(dd, 114862306a36Sopenharmony_ci "pre-read failed: elt %d, addr 0x%X, chnl %d\n", 114962306a36Sopenharmony_ci (sloc & 0xF), 115062306a36Sopenharmony_ci (sloc >> 9) & 0x3f, chnl); 115162306a36Sopenharmony_ci return ret; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci val = (ret & ~mask) | (val & mask); 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci loc &= ~(7 << (4+EPB_ADDR_SHF)); 115662306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, val, 0xFF); 115762306a36Sopenharmony_ci if (ret < 0) { 115862306a36Sopenharmony_ci int sloc = loc >> EPB_ADDR_SHF; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci qib_dev_err(dd, 116162306a36Sopenharmony_ci "Global WR failed: elt %d, addr 0x%X, val %02X\n", 116262306a36Sopenharmony_ci (sloc & 0xF), (sloc >> 9) & 0x3f, val); 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci return ret; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci /* Clear "channel" and set CS so we can simply iterate */ 116762306a36Sopenharmony_ci loc &= ~(7 << (4+EPB_ADDR_SHF)); 116862306a36Sopenharmony_ci loc |= (1U << EPB_IB_QUAD0_CS_SHF); 116962306a36Sopenharmony_ci for (chnl = 0; chnl < 4; ++chnl) { 117062306a36Sopenharmony_ci int cloc = loc | (chnl << (4+EPB_ADDR_SHF)); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, cloc, val, mask); 117362306a36Sopenharmony_ci if (ret < 0) { 117462306a36Sopenharmony_ci int sloc = loc >> EPB_ADDR_SHF; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci qib_dev_err(dd, 117762306a36Sopenharmony_ci "Write failed: elt %d, addr 0x%X, chnl %d, val 0x%02X, mask 0x%02X\n", 117862306a36Sopenharmony_ci (sloc & 0xF), (sloc >> 9) & 0x3f, chnl, 117962306a36Sopenharmony_ci val & 0xFF, mask & 0xFF); 118062306a36Sopenharmony_ci break; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci return ret; 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci/* 118762306a36Sopenharmony_ci * Set the Tx values normally modified by IBC in IB1.2 mode to default 118862306a36Sopenharmony_ci * values, as gotten from first row of init table. 118962306a36Sopenharmony_ci */ 119062306a36Sopenharmony_cistatic int set_dds_vals(struct qib_devdata *dd, struct dds_init *ddi) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci int ret; 119362306a36Sopenharmony_ci int idx, reg, data; 119462306a36Sopenharmony_ci uint32_t regmap; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci regmap = DDS_REG_MAP; 119762306a36Sopenharmony_ci for (idx = 0; idx < NUM_DDS_REGS; ++idx) { 119862306a36Sopenharmony_ci reg = (regmap & 0xF); 119962306a36Sopenharmony_ci regmap >>= 4; 120062306a36Sopenharmony_ci data = ddi->reg_vals[idx]; 120162306a36Sopenharmony_ci /* Vendor says RMW not needed for these regs, use 0xFF mask */ 120262306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, EPB_LOC(0, 9, reg), data, 0xFF); 120362306a36Sopenharmony_ci if (ret < 0) 120462306a36Sopenharmony_ci break; 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci return ret; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/* 121062306a36Sopenharmony_ci * Set the Rx values normally modified by IBC in IB1.2 mode to default 121162306a36Sopenharmony_ci * values, as gotten from selected column of init table. 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_cistatic int set_rxeq_vals(struct qib_devdata *dd, int vsel) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci int ret; 121662306a36Sopenharmony_ci int ridx; 121762306a36Sopenharmony_ci int cnt = ARRAY_SIZE(rxeq_init_vals); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci for (ridx = 0; ridx < cnt; ++ridx) { 122062306a36Sopenharmony_ci int elt, reg, val, loc; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci elt = rxeq_init_vals[ridx].rdesc & 0xF; 122362306a36Sopenharmony_ci reg = rxeq_init_vals[ridx].rdesc >> 4; 122462306a36Sopenharmony_ci loc = EPB_LOC(0, elt, reg); 122562306a36Sopenharmony_ci val = rxeq_init_vals[ridx].rdata[vsel]; 122662306a36Sopenharmony_ci /* mask of 0xFF, because hardware does full-byte store. */ 122762306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, loc, val, 0xFF); 122862306a36Sopenharmony_ci if (ret < 0) 122962306a36Sopenharmony_ci break; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci return ret; 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci/* 123562306a36Sopenharmony_ci * Set the default values (row 0) for DDR Driver Demphasis. 123662306a36Sopenharmony_ci * we do this initially and whenever we turn off IB-1.2 123762306a36Sopenharmony_ci * 123862306a36Sopenharmony_ci * The "default" values for Rx equalization are also stored to 123962306a36Sopenharmony_ci * SerDes registers. Formerly (and still default), we used set 2. 124062306a36Sopenharmony_ci * For experimenting with cables and link-partners, we allow changing 124162306a36Sopenharmony_ci * that via a module parameter. 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_cistatic unsigned qib_rxeq_set = 2; 124462306a36Sopenharmony_cimodule_param_named(rxeq_default_set, qib_rxeq_set, uint, 124562306a36Sopenharmony_ci S_IWUSR | S_IRUGO); 124662306a36Sopenharmony_ciMODULE_PARM_DESC(rxeq_default_set, 124762306a36Sopenharmony_ci "Which set [0..3] of Rx Equalization values is default"); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_cistatic int qib_internal_presets(struct qib_devdata *dd) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci int ret = 0; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci ret = set_dds_vals(dd, dds_init_vals + DDS_3M); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci if (ret < 0) 125662306a36Sopenharmony_ci qib_dev_err(dd, "Failed to set default DDS values\n"); 125762306a36Sopenharmony_ci ret = set_rxeq_vals(dd, qib_rxeq_set & 3); 125862306a36Sopenharmony_ci if (ret < 0) 125962306a36Sopenharmony_ci qib_dev_err(dd, "Failed to set default RXEQ values\n"); 126062306a36Sopenharmony_ci return ret; 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ciint qib_sd7220_presets(struct qib_devdata *dd) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci int ret = 0; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci if (!dd->cspec->presets_needed) 126862306a36Sopenharmony_ci return ret; 126962306a36Sopenharmony_ci dd->cspec->presets_needed = 0; 127062306a36Sopenharmony_ci /* Assert uC reset, so we don't clash with it. */ 127162306a36Sopenharmony_ci qib_ibsd_reset(dd, 1); 127262306a36Sopenharmony_ci udelay(2); 127362306a36Sopenharmony_ci qib_sd_trimdone_monitor(dd, "link-down"); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci ret = qib_internal_presets(dd); 127662306a36Sopenharmony_ci return ret; 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_cistatic int qib_sd_trimself(struct qib_devdata *dd, int val) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci int loc = CMUCTRL5 | (1U << EPB_IB_QUAD0_CS_SHF); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci return qib_sd7220_reg_mod(dd, IB_7220_SERDES, loc, val, 0xFF); 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic int qib_sd_early(struct qib_devdata *dd) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci int ret; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, RXHSCTRL0(0) | EPB_GLOBAL_WR, 0xD4, 0xFF); 129162306a36Sopenharmony_ci if (ret < 0) 129262306a36Sopenharmony_ci goto bail; 129362306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, START_EQ1(0) | EPB_GLOBAL_WR, 0x10, 0xFF); 129462306a36Sopenharmony_ci if (ret < 0) 129562306a36Sopenharmony_ci goto bail; 129662306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, START_EQ2(0) | EPB_GLOBAL_WR, 0x30, 0xFF); 129762306a36Sopenharmony_cibail: 129862306a36Sopenharmony_ci return ret; 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci#define BACTRL(chnl) EPB_LOC(chnl, 6, 0x0E) 130262306a36Sopenharmony_ci#define LDOUTCTRL1(chnl) EPB_LOC(chnl, 7, 6) 130362306a36Sopenharmony_ci#define RXHSSTATUS(chnl) EPB_LOC(chnl, 6, 0xF) 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cistatic int qib_sd_dactrim(struct qib_devdata *dd) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci int ret; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, VCDL_DAC2(0) | EPB_GLOBAL_WR, 0x2D, 0xFF); 131062306a36Sopenharmony_ci if (ret < 0) 131162306a36Sopenharmony_ci goto bail; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci /* more fine-tuning of what will be default */ 131462306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, VCDL_CTRL2(0), 3, 0xF); 131562306a36Sopenharmony_ci if (ret < 0) 131662306a36Sopenharmony_ci goto bail; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, BACTRL(0) | EPB_GLOBAL_WR, 0x40, 0xFF); 131962306a36Sopenharmony_ci if (ret < 0) 132062306a36Sopenharmony_ci goto bail; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, LDOUTCTRL1(0) | EPB_GLOBAL_WR, 0x04, 0xFF); 132362306a36Sopenharmony_ci if (ret < 0) 132462306a36Sopenharmony_ci goto bail; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, RXHSSTATUS(0) | EPB_GLOBAL_WR, 0x04, 0xFF); 132762306a36Sopenharmony_ci if (ret < 0) 132862306a36Sopenharmony_ci goto bail; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* 133162306a36Sopenharmony_ci * Delay for max possible number of steps, with slop. 133262306a36Sopenharmony_ci * Each step is about 4usec. 133362306a36Sopenharmony_ci */ 133462306a36Sopenharmony_ci udelay(415); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, LDOUTCTRL1(0) | EPB_GLOBAL_WR, 0x00, 0xFF); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_cibail: 133962306a36Sopenharmony_ci return ret; 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci#define RELOCK_FIRST_MS 3 134362306a36Sopenharmony_ci#define RXLSPPM(chan) EPB_LOC(chan, 0, 2) 134462306a36Sopenharmony_civoid toggle_7220_rclkrls(struct qib_devdata *dd) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci int loc = RXLSPPM(0) | EPB_GLOBAL_WR; 134762306a36Sopenharmony_ci int ret; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, loc, 0, 0x80); 135062306a36Sopenharmony_ci if (ret < 0) 135162306a36Sopenharmony_ci qib_dev_err(dd, "RCLKRLS failed to clear D7\n"); 135262306a36Sopenharmony_ci else { 135362306a36Sopenharmony_ci udelay(1); 135462306a36Sopenharmony_ci ibsd_mod_allchnls(dd, loc, 0x80, 0x80); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci /* And again for good measure */ 135762306a36Sopenharmony_ci udelay(1); 135862306a36Sopenharmony_ci ret = ibsd_mod_allchnls(dd, loc, 0, 0x80); 135962306a36Sopenharmony_ci if (ret < 0) 136062306a36Sopenharmony_ci qib_dev_err(dd, "RCLKRLS failed to clear D7\n"); 136162306a36Sopenharmony_ci else { 136262306a36Sopenharmony_ci udelay(1); 136362306a36Sopenharmony_ci ibsd_mod_allchnls(dd, loc, 0x80, 0x80); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci /* Now reset xgxs and IBC to complete the recovery */ 136662306a36Sopenharmony_ci dd->f_xgxs_reset(dd->pport); 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci/* 137062306a36Sopenharmony_ci * Shut down the timer that polls for relock occasions, if needed 137162306a36Sopenharmony_ci * this is "hooked" from qib_7220_quiet_serdes(), which is called 137262306a36Sopenharmony_ci * just before qib_shutdown_device() in qib_driver.c shuts down all 137362306a36Sopenharmony_ci * the other timers 137462306a36Sopenharmony_ci */ 137562306a36Sopenharmony_civoid shutdown_7220_relock_poll(struct qib_devdata *dd) 137662306a36Sopenharmony_ci{ 137762306a36Sopenharmony_ci if (dd->cspec->relock_timer_active) 137862306a36Sopenharmony_ci del_timer_sync(&dd->cspec->relock_timer); 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_cistatic unsigned qib_relock_by_timer = 1; 138262306a36Sopenharmony_cimodule_param_named(relock_by_timer, qib_relock_by_timer, uint, 138362306a36Sopenharmony_ci S_IWUSR | S_IRUGO); 138462306a36Sopenharmony_ciMODULE_PARM_DESC(relock_by_timer, "Allow relock attempt if link not up"); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic void qib_run_relock(struct timer_list *t) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci struct qib_chip_specific *cs = from_timer(cs, t, relock_timer); 138962306a36Sopenharmony_ci struct qib_devdata *dd = cs->dd; 139062306a36Sopenharmony_ci struct qib_pportdata *ppd = dd->pport; 139162306a36Sopenharmony_ci int timeoff; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* 139462306a36Sopenharmony_ci * Check link-training state for "stuck" state, when down. 139562306a36Sopenharmony_ci * if found, try relock and schedule another try at 139662306a36Sopenharmony_ci * exponentially growing delay, maxed at one second. 139762306a36Sopenharmony_ci * if not stuck, our work is done. 139862306a36Sopenharmony_ci */ 139962306a36Sopenharmony_ci if ((dd->flags & QIB_INITTED) && !(ppd->lflags & 140062306a36Sopenharmony_ci (QIBL_IB_AUTONEG_INPROG | QIBL_LINKINIT | QIBL_LINKARMED | 140162306a36Sopenharmony_ci QIBL_LINKACTIVE))) { 140262306a36Sopenharmony_ci if (qib_relock_by_timer) { 140362306a36Sopenharmony_ci if (!(ppd->lflags & QIBL_IB_LINK_DISABLED)) 140462306a36Sopenharmony_ci toggle_7220_rclkrls(dd); 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci /* re-set timer for next check */ 140762306a36Sopenharmony_ci timeoff = cs->relock_interval << 1; 140862306a36Sopenharmony_ci if (timeoff > HZ) 140962306a36Sopenharmony_ci timeoff = HZ; 141062306a36Sopenharmony_ci cs->relock_interval = timeoff; 141162306a36Sopenharmony_ci } else 141262306a36Sopenharmony_ci timeoff = HZ; 141362306a36Sopenharmony_ci mod_timer(&cs->relock_timer, jiffies + timeoff); 141462306a36Sopenharmony_ci} 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_civoid set_7220_relock_poll(struct qib_devdata *dd, int ibup) 141762306a36Sopenharmony_ci{ 141862306a36Sopenharmony_ci struct qib_chip_specific *cs = dd->cspec; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (ibup) { 142162306a36Sopenharmony_ci /* We are now up, relax timer to 1 second interval */ 142262306a36Sopenharmony_ci if (cs->relock_timer_active) { 142362306a36Sopenharmony_ci cs->relock_interval = HZ; 142462306a36Sopenharmony_ci mod_timer(&cs->relock_timer, jiffies + HZ); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci } else { 142762306a36Sopenharmony_ci /* Transition to down, (re-)set timer to short interval. */ 142862306a36Sopenharmony_ci unsigned int timeout; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci timeout = msecs_to_jiffies(RELOCK_FIRST_MS); 143162306a36Sopenharmony_ci if (timeout == 0) 143262306a36Sopenharmony_ci timeout = 1; 143362306a36Sopenharmony_ci /* If timer has not yet been started, do so. */ 143462306a36Sopenharmony_ci if (!cs->relock_timer_active) { 143562306a36Sopenharmony_ci cs->relock_timer_active = 1; 143662306a36Sopenharmony_ci timer_setup(&cs->relock_timer, qib_run_relock, 0); 143762306a36Sopenharmony_ci cs->relock_interval = timeout; 143862306a36Sopenharmony_ci cs->relock_timer.expires = jiffies + timeout; 143962306a36Sopenharmony_ci add_timer(&cs->relock_timer); 144062306a36Sopenharmony_ci } else { 144162306a36Sopenharmony_ci cs->relock_interval = timeout; 144262306a36Sopenharmony_ci mod_timer(&cs->relock_timer, jiffies + timeout); 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci} 1446