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