xref: /openbmc/linux/drivers/net/phy/bcm7xxx.c (revision bef7a78d)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Broadcom BCM7xxx internal transceivers support.
4  *
5  * Copyright (C) 2014-2017 Broadcom
6  */
7 
8 #include <linux/module.h>
9 #include <linux/phy.h>
10 #include <linux/delay.h>
11 #include "bcm-phy-lib.h"
12 #include <linux/bitops.h>
13 #include <linux/brcmphy.h>
14 #include <linux/clk.h>
15 #include <linux/mdio.h>
16 
17 /* Broadcom BCM7xxx internal PHY registers */
18 
19 /* EPHY only register definitions */
20 #define MII_BCM7XXX_100TX_AUX_CTL	0x10
21 #define MII_BCM7XXX_100TX_FALSE_CAR	0x13
22 #define MII_BCM7XXX_100TX_DISC		0x14
23 #define MII_BCM7XXX_AUX_MODE		0x1d
24 #define  MII_BCM7XXX_64CLK_MDIO		BIT(12)
25 #define MII_BCM7XXX_TEST		0x1f
26 #define  MII_BCM7XXX_SHD_MODE_2		BIT(2)
27 #define MII_BCM7XXX_SHD_2_ADDR_CTRL	0xe
28 #define MII_BCM7XXX_SHD_2_CTRL_STAT	0xf
29 #define MII_BCM7XXX_SHD_2_BIAS_TRIM	0x1a
30 #define MII_BCM7XXX_SHD_3_AN_EEE_ADV	0x3
31 #define MII_BCM7XXX_SHD_3_PCS_CTRL_2	0x6
32 #define  MII_BCM7XXX_PCS_CTRL_2_DEF	0x4400
33 #define MII_BCM7XXX_SHD_3_AN_STAT	0xb
34 #define  MII_BCM7XXX_AN_NULL_MSG_EN	BIT(0)
35 #define  MII_BCM7XXX_AN_EEE_EN		BIT(1)
36 #define MII_BCM7XXX_SHD_3_EEE_THRESH	0xe
37 #define  MII_BCM7XXX_EEE_THRESH_DEF	0x50
38 #define MII_BCM7XXX_SHD_3_TL4		0x23
39 #define  MII_BCM7XXX_TL4_RST_MSK	(BIT(2) | BIT(1))
40 
41 struct bcm7xxx_phy_priv {
42 	u64	*stats;
43 	struct clk *clk;
44 };
45 
46 static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
47 {
48 	/* AFE_RXCONFIG_0 */
49 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
50 
51 	/* AFE_RXCONFIG_1 */
52 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
53 
54 	/* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
55 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
56 
57 	/* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
58 	bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
59 
60 	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
61 	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
62 
63 	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
64 	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
65 
66 	/* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
67 	bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
68 
69 	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
70 	 * offset for HT=0 code
71 	 */
72 	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
73 
74 	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
75 	phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
76 
77 	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
78 	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
79 
80 	/* Reset R_CAL/RC_CAL engine */
81 	bcm_phy_r_rc_cal_reset(phydev);
82 
83 	return 0;
84 }
85 
86 static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
87 {
88 	/* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
89 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
90 
91 	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
92 	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
93 
94 	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
95 	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
96 
97 	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
98 	 * offset for HT=0 code
99 	 */
100 	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
101 
102 	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
103 	phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
104 
105 	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
106 	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
107 
108 	/* Reset R_CAL/RC_CAL engine */
109 	bcm_phy_r_rc_cal_reset(phydev);
110 
111 	return 0;
112 }
113 
114 static int bcm7xxx_28nm_a0_patch_afe_config_init(struct phy_device *phydev)
115 {
116 	/* +1 RC_CAL codes for RL centering for both LT and HT conditions */
117 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0xd003);
118 
119 	/* Cut master bias current by 2% to compensate for RC_CAL offset */
120 	bcm_phy_write_misc(phydev, DSP_TAP10, 0x791b);
121 
122 	/* Improve hybrid leakage */
123 	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x10e3);
124 
125 	/* Change rx_on_tune 8 to 0xf */
126 	bcm_phy_write_misc(phydev, 0x21, 0x2, 0x87f6);
127 
128 	/* Change 100Tx EEE bandwidth */
129 	bcm_phy_write_misc(phydev, 0x22, 0x2, 0x017d);
130 
131 	/* Enable ffe zero detection for Vitesse interoperability */
132 	bcm_phy_write_misc(phydev, 0x26, 0x2, 0x0015);
133 
134 	bcm_phy_r_rc_cal_reset(phydev);
135 
136 	return 0;
137 }
138 
139 static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
140 {
141 	u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
142 	u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
143 	u8 count;
144 	int ret = 0;
145 
146 	/* Newer devices have moved the revision information back into a
147 	 * standard location in MII_PHYS_ID[23]
148 	 */
149 	if (rev == 0)
150 		rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
151 
152 	pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
153 		     phydev_name(phydev), phydev->drv->name, rev, patch);
154 
155 	/* Dummy read to a register to workaround an issue upon reset where the
156 	 * internal inverter may not allow the first MDIO transaction to pass
157 	 * the MDIO management controller and make us return 0xffff for such
158 	 * reads.
159 	 */
160 	phy_read(phydev, MII_BMSR);
161 
162 	switch (rev) {
163 	case 0xa0:
164 	case 0xb0:
165 		ret = bcm_phy_28nm_a0b0_afe_config_init(phydev);
166 		break;
167 	case 0xd0:
168 		ret = bcm7xxx_28nm_d0_afe_config_init(phydev);
169 		break;
170 	case 0xe0:
171 	case 0xf0:
172 	/* Rev G0 introduces a roll over */
173 	case 0x10:
174 		ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
175 		break;
176 	case 0x01:
177 		ret = bcm7xxx_28nm_a0_patch_afe_config_init(phydev);
178 		break;
179 	default:
180 		break;
181 	}
182 
183 	if (ret)
184 		return ret;
185 
186 	ret =  bcm_phy_enable_jumbo(phydev);
187 	if (ret)
188 		return ret;
189 
190 	ret = bcm_phy_downshift_get(phydev, &count);
191 	if (ret)
192 		return ret;
193 
194 	/* Only enable EEE if Wirespeed/downshift is disabled */
195 	ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
196 	if (ret)
197 		return ret;
198 
199 	return bcm_phy_enable_apd(phydev, true);
200 }
201 
202 static int bcm7xxx_28nm_resume(struct phy_device *phydev)
203 {
204 	int ret;
205 
206 	/* Re-apply workarounds coming out suspend/resume */
207 	ret = bcm7xxx_28nm_config_init(phydev);
208 	if (ret)
209 		return ret;
210 
211 	/* 28nm Gigabit PHYs come out of reset without any half-duplex
212 	 * or "hub" compliant advertised mode, fix that. This does not
213 	 * cause any problems with the PHY library since genphy_config_aneg()
214 	 * gracefully handles auto-negotiated and forced modes.
215 	 */
216 	return genphy_config_aneg(phydev);
217 }
218 
219 static int phy_set_clr_bits(struct phy_device *dev, int location,
220 					int set_mask, int clr_mask)
221 {
222 	int v, ret;
223 
224 	v = phy_read(dev, location);
225 	if (v < 0)
226 		return v;
227 
228 	v &= ~clr_mask;
229 	v |= set_mask;
230 
231 	ret = phy_write(dev, location, v);
232 	if (ret < 0)
233 		return ret;
234 
235 	return v;
236 }
237 
238 static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
239 {
240 	int ret;
241 
242 	/* set shadow mode 2 */
243 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
244 			       MII_BCM7XXX_SHD_MODE_2, 0);
245 	if (ret < 0)
246 		return ret;
247 
248 	/* Set current trim values INT_trim = -1, Ext_trim =0 */
249 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0);
250 	if (ret < 0)
251 		goto reset_shadow_mode;
252 
253 	/* Cal reset */
254 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
255 			MII_BCM7XXX_SHD_3_TL4);
256 	if (ret < 0)
257 		goto reset_shadow_mode;
258 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
259 			       MII_BCM7XXX_TL4_RST_MSK, 0);
260 	if (ret < 0)
261 		goto reset_shadow_mode;
262 
263 	/* Cal reset disable */
264 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
265 			MII_BCM7XXX_SHD_3_TL4);
266 	if (ret < 0)
267 		goto reset_shadow_mode;
268 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
269 			       0, MII_BCM7XXX_TL4_RST_MSK);
270 	if (ret < 0)
271 		goto reset_shadow_mode;
272 
273 reset_shadow_mode:
274 	/* reset shadow mode 2 */
275 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
276 			       MII_BCM7XXX_SHD_MODE_2);
277 	if (ret < 0)
278 		return ret;
279 
280 	return 0;
281 }
282 
283 /* The 28nm EPHY does not support Clause 45 (MMD) used by bcm-phy-lib */
284 static int bcm7xxx_28nm_ephy_apd_enable(struct phy_device *phydev)
285 {
286 	int ret;
287 
288 	/* set shadow mode 1 */
289 	ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST,
290 			       MII_BRCM_FET_BT_SRE, 0);
291 	if (ret < 0)
292 		return ret;
293 
294 	/* Enable auto-power down */
295 	ret = phy_set_clr_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
296 			       MII_BRCM_FET_SHDW_AS2_APDE, 0);
297 	if (ret < 0)
298 		return ret;
299 
300 	/* reset shadow mode 1 */
301 	ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0,
302 			       MII_BRCM_FET_BT_SRE);
303 	if (ret < 0)
304 		return ret;
305 
306 	return 0;
307 }
308 
309 static int bcm7xxx_28nm_ephy_eee_enable(struct phy_device *phydev)
310 {
311 	int ret;
312 
313 	/* set shadow mode 2 */
314 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
315 			       MII_BCM7XXX_SHD_MODE_2, 0);
316 	if (ret < 0)
317 		return ret;
318 
319 	/* Advertise supported modes */
320 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
321 			MII_BCM7XXX_SHD_3_AN_EEE_ADV);
322 	if (ret < 0)
323 		goto reset_shadow_mode;
324 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
325 			MDIO_EEE_100TX);
326 	if (ret < 0)
327 		goto reset_shadow_mode;
328 
329 	/* Restore Defaults */
330 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
331 			MII_BCM7XXX_SHD_3_PCS_CTRL_2);
332 	if (ret < 0)
333 		goto reset_shadow_mode;
334 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
335 			MII_BCM7XXX_PCS_CTRL_2_DEF);
336 	if (ret < 0)
337 		goto reset_shadow_mode;
338 
339 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
340 			MII_BCM7XXX_SHD_3_EEE_THRESH);
341 	if (ret < 0)
342 		goto reset_shadow_mode;
343 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
344 			MII_BCM7XXX_EEE_THRESH_DEF);
345 	if (ret < 0)
346 		goto reset_shadow_mode;
347 
348 	/* Enable EEE autonegotiation */
349 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
350 			MII_BCM7XXX_SHD_3_AN_STAT);
351 	if (ret < 0)
352 		goto reset_shadow_mode;
353 	ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
354 			(MII_BCM7XXX_AN_NULL_MSG_EN | MII_BCM7XXX_AN_EEE_EN));
355 	if (ret < 0)
356 		goto reset_shadow_mode;
357 
358 reset_shadow_mode:
359 	/* reset shadow mode 2 */
360 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
361 			       MII_BCM7XXX_SHD_MODE_2);
362 	if (ret < 0)
363 		return ret;
364 
365 	/* Restart autoneg */
366 	phy_write(phydev, MII_BMCR,
367 		  (BMCR_SPEED100 | BMCR_ANENABLE | BMCR_ANRESTART));
368 
369 	return 0;
370 }
371 
372 static int bcm7xxx_28nm_ephy_config_init(struct phy_device *phydev)
373 {
374 	u8 rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
375 	int ret = 0;
376 
377 	pr_info_once("%s: %s PHY revision: 0x%02x\n",
378 		     phydev_name(phydev), phydev->drv->name, rev);
379 
380 	/* Dummy read to a register to workaround a possible issue upon reset
381 	 * where the internal inverter may not allow the first MDIO transaction
382 	 * to pass the MDIO management controller and make us return 0xffff for
383 	 * such reads.
384 	 */
385 	phy_read(phydev, MII_BMSR);
386 
387 	/* Apply AFE software work-around if necessary */
388 	if (rev == 0x01) {
389 		ret = bcm7xxx_28nm_ephy_01_afe_config_init(phydev);
390 		if (ret)
391 			return ret;
392 	}
393 
394 	ret = bcm7xxx_28nm_ephy_eee_enable(phydev);
395 	if (ret)
396 		return ret;
397 
398 	return bcm7xxx_28nm_ephy_apd_enable(phydev);
399 }
400 
401 static int bcm7xxx_28nm_ephy_resume(struct phy_device *phydev)
402 {
403 	int ret;
404 
405 	/* Re-apply workarounds coming out suspend/resume */
406 	ret = bcm7xxx_28nm_ephy_config_init(phydev);
407 	if (ret)
408 		return ret;
409 
410 	return genphy_config_aneg(phydev);
411 }
412 
413 static int bcm7xxx_config_init(struct phy_device *phydev)
414 {
415 	int ret;
416 
417 	/* Enable 64 clock MDIO */
418 	phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO);
419 	phy_read(phydev, MII_BCM7XXX_AUX_MODE);
420 
421 	/* set shadow mode 2 */
422 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
423 			MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
424 	if (ret < 0)
425 		return ret;
426 
427 	/* set iddq_clkbias */
428 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
429 	udelay(10);
430 
431 	/* reset iddq_clkbias */
432 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
433 
434 	phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
435 
436 	/* reset shadow mode 2 */
437 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
438 	if (ret < 0)
439 		return ret;
440 
441 	return 0;
442 }
443 
444 /* Workaround for putting the PHY in IDDQ mode, required
445  * for all BCM7XXX 40nm and 65nm PHYs
446  */
447 static int bcm7xxx_suspend(struct phy_device *phydev)
448 {
449 	int ret;
450 	static const struct bcm7xxx_regs {
451 		int reg;
452 		u16 value;
453 	} bcm7xxx_suspend_cfg[] = {
454 		{ MII_BCM7XXX_TEST, 0x008b },
455 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
456 		{ MII_BCM7XXX_100TX_DISC, 0x7000 },
457 		{ MII_BCM7XXX_TEST, 0x000f },
458 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
459 		{ MII_BCM7XXX_TEST, 0x000b },
460 	};
461 	unsigned int i;
462 
463 	for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
464 		ret = phy_write(phydev,
465 				bcm7xxx_suspend_cfg[i].reg,
466 				bcm7xxx_suspend_cfg[i].value);
467 		if (ret)
468 			return ret;
469 	}
470 
471 	return 0;
472 }
473 
474 static int bcm7xxx_28nm_get_tunable(struct phy_device *phydev,
475 				    struct ethtool_tunable *tuna,
476 				    void *data)
477 {
478 	switch (tuna->id) {
479 	case ETHTOOL_PHY_DOWNSHIFT:
480 		return bcm_phy_downshift_get(phydev, (u8 *)data);
481 	default:
482 		return -EOPNOTSUPP;
483 	}
484 }
485 
486 static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
487 				    struct ethtool_tunable *tuna,
488 				    const void *data)
489 {
490 	u8 count = *(u8 *)data;
491 	int ret;
492 
493 	switch (tuna->id) {
494 	case ETHTOOL_PHY_DOWNSHIFT:
495 		ret = bcm_phy_downshift_set(phydev, count);
496 		break;
497 	default:
498 		return -EOPNOTSUPP;
499 	}
500 
501 	if (ret)
502 		return ret;
503 
504 	/* Disable EEE advertisement since this prevents the PHY
505 	 * from successfully linking up, trigger auto-negotiation restart
506 	 * to let the MAC decide what to do.
507 	 */
508 	ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
509 	if (ret)
510 		return ret;
511 
512 	return genphy_restart_aneg(phydev);
513 }
514 
515 static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
516 				       struct ethtool_stats *stats, u64 *data)
517 {
518 	struct bcm7xxx_phy_priv *priv = phydev->priv;
519 
520 	bcm_phy_get_stats(phydev, priv->stats, stats, data);
521 }
522 
523 static int bcm7xxx_28nm_probe(struct phy_device *phydev)
524 {
525 	struct bcm7xxx_phy_priv *priv;
526 	int ret = 0;
527 
528 	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
529 	if (!priv)
530 		return -ENOMEM;
531 
532 	phydev->priv = priv;
533 
534 	priv->stats = devm_kcalloc(&phydev->mdio.dev,
535 				   bcm_phy_get_sset_count(phydev), sizeof(u64),
536 				   GFP_KERNEL);
537 	if (!priv->stats)
538 		return -ENOMEM;
539 
540 	priv->clk = devm_clk_get_optional(&phydev->mdio.dev, NULL);
541 	if (IS_ERR(priv->clk))
542 		return PTR_ERR(priv->clk);
543 
544 	ret = clk_prepare_enable(priv->clk);
545 	if (ret)
546 		return ret;
547 
548 	/* Dummy read to a register to workaround an issue upon reset where the
549 	 * internal inverter may not allow the first MDIO transaction to pass
550 	 * the MDIO management controller and make us return 0xffff for such
551 	 * reads. This is needed to ensure that any subsequent reads to the
552 	 * PHY will succeed.
553 	 */
554 	phy_read(phydev, MII_BMSR);
555 
556 	return ret;
557 }
558 
559 static void bcm7xxx_28nm_remove(struct phy_device *phydev)
560 {
561 	struct bcm7xxx_phy_priv *priv = phydev->priv;
562 
563 	clk_disable_unprepare(priv->clk);
564 }
565 
566 #define BCM7XXX_28NM_GPHY(_oui, _name)					\
567 {									\
568 	.phy_id		= (_oui),					\
569 	.phy_id_mask	= 0xfffffff0,					\
570 	.name		= _name,					\
571 	/* PHY_GBIT_FEATURES */						\
572 	.flags		= PHY_IS_INTERNAL,				\
573 	.config_init	= bcm7xxx_28nm_config_init,			\
574 	.resume		= bcm7xxx_28nm_resume,				\
575 	.get_tunable	= bcm7xxx_28nm_get_tunable,			\
576 	.set_tunable	= bcm7xxx_28nm_set_tunable,			\
577 	.get_sset_count	= bcm_phy_get_sset_count,			\
578 	.get_strings	= bcm_phy_get_strings,				\
579 	.get_stats	= bcm7xxx_28nm_get_phy_stats,			\
580 	.probe		= bcm7xxx_28nm_probe,				\
581 	.remove		= bcm7xxx_28nm_remove,				\
582 }
583 
584 #define BCM7XXX_28NM_EPHY(_oui, _name)					\
585 {									\
586 	.phy_id		= (_oui),					\
587 	.phy_id_mask	= 0xfffffff0,					\
588 	.name		= _name,					\
589 	/* PHY_BASIC_FEATURES */					\
590 	.flags		= PHY_IS_INTERNAL,				\
591 	.config_init	= bcm7xxx_28nm_ephy_config_init,		\
592 	.resume		= bcm7xxx_28nm_ephy_resume,			\
593 	.get_sset_count	= bcm_phy_get_sset_count,			\
594 	.get_strings	= bcm_phy_get_strings,				\
595 	.get_stats	= bcm7xxx_28nm_get_phy_stats,			\
596 	.probe		= bcm7xxx_28nm_probe,				\
597 	.remove		= bcm7xxx_28nm_remove,				\
598 }
599 
600 #define BCM7XXX_40NM_EPHY(_oui, _name)					\
601 {									\
602 	.phy_id         = (_oui),					\
603 	.phy_id_mask    = 0xfffffff0,					\
604 	.name           = _name,					\
605 	/* PHY_BASIC_FEATURES */					\
606 	.flags          = PHY_IS_INTERNAL,				\
607 	.soft_reset	= genphy_soft_reset,				\
608 	.config_init    = bcm7xxx_config_init,				\
609 	.suspend        = bcm7xxx_suspend,				\
610 	.resume         = bcm7xxx_config_init,				\
611 }
612 
613 static struct phy_driver bcm7xxx_driver[] = {
614 	BCM7XXX_28NM_EPHY(PHY_ID_BCM72113, "Broadcom BCM72113"),
615 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
616 	BCM7XXX_28NM_EPHY(PHY_ID_BCM7255, "Broadcom BCM7255"),
617 	BCM7XXX_28NM_EPHY(PHY_ID_BCM7260, "Broadcom BCM7260"),
618 	BCM7XXX_28NM_EPHY(PHY_ID_BCM7268, "Broadcom BCM7268"),
619 	BCM7XXX_28NM_EPHY(PHY_ID_BCM7271, "Broadcom BCM7271"),
620 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7278, "Broadcom BCM7278"),
621 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
622 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
623 	BCM7XXX_28NM_GPHY(PHY_ID_BCM74371, "Broadcom BCM74371"),
624 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
625 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
626 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
627 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"),
628 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"),
629 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"),
630 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"),
631 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"),
632 };
633 
634 static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
635 	{ PHY_ID_BCM72113, 0xfffffff0 },
636 	{ PHY_ID_BCM7250, 0xfffffff0, },
637 	{ PHY_ID_BCM7255, 0xfffffff0, },
638 	{ PHY_ID_BCM7260, 0xfffffff0, },
639 	{ PHY_ID_BCM7268, 0xfffffff0, },
640 	{ PHY_ID_BCM7271, 0xfffffff0, },
641 	{ PHY_ID_BCM7278, 0xfffffff0, },
642 	{ PHY_ID_BCM7364, 0xfffffff0, },
643 	{ PHY_ID_BCM7366, 0xfffffff0, },
644 	{ PHY_ID_BCM7346, 0xfffffff0, },
645 	{ PHY_ID_BCM7362, 0xfffffff0, },
646 	{ PHY_ID_BCM7425, 0xfffffff0, },
647 	{ PHY_ID_BCM7429, 0xfffffff0, },
648 	{ PHY_ID_BCM74371, 0xfffffff0, },
649 	{ PHY_ID_BCM7439, 0xfffffff0, },
650 	{ PHY_ID_BCM7435, 0xfffffff0, },
651 	{ PHY_ID_BCM7445, 0xfffffff0, },
652 	{ }
653 };
654 
655 module_phy_driver(bcm7xxx_driver);
656 
657 MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
658 
659 MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
660 MODULE_LICENSE("GPL");
661 MODULE_AUTHOR("Broadcom Corporation");
662