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}