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_BCM54210E) 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_BCM54210E: 346 err = bcm54210e_config_init(phydev); 347 break; 348 case PHY_ID_BCM54612E: 349 err = bcm54612e_config_init(phydev); 350 break; 351 case PHY_ID_BCM54616S: 352 err = bcm54616s_config_init(phydev); 353 break; 354 case PHY_ID_BCM54810: 355 /* For BCM54810, we need to disable BroadR-Reach function */ 356 val = bcm_phy_read_exp(phydev, 357 BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 358 val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 359 err = bcm_phy_write_exp(phydev, 360 BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 361 val); 362 break; 363 } 364 if (err) 365 return err; 366 367 bcm54xx_phydsp_config(phydev); 368 369 /* For non-SFP setups, encode link speed into LED1 and LED3 pair 370 * (green/amber). 371 * Also flash these two LEDs on activity. This means configuring 372 * them for MULTICOLOR and encoding link/activity into them. 373 * Don't do this for devices on an SFP module, since some of these 374 * use the LED outputs to control the SFP LOS signal, and changing 375 * these settings will cause LOS to malfunction. 376 */ 377 if (!phy_on_sfp(phydev)) { 378 val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | 379 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); 380 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); 381 382 val = BCM_LED_MULTICOLOR_IN_PHASE | 383 BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | 384 BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); 385 bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); 386 } 387 388 return 0; 389 } 390 391 static int bcm54xx_resume(struct phy_device *phydev) 392 { 393 int ret; 394 395 /* Writes to register other than BMCR would be ignored 396 * unless we clear the PDOWN bit first 397 */ 398 ret = genphy_resume(phydev); 399 if (ret < 0) 400 return ret; 401 402 return bcm54xx_config_init(phydev); 403 } 404 405 static int bcm54811_config_init(struct phy_device *phydev) 406 { 407 int err, reg; 408 409 /* Disable BroadR-Reach function. */ 410 reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 411 reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 412 err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 413 reg); 414 if (err < 0) 415 return err; 416 417 err = bcm54xx_config_init(phydev); 418 419 /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ 420 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { 421 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); 422 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, 423 BCM54612E_LED4_CLK125OUT_EN | reg); 424 if (err < 0) 425 return err; 426 } 427 428 return err; 429 } 430 431 static int bcm5481_config_aneg(struct phy_device *phydev) 432 { 433 struct device_node *np = phydev->mdio.dev.of_node; 434 int ret; 435 436 /* Aneg firstly. */ 437 ret = genphy_config_aneg(phydev); 438 439 /* Then we can set up the delay. */ 440 bcm54xx_config_clock_delay(phydev); 441 442 if (of_property_read_bool(np, "enet-phy-lane-swap")) { 443 /* Lane Swap - Undocumented register...magic! */ 444 ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9, 445 0x11B); 446 if (ret < 0) 447 return ret; 448 } 449 450 return ret; 451 } 452 453 struct bcm54616s_phy_priv { 454 bool mode_1000bx_en; 455 }; 456 457 static int bcm54616s_probe(struct phy_device *phydev) 458 { 459 struct bcm54616s_phy_priv *priv; 460 int val; 461 462 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 463 if (!priv) 464 return -ENOMEM; 465 466 phydev->priv = priv; 467 468 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 469 if (val < 0) 470 return val; 471 472 /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] 473 * is 01b, and the link between PHY and its link partner can be 474 * either 1000Base-X or 100Base-FX. 475 * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX 476 * support is still missing as of now. 477 */ 478 if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) { 479 val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); 480 if (val < 0) 481 return val; 482 483 /* Bit 0 of the SerDes 100-FX Control register, when set 484 * to 1, sets the MII/RGMII -> 100BASE-FX configuration. 485 * When this bit is set to 0, it sets the GMII/RGMII -> 486 * 1000BASE-X configuration. 487 */ 488 if (!(val & BCM54616S_100FX_MODE)) 489 priv->mode_1000bx_en = true; 490 491 phydev->port = PORT_FIBRE; 492 } 493 494 return 0; 495 } 496 497 static int bcm54616s_config_aneg(struct phy_device *phydev) 498 { 499 struct bcm54616s_phy_priv *priv = phydev->priv; 500 int ret; 501 502 /* Aneg firstly. */ 503 if (priv->mode_1000bx_en) 504 ret = genphy_c37_config_aneg(phydev); 505 else 506 ret = genphy_config_aneg(phydev); 507 508 /* Then we can set up the delay. */ 509 bcm54xx_config_clock_delay(phydev); 510 511 return ret; 512 } 513 514 static int bcm54616s_read_status(struct phy_device *phydev) 515 { 516 struct bcm54616s_phy_priv *priv = phydev->priv; 517 int err; 518 519 if (priv->mode_1000bx_en) 520 err = genphy_c37_read_status(phydev); 521 else 522 err = genphy_read_status(phydev); 523 524 return err; 525 } 526 527 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 528 { 529 int val; 530 531 val = phy_read(phydev, reg); 532 if (val < 0) 533 return val; 534 535 return phy_write(phydev, reg, val | set); 536 } 537 538 static int brcm_fet_config_init(struct phy_device *phydev) 539 { 540 int reg, err, err2, brcmtest; 541 542 /* Reset the PHY to bring it to a known state. */ 543 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 544 if (err < 0) 545 return err; 546 547 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 548 if (reg < 0) 549 return reg; 550 551 /* Unmask events we are interested in and mask interrupts globally. */ 552 reg = MII_BRCM_FET_IR_DUPLEX_EN | 553 MII_BRCM_FET_IR_SPEED_EN | 554 MII_BRCM_FET_IR_LINK_EN | 555 MII_BRCM_FET_IR_ENABLE | 556 MII_BRCM_FET_IR_MASK; 557 558 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 559 if (err < 0) 560 return err; 561 562 /* Enable shadow register access */ 563 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 564 if (brcmtest < 0) 565 return brcmtest; 566 567 reg = brcmtest | MII_BRCM_FET_BT_SRE; 568 569 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 570 if (err < 0) 571 return err; 572 573 /* Set the LED mode */ 574 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 575 if (reg < 0) { 576 err = reg; 577 goto done; 578 } 579 580 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 581 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 582 583 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 584 if (err < 0) 585 goto done; 586 587 /* Enable auto MDIX */ 588 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 589 MII_BRCM_FET_SHDW_MC_FAME); 590 if (err < 0) 591 goto done; 592 593 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 594 /* Enable auto power down */ 595 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 596 MII_BRCM_FET_SHDW_AS2_APDE); 597 } 598 599 done: 600 /* Disable shadow register access */ 601 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 602 if (!err) 603 err = err2; 604 605 return err; 606 } 607 608 static int brcm_fet_ack_interrupt(struct phy_device *phydev) 609 { 610 int reg; 611 612 /* Clear pending interrupts. */ 613 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 614 if (reg < 0) 615 return reg; 616 617 return 0; 618 } 619 620 static int brcm_fet_config_intr(struct phy_device *phydev) 621 { 622 int reg, err; 623 624 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 625 if (reg < 0) 626 return reg; 627 628 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 629 err = brcm_fet_ack_interrupt(phydev); 630 if (err) 631 return err; 632 633 reg &= ~MII_BRCM_FET_IR_MASK; 634 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 635 } else { 636 reg |= MII_BRCM_FET_IR_MASK; 637 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 638 if (err) 639 return err; 640 641 err = brcm_fet_ack_interrupt(phydev); 642 } 643 644 return err; 645 } 646 647 static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev) 648 { 649 int irq_status; 650 651 irq_status = phy_read(phydev, MII_BRCM_FET_INTREG); 652 if (irq_status < 0) { 653 phy_error(phydev); 654 return IRQ_NONE; 655 } 656 657 if (irq_status == 0) 658 return IRQ_NONE; 659 660 phy_trigger_machine(phydev); 661 662 return IRQ_HANDLED; 663 } 664 665 struct bcm53xx_phy_priv { 666 u64 *stats; 667 }; 668 669 static int bcm53xx_phy_probe(struct phy_device *phydev) 670 { 671 struct bcm53xx_phy_priv *priv; 672 673 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 674 if (!priv) 675 return -ENOMEM; 676 677 phydev->priv = priv; 678 679 priv->stats = devm_kcalloc(&phydev->mdio.dev, 680 bcm_phy_get_sset_count(phydev), sizeof(u64), 681 GFP_KERNEL); 682 if (!priv->stats) 683 return -ENOMEM; 684 685 return 0; 686 } 687 688 static void bcm53xx_phy_get_stats(struct phy_device *phydev, 689 struct ethtool_stats *stats, u64 *data) 690 { 691 struct bcm53xx_phy_priv *priv = phydev->priv; 692 693 bcm_phy_get_stats(phydev, priv->stats, stats, data); 694 } 695 696 static struct phy_driver broadcom_drivers[] = { 697 { 698 .phy_id = PHY_ID_BCM5411, 699 .phy_id_mask = 0xfffffff0, 700 .name = "Broadcom BCM5411", 701 /* PHY_GBIT_FEATURES */ 702 .config_init = bcm54xx_config_init, 703 .config_intr = bcm_phy_config_intr, 704 .handle_interrupt = bcm_phy_handle_interrupt, 705 }, { 706 .phy_id = PHY_ID_BCM5421, 707 .phy_id_mask = 0xfffffff0, 708 .name = "Broadcom BCM5421", 709 /* PHY_GBIT_FEATURES */ 710 .config_init = bcm54xx_config_init, 711 .config_intr = bcm_phy_config_intr, 712 .handle_interrupt = bcm_phy_handle_interrupt, 713 }, { 714 .phy_id = PHY_ID_BCM54210E, 715 .phy_id_mask = 0xfffffff0, 716 .name = "Broadcom BCM54210E", 717 /* PHY_GBIT_FEATURES */ 718 .config_init = bcm54xx_config_init, 719 .config_intr = bcm_phy_config_intr, 720 .handle_interrupt = bcm_phy_handle_interrupt, 721 }, { 722 .phy_id = PHY_ID_BCM5461, 723 .phy_id_mask = 0xfffffff0, 724 .name = "Broadcom BCM5461", 725 /* PHY_GBIT_FEATURES */ 726 .config_init = bcm54xx_config_init, 727 .config_intr = bcm_phy_config_intr, 728 .handle_interrupt = bcm_phy_handle_interrupt, 729 }, { 730 .phy_id = PHY_ID_BCM54612E, 731 .phy_id_mask = 0xfffffff0, 732 .name = "Broadcom BCM54612E", 733 /* PHY_GBIT_FEATURES */ 734 .config_init = bcm54xx_config_init, 735 .config_intr = bcm_phy_config_intr, 736 .handle_interrupt = bcm_phy_handle_interrupt, 737 }, { 738 .phy_id = PHY_ID_BCM54616S, 739 .phy_id_mask = 0xfffffff0, 740 .name = "Broadcom BCM54616S", 741 /* PHY_GBIT_FEATURES */ 742 .config_init = bcm54xx_config_init, 743 .config_aneg = bcm54616s_config_aneg, 744 .config_intr = bcm_phy_config_intr, 745 .handle_interrupt = bcm_phy_handle_interrupt, 746 .read_status = bcm54616s_read_status, 747 .probe = bcm54616s_probe, 748 }, { 749 .phy_id = PHY_ID_BCM5464, 750 .phy_id_mask = 0xfffffff0, 751 .name = "Broadcom BCM5464", 752 /* PHY_GBIT_FEATURES */ 753 .config_init = bcm54xx_config_init, 754 .config_intr = bcm_phy_config_intr, 755 .handle_interrupt = bcm_phy_handle_interrupt, 756 .suspend = genphy_suspend, 757 .resume = genphy_resume, 758 }, { 759 .phy_id = PHY_ID_BCM5481, 760 .phy_id_mask = 0xfffffff0, 761 .name = "Broadcom BCM5481", 762 /* PHY_GBIT_FEATURES */ 763 .config_init = bcm54xx_config_init, 764 .config_aneg = bcm5481_config_aneg, 765 .config_intr = bcm_phy_config_intr, 766 .handle_interrupt = bcm_phy_handle_interrupt, 767 }, { 768 .phy_id = PHY_ID_BCM54810, 769 .phy_id_mask = 0xfffffff0, 770 .name = "Broadcom BCM54810", 771 /* PHY_GBIT_FEATURES */ 772 .config_init = bcm54xx_config_init, 773 .config_aneg = bcm5481_config_aneg, 774 .config_intr = bcm_phy_config_intr, 775 .handle_interrupt = bcm_phy_handle_interrupt, 776 .suspend = genphy_suspend, 777 .resume = bcm54xx_resume, 778 }, { 779 .phy_id = PHY_ID_BCM54811, 780 .phy_id_mask = 0xfffffff0, 781 .name = "Broadcom BCM54811", 782 /* PHY_GBIT_FEATURES */ 783 .config_init = bcm54811_config_init, 784 .config_aneg = bcm5481_config_aneg, 785 .config_intr = bcm_phy_config_intr, 786 .handle_interrupt = bcm_phy_handle_interrupt, 787 .suspend = genphy_suspend, 788 .resume = bcm54xx_resume, 789 }, { 790 .phy_id = PHY_ID_BCM5482, 791 .phy_id_mask = 0xfffffff0, 792 .name = "Broadcom BCM5482", 793 /* PHY_GBIT_FEATURES */ 794 .config_init = bcm54xx_config_init, 795 .config_intr = bcm_phy_config_intr, 796 .handle_interrupt = bcm_phy_handle_interrupt, 797 }, { 798 .phy_id = PHY_ID_BCM50610, 799 .phy_id_mask = 0xfffffff0, 800 .name = "Broadcom BCM50610", 801 /* PHY_GBIT_FEATURES */ 802 .config_init = bcm54xx_config_init, 803 .config_intr = bcm_phy_config_intr, 804 .handle_interrupt = bcm_phy_handle_interrupt, 805 }, { 806 .phy_id = PHY_ID_BCM50610M, 807 .phy_id_mask = 0xfffffff0, 808 .name = "Broadcom BCM50610M", 809 /* PHY_GBIT_FEATURES */ 810 .config_init = bcm54xx_config_init, 811 .config_intr = bcm_phy_config_intr, 812 .handle_interrupt = bcm_phy_handle_interrupt, 813 }, { 814 .phy_id = PHY_ID_BCM57780, 815 .phy_id_mask = 0xfffffff0, 816 .name = "Broadcom BCM57780", 817 /* PHY_GBIT_FEATURES */ 818 .config_init = bcm54xx_config_init, 819 .config_intr = bcm_phy_config_intr, 820 .handle_interrupt = bcm_phy_handle_interrupt, 821 }, { 822 .phy_id = PHY_ID_BCMAC131, 823 .phy_id_mask = 0xfffffff0, 824 .name = "Broadcom BCMAC131", 825 /* PHY_BASIC_FEATURES */ 826 .config_init = brcm_fet_config_init, 827 .config_intr = brcm_fet_config_intr, 828 .handle_interrupt = brcm_fet_handle_interrupt, 829 }, { 830 .phy_id = PHY_ID_BCM5241, 831 .phy_id_mask = 0xfffffff0, 832 .name = "Broadcom BCM5241", 833 /* PHY_BASIC_FEATURES */ 834 .config_init = brcm_fet_config_init, 835 .config_intr = brcm_fet_config_intr, 836 .handle_interrupt = brcm_fet_handle_interrupt, 837 }, { 838 .phy_id = PHY_ID_BCM5395, 839 .phy_id_mask = 0xfffffff0, 840 .name = "Broadcom BCM5395", 841 .flags = PHY_IS_INTERNAL, 842 /* PHY_GBIT_FEATURES */ 843 .get_sset_count = bcm_phy_get_sset_count, 844 .get_strings = bcm_phy_get_strings, 845 .get_stats = bcm53xx_phy_get_stats, 846 .probe = bcm53xx_phy_probe, 847 }, { 848 .phy_id = PHY_ID_BCM53125, 849 .phy_id_mask = 0xfffffff0, 850 .name = "Broadcom BCM53125", 851 .flags = PHY_IS_INTERNAL, 852 /* PHY_GBIT_FEATURES */ 853 .get_sset_count = bcm_phy_get_sset_count, 854 .get_strings = bcm_phy_get_strings, 855 .get_stats = bcm53xx_phy_get_stats, 856 .probe = bcm53xx_phy_probe, 857 .config_init = bcm54xx_config_init, 858 .config_intr = bcm_phy_config_intr, 859 .handle_interrupt = bcm_phy_handle_interrupt, 860 }, { 861 .phy_id = PHY_ID_BCM89610, 862 .phy_id_mask = 0xfffffff0, 863 .name = "Broadcom BCM89610", 864 /* PHY_GBIT_FEATURES */ 865 .config_init = bcm54xx_config_init, 866 .config_intr = bcm_phy_config_intr, 867 .handle_interrupt = bcm_phy_handle_interrupt, 868 } }; 869 870 module_phy_driver(broadcom_drivers); 871 872 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 873 { PHY_ID_BCM5411, 0xfffffff0 }, 874 { PHY_ID_BCM5421, 0xfffffff0 }, 875 { PHY_ID_BCM54210E, 0xfffffff0 }, 876 { PHY_ID_BCM5461, 0xfffffff0 }, 877 { PHY_ID_BCM54612E, 0xfffffff0 }, 878 { PHY_ID_BCM54616S, 0xfffffff0 }, 879 { PHY_ID_BCM5464, 0xfffffff0 }, 880 { PHY_ID_BCM5481, 0xfffffff0 }, 881 { PHY_ID_BCM54810, 0xfffffff0 }, 882 { PHY_ID_BCM54811, 0xfffffff0 }, 883 { PHY_ID_BCM5482, 0xfffffff0 }, 884 { PHY_ID_BCM50610, 0xfffffff0 }, 885 { PHY_ID_BCM50610M, 0xfffffff0 }, 886 { PHY_ID_BCM57780, 0xfffffff0 }, 887 { PHY_ID_BCMAC131, 0xfffffff0 }, 888 { PHY_ID_BCM5241, 0xfffffff0 }, 889 { PHY_ID_BCM5395, 0xfffffff0 }, 890 { PHY_ID_BCM53125, 0xfffffff0 }, 891 { PHY_ID_BCM89610, 0xfffffff0 }, 892 { } 893 }; 894 895 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 896