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