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