1 /* 2 * drivers/net/phy/broadcom.c 3 * 4 * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet 5 * transceivers. 6 * 7 * Copyright (c) 2006 Maciej W. Rozycki 8 * 9 * Inspired by code written by Amy Fong. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 14 * 2 of the License, or (at your option) any later version. 15 */ 16 17 #include <linux/module.h> 18 #include <linux/phy.h> 19 #include <linux/brcmphy.h> 20 21 22 #define BRCM_PHY_MODEL(phydev) \ 23 ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) 24 25 #define BRCM_PHY_REV(phydev) \ 26 ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) 27 28 /* 29 * Broadcom LED source encodings. These are used in BCM5461, BCM5481, 30 * BCM5482, and possibly some others. 31 */ 32 #define BCM_LED_SRC_LINKSPD1 0x0 33 #define BCM_LED_SRC_LINKSPD2 0x1 34 #define BCM_LED_SRC_XMITLED 0x2 35 #define BCM_LED_SRC_ACTIVITYLED 0x3 36 #define BCM_LED_SRC_FDXLED 0x4 37 #define BCM_LED_SRC_SLAVE 0x5 38 #define BCM_LED_SRC_INTR 0x6 39 #define BCM_LED_SRC_QUALITY 0x7 40 #define BCM_LED_SRC_RCVLED 0x8 41 #define BCM_LED_SRC_MULTICOLOR1 0xa 42 #define BCM_LED_SRC_OPENSHORT 0xb 43 #define BCM_LED_SRC_OFF 0xe /* Tied high */ 44 #define BCM_LED_SRC_ON 0xf /* Tied low */ 45 46 47 /* 48 * BCM5482: Shadow registers 49 * Shadow values go into bits [14:10] of register 0x1c to select a shadow 50 * register to access. 51 */ 52 /* 00101: Spare Control Register 3 */ 53 #define BCM54XX_SHD_SCR3 0x05 54 #define BCM54XX_SHD_SCR3_DEF_CLK125 0x0001 55 #define BCM54XX_SHD_SCR3_DLLAPD_DIS 0x0002 56 #define BCM54XX_SHD_SCR3_TRDDAPD 0x0004 57 58 /* 01010: Auto Power-Down */ 59 #define BCM54XX_SHD_APD 0x0a 60 #define BCM54XX_SHD_APD_EN 0x0020 61 62 #define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ 63 /* LED3 / ~LINKSPD[2] selector */ 64 #define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) 65 /* LED1 / ~LINKSPD[1] selector */ 66 #define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) 67 #define BCM54XX_SHD_RGMII_MODE 0x0b /* 01011: RGMII Mode Selector */ 68 #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ 69 #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ 70 #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ 71 #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ 72 #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ 73 74 75 /* 76 * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) 77 */ 78 #define MII_BCM54XX_EXP_AADJ1CH0 0x001f 79 #define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200 80 #define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100 81 #define MII_BCM54XX_EXP_AADJ1CH3 0x601f 82 #define MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ 0x0002 83 #define MII_BCM54XX_EXP_EXP08 0x0F08 84 #define MII_BCM54XX_EXP_EXP08_RJCT_2MHZ 0x0001 85 #define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200 86 #define MII_BCM54XX_EXP_EXP75 0x0f75 87 #define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c 88 #define MII_BCM54XX_EXP_EXP75_CM_OSC 0x0001 89 #define MII_BCM54XX_EXP_EXP96 0x0f96 90 #define MII_BCM54XX_EXP_EXP96_MYST 0x0010 91 #define MII_BCM54XX_EXP_EXP97 0x0f97 92 #define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c 93 94 /* 95 * BCM5482: Secondary SerDes registers 96 */ 97 #define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */ 98 #define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800 /* Power-down SSD */ 99 #define BCM5482_SSD_SGMII_SLAVE 0x15 /* SGMII Slave Register */ 100 #define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ 101 #define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ 102 103 104 /*****************************************************************************/ 105 /* Fast Ethernet Transceiver definitions. */ 106 /*****************************************************************************/ 107 108 #define MII_BRCM_FET_INTREG 0x1a /* Interrupt register */ 109 #define MII_BRCM_FET_IR_MASK 0x0100 /* Mask all interrupts */ 110 #define MII_BRCM_FET_IR_LINK_EN 0x0200 /* Link status change enable */ 111 #define MII_BRCM_FET_IR_SPEED_EN 0x0400 /* Link speed change enable */ 112 #define MII_BRCM_FET_IR_DUPLEX_EN 0x0800 /* Duplex mode change enable */ 113 #define MII_BRCM_FET_IR_ENABLE 0x4000 /* Interrupt enable */ 114 115 #define MII_BRCM_FET_BRCMTEST 0x1f /* Brcm test register */ 116 #define MII_BRCM_FET_BT_SRE 0x0080 /* Shadow register enable */ 117 118 119 /*** Shadow register definitions ***/ 120 121 #define MII_BRCM_FET_SHDW_MISCCTRL 0x10 /* Shadow misc ctrl */ 122 #define MII_BRCM_FET_SHDW_MC_FAME 0x4000 /* Force Auto MDIX enable */ 123 124 #define MII_BRCM_FET_SHDW_AUXMODE4 0x1a /* Auxiliary mode 4 */ 125 #define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003 126 #define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001 127 128 #define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */ 129 #define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */ 130 131 132 MODULE_DESCRIPTION("Broadcom PHY driver"); 133 MODULE_AUTHOR("Maciej W. Rozycki"); 134 MODULE_LICENSE("GPL"); 135 136 /* 137 * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T 138 * 0x1c shadow registers. 139 */ 140 static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow) 141 { 142 phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow)); 143 return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD)); 144 } 145 146 static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) 147 { 148 return phy_write(phydev, MII_BCM54XX_SHD, 149 MII_BCM54XX_SHD_WRITE | 150 MII_BCM54XX_SHD_VAL(shadow) | 151 MII_BCM54XX_SHD_DATA(val)); 152 } 153 154 /* Indirect register access functions for the Expansion Registers */ 155 static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum) 156 { 157 int val; 158 159 val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); 160 if (val < 0) 161 return val; 162 163 val = phy_read(phydev, MII_BCM54XX_EXP_DATA); 164 165 /* Restore default value. It's O.K. if this write fails. */ 166 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0); 167 168 return val; 169 } 170 171 static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val) 172 { 173 int ret; 174 175 ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); 176 if (ret < 0) 177 return ret; 178 179 ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val); 180 181 /* Restore default value. It's O.K. if this write fails. */ 182 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0); 183 184 return ret; 185 } 186 187 static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) 188 { 189 return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); 190 } 191 192 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ 193 static int bcm50610_a0_workaround(struct phy_device *phydev) 194 { 195 int err; 196 197 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, 198 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | 199 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); 200 if (err < 0) 201 return err; 202 203 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, 204 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); 205 if (err < 0) 206 return err; 207 208 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, 209 MII_BCM54XX_EXP_EXP75_VDACCTRL); 210 if (err < 0) 211 return err; 212 213 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, 214 MII_BCM54XX_EXP_EXP96_MYST); 215 if (err < 0) 216 return err; 217 218 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, 219 MII_BCM54XX_EXP_EXP97_MYST); 220 221 return err; 222 } 223 224 static int bcm54xx_phydsp_config(struct phy_device *phydev) 225 { 226 int err, err2; 227 228 /* Enable the SMDSP clock */ 229 err = bcm54xx_auxctl_write(phydev, 230 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 231 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | 232 MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 233 if (err < 0) 234 return err; 235 236 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 237 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) { 238 /* Clear bit 9 to fix a phy interop issue. */ 239 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08, 240 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ); 241 if (err < 0) 242 goto error; 243 244 if (phydev->drv->phy_id == PHY_ID_BCM50610) { 245 err = bcm50610_a0_workaround(phydev); 246 if (err < 0) 247 goto error; 248 } 249 } 250 251 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { 252 int val; 253 254 val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75); 255 if (val < 0) 256 goto error; 257 258 val |= MII_BCM54XX_EXP_EXP75_CM_OSC; 259 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val); 260 } 261 262 error: 263 /* Disable the SMDSP clock */ 264 err2 = bcm54xx_auxctl_write(phydev, 265 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 266 MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 267 268 /* Return the first error reported. */ 269 return err ? err : err2; 270 } 271 272 static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) 273 { 274 u32 orig; 275 int val; 276 bool clk125en = true; 277 278 /* Abort if we are using an untested phy. */ 279 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && 280 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && 281 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M) 282 return; 283 284 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3); 285 if (val < 0) 286 return; 287 288 orig = val; 289 290 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 291 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 292 BRCM_PHY_REV(phydev) >= 0x3) { 293 /* 294 * Here, bit 0 _disables_ CLK125 when set. 295 * This bit is set by default. 296 */ 297 clk125en = false; 298 } else { 299 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { 300 /* Here, bit 0 _enables_ CLK125 when set */ 301 val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; 302 clk125en = false; 303 } 304 } 305 306 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 307 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; 308 else 309 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 310 311 if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) 312 val |= BCM54XX_SHD_SCR3_TRDDAPD; 313 314 if (orig != val) 315 bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val); 316 317 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD); 318 if (val < 0) 319 return; 320 321 orig = val; 322 323 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 324 val |= BCM54XX_SHD_APD_EN; 325 else 326 val &= ~BCM54XX_SHD_APD_EN; 327 328 if (orig != val) 329 bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val); 330 } 331 332 static int bcm54xx_config_init(struct phy_device *phydev) 333 { 334 int reg, err; 335 336 reg = phy_read(phydev, MII_BCM54XX_ECR); 337 if (reg < 0) 338 return reg; 339 340 /* Mask interrupts globally. */ 341 reg |= MII_BCM54XX_ECR_IM; 342 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 343 if (err < 0) 344 return err; 345 346 /* Unmask events we are interested in. */ 347 reg = ~(MII_BCM54XX_INT_DUPLEX | 348 MII_BCM54XX_INT_SPEED | 349 MII_BCM54XX_INT_LINK); 350 err = phy_write(phydev, MII_BCM54XX_IMR, reg); 351 if (err < 0) 352 return err; 353 354 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 355 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 356 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) 357 bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0); 358 359 if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || 360 (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || 361 (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 362 bcm54xx_adjust_rxrefclk(phydev); 363 364 bcm54xx_phydsp_config(phydev); 365 366 return 0; 367 } 368 369 static int bcm5482_config_init(struct phy_device *phydev) 370 { 371 int err, reg; 372 373 err = bcm54xx_config_init(phydev); 374 375 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 376 /* 377 * Enable secondary SerDes and its use as an LED source 378 */ 379 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD); 380 bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD, 381 reg | 382 BCM5482_SHD_SSD_LEDM | 383 BCM5482_SHD_SSD_EN); 384 385 /* 386 * Enable SGMII slave mode and auto-detection 387 */ 388 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; 389 err = bcm54xx_exp_read(phydev, reg); 390 if (err < 0) 391 return err; 392 err = bcm54xx_exp_write(phydev, reg, err | 393 BCM5482_SSD_SGMII_SLAVE_EN | 394 BCM5482_SSD_SGMII_SLAVE_AD); 395 if (err < 0) 396 return err; 397 398 /* 399 * Disable secondary SerDes powerdown 400 */ 401 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; 402 err = bcm54xx_exp_read(phydev, reg); 403 if (err < 0) 404 return err; 405 err = bcm54xx_exp_write(phydev, reg, 406 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); 407 if (err < 0) 408 return err; 409 410 /* 411 * Select 1000BASE-X register set (primary SerDes) 412 */ 413 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE); 414 bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE, 415 reg | BCM5482_SHD_MODE_1000BX); 416 417 /* 418 * LED1=ACTIVITYLED, LED3=LINKSPD[2] 419 * (Use LED1 as secondary SerDes ACTIVITY LED) 420 */ 421 bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1, 422 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | 423 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); 424 425 /* 426 * Auto-negotiation doesn't seem to work quite right 427 * in this mode, so we disable it and force it to the 428 * right speed/duplex setting. Only 'link status' 429 * is important. 430 */ 431 phydev->autoneg = AUTONEG_DISABLE; 432 phydev->speed = SPEED_1000; 433 phydev->duplex = DUPLEX_FULL; 434 } 435 436 return err; 437 } 438 439 static int bcm5482_read_status(struct phy_device *phydev) 440 { 441 int err; 442 443 err = genphy_read_status(phydev); 444 445 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 446 /* 447 * Only link status matters for 1000Base-X mode, so force 448 * 1000 Mbit/s full-duplex status 449 */ 450 if (phydev->link) { 451 phydev->speed = SPEED_1000; 452 phydev->duplex = DUPLEX_FULL; 453 } 454 } 455 456 return err; 457 } 458 459 static int bcm54xx_ack_interrupt(struct phy_device *phydev) 460 { 461 int reg; 462 463 /* Clear pending interrupts. */ 464 reg = phy_read(phydev, MII_BCM54XX_ISR); 465 if (reg < 0) 466 return reg; 467 468 return 0; 469 } 470 471 static int bcm54xx_config_intr(struct phy_device *phydev) 472 { 473 int reg, err; 474 475 reg = phy_read(phydev, MII_BCM54XX_ECR); 476 if (reg < 0) 477 return reg; 478 479 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 480 reg &= ~MII_BCM54XX_ECR_IM; 481 else 482 reg |= MII_BCM54XX_ECR_IM; 483 484 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 485 return err; 486 } 487 488 static int bcm5481_config_aneg(struct phy_device *phydev) 489 { 490 int ret; 491 492 /* Aneg firsly. */ 493 ret = genphy_config_aneg(phydev); 494 495 /* Then we can set up the delay. */ 496 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 497 u16 reg; 498 499 /* 500 * There is no BCM5481 specification available, so down 501 * here is everything we know about "register 0x18". This 502 * at least helps BCM5481 to successfully receive packets 503 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com> 504 * says: "This sets delay between the RXD and RXC signals 505 * instead of using trace lengths to achieve timing". 506 */ 507 508 /* Set RDX clk delay. */ 509 reg = 0x7 | (0x7 << 12); 510 phy_write(phydev, 0x18, reg); 511 512 reg = phy_read(phydev, 0x18); 513 /* Set RDX-RXC skew. */ 514 reg |= (1 << 8); 515 /* Write bits 14:0. */ 516 reg |= (1 << 15); 517 phy_write(phydev, 0x18, reg); 518 } 519 520 return ret; 521 } 522 523 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 524 { 525 int val; 526 527 val = phy_read(phydev, reg); 528 if (val < 0) 529 return val; 530 531 return phy_write(phydev, reg, val | set); 532 } 533 534 static int brcm_fet_config_init(struct phy_device *phydev) 535 { 536 int reg, err, err2, brcmtest; 537 538 /* Reset the PHY to bring it to a known state. */ 539 err = phy_write(phydev, MII_BMCR, BMCR_RESET); 540 if (err < 0) 541 return err; 542 543 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 544 if (reg < 0) 545 return reg; 546 547 /* Unmask events we are interested in and mask interrupts globally. */ 548 reg = MII_BRCM_FET_IR_DUPLEX_EN | 549 MII_BRCM_FET_IR_SPEED_EN | 550 MII_BRCM_FET_IR_LINK_EN | 551 MII_BRCM_FET_IR_ENABLE | 552 MII_BRCM_FET_IR_MASK; 553 554 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 555 if (err < 0) 556 return err; 557 558 /* Enable shadow register access */ 559 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 560 if (brcmtest < 0) 561 return brcmtest; 562 563 reg = brcmtest | MII_BRCM_FET_BT_SRE; 564 565 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 566 if (err < 0) 567 return err; 568 569 /* Set the LED mode */ 570 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 571 if (reg < 0) { 572 err = reg; 573 goto done; 574 } 575 576 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 577 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 578 579 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 580 if (err < 0) 581 goto done; 582 583 /* Enable auto MDIX */ 584 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 585 MII_BRCM_FET_SHDW_MC_FAME); 586 if (err < 0) 587 goto done; 588 589 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 590 /* Enable auto power down */ 591 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 592 MII_BRCM_FET_SHDW_AS2_APDE); 593 } 594 595 done: 596 /* Disable shadow register access */ 597 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 598 if (!err) 599 err = err2; 600 601 return err; 602 } 603 604 static int brcm_fet_ack_interrupt(struct phy_device *phydev) 605 { 606 int reg; 607 608 /* Clear pending interrupts. */ 609 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 610 if (reg < 0) 611 return reg; 612 613 return 0; 614 } 615 616 static int brcm_fet_config_intr(struct phy_device *phydev) 617 { 618 int reg, err; 619 620 reg = phy_read(phydev, MII_BRCM_FET_INTREG); 621 if (reg < 0) 622 return reg; 623 624 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 625 reg &= ~MII_BRCM_FET_IR_MASK; 626 else 627 reg |= MII_BRCM_FET_IR_MASK; 628 629 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 630 return err; 631 } 632 633 static struct phy_driver broadcom_drivers[] = { 634 { 635 .phy_id = PHY_ID_BCM5411, 636 .phy_id_mask = 0xfffffff0, 637 .name = "Broadcom BCM5411", 638 .features = PHY_GBIT_FEATURES | 639 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 640 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 641 .config_init = bcm54xx_config_init, 642 .config_aneg = genphy_config_aneg, 643 .read_status = genphy_read_status, 644 .ack_interrupt = bcm54xx_ack_interrupt, 645 .config_intr = bcm54xx_config_intr, 646 .driver = { .owner = THIS_MODULE }, 647 }, { 648 .phy_id = PHY_ID_BCM5421, 649 .phy_id_mask = 0xfffffff0, 650 .name = "Broadcom BCM5421", 651 .features = PHY_GBIT_FEATURES | 652 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 653 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 654 .config_init = bcm54xx_config_init, 655 .config_aneg = genphy_config_aneg, 656 .read_status = genphy_read_status, 657 .ack_interrupt = bcm54xx_ack_interrupt, 658 .config_intr = bcm54xx_config_intr, 659 .driver = { .owner = THIS_MODULE }, 660 }, { 661 .phy_id = PHY_ID_BCM5461, 662 .phy_id_mask = 0xfffffff0, 663 .name = "Broadcom BCM5461", 664 .features = PHY_GBIT_FEATURES | 665 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 666 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 667 .config_init = bcm54xx_config_init, 668 .config_aneg = genphy_config_aneg, 669 .read_status = genphy_read_status, 670 .ack_interrupt = bcm54xx_ack_interrupt, 671 .config_intr = bcm54xx_config_intr, 672 .driver = { .owner = THIS_MODULE }, 673 }, { 674 .phy_id = PHY_ID_BCM5464, 675 .phy_id_mask = 0xfffffff0, 676 .name = "Broadcom BCM5464", 677 .features = PHY_GBIT_FEATURES | 678 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 679 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 680 .config_init = bcm54xx_config_init, 681 .config_aneg = genphy_config_aneg, 682 .read_status = genphy_read_status, 683 .ack_interrupt = bcm54xx_ack_interrupt, 684 .config_intr = bcm54xx_config_intr, 685 .driver = { .owner = THIS_MODULE }, 686 }, { 687 .phy_id = PHY_ID_BCM5481, 688 .phy_id_mask = 0xfffffff0, 689 .name = "Broadcom BCM5481", 690 .features = PHY_GBIT_FEATURES | 691 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 692 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 693 .config_init = bcm54xx_config_init, 694 .config_aneg = bcm5481_config_aneg, 695 .read_status = genphy_read_status, 696 .ack_interrupt = bcm54xx_ack_interrupt, 697 .config_intr = bcm54xx_config_intr, 698 .driver = { .owner = THIS_MODULE }, 699 }, { 700 .phy_id = PHY_ID_BCM5482, 701 .phy_id_mask = 0xfffffff0, 702 .name = "Broadcom BCM5482", 703 .features = PHY_GBIT_FEATURES | 704 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 705 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 706 .config_init = bcm5482_config_init, 707 .config_aneg = genphy_config_aneg, 708 .read_status = bcm5482_read_status, 709 .ack_interrupt = bcm54xx_ack_interrupt, 710 .config_intr = bcm54xx_config_intr, 711 .driver = { .owner = THIS_MODULE }, 712 }, { 713 .phy_id = PHY_ID_BCM50610, 714 .phy_id_mask = 0xfffffff0, 715 .name = "Broadcom BCM50610", 716 .features = PHY_GBIT_FEATURES | 717 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 718 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 719 .config_init = bcm54xx_config_init, 720 .config_aneg = genphy_config_aneg, 721 .read_status = genphy_read_status, 722 .ack_interrupt = bcm54xx_ack_interrupt, 723 .config_intr = bcm54xx_config_intr, 724 .driver = { .owner = THIS_MODULE }, 725 }, { 726 .phy_id = PHY_ID_BCM50610M, 727 .phy_id_mask = 0xfffffff0, 728 .name = "Broadcom BCM50610M", 729 .features = PHY_GBIT_FEATURES | 730 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 731 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 732 .config_init = bcm54xx_config_init, 733 .config_aneg = genphy_config_aneg, 734 .read_status = genphy_read_status, 735 .ack_interrupt = bcm54xx_ack_interrupt, 736 .config_intr = bcm54xx_config_intr, 737 .driver = { .owner = THIS_MODULE }, 738 }, { 739 .phy_id = PHY_ID_BCM57780, 740 .phy_id_mask = 0xfffffff0, 741 .name = "Broadcom BCM57780", 742 .features = PHY_GBIT_FEATURES | 743 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 744 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 745 .config_init = bcm54xx_config_init, 746 .config_aneg = genphy_config_aneg, 747 .read_status = genphy_read_status, 748 .ack_interrupt = bcm54xx_ack_interrupt, 749 .config_intr = bcm54xx_config_intr, 750 .driver = { .owner = THIS_MODULE }, 751 }, { 752 .phy_id = PHY_ID_BCMAC131, 753 .phy_id_mask = 0xfffffff0, 754 .name = "Broadcom BCMAC131", 755 .features = PHY_BASIC_FEATURES | 756 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 757 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 758 .config_init = brcm_fet_config_init, 759 .config_aneg = genphy_config_aneg, 760 .read_status = genphy_read_status, 761 .ack_interrupt = brcm_fet_ack_interrupt, 762 .config_intr = brcm_fet_config_intr, 763 .driver = { .owner = THIS_MODULE }, 764 }, { 765 .phy_id = PHY_ID_BCM5241, 766 .phy_id_mask = 0xfffffff0, 767 .name = "Broadcom BCM5241", 768 .features = PHY_BASIC_FEATURES | 769 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 770 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 771 .config_init = brcm_fet_config_init, 772 .config_aneg = genphy_config_aneg, 773 .read_status = genphy_read_status, 774 .ack_interrupt = brcm_fet_ack_interrupt, 775 .config_intr = brcm_fet_config_intr, 776 .driver = { .owner = THIS_MODULE }, 777 } }; 778 779 static int __init broadcom_init(void) 780 { 781 return phy_drivers_register(broadcom_drivers, 782 ARRAY_SIZE(broadcom_drivers)); 783 } 784 785 static void __exit broadcom_exit(void) 786 { 787 phy_drivers_unregister(broadcom_drivers, 788 ARRAY_SIZE(broadcom_drivers)); 789 } 790 791 module_init(broadcom_init); 792 module_exit(broadcom_exit); 793 794 static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 795 { PHY_ID_BCM5411, 0xfffffff0 }, 796 { PHY_ID_BCM5421, 0xfffffff0 }, 797 { PHY_ID_BCM5461, 0xfffffff0 }, 798 { PHY_ID_BCM5464, 0xfffffff0 }, 799 { PHY_ID_BCM5482, 0xfffffff0 }, 800 { PHY_ID_BCM5482, 0xfffffff0 }, 801 { PHY_ID_BCM50610, 0xfffffff0 }, 802 { PHY_ID_BCM50610M, 0xfffffff0 }, 803 { PHY_ID_BCM57780, 0xfffffff0 }, 804 { PHY_ID_BCMAC131, 0xfffffff0 }, 805 { PHY_ID_BCM5241, 0xfffffff0 }, 806 { } 807 }; 808 809 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 810