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