0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #include "common.h"
0033 #include "regs.h"
0034
0035 enum {
0036 AEL100X_TX_CONFIG1 = 0xc002,
0037 AEL1002_PWR_DOWN_HI = 0xc011,
0038 AEL1002_PWR_DOWN_LO = 0xc012,
0039 AEL1002_XFI_EQL = 0xc015,
0040 AEL1002_LB_EN = 0xc017,
0041 AEL_OPT_SETTINGS = 0xc017,
0042 AEL_I2C_CTRL = 0xc30a,
0043 AEL_I2C_DATA = 0xc30b,
0044 AEL_I2C_STAT = 0xc30c,
0045 AEL2005_GPIO_CTRL = 0xc214,
0046 AEL2005_GPIO_STAT = 0xc215,
0047
0048 AEL2020_GPIO_INTR = 0xc103,
0049 AEL2020_GPIO_CTRL = 0xc108,
0050 AEL2020_GPIO_STAT = 0xc10c,
0051 AEL2020_GPIO_CFG = 0xc110,
0052
0053 AEL2020_GPIO_SDA = 0,
0054 AEL2020_GPIO_MODDET = 1,
0055 AEL2020_GPIO_0 = 3,
0056 AEL2020_GPIO_1 = 2,
0057 AEL2020_GPIO_LSTAT = AEL2020_GPIO_1,
0058 };
0059
0060 enum { edc_none, edc_sr, edc_twinax };
0061
0062
0063 enum {
0064 MODULE_DEV_ADDR = 0xa0,
0065 SFF_DEV_ADDR = 0xa2,
0066 };
0067
0068
0069 enum {
0070 phy_transtype_unknown = 0,
0071 phy_transtype_sfp = 3,
0072 phy_transtype_xfp = 6,
0073 };
0074
0075 #define AEL2005_MODDET_IRQ 4
0076
0077 struct reg_val {
0078 unsigned short mmd_addr;
0079 unsigned short reg_addr;
0080 unsigned short clear_bits;
0081 unsigned short set_bits;
0082 };
0083
0084 static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
0085 {
0086 int err;
0087
0088 for (err = 0; rv->mmd_addr && !err; rv++) {
0089 if (rv->clear_bits == 0xffff)
0090 err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr,
0091 rv->set_bits);
0092 else
0093 err = t3_mdio_change_bits(phy, rv->mmd_addr,
0094 rv->reg_addr, rv->clear_bits,
0095 rv->set_bits);
0096 }
0097 return err;
0098 }
0099
0100 static void ael100x_txon(struct cphy *phy)
0101 {
0102 int tx_on_gpio =
0103 phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
0104
0105 msleep(100);
0106 t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
0107 msleep(30);
0108 }
0109
0110
0111
0112
0113 static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
0114 {
0115 int i, err;
0116 unsigned int stat, data;
0117
0118 err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL,
0119 (dev_addr << 8) | (1 << 8) | word_addr);
0120 if (err)
0121 return err;
0122
0123 for (i = 0; i < 200; i++) {
0124 msleep(1);
0125 err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat);
0126 if (err)
0127 return err;
0128 if ((stat & 3) == 1) {
0129 err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA,
0130 &data);
0131 if (err)
0132 return err;
0133 return data >> 8;
0134 }
0135 }
0136 CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n",
0137 phy->mdio.prtad, dev_addr, word_addr);
0138 return -ETIMEDOUT;
0139 }
0140
0141 static int ael1002_power_down(struct cphy *phy, int enable)
0142 {
0143 int err;
0144
0145 err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable);
0146 if (!err)
0147 err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
0148 MDIO_MMD_PMAPMD, MDIO_CTRL1,
0149 MDIO_CTRL1_LPOWER, enable);
0150 return err;
0151 }
0152
0153 static int ael1002_reset(struct cphy *phy, int wait)
0154 {
0155 int err;
0156
0157 if ((err = ael1002_power_down(phy, 0)) ||
0158 (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) ||
0159 (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) ||
0160 (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) ||
0161 (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) ||
0162 (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN,
0163 0, 1 << 5)))
0164 return err;
0165 return 0;
0166 }
0167
0168 static int ael1002_intr_noop(struct cphy *phy)
0169 {
0170 return 0;
0171 }
0172
0173
0174
0175
0176 static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed,
0177 int *duplex, int *fc)
0178 {
0179 if (link_ok) {
0180 unsigned int stat0, stat1, stat2;
0181 int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
0182 MDIO_PMA_RXDET, &stat0);
0183
0184 if (!err)
0185 err = t3_mdio_read(phy, MDIO_MMD_PCS,
0186 MDIO_PCS_10GBRT_STAT1, &stat1);
0187 if (!err)
0188 err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
0189 MDIO_PHYXS_LNSTAT, &stat2);
0190 if (err)
0191 return err;
0192 *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1;
0193 }
0194 if (speed)
0195 *speed = SPEED_10000;
0196 if (duplex)
0197 *duplex = DUPLEX_FULL;
0198 return 0;
0199 }
0200
0201 static const struct cphy_ops ael1002_ops = {
0202 .reset = ael1002_reset,
0203 .intr_enable = ael1002_intr_noop,
0204 .intr_disable = ael1002_intr_noop,
0205 .intr_clear = ael1002_intr_noop,
0206 .intr_handler = ael1002_intr_noop,
0207 .get_link_status = get_link_status_r,
0208 .power_down = ael1002_power_down,
0209 .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
0210 };
0211
0212 int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
0213 int phy_addr, const struct mdio_ops *mdio_ops)
0214 {
0215 cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
0216 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
0217 "10GBASE-R");
0218 ael100x_txon(phy);
0219 return 0;
0220 }
0221
0222 static int ael1006_reset(struct cphy *phy, int wait)
0223 {
0224 return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
0225 }
0226
0227 static const struct cphy_ops ael1006_ops = {
0228 .reset = ael1006_reset,
0229 .intr_enable = t3_phy_lasi_intr_enable,
0230 .intr_disable = t3_phy_lasi_intr_disable,
0231 .intr_clear = t3_phy_lasi_intr_clear,
0232 .intr_handler = t3_phy_lasi_intr_handler,
0233 .get_link_status = get_link_status_r,
0234 .power_down = ael1002_power_down,
0235 .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
0236 };
0237
0238 int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
0239 int phy_addr, const struct mdio_ops *mdio_ops)
0240 {
0241 cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
0242 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
0243 "10GBASE-SR");
0244 ael100x_txon(phy);
0245 return 0;
0246 }
0247
0248
0249
0250
0251 static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms)
0252 {
0253 int v;
0254
0255 if (delay_ms)
0256 msleep(delay_ms);
0257
0258
0259 v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3);
0260 if (v < 0)
0261 return v;
0262
0263 if (v == 0x10)
0264 return phy_modtype_sr;
0265 if (v == 0x20)
0266 return phy_modtype_lr;
0267 if (v == 0x40)
0268 return phy_modtype_lrm;
0269
0270 v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6);
0271 if (v < 0)
0272 return v;
0273 if (v != 4)
0274 goto unknown;
0275
0276 v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10);
0277 if (v < 0)
0278 return v;
0279
0280 if (v & 0x80) {
0281 v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
0282 if (v < 0)
0283 return v;
0284 return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
0285 }
0286 unknown:
0287 return phy_modtype_unknown;
0288 }
0289
0290
0291
0292
0293 static int ael2005_setup_sr_edc(struct cphy *phy)
0294 {
0295 static const struct reg_val regs[] = {
0296 { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 },
0297 { MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a },
0298 { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
0299 { 0, 0, 0, 0 }
0300 };
0301
0302 int i, err;
0303
0304 err = set_phy_regs(phy, regs);
0305 if (err)
0306 return err;
0307
0308 msleep(50);
0309
0310 if (phy->priv != edc_sr)
0311 err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
0312 EDC_OPT_AEL2005_SIZE);
0313 if (err)
0314 return err;
0315
0316 for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
0317 err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
0318 phy->phy_cache[i],
0319 phy->phy_cache[i + 1]);
0320 if (!err)
0321 phy->priv = edc_sr;
0322 return err;
0323 }
0324
0325 static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
0326 {
0327 static const struct reg_val regs[] = {
0328 { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 },
0329 { 0, 0, 0, 0 }
0330 };
0331 static const struct reg_val preemphasis[] = {
0332 { MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 },
0333 { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
0334 { 0, 0, 0, 0 }
0335 };
0336 int i, err;
0337
0338 err = set_phy_regs(phy, regs);
0339 if (!err && modtype == phy_modtype_twinax_long)
0340 err = set_phy_regs(phy, preemphasis);
0341 if (err)
0342 return err;
0343
0344 msleep(50);
0345
0346 if (phy->priv != edc_twinax)
0347 err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
0348 EDC_TWX_AEL2005_SIZE);
0349 if (err)
0350 return err;
0351
0352 for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
0353 err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
0354 phy->phy_cache[i],
0355 phy->phy_cache[i + 1]);
0356 if (!err)
0357 phy->priv = edc_twinax;
0358 return err;
0359 }
0360
0361 static int ael2005_get_module_type(struct cphy *phy, int delay_ms)
0362 {
0363 int v;
0364 unsigned int stat;
0365
0366 v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat);
0367 if (v)
0368 return v;
0369
0370 if (stat & (1 << 8))
0371 return phy_modtype_none;
0372
0373 return ael2xxx_get_module_type(phy, delay_ms);
0374 }
0375
0376 static int ael2005_intr_enable(struct cphy *phy)
0377 {
0378 int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x200);
0379 return err ? err : t3_phy_lasi_intr_enable(phy);
0380 }
0381
0382 static int ael2005_intr_disable(struct cphy *phy)
0383 {
0384 int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x100);
0385 return err ? err : t3_phy_lasi_intr_disable(phy);
0386 }
0387
0388 static int ael2005_intr_clear(struct cphy *phy)
0389 {
0390 int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0xd00);
0391 return err ? err : t3_phy_lasi_intr_clear(phy);
0392 }
0393
0394 static int ael2005_reset(struct cphy *phy, int wait)
0395 {
0396 static const struct reg_val regs0[] = {
0397 { MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 },
0398 { MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 },
0399 { MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 },
0400 { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
0401 { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 },
0402 { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
0403 { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 },
0404 { 0, 0, 0, 0 }
0405 };
0406 static const struct reg_val regs1[] = {
0407 { MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 },
0408 { MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 },
0409 { 0, 0, 0, 0 }
0410 };
0411
0412 int err;
0413 unsigned int lasi_ctrl;
0414
0415 err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
0416 &lasi_ctrl);
0417 if (err)
0418 return err;
0419
0420 err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0);
0421 if (err)
0422 return err;
0423
0424 msleep(125);
0425 phy->priv = edc_none;
0426 err = set_phy_regs(phy, regs0);
0427 if (err)
0428 return err;
0429
0430 msleep(50);
0431
0432 err = ael2005_get_module_type(phy, 0);
0433 if (err < 0)
0434 return err;
0435 phy->modtype = err;
0436
0437 if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
0438 err = ael2005_setup_twinax_edc(phy, err);
0439 else
0440 err = ael2005_setup_sr_edc(phy);
0441 if (err)
0442 return err;
0443
0444 err = set_phy_regs(phy, regs1);
0445 if (err)
0446 return err;
0447
0448
0449 if (lasi_ctrl & 1)
0450 err = ael2005_intr_enable(phy);
0451 return err;
0452 }
0453
0454 static int ael2005_intr_handler(struct cphy *phy)
0455 {
0456 unsigned int stat;
0457 int ret, edc_needed, cause = 0;
0458
0459 ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_STAT, &stat);
0460 if (ret)
0461 return ret;
0462
0463 if (stat & AEL2005_MODDET_IRQ) {
0464 ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL,
0465 0xd00);
0466 if (ret)
0467 return ret;
0468
0469
0470 ret = ael2005_get_module_type(phy, 300);
0471 if (ret < 0)
0472 return ret;
0473
0474 phy->modtype = ret;
0475 if (ret == phy_modtype_none)
0476 edc_needed = phy->priv;
0477 else if (ret == phy_modtype_twinax ||
0478 ret == phy_modtype_twinax_long)
0479 edc_needed = edc_twinax;
0480 else
0481 edc_needed = edc_sr;
0482
0483 if (edc_needed != phy->priv) {
0484 ret = ael2005_reset(phy, 0);
0485 return ret ? ret : cphy_cause_module_change;
0486 }
0487 cause = cphy_cause_module_change;
0488 }
0489
0490 ret = t3_phy_lasi_intr_handler(phy);
0491 if (ret < 0)
0492 return ret;
0493
0494 ret |= cause;
0495 return ret ? ret : cphy_cause_link_change;
0496 }
0497
0498 static const struct cphy_ops ael2005_ops = {
0499 .reset = ael2005_reset,
0500 .intr_enable = ael2005_intr_enable,
0501 .intr_disable = ael2005_intr_disable,
0502 .intr_clear = ael2005_intr_clear,
0503 .intr_handler = ael2005_intr_handler,
0504 .get_link_status = get_link_status_r,
0505 .power_down = ael1002_power_down,
0506 .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
0507 };
0508
0509 int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
0510 int phy_addr, const struct mdio_ops *mdio_ops)
0511 {
0512 cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
0513 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
0514 SUPPORTED_IRQ, "10GBASE-R");
0515 msleep(125);
0516 return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0,
0517 1 << 5);
0518 }
0519
0520
0521
0522
0523 static int ael2020_setup_sr_edc(struct cphy *phy)
0524 {
0525 static const struct reg_val regs[] = {
0526
0527 { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a },
0528
0529
0530 { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 },
0531 { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 },
0532 { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 },
0533
0534
0535 { 0, 0, 0, 0 }
0536 };
0537 int err;
0538
0539 err = set_phy_regs(phy, regs);
0540 msleep(50);
0541 if (err)
0542 return err;
0543
0544 phy->priv = edc_sr;
0545 return 0;
0546 }
0547
0548
0549
0550
0551 static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
0552 {
0553
0554 static const struct reg_val uCclock40MHz[] = {
0555 { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 },
0556 { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 },
0557 { 0, 0, 0, 0 }
0558 };
0559
0560
0561 static const struct reg_val uCclockActivate[] = {
0562 { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 },
0563 { 0, 0, 0, 0 }
0564 };
0565
0566
0567 static const struct reg_val uCactivate[] = {
0568 { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 },
0569 { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
0570 { 0, 0, 0, 0 }
0571 };
0572 int i, err;
0573
0574
0575 err = set_phy_regs(phy, uCclock40MHz);
0576 msleep(500);
0577 if (err)
0578 return err;
0579 err = set_phy_regs(phy, uCclockActivate);
0580 msleep(500);
0581 if (err)
0582 return err;
0583
0584 if (phy->priv != edc_twinax)
0585 err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
0586 EDC_TWX_AEL2020_SIZE);
0587 if (err)
0588 return err;
0589
0590 for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
0591 err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
0592 phy->phy_cache[i],
0593 phy->phy_cache[i + 1]);
0594
0595 err = set_phy_regs(phy, uCactivate);
0596 if (!err)
0597 phy->priv = edc_twinax;
0598 return err;
0599 }
0600
0601
0602
0603
0604 static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
0605 {
0606 int v;
0607 unsigned int stat;
0608
0609 v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat);
0610 if (v)
0611 return v;
0612
0613 if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) {
0614
0615 return phy_modtype_none;
0616 }
0617
0618 return ael2xxx_get_module_type(phy, delay_ms);
0619 }
0620
0621
0622
0623
0624
0625 static int ael2020_intr_enable(struct cphy *phy)
0626 {
0627 static const struct reg_val regs[] = {
0628
0629 { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
0630 0xffff, 0x4 },
0631 { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
0632 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
0633
0634
0635 { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
0636 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
0637
0638
0639 { 0, 0, 0, 0 }
0640 };
0641 int err, link_ok = 0;
0642
0643
0644 err = set_phy_regs(phy, regs);
0645 if (err)
0646 return err;
0647
0648 err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
0649 if (err)
0650 return err;
0651 if (link_ok)
0652 t3_link_changed(phy->adapter,
0653 phy2portid(phy));
0654
0655 err = t3_phy_lasi_intr_enable(phy);
0656 if (err)
0657 return err;
0658
0659 return 0;
0660 }
0661
0662
0663
0664
0665 static int ael2020_intr_disable(struct cphy *phy)
0666 {
0667 static const struct reg_val regs[] = {
0668
0669 { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
0670 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
0671
0672
0673 { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
0674 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
0675
0676
0677 { 0, 0, 0, 0 }
0678 };
0679 int err;
0680
0681
0682 err = set_phy_regs(phy, regs);
0683 if (err)
0684 return err;
0685
0686 return t3_phy_lasi_intr_disable(phy);
0687 }
0688
0689
0690
0691
0692 static int ael2020_intr_clear(struct cphy *phy)
0693 {
0694
0695
0696
0697
0698
0699 unsigned int stat;
0700 int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
0701 return err ? err : t3_phy_lasi_intr_clear(phy);
0702 }
0703
0704 static const struct reg_val ael2020_reset_regs[] = {
0705
0706 { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
0707
0708
0709 { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
0710
0711
0712 { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
0713 { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
0714 { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
0715
0716
0717 { 0, 0, 0, 0 }
0718 };
0719
0720
0721
0722 static int ael2020_reset(struct cphy *phy, int wait)
0723 {
0724 int err;
0725 unsigned int lasi_ctrl;
0726
0727
0728 err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
0729 &lasi_ctrl);
0730 if (err)
0731 return err;
0732
0733 err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125);
0734 if (err)
0735 return err;
0736 msleep(100);
0737
0738
0739 phy->priv = edc_none;
0740 err = set_phy_regs(phy, ael2020_reset_regs);
0741 if (err)
0742 return err;
0743
0744
0745 err = ael2020_get_module_type(phy, 0);
0746 if (err < 0)
0747 return err;
0748 phy->modtype = (u8)err;
0749 if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
0750 err = ael2020_setup_twinax_edc(phy, err);
0751 else
0752 err = ael2020_setup_sr_edc(phy);
0753 if (err)
0754 return err;
0755
0756
0757 if (lasi_ctrl & 1)
0758 err = ael2005_intr_enable(phy);
0759 return err;
0760 }
0761
0762
0763
0764
0765 static int ael2020_intr_handler(struct cphy *phy)
0766 {
0767 unsigned int stat;
0768 int ret, edc_needed, cause = 0;
0769
0770 ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
0771 if (ret)
0772 return ret;
0773
0774 if (stat & (0x1 << AEL2020_GPIO_MODDET)) {
0775
0776 ret = ael2020_get_module_type(phy, 300);
0777 if (ret < 0)
0778 return ret;
0779
0780 phy->modtype = (u8)ret;
0781 if (ret == phy_modtype_none)
0782 edc_needed = phy->priv;
0783 else if (ret == phy_modtype_twinax ||
0784 ret == phy_modtype_twinax_long)
0785 edc_needed = edc_twinax;
0786 else
0787 edc_needed = edc_sr;
0788
0789 if (edc_needed != phy->priv) {
0790 ret = ael2020_reset(phy, 0);
0791 return ret ? ret : cphy_cause_module_change;
0792 }
0793 cause = cphy_cause_module_change;
0794 }
0795
0796 ret = t3_phy_lasi_intr_handler(phy);
0797 if (ret < 0)
0798 return ret;
0799
0800 ret |= cause;
0801 return ret ? ret : cphy_cause_link_change;
0802 }
0803
0804 static const struct cphy_ops ael2020_ops = {
0805 .reset = ael2020_reset,
0806 .intr_enable = ael2020_intr_enable,
0807 .intr_disable = ael2020_intr_disable,
0808 .intr_clear = ael2020_intr_clear,
0809 .intr_handler = ael2020_intr_handler,
0810 .get_link_status = get_link_status_r,
0811 .power_down = ael1002_power_down,
0812 .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
0813 };
0814
0815 int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
0816 const struct mdio_ops *mdio_ops)
0817 {
0818 cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
0819 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
0820 SUPPORTED_IRQ, "10GBASE-R");
0821 msleep(125);
0822
0823 return set_phy_regs(phy, ael2020_reset_regs);
0824 }
0825
0826
0827
0828
0829 static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
0830 int *duplex, int *fc)
0831 {
0832 if (link_ok) {
0833 unsigned int stat0, stat1, stat2;
0834 int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
0835 MDIO_PMA_RXDET, &stat0);
0836
0837 if (!err)
0838 err = t3_mdio_read(phy, MDIO_MMD_PCS,
0839 MDIO_PCS_10GBX_STAT1, &stat1);
0840 if (!err)
0841 err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
0842 MDIO_PHYXS_LNSTAT, &stat2);
0843 if (err)
0844 return err;
0845 *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1;
0846 }
0847 if (speed)
0848 *speed = SPEED_10000;
0849 if (duplex)
0850 *duplex = DUPLEX_FULL;
0851 return 0;
0852 }
0853
0854 static const struct cphy_ops qt2045_ops = {
0855 .reset = ael1006_reset,
0856 .intr_enable = t3_phy_lasi_intr_enable,
0857 .intr_disable = t3_phy_lasi_intr_disable,
0858 .intr_clear = t3_phy_lasi_intr_clear,
0859 .intr_handler = t3_phy_lasi_intr_handler,
0860 .get_link_status = get_link_status_x,
0861 .power_down = ael1002_power_down,
0862 .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
0863 };
0864
0865 int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
0866 int phy_addr, const struct mdio_ops *mdio_ops)
0867 {
0868 unsigned int stat;
0869
0870 cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
0871 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
0872 "10GBASE-CX4");
0873
0874
0875
0876
0877
0878 if (!phy_addr &&
0879 !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) &&
0880 stat == 0xffff)
0881 phy->mdio.prtad = 1;
0882 return 0;
0883 }
0884
0885 static int xaui_direct_reset(struct cphy *phy, int wait)
0886 {
0887 return 0;
0888 }
0889
0890 static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
0891 int *speed, int *duplex, int *fc)
0892 {
0893 if (link_ok) {
0894 unsigned int status;
0895 int prtad = phy->mdio.prtad;
0896
0897 status = t3_read_reg(phy->adapter,
0898 XGM_REG(A_XGM_SERDES_STAT0, prtad)) |
0899 t3_read_reg(phy->adapter,
0900 XGM_REG(A_XGM_SERDES_STAT1, prtad)) |
0901 t3_read_reg(phy->adapter,
0902 XGM_REG(A_XGM_SERDES_STAT2, prtad)) |
0903 t3_read_reg(phy->adapter,
0904 XGM_REG(A_XGM_SERDES_STAT3, prtad));
0905 *link_ok = !(status & F_LOWSIG0);
0906 }
0907 if (speed)
0908 *speed = SPEED_10000;
0909 if (duplex)
0910 *duplex = DUPLEX_FULL;
0911 return 0;
0912 }
0913
0914 static int xaui_direct_power_down(struct cphy *phy, int enable)
0915 {
0916 return 0;
0917 }
0918
0919 static const struct cphy_ops xaui_direct_ops = {
0920 .reset = xaui_direct_reset,
0921 .intr_enable = ael1002_intr_noop,
0922 .intr_disable = ael1002_intr_noop,
0923 .intr_clear = ael1002_intr_noop,
0924 .intr_handler = ael1002_intr_noop,
0925 .get_link_status = xaui_direct_get_link_status,
0926 .power_down = xaui_direct_power_down,
0927 };
0928
0929 int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
0930 int phy_addr, const struct mdio_ops *mdio_ops)
0931 {
0932 cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
0933 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
0934 "10GBASE-CX4");
0935 return 0;
0936 }