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