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 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 530 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 531 .config_init = bcm54xx_config_init, 532 .config_aneg = genphy_config_aneg, 533 .read_status = genphy_read_status, 534 .ack_interrupt = bcm_phy_ack_intr, 535 .config_intr = bcm_phy_config_intr, 536 }, { 537 .phy_id = PHY_ID_BCM5421, 538 .phy_id_mask = 0xfffffff0, 539 .name = "Broadcom BCM5421", 540 .features = PHY_GBIT_FEATURES | 541 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 542 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 543 .config_init = bcm54xx_config_init, 544 .config_aneg = genphy_config_aneg, 545 .read_status = genphy_read_status, 546 .ack_interrupt = bcm_phy_ack_intr, 547 .config_intr = bcm_phy_config_intr, 548 }, { 549 .phy_id = PHY_ID_BCM5461, 550 .phy_id_mask = 0xfffffff0, 551 .name = "Broadcom BCM5461", 552 .features = PHY_GBIT_FEATURES | 553 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 554 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 555 .config_init = bcm54xx_config_init, 556 .config_aneg = genphy_config_aneg, 557 .read_status = genphy_read_status, 558 .ack_interrupt = bcm_phy_ack_intr, 559 .config_intr = bcm_phy_config_intr, 560 }, { 561 .phy_id = PHY_ID_BCM54612E, 562 .phy_id_mask = 0xfffffff0, 563 .name = "Broadcom BCM54612E", 564 .features = PHY_GBIT_FEATURES | 565 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 566 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 567 .config_init = bcm54xx_config_init, 568 .config_aneg = bcm54612e_config_aneg, 569 .read_status = genphy_read_status, 570 .ack_interrupt = bcm_phy_ack_intr, 571 .config_intr = bcm_phy_config_intr, 572 }, { 573 .phy_id = PHY_ID_BCM54616S, 574 .phy_id_mask = 0xfffffff0, 575 .name = "Broadcom BCM54616S", 576 .features = PHY_GBIT_FEATURES | 577 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 578 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 579 .config_init = bcm54xx_config_init, 580 .config_aneg = genphy_config_aneg, 581 .read_status = genphy_read_status, 582 .ack_interrupt = bcm_phy_ack_intr, 583 .config_intr = bcm_phy_config_intr, 584 }, { 585 .phy_id = PHY_ID_BCM5464, 586 .phy_id_mask = 0xfffffff0, 587 .name = "Broadcom BCM5464", 588 .features = PHY_GBIT_FEATURES | 589 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 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_BCM5481, 598 .phy_id_mask = 0xfffffff0, 599 .name = "Broadcom BCM5481", 600 .features = PHY_GBIT_FEATURES | 601 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 602 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 603 .config_init = bcm54xx_config_init, 604 .config_aneg = bcm5481_config_aneg, 605 .read_status = genphy_read_status, 606 .ack_interrupt = bcm_phy_ack_intr, 607 .config_intr = bcm_phy_config_intr, 608 }, { 609 .phy_id = PHY_ID_BCM54810, 610 .phy_id_mask = 0xfffffff0, 611 .name = "Broadcom BCM54810", 612 .features = PHY_GBIT_FEATURES | 613 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 614 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 615 .config_init = bcm54xx_config_init, 616 .config_aneg = bcm5481_config_aneg, 617 .read_status = genphy_read_status, 618 .ack_interrupt = bcm_phy_ack_intr, 619 .config_intr = bcm_phy_config_intr, 620 }, { 621 .phy_id = PHY_ID_BCM5482, 622 .phy_id_mask = 0xfffffff0, 623 .name = "Broadcom BCM5482", 624 .features = PHY_GBIT_FEATURES | 625 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 626 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 627 .config_init = bcm5482_config_init, 628 .config_aneg = genphy_config_aneg, 629 .read_status = bcm5482_read_status, 630 .ack_interrupt = bcm_phy_ack_intr, 631 .config_intr = bcm_phy_config_intr, 632 }, { 633 .phy_id = PHY_ID_BCM50610, 634 .phy_id_mask = 0xfffffff0, 635 .name = "Broadcom BCM50610", 636 .features = PHY_GBIT_FEATURES | 637 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 638 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 639 .config_init = bcm54xx_config_init, 640 .config_aneg = genphy_config_aneg, 641 .read_status = genphy_read_status, 642 .ack_interrupt = bcm_phy_ack_intr, 643 .config_intr = bcm_phy_config_intr, 644 }, { 645 .phy_id = PHY_ID_BCM50610M, 646 .phy_id_mask = 0xfffffff0, 647 .name = "Broadcom BCM50610M", 648 .features = PHY_GBIT_FEATURES | 649 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 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_BCM57780, 658 .phy_id_mask = 0xfffffff0, 659 .name = "Broadcom BCM57780", 660 .features = PHY_GBIT_FEATURES | 661 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 662 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 663 .config_init = bcm54xx_config_init, 664 .config_aneg = genphy_config_aneg, 665 .read_status = genphy_read_status, 666 .ack_interrupt = bcm_phy_ack_intr, 667 .config_intr = bcm_phy_config_intr, 668 }, { 669 .phy_id = PHY_ID_BCMAC131, 670 .phy_id_mask = 0xfffffff0, 671 .name = "Broadcom BCMAC131", 672 .features = PHY_BASIC_FEATURES | 673 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 674 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 675 .config_init = brcm_fet_config_init, 676 .config_aneg = genphy_config_aneg, 677 .read_status = genphy_read_status, 678 .ack_interrupt = brcm_fet_ack_interrupt, 679 .config_intr = brcm_fet_config_intr, 680 }, { 681 .phy_id = PHY_ID_BCM5241, 682 .phy_id_mask = 0xfffffff0, 683 .name = "Broadcom BCM5241", 684 .features = PHY_BASIC_FEATURES | 685 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 686 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 687 .config_init = brcm_fet_config_init, 688 .config_aneg = genphy_config_aneg, 689 .read_status = genphy_read_status, 690 .ack_interrupt = brcm_fet_ack_interrupt, 691 .config_intr = brcm_fet_config_intr, 692 } }; 693 694 module_phy_driver(broadcom_drivers); 695 696 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 697 { PHY_ID_BCM5411, 0xfffffff0 }, 698 { PHY_ID_BCM5421, 0xfffffff0 }, 699 { PHY_ID_BCM5461, 0xfffffff0 }, 700 { PHY_ID_BCM54612E, 0xfffffff0 }, 701 { PHY_ID_BCM54616S, 0xfffffff0 }, 702 { PHY_ID_BCM5464, 0xfffffff0 }, 703 { PHY_ID_BCM5481, 0xfffffff0 }, 704 { PHY_ID_BCM54810, 0xfffffff0 }, 705 { PHY_ID_BCM5482, 0xfffffff0 }, 706 { PHY_ID_BCM50610, 0xfffffff0 }, 707 { PHY_ID_BCM50610M, 0xfffffff0 }, 708 { PHY_ID_BCM57780, 0xfffffff0 }, 709 { PHY_ID_BCMAC131, 0xfffffff0 }, 710 { PHY_ID_BCM5241, 0xfffffff0 }, 711 { } 712 }; 713 714 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 715