cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ael1002.c (23752B)


      1/*
      2 * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
      3 *
      4 * This software is available to you under a choice of one of two
      5 * licenses.  You may choose to be licensed under the terms of the GNU
      6 * General Public License (GPL) Version 2, available from the file
      7 * COPYING in the main directory of this source tree, or the
      8 * OpenIB.org BSD license below:
      9 *
     10 *     Redistribution and use in source and binary forms, with or
     11 *     without modification, are permitted provided that the following
     12 *     conditions are met:
     13 *
     14 *      - Redistributions of source code must retain the above
     15 *        copyright notice, this list of conditions and the following
     16 *        disclaimer.
     17 *
     18 *      - Redistributions in binary form must reproduce the above
     19 *        copyright notice, this list of conditions and the following
     20 *        disclaimer in the documentation and/or other materials
     21 *        provided with the distribution.
     22 *
     23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     30 * SOFTWARE.
     31 */
     32#include "common.h"
     33#include "regs.h"
     34
     35enum {
     36	AEL100X_TX_CONFIG1 = 0xc002,
     37	AEL1002_PWR_DOWN_HI = 0xc011,
     38	AEL1002_PWR_DOWN_LO = 0xc012,
     39	AEL1002_XFI_EQL = 0xc015,
     40	AEL1002_LB_EN = 0xc017,
     41	AEL_OPT_SETTINGS = 0xc017,
     42	AEL_I2C_CTRL = 0xc30a,
     43	AEL_I2C_DATA = 0xc30b,
     44	AEL_I2C_STAT = 0xc30c,
     45	AEL2005_GPIO_CTRL = 0xc214,
     46	AEL2005_GPIO_STAT = 0xc215,
     47
     48	AEL2020_GPIO_INTR   = 0xc103,	/* Latch High (LH) */
     49	AEL2020_GPIO_CTRL   = 0xc108,	/* Store Clear (SC) */
     50	AEL2020_GPIO_STAT   = 0xc10c,	/* Read Only (RO) */
     51	AEL2020_GPIO_CFG    = 0xc110,	/* Read Write (RW) */
     52
     53	AEL2020_GPIO_SDA    = 0,	/* IN: i2c serial data */
     54	AEL2020_GPIO_MODDET = 1,	/* IN: Module Detect */
     55	AEL2020_GPIO_0      = 3,	/* IN: unassigned */
     56	AEL2020_GPIO_1      = 2,	/* OUT: unassigned */
     57	AEL2020_GPIO_LSTAT  = AEL2020_GPIO_1, /* wired to link status LED */
     58};
     59
     60enum { edc_none, edc_sr, edc_twinax };
     61
     62/* PHY module I2C device address */
     63enum {
     64	MODULE_DEV_ADDR	= 0xa0,
     65	SFF_DEV_ADDR	= 0xa2,
     66};
     67
     68/* PHY transceiver type */
     69enum {
     70	phy_transtype_unknown = 0,
     71	phy_transtype_sfp     = 3,
     72	phy_transtype_xfp     = 6,
     73};
     74
     75#define AEL2005_MODDET_IRQ 4
     76
     77struct reg_val {
     78	unsigned short mmd_addr;
     79	unsigned short reg_addr;
     80	unsigned short clear_bits;
     81	unsigned short set_bits;
     82};
     83
     84static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
     85{
     86	int err;
     87
     88	for (err = 0; rv->mmd_addr && !err; rv++) {
     89		if (rv->clear_bits == 0xffff)
     90			err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr,
     91					    rv->set_bits);
     92		else
     93			err = t3_mdio_change_bits(phy, rv->mmd_addr,
     94						  rv->reg_addr, rv->clear_bits,
     95						  rv->set_bits);
     96	}
     97	return err;
     98}
     99
    100static void ael100x_txon(struct cphy *phy)
    101{
    102	int tx_on_gpio =
    103		phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
    104
    105	msleep(100);
    106	t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
    107	msleep(30);
    108}
    109
    110/*
    111 * Read an 8-bit word from a device attached to the PHY's i2c bus.
    112 */
    113static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
    114{
    115	int i, err;
    116	unsigned int stat, data;
    117
    118	err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL,
    119			    (dev_addr << 8) | (1 << 8) | word_addr);
    120	if (err)
    121		return err;
    122
    123	for (i = 0; i < 200; i++) {
    124		msleep(1);
    125		err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat);
    126		if (err)
    127			return err;
    128		if ((stat & 3) == 1) {
    129			err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA,
    130					   &data);
    131			if (err)
    132				return err;
    133			return data >> 8;
    134		}
    135	}
    136	CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n",
    137		phy->mdio.prtad, dev_addr, word_addr);
    138	return -ETIMEDOUT;
    139}
    140
    141static int ael1002_power_down(struct cphy *phy, int enable)
    142{
    143	int err;
    144
    145	err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable);
    146	if (!err)
    147		err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
    148				    MDIO_MMD_PMAPMD, MDIO_CTRL1,
    149				    MDIO_CTRL1_LPOWER, enable);
    150	return err;
    151}
    152
    153static int ael1002_reset(struct cphy *phy, int wait)
    154{
    155	int err;
    156
    157	if ((err = ael1002_power_down(phy, 0)) ||
    158	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) ||
    159	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) ||
    160	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) ||
    161	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) ||
    162	    (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN,
    163				       0, 1 << 5)))
    164		return err;
    165	return 0;
    166}
    167
    168static int ael1002_intr_noop(struct cphy *phy)
    169{
    170	return 0;
    171}
    172
    173/*
    174 * Get link status for a 10GBASE-R device.
    175 */
    176static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed,
    177			     int *duplex, int *fc)
    178{
    179	if (link_ok) {
    180		unsigned int stat0, stat1, stat2;
    181		int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
    182				       MDIO_PMA_RXDET, &stat0);
    183
    184		if (!err)
    185			err = t3_mdio_read(phy, MDIO_MMD_PCS,
    186					   MDIO_PCS_10GBRT_STAT1, &stat1);
    187		if (!err)
    188			err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
    189					   MDIO_PHYXS_LNSTAT, &stat2);
    190		if (err)
    191			return err;
    192		*link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1;
    193	}
    194	if (speed)
    195		*speed = SPEED_10000;
    196	if (duplex)
    197		*duplex = DUPLEX_FULL;
    198	return 0;
    199}
    200
    201static const struct cphy_ops ael1002_ops = {
    202	.reset = ael1002_reset,
    203	.intr_enable = ael1002_intr_noop,
    204	.intr_disable = ael1002_intr_noop,
    205	.intr_clear = ael1002_intr_noop,
    206	.intr_handler = ael1002_intr_noop,
    207	.get_link_status = get_link_status_r,
    208	.power_down = ael1002_power_down,
    209	.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
    210};
    211
    212int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
    213			int phy_addr, const struct mdio_ops *mdio_ops)
    214{
    215	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
    216		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
    217		   "10GBASE-R");
    218	ael100x_txon(phy);
    219	return 0;
    220}
    221
    222static int ael1006_reset(struct cphy *phy, int wait)
    223{
    224	return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
    225}
    226
    227static const struct cphy_ops ael1006_ops = {
    228	.reset = ael1006_reset,
    229	.intr_enable = t3_phy_lasi_intr_enable,
    230	.intr_disable = t3_phy_lasi_intr_disable,
    231	.intr_clear = t3_phy_lasi_intr_clear,
    232	.intr_handler = t3_phy_lasi_intr_handler,
    233	.get_link_status = get_link_status_r,
    234	.power_down = ael1002_power_down,
    235	.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
    236};
    237
    238int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
    239			     int phy_addr, const struct mdio_ops *mdio_ops)
    240{
    241	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
    242		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
    243		   "10GBASE-SR");
    244	ael100x_txon(phy);
    245	return 0;
    246}
    247
    248/*
    249 * Decode our module type.
    250 */
    251static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms)
    252{
    253	int v;
    254
    255	if (delay_ms)
    256		msleep(delay_ms);
    257
    258	/* see SFF-8472 for below */
    259	v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3);
    260	if (v < 0)
    261		return v;
    262
    263	if (v == 0x10)
    264		return phy_modtype_sr;
    265	if (v == 0x20)
    266		return phy_modtype_lr;
    267	if (v == 0x40)
    268		return phy_modtype_lrm;
    269
    270	v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6);
    271	if (v < 0)
    272		return v;
    273	if (v != 4)
    274		goto unknown;
    275
    276	v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10);
    277	if (v < 0)
    278		return v;
    279
    280	if (v & 0x80) {
    281		v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
    282		if (v < 0)
    283			return v;
    284		return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
    285	}
    286unknown:
    287	return phy_modtype_unknown;
    288}
    289
    290/*
    291 * Code to support the Aeluros/NetLogic 2005 10Gb PHY.
    292 */
    293static int ael2005_setup_sr_edc(struct cphy *phy)
    294{
    295	static const struct reg_val regs[] = {
    296		{ MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 },
    297		{ MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a },
    298		{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
    299		{ 0, 0, 0, 0 }
    300	};
    301
    302	int i, err;
    303
    304	err = set_phy_regs(phy, regs);
    305	if (err)
    306		return err;
    307
    308	msleep(50);
    309
    310	if (phy->priv != edc_sr)
    311		err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
    312				    EDC_OPT_AEL2005_SIZE);
    313	if (err)
    314		return err;
    315
    316	for (i = 0; i <  EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
    317		err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
    318				    phy->phy_cache[i],
    319				    phy->phy_cache[i + 1]);
    320	if (!err)
    321		phy->priv = edc_sr;
    322	return err;
    323}
    324
    325static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
    326{
    327	static const struct reg_val regs[] = {
    328		{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 },
    329		{ 0, 0, 0, 0 }
    330	};
    331	static const struct reg_val preemphasis[] = {
    332		{ MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 },
    333		{ MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
    334		{ 0, 0, 0, 0 }
    335	};
    336	int i, err;
    337
    338	err = set_phy_regs(phy, regs);
    339	if (!err && modtype == phy_modtype_twinax_long)
    340		err = set_phy_regs(phy, preemphasis);
    341	if (err)
    342		return err;
    343
    344	msleep(50);
    345
    346	if (phy->priv != edc_twinax)
    347		err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
    348				    EDC_TWX_AEL2005_SIZE);
    349	if (err)
    350		return err;
    351
    352	for (i = 0; i <  EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
    353		err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
    354				    phy->phy_cache[i],
    355				    phy->phy_cache[i + 1]);
    356	if (!err)
    357		phy->priv = edc_twinax;
    358	return err;
    359}
    360
    361static int ael2005_get_module_type(struct cphy *phy, int delay_ms)
    362{
    363	int v;
    364	unsigned int stat;
    365
    366	v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat);
    367	if (v)
    368		return v;
    369
    370	if (stat & (1 << 8))			/* module absent */
    371		return phy_modtype_none;
    372
    373	return ael2xxx_get_module_type(phy, delay_ms);
    374}
    375
    376static int ael2005_intr_enable(struct cphy *phy)
    377{
    378	int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x200);
    379	return err ? err : t3_phy_lasi_intr_enable(phy);
    380}
    381
    382static int ael2005_intr_disable(struct cphy *phy)
    383{
    384	int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x100);
    385	return err ? err : t3_phy_lasi_intr_disable(phy);
    386}
    387
    388static int ael2005_intr_clear(struct cphy *phy)
    389{
    390	int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0xd00);
    391	return err ? err : t3_phy_lasi_intr_clear(phy);
    392}
    393
    394static int ael2005_reset(struct cphy *phy, int wait)
    395{
    396	static const struct reg_val regs0[] = {
    397		{ MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 },
    398		{ MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 },
    399		{ MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 },
    400		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
    401		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 },
    402		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
    403		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 },
    404		{ 0, 0, 0, 0 }
    405	};
    406	static const struct reg_val regs1[] = {
    407		{ MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 },
    408		{ MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 },
    409		{ 0, 0, 0, 0 }
    410	};
    411
    412	int err;
    413	unsigned int lasi_ctrl;
    414
    415	err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
    416			   &lasi_ctrl);
    417	if (err)
    418		return err;
    419
    420	err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0);
    421	if (err)
    422		return err;
    423
    424	msleep(125);
    425	phy->priv = edc_none;
    426	err = set_phy_regs(phy, regs0);
    427	if (err)
    428		return err;
    429
    430	msleep(50);
    431
    432	err = ael2005_get_module_type(phy, 0);
    433	if (err < 0)
    434		return err;
    435	phy->modtype = err;
    436
    437	if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
    438		err = ael2005_setup_twinax_edc(phy, err);
    439	else
    440		err = ael2005_setup_sr_edc(phy);
    441	if (err)
    442		return err;
    443
    444	err = set_phy_regs(phy, regs1);
    445	if (err)
    446		return err;
    447
    448	/* reset wipes out interrupts, reenable them if they were on */
    449	if (lasi_ctrl & 1)
    450		err = ael2005_intr_enable(phy);
    451	return err;
    452}
    453
    454static int ael2005_intr_handler(struct cphy *phy)
    455{
    456	unsigned int stat;
    457	int ret, edc_needed, cause = 0;
    458
    459	ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_STAT, &stat);
    460	if (ret)
    461		return ret;
    462
    463	if (stat & AEL2005_MODDET_IRQ) {
    464		ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL,
    465				    0xd00);
    466		if (ret)
    467			return ret;
    468
    469		/* modules have max 300 ms init time after hot plug */
    470		ret = ael2005_get_module_type(phy, 300);
    471		if (ret < 0)
    472			return ret;
    473
    474		phy->modtype = ret;
    475		if (ret == phy_modtype_none)
    476			edc_needed = phy->priv;       /* on unplug retain EDC */
    477		else if (ret == phy_modtype_twinax ||
    478			 ret == phy_modtype_twinax_long)
    479			edc_needed = edc_twinax;
    480		else
    481			edc_needed = edc_sr;
    482
    483		if (edc_needed != phy->priv) {
    484			ret = ael2005_reset(phy, 0);
    485			return ret ? ret : cphy_cause_module_change;
    486		}
    487		cause = cphy_cause_module_change;
    488	}
    489
    490	ret = t3_phy_lasi_intr_handler(phy);
    491	if (ret < 0)
    492		return ret;
    493
    494	ret |= cause;
    495	return ret ? ret : cphy_cause_link_change;
    496}
    497
    498static const struct cphy_ops ael2005_ops = {
    499	.reset           = ael2005_reset,
    500	.intr_enable     = ael2005_intr_enable,
    501	.intr_disable    = ael2005_intr_disable,
    502	.intr_clear      = ael2005_intr_clear,
    503	.intr_handler    = ael2005_intr_handler,
    504	.get_link_status = get_link_status_r,
    505	.power_down      = ael1002_power_down,
    506	.mmds            = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
    507};
    508
    509int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
    510			int phy_addr, const struct mdio_ops *mdio_ops)
    511{
    512	cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
    513		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
    514		  SUPPORTED_IRQ, "10GBASE-R");
    515	msleep(125);
    516	return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0,
    517				   1 << 5);
    518}
    519
    520/*
    521 * Setup EDC and other parameters for operation with an optical module.
    522 */
    523static int ael2020_setup_sr_edc(struct cphy *phy)
    524{
    525	static const struct reg_val regs[] = {
    526		/* set CDR offset to 10 */
    527		{ MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a },
    528
    529		/* adjust 10G RX bias current */
    530		{ MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 },
    531		{ MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 },
    532		{ MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 },
    533
    534		/* end */
    535		{ 0, 0, 0, 0 }
    536	};
    537	int err;
    538
    539	err = set_phy_regs(phy, regs);
    540	msleep(50);
    541	if (err)
    542		return err;
    543
    544	phy->priv = edc_sr;
    545	return 0;
    546}
    547
    548/*
    549 * Setup EDC and other parameters for operation with an TWINAX module.
    550 */
    551static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
    552{
    553	/* set uC to 40MHz */
    554	static const struct reg_val uCclock40MHz[] = {
    555		{ MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 },
    556		{ MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 },
    557		{ 0, 0, 0, 0 }
    558	};
    559
    560	/* activate uC clock */
    561	static const struct reg_val uCclockActivate[] = {
    562		{ MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 },
    563		{ 0, 0, 0, 0 }
    564	};
    565
    566	/* set PC to start of SRAM and activate uC */
    567	static const struct reg_val uCactivate[] = {
    568		{ MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 },
    569		{ MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
    570		{ 0, 0, 0, 0 }
    571	};
    572	int i, err;
    573
    574	/* set uC clock and activate it */
    575	err = set_phy_regs(phy, uCclock40MHz);
    576	msleep(500);
    577	if (err)
    578		return err;
    579	err = set_phy_regs(phy, uCclockActivate);
    580	msleep(500);
    581	if (err)
    582		return err;
    583
    584	if (phy->priv != edc_twinax)
    585		err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
    586				    EDC_TWX_AEL2020_SIZE);
    587	if (err)
    588		return err;
    589
    590	for (i = 0; i <  EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
    591		err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
    592				    phy->phy_cache[i],
    593				    phy->phy_cache[i + 1]);
    594	/* activate uC */
    595	err = set_phy_regs(phy, uCactivate);
    596	if (!err)
    597		phy->priv = edc_twinax;
    598	return err;
    599}
    600
    601/*
    602 * Return Module Type.
    603 */
    604static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
    605{
    606	int v;
    607	unsigned int stat;
    608
    609	v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat);
    610	if (v)
    611		return v;
    612
    613	if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) {
    614		/* module absent */
    615		return phy_modtype_none;
    616	}
    617
    618	return ael2xxx_get_module_type(phy, delay_ms);
    619}
    620
    621/*
    622 * Enable PHY interrupts.  We enable "Module Detection" interrupts (on any
    623 * state transition) and then generic Link Alarm Status Interrupt (LASI).
    624 */
    625static int ael2020_intr_enable(struct cphy *phy)
    626{
    627	static const struct reg_val regs[] = {
    628		/* output Module's Loss Of Signal (LOS) to LED */
    629		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
    630			0xffff, 0x4 },
    631		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
    632			0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
    633
    634		 /* enable module detect status change interrupts */
    635		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
    636			0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
    637
    638		/* end */
    639		{ 0, 0, 0, 0 }
    640	};
    641	int err, link_ok = 0;
    642
    643	/* set up "link status" LED and enable module change interrupts */
    644	err = set_phy_regs(phy, regs);
    645	if (err)
    646		return err;
    647
    648	err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
    649	if (err)
    650		return err;
    651	if (link_ok)
    652		t3_link_changed(phy->adapter,
    653				phy2portid(phy));
    654
    655	err = t3_phy_lasi_intr_enable(phy);
    656	if (err)
    657		return err;
    658
    659	return 0;
    660}
    661
    662/*
    663 * Disable PHY interrupts.  The mirror of the above ...
    664 */
    665static int ael2020_intr_disable(struct cphy *phy)
    666{
    667	static const struct reg_val regs[] = {
    668		/* reset "link status" LED to "off" */
    669		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
    670			0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
    671
    672		/* disable module detect status change interrupts */
    673		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
    674			0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
    675
    676		/* end */
    677		{ 0, 0, 0, 0 }
    678	};
    679	int err;
    680
    681	/* turn off "link status" LED and disable module change interrupts */
    682	err = set_phy_regs(phy, regs);
    683	if (err)
    684		return err;
    685
    686	return t3_phy_lasi_intr_disable(phy);
    687}
    688
    689/*
    690 * Clear PHY interrupt state.
    691 */
    692static int ael2020_intr_clear(struct cphy *phy)
    693{
    694	/*
    695	 * The GPIO Interrupt register on the AEL2020 is a "Latching High"
    696	 * (LH) register which is cleared to the current state when it's read.
    697	 * Thus, we simply read the register and discard the result.
    698	 */
    699	unsigned int stat;
    700	int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
    701	return err ? err : t3_phy_lasi_intr_clear(phy);
    702}
    703
    704static const struct reg_val ael2020_reset_regs[] = {
    705	/* Erratum #2: CDRLOL asserted, causing PMA link down status */
    706	{ MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
    707
    708	/* force XAUI to send LF when RX_LOS is asserted */
    709	{ MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
    710
    711	/* allow writes to transceiver module EEPROM on i2c bus */
    712	{ MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
    713	{ MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
    714	{ MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
    715
    716	/* end */
    717	{ 0, 0, 0, 0 }
    718};
    719/*
    720 * Reset the PHY and put it into a canonical operating state.
    721 */
    722static int ael2020_reset(struct cphy *phy, int wait)
    723{
    724	int err;
    725	unsigned int lasi_ctrl;
    726
    727	/* grab current interrupt state */
    728	err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
    729			   &lasi_ctrl);
    730	if (err)
    731		return err;
    732
    733	err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125);
    734	if (err)
    735		return err;
    736	msleep(100);
    737
    738	/* basic initialization for all module types */
    739	phy->priv = edc_none;
    740	err = set_phy_regs(phy, ael2020_reset_regs);
    741	if (err)
    742		return err;
    743
    744	/* determine module type and perform appropriate initialization */
    745	err = ael2020_get_module_type(phy, 0);
    746	if (err < 0)
    747		return err;
    748	phy->modtype = (u8)err;
    749	if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
    750		err = ael2020_setup_twinax_edc(phy, err);
    751	else
    752		err = ael2020_setup_sr_edc(phy);
    753	if (err)
    754		return err;
    755
    756	/* reset wipes out interrupts, reenable them if they were on */
    757	if (lasi_ctrl & 1)
    758		err = ael2005_intr_enable(phy);
    759	return err;
    760}
    761
    762/*
    763 * Handle a PHY interrupt.
    764 */
    765static int ael2020_intr_handler(struct cphy *phy)
    766{
    767	unsigned int stat;
    768	int ret, edc_needed, cause = 0;
    769
    770	ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
    771	if (ret)
    772		return ret;
    773
    774	if (stat & (0x1 << AEL2020_GPIO_MODDET)) {
    775		/* modules have max 300 ms init time after hot plug */
    776		ret = ael2020_get_module_type(phy, 300);
    777		if (ret < 0)
    778			return ret;
    779
    780		phy->modtype = (u8)ret;
    781		if (ret == phy_modtype_none)
    782			edc_needed = phy->priv;       /* on unplug retain EDC */
    783		else if (ret == phy_modtype_twinax ||
    784			 ret == phy_modtype_twinax_long)
    785			edc_needed = edc_twinax;
    786		else
    787			edc_needed = edc_sr;
    788
    789		if (edc_needed != phy->priv) {
    790			ret = ael2020_reset(phy, 0);
    791			return ret ? ret : cphy_cause_module_change;
    792		}
    793		cause = cphy_cause_module_change;
    794	}
    795
    796	ret = t3_phy_lasi_intr_handler(phy);
    797	if (ret < 0)
    798		return ret;
    799
    800	ret |= cause;
    801	return ret ? ret : cphy_cause_link_change;
    802}
    803
    804static const struct cphy_ops ael2020_ops = {
    805	.reset           = ael2020_reset,
    806	.intr_enable     = ael2020_intr_enable,
    807	.intr_disable    = ael2020_intr_disable,
    808	.intr_clear      = ael2020_intr_clear,
    809	.intr_handler    = ael2020_intr_handler,
    810	.get_link_status = get_link_status_r,
    811	.power_down      = ael1002_power_down,
    812	.mmds		 = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
    813};
    814
    815int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
    816			const struct mdio_ops *mdio_ops)
    817{
    818	cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
    819		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
    820		  SUPPORTED_IRQ, "10GBASE-R");
    821	msleep(125);
    822
    823	return set_phy_regs(phy, ael2020_reset_regs);
    824}
    825
    826/*
    827 * Get link status for a 10GBASE-X device.
    828 */
    829static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
    830			     int *duplex, int *fc)
    831{
    832	if (link_ok) {
    833		unsigned int stat0, stat1, stat2;
    834		int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
    835				       MDIO_PMA_RXDET, &stat0);
    836
    837		if (!err)
    838			err = t3_mdio_read(phy, MDIO_MMD_PCS,
    839					   MDIO_PCS_10GBX_STAT1, &stat1);
    840		if (!err)
    841			err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
    842					   MDIO_PHYXS_LNSTAT, &stat2);
    843		if (err)
    844			return err;
    845		*link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1;
    846	}
    847	if (speed)
    848		*speed = SPEED_10000;
    849	if (duplex)
    850		*duplex = DUPLEX_FULL;
    851	return 0;
    852}
    853
    854static const struct cphy_ops qt2045_ops = {
    855	.reset = ael1006_reset,
    856	.intr_enable = t3_phy_lasi_intr_enable,
    857	.intr_disable = t3_phy_lasi_intr_disable,
    858	.intr_clear = t3_phy_lasi_intr_clear,
    859	.intr_handler = t3_phy_lasi_intr_handler,
    860	.get_link_status = get_link_status_x,
    861	.power_down = ael1002_power_down,
    862	.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
    863};
    864
    865int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
    866		       int phy_addr, const struct mdio_ops *mdio_ops)
    867{
    868	unsigned int stat;
    869
    870	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
    871		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
    872		  "10GBASE-CX4");
    873
    874	/*
    875	 * Some cards where the PHY is supposed to be at address 0 actually
    876	 * have it at 1.
    877	 */
    878	if (!phy_addr &&
    879	    !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) &&
    880	    stat == 0xffff)
    881		phy->mdio.prtad = 1;
    882	return 0;
    883}
    884
    885static int xaui_direct_reset(struct cphy *phy, int wait)
    886{
    887	return 0;
    888}
    889
    890static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
    891				       int *speed, int *duplex, int *fc)
    892{
    893	if (link_ok) {
    894		unsigned int status;
    895		int prtad = phy->mdio.prtad;
    896
    897		status = t3_read_reg(phy->adapter,
    898				     XGM_REG(A_XGM_SERDES_STAT0, prtad)) |
    899		    t3_read_reg(phy->adapter,
    900				    XGM_REG(A_XGM_SERDES_STAT1, prtad)) |
    901		    t3_read_reg(phy->adapter,
    902				XGM_REG(A_XGM_SERDES_STAT2, prtad)) |
    903		    t3_read_reg(phy->adapter,
    904				XGM_REG(A_XGM_SERDES_STAT3, prtad));
    905		*link_ok = !(status & F_LOWSIG0);
    906	}
    907	if (speed)
    908		*speed = SPEED_10000;
    909	if (duplex)
    910		*duplex = DUPLEX_FULL;
    911	return 0;
    912}
    913
    914static int xaui_direct_power_down(struct cphy *phy, int enable)
    915{
    916	return 0;
    917}
    918
    919static const struct cphy_ops xaui_direct_ops = {
    920	.reset = xaui_direct_reset,
    921	.intr_enable = ael1002_intr_noop,
    922	.intr_disable = ael1002_intr_noop,
    923	.intr_clear = ael1002_intr_noop,
    924	.intr_handler = ael1002_intr_noop,
    925	.get_link_status = xaui_direct_get_link_status,
    926	.power_down = xaui_direct_power_down,
    927};
    928
    929int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
    930			    int phy_addr, const struct mdio_ops *mdio_ops)
    931{
    932	cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
    933		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
    934		  "10GBASE-CX4");
    935	return 0;
    936}