xref: /openbmc/linux/drivers/net/phy/broadcom.c (revision c51d39010a1bccc9c1294e2d7c00005aefeb2b5c)
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 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
530 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
531 	.config_init	= bcm54xx_config_init,
532 	.config_aneg	= genphy_config_aneg,
533 	.read_status	= genphy_read_status,
534 	.ack_interrupt	= bcm_phy_ack_intr,
535 	.config_intr	= bcm_phy_config_intr,
536 }, {
537 	.phy_id		= PHY_ID_BCM5421,
538 	.phy_id_mask	= 0xfffffff0,
539 	.name		= "Broadcom BCM5421",
540 	.features	= PHY_GBIT_FEATURES |
541 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
542 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
543 	.config_init	= bcm54xx_config_init,
544 	.config_aneg	= genphy_config_aneg,
545 	.read_status	= genphy_read_status,
546 	.ack_interrupt	= bcm_phy_ack_intr,
547 	.config_intr	= bcm_phy_config_intr,
548 }, {
549 	.phy_id		= PHY_ID_BCM5461,
550 	.phy_id_mask	= 0xfffffff0,
551 	.name		= "Broadcom BCM5461",
552 	.features	= PHY_GBIT_FEATURES |
553 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
554 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
555 	.config_init	= bcm54xx_config_init,
556 	.config_aneg	= genphy_config_aneg,
557 	.read_status	= genphy_read_status,
558 	.ack_interrupt	= bcm_phy_ack_intr,
559 	.config_intr	= bcm_phy_config_intr,
560 }, {
561 	.phy_id		= PHY_ID_BCM54612E,
562 	.phy_id_mask	= 0xfffffff0,
563 	.name		= "Broadcom BCM54612E",
564 	.features	= PHY_GBIT_FEATURES |
565 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
566 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
567 	.config_init	= bcm54xx_config_init,
568 	.config_aneg	= bcm54612e_config_aneg,
569 	.read_status	= genphy_read_status,
570 	.ack_interrupt	= bcm_phy_ack_intr,
571 	.config_intr	= bcm_phy_config_intr,
572 }, {
573 	.phy_id		= PHY_ID_BCM54616S,
574 	.phy_id_mask	= 0xfffffff0,
575 	.name		= "Broadcom BCM54616S",
576 	.features	= PHY_GBIT_FEATURES |
577 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
578 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
579 	.config_init	= bcm54xx_config_init,
580 	.config_aneg	= genphy_config_aneg,
581 	.read_status	= genphy_read_status,
582 	.ack_interrupt	= bcm_phy_ack_intr,
583 	.config_intr	= bcm_phy_config_intr,
584 }, {
585 	.phy_id		= PHY_ID_BCM5464,
586 	.phy_id_mask	= 0xfffffff0,
587 	.name		= "Broadcom BCM5464",
588 	.features	= PHY_GBIT_FEATURES |
589 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
590 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
591 	.config_init	= bcm54xx_config_init,
592 	.config_aneg	= genphy_config_aneg,
593 	.read_status	= genphy_read_status,
594 	.ack_interrupt	= bcm_phy_ack_intr,
595 	.config_intr	= bcm_phy_config_intr,
596 }, {
597 	.phy_id		= PHY_ID_BCM5481,
598 	.phy_id_mask	= 0xfffffff0,
599 	.name		= "Broadcom BCM5481",
600 	.features	= PHY_GBIT_FEATURES |
601 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
602 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
603 	.config_init	= bcm54xx_config_init,
604 	.config_aneg	= bcm5481_config_aneg,
605 	.read_status	= genphy_read_status,
606 	.ack_interrupt	= bcm_phy_ack_intr,
607 	.config_intr	= bcm_phy_config_intr,
608 }, {
609 	.phy_id         = PHY_ID_BCM54810,
610 	.phy_id_mask    = 0xfffffff0,
611 	.name           = "Broadcom BCM54810",
612 	.features       = PHY_GBIT_FEATURES |
613 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
614 	.flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
615 	.config_init    = bcm54xx_config_init,
616 	.config_aneg    = bcm5481_config_aneg,
617 	.read_status    = genphy_read_status,
618 	.ack_interrupt  = bcm_phy_ack_intr,
619 	.config_intr    = bcm_phy_config_intr,
620 }, {
621 	.phy_id		= PHY_ID_BCM5482,
622 	.phy_id_mask	= 0xfffffff0,
623 	.name		= "Broadcom BCM5482",
624 	.features	= PHY_GBIT_FEATURES |
625 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
626 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
627 	.config_init	= bcm5482_config_init,
628 	.config_aneg	= genphy_config_aneg,
629 	.read_status	= bcm5482_read_status,
630 	.ack_interrupt	= bcm_phy_ack_intr,
631 	.config_intr	= bcm_phy_config_intr,
632 }, {
633 	.phy_id		= PHY_ID_BCM50610,
634 	.phy_id_mask	= 0xfffffff0,
635 	.name		= "Broadcom BCM50610",
636 	.features	= PHY_GBIT_FEATURES |
637 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
638 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
639 	.config_init	= bcm54xx_config_init,
640 	.config_aneg	= genphy_config_aneg,
641 	.read_status	= genphy_read_status,
642 	.ack_interrupt	= bcm_phy_ack_intr,
643 	.config_intr	= bcm_phy_config_intr,
644 }, {
645 	.phy_id		= PHY_ID_BCM50610M,
646 	.phy_id_mask	= 0xfffffff0,
647 	.name		= "Broadcom BCM50610M",
648 	.features	= PHY_GBIT_FEATURES |
649 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
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_BCM57780,
658 	.phy_id_mask	= 0xfffffff0,
659 	.name		= "Broadcom BCM57780",
660 	.features	= PHY_GBIT_FEATURES |
661 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
662 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
663 	.config_init	= bcm54xx_config_init,
664 	.config_aneg	= genphy_config_aneg,
665 	.read_status	= genphy_read_status,
666 	.ack_interrupt	= bcm_phy_ack_intr,
667 	.config_intr	= bcm_phy_config_intr,
668 }, {
669 	.phy_id		= PHY_ID_BCMAC131,
670 	.phy_id_mask	= 0xfffffff0,
671 	.name		= "Broadcom BCMAC131",
672 	.features	= PHY_BASIC_FEATURES |
673 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
674 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
675 	.config_init	= brcm_fet_config_init,
676 	.config_aneg	= genphy_config_aneg,
677 	.read_status	= genphy_read_status,
678 	.ack_interrupt	= brcm_fet_ack_interrupt,
679 	.config_intr	= brcm_fet_config_intr,
680 }, {
681 	.phy_id		= PHY_ID_BCM5241,
682 	.phy_id_mask	= 0xfffffff0,
683 	.name		= "Broadcom BCM5241",
684 	.features	= PHY_BASIC_FEATURES |
685 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
686 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
687 	.config_init	= brcm_fet_config_init,
688 	.config_aneg	= genphy_config_aneg,
689 	.read_status	= genphy_read_status,
690 	.ack_interrupt	= brcm_fet_ack_interrupt,
691 	.config_intr	= brcm_fet_config_intr,
692 } };
693 
694 module_phy_driver(broadcom_drivers);
695 
696 static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
697 	{ PHY_ID_BCM5411, 0xfffffff0 },
698 	{ PHY_ID_BCM5421, 0xfffffff0 },
699 	{ PHY_ID_BCM5461, 0xfffffff0 },
700 	{ PHY_ID_BCM54612E, 0xfffffff0 },
701 	{ PHY_ID_BCM54616S, 0xfffffff0 },
702 	{ PHY_ID_BCM5464, 0xfffffff0 },
703 	{ PHY_ID_BCM5481, 0xfffffff0 },
704 	{ PHY_ID_BCM54810, 0xfffffff0 },
705 	{ PHY_ID_BCM5482, 0xfffffff0 },
706 	{ PHY_ID_BCM50610, 0xfffffff0 },
707 	{ PHY_ID_BCM50610M, 0xfffffff0 },
708 	{ PHY_ID_BCM57780, 0xfffffff0 },
709 	{ PHY_ID_BCMAC131, 0xfffffff0 },
710 	{ PHY_ID_BCM5241, 0xfffffff0 },
711 	{ }
712 };
713 
714 MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
715