aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/broadcom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/broadcom.c')
-rw-r--r--drivers/net/phy/broadcom.c214
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() */
240static int bcm50610_a0_workaround(struct phy_device *phydev) 245static 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
276static 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
281error: 314error:
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
324static 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
289static int bcm54xx_config_init(struct phy_device *phydev) 386static 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
334error: 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
571done: 649done:
572 /* Disable shadow register access */ 650 /* Disable shadow register access */
@@ -742,7 +820,7 @@ static struct phy_driver bcm57780_driver = {
742}; 820};
743 821
744static struct phy_driver bcmac131_driver = { 822static 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 |