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