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