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 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 && 199 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) 200 return; 201 202 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); 203 if (val < 0) 204 return; 205 206 orig = val; 207 208 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 209 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 210 BRCM_PHY_REV(phydev) >= 0x3) { 211 /* 212 * Here, bit 0 _disables_ CLK125 when set. 213 * This bit is set by default. 214 */ 215 clk125en = false; 216 } else { 217 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { 218 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) { 219 /* Here, bit 0 _enables_ CLK125 when set */ 220 val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; 221 } 222 clk125en = false; 223 } 224 } 225 226 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 227 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; 228 else 229 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 230 231 if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) { 232 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 || 233 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811) 234 val |= BCM54810_SHD_SCR3_TRDDAPD; 235 else 236 val |= BCM54XX_SHD_SCR3_TRDDAPD; 237 } 238 239 if (orig != val) 240 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); 241 242 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); 243 if (val < 0) 244 return; 245 246 orig = val; 247 248 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 249 val |= BCM54XX_SHD_APD_EN; 250 else 251 val &= ~BCM54XX_SHD_APD_EN; 252 253 if (orig != val) 254 bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); 255 } 256 257 static int bcm54xx_config_init(struct phy_device *phydev) 258 { 259 int reg, err, val; 260 261 reg = phy_read(phydev, MII_BCM54XX_ECR); 262 if (reg < 0) 263 return reg; 264 265 /* Mask interrupts globally. */ 266 reg |= MII_BCM54XX_ECR_IM; 267 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 268 if (err < 0) 269 return err; 270 271 /* Unmask events we are interested in. */ 272 reg = ~(MII_BCM54XX_INT_DUPLEX | 273 MII_BCM54XX_INT_SPEED | 274 MII_BCM54XX_INT_LINK); 275 err = phy_write(phydev, MII_BCM54XX_IMR, reg); 276 if (err < 0) 277 return err; 278 279 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 280 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 281 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) 282 bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); 283 284 bcm54xx_adjust_rxrefclk(phydev); 285 286 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) { 287 err = bcm54210e_config_init(phydev); 288 if (err) 289 return err; 290 } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) { 291 err = bcm54612e_config_init(phydev); 292 if (err) 293 return err; 294 } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) { 295 /* For BCM54810, we need to disable BroadR-Reach function */ 296 val = bcm_phy_read_exp(phydev, 297 BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 298 val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 299 err = bcm_phy_write_exp(phydev, 300 BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 301 val); 302 if (err < 0) 303 return err; 304 } 305 306 bcm54xx_phydsp_config(phydev); 307 308 /* Encode link speed into LED1 and LED3 pair (green/amber). 309 * Also flash these two LEDs on activity. This means configuring 310 * them for MULTICOLOR and encoding link/activity into them. 311 */ 312 val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | 313 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); 314 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); 315 316 val = BCM_LED_MULTICOLOR_IN_PHASE | 317 BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | 318 BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); 319 bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); 320 321 return 0; 322 } 323 324 static int bcm54xx_resume(struct phy_device *phydev) 325 { 326 int ret; 327 328 /* Writes to register other than BMCR would be ignored 329 * unless we clear the PDOWN bit first 330 */ 331 ret = genphy_resume(phydev); 332 if (ret < 0) 333 return ret; 334 335 return bcm54xx_config_init(phydev); 336 } 337 338 static int bcm54811_config_init(struct phy_device *phydev) 339 { 340 int err, reg; 341 342 /* Disable BroadR-Reach function. */ 343 reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 344 reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 345 err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 346 reg); 347 if (err < 0) 348 return err; 349 350 err = bcm54xx_config_init(phydev); 351 352 /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ 353 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { 354 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); 355 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, 356 BCM54612E_LED4_CLK125OUT_EN | reg); 357 if (err < 0) 358 return err; 359 } 360 361 return err; 362 } 363 364 static int bcm5482_config_init(struct phy_device *phydev) 365 { 366 int err, reg; 367 368 err = bcm54xx_config_init(phydev); 369 370 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 371 /* 372 * Enable secondary SerDes and its use as an LED source 373 */ 374 reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD); 375 bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD, 376 reg | 377 BCM5482_SHD_SSD_LEDM | 378 BCM5482_SHD_SSD_EN); 379 380 /* 381 * Enable SGMII slave mode and auto-detection 382 */ 383 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; 384 err = bcm_phy_read_exp(phydev, reg); 385 if (err < 0) 386 return err; 387 err = bcm_phy_write_exp(phydev, reg, err | 388 BCM5482_SSD_SGMII_SLAVE_EN | 389 BCM5482_SSD_SGMII_SLAVE_AD); 390 if (err < 0) 391 return err; 392 393 /* 394 * Disable secondary SerDes powerdown 395 */ 396 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; 397 err = bcm_phy_read_exp(phydev, reg); 398 if (err < 0) 399 return err; 400 err = bcm_phy_write_exp(phydev, reg, 401 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); 402 if (err < 0) 403 return err; 404 405 /* 406 * Select 1000BASE-X register set (primary SerDes) 407 */ 408 reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 409 bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, 410 reg | BCM54XX_SHD_MODE_1000BX); 411 412 /* 413 * LED1=ACTIVITYLED, LED3=LINKSPD[2] 414 * (Use LED1 as secondary SerDes ACTIVITY LED) 415 */ 416 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, 417 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | 418 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); 419 420 /* 421 * Auto-negotiation doesn't seem to work quite right 422 * in this mode, so we disable it and force it to the 423 * right speed/duplex setting. Only 'link status' 424 * is important. 425 */ 426 phydev->autoneg = AUTONEG_DISABLE; 427 phydev->speed = SPEED_1000; 428 phydev->duplex = DUPLEX_FULL; 429 } 430 431 return err; 432 } 433 434 static int bcm5482_read_status(struct phy_device *phydev) 435 { 436 int err; 437 438 err = genphy_read_status(phydev); 439 440 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 441 /* 442 * Only link status matters for 1000Base-X mode, so force 443 * 1000 Mbit/s full-duplex status 444 */ 445 if (phydev->link) { 446 phydev->speed = SPEED_1000; 447 phydev->duplex = DUPLEX_FULL; 448 } 449 } 450 451 return err; 452 } 453 454 static int bcm5481_config_aneg(struct phy_device *phydev) 455 { 456 struct device_node *np = phydev->mdio.dev.of_node; 457 int ret; 458 459 /* Aneg firstly. */ 460 ret = genphy_config_aneg(phydev); 461 462 /* Then we can set up the delay. */ 463 bcm54xx_config_clock_delay(phydev); 464 465 if (of_property_read_bool(np, "enet-phy-lane-swap")) { 466 /* Lane Swap - Undocumented register...magic! */ 467 ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9, 468 0x11B); 469 if (ret < 0) 470 return ret; 471 } 472 473 return ret; 474 } 475 476 static int bcm54616s_probe(struct phy_device *phydev) 477 { 478 int val, intf_sel; 479 480 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 481 if (val < 0) 482 return val; 483 484 /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] 485 * is 01b, and the link between PHY and its link partner can be 486 * either 1000Base-X or 100Base-FX. 487 * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX 488 * support is still missing as of now. 489 */ 490 intf_sel = (val & BCM54XX_SHD_INTF_SEL_MASK) >> 1; 491 if (intf_sel == 1) { 492 val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); 493 if (val < 0) 494 return val; 495 496 /* Bit 0 of the SerDes 100-FX Control register, when set 497 * to 1, sets the MII/RGMII -> 100BASE-FX configuration. 498 * When this bit is set to 0, it sets the GMII/RGMII -> 499 * 1000BASE-X configuration. 500 */ 501 if (!(val & BCM54616S_100FX_MODE)) 502 phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX; 503 } 504 505 return 0; 506 } 507 508 static int bcm54616s_config_aneg(struct phy_device *phydev) 509 { 510 int ret; 511 512 /* Aneg firstly. */ 513 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) 514 ret = genphy_c37_config_aneg(phydev); 515 else 516 ret = genphy_config_aneg(phydev); 517 518 /* Then we can set up the delay. */ 519 bcm54xx_config_clock_delay(phydev); 520 521 return ret; 522 } 523 524 static int bcm54616s_read_status(struct phy_device *phydev) 525 { 526 int err; 527 528 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) 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 bcm53xx_phy_priv { 675 u64 *stats; 676 }; 677 678 static int bcm53xx_phy_probe(struct phy_device *phydev) 679 { 680 struct bcm53xx_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 bcm53xx_phy_get_stats(struct phy_device *phydev, 698 struct ethtool_stats *stats, u64 *data) 699 { 700 struct bcm53xx_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 .config_init = bcm54xx_config_init, 712 .config_intr = bcm_phy_config_intr, 713 .handle_interrupt = bcm_phy_handle_interrupt, 714 }, { 715 .phy_id = PHY_ID_BCM5421, 716 .phy_id_mask = 0xfffffff0, 717 .name = "Broadcom BCM5421", 718 /* PHY_GBIT_FEATURES */ 719 .config_init = bcm54xx_config_init, 720 .config_intr = bcm_phy_config_intr, 721 .handle_interrupt = bcm_phy_handle_interrupt, 722 }, { 723 .phy_id = PHY_ID_BCM54210E, 724 .phy_id_mask = 0xfffffff0, 725 .name = "Broadcom BCM54210E", 726 /* PHY_GBIT_FEATURES */ 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_BCM5461, 732 .phy_id_mask = 0xfffffff0, 733 .name = "Broadcom BCM5461", 734 /* PHY_GBIT_FEATURES */ 735 .config_init = bcm54xx_config_init, 736 .config_intr = bcm_phy_config_intr, 737 .handle_interrupt = bcm_phy_handle_interrupt, 738 }, { 739 .phy_id = PHY_ID_BCM54612E, 740 .phy_id_mask = 0xfffffff0, 741 .name = "Broadcom BCM54612E", 742 /* PHY_GBIT_FEATURES */ 743 .config_init = bcm54xx_config_init, 744 .config_intr = bcm_phy_config_intr, 745 .handle_interrupt = bcm_phy_handle_interrupt, 746 }, { 747 .phy_id = PHY_ID_BCM54616S, 748 .phy_id_mask = 0xfffffff0, 749 .name = "Broadcom BCM54616S", 750 /* PHY_GBIT_FEATURES */ 751 .config_init = bcm54xx_config_init, 752 .config_aneg = bcm54616s_config_aneg, 753 .config_intr = bcm_phy_config_intr, 754 .handle_interrupt = bcm_phy_handle_interrupt, 755 .read_status = bcm54616s_read_status, 756 .probe = bcm54616s_probe, 757 }, { 758 .phy_id = PHY_ID_BCM5464, 759 .phy_id_mask = 0xfffffff0, 760 .name = "Broadcom BCM5464", 761 /* PHY_GBIT_FEATURES */ 762 .config_init = bcm54xx_config_init, 763 .config_intr = bcm_phy_config_intr, 764 .handle_interrupt = bcm_phy_handle_interrupt, 765 .suspend = genphy_suspend, 766 .resume = genphy_resume, 767 }, { 768 .phy_id = PHY_ID_BCM5481, 769 .phy_id_mask = 0xfffffff0, 770 .name = "Broadcom BCM5481", 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 }, { 777 .phy_id = PHY_ID_BCM54810, 778 .phy_id_mask = 0xfffffff0, 779 .name = "Broadcom BCM54810", 780 /* PHY_GBIT_FEATURES */ 781 .config_init = bcm54xx_config_init, 782 .config_aneg = bcm5481_config_aneg, 783 .config_intr = bcm_phy_config_intr, 784 .handle_interrupt = bcm_phy_handle_interrupt, 785 .suspend = genphy_suspend, 786 .resume = bcm54xx_resume, 787 }, { 788 .phy_id = PHY_ID_BCM54811, 789 .phy_id_mask = 0xfffffff0, 790 .name = "Broadcom BCM54811", 791 /* PHY_GBIT_FEATURES */ 792 .config_init = bcm54811_config_init, 793 .config_aneg = bcm5481_config_aneg, 794 .config_intr = bcm_phy_config_intr, 795 .handle_interrupt = bcm_phy_handle_interrupt, 796 .suspend = genphy_suspend, 797 .resume = bcm54xx_resume, 798 }, { 799 .phy_id = PHY_ID_BCM5482, 800 .phy_id_mask = 0xfffffff0, 801 .name = "Broadcom BCM5482", 802 /* PHY_GBIT_FEATURES */ 803 .config_init = bcm5482_config_init, 804 .read_status = bcm5482_read_status, 805 .config_intr = bcm_phy_config_intr, 806 .handle_interrupt = bcm_phy_handle_interrupt, 807 }, { 808 .phy_id = PHY_ID_BCM50610, 809 .phy_id_mask = 0xfffffff0, 810 .name = "Broadcom BCM50610", 811 /* PHY_GBIT_FEATURES */ 812 .config_init = bcm54xx_config_init, 813 .config_intr = bcm_phy_config_intr, 814 .handle_interrupt = bcm_phy_handle_interrupt, 815 }, { 816 .phy_id = PHY_ID_BCM50610M, 817 .phy_id_mask = 0xfffffff0, 818 .name = "Broadcom BCM50610M", 819 /* PHY_GBIT_FEATURES */ 820 .config_init = bcm54xx_config_init, 821 .config_intr = bcm_phy_config_intr, 822 .handle_interrupt = bcm_phy_handle_interrupt, 823 }, { 824 .phy_id = PHY_ID_BCM57780, 825 .phy_id_mask = 0xfffffff0, 826 .name = "Broadcom BCM57780", 827 /* PHY_GBIT_FEATURES */ 828 .config_init = bcm54xx_config_init, 829 .config_intr = bcm_phy_config_intr, 830 .handle_interrupt = bcm_phy_handle_interrupt, 831 }, { 832 .phy_id = PHY_ID_BCMAC131, 833 .phy_id_mask = 0xfffffff0, 834 .name = "Broadcom BCMAC131", 835 /* PHY_BASIC_FEATURES */ 836 .config_init = brcm_fet_config_init, 837 .config_intr = brcm_fet_config_intr, 838 .handle_interrupt = brcm_fet_handle_interrupt, 839 }, { 840 .phy_id = PHY_ID_BCM5241, 841 .phy_id_mask = 0xfffffff0, 842 .name = "Broadcom BCM5241", 843 /* PHY_BASIC_FEATURES */ 844 .config_init = brcm_fet_config_init, 845 .config_intr = brcm_fet_config_intr, 846 .handle_interrupt = brcm_fet_handle_interrupt, 847 }, { 848 .phy_id = PHY_ID_BCM5395, 849 .phy_id_mask = 0xfffffff0, 850 .name = "Broadcom BCM5395", 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 }, { 858 .phy_id = PHY_ID_BCM53125, 859 .phy_id_mask = 0xfffffff0, 860 .name = "Broadcom BCM53125", 861 .flags = PHY_IS_INTERNAL, 862 /* PHY_GBIT_FEATURES */ 863 .get_sset_count = bcm_phy_get_sset_count, 864 .get_strings = bcm_phy_get_strings, 865 .get_stats = bcm53xx_phy_get_stats, 866 .probe = bcm53xx_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_BCM89610, 872 .phy_id_mask = 0xfffffff0, 873 .name = "Broadcom BCM89610", 874 /* PHY_GBIT_FEATURES */ 875 .config_init = bcm54xx_config_init, 876 .config_intr = bcm_phy_config_intr, 877 .handle_interrupt = bcm_phy_handle_interrupt, 878 } }; 879 880 module_phy_driver(broadcom_drivers); 881 882 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 883 { PHY_ID_BCM5411, 0xfffffff0 }, 884 { PHY_ID_BCM5421, 0xfffffff0 }, 885 { PHY_ID_BCM54210E, 0xfffffff0 }, 886 { PHY_ID_BCM5461, 0xfffffff0 }, 887 { PHY_ID_BCM54612E, 0xfffffff0 }, 888 { PHY_ID_BCM54616S, 0xfffffff0 }, 889 { PHY_ID_BCM5464, 0xfffffff0 }, 890 { PHY_ID_BCM5481, 0xfffffff0 }, 891 { PHY_ID_BCM54810, 0xfffffff0 }, 892 { PHY_ID_BCM54811, 0xfffffff0 }, 893 { PHY_ID_BCM5482, 0xfffffff0 }, 894 { PHY_ID_BCM50610, 0xfffffff0 }, 895 { PHY_ID_BCM50610M, 0xfffffff0 }, 896 { PHY_ID_BCM57780, 0xfffffff0 }, 897 { PHY_ID_BCMAC131, 0xfffffff0 }, 898 { PHY_ID_BCM5241, 0xfffffff0 }, 899 { PHY_ID_BCM5395, 0xfffffff0 }, 900 { PHY_ID_BCM53125, 0xfffffff0 }, 901 { PHY_ID_BCM89610, 0xfffffff0 }, 902 { } 903 }; 904 905 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 906