diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/broadcom.c | 208 |
1 files changed, 144 insertions, 64 deletions
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index f81e53222230..f63c96a4ecb4 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c | |||
@@ -16,6 +16,7 @@ | |||
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_BCM50610 0x0143bd60 |
21 | #define PHY_ID_BCM50610M 0x0143bd70 | 22 | #define PHY_ID_BCM50610M 0x0143bd70 |
@@ -24,6 +25,9 @@ | |||
24 | #define BRCM_PHY_MODEL(phydev) \ | 25 | #define BRCM_PHY_MODEL(phydev) \ |
25 | ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) | 26 | ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) |
26 | 27 | ||
28 | #define BRCM_PHY_REV(phydev) \ | ||
29 | ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) | ||
30 | |||
27 | 31 | ||
28 | #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ | 32 | #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ |
29 | #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ | 33 | #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ |
@@ -94,22 +98,35 @@ | |||
94 | #define BCM_LED_SRC_OFF 0xe /* Tied high */ | 98 | #define BCM_LED_SRC_OFF 0xe /* Tied high */ |
95 | #define BCM_LED_SRC_ON 0xf /* Tied low */ | 99 | #define BCM_LED_SRC_ON 0xf /* Tied low */ |
96 | 100 | ||
101 | |||
97 | /* | 102 | /* |
98 | * BCM5482: Shadow registers | 103 | * BCM5482: Shadow registers |
99 | * Shadow values go into bits [14:10] of register 0x1c to select a shadow | 104 | * Shadow values go into bits [14:10] of register 0x1c to select a shadow |
100 | * register to access. | 105 | * register to access. |
101 | */ | 106 | */ |
107 | /* 00101: Spare Control Register 3 */ | ||
108 | #define BCM54XX_SHD_SCR3 0x05 | ||
109 | #define BCM54XX_SHD_SCR3_DEF_CLK125 0x0001 | ||
110 | #define BCM54XX_SHD_SCR3_DLLAPD_DIS 0x0002 | ||
111 | #define BCM54XX_SHD_SCR3_TRDDAPD 0x0004 | ||
112 | |||
113 | /* 01010: Auto Power-Down */ | ||
114 | #define BCM54XX_SHD_APD 0x0a | ||
115 | #define BCM54XX_SHD_APD_EN 0x0020 | ||
116 | |||
102 | #define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ | 117 | #define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ |
103 | /* LED3 / ~LINKSPD[2] selector */ | 118 | /* LED3 / ~LINKSPD[2] selector */ |
104 | #define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) | 119 | #define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) |
105 | /* LED1 / ~LINKSPD[1] selector */ | 120 | /* LED1 / ~LINKSPD[1] selector */ |
106 | #define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) | 121 | #define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) |
122 | #define BCM54XX_SHD_RGMII_MODE 0x0b /* 01011: RGMII Mode Selector */ | ||
107 | #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ | 123 | #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ |
108 | #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ | 124 | #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ |
109 | #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ | 125 | #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ |
110 | #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ | 126 | #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ |
111 | #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ | 127 | #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ |
112 | 128 | ||
129 | |||
113 | /* | 130 | /* |
114 | * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) | 131 | * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) |
115 | */ | 132 | */ |
@@ -138,16 +155,6 @@ | |||
138 | #define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ | 155 | #define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ |
139 | #define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ | 156 | #define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ |
140 | 157 | ||
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 | 158 | ||
152 | /*****************************************************************************/ | 159 | /*****************************************************************************/ |
153 | /* Fast Ethernet Transceiver definitions. */ | 160 | /* Fast Ethernet Transceiver definitions. */ |
@@ -237,53 +244,145 @@ static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) | |||
237 | return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); | 244 | return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); |
238 | } | 245 | } |
239 | 246 | ||
247 | /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ | ||
240 | static int bcm50610_a0_workaround(struct phy_device *phydev) | 248 | static int bcm50610_a0_workaround(struct phy_device *phydev) |
241 | { | 249 | { |
242 | int err; | 250 | int err; |
243 | 251 | ||
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, | 252 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, |
258 | MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | | 253 | MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | |
259 | MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); | 254 | MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); |
260 | if (err < 0) | 255 | if (err < 0) |
261 | goto error; | 256 | return err; |
262 | 257 | ||
263 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, | 258 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, |
264 | MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); | 259 | MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); |
265 | if (err < 0) | 260 | if (err < 0) |
266 | goto error; | 261 | return err; |
267 | 262 | ||
268 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, | 263 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, |
269 | MII_BCM54XX_EXP_EXP75_VDACCTRL); | 264 | MII_BCM54XX_EXP_EXP75_VDACCTRL); |
270 | if (err < 0) | 265 | if (err < 0) |
271 | goto error; | 266 | return err; |
272 | 267 | ||
273 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, | 268 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, |
274 | MII_BCM54XX_EXP_EXP96_MYST); | 269 | MII_BCM54XX_EXP_EXP96_MYST); |
275 | if (err < 0) | 270 | if (err < 0) |
276 | goto error; | 271 | return err; |
277 | 272 | ||
278 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, | 273 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, |
279 | MII_BCM54XX_EXP_EXP97_MYST); | 274 | MII_BCM54XX_EXP_EXP97_MYST); |
280 | 275 | ||
276 | return err; | ||
277 | } | ||
278 | |||
279 | static int bcm54xx_phydsp_config(struct phy_device *phydev) | ||
280 | { | ||
281 | int err, err2; | ||
282 | |||
283 | /* Enable the SMDSP clock */ | ||
284 | err = bcm54xx_auxctl_write(phydev, | ||
285 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | ||
286 | MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | | ||
287 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
288 | if (err < 0) | ||
289 | return err; | ||
290 | |||
291 | if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || | ||
292 | BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) { | ||
293 | /* Clear bit 9 to fix a phy interop issue. */ | ||
294 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08, | ||
295 | MII_BCM54XX_EXP_EXP08_RJCT_2MHZ); | ||
296 | if (err < 0) | ||
297 | goto error; | ||
298 | |||
299 | if (phydev->drv->phy_id == PHY_ID_BCM50610) { | ||
300 | err = bcm50610_a0_workaround(phydev); | ||
301 | if (err < 0) | ||
302 | goto error; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { | ||
307 | int val; | ||
308 | |||
309 | val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75); | ||
310 | if (val < 0) | ||
311 | goto error; | ||
312 | |||
313 | val |= MII_BCM54XX_EXP_EXP75_CM_OSC; | ||
314 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val); | ||
315 | } | ||
316 | |||
281 | error: | 317 | error: |
282 | bcm54xx_auxctl_write(phydev, | 318 | /* Disable the SMDSP clock */ |
283 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | 319 | err2 = bcm54xx_auxctl_write(phydev, |
284 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | 320 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, |
321 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
285 | 322 | ||
286 | return err; | 323 | /* Return the first error reported. */ |
324 | return err ? err : err2; | ||
325 | } | ||
326 | |||
327 | static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) | ||
328 | { | ||
329 | u32 val, orig; | ||
330 | bool clk125en = true; | ||
331 | |||
332 | /* Abort if we are using an untested phy. */ | ||
333 | if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 || | ||
334 | BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 || | ||
335 | BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M) | ||
336 | return; | ||
337 | |||
338 | val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3); | ||
339 | if (val < 0) | ||
340 | return; | ||
341 | |||
342 | orig = val; | ||
343 | |||
344 | if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || | ||
345 | BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && | ||
346 | BRCM_PHY_REV(phydev) >= 0x3) { | ||
347 | /* | ||
348 | * Here, bit 0 _disables_ CLK125 when set. | ||
349 | * This bit is set by default. | ||
350 | */ | ||
351 | clk125en = false; | ||
352 | } else { | ||
353 | if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { | ||
354 | /* Here, bit 0 _enables_ CLK125 when set */ | ||
355 | val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; | ||
356 | clk125en = false; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | if (clk125en == false || | ||
361 | (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) | ||
362 | val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; | ||
363 | else | ||
364 | val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; | ||
365 | |||
366 | if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) | ||
367 | val |= BCM54XX_SHD_SCR3_TRDDAPD; | ||
368 | |||
369 | if (orig != val) | ||
370 | bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val); | ||
371 | |||
372 | val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD); | ||
373 | if (val < 0) | ||
374 | return; | ||
375 | |||
376 | orig = val; | ||
377 | |||
378 | if (clk125en == false || | ||
379 | (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) | ||
380 | val |= BCM54XX_SHD_APD_EN; | ||
381 | else | ||
382 | val &= ~BCM54XX_SHD_APD_EN; | ||
383 | |||
384 | if (orig != val) | ||
385 | bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val); | ||
287 | } | 386 | } |
288 | 387 | ||
289 | static int bcm54xx_config_init(struct phy_device *phydev) | 388 | static int bcm54xx_config_init(struct phy_device *phydev) |
@@ -308,38 +407,17 @@ static int bcm54xx_config_init(struct phy_device *phydev) | |||
308 | if (err < 0) | 407 | if (err < 0) |
309 | return err; | 408 | return err; |
310 | 409 | ||
311 | if (phydev->drv->phy_id == PHY_ID_BCM50610) { | 410 | if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || |
312 | err = bcm50610_a0_workaround(phydev); | 411 | BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && |
313 | if (err < 0) | 412 | (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) |
314 | return err; | 413 | 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 | 414 | ||
331 | reg |= MII_BCM54XX_EXP_EXP75_CM_OSC; | 415 | if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || |
332 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, reg); | 416 | (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || |
417 | (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) | ||
418 | bcm54xx_adjust_rxrefclk(phydev); | ||
333 | 419 | ||
334 | error: | 420 | 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 | 421 | ||
344 | return 0; | 422 | return 0; |
345 | } | 423 | } |
@@ -564,9 +642,11 @@ static int brcm_fet_config_init(struct phy_device *phydev) | |||
564 | if (err < 0) | 642 | if (err < 0) |
565 | goto done; | 643 | goto done; |
566 | 644 | ||
567 | /* Enable auto power down */ | 645 | if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { |
568 | err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, | 646 | /* Enable auto power down */ |
569 | MII_BRCM_FET_SHDW_AS2_APDE); | 647 | err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, |
648 | MII_BRCM_FET_SHDW_AS2_APDE); | ||
649 | } | ||
570 | 650 | ||
571 | done: | 651 | done: |
572 | /* Disable shadow register access */ | 652 | /* Disable shadow register access */ |