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