xref: /openbmc/linux/drivers/net/phy/mxl-gpy.c (revision 3ce7547e)
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (C) 2021 Maxlinear Corporation
3  * Copyright (C) 2020 Intel Corporation
4  *
5  * Drivers for Maxlinear Ethernet GPY
6  *
7  */
8 
9 #include <linux/module.h>
10 #include <linux/bitfield.h>
11 #include <linux/hwmon.h>
12 #include <linux/phy.h>
13 #include <linux/polynomial.h>
14 #include <linux/netdevice.h>
15 
16 /* PHY ID */
17 #define PHY_ID_GPYx15B_MASK	0xFFFFFFFC
18 #define PHY_ID_GPY21xB_MASK	0xFFFFFFF9
19 #define PHY_ID_GPY2xx		0x67C9DC00
20 #define PHY_ID_GPY115B		0x67C9DF00
21 #define PHY_ID_GPY115C		0x67C9DF10
22 #define PHY_ID_GPY211B		0x67C9DE08
23 #define PHY_ID_GPY211C		0x67C9DE10
24 #define PHY_ID_GPY212B		0x67C9DE09
25 #define PHY_ID_GPY212C		0x67C9DE20
26 #define PHY_ID_GPY215B		0x67C9DF04
27 #define PHY_ID_GPY215C		0x67C9DF20
28 #define PHY_ID_GPY241B		0x67C9DE40
29 #define PHY_ID_GPY241BM		0x67C9DE80
30 #define PHY_ID_GPY245B		0x67C9DEC0
31 
32 #define PHY_MIISTAT		0x18	/* MII state */
33 #define PHY_IMASK		0x19	/* interrupt mask */
34 #define PHY_ISTAT		0x1A	/* interrupt status */
35 #define PHY_FWV			0x1E	/* firmware version */
36 
37 #define PHY_MIISTAT_SPD_MASK	GENMASK(2, 0)
38 #define PHY_MIISTAT_DPX		BIT(3)
39 #define PHY_MIISTAT_LS		BIT(10)
40 
41 #define PHY_MIISTAT_SPD_10	0
42 #define PHY_MIISTAT_SPD_100	1
43 #define PHY_MIISTAT_SPD_1000	2
44 #define PHY_MIISTAT_SPD_2500	4
45 
46 #define PHY_IMASK_WOL		BIT(15)	/* Wake-on-LAN */
47 #define PHY_IMASK_ANC		BIT(10)	/* Auto-Neg complete */
48 #define PHY_IMASK_ADSC		BIT(5)	/* Link auto-downspeed detect */
49 #define PHY_IMASK_DXMC		BIT(2)	/* Duplex mode change */
50 #define PHY_IMASK_LSPC		BIT(1)	/* Link speed change */
51 #define PHY_IMASK_LSTC		BIT(0)	/* Link state change */
52 #define PHY_IMASK_MASK		(PHY_IMASK_LSTC | \
53 				 PHY_IMASK_LSPC | \
54 				 PHY_IMASK_DXMC | \
55 				 PHY_IMASK_ADSC | \
56 				 PHY_IMASK_ANC)
57 
58 #define PHY_FWV_REL_MASK	BIT(15)
59 #define PHY_FWV_TYPE_MASK	GENMASK(11, 8)
60 #define PHY_FWV_MINOR_MASK	GENMASK(7, 0)
61 
62 /* SGMII */
63 #define VSPEC1_SGMII_CTRL	0x08
64 #define VSPEC1_SGMII_CTRL_ANEN	BIT(12)		/* Aneg enable */
65 #define VSPEC1_SGMII_CTRL_ANRS	BIT(9)		/* Restart Aneg */
66 #define VSPEC1_SGMII_ANEN_ANRS	(VSPEC1_SGMII_CTRL_ANEN | \
67 				 VSPEC1_SGMII_CTRL_ANRS)
68 
69 /* Temperature sensor */
70 #define VPSPEC1_TEMP_STA	0x0E
71 #define VPSPEC1_TEMP_STA_DATA	GENMASK(9, 0)
72 
73 /* WoL */
74 #define VPSPEC2_WOL_CTL		0x0E06
75 #define VPSPEC2_WOL_AD01	0x0E08
76 #define VPSPEC2_WOL_AD23	0x0E09
77 #define VPSPEC2_WOL_AD45	0x0E0A
78 #define WOL_EN			BIT(0)
79 
80 static const struct {
81 	int type;
82 	int minor;
83 } ver_need_sgmii_reaneg[] = {
84 	{7, 0x6D},
85 	{8, 0x6D},
86 	{9, 0x73},
87 };
88 
89 #if IS_ENABLED(CONFIG_HWMON)
90 /* The original translation formulae of the temperature (in degrees of Celsius)
91  * are as follows:
92  *
93  *   T = -2.5761e-11*(N^4) + 9.7332e-8*(N^3) + -1.9165e-4*(N^2) +
94  *       3.0762e-1*(N^1) + -5.2156e1
95  *
96  * where [-52.156, 137.961]C and N = [0, 1023].
97  *
98  * They must be accordingly altered to be suitable for the integer arithmetics.
99  * The technique is called 'factor redistribution', which just makes sure the
100  * multiplications and divisions are made so to have a result of the operations
101  * within the integer numbers limit. In addition we need to translate the
102  * formulae to accept millidegrees of Celsius. Here what it looks like after
103  * the alterations:
104  *
105  *   T = -25761e-12*(N^4) + 97332e-9*(N^3) + -191650e-6*(N^2) +
106  *       307620e-3*(N^1) + -52156
107  *
108  * where T = [-52156, 137961]mC and N = [0, 1023].
109  */
110 static const struct polynomial poly_N_to_temp = {
111 	.terms = {
112 		{4,  -25761, 1000, 1},
113 		{3,   97332, 1000, 1},
114 		{2, -191650, 1000, 1},
115 		{1,  307620, 1000, 1},
116 		{0,  -52156,    1, 1}
117 	}
118 };
119 
120 static int gpy_hwmon_read(struct device *dev,
121 			  enum hwmon_sensor_types type,
122 			  u32 attr, int channel, long *value)
123 {
124 	struct phy_device *phydev = dev_get_drvdata(dev);
125 	int ret;
126 
127 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VPSPEC1_TEMP_STA);
128 	if (ret < 0)
129 		return ret;
130 	if (!ret)
131 		return -ENODATA;
132 
133 	*value = polynomial_calc(&poly_N_to_temp,
134 				 FIELD_GET(VPSPEC1_TEMP_STA_DATA, ret));
135 
136 	return 0;
137 }
138 
139 static umode_t gpy_hwmon_is_visible(const void *data,
140 				    enum hwmon_sensor_types type,
141 				    u32 attr, int channel)
142 {
143 	return 0444;
144 }
145 
146 static const struct hwmon_channel_info *gpy_hwmon_info[] = {
147 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
148 	NULL
149 };
150 
151 static const struct hwmon_ops gpy_hwmon_hwmon_ops = {
152 	.is_visible	= gpy_hwmon_is_visible,
153 	.read		= gpy_hwmon_read,
154 };
155 
156 static const struct hwmon_chip_info gpy_hwmon_chip_info = {
157 	.ops		= &gpy_hwmon_hwmon_ops,
158 	.info		= gpy_hwmon_info,
159 };
160 
161 static int gpy_hwmon_register(struct phy_device *phydev)
162 {
163 	struct device *dev = &phydev->mdio.dev;
164 	struct device *hwmon_dev;
165 	char *hwmon_name;
166 
167 	hwmon_name = devm_hwmon_sanitize_name(dev, dev_name(dev));
168 	if (IS_ERR(hwmon_name))
169 		return PTR_ERR(hwmon_name);
170 
171 	hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name,
172 							 phydev,
173 							 &gpy_hwmon_chip_info,
174 							 NULL);
175 
176 	return PTR_ERR_OR_ZERO(hwmon_dev);
177 }
178 #else
179 static int gpy_hwmon_register(struct phy_device *phydev)
180 {
181 	return 0;
182 }
183 #endif
184 
185 static int gpy_config_init(struct phy_device *phydev)
186 {
187 	int ret;
188 
189 	/* Mask all interrupts */
190 	ret = phy_write(phydev, PHY_IMASK, 0);
191 	if (ret)
192 		return ret;
193 
194 	/* Clear all pending interrupts */
195 	ret = phy_read(phydev, PHY_ISTAT);
196 	return ret < 0 ? ret : 0;
197 }
198 
199 static int gpy_probe(struct phy_device *phydev)
200 {
201 	int ret;
202 
203 	if (!phydev->is_c45) {
204 		ret = phy_get_c45_ids(phydev);
205 		if (ret < 0)
206 			return ret;
207 	}
208 
209 	/* Show GPY PHY FW version in dmesg */
210 	ret = phy_read(phydev, PHY_FWV);
211 	if (ret < 0)
212 		return ret;
213 
214 	ret = gpy_hwmon_register(phydev);
215 	if (ret)
216 		return ret;
217 
218 	phydev_info(phydev, "Firmware Version: 0x%04X (%s)\n", ret,
219 		    (ret & PHY_FWV_REL_MASK) ? "release" : "test");
220 
221 	return 0;
222 }
223 
224 static bool gpy_sgmii_need_reaneg(struct phy_device *phydev)
225 {
226 	int fw_ver, fw_type, fw_minor;
227 	size_t i;
228 
229 	fw_ver = phy_read(phydev, PHY_FWV);
230 	if (fw_ver < 0)
231 		return true;
232 
233 	fw_type = FIELD_GET(PHY_FWV_TYPE_MASK, fw_ver);
234 	fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_ver);
235 
236 	for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) {
237 		if (fw_type != ver_need_sgmii_reaneg[i].type)
238 			continue;
239 		if (fw_minor < ver_need_sgmii_reaneg[i].minor)
240 			return true;
241 		break;
242 	}
243 
244 	return false;
245 }
246 
247 static bool gpy_2500basex_chk(struct phy_device *phydev)
248 {
249 	int ret;
250 
251 	ret = phy_read(phydev, PHY_MIISTAT);
252 	if (ret < 0) {
253 		phydev_err(phydev, "Error: MDIO register access failed: %d\n",
254 			   ret);
255 		return false;
256 	}
257 
258 	if (!(ret & PHY_MIISTAT_LS) ||
259 	    FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500)
260 		return false;
261 
262 	phydev->speed = SPEED_2500;
263 	phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
264 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
265 		       VSPEC1_SGMII_CTRL_ANEN, 0);
266 	return true;
267 }
268 
269 static bool gpy_sgmii_aneg_en(struct phy_device *phydev)
270 {
271 	int ret;
272 
273 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL);
274 	if (ret < 0) {
275 		phydev_err(phydev, "Error: MMD register access failed: %d\n",
276 			   ret);
277 		return true;
278 	}
279 
280 	return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false;
281 }
282 
283 static int gpy_config_aneg(struct phy_device *phydev)
284 {
285 	bool changed = false;
286 	u32 adv;
287 	int ret;
288 
289 	if (phydev->autoneg == AUTONEG_DISABLE) {
290 		/* Configure half duplex with genphy_setup_forced,
291 		 * because genphy_c45_pma_setup_forced does not support.
292 		 */
293 		return phydev->duplex != DUPLEX_FULL
294 			? genphy_setup_forced(phydev)
295 			: genphy_c45_pma_setup_forced(phydev);
296 	}
297 
298 	ret = genphy_c45_an_config_aneg(phydev);
299 	if (ret < 0)
300 		return ret;
301 	if (ret > 0)
302 		changed = true;
303 
304 	adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
305 	ret = phy_modify_changed(phydev, MII_CTRL1000,
306 				 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
307 				 adv);
308 	if (ret < 0)
309 		return ret;
310 	if (ret > 0)
311 		changed = true;
312 
313 	ret = genphy_c45_check_and_restart_aneg(phydev, changed);
314 	if (ret < 0)
315 		return ret;
316 
317 	if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
318 	    phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
319 		return 0;
320 
321 	/* No need to trigger re-ANEG if link speed is 2.5G or SGMII ANEG is
322 	 * disabled.
323 	 */
324 	if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) ||
325 	    !gpy_sgmii_aneg_en(phydev))
326 		return 0;
327 
328 	/* There is a design constraint in GPY2xx device where SGMII AN is
329 	 * only triggered when there is change of speed. If, PHY link
330 	 * partner`s speed is still same even after PHY TPI is down and up
331 	 * again, SGMII AN is not triggered and hence no new in-band message
332 	 * from GPY to MAC side SGMII.
333 	 * This could cause an issue during power up, when PHY is up prior to
334 	 * MAC. At this condition, once MAC side SGMII is up, MAC side SGMII
335 	 * wouldn`t receive new in-band message from GPY with correct link
336 	 * status, speed and duplex info.
337 	 *
338 	 * 1) If PHY is already up and TPI link status is still down (such as
339 	 *    hard reboot), TPI link status is polled for 4 seconds before
340 	 *    retriggerring SGMII AN.
341 	 * 2) If PHY is already up and TPI link status is also up (such as soft
342 	 *    reboot), polling of TPI link status is not needed and SGMII AN is
343 	 *    immediately retriggered.
344 	 * 3) Other conditions such as PHY is down, speed change etc, skip
345 	 *    retriggering SGMII AN. Note: in case of speed change, GPY FW will
346 	 *    initiate SGMII AN.
347 	 */
348 
349 	if (phydev->state != PHY_UP)
350 		return 0;
351 
352 	ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS,
353 				    20000, 4000000, false);
354 	if (ret == -ETIMEDOUT)
355 		return 0;
356 	else if (ret < 0)
357 		return ret;
358 
359 	/* Trigger SGMII AN. */
360 	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
361 			      VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS);
362 }
363 
364 static void gpy_update_interface(struct phy_device *phydev)
365 {
366 	int ret;
367 
368 	/* Interface mode is fixed for USXGMII and integrated PHY */
369 	if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
370 	    phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
371 		return;
372 
373 	/* Automatically switch SERDES interface between SGMII and 2500-BaseX
374 	 * according to speed. Disable ANEG in 2500-BaseX mode.
375 	 */
376 	switch (phydev->speed) {
377 	case SPEED_2500:
378 		phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
379 		ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
380 				     VSPEC1_SGMII_CTRL_ANEN, 0);
381 		if (ret < 0)
382 			phydev_err(phydev,
383 				   "Error: Disable of SGMII ANEG failed: %d\n",
384 				   ret);
385 		break;
386 	case SPEED_1000:
387 	case SPEED_100:
388 	case SPEED_10:
389 		phydev->interface = PHY_INTERFACE_MODE_SGMII;
390 		if (gpy_sgmii_aneg_en(phydev))
391 			break;
392 		/* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed
393 		 * if ANEG is disabled (in 2500-BaseX mode).
394 		 */
395 		ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
396 				     VSPEC1_SGMII_ANEN_ANRS,
397 				     VSPEC1_SGMII_ANEN_ANRS);
398 		if (ret < 0)
399 			phydev_err(phydev,
400 				   "Error: Enable of SGMII ANEG failed: %d\n",
401 				   ret);
402 		break;
403 	}
404 
405 	if (phydev->speed == SPEED_2500 || phydev->speed == SPEED_1000)
406 		genphy_read_master_slave(phydev);
407 }
408 
409 static int gpy_read_status(struct phy_device *phydev)
410 {
411 	int ret;
412 
413 	ret = genphy_update_link(phydev);
414 	if (ret)
415 		return ret;
416 
417 	phydev->speed = SPEED_UNKNOWN;
418 	phydev->duplex = DUPLEX_UNKNOWN;
419 	phydev->pause = 0;
420 	phydev->asym_pause = 0;
421 
422 	if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
423 		ret = genphy_c45_read_lpa(phydev);
424 		if (ret < 0)
425 			return ret;
426 
427 		/* Read the link partner's 1G advertisement */
428 		ret = phy_read(phydev, MII_STAT1000);
429 		if (ret < 0)
430 			return ret;
431 		mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
432 	} else if (phydev->autoneg == AUTONEG_DISABLE) {
433 		linkmode_zero(phydev->lp_advertising);
434 	}
435 
436 	ret = phy_read(phydev, PHY_MIISTAT);
437 	if (ret < 0)
438 		return ret;
439 
440 	phydev->link = (ret & PHY_MIISTAT_LS) ? 1 : 0;
441 	phydev->duplex = (ret & PHY_MIISTAT_DPX) ? DUPLEX_FULL : DUPLEX_HALF;
442 	switch (FIELD_GET(PHY_MIISTAT_SPD_MASK, ret)) {
443 	case PHY_MIISTAT_SPD_10:
444 		phydev->speed = SPEED_10;
445 		break;
446 	case PHY_MIISTAT_SPD_100:
447 		phydev->speed = SPEED_100;
448 		break;
449 	case PHY_MIISTAT_SPD_1000:
450 		phydev->speed = SPEED_1000;
451 		break;
452 	case PHY_MIISTAT_SPD_2500:
453 		phydev->speed = SPEED_2500;
454 		break;
455 	}
456 
457 	if (phydev->link)
458 		gpy_update_interface(phydev);
459 
460 	return 0;
461 }
462 
463 static int gpy_config_intr(struct phy_device *phydev)
464 {
465 	u16 mask = 0;
466 
467 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
468 		mask = PHY_IMASK_MASK;
469 
470 	return phy_write(phydev, PHY_IMASK, mask);
471 }
472 
473 static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev)
474 {
475 	int reg;
476 
477 	reg = phy_read(phydev, PHY_ISTAT);
478 	if (reg < 0) {
479 		phy_error(phydev);
480 		return IRQ_NONE;
481 	}
482 
483 	if (!(reg & PHY_IMASK_MASK))
484 		return IRQ_NONE;
485 
486 	phy_trigger_machine(phydev);
487 
488 	return IRQ_HANDLED;
489 }
490 
491 static int gpy_set_wol(struct phy_device *phydev,
492 		       struct ethtool_wolinfo *wol)
493 {
494 	struct net_device *attach_dev = phydev->attached_dev;
495 	int ret;
496 
497 	if (wol->wolopts & WAKE_MAGIC) {
498 		/* MAC address - Byte0:Byte1:Byte2:Byte3:Byte4:Byte5
499 		 * VPSPEC2_WOL_AD45 = Byte0:Byte1
500 		 * VPSPEC2_WOL_AD23 = Byte2:Byte3
501 		 * VPSPEC2_WOL_AD01 = Byte4:Byte5
502 		 */
503 		ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
504 				       VPSPEC2_WOL_AD45,
505 				       ((attach_dev->dev_addr[0] << 8) |
506 				       attach_dev->dev_addr[1]));
507 		if (ret < 0)
508 			return ret;
509 
510 		ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
511 				       VPSPEC2_WOL_AD23,
512 				       ((attach_dev->dev_addr[2] << 8) |
513 				       attach_dev->dev_addr[3]));
514 		if (ret < 0)
515 			return ret;
516 
517 		ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
518 				       VPSPEC2_WOL_AD01,
519 				       ((attach_dev->dev_addr[4] << 8) |
520 				       attach_dev->dev_addr[5]));
521 		if (ret < 0)
522 			return ret;
523 
524 		/* Enable the WOL interrupt */
525 		ret = phy_write(phydev, PHY_IMASK, PHY_IMASK_WOL);
526 		if (ret < 0)
527 			return ret;
528 
529 		/* Enable magic packet matching */
530 		ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
531 				       VPSPEC2_WOL_CTL,
532 				       WOL_EN);
533 		if (ret < 0)
534 			return ret;
535 
536 		/* Clear the interrupt status register.
537 		 * Only WoL is enabled so clear all.
538 		 */
539 		ret = phy_read(phydev, PHY_ISTAT);
540 		if (ret < 0)
541 			return ret;
542 	} else {
543 		/* Disable magic packet matching */
544 		ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
545 					 VPSPEC2_WOL_CTL,
546 					 WOL_EN);
547 		if (ret < 0)
548 			return ret;
549 	}
550 
551 	if (wol->wolopts & WAKE_PHY) {
552 		/* Enable the link state change interrupt */
553 		ret = phy_set_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
554 		if (ret < 0)
555 			return ret;
556 
557 		/* Clear the interrupt status register */
558 		ret = phy_read(phydev, PHY_ISTAT);
559 		if (ret < 0)
560 			return ret;
561 
562 		if (ret & (PHY_IMASK_MASK & ~PHY_IMASK_LSTC))
563 			phy_trigger_machine(phydev);
564 
565 		return 0;
566 	}
567 
568 	/* Disable the link state change interrupt */
569 	return phy_clear_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
570 }
571 
572 static void gpy_get_wol(struct phy_device *phydev,
573 			struct ethtool_wolinfo *wol)
574 {
575 	int ret;
576 
577 	wol->supported = WAKE_MAGIC | WAKE_PHY;
578 	wol->wolopts = 0;
579 
580 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, VPSPEC2_WOL_CTL);
581 	if (ret & WOL_EN)
582 		wol->wolopts |= WAKE_MAGIC;
583 
584 	ret = phy_read(phydev, PHY_IMASK);
585 	if (ret & PHY_IMASK_LSTC)
586 		wol->wolopts |= WAKE_PHY;
587 }
588 
589 static int gpy_loopback(struct phy_device *phydev, bool enable)
590 {
591 	int ret;
592 
593 	ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
594 			 enable ? BMCR_LOOPBACK : 0);
595 	if (!ret) {
596 		/* It takes some time for PHY device to switch
597 		 * into/out-of loopback mode.
598 		 */
599 		msleep(100);
600 	}
601 
602 	return ret;
603 }
604 
605 static int gpy115_loopback(struct phy_device *phydev, bool enable)
606 {
607 	int ret;
608 	int fw_minor;
609 
610 	if (enable)
611 		return gpy_loopback(phydev, enable);
612 
613 	ret = phy_read(phydev, PHY_FWV);
614 	if (ret < 0)
615 		return ret;
616 
617 	fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, ret);
618 	if (fw_minor > 0x0076)
619 		return gpy_loopback(phydev, 0);
620 
621 	return genphy_soft_reset(phydev);
622 }
623 
624 static struct phy_driver gpy_drivers[] = {
625 	{
626 		PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
627 		.name		= "Maxlinear Ethernet GPY2xx",
628 		.get_features	= genphy_c45_pma_read_abilities,
629 		.config_init	= gpy_config_init,
630 		.probe		= gpy_probe,
631 		.suspend	= genphy_suspend,
632 		.resume		= genphy_resume,
633 		.config_aneg	= gpy_config_aneg,
634 		.aneg_done	= genphy_c45_aneg_done,
635 		.read_status	= gpy_read_status,
636 		.config_intr	= gpy_config_intr,
637 		.handle_interrupt = gpy_handle_interrupt,
638 		.set_wol	= gpy_set_wol,
639 		.get_wol	= gpy_get_wol,
640 		.set_loopback	= gpy_loopback,
641 	},
642 	{
643 		.phy_id		= PHY_ID_GPY115B,
644 		.phy_id_mask	= PHY_ID_GPYx15B_MASK,
645 		.name		= "Maxlinear Ethernet GPY115B",
646 		.get_features	= genphy_c45_pma_read_abilities,
647 		.config_init	= gpy_config_init,
648 		.probe		= gpy_probe,
649 		.suspend	= genphy_suspend,
650 		.resume		= genphy_resume,
651 		.config_aneg	= gpy_config_aneg,
652 		.aneg_done	= genphy_c45_aneg_done,
653 		.read_status	= gpy_read_status,
654 		.config_intr	= gpy_config_intr,
655 		.handle_interrupt = gpy_handle_interrupt,
656 		.set_wol	= gpy_set_wol,
657 		.get_wol	= gpy_get_wol,
658 		.set_loopback	= gpy115_loopback,
659 	},
660 	{
661 		PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
662 		.name		= "Maxlinear Ethernet GPY115C",
663 		.get_features	= genphy_c45_pma_read_abilities,
664 		.config_init	= gpy_config_init,
665 		.probe		= gpy_probe,
666 		.suspend	= genphy_suspend,
667 		.resume		= genphy_resume,
668 		.config_aneg	= gpy_config_aneg,
669 		.aneg_done	= genphy_c45_aneg_done,
670 		.read_status	= gpy_read_status,
671 		.config_intr	= gpy_config_intr,
672 		.handle_interrupt = gpy_handle_interrupt,
673 		.set_wol	= gpy_set_wol,
674 		.get_wol	= gpy_get_wol,
675 		.set_loopback	= gpy115_loopback,
676 	},
677 	{
678 		.phy_id		= PHY_ID_GPY211B,
679 		.phy_id_mask	= PHY_ID_GPY21xB_MASK,
680 		.name		= "Maxlinear Ethernet GPY211B",
681 		.get_features	= genphy_c45_pma_read_abilities,
682 		.config_init	= gpy_config_init,
683 		.probe		= gpy_probe,
684 		.suspend	= genphy_suspend,
685 		.resume		= genphy_resume,
686 		.config_aneg	= gpy_config_aneg,
687 		.aneg_done	= genphy_c45_aneg_done,
688 		.read_status	= gpy_read_status,
689 		.config_intr	= gpy_config_intr,
690 		.handle_interrupt = gpy_handle_interrupt,
691 		.set_wol	= gpy_set_wol,
692 		.get_wol	= gpy_get_wol,
693 		.set_loopback	= gpy_loopback,
694 	},
695 	{
696 		PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
697 		.name		= "Maxlinear Ethernet GPY211C",
698 		.get_features	= genphy_c45_pma_read_abilities,
699 		.config_init	= gpy_config_init,
700 		.probe		= gpy_probe,
701 		.suspend	= genphy_suspend,
702 		.resume		= genphy_resume,
703 		.config_aneg	= gpy_config_aneg,
704 		.aneg_done	= genphy_c45_aneg_done,
705 		.read_status	= gpy_read_status,
706 		.config_intr	= gpy_config_intr,
707 		.handle_interrupt = gpy_handle_interrupt,
708 		.set_wol	= gpy_set_wol,
709 		.get_wol	= gpy_get_wol,
710 		.set_loopback	= gpy_loopback,
711 	},
712 	{
713 		.phy_id		= PHY_ID_GPY212B,
714 		.phy_id_mask	= PHY_ID_GPY21xB_MASK,
715 		.name		= "Maxlinear Ethernet GPY212B",
716 		.get_features	= genphy_c45_pma_read_abilities,
717 		.config_init	= gpy_config_init,
718 		.probe		= gpy_probe,
719 		.suspend	= genphy_suspend,
720 		.resume		= genphy_resume,
721 		.config_aneg	= gpy_config_aneg,
722 		.aneg_done	= genphy_c45_aneg_done,
723 		.read_status	= gpy_read_status,
724 		.config_intr	= gpy_config_intr,
725 		.handle_interrupt = gpy_handle_interrupt,
726 		.set_wol	= gpy_set_wol,
727 		.get_wol	= gpy_get_wol,
728 		.set_loopback	= gpy_loopback,
729 	},
730 	{
731 		PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
732 		.name		= "Maxlinear Ethernet GPY212C",
733 		.get_features	= genphy_c45_pma_read_abilities,
734 		.config_init	= gpy_config_init,
735 		.probe		= gpy_probe,
736 		.suspend	= genphy_suspend,
737 		.resume		= genphy_resume,
738 		.config_aneg	= gpy_config_aneg,
739 		.aneg_done	= genphy_c45_aneg_done,
740 		.read_status	= gpy_read_status,
741 		.config_intr	= gpy_config_intr,
742 		.handle_interrupt = gpy_handle_interrupt,
743 		.set_wol	= gpy_set_wol,
744 		.get_wol	= gpy_get_wol,
745 		.set_loopback	= gpy_loopback,
746 	},
747 	{
748 		.phy_id		= PHY_ID_GPY215B,
749 		.phy_id_mask	= PHY_ID_GPYx15B_MASK,
750 		.name		= "Maxlinear Ethernet GPY215B",
751 		.get_features	= genphy_c45_pma_read_abilities,
752 		.config_init	= gpy_config_init,
753 		.probe		= gpy_probe,
754 		.suspend	= genphy_suspend,
755 		.resume		= genphy_resume,
756 		.config_aneg	= gpy_config_aneg,
757 		.aneg_done	= genphy_c45_aneg_done,
758 		.read_status	= gpy_read_status,
759 		.config_intr	= gpy_config_intr,
760 		.handle_interrupt = gpy_handle_interrupt,
761 		.set_wol	= gpy_set_wol,
762 		.get_wol	= gpy_get_wol,
763 		.set_loopback	= gpy_loopback,
764 	},
765 	{
766 		PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
767 		.name		= "Maxlinear Ethernet GPY215C",
768 		.get_features	= genphy_c45_pma_read_abilities,
769 		.config_init	= gpy_config_init,
770 		.probe		= gpy_probe,
771 		.suspend	= genphy_suspend,
772 		.resume		= genphy_resume,
773 		.config_aneg	= gpy_config_aneg,
774 		.aneg_done	= genphy_c45_aneg_done,
775 		.read_status	= gpy_read_status,
776 		.config_intr	= gpy_config_intr,
777 		.handle_interrupt = gpy_handle_interrupt,
778 		.set_wol	= gpy_set_wol,
779 		.get_wol	= gpy_get_wol,
780 		.set_loopback	= gpy_loopback,
781 	},
782 	{
783 		PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
784 		.name		= "Maxlinear Ethernet GPY241B",
785 		.get_features	= genphy_c45_pma_read_abilities,
786 		.config_init	= gpy_config_init,
787 		.probe		= gpy_probe,
788 		.suspend	= genphy_suspend,
789 		.resume		= genphy_resume,
790 		.config_aneg	= gpy_config_aneg,
791 		.aneg_done	= genphy_c45_aneg_done,
792 		.read_status	= gpy_read_status,
793 		.config_intr	= gpy_config_intr,
794 		.handle_interrupt = gpy_handle_interrupt,
795 		.set_wol	= gpy_set_wol,
796 		.get_wol	= gpy_get_wol,
797 		.set_loopback	= gpy_loopback,
798 	},
799 	{
800 		PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM),
801 		.name		= "Maxlinear Ethernet GPY241BM",
802 		.get_features	= genphy_c45_pma_read_abilities,
803 		.config_init	= gpy_config_init,
804 		.probe		= gpy_probe,
805 		.suspend	= genphy_suspend,
806 		.resume		= genphy_resume,
807 		.config_aneg	= gpy_config_aneg,
808 		.aneg_done	= genphy_c45_aneg_done,
809 		.read_status	= gpy_read_status,
810 		.config_intr	= gpy_config_intr,
811 		.handle_interrupt = gpy_handle_interrupt,
812 		.set_wol	= gpy_set_wol,
813 		.get_wol	= gpy_get_wol,
814 		.set_loopback	= gpy_loopback,
815 	},
816 	{
817 		PHY_ID_MATCH_MODEL(PHY_ID_GPY245B),
818 		.name		= "Maxlinear Ethernet GPY245B",
819 		.get_features	= genphy_c45_pma_read_abilities,
820 		.config_init	= gpy_config_init,
821 		.probe		= gpy_probe,
822 		.suspend	= genphy_suspend,
823 		.resume		= genphy_resume,
824 		.config_aneg	= gpy_config_aneg,
825 		.aneg_done	= genphy_c45_aneg_done,
826 		.read_status	= gpy_read_status,
827 		.config_intr	= gpy_config_intr,
828 		.handle_interrupt = gpy_handle_interrupt,
829 		.set_wol	= gpy_set_wol,
830 		.get_wol	= gpy_get_wol,
831 		.set_loopback	= gpy_loopback,
832 	},
833 };
834 module_phy_driver(gpy_drivers);
835 
836 static struct mdio_device_id __maybe_unused gpy_tbl[] = {
837 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)},
838 	{PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK},
839 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)},
840 	{PHY_ID_GPY211B, PHY_ID_GPY21xB_MASK},
841 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY211C)},
842 	{PHY_ID_GPY212B, PHY_ID_GPY21xB_MASK},
843 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY212C)},
844 	{PHY_ID_GPY215B, PHY_ID_GPYx15B_MASK},
845 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY215C)},
846 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)},
847 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)},
848 	{PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)},
849 	{ }
850 };
851 MODULE_DEVICE_TABLE(mdio, gpy_tbl);
852 
853 MODULE_DESCRIPTION("Maxlinear Ethernet GPY Driver");
854 MODULE_AUTHOR("Xu Liang");
855 MODULE_LICENSE("GPL");
856