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, BCM5482_SHD_MODE); 363 bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE, 364 reg | BCM5482_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 firsly. */ 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_config_aneg(struct phy_device *phydev) 431 { 432 int ret; 433 434 /* Aneg firsly. */ 435 ret = genphy_config_aneg(phydev); 436 437 /* Then we can set up the delay. */ 438 bcm54xx_config_clock_delay(phydev); 439 440 return ret; 441 } 442 443 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 444 { 445 int val; 446 447 val = phy_read(phydev, reg); 448 if (val < 0) 449 return val; 450 451 return phy_write(phydev, reg, val | set); 452 } 453 454 static int brcm_fet_config_init(struct phy_device *phydev) 455 { 456 int reg, err, err2, brcmtest; 457 458 /* Reset the PHY to bring it to a known state. */ 459 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 460 if (err < 0) 461 return err; 462 463 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 464 if (reg < 0) 465 return reg; 466 467 /* Unmask events we are interested in and mask interrupts globally. */ 468 reg = MII_BRCM_FET_IR_DUPLEX_EN | 469 MII_BRCM_FET_IR_SPEED_EN | 470 MII_BRCM_FET_IR_LINK_EN | 471 MII_BRCM_FET_IR_ENABLE | 472 MII_BRCM_FET_IR_MASK; 473 474 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 475 if (err < 0) 476 return err; 477 478 /* Enable shadow register access */ 479 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 480 if (brcmtest < 0) 481 return brcmtest; 482 483 reg = brcmtest | MII_BRCM_FET_BT_SRE; 484 485 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 486 if (err < 0) 487 return err; 488 489 /* Set the LED mode */ 490 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 491 if (reg < 0) { 492 err = reg; 493 goto done; 494 } 495 496 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 497 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 498 499 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 500 if (err < 0) 501 goto done; 502 503 /* Enable auto MDIX */ 504 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 505 MII_BRCM_FET_SHDW_MC_FAME); 506 if (err < 0) 507 goto done; 508 509 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 510 /* Enable auto power down */ 511 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 512 MII_BRCM_FET_SHDW_AS2_APDE); 513 } 514 515 done: 516 /* Disable shadow register access */ 517 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 518 if (!err) 519 err = err2; 520 521 return err; 522 } 523 524 static int brcm_fet_ack_interrupt(struct phy_device *phydev) 525 { 526 int reg; 527 528 /* Clear pending interrupts. */ 529 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 530 if (reg < 0) 531 return reg; 532 533 return 0; 534 } 535 536 static int brcm_fet_config_intr(struct phy_device *phydev) 537 { 538 int reg, err; 539 540 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 541 if (reg < 0) 542 return reg; 543 544 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 545 reg &= ~MII_BRCM_FET_IR_MASK; 546 else 547 reg |= MII_BRCM_FET_IR_MASK; 548 549 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 550 return err; 551 } 552 553 struct bcm53xx_phy_priv { 554 u64 *stats; 555 }; 556 557 static int bcm53xx_phy_probe(struct phy_device *phydev) 558 { 559 struct bcm53xx_phy_priv *priv; 560 561 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 562 if (!priv) 563 return -ENOMEM; 564 565 phydev->priv = priv; 566 567 priv->stats = devm_kcalloc(&phydev->mdio.dev, 568 bcm_phy_get_sset_count(phydev), sizeof(u64), 569 GFP_KERNEL); 570 if (!priv->stats) 571 return -ENOMEM; 572 573 return 0; 574 } 575 576 static void bcm53xx_phy_get_stats(struct phy_device *phydev, 577 struct ethtool_stats *stats, u64 *data) 578 { 579 struct bcm53xx_phy_priv *priv = phydev->priv; 580 581 bcm_phy_get_stats(phydev, priv->stats, stats, data); 582 } 583 584 static struct phy_driver broadcom_drivers[] = { 585 { 586 .phy_id = PHY_ID_BCM5411, 587 .phy_id_mask = 0xfffffff0, 588 .name = "Broadcom BCM5411", 589 /* PHY_GBIT_FEATURES */ 590 .config_init = bcm54xx_config_init, 591 .ack_interrupt = bcm_phy_ack_intr, 592 .config_intr = bcm_phy_config_intr, 593 }, { 594 .phy_id = PHY_ID_BCM5421, 595 .phy_id_mask = 0xfffffff0, 596 .name = "Broadcom BCM5421", 597 /* PHY_GBIT_FEATURES */ 598 .config_init = bcm54xx_config_init, 599 .ack_interrupt = bcm_phy_ack_intr, 600 .config_intr = bcm_phy_config_intr, 601 }, { 602 .phy_id = PHY_ID_BCM54210E, 603 .phy_id_mask = 0xfffffff0, 604 .name = "Broadcom BCM54210E", 605 /* PHY_GBIT_FEATURES */ 606 .config_init = bcm54xx_config_init, 607 .ack_interrupt = bcm_phy_ack_intr, 608 .config_intr = bcm_phy_config_intr, 609 }, { 610 .phy_id = PHY_ID_BCM5461, 611 .phy_id_mask = 0xfffffff0, 612 .name = "Broadcom BCM5461", 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_BCM54612E, 619 .phy_id_mask = 0xfffffff0, 620 .name = "Broadcom BCM54612E", 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_BCM54616S, 627 .phy_id_mask = 0xfffffff0, 628 .name = "Broadcom BCM54616S", 629 /* PHY_GBIT_FEATURES */ 630 .config_init = bcm54xx_config_init, 631 .config_aneg = bcm54616s_config_aneg, 632 .ack_interrupt = bcm_phy_ack_intr, 633 .config_intr = bcm_phy_config_intr, 634 }, { 635 .phy_id = PHY_ID_BCM5464, 636 .phy_id_mask = 0xfffffff0, 637 .name = "Broadcom BCM5464", 638 /* PHY_GBIT_FEATURES */ 639 .config_init = bcm54xx_config_init, 640 .ack_interrupt = bcm_phy_ack_intr, 641 .config_intr = bcm_phy_config_intr, 642 .suspend = genphy_suspend, 643 .resume = genphy_resume, 644 }, { 645 .phy_id = PHY_ID_BCM5481, 646 .phy_id_mask = 0xfffffff0, 647 .name = "Broadcom BCM5481", 648 /* PHY_GBIT_FEATURES */ 649 .config_init = bcm54xx_config_init, 650 .config_aneg = bcm5481_config_aneg, 651 .ack_interrupt = bcm_phy_ack_intr, 652 .config_intr = bcm_phy_config_intr, 653 }, { 654 .phy_id = PHY_ID_BCM54810, 655 .phy_id_mask = 0xfffffff0, 656 .name = "Broadcom BCM54810", 657 /* PHY_GBIT_FEATURES */ 658 .config_init = bcm54xx_config_init, 659 .config_aneg = bcm5481_config_aneg, 660 .ack_interrupt = bcm_phy_ack_intr, 661 .config_intr = bcm_phy_config_intr, 662 }, { 663 .phy_id = PHY_ID_BCM5482, 664 .phy_id_mask = 0xfffffff0, 665 .name = "Broadcom BCM5482", 666 /* PHY_GBIT_FEATURES */ 667 .config_init = bcm5482_config_init, 668 .read_status = bcm5482_read_status, 669 .ack_interrupt = bcm_phy_ack_intr, 670 .config_intr = bcm_phy_config_intr, 671 }, { 672 .phy_id = PHY_ID_BCM50610, 673 .phy_id_mask = 0xfffffff0, 674 .name = "Broadcom BCM50610", 675 /* PHY_GBIT_FEATURES */ 676 .config_init = bcm54xx_config_init, 677 .ack_interrupt = bcm_phy_ack_intr, 678 .config_intr = bcm_phy_config_intr, 679 }, { 680 .phy_id = PHY_ID_BCM50610M, 681 .phy_id_mask = 0xfffffff0, 682 .name = "Broadcom BCM50610M", 683 /* PHY_GBIT_FEATURES */ 684 .config_init = bcm54xx_config_init, 685 .ack_interrupt = bcm_phy_ack_intr, 686 .config_intr = bcm_phy_config_intr, 687 }, { 688 .phy_id = PHY_ID_BCM57780, 689 .phy_id_mask = 0xfffffff0, 690 .name = "Broadcom BCM57780", 691 /* PHY_GBIT_FEATURES */ 692 .config_init = bcm54xx_config_init, 693 .ack_interrupt = bcm_phy_ack_intr, 694 .config_intr = bcm_phy_config_intr, 695 }, { 696 .phy_id = PHY_ID_BCMAC131, 697 .phy_id_mask = 0xfffffff0, 698 .name = "Broadcom BCMAC131", 699 /* PHY_BASIC_FEATURES */ 700 .config_init = brcm_fet_config_init, 701 .ack_interrupt = brcm_fet_ack_interrupt, 702 .config_intr = brcm_fet_config_intr, 703 }, { 704 .phy_id = PHY_ID_BCM5241, 705 .phy_id_mask = 0xfffffff0, 706 .name = "Broadcom BCM5241", 707 /* PHY_BASIC_FEATURES */ 708 .config_init = brcm_fet_config_init, 709 .ack_interrupt = brcm_fet_ack_interrupt, 710 .config_intr = brcm_fet_config_intr, 711 }, { 712 .phy_id = PHY_ID_BCM5395, 713 .phy_id_mask = 0xfffffff0, 714 .name = "Broadcom BCM5395", 715 .flags = PHY_IS_INTERNAL, 716 /* PHY_GBIT_FEATURES */ 717 .get_sset_count = bcm_phy_get_sset_count, 718 .get_strings = bcm_phy_get_strings, 719 .get_stats = bcm53xx_phy_get_stats, 720 .probe = bcm53xx_phy_probe, 721 }, { 722 .phy_id = PHY_ID_BCM89610, 723 .phy_id_mask = 0xfffffff0, 724 .name = "Broadcom BCM89610", 725 /* PHY_GBIT_FEATURES */ 726 .config_init = bcm54xx_config_init, 727 .ack_interrupt = bcm_phy_ack_intr, 728 .config_intr = bcm_phy_config_intr, 729 } }; 730 731 module_phy_driver(broadcom_drivers); 732 733 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 734 { PHY_ID_BCM5411, 0xfffffff0 }, 735 { PHY_ID_BCM5421, 0xfffffff0 }, 736 { PHY_ID_BCM54210E, 0xfffffff0 }, 737 { PHY_ID_BCM5461, 0xfffffff0 }, 738 { PHY_ID_BCM54612E, 0xfffffff0 }, 739 { PHY_ID_BCM54616S, 0xfffffff0 }, 740 { PHY_ID_BCM5464, 0xfffffff0 }, 741 { PHY_ID_BCM5481, 0xfffffff0 }, 742 { PHY_ID_BCM54810, 0xfffffff0 }, 743 { PHY_ID_BCM5482, 0xfffffff0 }, 744 { PHY_ID_BCM50610, 0xfffffff0 }, 745 { PHY_ID_BCM50610M, 0xfffffff0 }, 746 { PHY_ID_BCM57780, 0xfffffff0 }, 747 { PHY_ID_BCMAC131, 0xfffffff0 }, 748 { PHY_ID_BCM5241, 0xfffffff0 }, 749 { PHY_ID_BCM5395, 0xfffffff0 }, 750 { PHY_ID_BCM89610, 0xfffffff0 }, 751 { } 752 }; 753 754 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 755