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