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 int rc, val; 32 33 /* handling PHY's internal RX clock delay */ 34 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 35 val |= MII_BCM54XX_AUXCTL_MISC_WREN; 36 if (phydev->interface == PHY_INTERFACE_MODE_RGMII || 37 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 38 /* Disable RGMII RXC-RXD skew */ 39 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 40 } 41 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 42 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 43 /* Enable RGMII RXC-RXD skew */ 44 val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 45 } 46 rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 47 val); 48 if (rc < 0) 49 return rc; 50 51 /* handling PHY's internal TX clock delay */ 52 val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); 53 if (phydev->interface == PHY_INTERFACE_MODE_RGMII || 54 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 55 /* Disable internal TX clock delay */ 56 val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; 57 } 58 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 59 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 60 /* Enable internal TX clock delay */ 61 val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN; 62 } 63 rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); 64 if (rc < 0) 65 return rc; 66 67 return 0; 68 } 69 70 static int bcm54210e_config_init(struct phy_device *phydev) 71 { 72 int val; 73 74 bcm54xx_config_clock_delay(phydev); 75 76 if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { 77 val = phy_read(phydev, MII_CTRL1000); 78 val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; 79 phy_write(phydev, MII_CTRL1000, val); 80 } 81 82 return 0; 83 } 84 85 static int bcm54612e_config_init(struct phy_device *phydev) 86 { 87 int reg; 88 89 bcm54xx_config_clock_delay(phydev); 90 91 /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ 92 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { 93 int err; 94 95 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); 96 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, 97 BCM54612E_LED4_CLK125OUT_EN | reg); 98 99 if (err < 0) 100 return err; 101 } 102 103 return 0; 104 } 105 106 static int bcm54616s_config_init(struct phy_device *phydev) 107 { 108 int rc, val; 109 110 if (phydev->interface != PHY_INTERFACE_MODE_SGMII && 111 phydev->interface != PHY_INTERFACE_MODE_1000BASEX) 112 return 0; 113 114 /* Ensure proper interface mode is selected. */ 115 /* Disable RGMII mode */ 116 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 117 if (val < 0) 118 return val; 119 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN; 120 val |= MII_BCM54XX_AUXCTL_MISC_WREN; 121 rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 122 val); 123 if (rc < 0) 124 return rc; 125 126 /* Select 1000BASE-X register set (primary SerDes) */ 127 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 128 if (val < 0) 129 return val; 130 val |= BCM54XX_SHD_MODE_1000BX; 131 rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); 132 if (rc < 0) 133 return rc; 134 135 /* Power down SerDes interface */ 136 rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); 137 if (rc < 0) 138 return rc; 139 140 /* Select proper interface mode */ 141 val &= ~BCM54XX_SHD_INTF_SEL_MASK; 142 val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ? 143 BCM54XX_SHD_INTF_SEL_SGMII : 144 BCM54XX_SHD_INTF_SEL_GBIC; 145 rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); 146 if (rc < 0) 147 return rc; 148 149 /* Power up SerDes interface */ 150 rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN); 151 if (rc < 0) 152 return rc; 153 154 /* Select copper register set */ 155 val &= ~BCM54XX_SHD_MODE_1000BX; 156 rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); 157 if (rc < 0) 158 return rc; 159 160 /* Power up copper interface */ 161 return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN); 162 } 163 164 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ 165 static int bcm50610_a0_workaround(struct phy_device *phydev) 166 { 167 int err; 168 169 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0, 170 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | 171 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); 172 if (err < 0) 173 return err; 174 175 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3, 176 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); 177 if (err < 0) 178 return err; 179 180 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, 181 MII_BCM54XX_EXP_EXP75_VDACCTRL); 182 if (err < 0) 183 return err; 184 185 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96, 186 MII_BCM54XX_EXP_EXP96_MYST); 187 if (err < 0) 188 return err; 189 190 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97, 191 MII_BCM54XX_EXP_EXP97_MYST); 192 193 return err; 194 } 195 196 static int bcm54xx_phydsp_config(struct phy_device *phydev) 197 { 198 int err, err2; 199 200 /* Enable the SMDSP clock */ 201 err = bcm54xx_auxctl_write(phydev, 202 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 203 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | 204 MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 205 if (err < 0) 206 return err; 207 208 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 209 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) { 210 /* Clear bit 9 to fix a phy interop issue. */ 211 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, 212 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ); 213 if (err < 0) 214 goto error; 215 216 if (phydev->drv->phy_id == PHY_ID_BCM50610) { 217 err = bcm50610_a0_workaround(phydev); 218 if (err < 0) 219 goto error; 220 } 221 } 222 223 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { 224 int val; 225 226 val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75); 227 if (val < 0) 228 goto error; 229 230 val |= MII_BCM54XX_EXP_EXP75_CM_OSC; 231 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val); 232 } 233 234 error: 235 /* Disable the SMDSP clock */ 236 err2 = bcm54xx_auxctl_write(phydev, 237 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 238 MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 239 240 /* Return the first error reported. */ 241 return err ? err : err2; 242 } 243 244 static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) 245 { 246 u32 orig; 247 int val; 248 bool clk125en = true; 249 250 /* Abort if we are using an untested phy. */ 251 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && 252 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && 253 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M && 254 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E && 255 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 && 256 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) 257 return; 258 259 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); 260 if (val < 0) 261 return; 262 263 orig = val; 264 265 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 266 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 267 BRCM_PHY_REV(phydev) >= 0x3) { 268 /* 269 * Here, bit 0 _disables_ CLK125 when set. 270 * This bit is set by default. 271 */ 272 clk125en = false; 273 } else { 274 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { 275 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) { 276 /* Here, bit 0 _enables_ CLK125 when set */ 277 val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; 278 } 279 clk125en = false; 280 } 281 } 282 283 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 284 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; 285 else 286 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 287 288 if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) { 289 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E || 290 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 || 291 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811) 292 val |= BCM54XX_SHD_SCR3_RXCTXC_DIS; 293 else 294 val |= BCM54XX_SHD_SCR3_TRDDAPD; 295 } 296 297 if (orig != val) 298 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); 299 300 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); 301 if (val < 0) 302 return; 303 304 orig = val; 305 306 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 307 val |= BCM54XX_SHD_APD_EN; 308 else 309 val &= ~BCM54XX_SHD_APD_EN; 310 311 if (orig != val) 312 bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); 313 } 314 315 static int bcm54xx_config_init(struct phy_device *phydev) 316 { 317 int reg, err, val; 318 319 reg = phy_read(phydev, MII_BCM54XX_ECR); 320 if (reg < 0) 321 return reg; 322 323 /* Mask interrupts globally. */ 324 reg |= MII_BCM54XX_ECR_IM; 325 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 326 if (err < 0) 327 return err; 328 329 /* Unmask events we are interested in. */ 330 reg = ~(MII_BCM54XX_INT_DUPLEX | 331 MII_BCM54XX_INT_SPEED | 332 MII_BCM54XX_INT_LINK); 333 err = phy_write(phydev, MII_BCM54XX_IMR, reg); 334 if (err < 0) 335 return err; 336 337 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 338 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 339 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) 340 bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); 341 342 bcm54xx_adjust_rxrefclk(phydev); 343 344 switch (BRCM_PHY_MODEL(phydev)) { 345 case PHY_ID_BCM50610: 346 case PHY_ID_BCM50610M: 347 err = bcm54xx_config_clock_delay(phydev); 348 break; 349 case PHY_ID_BCM54210E: 350 err = bcm54210e_config_init(phydev); 351 break; 352 case PHY_ID_BCM54612E: 353 err = bcm54612e_config_init(phydev); 354 break; 355 case PHY_ID_BCM54616S: 356 err = bcm54616s_config_init(phydev); 357 break; 358 case PHY_ID_BCM54810: 359 /* For BCM54810, we need to disable BroadR-Reach function */ 360 val = bcm_phy_read_exp(phydev, 361 BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 362 val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 363 err = bcm_phy_write_exp(phydev, 364 BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 365 val); 366 break; 367 } 368 if (err) 369 return err; 370 371 bcm54xx_phydsp_config(phydev); 372 373 /* For non-SFP setups, encode link speed into LED1 and LED3 pair 374 * (green/amber). 375 * Also flash these two LEDs on activity. This means configuring 376 * them for MULTICOLOR and encoding link/activity into them. 377 * Don't do this for devices on an SFP module, since some of these 378 * use the LED outputs to control the SFP LOS signal, and changing 379 * these settings will cause LOS to malfunction. 380 */ 381 if (!phy_on_sfp(phydev)) { 382 val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | 383 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); 384 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); 385 386 val = BCM_LED_MULTICOLOR_IN_PHASE | 387 BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | 388 BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); 389 bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); 390 } 391 392 return 0; 393 } 394 395 static int bcm54xx_resume(struct phy_device *phydev) 396 { 397 int ret; 398 399 /* Writes to register other than BMCR would be ignored 400 * unless we clear the PDOWN bit first 401 */ 402 ret = genphy_resume(phydev); 403 if (ret < 0) 404 return ret; 405 406 /* Upon exiting power down, the PHY remains in an internal reset state 407 * for 40us 408 */ 409 fsleep(40); 410 411 return bcm54xx_config_init(phydev); 412 } 413 414 static int bcm54811_config_init(struct phy_device *phydev) 415 { 416 int err, reg; 417 418 /* Disable BroadR-Reach function. */ 419 reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 420 reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 421 err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 422 reg); 423 if (err < 0) 424 return err; 425 426 err = bcm54xx_config_init(phydev); 427 428 /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ 429 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { 430 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); 431 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, 432 BCM54612E_LED4_CLK125OUT_EN | reg); 433 if (err < 0) 434 return err; 435 } 436 437 return err; 438 } 439 440 static int bcm5481_config_aneg(struct phy_device *phydev) 441 { 442 struct device_node *np = phydev->mdio.dev.of_node; 443 int ret; 444 445 /* Aneg firstly. */ 446 ret = genphy_config_aneg(phydev); 447 448 /* Then we can set up the delay. */ 449 bcm54xx_config_clock_delay(phydev); 450 451 if (of_property_read_bool(np, "enet-phy-lane-swap")) { 452 /* Lane Swap - Undocumented register...magic! */ 453 ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9, 454 0x11B); 455 if (ret < 0) 456 return ret; 457 } 458 459 return ret; 460 } 461 462 struct bcm54616s_phy_priv { 463 bool mode_1000bx_en; 464 }; 465 466 static int bcm54616s_probe(struct phy_device *phydev) 467 { 468 struct bcm54616s_phy_priv *priv; 469 int val; 470 471 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 472 if (!priv) 473 return -ENOMEM; 474 475 phydev->priv = priv; 476 477 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 478 if (val < 0) 479 return val; 480 481 /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] 482 * is 01b, and the link between PHY and its link partner can be 483 * either 1000Base-X or 100Base-FX. 484 * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX 485 * support is still missing as of now. 486 */ 487 if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) { 488 val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); 489 if (val < 0) 490 return val; 491 492 /* Bit 0 of the SerDes 100-FX Control register, when set 493 * to 1, sets the MII/RGMII -> 100BASE-FX configuration. 494 * When this bit is set to 0, it sets the GMII/RGMII -> 495 * 1000BASE-X configuration. 496 */ 497 if (!(val & BCM54616S_100FX_MODE)) 498 priv->mode_1000bx_en = true; 499 500 phydev->port = PORT_FIBRE; 501 } 502 503 return 0; 504 } 505 506 static int bcm54616s_config_aneg(struct phy_device *phydev) 507 { 508 struct bcm54616s_phy_priv *priv = phydev->priv; 509 int ret; 510 511 /* Aneg firstly. */ 512 if (priv->mode_1000bx_en) 513 ret = genphy_c37_config_aneg(phydev); 514 else 515 ret = genphy_config_aneg(phydev); 516 517 /* Then we can set up the delay. */ 518 bcm54xx_config_clock_delay(phydev); 519 520 return ret; 521 } 522 523 static int bcm54616s_read_status(struct phy_device *phydev) 524 { 525 struct bcm54616s_phy_priv *priv = phydev->priv; 526 int err; 527 528 if (priv->mode_1000bx_en) 529 err = genphy_c37_read_status(phydev); 530 else 531 err = genphy_read_status(phydev); 532 533 return err; 534 } 535 536 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 537 { 538 int val; 539 540 val = phy_read(phydev, reg); 541 if (val < 0) 542 return val; 543 544 return phy_write(phydev, reg, val | set); 545 } 546 547 static int brcm_fet_config_init(struct phy_device *phydev) 548 { 549 int reg, err, err2, brcmtest; 550 551 /* Reset the PHY to bring it to a known state. */ 552 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 553 if (err < 0) 554 return err; 555 556 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 557 if (reg < 0) 558 return reg; 559 560 /* Unmask events we are interested in and mask interrupts globally. */ 561 reg = MII_BRCM_FET_IR_DUPLEX_EN | 562 MII_BRCM_FET_IR_SPEED_EN | 563 MII_BRCM_FET_IR_LINK_EN | 564 MII_BRCM_FET_IR_ENABLE | 565 MII_BRCM_FET_IR_MASK; 566 567 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 568 if (err < 0) 569 return err; 570 571 /* Enable shadow register access */ 572 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 573 if (brcmtest < 0) 574 return brcmtest; 575 576 reg = brcmtest | MII_BRCM_FET_BT_SRE; 577 578 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 579 if (err < 0) 580 return err; 581 582 /* Set the LED mode */ 583 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 584 if (reg < 0) { 585 err = reg; 586 goto done; 587 } 588 589 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 590 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 591 592 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 593 if (err < 0) 594 goto done; 595 596 /* Enable auto MDIX */ 597 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 598 MII_BRCM_FET_SHDW_MC_FAME); 599 if (err < 0) 600 goto done; 601 602 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 603 /* Enable auto power down */ 604 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 605 MII_BRCM_FET_SHDW_AS2_APDE); 606 } 607 608 done: 609 /* Disable shadow register access */ 610 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 611 if (!err) 612 err = err2; 613 614 return err; 615 } 616 617 static int brcm_fet_ack_interrupt(struct phy_device *phydev) 618 { 619 int reg; 620 621 /* Clear pending interrupts. */ 622 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 623 if (reg < 0) 624 return reg; 625 626 return 0; 627 } 628 629 static int brcm_fet_config_intr(struct phy_device *phydev) 630 { 631 int reg, err; 632 633 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 634 if (reg < 0) 635 return reg; 636 637 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 638 err = brcm_fet_ack_interrupt(phydev); 639 if (err) 640 return err; 641 642 reg &= ~MII_BRCM_FET_IR_MASK; 643 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 644 } else { 645 reg |= MII_BRCM_FET_IR_MASK; 646 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 647 if (err) 648 return err; 649 650 err = brcm_fet_ack_interrupt(phydev); 651 } 652 653 return err; 654 } 655 656 static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev) 657 { 658 int irq_status; 659 660 irq_status = phy_read(phydev, MII_BRCM_FET_INTREG); 661 if (irq_status < 0) { 662 phy_error(phydev); 663 return IRQ_NONE; 664 } 665 666 if (irq_status == 0) 667 return IRQ_NONE; 668 669 phy_trigger_machine(phydev); 670 671 return IRQ_HANDLED; 672 } 673 674 struct bcm54xx_phy_priv { 675 u64 *stats; 676 }; 677 678 static int bcm54xx_phy_probe(struct phy_device *phydev) 679 { 680 struct bcm54xx_phy_priv *priv; 681 682 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 683 if (!priv) 684 return -ENOMEM; 685 686 phydev->priv = priv; 687 688 priv->stats = devm_kcalloc(&phydev->mdio.dev, 689 bcm_phy_get_sset_count(phydev), sizeof(u64), 690 GFP_KERNEL); 691 if (!priv->stats) 692 return -ENOMEM; 693 694 return 0; 695 } 696 697 static void bcm54xx_get_stats(struct phy_device *phydev, 698 struct ethtool_stats *stats, u64 *data) 699 { 700 struct bcm54xx_phy_priv *priv = phydev->priv; 701 702 bcm_phy_get_stats(phydev, priv->stats, stats, data); 703 } 704 705 static struct phy_driver broadcom_drivers[] = { 706 { 707 .phy_id = PHY_ID_BCM5411, 708 .phy_id_mask = 0xfffffff0, 709 .name = "Broadcom BCM5411", 710 /* PHY_GBIT_FEATURES */ 711 .get_sset_count = bcm_phy_get_sset_count, 712 .get_strings = bcm_phy_get_strings, 713 .get_stats = bcm54xx_get_stats, 714 .probe = bcm54xx_phy_probe, 715 .config_init = bcm54xx_config_init, 716 .config_intr = bcm_phy_config_intr, 717 .handle_interrupt = bcm_phy_handle_interrupt, 718 }, { 719 .phy_id = PHY_ID_BCM5421, 720 .phy_id_mask = 0xfffffff0, 721 .name = "Broadcom BCM5421", 722 /* PHY_GBIT_FEATURES */ 723 .get_sset_count = bcm_phy_get_sset_count, 724 .get_strings = bcm_phy_get_strings, 725 .get_stats = bcm54xx_get_stats, 726 .probe = bcm54xx_phy_probe, 727 .config_init = bcm54xx_config_init, 728 .config_intr = bcm_phy_config_intr, 729 .handle_interrupt = bcm_phy_handle_interrupt, 730 }, { 731 .phy_id = PHY_ID_BCM54210E, 732 .phy_id_mask = 0xfffffff0, 733 .name = "Broadcom BCM54210E", 734 /* PHY_GBIT_FEATURES */ 735 .get_sset_count = bcm_phy_get_sset_count, 736 .get_strings = bcm_phy_get_strings, 737 .get_stats = bcm54xx_get_stats, 738 .probe = bcm54xx_phy_probe, 739 .config_init = bcm54xx_config_init, 740 .config_intr = bcm_phy_config_intr, 741 .handle_interrupt = bcm_phy_handle_interrupt, 742 }, { 743 .phy_id = PHY_ID_BCM5461, 744 .phy_id_mask = 0xfffffff0, 745 .name = "Broadcom BCM5461", 746 /* PHY_GBIT_FEATURES */ 747 .get_sset_count = bcm_phy_get_sset_count, 748 .get_strings = bcm_phy_get_strings, 749 .get_stats = bcm54xx_get_stats, 750 .probe = bcm54xx_phy_probe, 751 .config_init = bcm54xx_config_init, 752 .config_intr = bcm_phy_config_intr, 753 .handle_interrupt = bcm_phy_handle_interrupt, 754 }, { 755 .phy_id = PHY_ID_BCM54612E, 756 .phy_id_mask = 0xfffffff0, 757 .name = "Broadcom BCM54612E", 758 /* PHY_GBIT_FEATURES */ 759 .get_sset_count = bcm_phy_get_sset_count, 760 .get_strings = bcm_phy_get_strings, 761 .get_stats = bcm54xx_get_stats, 762 .probe = bcm54xx_phy_probe, 763 .config_init = bcm54xx_config_init, 764 .config_intr = bcm_phy_config_intr, 765 .handle_interrupt = bcm_phy_handle_interrupt, 766 }, { 767 .phy_id = PHY_ID_BCM54616S, 768 .phy_id_mask = 0xfffffff0, 769 .name = "Broadcom BCM54616S", 770 /* PHY_GBIT_FEATURES */ 771 .config_init = bcm54xx_config_init, 772 .config_aneg = bcm54616s_config_aneg, 773 .config_intr = bcm_phy_config_intr, 774 .handle_interrupt = bcm_phy_handle_interrupt, 775 .read_status = bcm54616s_read_status, 776 .probe = bcm54616s_probe, 777 }, { 778 .phy_id = PHY_ID_BCM5464, 779 .phy_id_mask = 0xfffffff0, 780 .name = "Broadcom BCM5464", 781 /* PHY_GBIT_FEATURES */ 782 .get_sset_count = bcm_phy_get_sset_count, 783 .get_strings = bcm_phy_get_strings, 784 .get_stats = bcm54xx_get_stats, 785 .probe = bcm54xx_phy_probe, 786 .config_init = bcm54xx_config_init, 787 .config_intr = bcm_phy_config_intr, 788 .handle_interrupt = bcm_phy_handle_interrupt, 789 .suspend = genphy_suspend, 790 .resume = genphy_resume, 791 }, { 792 .phy_id = PHY_ID_BCM5481, 793 .phy_id_mask = 0xfffffff0, 794 .name = "Broadcom BCM5481", 795 /* PHY_GBIT_FEATURES */ 796 .get_sset_count = bcm_phy_get_sset_count, 797 .get_strings = bcm_phy_get_strings, 798 .get_stats = bcm54xx_get_stats, 799 .probe = bcm54xx_phy_probe, 800 .config_init = bcm54xx_config_init, 801 .config_aneg = bcm5481_config_aneg, 802 .config_intr = bcm_phy_config_intr, 803 .handle_interrupt = bcm_phy_handle_interrupt, 804 }, { 805 .phy_id = PHY_ID_BCM54810, 806 .phy_id_mask = 0xfffffff0, 807 .name = "Broadcom BCM54810", 808 /* PHY_GBIT_FEATURES */ 809 .get_sset_count = bcm_phy_get_sset_count, 810 .get_strings = bcm_phy_get_strings, 811 .get_stats = bcm54xx_get_stats, 812 .probe = bcm54xx_phy_probe, 813 .config_init = bcm54xx_config_init, 814 .config_aneg = bcm5481_config_aneg, 815 .config_intr = bcm_phy_config_intr, 816 .handle_interrupt = bcm_phy_handle_interrupt, 817 .suspend = genphy_suspend, 818 .resume = bcm54xx_resume, 819 }, { 820 .phy_id = PHY_ID_BCM54811, 821 .phy_id_mask = 0xfffffff0, 822 .name = "Broadcom BCM54811", 823 /* PHY_GBIT_FEATURES */ 824 .get_sset_count = bcm_phy_get_sset_count, 825 .get_strings = bcm_phy_get_strings, 826 .get_stats = bcm54xx_get_stats, 827 .probe = bcm54xx_phy_probe, 828 .config_init = bcm54811_config_init, 829 .config_aneg = bcm5481_config_aneg, 830 .config_intr = bcm_phy_config_intr, 831 .handle_interrupt = bcm_phy_handle_interrupt, 832 .suspend = genphy_suspend, 833 .resume = bcm54xx_resume, 834 }, { 835 .phy_id = PHY_ID_BCM5482, 836 .phy_id_mask = 0xfffffff0, 837 .name = "Broadcom BCM5482", 838 /* PHY_GBIT_FEATURES */ 839 .get_sset_count = bcm_phy_get_sset_count, 840 .get_strings = bcm_phy_get_strings, 841 .get_stats = bcm54xx_get_stats, 842 .probe = bcm54xx_phy_probe, 843 .config_init = bcm54xx_config_init, 844 .config_intr = bcm_phy_config_intr, 845 .handle_interrupt = bcm_phy_handle_interrupt, 846 }, { 847 .phy_id = PHY_ID_BCM50610, 848 .phy_id_mask = 0xfffffff0, 849 .name = "Broadcom BCM50610", 850 /* PHY_GBIT_FEATURES */ 851 .get_sset_count = bcm_phy_get_sset_count, 852 .get_strings = bcm_phy_get_strings, 853 .get_stats = bcm54xx_get_stats, 854 .probe = bcm54xx_phy_probe, 855 .config_init = bcm54xx_config_init, 856 .config_intr = bcm_phy_config_intr, 857 .handle_interrupt = bcm_phy_handle_interrupt, 858 }, { 859 .phy_id = PHY_ID_BCM50610M, 860 .phy_id_mask = 0xfffffff0, 861 .name = "Broadcom BCM50610M", 862 /* PHY_GBIT_FEATURES */ 863 .get_sset_count = bcm_phy_get_sset_count, 864 .get_strings = bcm_phy_get_strings, 865 .get_stats = bcm54xx_get_stats, 866 .probe = bcm54xx_phy_probe, 867 .config_init = bcm54xx_config_init, 868 .config_intr = bcm_phy_config_intr, 869 .handle_interrupt = bcm_phy_handle_interrupt, 870 }, { 871 .phy_id = PHY_ID_BCM57780, 872 .phy_id_mask = 0xfffffff0, 873 .name = "Broadcom BCM57780", 874 /* PHY_GBIT_FEATURES */ 875 .get_sset_count = bcm_phy_get_sset_count, 876 .get_strings = bcm_phy_get_strings, 877 .get_stats = bcm54xx_get_stats, 878 .probe = bcm54xx_phy_probe, 879 .config_init = bcm54xx_config_init, 880 .config_intr = bcm_phy_config_intr, 881 .handle_interrupt = bcm_phy_handle_interrupt, 882 }, { 883 .phy_id = PHY_ID_BCMAC131, 884 .phy_id_mask = 0xfffffff0, 885 .name = "Broadcom BCMAC131", 886 /* PHY_BASIC_FEATURES */ 887 .config_init = brcm_fet_config_init, 888 .config_intr = brcm_fet_config_intr, 889 .handle_interrupt = brcm_fet_handle_interrupt, 890 }, { 891 .phy_id = PHY_ID_BCM5241, 892 .phy_id_mask = 0xfffffff0, 893 .name = "Broadcom BCM5241", 894 /* PHY_BASIC_FEATURES */ 895 .config_init = brcm_fet_config_init, 896 .config_intr = brcm_fet_config_intr, 897 .handle_interrupt = brcm_fet_handle_interrupt, 898 }, { 899 .phy_id = PHY_ID_BCM5395, 900 .phy_id_mask = 0xfffffff0, 901 .name = "Broadcom BCM5395", 902 .flags = PHY_IS_INTERNAL, 903 /* PHY_GBIT_FEATURES */ 904 .get_sset_count = bcm_phy_get_sset_count, 905 .get_strings = bcm_phy_get_strings, 906 .get_stats = bcm54xx_get_stats, 907 .probe = bcm54xx_phy_probe, 908 }, { 909 .phy_id = PHY_ID_BCM53125, 910 .phy_id_mask = 0xfffffff0, 911 .name = "Broadcom BCM53125", 912 .flags = PHY_IS_INTERNAL, 913 /* PHY_GBIT_FEATURES */ 914 .get_sset_count = bcm_phy_get_sset_count, 915 .get_strings = bcm_phy_get_strings, 916 .get_stats = bcm54xx_get_stats, 917 .probe = bcm54xx_phy_probe, 918 .config_init = bcm54xx_config_init, 919 .config_intr = bcm_phy_config_intr, 920 .handle_interrupt = bcm_phy_handle_interrupt, 921 }, { 922 .phy_id = PHY_ID_BCM89610, 923 .phy_id_mask = 0xfffffff0, 924 .name = "Broadcom BCM89610", 925 /* PHY_GBIT_FEATURES */ 926 .get_sset_count = bcm_phy_get_sset_count, 927 .get_strings = bcm_phy_get_strings, 928 .get_stats = bcm54xx_get_stats, 929 .probe = bcm54xx_phy_probe, 930 .config_init = bcm54xx_config_init, 931 .config_intr = bcm_phy_config_intr, 932 .handle_interrupt = bcm_phy_handle_interrupt, 933 } }; 934 935 module_phy_driver(broadcom_drivers); 936 937 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 938 { PHY_ID_BCM5411, 0xfffffff0 }, 939 { PHY_ID_BCM5421, 0xfffffff0 }, 940 { PHY_ID_BCM54210E, 0xfffffff0 }, 941 { PHY_ID_BCM5461, 0xfffffff0 }, 942 { PHY_ID_BCM54612E, 0xfffffff0 }, 943 { PHY_ID_BCM54616S, 0xfffffff0 }, 944 { PHY_ID_BCM5464, 0xfffffff0 }, 945 { PHY_ID_BCM5481, 0xfffffff0 }, 946 { PHY_ID_BCM54810, 0xfffffff0 }, 947 { PHY_ID_BCM54811, 0xfffffff0 }, 948 { PHY_ID_BCM5482, 0xfffffff0 }, 949 { PHY_ID_BCM50610, 0xfffffff0 }, 950 { PHY_ID_BCM50610M, 0xfffffff0 }, 951 { PHY_ID_BCM57780, 0xfffffff0 }, 952 { PHY_ID_BCMAC131, 0xfffffff0 }, 953 { PHY_ID_BCM5241, 0xfffffff0 }, 954 { PHY_ID_BCM5395, 0xfffffff0 }, 955 { PHY_ID_BCM53125, 0xfffffff0 }, 956 { PHY_ID_BCM89610, 0xfffffff0 }, 957 { } 958 }; 959 960 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 961