xref: /openbmc/linux/drivers/net/phy/broadcom.c (revision 8730046c)
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 "bcm-phy-lib.h"
18 #include <linux/module.h>
19 #include <linux/phy.h>
20 #include <linux/brcmphy.h>
21 #include <linux/of.h>
22 
23 #define BRCM_PHY_MODEL(phydev) \
24 	((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
25 
26 #define BRCM_PHY_REV(phydev) \
27 	((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
28 
29 MODULE_DESCRIPTION("Broadcom PHY driver");
30 MODULE_AUTHOR("Maciej W. Rozycki");
31 MODULE_LICENSE("GPL");
32 
33 static int bcm54810_config(struct phy_device *phydev)
34 {
35 	int rc, val;
36 
37 	val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
38 	val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
39 	rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
40 			       val);
41 	if (rc < 0)
42 		return rc;
43 
44 	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
45 	val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
46 	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
47 	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
48 				  val);
49 	if (rc < 0)
50 		return rc;
51 
52 	val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
53 	val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
54 	rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
55 	if (rc < 0)
56 		return rc;
57 
58 	return 0;
59 }
60 
61 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
62 static int bcm50610_a0_workaround(struct phy_device *phydev)
63 {
64 	int err;
65 
66 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
67 				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
68 				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
69 	if (err < 0)
70 		return err;
71 
72 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
73 				MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
74 	if (err < 0)
75 		return err;
76 
77 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
78 				MII_BCM54XX_EXP_EXP75_VDACCTRL);
79 	if (err < 0)
80 		return err;
81 
82 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
83 				MII_BCM54XX_EXP_EXP96_MYST);
84 	if (err < 0)
85 		return err;
86 
87 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
88 				MII_BCM54XX_EXP_EXP97_MYST);
89 
90 	return err;
91 }
92 
93 static int bcm54xx_phydsp_config(struct phy_device *phydev)
94 {
95 	int err, err2;
96 
97 	/* Enable the SMDSP clock */
98 	err = bcm54xx_auxctl_write(phydev,
99 				   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
100 				   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
101 				   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
102 	if (err < 0)
103 		return err;
104 
105 	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
106 	    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
107 		/* Clear bit 9 to fix a phy interop issue. */
108 		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
109 					MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
110 		if (err < 0)
111 			goto error;
112 
113 		if (phydev->drv->phy_id == PHY_ID_BCM50610) {
114 			err = bcm50610_a0_workaround(phydev);
115 			if (err < 0)
116 				goto error;
117 		}
118 	}
119 
120 	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
121 		int val;
122 
123 		val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
124 		if (val < 0)
125 			goto error;
126 
127 		val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
128 		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
129 	}
130 
131 error:
132 	/* Disable the SMDSP clock */
133 	err2 = bcm54xx_auxctl_write(phydev,
134 				    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
135 				    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
136 
137 	/* Return the first error reported. */
138 	return err ? err : err2;
139 }
140 
141 static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
142 {
143 	u32 orig;
144 	int val;
145 	bool clk125en = true;
146 
147 	/* Abort if we are using an untested phy. */
148 	if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
149 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
150 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
151 		return;
152 
153 	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
154 	if (val < 0)
155 		return;
156 
157 	orig = val;
158 
159 	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
160 	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
161 	    BRCM_PHY_REV(phydev) >= 0x3) {
162 		/*
163 		 * Here, bit 0 _disables_ CLK125 when set.
164 		 * This bit is set by default.
165 		 */
166 		clk125en = false;
167 	} else {
168 		if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
169 			/* Here, bit 0 _enables_ CLK125 when set */
170 			val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
171 			clk125en = false;
172 		}
173 	}
174 
175 	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
176 		val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
177 	else
178 		val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
179 
180 	if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY)
181 		val |= BCM54XX_SHD_SCR3_TRDDAPD;
182 
183 	if (orig != val)
184 		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
185 
186 	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
187 	if (val < 0)
188 		return;
189 
190 	orig = val;
191 
192 	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
193 		val |= BCM54XX_SHD_APD_EN;
194 	else
195 		val &= ~BCM54XX_SHD_APD_EN;
196 
197 	if (orig != val)
198 		bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
199 }
200 
201 static int bcm54xx_config_init(struct phy_device *phydev)
202 {
203 	int reg, err;
204 
205 	reg = phy_read(phydev, MII_BCM54XX_ECR);
206 	if (reg < 0)
207 		return reg;
208 
209 	/* Mask interrupts globally.  */
210 	reg |= MII_BCM54XX_ECR_IM;
211 	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
212 	if (err < 0)
213 		return err;
214 
215 	/* Unmask events we are interested in.  */
216 	reg = ~(MII_BCM54XX_INT_DUPLEX |
217 		MII_BCM54XX_INT_SPEED |
218 		MII_BCM54XX_INT_LINK);
219 	err = phy_write(phydev, MII_BCM54XX_IMR, reg);
220 	if (err < 0)
221 		return err;
222 
223 	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
224 	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
225 	    (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
226 		bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
227 
228 	if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
229 	    (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
230 	    (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
231 		bcm54xx_adjust_rxrefclk(phydev);
232 
233 	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
234 		err = bcm54810_config(phydev);
235 		if (err)
236 			return err;
237 	}
238 
239 	bcm54xx_phydsp_config(phydev);
240 
241 	return 0;
242 }
243 
244 static int bcm5482_config_init(struct phy_device *phydev)
245 {
246 	int err, reg;
247 
248 	err = bcm54xx_config_init(phydev);
249 
250 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
251 		/*
252 		 * Enable secondary SerDes and its use as an LED source
253 		 */
254 		reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
255 		bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
256 				     reg |
257 				     BCM5482_SHD_SSD_LEDM |
258 				     BCM5482_SHD_SSD_EN);
259 
260 		/*
261 		 * Enable SGMII slave mode and auto-detection
262 		 */
263 		reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
264 		err = bcm_phy_read_exp(phydev, reg);
265 		if (err < 0)
266 			return err;
267 		err = bcm_phy_write_exp(phydev, reg, err |
268 					BCM5482_SSD_SGMII_SLAVE_EN |
269 					BCM5482_SSD_SGMII_SLAVE_AD);
270 		if (err < 0)
271 			return err;
272 
273 		/*
274 		 * Disable secondary SerDes powerdown
275 		 */
276 		reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
277 		err = bcm_phy_read_exp(phydev, reg);
278 		if (err < 0)
279 			return err;
280 		err = bcm_phy_write_exp(phydev, reg,
281 					err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
282 		if (err < 0)
283 			return err;
284 
285 		/*
286 		 * Select 1000BASE-X register set (primary SerDes)
287 		 */
288 		reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
289 		bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
290 				     reg | BCM5482_SHD_MODE_1000BX);
291 
292 		/*
293 		 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
294 		 * (Use LED1 as secondary SerDes ACTIVITY LED)
295 		 */
296 		bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
297 			BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
298 			BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
299 
300 		/*
301 		 * Auto-negotiation doesn't seem to work quite right
302 		 * in this mode, so we disable it and force it to the
303 		 * right speed/duplex setting.  Only 'link status'
304 		 * is important.
305 		 */
306 		phydev->autoneg = AUTONEG_DISABLE;
307 		phydev->speed = SPEED_1000;
308 		phydev->duplex = DUPLEX_FULL;
309 	}
310 
311 	return err;
312 }
313 
314 static int bcm5482_read_status(struct phy_device *phydev)
315 {
316 	int err;
317 
318 	err = genphy_read_status(phydev);
319 
320 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
321 		/*
322 		 * Only link status matters for 1000Base-X mode, so force
323 		 * 1000 Mbit/s full-duplex status
324 		 */
325 		if (phydev->link) {
326 			phydev->speed = SPEED_1000;
327 			phydev->duplex = DUPLEX_FULL;
328 		}
329 	}
330 
331 	return err;
332 }
333 
334 static int bcm5481_config_aneg(struct phy_device *phydev)
335 {
336 	struct device_node *np = phydev->mdio.dev.of_node;
337 	int ret;
338 
339 	/* Aneg firsly. */
340 	ret = genphy_config_aneg(phydev);
341 
342 	/* Then we can set up the delay. */
343 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
344 		u16 reg;
345 
346 		/*
347 		 * There is no BCM5481 specification available, so down
348 		 * here is everything we know about "register 0x18". This
349 		 * at least helps BCM5481 to successfully receive packets
350 		 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
351 		 * says: "This sets delay between the RXD and RXC signals
352 		 * instead of using trace lengths to achieve timing".
353 		 */
354 
355 		/* Set RDX clk delay. */
356 		reg = 0x7 | (0x7 << 12);
357 		phy_write(phydev, 0x18, reg);
358 
359 		reg = phy_read(phydev, 0x18);
360 		/* Set RDX-RXC skew. */
361 		reg |= (1 << 8);
362 		/* Write bits 14:0. */
363 		reg |= (1 << 15);
364 		phy_write(phydev, 0x18, reg);
365 	}
366 
367 	if (of_property_read_bool(np, "enet-phy-lane-swap")) {
368 		/* Lane Swap - Undocumented register...magic! */
369 		ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
370 					0x11B);
371 		if (ret < 0)
372 			return ret;
373 	}
374 
375 	return ret;
376 }
377 
378 static int bcm54612e_config_aneg(struct phy_device *phydev)
379 {
380 	int ret;
381 
382 	/* First, auto-negotiate. */
383 	ret = genphy_config_aneg(phydev);
384 
385 	/* Clear TX internal delay unless requested. */
386 	if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
387 	    (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
388 		/* Disable TXD to GTXCLK clock delay (default set) */
389 		/* Bit 9 is the only field in shadow register 00011 */
390 		bcm_phy_write_shadow(phydev, 0x03, 0);
391 	}
392 
393 	/* Clear RX internal delay unless requested. */
394 	if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
395 	    (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
396 		u16 reg;
397 
398 		/* Errata: reads require filling in the write selector field */
399 		bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
400 				     MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC);
401 		reg = phy_read(phydev, MII_BCM54XX_AUX_CTL);
402 		/* Disable RXD to RXC delay (default set) */
403 		reg &= ~MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW;
404 		/* Clear shadow selector field */
405 		reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
406 		bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
407 				     MII_BCM54XX_AUXCTL_MISC_WREN | reg);
408 	}
409 
410 	return ret;
411 }
412 
413 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
414 {
415 	int val;
416 
417 	val = phy_read(phydev, reg);
418 	if (val < 0)
419 		return val;
420 
421 	return phy_write(phydev, reg, val | set);
422 }
423 
424 static int brcm_fet_config_init(struct phy_device *phydev)
425 {
426 	int reg, err, err2, brcmtest;
427 
428 	/* Reset the PHY to bring it to a known state. */
429 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
430 	if (err < 0)
431 		return err;
432 
433 	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
434 	if (reg < 0)
435 		return reg;
436 
437 	/* Unmask events we are interested in and mask interrupts globally. */
438 	reg = MII_BRCM_FET_IR_DUPLEX_EN |
439 	      MII_BRCM_FET_IR_SPEED_EN |
440 	      MII_BRCM_FET_IR_LINK_EN |
441 	      MII_BRCM_FET_IR_ENABLE |
442 	      MII_BRCM_FET_IR_MASK;
443 
444 	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
445 	if (err < 0)
446 		return err;
447 
448 	/* Enable shadow register access */
449 	brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
450 	if (brcmtest < 0)
451 		return brcmtest;
452 
453 	reg = brcmtest | MII_BRCM_FET_BT_SRE;
454 
455 	err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
456 	if (err < 0)
457 		return err;
458 
459 	/* Set the LED mode */
460 	reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
461 	if (reg < 0) {
462 		err = reg;
463 		goto done;
464 	}
465 
466 	reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
467 	reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
468 
469 	err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
470 	if (err < 0)
471 		goto done;
472 
473 	/* Enable auto MDIX */
474 	err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
475 				       MII_BRCM_FET_SHDW_MC_FAME);
476 	if (err < 0)
477 		goto done;
478 
479 	if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
480 		/* Enable auto power down */
481 		err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
482 					       MII_BRCM_FET_SHDW_AS2_APDE);
483 	}
484 
485 done:
486 	/* Disable shadow register access */
487 	err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
488 	if (!err)
489 		err = err2;
490 
491 	return err;
492 }
493 
494 static int brcm_fet_ack_interrupt(struct phy_device *phydev)
495 {
496 	int reg;
497 
498 	/* Clear pending interrupts.  */
499 	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
500 	if (reg < 0)
501 		return reg;
502 
503 	return 0;
504 }
505 
506 static int brcm_fet_config_intr(struct phy_device *phydev)
507 {
508 	int reg, err;
509 
510 	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
511 	if (reg < 0)
512 		return reg;
513 
514 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
515 		reg &= ~MII_BRCM_FET_IR_MASK;
516 	else
517 		reg |= MII_BRCM_FET_IR_MASK;
518 
519 	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
520 	return err;
521 }
522 
523 static struct phy_driver broadcom_drivers[] = {
524 {
525 	.phy_id		= PHY_ID_BCM5411,
526 	.phy_id_mask	= 0xfffffff0,
527 	.name		= "Broadcom BCM5411",
528 	.features	= PHY_GBIT_FEATURES,
529 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
530 	.config_init	= bcm54xx_config_init,
531 	.config_aneg	= genphy_config_aneg,
532 	.read_status	= genphy_read_status,
533 	.ack_interrupt	= bcm_phy_ack_intr,
534 	.config_intr	= bcm_phy_config_intr,
535 }, {
536 	.phy_id		= PHY_ID_BCM5421,
537 	.phy_id_mask	= 0xfffffff0,
538 	.name		= "Broadcom BCM5421",
539 	.features	= PHY_GBIT_FEATURES,
540 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
541 	.config_init	= bcm54xx_config_init,
542 	.config_aneg	= genphy_config_aneg,
543 	.read_status	= genphy_read_status,
544 	.ack_interrupt	= bcm_phy_ack_intr,
545 	.config_intr	= bcm_phy_config_intr,
546 }, {
547 	.phy_id		= PHY_ID_BCM5461,
548 	.phy_id_mask	= 0xfffffff0,
549 	.name		= "Broadcom BCM5461",
550 	.features	= PHY_GBIT_FEATURES,
551 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
552 	.config_init	= bcm54xx_config_init,
553 	.config_aneg	= genphy_config_aneg,
554 	.read_status	= genphy_read_status,
555 	.ack_interrupt	= bcm_phy_ack_intr,
556 	.config_intr	= bcm_phy_config_intr,
557 }, {
558 	.phy_id		= PHY_ID_BCM54612E,
559 	.phy_id_mask	= 0xfffffff0,
560 	.name		= "Broadcom BCM54612E",
561 	.features	= PHY_GBIT_FEATURES,
562 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
563 	.config_init	= bcm54xx_config_init,
564 	.config_aneg	= bcm54612e_config_aneg,
565 	.read_status	= genphy_read_status,
566 	.ack_interrupt	= bcm_phy_ack_intr,
567 	.config_intr	= bcm_phy_config_intr,
568 }, {
569 	.phy_id		= PHY_ID_BCM54616S,
570 	.phy_id_mask	= 0xfffffff0,
571 	.name		= "Broadcom BCM54616S",
572 	.features	= PHY_GBIT_FEATURES,
573 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
574 	.config_init	= bcm54xx_config_init,
575 	.config_aneg	= genphy_config_aneg,
576 	.read_status	= genphy_read_status,
577 	.ack_interrupt	= bcm_phy_ack_intr,
578 	.config_intr	= bcm_phy_config_intr,
579 }, {
580 	.phy_id		= PHY_ID_BCM5464,
581 	.phy_id_mask	= 0xfffffff0,
582 	.name		= "Broadcom BCM5464",
583 	.features	= PHY_GBIT_FEATURES,
584 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
585 	.config_init	= bcm54xx_config_init,
586 	.config_aneg	= genphy_config_aneg,
587 	.read_status	= genphy_read_status,
588 	.ack_interrupt	= bcm_phy_ack_intr,
589 	.config_intr	= bcm_phy_config_intr,
590 }, {
591 	.phy_id		= PHY_ID_BCM5481,
592 	.phy_id_mask	= 0xfffffff0,
593 	.name		= "Broadcom BCM5481",
594 	.features	= PHY_GBIT_FEATURES,
595 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
596 	.config_init	= bcm54xx_config_init,
597 	.config_aneg	= bcm5481_config_aneg,
598 	.read_status	= genphy_read_status,
599 	.ack_interrupt	= bcm_phy_ack_intr,
600 	.config_intr	= bcm_phy_config_intr,
601 }, {
602 	.phy_id         = PHY_ID_BCM54810,
603 	.phy_id_mask    = 0xfffffff0,
604 	.name           = "Broadcom BCM54810",
605 	.features       = PHY_GBIT_FEATURES,
606 	.flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
607 	.config_init    = bcm54xx_config_init,
608 	.config_aneg    = bcm5481_config_aneg,
609 	.read_status    = genphy_read_status,
610 	.ack_interrupt  = bcm_phy_ack_intr,
611 	.config_intr    = bcm_phy_config_intr,
612 }, {
613 	.phy_id		= PHY_ID_BCM5482,
614 	.phy_id_mask	= 0xfffffff0,
615 	.name		= "Broadcom BCM5482",
616 	.features	= PHY_GBIT_FEATURES,
617 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
618 	.config_init	= bcm5482_config_init,
619 	.config_aneg	= genphy_config_aneg,
620 	.read_status	= bcm5482_read_status,
621 	.ack_interrupt	= bcm_phy_ack_intr,
622 	.config_intr	= bcm_phy_config_intr,
623 }, {
624 	.phy_id		= PHY_ID_BCM50610,
625 	.phy_id_mask	= 0xfffffff0,
626 	.name		= "Broadcom BCM50610",
627 	.features	= PHY_GBIT_FEATURES,
628 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
629 	.config_init	= bcm54xx_config_init,
630 	.config_aneg	= genphy_config_aneg,
631 	.read_status	= genphy_read_status,
632 	.ack_interrupt	= bcm_phy_ack_intr,
633 	.config_intr	= bcm_phy_config_intr,
634 }, {
635 	.phy_id		= PHY_ID_BCM50610M,
636 	.phy_id_mask	= 0xfffffff0,
637 	.name		= "Broadcom BCM50610M",
638 	.features	= PHY_GBIT_FEATURES,
639 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
640 	.config_init	= bcm54xx_config_init,
641 	.config_aneg	= genphy_config_aneg,
642 	.read_status	= genphy_read_status,
643 	.ack_interrupt	= bcm_phy_ack_intr,
644 	.config_intr	= bcm_phy_config_intr,
645 }, {
646 	.phy_id		= PHY_ID_BCM57780,
647 	.phy_id_mask	= 0xfffffff0,
648 	.name		= "Broadcom BCM57780",
649 	.features	= PHY_GBIT_FEATURES,
650 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
651 	.config_init	= bcm54xx_config_init,
652 	.config_aneg	= genphy_config_aneg,
653 	.read_status	= genphy_read_status,
654 	.ack_interrupt	= bcm_phy_ack_intr,
655 	.config_intr	= bcm_phy_config_intr,
656 }, {
657 	.phy_id		= PHY_ID_BCMAC131,
658 	.phy_id_mask	= 0xfffffff0,
659 	.name		= "Broadcom BCMAC131",
660 	.features	= PHY_BASIC_FEATURES,
661 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
662 	.config_init	= brcm_fet_config_init,
663 	.config_aneg	= genphy_config_aneg,
664 	.read_status	= genphy_read_status,
665 	.ack_interrupt	= brcm_fet_ack_interrupt,
666 	.config_intr	= brcm_fet_config_intr,
667 }, {
668 	.phy_id		= PHY_ID_BCM5241,
669 	.phy_id_mask	= 0xfffffff0,
670 	.name		= "Broadcom BCM5241",
671 	.features	= PHY_BASIC_FEATURES,
672 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
673 	.config_init	= brcm_fet_config_init,
674 	.config_aneg	= genphy_config_aneg,
675 	.read_status	= genphy_read_status,
676 	.ack_interrupt	= brcm_fet_ack_interrupt,
677 	.config_intr	= brcm_fet_config_intr,
678 } };
679 
680 module_phy_driver(broadcom_drivers);
681 
682 static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
683 	{ PHY_ID_BCM5411, 0xfffffff0 },
684 	{ PHY_ID_BCM5421, 0xfffffff0 },
685 	{ PHY_ID_BCM5461, 0xfffffff0 },
686 	{ PHY_ID_BCM54612E, 0xfffffff0 },
687 	{ PHY_ID_BCM54616S, 0xfffffff0 },
688 	{ PHY_ID_BCM5464, 0xfffffff0 },
689 	{ PHY_ID_BCM5481, 0xfffffff0 },
690 	{ PHY_ID_BCM54810, 0xfffffff0 },
691 	{ PHY_ID_BCM5482, 0xfffffff0 },
692 	{ PHY_ID_BCM50610, 0xfffffff0 },
693 	{ PHY_ID_BCM50610M, 0xfffffff0 },
694 	{ PHY_ID_BCM57780, 0xfffffff0 },
695 	{ PHY_ID_BCMAC131, 0xfffffff0 },
696 	{ PHY_ID_BCM5241, 0xfffffff0 },
697 	{ }
698 };
699 
700 MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
701