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