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