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