1 /* 2 * drivers/net/phy/broadcom.c 3 * 4 * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet 5 * transceivers. 6 * 7 * Copyright (c) 2006 Maciej W. Rozycki 8 * 9 * Inspired by code written by Amy Fong. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 14 * 2 of the License, or (at your option) any later version. 15 */ 16 17 #include "bcm-phy-lib.h" 18 #include <linux/module.h> 19 #include <linux/phy.h> 20 #include <linux/brcmphy.h> 21 #include <linux/of.h> 22 23 #define BRCM_PHY_MODEL(phydev) \ 24 ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) 25 26 #define BRCM_PHY_REV(phydev) \ 27 ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) 28 29 MODULE_DESCRIPTION("Broadcom PHY driver"); 30 MODULE_AUTHOR("Maciej W. Rozycki"); 31 MODULE_LICENSE("GPL"); 32 33 static int bcm54210e_config_init(struct phy_device *phydev) 34 { 35 int val; 36 37 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 38 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 39 val |= MII_BCM54XX_AUXCTL_MISC_WREN; 40 bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val); 41 42 val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); 43 val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; 44 bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); 45 46 return 0; 47 } 48 49 static int bcm54612e_config_init(struct phy_device *phydev) 50 { 51 /* Clear TX internal delay unless requested. */ 52 if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && 53 (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) { 54 /* Disable TXD to GTXCLK clock delay (default set) */ 55 /* Bit 9 is the only field in shadow register 00011 */ 56 bcm_phy_write_shadow(phydev, 0x03, 0); 57 } 58 59 /* Clear RX internal delay unless requested. */ 60 if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && 61 (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) { 62 u16 reg; 63 64 reg = bcm54xx_auxctl_read(phydev, 65 MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 66 /* Disable RXD to RXC delay (default set) */ 67 reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 68 /* Clear shadow selector field */ 69 reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK; 70 bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 71 MII_BCM54XX_AUXCTL_MISC_WREN | reg); 72 } 73 74 return 0; 75 } 76 77 static int bcm54810_config(struct phy_device *phydev) 78 { 79 int rc, val; 80 81 val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 82 val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 83 rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 84 val); 85 if (rc < 0) 86 return rc; 87 88 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 89 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 90 val |= MII_BCM54XX_AUXCTL_MISC_WREN; 91 rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 92 val); 93 if (rc < 0) 94 return rc; 95 96 val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); 97 val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; 98 rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); 99 if (rc < 0) 100 return rc; 101 102 return 0; 103 } 104 105 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ 106 static int bcm50610_a0_workaround(struct phy_device *phydev) 107 { 108 int err; 109 110 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0, 111 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | 112 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); 113 if (err < 0) 114 return err; 115 116 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3, 117 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); 118 if (err < 0) 119 return err; 120 121 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, 122 MII_BCM54XX_EXP_EXP75_VDACCTRL); 123 if (err < 0) 124 return err; 125 126 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96, 127 MII_BCM54XX_EXP_EXP96_MYST); 128 if (err < 0) 129 return err; 130 131 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97, 132 MII_BCM54XX_EXP_EXP97_MYST); 133 134 return err; 135 } 136 137 static int bcm54xx_phydsp_config(struct phy_device *phydev) 138 { 139 int err, err2; 140 141 /* Enable the SMDSP clock */ 142 err = bcm54xx_auxctl_write(phydev, 143 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 144 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | 145 MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 146 if (err < 0) 147 return err; 148 149 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 150 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) { 151 /* Clear bit 9 to fix a phy interop issue. */ 152 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, 153 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ); 154 if (err < 0) 155 goto error; 156 157 if (phydev->drv->phy_id == PHY_ID_BCM50610) { 158 err = bcm50610_a0_workaround(phydev); 159 if (err < 0) 160 goto error; 161 } 162 } 163 164 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { 165 int val; 166 167 val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75); 168 if (val < 0) 169 goto error; 170 171 val |= MII_BCM54XX_EXP_EXP75_CM_OSC; 172 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val); 173 } 174 175 error: 176 /* Disable the SMDSP clock */ 177 err2 = bcm54xx_auxctl_write(phydev, 178 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 179 MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 180 181 /* Return the first error reported. */ 182 return err ? err : err2; 183 } 184 185 static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) 186 { 187 u32 orig; 188 int val; 189 bool clk125en = true; 190 191 /* Abort if we are using an untested phy. */ 192 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && 193 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && 194 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M) 195 return; 196 197 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); 198 if (val < 0) 199 return; 200 201 orig = val; 202 203 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 204 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 205 BRCM_PHY_REV(phydev) >= 0x3) { 206 /* 207 * Here, bit 0 _disables_ CLK125 when set. 208 * This bit is set by default. 209 */ 210 clk125en = false; 211 } else { 212 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { 213 /* Here, bit 0 _enables_ CLK125 when set */ 214 val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; 215 clk125en = false; 216 } 217 } 218 219 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 220 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; 221 else 222 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 223 224 if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) 225 val |= BCM54XX_SHD_SCR3_TRDDAPD; 226 227 if (orig != val) 228 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); 229 230 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); 231 if (val < 0) 232 return; 233 234 orig = val; 235 236 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 237 val |= BCM54XX_SHD_APD_EN; 238 else 239 val &= ~BCM54XX_SHD_APD_EN; 240 241 if (orig != val) 242 bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); 243 } 244 245 static int bcm54xx_config_init(struct phy_device *phydev) 246 { 247 int reg, err; 248 249 reg = phy_read(phydev, MII_BCM54XX_ECR); 250 if (reg < 0) 251 return reg; 252 253 /* Mask interrupts globally. */ 254 reg |= MII_BCM54XX_ECR_IM; 255 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 256 if (err < 0) 257 return err; 258 259 /* Unmask events we are interested in. */ 260 reg = ~(MII_BCM54XX_INT_DUPLEX | 261 MII_BCM54XX_INT_SPEED | 262 MII_BCM54XX_INT_LINK); 263 err = phy_write(phydev, MII_BCM54XX_IMR, reg); 264 if (err < 0) 265 return err; 266 267 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 268 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 269 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) 270 bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); 271 272 if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || 273 (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || 274 (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 275 bcm54xx_adjust_rxrefclk(phydev); 276 277 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) { 278 err = bcm54210e_config_init(phydev); 279 if (err) 280 return err; 281 } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) { 282 err = bcm54612e_config_init(phydev); 283 if (err) 284 return err; 285 } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) { 286 err = bcm54810_config(phydev); 287 if (err) 288 return err; 289 } 290 291 bcm54xx_phydsp_config(phydev); 292 293 return 0; 294 } 295 296 static int bcm5482_config_init(struct phy_device *phydev) 297 { 298 int err, reg; 299 300 err = bcm54xx_config_init(phydev); 301 302 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 303 /* 304 * Enable secondary SerDes and its use as an LED source 305 */ 306 reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD); 307 bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD, 308 reg | 309 BCM5482_SHD_SSD_LEDM | 310 BCM5482_SHD_SSD_EN); 311 312 /* 313 * Enable SGMII slave mode and auto-detection 314 */ 315 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; 316 err = bcm_phy_read_exp(phydev, reg); 317 if (err < 0) 318 return err; 319 err = bcm_phy_write_exp(phydev, reg, err | 320 BCM5482_SSD_SGMII_SLAVE_EN | 321 BCM5482_SSD_SGMII_SLAVE_AD); 322 if (err < 0) 323 return err; 324 325 /* 326 * Disable secondary SerDes powerdown 327 */ 328 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; 329 err = bcm_phy_read_exp(phydev, reg); 330 if (err < 0) 331 return err; 332 err = bcm_phy_write_exp(phydev, reg, 333 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); 334 if (err < 0) 335 return err; 336 337 /* 338 * Select 1000BASE-X register set (primary SerDes) 339 */ 340 reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE); 341 bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE, 342 reg | BCM5482_SHD_MODE_1000BX); 343 344 /* 345 * LED1=ACTIVITYLED, LED3=LINKSPD[2] 346 * (Use LED1 as secondary SerDes ACTIVITY LED) 347 */ 348 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, 349 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | 350 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); 351 352 /* 353 * Auto-negotiation doesn't seem to work quite right 354 * in this mode, so we disable it and force it to the 355 * right speed/duplex setting. Only 'link status' 356 * is important. 357 */ 358 phydev->autoneg = AUTONEG_DISABLE; 359 phydev->speed = SPEED_1000; 360 phydev->duplex = DUPLEX_FULL; 361 } 362 363 return err; 364 } 365 366 static int bcm5482_read_status(struct phy_device *phydev) 367 { 368 int err; 369 370 err = genphy_read_status(phydev); 371 372 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 373 /* 374 * Only link status matters for 1000Base-X mode, so force 375 * 1000 Mbit/s full-duplex status 376 */ 377 if (phydev->link) { 378 phydev->speed = SPEED_1000; 379 phydev->duplex = DUPLEX_FULL; 380 } 381 } 382 383 return err; 384 } 385 386 static int bcm5481_config_aneg(struct phy_device *phydev) 387 { 388 struct device_node *np = phydev->mdio.dev.of_node; 389 int ret; 390 391 /* Aneg firsly. */ 392 ret = genphy_config_aneg(phydev); 393 394 /* Then we can set up the delay. */ 395 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 396 u16 reg; 397 398 /* 399 * There is no BCM5481 specification available, so down 400 * here is everything we know about "register 0x18". This 401 * at least helps BCM5481 to successfully receive packets 402 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com> 403 * says: "This sets delay between the RXD and RXC signals 404 * instead of using trace lengths to achieve timing". 405 */ 406 407 /* Set RDX clk delay. */ 408 reg = 0x7 | (0x7 << 12); 409 phy_write(phydev, 0x18, reg); 410 411 reg = phy_read(phydev, 0x18); 412 /* Set RDX-RXC skew. */ 413 reg |= (1 << 8); 414 /* Write bits 14:0. */ 415 reg |= (1 << 15); 416 phy_write(phydev, 0x18, reg); 417 } 418 419 if (of_property_read_bool(np, "enet-phy-lane-swap")) { 420 /* Lane Swap - Undocumented register...magic! */ 421 ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9, 422 0x11B); 423 if (ret < 0) 424 return ret; 425 } 426 427 return ret; 428 } 429 430 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 431 { 432 int val; 433 434 val = phy_read(phydev, reg); 435 if (val < 0) 436 return val; 437 438 return phy_write(phydev, reg, val | set); 439 } 440 441 static int brcm_fet_config_init(struct phy_device *phydev) 442 { 443 int reg, err, err2, brcmtest; 444 445 /* Reset the PHY to bring it to a known state. */ 446 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 447 if (err < 0) 448 return err; 449 450 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 451 if (reg < 0) 452 return reg; 453 454 /* Unmask events we are interested in and mask interrupts globally. */ 455 reg = MII_BRCM_FET_IR_DUPLEX_EN | 456 MII_BRCM_FET_IR_SPEED_EN | 457 MII_BRCM_FET_IR_LINK_EN | 458 MII_BRCM_FET_IR_ENABLE | 459 MII_BRCM_FET_IR_MASK; 460 461 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 462 if (err < 0) 463 return err; 464 465 /* Enable shadow register access */ 466 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 467 if (brcmtest < 0) 468 return brcmtest; 469 470 reg = brcmtest | MII_BRCM_FET_BT_SRE; 471 472 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 473 if (err < 0) 474 return err; 475 476 /* Set the LED mode */ 477 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 478 if (reg < 0) { 479 err = reg; 480 goto done; 481 } 482 483 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 484 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 485 486 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 487 if (err < 0) 488 goto done; 489 490 /* Enable auto MDIX */ 491 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 492 MII_BRCM_FET_SHDW_MC_FAME); 493 if (err < 0) 494 goto done; 495 496 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 497 /* Enable auto power down */ 498 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 499 MII_BRCM_FET_SHDW_AS2_APDE); 500 } 501 502 done: 503 /* Disable shadow register access */ 504 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 505 if (!err) 506 err = err2; 507 508 return err; 509 } 510 511 static int brcm_fet_ack_interrupt(struct phy_device *phydev) 512 { 513 int reg; 514 515 /* Clear pending interrupts. */ 516 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 517 if (reg < 0) 518 return reg; 519 520 return 0; 521 } 522 523 static int brcm_fet_config_intr(struct phy_device *phydev) 524 { 525 int reg, err; 526 527 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 528 if (reg < 0) 529 return reg; 530 531 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 532 reg &= ~MII_BRCM_FET_IR_MASK; 533 else 534 reg |= MII_BRCM_FET_IR_MASK; 535 536 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 537 return err; 538 } 539 540 static struct phy_driver broadcom_drivers[] = { 541 { 542 .phy_id = PHY_ID_BCM5411, 543 .phy_id_mask = 0xfffffff0, 544 .name = "Broadcom BCM5411", 545 .features = PHY_GBIT_FEATURES, 546 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 547 .config_init = bcm54xx_config_init, 548 .config_aneg = genphy_config_aneg, 549 .read_status = genphy_read_status, 550 .ack_interrupt = bcm_phy_ack_intr, 551 .config_intr = bcm_phy_config_intr, 552 }, { 553 .phy_id = PHY_ID_BCM5421, 554 .phy_id_mask = 0xfffffff0, 555 .name = "Broadcom BCM5421", 556 .features = PHY_GBIT_FEATURES, 557 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 558 .config_init = bcm54xx_config_init, 559 .config_aneg = genphy_config_aneg, 560 .read_status = genphy_read_status, 561 .ack_interrupt = bcm_phy_ack_intr, 562 .config_intr = bcm_phy_config_intr, 563 }, { 564 .phy_id = PHY_ID_BCM54210E, 565 .phy_id_mask = 0xfffffff0, 566 .name = "Broadcom BCM54210E", 567 .features = PHY_GBIT_FEATURES, 568 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 569 .config_init = bcm54xx_config_init, 570 .config_aneg = genphy_config_aneg, 571 .read_status = genphy_read_status, 572 .ack_interrupt = bcm_phy_ack_intr, 573 .config_intr = bcm_phy_config_intr, 574 }, { 575 .phy_id = PHY_ID_BCM5461, 576 .phy_id_mask = 0xfffffff0, 577 .name = "Broadcom BCM5461", 578 .features = PHY_GBIT_FEATURES, 579 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 580 .config_init = bcm54xx_config_init, 581 .config_aneg = genphy_config_aneg, 582 .read_status = genphy_read_status, 583 .ack_interrupt = bcm_phy_ack_intr, 584 .config_intr = bcm_phy_config_intr, 585 }, { 586 .phy_id = PHY_ID_BCM54612E, 587 .phy_id_mask = 0xfffffff0, 588 .name = "Broadcom BCM54612E", 589 .features = PHY_GBIT_FEATURES, 590 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 591 .config_init = bcm54xx_config_init, 592 .config_aneg = genphy_config_aneg, 593 .read_status = genphy_read_status, 594 .ack_interrupt = bcm_phy_ack_intr, 595 .config_intr = bcm_phy_config_intr, 596 }, { 597 .phy_id = PHY_ID_BCM54616S, 598 .phy_id_mask = 0xfffffff0, 599 .name = "Broadcom BCM54616S", 600 .features = PHY_GBIT_FEATURES, 601 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 602 .config_init = bcm54xx_config_init, 603 .config_aneg = genphy_config_aneg, 604 .read_status = genphy_read_status, 605 .ack_interrupt = bcm_phy_ack_intr, 606 .config_intr = bcm_phy_config_intr, 607 }, { 608 .phy_id = PHY_ID_BCM5464, 609 .phy_id_mask = 0xfffffff0, 610 .name = "Broadcom BCM5464", 611 .features = PHY_GBIT_FEATURES, 612 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 613 .config_init = bcm54xx_config_init, 614 .config_aneg = genphy_config_aneg, 615 .read_status = genphy_read_status, 616 .ack_interrupt = bcm_phy_ack_intr, 617 .config_intr = bcm_phy_config_intr, 618 }, { 619 .phy_id = PHY_ID_BCM5481, 620 .phy_id_mask = 0xfffffff0, 621 .name = "Broadcom BCM5481", 622 .features = PHY_GBIT_FEATURES, 623 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 624 .config_init = bcm54xx_config_init, 625 .config_aneg = bcm5481_config_aneg, 626 .read_status = genphy_read_status, 627 .ack_interrupt = bcm_phy_ack_intr, 628 .config_intr = bcm_phy_config_intr, 629 }, { 630 .phy_id = PHY_ID_BCM54810, 631 .phy_id_mask = 0xfffffff0, 632 .name = "Broadcom BCM54810", 633 .features = PHY_GBIT_FEATURES, 634 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 635 .config_init = bcm54xx_config_init, 636 .config_aneg = bcm5481_config_aneg, 637 .read_status = genphy_read_status, 638 .ack_interrupt = bcm_phy_ack_intr, 639 .config_intr = bcm_phy_config_intr, 640 }, { 641 .phy_id = PHY_ID_BCM5482, 642 .phy_id_mask = 0xfffffff0, 643 .name = "Broadcom BCM5482", 644 .features = PHY_GBIT_FEATURES, 645 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 646 .config_init = bcm5482_config_init, 647 .config_aneg = genphy_config_aneg, 648 .read_status = bcm5482_read_status, 649 .ack_interrupt = bcm_phy_ack_intr, 650 .config_intr = bcm_phy_config_intr, 651 }, { 652 .phy_id = PHY_ID_BCM50610, 653 .phy_id_mask = 0xfffffff0, 654 .name = "Broadcom BCM50610", 655 .features = PHY_GBIT_FEATURES, 656 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 657 .config_init = bcm54xx_config_init, 658 .config_aneg = genphy_config_aneg, 659 .read_status = genphy_read_status, 660 .ack_interrupt = bcm_phy_ack_intr, 661 .config_intr = bcm_phy_config_intr, 662 }, { 663 .phy_id = PHY_ID_BCM50610M, 664 .phy_id_mask = 0xfffffff0, 665 .name = "Broadcom BCM50610M", 666 .features = PHY_GBIT_FEATURES, 667 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 668 .config_init = bcm54xx_config_init, 669 .config_aneg = genphy_config_aneg, 670 .read_status = genphy_read_status, 671 .ack_interrupt = bcm_phy_ack_intr, 672 .config_intr = bcm_phy_config_intr, 673 }, { 674 .phy_id = PHY_ID_BCM57780, 675 .phy_id_mask = 0xfffffff0, 676 .name = "Broadcom BCM57780", 677 .features = PHY_GBIT_FEATURES, 678 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 679 .config_init = bcm54xx_config_init, 680 .config_aneg = genphy_config_aneg, 681 .read_status = genphy_read_status, 682 .ack_interrupt = bcm_phy_ack_intr, 683 .config_intr = bcm_phy_config_intr, 684 }, { 685 .phy_id = PHY_ID_BCMAC131, 686 .phy_id_mask = 0xfffffff0, 687 .name = "Broadcom BCMAC131", 688 .features = PHY_BASIC_FEATURES, 689 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 690 .config_init = brcm_fet_config_init, 691 .config_aneg = genphy_config_aneg, 692 .read_status = genphy_read_status, 693 .ack_interrupt = brcm_fet_ack_interrupt, 694 .config_intr = brcm_fet_config_intr, 695 }, { 696 .phy_id = PHY_ID_BCM5241, 697 .phy_id_mask = 0xfffffff0, 698 .name = "Broadcom BCM5241", 699 .features = PHY_BASIC_FEATURES, 700 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 701 .config_init = brcm_fet_config_init, 702 .config_aneg = genphy_config_aneg, 703 .read_status = genphy_read_status, 704 .ack_interrupt = brcm_fet_ack_interrupt, 705 .config_intr = brcm_fet_config_intr, 706 } }; 707 708 module_phy_driver(broadcom_drivers); 709 710 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 711 { PHY_ID_BCM5411, 0xfffffff0 }, 712 { PHY_ID_BCM5421, 0xfffffff0 }, 713 { PHY_ID_BCM54210E, 0xfffffff0 }, 714 { PHY_ID_BCM5461, 0xfffffff0 }, 715 { PHY_ID_BCM54612E, 0xfffffff0 }, 716 { PHY_ID_BCM54616S, 0xfffffff0 }, 717 { PHY_ID_BCM5464, 0xfffffff0 }, 718 { PHY_ID_BCM5481, 0xfffffff0 }, 719 { PHY_ID_BCM54810, 0xfffffff0 }, 720 { PHY_ID_BCM5482, 0xfffffff0 }, 721 { PHY_ID_BCM50610, 0xfffffff0 }, 722 { PHY_ID_BCM50610M, 0xfffffff0 }, 723 { PHY_ID_BCM57780, 0xfffffff0 }, 724 { PHY_ID_BCMAC131, 0xfffffff0 }, 725 { PHY_ID_BCM5241, 0xfffffff0 }, 726 { } 727 }; 728 729 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 730