diff options
Diffstat (limited to 'drivers/net/phy/broadcom.c')
-rw-r--r-- | drivers/net/phy/broadcom.c | 214 |
1 files changed, 146 insertions, 68 deletions
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index f81e53222230..f482fc4f8cf1 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c | |||
@@ -16,14 +16,15 @@ | |||
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/phy.h> | 18 | #include <linux/phy.h> |
19 | #include <linux/brcmphy.h> | ||
19 | 20 | ||
20 | #define PHY_ID_BCM50610 0x0143bd60 | ||
21 | #define PHY_ID_BCM50610M 0x0143bd70 | ||
22 | #define PHY_ID_BCM57780 0x03625d90 | ||
23 | 21 | ||
24 | #define BRCM_PHY_MODEL(phydev) \ | 22 | #define BRCM_PHY_MODEL(phydev) \ |
25 | ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) | 23 | ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) |
26 | 24 | ||
25 | #define BRCM_PHY_REV(phydev) \ | ||
26 | ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) | ||
27 | |||
27 | 28 | ||
28 | #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ | 29 | #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ |
29 | #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ | 30 | #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ |
@@ -94,22 +95,35 @@ | |||
94 | #define BCM_LED_SRC_OFF 0xe /* Tied high */ | 95 | #define BCM_LED_SRC_OFF 0xe /* Tied high */ |
95 | #define BCM_LED_SRC_ON 0xf /* Tied low */ | 96 | #define BCM_LED_SRC_ON 0xf /* Tied low */ |
96 | 97 | ||
98 | |||
97 | /* | 99 | /* |
98 | * BCM5482: Shadow registers | 100 | * BCM5482: Shadow registers |
99 | * Shadow values go into bits [14:10] of register 0x1c to select a shadow | 101 | * Shadow values go into bits [14:10] of register 0x1c to select a shadow |
100 | * register to access. | 102 | * register to access. |
101 | */ | 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 | |||
102 | #define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ | 114 | #define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ |
103 | /* LED3 / ~LINKSPD[2] selector */ | 115 | /* LED3 / ~LINKSPD[2] selector */ |
104 | #define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) | 116 | #define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) |
105 | /* LED1 / ~LINKSPD[1] selector */ | 117 | /* LED1 / ~LINKSPD[1] selector */ |
106 | #define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) | 118 | #define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) |
119 | #define BCM54XX_SHD_RGMII_MODE 0x0b /* 01011: RGMII Mode Selector */ | ||
107 | #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ | 120 | #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ |
108 | #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ | 121 | #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ |
109 | #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ | 122 | #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ |
110 | #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ | 123 | #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ |
111 | #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ | 124 | #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ |
112 | 125 | ||
126 | |||
113 | /* | 127 | /* |
114 | * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) | 128 | * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) |
115 | */ | 129 | */ |
@@ -138,16 +152,6 @@ | |||
138 | #define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ | 152 | #define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ |
139 | #define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ | 153 | #define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ |
140 | 154 | ||
141 | /* | ||
142 | * Device flags for PHYs that can be configured for different operating | ||
143 | * modes. | ||
144 | */ | ||
145 | #define PHY_BCM_FLAGS_VALID 0x80000000 | ||
146 | #define PHY_BCM_FLAGS_INTF_XAUI 0x00000020 | ||
147 | #define PHY_BCM_FLAGS_INTF_SGMII 0x00000010 | ||
148 | #define PHY_BCM_FLAGS_MODE_1000BX 0x00000002 | ||
149 | #define PHY_BCM_FLAGS_MODE_COPPER 0x00000001 | ||
150 | |||
151 | 155 | ||
152 | /*****************************************************************************/ | 156 | /*****************************************************************************/ |
153 | /* Fast Ethernet Transceiver definitions. */ | 157 | /* Fast Ethernet Transceiver definitions. */ |
@@ -237,53 +241,146 @@ static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) | |||
237 | return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); | 241 | return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); |
238 | } | 242 | } |
239 | 243 | ||
244 | /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ | ||
240 | static int bcm50610_a0_workaround(struct phy_device *phydev) | 245 | static int bcm50610_a0_workaround(struct phy_device *phydev) |
241 | { | 246 | { |
242 | int err; | 247 | int err; |
243 | 248 | ||
244 | err = bcm54xx_auxctl_write(phydev, | ||
245 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | ||
246 | MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | | ||
247 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
248 | if (err < 0) | ||
249 | return err; | ||
250 | |||
251 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08, | ||
252 | MII_BCM54XX_EXP_EXP08_RJCT_2MHZ | | ||
253 | MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE); | ||
254 | if (err < 0) | ||
255 | goto error; | ||
256 | |||
257 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, | 249 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, |
258 | MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | | 250 | MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | |
259 | MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); | 251 | MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); |
260 | if (err < 0) | 252 | if (err < 0) |
261 | goto error; | 253 | return err; |
262 | 254 | ||
263 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, | 255 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, |
264 | MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); | 256 | MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); |
265 | if (err < 0) | 257 | if (err < 0) |
266 | goto error; | 258 | return err; |
267 | 259 | ||
268 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, | 260 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, |
269 | MII_BCM54XX_EXP_EXP75_VDACCTRL); | 261 | MII_BCM54XX_EXP_EXP75_VDACCTRL); |
270 | if (err < 0) | 262 | if (err < 0) |
271 | goto error; | 263 | return err; |
272 | 264 | ||
273 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, | 265 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, |
274 | MII_BCM54XX_EXP_EXP96_MYST); | 266 | MII_BCM54XX_EXP_EXP96_MYST); |
275 | if (err < 0) | 267 | if (err < 0) |
276 | goto error; | 268 | return err; |
277 | 269 | ||
278 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, | 270 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, |
279 | MII_BCM54XX_EXP_EXP97_MYST); | 271 | MII_BCM54XX_EXP_EXP97_MYST); |
280 | 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 | |||
281 | error: | 314 | error: |
282 | bcm54xx_auxctl_write(phydev, | 315 | /* Disable the SMDSP clock */ |
283 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | 316 | err2 = bcm54xx_auxctl_write(phydev, |
284 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | 317 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, |
318 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
285 | 319 | ||
286 | return err; | 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); | ||
287 | } | 384 | } |
288 | 385 | ||
289 | static int bcm54xx_config_init(struct phy_device *phydev) | 386 | static int bcm54xx_config_init(struct phy_device *phydev) |
@@ -308,38 +405,17 @@ static int bcm54xx_config_init(struct phy_device *phydev) | |||
308 | if (err < 0) | 405 | if (err < 0) |
309 | return err; | 406 | return err; |
310 | 407 | ||
311 | if (phydev->drv->phy_id == PHY_ID_BCM50610) { | 408 | if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || |
312 | err = bcm50610_a0_workaround(phydev); | 409 | BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && |
313 | if (err < 0) | 410 | (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) |
314 | return err; | 411 | bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0); |
315 | } | ||
316 | |||
317 | if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { | ||
318 | int err2; | ||
319 | |||
320 | err = bcm54xx_auxctl_write(phydev, | ||
321 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | ||
322 | MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | | ||
323 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
324 | if (err < 0) | ||
325 | return err; | ||
326 | |||
327 | reg = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75); | ||
328 | if (reg < 0) | ||
329 | goto error; | ||
330 | 412 | ||
331 | reg |= MII_BCM54XX_EXP_EXP75_CM_OSC; | 413 | if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || |
332 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, reg); | 414 | (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || |
415 | (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) | ||
416 | bcm54xx_adjust_rxrefclk(phydev); | ||
333 | 417 | ||
334 | error: | 418 | bcm54xx_phydsp_config(phydev); |
335 | err2 = bcm54xx_auxctl_write(phydev, | ||
336 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | ||
337 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
338 | if (err) | ||
339 | return err; | ||
340 | if (err2) | ||
341 | return err2; | ||
342 | } | ||
343 | 419 | ||
344 | return 0; | 420 | return 0; |
345 | } | 421 | } |
@@ -564,9 +640,11 @@ static int brcm_fet_config_init(struct phy_device *phydev) | |||
564 | if (err < 0) | 640 | if (err < 0) |
565 | goto done; | 641 | goto done; |
566 | 642 | ||
567 | /* Enable auto power down */ | 643 | if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { |
568 | err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, | 644 | /* Enable auto power down */ |
569 | MII_BRCM_FET_SHDW_AS2_APDE); | 645 | err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, |
646 | MII_BRCM_FET_SHDW_AS2_APDE); | ||
647 | } | ||
570 | 648 | ||
571 | done: | 649 | done: |
572 | /* Disable shadow register access */ | 650 | /* Disable shadow register access */ |
@@ -742,7 +820,7 @@ static struct phy_driver bcm57780_driver = { | |||
742 | }; | 820 | }; |
743 | 821 | ||
744 | static struct phy_driver bcmac131_driver = { | 822 | static struct phy_driver bcmac131_driver = { |
745 | .phy_id = 0x0143bc70, | 823 | .phy_id = PHY_ID_BCMAC131, |
746 | .phy_id_mask = 0xfffffff0, | 824 | .phy_id_mask = 0xfffffff0, |
747 | .name = "Broadcom BCMAC131", | 825 | .name = "Broadcom BCMAC131", |
748 | .features = PHY_BASIC_FEATURES | | 826 | .features = PHY_BASIC_FEATURES | |