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 reg &= ~MII_BRCM_FET_IR_MASK; 639 else 640 reg |= MII_BRCM_FET_IR_MASK; 641 642 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 643 return err; 644 } 645 646 struct bcm53xx_phy_priv { 647 u64 *stats; 648 }; 649 650 static int bcm53xx_phy_probe(struct phy_device *phydev) 651 { 652 struct bcm53xx_phy_priv *priv; 653 654 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 655 if (!priv) 656 return -ENOMEM; 657 658 phydev->priv = priv; 659 660 priv->stats = devm_kcalloc(&phydev->mdio.dev, 661 bcm_phy_get_sset_count(phydev), sizeof(u64), 662 GFP_KERNEL); 663 if (!priv->stats) 664 return -ENOMEM; 665 666 return 0; 667 } 668 669 static void bcm53xx_phy_get_stats(struct phy_device *phydev, 670 struct ethtool_stats *stats, u64 *data) 671 { 672 struct bcm53xx_phy_priv *priv = phydev->priv; 673 674 bcm_phy_get_stats(phydev, priv->stats, stats, data); 675 } 676 677 static struct phy_driver broadcom_drivers[] = { 678 { 679 .phy_id = PHY_ID_BCM5411, 680 .phy_id_mask = 0xfffffff0, 681 .name = "Broadcom BCM5411", 682 /* PHY_GBIT_FEATURES */ 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_BCM5421, 688 .phy_id_mask = 0xfffffff0, 689 .name = "Broadcom BCM5421", 690 /* PHY_GBIT_FEATURES */ 691 .config_init = bcm54xx_config_init, 692 .ack_interrupt = bcm_phy_ack_intr, 693 .config_intr = bcm_phy_config_intr, 694 }, { 695 .phy_id = PHY_ID_BCM54210E, 696 .phy_id_mask = 0xfffffff0, 697 .name = "Broadcom BCM54210E", 698 /* PHY_GBIT_FEATURES */ 699 .config_init = bcm54xx_config_init, 700 .ack_interrupt = bcm_phy_ack_intr, 701 .config_intr = bcm_phy_config_intr, 702 }, { 703 .phy_id = PHY_ID_BCM5461, 704 .phy_id_mask = 0xfffffff0, 705 .name = "Broadcom BCM5461", 706 /* PHY_GBIT_FEATURES */ 707 .config_init = bcm54xx_config_init, 708 .ack_interrupt = bcm_phy_ack_intr, 709 .config_intr = bcm_phy_config_intr, 710 }, { 711 .phy_id = PHY_ID_BCM54612E, 712 .phy_id_mask = 0xfffffff0, 713 .name = "Broadcom BCM54612E", 714 /* PHY_GBIT_FEATURES */ 715 .config_init = bcm54xx_config_init, 716 .ack_interrupt = bcm_phy_ack_intr, 717 .config_intr = bcm_phy_config_intr, 718 }, { 719 .phy_id = PHY_ID_BCM54616S, 720 .phy_id_mask = 0xfffffff0, 721 .name = "Broadcom BCM54616S", 722 /* PHY_GBIT_FEATURES */ 723 .config_init = bcm54xx_config_init, 724 .config_aneg = bcm54616s_config_aneg, 725 .ack_interrupt = bcm_phy_ack_intr, 726 .config_intr = bcm_phy_config_intr, 727 .read_status = bcm54616s_read_status, 728 .probe = bcm54616s_probe, 729 }, { 730 .phy_id = PHY_ID_BCM5464, 731 .phy_id_mask = 0xfffffff0, 732 .name = "Broadcom BCM5464", 733 /* PHY_GBIT_FEATURES */ 734 .config_init = bcm54xx_config_init, 735 .ack_interrupt = bcm_phy_ack_intr, 736 .config_intr = bcm_phy_config_intr, 737 .suspend = genphy_suspend, 738 .resume = genphy_resume, 739 }, { 740 .phy_id = PHY_ID_BCM5481, 741 .phy_id_mask = 0xfffffff0, 742 .name = "Broadcom BCM5481", 743 /* PHY_GBIT_FEATURES */ 744 .config_init = bcm54xx_config_init, 745 .config_aneg = bcm5481_config_aneg, 746 .ack_interrupt = bcm_phy_ack_intr, 747 .config_intr = bcm_phy_config_intr, 748 }, { 749 .phy_id = PHY_ID_BCM54810, 750 .phy_id_mask = 0xfffffff0, 751 .name = "Broadcom BCM54810", 752 /* PHY_GBIT_FEATURES */ 753 .config_init = bcm54xx_config_init, 754 .config_aneg = bcm5481_config_aneg, 755 .ack_interrupt = bcm_phy_ack_intr, 756 .config_intr = bcm_phy_config_intr, 757 .suspend = genphy_suspend, 758 .resume = bcm54xx_resume, 759 }, { 760 .phy_id = PHY_ID_BCM54811, 761 .phy_id_mask = 0xfffffff0, 762 .name = "Broadcom BCM54811", 763 /* PHY_GBIT_FEATURES */ 764 .config_init = bcm54811_config_init, 765 .config_aneg = bcm5481_config_aneg, 766 .ack_interrupt = bcm_phy_ack_intr, 767 .config_intr = bcm_phy_config_intr, 768 .suspend = genphy_suspend, 769 .resume = bcm54xx_resume, 770 }, { 771 .phy_id = PHY_ID_BCM5482, 772 .phy_id_mask = 0xfffffff0, 773 .name = "Broadcom BCM5482", 774 /* PHY_GBIT_FEATURES */ 775 .config_init = bcm5482_config_init, 776 .read_status = bcm5482_read_status, 777 .ack_interrupt = bcm_phy_ack_intr, 778 .config_intr = bcm_phy_config_intr, 779 }, { 780 .phy_id = PHY_ID_BCM50610, 781 .phy_id_mask = 0xfffffff0, 782 .name = "Broadcom BCM50610", 783 /* PHY_GBIT_FEATURES */ 784 .config_init = bcm54xx_config_init, 785 .ack_interrupt = bcm_phy_ack_intr, 786 .config_intr = bcm_phy_config_intr, 787 }, { 788 .phy_id = PHY_ID_BCM50610M, 789 .phy_id_mask = 0xfffffff0, 790 .name = "Broadcom BCM50610M", 791 /* PHY_GBIT_FEATURES */ 792 .config_init = bcm54xx_config_init, 793 .ack_interrupt = bcm_phy_ack_intr, 794 .config_intr = bcm_phy_config_intr, 795 }, { 796 .phy_id = PHY_ID_BCM57780, 797 .phy_id_mask = 0xfffffff0, 798 .name = "Broadcom BCM57780", 799 /* PHY_GBIT_FEATURES */ 800 .config_init = bcm54xx_config_init, 801 .ack_interrupt = bcm_phy_ack_intr, 802 .config_intr = bcm_phy_config_intr, 803 }, { 804 .phy_id = PHY_ID_BCMAC131, 805 .phy_id_mask = 0xfffffff0, 806 .name = "Broadcom BCMAC131", 807 /* PHY_BASIC_FEATURES */ 808 .config_init = brcm_fet_config_init, 809 .ack_interrupt = brcm_fet_ack_interrupt, 810 .config_intr = brcm_fet_config_intr, 811 }, { 812 .phy_id = PHY_ID_BCM5241, 813 .phy_id_mask = 0xfffffff0, 814 .name = "Broadcom BCM5241", 815 /* PHY_BASIC_FEATURES */ 816 .config_init = brcm_fet_config_init, 817 .ack_interrupt = brcm_fet_ack_interrupt, 818 .config_intr = brcm_fet_config_intr, 819 }, { 820 .phy_id = PHY_ID_BCM5395, 821 .phy_id_mask = 0xfffffff0, 822 .name = "Broadcom BCM5395", 823 .flags = PHY_IS_INTERNAL, 824 /* PHY_GBIT_FEATURES */ 825 .get_sset_count = bcm_phy_get_sset_count, 826 .get_strings = bcm_phy_get_strings, 827 .get_stats = bcm53xx_phy_get_stats, 828 .probe = bcm53xx_phy_probe, 829 }, { 830 .phy_id = PHY_ID_BCM53125, 831 .phy_id_mask = 0xfffffff0, 832 .name = "Broadcom BCM53125", 833 .flags = PHY_IS_INTERNAL, 834 /* PHY_GBIT_FEATURES */ 835 .get_sset_count = bcm_phy_get_sset_count, 836 .get_strings = bcm_phy_get_strings, 837 .get_stats = bcm53xx_phy_get_stats, 838 .probe = bcm53xx_phy_probe, 839 .config_init = bcm54xx_config_init, 840 .ack_interrupt = bcm_phy_ack_intr, 841 .config_intr = bcm_phy_config_intr, 842 }, { 843 .phy_id = PHY_ID_BCM89610, 844 .phy_id_mask = 0xfffffff0, 845 .name = "Broadcom BCM89610", 846 /* PHY_GBIT_FEATURES */ 847 .config_init = bcm54xx_config_init, 848 .ack_interrupt = bcm_phy_ack_intr, 849 .config_intr = bcm_phy_config_intr, 850 } }; 851 852 module_phy_driver(broadcom_drivers); 853 854 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 855 { PHY_ID_BCM5411, 0xfffffff0 }, 856 { PHY_ID_BCM5421, 0xfffffff0 }, 857 { PHY_ID_BCM54210E, 0xfffffff0 }, 858 { PHY_ID_BCM5461, 0xfffffff0 }, 859 { PHY_ID_BCM54612E, 0xfffffff0 }, 860 { PHY_ID_BCM54616S, 0xfffffff0 }, 861 { PHY_ID_BCM5464, 0xfffffff0 }, 862 { PHY_ID_BCM5481, 0xfffffff0 }, 863 { PHY_ID_BCM54810, 0xfffffff0 }, 864 { PHY_ID_BCM54811, 0xfffffff0 }, 865 { PHY_ID_BCM5482, 0xfffffff0 }, 866 { PHY_ID_BCM50610, 0xfffffff0 }, 867 { PHY_ID_BCM50610M, 0xfffffff0 }, 868 { PHY_ID_BCM57780, 0xfffffff0 }, 869 { PHY_ID_BCMAC131, 0xfffffff0 }, 870 { PHY_ID_BCM5241, 0xfffffff0 }, 871 { PHY_ID_BCM5395, 0xfffffff0 }, 872 { PHY_ID_BCM53125, 0xfffffff0 }, 873 { PHY_ID_BCM89610, 0xfffffff0 }, 874 { } 875 }; 876 877 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 878