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