aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/broadcom.c208
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() */
240static int bcm50610_a0_workaround(struct phy_device *phydev) 248static 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
279static 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
281error: 317error:
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
327static 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
289static int bcm54xx_config_init(struct phy_device *phydev) 388static 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
334error: 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
571done: 651done:
572 /* Disable shadow register access */ 652 /* Disable shadow register access */