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_iddq_set(struct phy_device *phydev, bool enable) 396 { 397 int ret = 0; 398 399 if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND)) 400 return ret; 401 402 ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL); 403 if (ret < 0) 404 goto out; 405 406 if (enable) 407 ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP; 408 else 409 ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP); 410 411 ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret); 412 out: 413 return ret; 414 } 415 416 static int bcm54xx_suspend(struct phy_device *phydev) 417 { 418 int ret; 419 420 /* We cannot use a read/modify/write here otherwise the PHY gets into 421 * a bad state where its LEDs keep flashing, thus defeating the purpose 422 * of low power mode. 423 */ 424 ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN); 425 if (ret < 0) 426 return ret; 427 428 return bcm54xx_iddq_set(phydev, true); 429 } 430 431 static int bcm54xx_resume(struct phy_device *phydev) 432 { 433 int ret; 434 435 ret = bcm54xx_iddq_set(phydev, false); 436 if (ret < 0) 437 return ret; 438 439 /* Writes to register other than BMCR would be ignored 440 * unless we clear the PDOWN bit first 441 */ 442 ret = genphy_resume(phydev); 443 if (ret < 0) 444 return ret; 445 446 /* Upon exiting power down, the PHY remains in an internal reset state 447 * for 40us 448 */ 449 fsleep(40); 450 451 /* Issue a soft reset after clearing the power down bit 452 * and before doing any other configuration. 453 */ 454 if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) { 455 ret = genphy_soft_reset(phydev); 456 if (ret < 0) 457 return ret; 458 } 459 460 return bcm54xx_config_init(phydev); 461 } 462 463 static int bcm54811_config_init(struct phy_device *phydev) 464 { 465 int err, reg; 466 467 /* Disable BroadR-Reach function. */ 468 reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 469 reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 470 err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 471 reg); 472 if (err < 0) 473 return err; 474 475 err = bcm54xx_config_init(phydev); 476 477 /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ 478 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { 479 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); 480 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, 481 BCM54612E_LED4_CLK125OUT_EN | reg); 482 if (err < 0) 483 return err; 484 } 485 486 return err; 487 } 488 489 static int bcm5481_config_aneg(struct phy_device *phydev) 490 { 491 struct device_node *np = phydev->mdio.dev.of_node; 492 int ret; 493 494 /* Aneg firstly. */ 495 ret = genphy_config_aneg(phydev); 496 497 /* Then we can set up the delay. */ 498 bcm54xx_config_clock_delay(phydev); 499 500 if (of_property_read_bool(np, "enet-phy-lane-swap")) { 501 /* Lane Swap - Undocumented register...magic! */ 502 ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9, 503 0x11B); 504 if (ret < 0) 505 return ret; 506 } 507 508 return ret; 509 } 510 511 struct bcm54616s_phy_priv { 512 bool mode_1000bx_en; 513 }; 514 515 static int bcm54616s_probe(struct phy_device *phydev) 516 { 517 struct bcm54616s_phy_priv *priv; 518 int val; 519 520 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 521 if (!priv) 522 return -ENOMEM; 523 524 phydev->priv = priv; 525 526 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 527 if (val < 0) 528 return val; 529 530 /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] 531 * is 01b, and the link between PHY and its link partner can be 532 * either 1000Base-X or 100Base-FX. 533 * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX 534 * support is still missing as of now. 535 */ 536 if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) { 537 val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); 538 if (val < 0) 539 return val; 540 541 /* Bit 0 of the SerDes 100-FX Control register, when set 542 * to 1, sets the MII/RGMII -> 100BASE-FX configuration. 543 * When this bit is set to 0, it sets the GMII/RGMII -> 544 * 1000BASE-X configuration. 545 */ 546 if (!(val & BCM54616S_100FX_MODE)) 547 priv->mode_1000bx_en = true; 548 549 phydev->port = PORT_FIBRE; 550 } 551 552 return 0; 553 } 554 555 static int bcm54616s_config_aneg(struct phy_device *phydev) 556 { 557 struct bcm54616s_phy_priv *priv = phydev->priv; 558 int ret; 559 560 /* Aneg firstly. */ 561 if (priv->mode_1000bx_en) 562 ret = genphy_c37_config_aneg(phydev); 563 else 564 ret = genphy_config_aneg(phydev); 565 566 /* Then we can set up the delay. */ 567 bcm54xx_config_clock_delay(phydev); 568 569 return ret; 570 } 571 572 static int bcm54616s_read_status(struct phy_device *phydev) 573 { 574 struct bcm54616s_phy_priv *priv = phydev->priv; 575 int err; 576 577 if (priv->mode_1000bx_en) 578 err = genphy_c37_read_status(phydev); 579 else 580 err = genphy_read_status(phydev); 581 582 return err; 583 } 584 585 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 586 { 587 int val; 588 589 val = phy_read(phydev, reg); 590 if (val < 0) 591 return val; 592 593 return phy_write(phydev, reg, val | set); 594 } 595 596 static int brcm_fet_config_init(struct phy_device *phydev) 597 { 598 int reg, err, err2, brcmtest; 599 600 /* Reset the PHY to bring it to a known state. */ 601 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 602 if (err < 0) 603 return err; 604 605 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 606 if (reg < 0) 607 return reg; 608 609 /* Unmask events we are interested in and mask interrupts globally. */ 610 reg = MII_BRCM_FET_IR_DUPLEX_EN | 611 MII_BRCM_FET_IR_SPEED_EN | 612 MII_BRCM_FET_IR_LINK_EN | 613 MII_BRCM_FET_IR_ENABLE | 614 MII_BRCM_FET_IR_MASK; 615 616 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 617 if (err < 0) 618 return err; 619 620 /* Enable shadow register access */ 621 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 622 if (brcmtest < 0) 623 return brcmtest; 624 625 reg = brcmtest | MII_BRCM_FET_BT_SRE; 626 627 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 628 if (err < 0) 629 return err; 630 631 /* Set the LED mode */ 632 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 633 if (reg < 0) { 634 err = reg; 635 goto done; 636 } 637 638 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 639 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 640 641 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 642 if (err < 0) 643 goto done; 644 645 /* Enable auto MDIX */ 646 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 647 MII_BRCM_FET_SHDW_MC_FAME); 648 if (err < 0) 649 goto done; 650 651 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 652 /* Enable auto power down */ 653 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 654 MII_BRCM_FET_SHDW_AS2_APDE); 655 } 656 657 done: 658 /* Disable shadow register access */ 659 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 660 if (!err) 661 err = err2; 662 663 return err; 664 } 665 666 static int brcm_fet_ack_interrupt(struct phy_device *phydev) 667 { 668 int reg; 669 670 /* Clear pending interrupts. */ 671 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 672 if (reg < 0) 673 return reg; 674 675 return 0; 676 } 677 678 static int brcm_fet_config_intr(struct phy_device *phydev) 679 { 680 int reg, err; 681 682 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 683 if (reg < 0) 684 return reg; 685 686 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 687 err = brcm_fet_ack_interrupt(phydev); 688 if (err) 689 return err; 690 691 reg &= ~MII_BRCM_FET_IR_MASK; 692 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 693 } else { 694 reg |= MII_BRCM_FET_IR_MASK; 695 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 696 if (err) 697 return err; 698 699 err = brcm_fet_ack_interrupt(phydev); 700 } 701 702 return err; 703 } 704 705 static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev) 706 { 707 int irq_status; 708 709 irq_status = phy_read(phydev, MII_BRCM_FET_INTREG); 710 if (irq_status < 0) { 711 phy_error(phydev); 712 return IRQ_NONE; 713 } 714 715 if (irq_status == 0) 716 return IRQ_NONE; 717 718 phy_trigger_machine(phydev); 719 720 return IRQ_HANDLED; 721 } 722 723 struct bcm54xx_phy_priv { 724 u64 *stats; 725 }; 726 727 static int bcm54xx_phy_probe(struct phy_device *phydev) 728 { 729 struct bcm54xx_phy_priv *priv; 730 731 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 732 if (!priv) 733 return -ENOMEM; 734 735 phydev->priv = priv; 736 737 priv->stats = devm_kcalloc(&phydev->mdio.dev, 738 bcm_phy_get_sset_count(phydev), sizeof(u64), 739 GFP_KERNEL); 740 if (!priv->stats) 741 return -ENOMEM; 742 743 return 0; 744 } 745 746 static void bcm54xx_get_stats(struct phy_device *phydev, 747 struct ethtool_stats *stats, u64 *data) 748 { 749 struct bcm54xx_phy_priv *priv = phydev->priv; 750 751 bcm_phy_get_stats(phydev, priv->stats, stats, data); 752 } 753 754 static void bcm54xx_link_change_notify(struct phy_device *phydev) 755 { 756 u16 mask = MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE | 757 MII_BCM54XX_EXP_EXP08_FORCE_DAC_WAKE; 758 int ret; 759 760 if (phydev->state != PHY_RUNNING) 761 return; 762 763 /* Don't change the DAC wake settings if auto power down 764 * is not requested. 765 */ 766 if (!(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 767 return; 768 769 ret = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP08); 770 if (ret < 0) 771 return; 772 773 /* Enable/disable 10BaseT auto and forced early DAC wake depending 774 * on the negotiated speed, those settings should only be done 775 * for 10Mbits/sec. 776 */ 777 if (phydev->speed == SPEED_10) 778 ret |= mask; 779 else 780 ret &= ~mask; 781 bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret); 782 } 783 784 static struct phy_driver broadcom_drivers[] = { 785 { 786 .phy_id = PHY_ID_BCM5411, 787 .phy_id_mask = 0xfffffff0, 788 .name = "Broadcom BCM5411", 789 /* PHY_GBIT_FEATURES */ 790 .get_sset_count = bcm_phy_get_sset_count, 791 .get_strings = bcm_phy_get_strings, 792 .get_stats = bcm54xx_get_stats, 793 .probe = bcm54xx_phy_probe, 794 .config_init = bcm54xx_config_init, 795 .config_intr = bcm_phy_config_intr, 796 .handle_interrupt = bcm_phy_handle_interrupt, 797 .link_change_notify = bcm54xx_link_change_notify, 798 }, { 799 .phy_id = PHY_ID_BCM5421, 800 .phy_id_mask = 0xfffffff0, 801 .name = "Broadcom BCM5421", 802 /* PHY_GBIT_FEATURES */ 803 .get_sset_count = bcm_phy_get_sset_count, 804 .get_strings = bcm_phy_get_strings, 805 .get_stats = bcm54xx_get_stats, 806 .probe = bcm54xx_phy_probe, 807 .config_init = bcm54xx_config_init, 808 .config_intr = bcm_phy_config_intr, 809 .handle_interrupt = bcm_phy_handle_interrupt, 810 .link_change_notify = bcm54xx_link_change_notify, 811 }, { 812 .phy_id = PHY_ID_BCM54210E, 813 .phy_id_mask = 0xfffffff0, 814 .name = "Broadcom BCM54210E", 815 /* PHY_GBIT_FEATURES */ 816 .get_sset_count = bcm_phy_get_sset_count, 817 .get_strings = bcm_phy_get_strings, 818 .get_stats = bcm54xx_get_stats, 819 .probe = bcm54xx_phy_probe, 820 .config_init = bcm54xx_config_init, 821 .config_intr = bcm_phy_config_intr, 822 .handle_interrupt = bcm_phy_handle_interrupt, 823 .link_change_notify = bcm54xx_link_change_notify, 824 .suspend = bcm54xx_suspend, 825 .resume = bcm54xx_resume, 826 }, { 827 .phy_id = PHY_ID_BCM5461, 828 .phy_id_mask = 0xfffffff0, 829 .name = "Broadcom BCM5461", 830 /* PHY_GBIT_FEATURES */ 831 .get_sset_count = bcm_phy_get_sset_count, 832 .get_strings = bcm_phy_get_strings, 833 .get_stats = bcm54xx_get_stats, 834 .probe = bcm54xx_phy_probe, 835 .config_init = bcm54xx_config_init, 836 .config_intr = bcm_phy_config_intr, 837 .handle_interrupt = bcm_phy_handle_interrupt, 838 .link_change_notify = bcm54xx_link_change_notify, 839 }, { 840 .phy_id = PHY_ID_BCM54612E, 841 .phy_id_mask = 0xfffffff0, 842 .name = "Broadcom BCM54612E", 843 /* PHY_GBIT_FEATURES */ 844 .get_sset_count = bcm_phy_get_sset_count, 845 .get_strings = bcm_phy_get_strings, 846 .get_stats = bcm54xx_get_stats, 847 .probe = bcm54xx_phy_probe, 848 .config_init = bcm54xx_config_init, 849 .config_intr = bcm_phy_config_intr, 850 .handle_interrupt = bcm_phy_handle_interrupt, 851 .link_change_notify = bcm54xx_link_change_notify, 852 }, { 853 .phy_id = PHY_ID_BCM54616S, 854 .phy_id_mask = 0xfffffff0, 855 .name = "Broadcom BCM54616S", 856 /* PHY_GBIT_FEATURES */ 857 .soft_reset = genphy_soft_reset, 858 .config_init = bcm54xx_config_init, 859 .config_aneg = bcm54616s_config_aneg, 860 .config_intr = bcm_phy_config_intr, 861 .handle_interrupt = bcm_phy_handle_interrupt, 862 .read_status = bcm54616s_read_status, 863 .probe = bcm54616s_probe, 864 .link_change_notify = bcm54xx_link_change_notify, 865 }, { 866 .phy_id = PHY_ID_BCM5464, 867 .phy_id_mask = 0xfffffff0, 868 .name = "Broadcom BCM5464", 869 /* PHY_GBIT_FEATURES */ 870 .get_sset_count = bcm_phy_get_sset_count, 871 .get_strings = bcm_phy_get_strings, 872 .get_stats = bcm54xx_get_stats, 873 .probe = bcm54xx_phy_probe, 874 .config_init = bcm54xx_config_init, 875 .config_intr = bcm_phy_config_intr, 876 .handle_interrupt = bcm_phy_handle_interrupt, 877 .suspend = genphy_suspend, 878 .resume = genphy_resume, 879 .link_change_notify = bcm54xx_link_change_notify, 880 }, { 881 .phy_id = PHY_ID_BCM5481, 882 .phy_id_mask = 0xfffffff0, 883 .name = "Broadcom BCM5481", 884 /* PHY_GBIT_FEATURES */ 885 .get_sset_count = bcm_phy_get_sset_count, 886 .get_strings = bcm_phy_get_strings, 887 .get_stats = bcm54xx_get_stats, 888 .probe = bcm54xx_phy_probe, 889 .config_init = bcm54xx_config_init, 890 .config_aneg = bcm5481_config_aneg, 891 .config_intr = bcm_phy_config_intr, 892 .handle_interrupt = bcm_phy_handle_interrupt, 893 .link_change_notify = bcm54xx_link_change_notify, 894 }, { 895 .phy_id = PHY_ID_BCM54810, 896 .phy_id_mask = 0xfffffff0, 897 .name = "Broadcom BCM54810", 898 /* PHY_GBIT_FEATURES */ 899 .get_sset_count = bcm_phy_get_sset_count, 900 .get_strings = bcm_phy_get_strings, 901 .get_stats = bcm54xx_get_stats, 902 .probe = bcm54xx_phy_probe, 903 .config_init = bcm54xx_config_init, 904 .config_aneg = bcm5481_config_aneg, 905 .config_intr = bcm_phy_config_intr, 906 .handle_interrupt = bcm_phy_handle_interrupt, 907 .suspend = bcm54xx_suspend, 908 .resume = bcm54xx_resume, 909 .link_change_notify = bcm54xx_link_change_notify, 910 }, { 911 .phy_id = PHY_ID_BCM54811, 912 .phy_id_mask = 0xfffffff0, 913 .name = "Broadcom BCM54811", 914 /* PHY_GBIT_FEATURES */ 915 .get_sset_count = bcm_phy_get_sset_count, 916 .get_strings = bcm_phy_get_strings, 917 .get_stats = bcm54xx_get_stats, 918 .probe = bcm54xx_phy_probe, 919 .config_init = bcm54811_config_init, 920 .config_aneg = bcm5481_config_aneg, 921 .config_intr = bcm_phy_config_intr, 922 .handle_interrupt = bcm_phy_handle_interrupt, 923 .suspend = bcm54xx_suspend, 924 .resume = bcm54xx_resume, 925 .link_change_notify = bcm54xx_link_change_notify, 926 }, { 927 .phy_id = PHY_ID_BCM5482, 928 .phy_id_mask = 0xfffffff0, 929 .name = "Broadcom BCM5482", 930 /* PHY_GBIT_FEATURES */ 931 .get_sset_count = bcm_phy_get_sset_count, 932 .get_strings = bcm_phy_get_strings, 933 .get_stats = bcm54xx_get_stats, 934 .probe = bcm54xx_phy_probe, 935 .config_init = bcm54xx_config_init, 936 .config_intr = bcm_phy_config_intr, 937 .handle_interrupt = bcm_phy_handle_interrupt, 938 .link_change_notify = bcm54xx_link_change_notify, 939 }, { 940 .phy_id = PHY_ID_BCM50610, 941 .phy_id_mask = 0xfffffff0, 942 .name = "Broadcom BCM50610", 943 /* PHY_GBIT_FEATURES */ 944 .get_sset_count = bcm_phy_get_sset_count, 945 .get_strings = bcm_phy_get_strings, 946 .get_stats = bcm54xx_get_stats, 947 .probe = bcm54xx_phy_probe, 948 .config_init = bcm54xx_config_init, 949 .config_intr = bcm_phy_config_intr, 950 .handle_interrupt = bcm_phy_handle_interrupt, 951 .link_change_notify = bcm54xx_link_change_notify, 952 .suspend = bcm54xx_suspend, 953 .resume = bcm54xx_resume, 954 }, { 955 .phy_id = PHY_ID_BCM50610M, 956 .phy_id_mask = 0xfffffff0, 957 .name = "Broadcom BCM50610M", 958 /* PHY_GBIT_FEATURES */ 959 .get_sset_count = bcm_phy_get_sset_count, 960 .get_strings = bcm_phy_get_strings, 961 .get_stats = bcm54xx_get_stats, 962 .probe = bcm54xx_phy_probe, 963 .config_init = bcm54xx_config_init, 964 .config_intr = bcm_phy_config_intr, 965 .handle_interrupt = bcm_phy_handle_interrupt, 966 .link_change_notify = bcm54xx_link_change_notify, 967 .suspend = bcm54xx_suspend, 968 .resume = bcm54xx_resume, 969 }, { 970 .phy_id = PHY_ID_BCM57780, 971 .phy_id_mask = 0xfffffff0, 972 .name = "Broadcom BCM57780", 973 /* PHY_GBIT_FEATURES */ 974 .get_sset_count = bcm_phy_get_sset_count, 975 .get_strings = bcm_phy_get_strings, 976 .get_stats = bcm54xx_get_stats, 977 .probe = bcm54xx_phy_probe, 978 .config_init = bcm54xx_config_init, 979 .config_intr = bcm_phy_config_intr, 980 .handle_interrupt = bcm_phy_handle_interrupt, 981 .link_change_notify = bcm54xx_link_change_notify, 982 }, { 983 .phy_id = PHY_ID_BCMAC131, 984 .phy_id_mask = 0xfffffff0, 985 .name = "Broadcom BCMAC131", 986 /* PHY_BASIC_FEATURES */ 987 .config_init = brcm_fet_config_init, 988 .config_intr = brcm_fet_config_intr, 989 .handle_interrupt = brcm_fet_handle_interrupt, 990 }, { 991 .phy_id = PHY_ID_BCM5241, 992 .phy_id_mask = 0xfffffff0, 993 .name = "Broadcom BCM5241", 994 /* PHY_BASIC_FEATURES */ 995 .config_init = brcm_fet_config_init, 996 .config_intr = brcm_fet_config_intr, 997 .handle_interrupt = brcm_fet_handle_interrupt, 998 }, { 999 .phy_id = PHY_ID_BCM5395, 1000 .phy_id_mask = 0xfffffff0, 1001 .name = "Broadcom BCM5395", 1002 .flags = PHY_IS_INTERNAL, 1003 /* PHY_GBIT_FEATURES */ 1004 .get_sset_count = bcm_phy_get_sset_count, 1005 .get_strings = bcm_phy_get_strings, 1006 .get_stats = bcm54xx_get_stats, 1007 .probe = bcm54xx_phy_probe, 1008 .link_change_notify = bcm54xx_link_change_notify, 1009 }, { 1010 .phy_id = PHY_ID_BCM53125, 1011 .phy_id_mask = 0xfffffff0, 1012 .name = "Broadcom BCM53125", 1013 .flags = PHY_IS_INTERNAL, 1014 /* PHY_GBIT_FEATURES */ 1015 .get_sset_count = bcm_phy_get_sset_count, 1016 .get_strings = bcm_phy_get_strings, 1017 .get_stats = bcm54xx_get_stats, 1018 .probe = bcm54xx_phy_probe, 1019 .config_init = bcm54xx_config_init, 1020 .config_intr = bcm_phy_config_intr, 1021 .handle_interrupt = bcm_phy_handle_interrupt, 1022 .link_change_notify = bcm54xx_link_change_notify, 1023 }, { 1024 .phy_id = PHY_ID_BCM89610, 1025 .phy_id_mask = 0xfffffff0, 1026 .name = "Broadcom BCM89610", 1027 /* PHY_GBIT_FEATURES */ 1028 .get_sset_count = bcm_phy_get_sset_count, 1029 .get_strings = bcm_phy_get_strings, 1030 .get_stats = bcm54xx_get_stats, 1031 .probe = bcm54xx_phy_probe, 1032 .config_init = bcm54xx_config_init, 1033 .config_intr = bcm_phy_config_intr, 1034 .handle_interrupt = bcm_phy_handle_interrupt, 1035 .link_change_notify = bcm54xx_link_change_notify, 1036 } }; 1037 1038 module_phy_driver(broadcom_drivers); 1039 1040 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 1041 { PHY_ID_BCM5411, 0xfffffff0 }, 1042 { PHY_ID_BCM5421, 0xfffffff0 }, 1043 { PHY_ID_BCM54210E, 0xfffffff0 }, 1044 { PHY_ID_BCM5461, 0xfffffff0 }, 1045 { PHY_ID_BCM54612E, 0xfffffff0 }, 1046 { PHY_ID_BCM54616S, 0xfffffff0 }, 1047 { PHY_ID_BCM5464, 0xfffffff0 }, 1048 { PHY_ID_BCM5481, 0xfffffff0 }, 1049 { PHY_ID_BCM54810, 0xfffffff0 }, 1050 { PHY_ID_BCM54811, 0xfffffff0 }, 1051 { PHY_ID_BCM5482, 0xfffffff0 }, 1052 { PHY_ID_BCM50610, 0xfffffff0 }, 1053 { PHY_ID_BCM50610M, 0xfffffff0 }, 1054 { PHY_ID_BCM57780, 0xfffffff0 }, 1055 { PHY_ID_BCMAC131, 0xfffffff0 }, 1056 { PHY_ID_BCM5241, 0xfffffff0 }, 1057 { PHY_ID_BCM5395, 0xfffffff0 }, 1058 { PHY_ID_BCM53125, 0xfffffff0 }, 1059 { PHY_ID_BCM89610, 0xfffffff0 }, 1060 { } 1061 }; 1062 1063 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 1064