1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+
2bbc4d71dSWilly Liu /* drivers/net/phy/realtek.c
3097c2aa8SJohnson Leung *
4097c2aa8SJohnson Leung * Driver for Realtek PHYs
5097c2aa8SJohnson Leung *
6097c2aa8SJohnson Leung * Author: Johnson Leung <r58129@freescale.com>
7097c2aa8SJohnson Leung *
8097c2aa8SJohnson Leung * Copyright (c) 2004 Freescale Semiconductor, Inc.
9097c2aa8SJohnson Leung */
108cc5baefSMartin Blumenstingl #include <linux/bitops.h>
110a4355c2SJoakim Zhang #include <linux/of.h>
12097c2aa8SJohnson Leung #include <linux/phy.h>
139d9779e7SPaul Gortmaker #include <linux/module.h>
14fee698d6SHeiner Kallweit #include <linux/delay.h>
157300c9b5SDetlev Casanova #include <linux/clk.h>
16097c2aa8SJohnson Leung
17097c2aa8SJohnson Leung #define RTL821x_PHYSR 0x11
188cc5baefSMartin Blumenstingl #define RTL821x_PHYSR_DUPLEX BIT(13)
198cc5baefSMartin Blumenstingl #define RTL821x_PHYSR_SPEED GENMASK(15, 14)
20a82f266dSMartin Blumenstingl
21097c2aa8SJohnson Leung #define RTL821x_INER 0x12
2269021e32SMartin Blumenstingl #define RTL8211B_INER_INIT 0x6400
238cc5baefSMartin Blumenstingl #define RTL8211E_INER_LINK_STATUS BIT(10)
248cc5baefSMartin Blumenstingl #define RTL8211F_INER_LINK_STATUS BIT(4)
25a82f266dSMartin Blumenstingl
26a82f266dSMartin Blumenstingl #define RTL821x_INSR 0x13
27a82f266dSMartin Blumenstingl
28f81dadbcSSerge Semin #define RTL821x_EXT_PAGE_SELECT 0x1e
29a82f266dSMartin Blumenstingl #define RTL821x_PAGE_SELECT 0x1f
30a82f266dSMartin Blumenstingl
3166e22932SJisheng Zhang #define RTL8211F_PHYCR1 0x18
320a4355c2SJoakim Zhang #define RTL8211F_PHYCR2 0x19
333447cf2eSShengzhou Liu #define RTL8211F_INSR 0x1d
34f609ab0eSMartin Blumenstingl
358cc5baefSMartin Blumenstingl #define RTL8211F_TX_DELAY BIT(8)
361b3047b5SMartin Blumenstingl #define RTL8211F_RX_DELAY BIT(3)
371b3047b5SMartin Blumenstingl
3866e22932SJisheng Zhang #define RTL8211F_ALDPS_PLL_OFF BIT(1)
3966e22932SJisheng Zhang #define RTL8211F_ALDPS_ENABLE BIT(2)
4066e22932SJisheng Zhang #define RTL8211F_ALDPS_XTAL_OFF BIT(12)
4166e22932SJisheng Zhang
42bbc4d71dSWilly Liu #define RTL8211E_CTRL_DELAY BIT(13)
43bbc4d71dSWilly Liu #define RTL8211E_TX_DELAY BIT(12)
44bbc4d71dSWilly Liu #define RTL8211E_RX_DELAY BIT(11)
453447cf2eSShengzhou Liu
460a4355c2SJoakim Zhang #define RTL8211F_CLKOUT_EN BIT(0)
470a4355c2SJoakim Zhang
48513588ddSJassi Brar #define RTL8201F_ISR 0x1e
4903829163SIoana Ciornei #define RTL8201F_ISR_ANERR BIT(15)
5003829163SIoana Ciornei #define RTL8201F_ISR_DUPLEX BIT(13)
5103829163SIoana Ciornei #define RTL8201F_ISR_LINK BIT(11)
5203829163SIoana Ciornei #define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \
5303829163SIoana Ciornei RTL8201F_ISR_DUPLEX | \
5403829163SIoana Ciornei RTL8201F_ISR_LINK)
55513588ddSJassi Brar #define RTL8201F_IER 0x13
56513588ddSJassi Brar
57d8545825SLinus Walleij #define RTL8366RB_POWER_SAVE 0x15
58d8545825SLinus Walleij #define RTL8366RB_POWER_SAVE_ON BIT(12)
59d8545825SLinus Walleij
605181b473SHeiner Kallweit #define RTL_SUPPORTS_5000FULL BIT(14)
615181b473SHeiner Kallweit #define RTL_SUPPORTS_2500FULL BIT(13)
625181b473SHeiner Kallweit #define RTL_SUPPORTS_10000FULL BIT(0)
63087f5b87SHeiner Kallweit #define RTL_ADV_2500FULL BIT(7)
64087f5b87SHeiner Kallweit #define RTL_LPADV_10000FULL BIT(11)
65087f5b87SHeiner Kallweit #define RTL_LPADV_5000FULL BIT(6)
66087f5b87SHeiner Kallweit #define RTL_LPADV_2500FULL BIT(5)
67087f5b87SHeiner Kallweit
682d8983f9SYuusuke Ashizuka #define RTL9000A_GINMR 0x14
692d8983f9SYuusuke Ashizuka #define RTL9000A_GINMR_LINK_STATUS BIT(4)
702d8983f9SYuusuke Ashizuka
71d445dff2SHeiner Kallweit #define RTLGEN_SPEED_MASK 0x0630
72d445dff2SHeiner Kallweit
735181b473SHeiner Kallweit #define RTL_GENERIC_PHYID 0x001cc800
74bb726b75SClark Wang #define RTL_8211FVD_PHYID 0x001cc878
755181b473SHeiner Kallweit
76097c2aa8SJohnson Leung MODULE_DESCRIPTION("Realtek PHY driver");
77097c2aa8SJohnson Leung MODULE_AUTHOR("Johnson Leung");
78097c2aa8SJohnson Leung MODULE_LICENSE("GPL");
79097c2aa8SJohnson Leung
800a4355c2SJoakim Zhang struct rtl821x_priv {
81d90db36aSJoakim Zhang u16 phycr1;
820a4355c2SJoakim Zhang u16 phycr2;
83bb726b75SClark Wang bool has_phycr2;
847300c9b5SDetlev Casanova struct clk *clk;
850a4355c2SJoakim Zhang };
860a4355c2SJoakim Zhang
rtl821x_read_page(struct phy_device * phydev)87d98c8ccdSHeiner Kallweit static int rtl821x_read_page(struct phy_device *phydev)
88136819a6SMartin Blumenstingl {
89d98c8ccdSHeiner Kallweit return __phy_read(phydev, RTL821x_PAGE_SELECT);
90136819a6SMartin Blumenstingl }
91136819a6SMartin Blumenstingl
rtl821x_write_page(struct phy_device * phydev,int page)92d98c8ccdSHeiner Kallweit static int rtl821x_write_page(struct phy_device *phydev, int page)
93136819a6SMartin Blumenstingl {
94d98c8ccdSHeiner Kallweit return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
95136819a6SMartin Blumenstingl }
96136819a6SMartin Blumenstingl
rtl821x_probe(struct phy_device * phydev)970a4355c2SJoakim Zhang static int rtl821x_probe(struct phy_device *phydev)
980a4355c2SJoakim Zhang {
990a4355c2SJoakim Zhang struct device *dev = &phydev->mdio.dev;
1000a4355c2SJoakim Zhang struct rtl821x_priv *priv;
101bb726b75SClark Wang u32 phy_id = phydev->drv->phy_id;
102f25247d8SColin Ian King int ret;
1030a4355c2SJoakim Zhang
1040a4355c2SJoakim Zhang priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1050a4355c2SJoakim Zhang if (!priv)
1060a4355c2SJoakim Zhang return -ENOMEM;
1070a4355c2SJoakim Zhang
1087300c9b5SDetlev Casanova priv->clk = devm_clk_get_optional_enabled(dev, NULL);
1097300c9b5SDetlev Casanova if (IS_ERR(priv->clk))
1107300c9b5SDetlev Casanova return dev_err_probe(dev, PTR_ERR(priv->clk),
1117300c9b5SDetlev Casanova "failed to get phy clock\n");
1127300c9b5SDetlev Casanova
113f25247d8SColin Ian King ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1);
114f25247d8SColin Ian King if (ret < 0)
115f25247d8SColin Ian King return ret;
116d90db36aSJoakim Zhang
117f25247d8SColin Ian King priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF);
118d90db36aSJoakim Zhang if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
119d90db36aSJoakim Zhang priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
120d90db36aSJoakim Zhang
121bb726b75SClark Wang priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID);
122bb726b75SClark Wang if (priv->has_phycr2) {
123f25247d8SColin Ian King ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
124f25247d8SColin Ian King if (ret < 0)
125f25247d8SColin Ian King return ret;
1260a4355c2SJoakim Zhang
127f25247d8SColin Ian King priv->phycr2 = ret & RTL8211F_CLKOUT_EN;
1280a4355c2SJoakim Zhang if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
1290a4355c2SJoakim Zhang priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
130bb726b75SClark Wang }
1310a4355c2SJoakim Zhang
1320a4355c2SJoakim Zhang phydev->priv = priv;
1330a4355c2SJoakim Zhang
1340a4355c2SJoakim Zhang return 0;
1350a4355c2SJoakim Zhang }
1360a4355c2SJoakim Zhang
rtl8201_ack_interrupt(struct phy_device * phydev)137513588ddSJassi Brar static int rtl8201_ack_interrupt(struct phy_device *phydev)
138513588ddSJassi Brar {
139513588ddSJassi Brar int err;
140513588ddSJassi Brar
141513588ddSJassi Brar err = phy_read(phydev, RTL8201F_ISR);
142513588ddSJassi Brar
143513588ddSJassi Brar return (err < 0) ? err : 0;
144513588ddSJassi Brar }
145513588ddSJassi Brar
rtl821x_ack_interrupt(struct phy_device * phydev)146097c2aa8SJohnson Leung static int rtl821x_ack_interrupt(struct phy_device *phydev)
147097c2aa8SJohnson Leung {
148097c2aa8SJohnson Leung int err;
149097c2aa8SJohnson Leung
150097c2aa8SJohnson Leung err = phy_read(phydev, RTL821x_INSR);
151097c2aa8SJohnson Leung
152097c2aa8SJohnson Leung return (err < 0) ? err : 0;
153097c2aa8SJohnson Leung }
154097c2aa8SJohnson Leung
rtl8211f_ack_interrupt(struct phy_device * phydev)1553447cf2eSShengzhou Liu static int rtl8211f_ack_interrupt(struct phy_device *phydev)
1563447cf2eSShengzhou Liu {
1573447cf2eSShengzhou Liu int err;
1583447cf2eSShengzhou Liu
159d98c8ccdSHeiner Kallweit err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
1603447cf2eSShengzhou Liu
1613447cf2eSShengzhou Liu return (err < 0) ? err : 0;
1623447cf2eSShengzhou Liu }
1633447cf2eSShengzhou Liu
rtl8201_config_intr(struct phy_device * phydev)164513588ddSJassi Brar static int rtl8201_config_intr(struct phy_device *phydev)
165513588ddSJassi Brar {
166136819a6SMartin Blumenstingl u16 val;
1678b43357fSIoana Ciornei int err;
168513588ddSJassi Brar
1698b43357fSIoana Ciornei if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1708b43357fSIoana Ciornei err = rtl8201_ack_interrupt(phydev);
1718b43357fSIoana Ciornei if (err)
1728b43357fSIoana Ciornei return err;
1738b43357fSIoana Ciornei
174136819a6SMartin Blumenstingl val = BIT(13) | BIT(12) | BIT(11);
1758b43357fSIoana Ciornei err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
1768b43357fSIoana Ciornei } else {
177136819a6SMartin Blumenstingl val = 0;
1788b43357fSIoana Ciornei err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
1798b43357fSIoana Ciornei if (err)
1808b43357fSIoana Ciornei return err;
181513588ddSJassi Brar
1828b43357fSIoana Ciornei err = rtl8201_ack_interrupt(phydev);
1838b43357fSIoana Ciornei }
1848b43357fSIoana Ciornei
1858b43357fSIoana Ciornei return err;
186513588ddSJassi Brar }
187513588ddSJassi Brar
rtl8211b_config_intr(struct phy_device * phydev)188ef3d9049SGiuseppe CAVALLARO static int rtl8211b_config_intr(struct phy_device *phydev)
189097c2aa8SJohnson Leung {
190097c2aa8SJohnson Leung int err;
191097c2aa8SJohnson Leung
1928b43357fSIoana Ciornei if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1938b43357fSIoana Ciornei err = rtl821x_ack_interrupt(phydev);
1948b43357fSIoana Ciornei if (err)
1958b43357fSIoana Ciornei return err;
1968b43357fSIoana Ciornei
197097c2aa8SJohnson Leung err = phy_write(phydev, RTL821x_INER,
19869021e32SMartin Blumenstingl RTL8211B_INER_INIT);
1998b43357fSIoana Ciornei } else {
200097c2aa8SJohnson Leung err = phy_write(phydev, RTL821x_INER, 0);
2018b43357fSIoana Ciornei if (err)
2028b43357fSIoana Ciornei return err;
2038b43357fSIoana Ciornei
2048b43357fSIoana Ciornei err = rtl821x_ack_interrupt(phydev);
2058b43357fSIoana Ciornei }
206097c2aa8SJohnson Leung
207097c2aa8SJohnson Leung return err;
208097c2aa8SJohnson Leung }
209097c2aa8SJohnson Leung
rtl8211e_config_intr(struct phy_device * phydev)210ef3d9049SGiuseppe CAVALLARO static int rtl8211e_config_intr(struct phy_device *phydev)
211ef3d9049SGiuseppe CAVALLARO {
212ef3d9049SGiuseppe CAVALLARO int err;
213ef3d9049SGiuseppe CAVALLARO
2148b43357fSIoana Ciornei if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
2158b43357fSIoana Ciornei err = rtl821x_ack_interrupt(phydev);
2168b43357fSIoana Ciornei if (err)
2178b43357fSIoana Ciornei return err;
2188b43357fSIoana Ciornei
219ef3d9049SGiuseppe CAVALLARO err = phy_write(phydev, RTL821x_INER,
2208b64fd61SGiuseppe CAVALLARO RTL8211E_INER_LINK_STATUS);
2218b43357fSIoana Ciornei } else {
222ef3d9049SGiuseppe CAVALLARO err = phy_write(phydev, RTL821x_INER, 0);
2238b43357fSIoana Ciornei if (err)
2248b43357fSIoana Ciornei return err;
2258b43357fSIoana Ciornei
2268b43357fSIoana Ciornei err = rtl821x_ack_interrupt(phydev);
2278b43357fSIoana Ciornei }
228ef3d9049SGiuseppe CAVALLARO
229ef3d9049SGiuseppe CAVALLARO return err;
230ef3d9049SGiuseppe CAVALLARO }
231ef3d9049SGiuseppe CAVALLARO
rtl8211f_config_intr(struct phy_device * phydev)2323447cf2eSShengzhou Liu static int rtl8211f_config_intr(struct phy_device *phydev)
2333447cf2eSShengzhou Liu {
234136819a6SMartin Blumenstingl u16 val;
2358b43357fSIoana Ciornei int err;
2363447cf2eSShengzhou Liu
2378b43357fSIoana Ciornei if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
2388b43357fSIoana Ciornei err = rtl8211f_ack_interrupt(phydev);
2398b43357fSIoana Ciornei if (err)
2408b43357fSIoana Ciornei return err;
2418b43357fSIoana Ciornei
242136819a6SMartin Blumenstingl val = RTL8211F_INER_LINK_STATUS;
2438b43357fSIoana Ciornei err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
2448b43357fSIoana Ciornei } else {
245136819a6SMartin Blumenstingl val = 0;
2468b43357fSIoana Ciornei err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
2478b43357fSIoana Ciornei if (err)
2488b43357fSIoana Ciornei return err;
2493447cf2eSShengzhou Liu
2508b43357fSIoana Ciornei err = rtl8211f_ack_interrupt(phydev);
2518b43357fSIoana Ciornei }
2528b43357fSIoana Ciornei
2538b43357fSIoana Ciornei return err;
2543447cf2eSShengzhou Liu }
2553447cf2eSShengzhou Liu
rtl8201_handle_interrupt(struct phy_device * phydev)25603829163SIoana Ciornei static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev)
25703829163SIoana Ciornei {
25803829163SIoana Ciornei int irq_status;
25903829163SIoana Ciornei
26003829163SIoana Ciornei irq_status = phy_read(phydev, RTL8201F_ISR);
26103829163SIoana Ciornei if (irq_status < 0) {
26203829163SIoana Ciornei phy_error(phydev);
26303829163SIoana Ciornei return IRQ_NONE;
26403829163SIoana Ciornei }
26503829163SIoana Ciornei
26603829163SIoana Ciornei if (!(irq_status & RTL8201F_ISR_MASK))
26703829163SIoana Ciornei return IRQ_NONE;
26803829163SIoana Ciornei
26903829163SIoana Ciornei phy_trigger_machine(phydev);
27003829163SIoana Ciornei
27103829163SIoana Ciornei return IRQ_HANDLED;
27203829163SIoana Ciornei }
27303829163SIoana Ciornei
rtl821x_handle_interrupt(struct phy_device * phydev)27403829163SIoana Ciornei static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev)
27503829163SIoana Ciornei {
27603829163SIoana Ciornei int irq_status, irq_enabled;
27703829163SIoana Ciornei
27803829163SIoana Ciornei irq_status = phy_read(phydev, RTL821x_INSR);
27903829163SIoana Ciornei if (irq_status < 0) {
28003829163SIoana Ciornei phy_error(phydev);
28103829163SIoana Ciornei return IRQ_NONE;
28203829163SIoana Ciornei }
28303829163SIoana Ciornei
28403829163SIoana Ciornei irq_enabled = phy_read(phydev, RTL821x_INER);
28503829163SIoana Ciornei if (irq_enabled < 0) {
28603829163SIoana Ciornei phy_error(phydev);
28703829163SIoana Ciornei return IRQ_NONE;
28803829163SIoana Ciornei }
28903829163SIoana Ciornei
29003829163SIoana Ciornei if (!(irq_status & irq_enabled))
29103829163SIoana Ciornei return IRQ_NONE;
29203829163SIoana Ciornei
29303829163SIoana Ciornei phy_trigger_machine(phydev);
29403829163SIoana Ciornei
29503829163SIoana Ciornei return IRQ_HANDLED;
29603829163SIoana Ciornei }
29703829163SIoana Ciornei
rtl8211f_handle_interrupt(struct phy_device * phydev)29803829163SIoana Ciornei static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev)
29903829163SIoana Ciornei {
30003829163SIoana Ciornei int irq_status;
30103829163SIoana Ciornei
30203829163SIoana Ciornei irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
30303829163SIoana Ciornei if (irq_status < 0) {
30403829163SIoana Ciornei phy_error(phydev);
30503829163SIoana Ciornei return IRQ_NONE;
30603829163SIoana Ciornei }
30703829163SIoana Ciornei
30803829163SIoana Ciornei if (!(irq_status & RTL8211F_INER_LINK_STATUS))
30903829163SIoana Ciornei return IRQ_NONE;
31003829163SIoana Ciornei
31103829163SIoana Ciornei phy_trigger_machine(phydev);
31203829163SIoana Ciornei
31303829163SIoana Ciornei return IRQ_HANDLED;
31403829163SIoana Ciornei }
31503829163SIoana Ciornei
rtl8211_config_aneg(struct phy_device * phydev)316d241d4aaSHeiner Kallweit static int rtl8211_config_aneg(struct phy_device *phydev)
317d241d4aaSHeiner Kallweit {
318d241d4aaSHeiner Kallweit int ret;
319d241d4aaSHeiner Kallweit
320d241d4aaSHeiner Kallweit ret = genphy_config_aneg(phydev);
321d241d4aaSHeiner Kallweit if (ret < 0)
322d241d4aaSHeiner Kallweit return ret;
323d241d4aaSHeiner Kallweit
324d241d4aaSHeiner Kallweit /* Quirk was copied from vendor driver. Unfortunately it includes no
325d241d4aaSHeiner Kallweit * description of the magic numbers.
326d241d4aaSHeiner Kallweit */
327d241d4aaSHeiner Kallweit if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
328d241d4aaSHeiner Kallweit phy_write(phydev, 0x17, 0x2138);
329d241d4aaSHeiner Kallweit phy_write(phydev, 0x0e, 0x0260);
330d241d4aaSHeiner Kallweit } else {
331d241d4aaSHeiner Kallweit phy_write(phydev, 0x17, 0x2108);
332d241d4aaSHeiner Kallweit phy_write(phydev, 0x0e, 0x0000);
333d241d4aaSHeiner Kallweit }
334d241d4aaSHeiner Kallweit
335d241d4aaSHeiner Kallweit return 0;
336d241d4aaSHeiner Kallweit }
337d241d4aaSHeiner Kallweit
rtl8211c_config_init(struct phy_device * phydev)338cf87915cSHeiner Kallweit static int rtl8211c_config_init(struct phy_device *phydev)
339cf87915cSHeiner Kallweit {
340cf87915cSHeiner Kallweit /* RTL8211C has an issue when operating in Gigabit slave mode */
34148e4adf9SHeiner Kallweit return phy_set_bits(phydev, MII_CTRL1000,
342cf87915cSHeiner Kallweit CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
343cf87915cSHeiner Kallweit }
344cf87915cSHeiner Kallweit
rtl8211f_config_init(struct phy_device * phydev)3453447cf2eSShengzhou Liu static int rtl8211f_config_init(struct phy_device *phydev)
3463447cf2eSShengzhou Liu {
3470a4355c2SJoakim Zhang struct rtl821x_priv *priv = phydev->priv;
3483aec743dSMartin Blumenstingl struct device *dev = &phydev->mdio.dev;
3491b3047b5SMartin Blumenstingl u16 val_txdly, val_rxdly;
3503aec743dSMartin Blumenstingl int ret;
3513447cf2eSShengzhou Liu
352d90db36aSJoakim Zhang ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1,
353d90db36aSJoakim Zhang RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
354d90db36aSJoakim Zhang priv->phycr1);
355d90db36aSJoakim Zhang if (ret < 0) {
356d90db36aSJoakim Zhang dev_err(dev, "aldps mode configuration failed: %pe\n",
357d90db36aSJoakim Zhang ERR_PTR(ret));
358d90db36aSJoakim Zhang return ret;
359d90db36aSJoakim Zhang }
36066e22932SJisheng Zhang
3611da7756eSSerge Semin switch (phydev->interface) {
3621da7756eSSerge Semin case PHY_INTERFACE_MODE_RGMII:
3631b3047b5SMartin Blumenstingl val_txdly = 0;
3641b3047b5SMartin Blumenstingl val_rxdly = 0;
3651b3047b5SMartin Blumenstingl break;
3661b3047b5SMartin Blumenstingl
3671da7756eSSerge Semin case PHY_INTERFACE_MODE_RGMII_RXID:
3681b3047b5SMartin Blumenstingl val_txdly = 0;
3691b3047b5SMartin Blumenstingl val_rxdly = RTL8211F_RX_DELAY;
3701da7756eSSerge Semin break;
3711b3047b5SMartin Blumenstingl
3721da7756eSSerge Semin case PHY_INTERFACE_MODE_RGMII_TXID:
3731b3047b5SMartin Blumenstingl val_txdly = RTL8211F_TX_DELAY;
3741b3047b5SMartin Blumenstingl val_rxdly = 0;
3751da7756eSSerge Semin break;
3761b3047b5SMartin Blumenstingl
3771b3047b5SMartin Blumenstingl case PHY_INTERFACE_MODE_RGMII_ID:
3781b3047b5SMartin Blumenstingl val_txdly = RTL8211F_TX_DELAY;
3791b3047b5SMartin Blumenstingl val_rxdly = RTL8211F_RX_DELAY;
3801b3047b5SMartin Blumenstingl break;
3811b3047b5SMartin Blumenstingl
3821da7756eSSerge Semin default: /* the rest of the modes imply leaving delay as is. */
3831da7756eSSerge Semin return 0;
3841da7756eSSerge Semin }
385e3230494SMartin Blumenstingl
3863aec743dSMartin Blumenstingl ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
3871b3047b5SMartin Blumenstingl val_txdly);
3883aec743dSMartin Blumenstingl if (ret < 0) {
3893aec743dSMartin Blumenstingl dev_err(dev, "Failed to update the TX delay register\n");
3903aec743dSMartin Blumenstingl return ret;
3913aec743dSMartin Blumenstingl } else if (ret) {
3923aec743dSMartin Blumenstingl dev_dbg(dev,
3933aec743dSMartin Blumenstingl "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
3941b3047b5SMartin Blumenstingl val_txdly ? "Enabling" : "Disabling");
3953aec743dSMartin Blumenstingl } else {
3963aec743dSMartin Blumenstingl dev_dbg(dev,
3973aec743dSMartin Blumenstingl "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
3981b3047b5SMartin Blumenstingl val_txdly ? "enabled" : "disabled");
3991b3047b5SMartin Blumenstingl }
4001b3047b5SMartin Blumenstingl
4011b3047b5SMartin Blumenstingl ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
4021b3047b5SMartin Blumenstingl val_rxdly);
4031b3047b5SMartin Blumenstingl if (ret < 0) {
4041b3047b5SMartin Blumenstingl dev_err(dev, "Failed to update the RX delay register\n");
4051b3047b5SMartin Blumenstingl return ret;
4061b3047b5SMartin Blumenstingl } else if (ret) {
4071b3047b5SMartin Blumenstingl dev_dbg(dev,
4081b3047b5SMartin Blumenstingl "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
4091b3047b5SMartin Blumenstingl val_rxdly ? "Enabling" : "Disabling");
4101b3047b5SMartin Blumenstingl } else {
4111b3047b5SMartin Blumenstingl dev_dbg(dev,
4121b3047b5SMartin Blumenstingl "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
4131b3047b5SMartin Blumenstingl val_rxdly ? "enabled" : "disabled");
4143aec743dSMartin Blumenstingl }
4153aec743dSMartin Blumenstingl
416bb726b75SClark Wang if (priv->has_phycr2) {
4170a4355c2SJoakim Zhang ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
4180a4355c2SJoakim Zhang RTL8211F_CLKOUT_EN, priv->phycr2);
4190a4355c2SJoakim Zhang if (ret < 0) {
4200a4355c2SJoakim Zhang dev_err(dev, "clkout configuration failed: %pe\n",
4210a4355c2SJoakim Zhang ERR_PTR(ret));
4220a4355c2SJoakim Zhang return ret;
4230a4355c2SJoakim Zhang }
4240a4355c2SJoakim Zhang
4250a4355c2SJoakim Zhang return genphy_soft_reset(phydev);
4263447cf2eSShengzhou Liu }
4273447cf2eSShengzhou Liu
428c7818378SSiddharth Vadapalli return 0;
429c7818378SSiddharth Vadapalli }
430c7818378SSiddharth Vadapalli
rtl821x_suspend(struct phy_device * phydev)43159e227e2SDetlev Casanova static int rtl821x_suspend(struct phy_device *phydev)
43259e227e2SDetlev Casanova {
43359e227e2SDetlev Casanova struct rtl821x_priv *priv = phydev->priv;
43459e227e2SDetlev Casanova int ret = 0;
43559e227e2SDetlev Casanova
43659e227e2SDetlev Casanova if (!phydev->wol_enabled) {
43759e227e2SDetlev Casanova ret = genphy_suspend(phydev);
43859e227e2SDetlev Casanova
43959e227e2SDetlev Casanova if (ret)
44059e227e2SDetlev Casanova return ret;
44159e227e2SDetlev Casanova
44259e227e2SDetlev Casanova clk_disable_unprepare(priv->clk);
44359e227e2SDetlev Casanova }
44459e227e2SDetlev Casanova
44559e227e2SDetlev Casanova return ret;
44659e227e2SDetlev Casanova }
44759e227e2SDetlev Casanova
rtl821x_resume(struct phy_device * phydev)4486813cc8cSJoakim Zhang static int rtl821x_resume(struct phy_device *phydev)
4496813cc8cSJoakim Zhang {
45059e227e2SDetlev Casanova struct rtl821x_priv *priv = phydev->priv;
4516813cc8cSJoakim Zhang int ret;
4526813cc8cSJoakim Zhang
45359e227e2SDetlev Casanova if (!phydev->wol_enabled)
45459e227e2SDetlev Casanova clk_prepare_enable(priv->clk);
45559e227e2SDetlev Casanova
4566813cc8cSJoakim Zhang ret = genphy_resume(phydev);
4576813cc8cSJoakim Zhang if (ret < 0)
4586813cc8cSJoakim Zhang return ret;
4596813cc8cSJoakim Zhang
4606813cc8cSJoakim Zhang msleep(20);
4616813cc8cSJoakim Zhang
4626813cc8cSJoakim Zhang return 0;
4636813cc8cSJoakim Zhang }
4646813cc8cSJoakim Zhang
rtl8211e_config_init(struct phy_device * phydev)465f81dadbcSSerge Semin static int rtl8211e_config_init(struct phy_device *phydev)
466f81dadbcSSerge Semin {
467f81dadbcSSerge Semin int ret = 0, oldpage;
468f81dadbcSSerge Semin u16 val;
469f81dadbcSSerge Semin
470f81dadbcSSerge Semin /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
471f81dadbcSSerge Semin switch (phydev->interface) {
472f81dadbcSSerge Semin case PHY_INTERFACE_MODE_RGMII:
473bbc4d71dSWilly Liu val = RTL8211E_CTRL_DELAY | 0;
474f81dadbcSSerge Semin break;
475f81dadbcSSerge Semin case PHY_INTERFACE_MODE_RGMII_ID:
476bbc4d71dSWilly Liu val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
477f81dadbcSSerge Semin break;
478f81dadbcSSerge Semin case PHY_INTERFACE_MODE_RGMII_RXID:
479bbc4d71dSWilly Liu val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
480f81dadbcSSerge Semin break;
481f81dadbcSSerge Semin case PHY_INTERFACE_MODE_RGMII_TXID:
482bbc4d71dSWilly Liu val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
483f81dadbcSSerge Semin break;
484f81dadbcSSerge Semin default: /* the rest of the modes imply leaving delays as is. */
485f81dadbcSSerge Semin return 0;
486f81dadbcSSerge Semin }
487f81dadbcSSerge Semin
488f81dadbcSSerge Semin /* According to a sample driver there is a 0x1c config register on the
489f81dadbcSSerge Semin * 0xa4 extension page (0x7) layout. It can be used to disable/enable
490bbc4d71dSWilly Liu * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
491bbc4d71dSWilly Liu * The configuration register definition:
492bbc4d71dSWilly Liu * 14 = reserved
493bbc4d71dSWilly Liu * 13 = Force Tx RX Delay controlled by bit12 bit11,
494bbc4d71dSWilly Liu * 12 = RX Delay, 11 = TX Delay
495bbc4d71dSWilly Liu * 10:0 = Test && debug settings reserved by realtek
496f81dadbcSSerge Semin */
497f81dadbcSSerge Semin oldpage = phy_select_page(phydev, 0x7);
498f81dadbcSSerge Semin if (oldpage < 0)
499f81dadbcSSerge Semin goto err_restore_page;
500f81dadbcSSerge Semin
501dffe7d2eSKunihiko Hayashi ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
502f81dadbcSSerge Semin if (ret)
503f81dadbcSSerge Semin goto err_restore_page;
504f81dadbcSSerge Semin
505bbc4d71dSWilly Liu ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
506bbc4d71dSWilly Liu | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
507f81dadbcSSerge Semin val);
508f81dadbcSSerge Semin
509f81dadbcSSerge Semin err_restore_page:
510f81dadbcSSerge Semin return phy_restore_page(phydev, oldpage, ret);
511f81dadbcSSerge Semin }
512f81dadbcSSerge Semin
rtl8211b_suspend(struct phy_device * phydev)513049ff57aSHeiner Kallweit static int rtl8211b_suspend(struct phy_device *phydev)
514049ff57aSHeiner Kallweit {
515049ff57aSHeiner Kallweit phy_write(phydev, MII_MMD_DATA, BIT(9));
516049ff57aSHeiner Kallweit
517049ff57aSHeiner Kallweit return genphy_suspend(phydev);
518049ff57aSHeiner Kallweit }
519049ff57aSHeiner Kallweit
rtl8211b_resume(struct phy_device * phydev)520049ff57aSHeiner Kallweit static int rtl8211b_resume(struct phy_device *phydev)
521049ff57aSHeiner Kallweit {
522049ff57aSHeiner Kallweit phy_write(phydev, MII_MMD_DATA, 0);
523049ff57aSHeiner Kallweit
524049ff57aSHeiner Kallweit return genphy_resume(phydev);
525049ff57aSHeiner Kallweit }
526049ff57aSHeiner Kallweit
rtl8366rb_config_init(struct phy_device * phydev)527d8545825SLinus Walleij static int rtl8366rb_config_init(struct phy_device *phydev)
528d8545825SLinus Walleij {
529d8545825SLinus Walleij int ret;
530d8545825SLinus Walleij
531d8545825SLinus Walleij ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
532d8545825SLinus Walleij RTL8366RB_POWER_SAVE_ON);
533d8545825SLinus Walleij if (ret) {
534d8545825SLinus Walleij dev_err(&phydev->mdio.dev,
535d8545825SLinus Walleij "error enabling power management\n");
536d8545825SLinus Walleij }
537d8545825SLinus Walleij
538d8545825SLinus Walleij return ret;
539d8545825SLinus Walleij }
540d8545825SLinus Walleij
541d445dff2SHeiner Kallweit /* get actual speed to cover the downshift case */
rtlgen_get_speed(struct phy_device * phydev)542d445dff2SHeiner Kallweit static int rtlgen_get_speed(struct phy_device *phydev)
543d445dff2SHeiner Kallweit {
544d445dff2SHeiner Kallweit int val;
545d445dff2SHeiner Kallweit
546d445dff2SHeiner Kallweit if (!phydev->link)
547d445dff2SHeiner Kallweit return 0;
548d445dff2SHeiner Kallweit
549d445dff2SHeiner Kallweit val = phy_read_paged(phydev, 0xa43, 0x12);
550d445dff2SHeiner Kallweit if (val < 0)
551d445dff2SHeiner Kallweit return val;
552d445dff2SHeiner Kallweit
553d445dff2SHeiner Kallweit switch (val & RTLGEN_SPEED_MASK) {
554d445dff2SHeiner Kallweit case 0x0000:
555d445dff2SHeiner Kallweit phydev->speed = SPEED_10;
556d445dff2SHeiner Kallweit break;
557d445dff2SHeiner Kallweit case 0x0010:
558d445dff2SHeiner Kallweit phydev->speed = SPEED_100;
559d445dff2SHeiner Kallweit break;
560d445dff2SHeiner Kallweit case 0x0020:
561d445dff2SHeiner Kallweit phydev->speed = SPEED_1000;
562d445dff2SHeiner Kallweit break;
563d445dff2SHeiner Kallweit case 0x0200:
564d445dff2SHeiner Kallweit phydev->speed = SPEED_10000;
565d445dff2SHeiner Kallweit break;
566d445dff2SHeiner Kallweit case 0x0210:
567d445dff2SHeiner Kallweit phydev->speed = SPEED_2500;
568d445dff2SHeiner Kallweit break;
569d445dff2SHeiner Kallweit case 0x0220:
570d445dff2SHeiner Kallweit phydev->speed = SPEED_5000;
571d445dff2SHeiner Kallweit break;
572d445dff2SHeiner Kallweit default:
573d445dff2SHeiner Kallweit break;
574d445dff2SHeiner Kallweit }
575d445dff2SHeiner Kallweit
576d445dff2SHeiner Kallweit return 0;
577d445dff2SHeiner Kallweit }
578d445dff2SHeiner Kallweit
rtlgen_read_status(struct phy_device * phydev)579d445dff2SHeiner Kallweit static int rtlgen_read_status(struct phy_device *phydev)
580d445dff2SHeiner Kallweit {
581d445dff2SHeiner Kallweit int ret;
582d445dff2SHeiner Kallweit
583d445dff2SHeiner Kallweit ret = genphy_read_status(phydev);
584d445dff2SHeiner Kallweit if (ret < 0)
585d445dff2SHeiner Kallweit return ret;
586d445dff2SHeiner Kallweit
587d445dff2SHeiner Kallweit return rtlgen_get_speed(phydev);
588d445dff2SHeiner Kallweit }
589d445dff2SHeiner Kallweit
rtlgen_read_mmd(struct phy_device * phydev,int devnum,u16 regnum)5905b3f1395SHeiner Kallweit static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
5915b3f1395SHeiner Kallweit {
5925b3f1395SHeiner Kallweit int ret;
5935b3f1395SHeiner Kallweit
5945b3f1395SHeiner Kallweit if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
5955b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0xa5c);
5965b3f1395SHeiner Kallweit ret = __phy_read(phydev, 0x12);
5975b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0);
5985b3f1395SHeiner Kallweit } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
5995b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0xa5d);
6005b3f1395SHeiner Kallweit ret = __phy_read(phydev, 0x10);
6015b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0);
6025b3f1395SHeiner Kallweit } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) {
6035b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0xa5d);
6045b3f1395SHeiner Kallweit ret = __phy_read(phydev, 0x11);
6055b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0);
6065b3f1395SHeiner Kallweit } else {
6075b3f1395SHeiner Kallweit ret = -EOPNOTSUPP;
6085b3f1395SHeiner Kallweit }
6095b3f1395SHeiner Kallweit
6105b3f1395SHeiner Kallweit return ret;
6115b3f1395SHeiner Kallweit }
6125b3f1395SHeiner Kallweit
rtlgen_write_mmd(struct phy_device * phydev,int devnum,u16 regnum,u16 val)6135b3f1395SHeiner Kallweit static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
6145b3f1395SHeiner Kallweit u16 val)
6155b3f1395SHeiner Kallweit {
6165b3f1395SHeiner Kallweit int ret;
6175b3f1395SHeiner Kallweit
6185b3f1395SHeiner Kallweit if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
6195b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0xa5d);
6205b3f1395SHeiner Kallweit ret = __phy_write(phydev, 0x10, val);
6215b3f1395SHeiner Kallweit rtl821x_write_page(phydev, 0);
6225b3f1395SHeiner Kallweit } else {
6235b3f1395SHeiner Kallweit ret = -EOPNOTSUPP;
6245b3f1395SHeiner Kallweit }
6255b3f1395SHeiner Kallweit
6265b3f1395SHeiner Kallweit return ret;
6275b3f1395SHeiner Kallweit }
6285b3f1395SHeiner Kallweit
rtl822x_read_mmd(struct phy_device * phydev,int devnum,u16 regnum)6297a333af6SWilly Liu static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
630edde25e5SHeiner Kallweit {
631edde25e5SHeiner Kallweit int ret = rtlgen_read_mmd(phydev, devnum, regnum);
632edde25e5SHeiner Kallweit
633edde25e5SHeiner Kallweit if (ret != -EOPNOTSUPP)
634edde25e5SHeiner Kallweit return ret;
635edde25e5SHeiner Kallweit
636edde25e5SHeiner Kallweit if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) {
637edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0xa6e);
638edde25e5SHeiner Kallweit ret = __phy_read(phydev, 0x16);
639edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0);
640edde25e5SHeiner Kallweit } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
641edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0xa6d);
642edde25e5SHeiner Kallweit ret = __phy_read(phydev, 0x12);
643edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0);
644edde25e5SHeiner Kallweit } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) {
645edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0xa6d);
646edde25e5SHeiner Kallweit ret = __phy_read(phydev, 0x10);
647edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0);
648edde25e5SHeiner Kallweit }
649edde25e5SHeiner Kallweit
650edde25e5SHeiner Kallweit return ret;
651edde25e5SHeiner Kallweit }
652edde25e5SHeiner Kallweit
rtl822x_write_mmd(struct phy_device * phydev,int devnum,u16 regnum,u16 val)6537a333af6SWilly Liu static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
654edde25e5SHeiner Kallweit u16 val)
655edde25e5SHeiner Kallweit {
656edde25e5SHeiner Kallweit int ret = rtlgen_write_mmd(phydev, devnum, regnum, val);
657edde25e5SHeiner Kallweit
658edde25e5SHeiner Kallweit if (ret != -EOPNOTSUPP)
659edde25e5SHeiner Kallweit return ret;
660edde25e5SHeiner Kallweit
661edde25e5SHeiner Kallweit if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
662edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0xa6d);
663edde25e5SHeiner Kallweit ret = __phy_write(phydev, 0x12, val);
664edde25e5SHeiner Kallweit rtl821x_write_page(phydev, 0);
665edde25e5SHeiner Kallweit }
666edde25e5SHeiner Kallweit
667edde25e5SHeiner Kallweit return ret;
668edde25e5SHeiner Kallweit }
669edde25e5SHeiner Kallweit
rtl822x_get_features(struct phy_device * phydev)6707a333af6SWilly Liu static int rtl822x_get_features(struct phy_device *phydev)
671087f5b87SHeiner Kallweit {
6725181b473SHeiner Kallweit int val;
6735181b473SHeiner Kallweit
6745181b473SHeiner Kallweit val = phy_read_paged(phydev, 0xa61, 0x13);
6755181b473SHeiner Kallweit if (val < 0)
6765181b473SHeiner Kallweit return val;
6775181b473SHeiner Kallweit
6785181b473SHeiner Kallweit linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
6795181b473SHeiner Kallweit phydev->supported, val & RTL_SUPPORTS_2500FULL);
6805181b473SHeiner Kallweit linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
6815181b473SHeiner Kallweit phydev->supported, val & RTL_SUPPORTS_5000FULL);
6825181b473SHeiner Kallweit linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
6835181b473SHeiner Kallweit phydev->supported, val & RTL_SUPPORTS_10000FULL);
684087f5b87SHeiner Kallweit
685087f5b87SHeiner Kallweit return genphy_read_abilities(phydev);
686087f5b87SHeiner Kallweit }
687087f5b87SHeiner Kallweit
rtl822x_config_aneg(struct phy_device * phydev)6887a333af6SWilly Liu static int rtl822x_config_aneg(struct phy_device *phydev)
689087f5b87SHeiner Kallweit {
690087f5b87SHeiner Kallweit int ret = 0;
691087f5b87SHeiner Kallweit
692087f5b87SHeiner Kallweit if (phydev->autoneg == AUTONEG_ENABLE) {
693087f5b87SHeiner Kallweit u16 adv2500 = 0;
694087f5b87SHeiner Kallweit
695087f5b87SHeiner Kallweit if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
696087f5b87SHeiner Kallweit phydev->advertising))
697087f5b87SHeiner Kallweit adv2500 = RTL_ADV_2500FULL;
698087f5b87SHeiner Kallweit
699087f5b87SHeiner Kallweit ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
700087f5b87SHeiner Kallweit RTL_ADV_2500FULL, adv2500);
701087f5b87SHeiner Kallweit if (ret < 0)
702087f5b87SHeiner Kallweit return ret;
703087f5b87SHeiner Kallweit }
704087f5b87SHeiner Kallweit
705087f5b87SHeiner Kallweit return __genphy_config_aneg(phydev, ret);
706087f5b87SHeiner Kallweit }
707087f5b87SHeiner Kallweit
rtl822x_read_status(struct phy_device * phydev)7087a333af6SWilly Liu static int rtl822x_read_status(struct phy_device *phydev)
709087f5b87SHeiner Kallweit {
710d445dff2SHeiner Kallweit int ret;
711d445dff2SHeiner Kallweit
712087f5b87SHeiner Kallweit if (phydev->autoneg == AUTONEG_ENABLE) {
713087f5b87SHeiner Kallweit int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
714087f5b87SHeiner Kallweit
715087f5b87SHeiner Kallweit if (lpadv < 0)
716087f5b87SHeiner Kallweit return lpadv;
717087f5b87SHeiner Kallweit
718087f5b87SHeiner Kallweit linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
719087f5b87SHeiner Kallweit phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL);
720087f5b87SHeiner Kallweit linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
721087f5b87SHeiner Kallweit phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL);
722087f5b87SHeiner Kallweit linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
723087f5b87SHeiner Kallweit phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
724087f5b87SHeiner Kallweit }
725087f5b87SHeiner Kallweit
726d445dff2SHeiner Kallweit ret = genphy_read_status(phydev);
727d445dff2SHeiner Kallweit if (ret < 0)
728d445dff2SHeiner Kallweit return ret;
729d445dff2SHeiner Kallweit
730d445dff2SHeiner Kallweit return rtlgen_get_speed(phydev);
731087f5b87SHeiner Kallweit }
732087f5b87SHeiner Kallweit
rtlgen_supports_2_5gbps(struct phy_device * phydev)7335181b473SHeiner Kallweit static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
7345181b473SHeiner Kallweit {
7355181b473SHeiner Kallweit int val;
7365181b473SHeiner Kallweit
7375181b473SHeiner Kallweit phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61);
7385181b473SHeiner Kallweit val = phy_read(phydev, 0x13);
7395181b473SHeiner Kallweit phy_write(phydev, RTL821x_PAGE_SELECT, 0);
7405181b473SHeiner Kallweit
7415181b473SHeiner Kallweit return val >= 0 && val & RTL_SUPPORTS_2500FULL;
7425181b473SHeiner Kallweit }
7435181b473SHeiner Kallweit
rtlgen_match_phy_device(struct phy_device * phydev)7445181b473SHeiner Kallweit static int rtlgen_match_phy_device(struct phy_device *phydev)
7455181b473SHeiner Kallweit {
7465181b473SHeiner Kallweit return phydev->phy_id == RTL_GENERIC_PHYID &&
7475181b473SHeiner Kallweit !rtlgen_supports_2_5gbps(phydev);
7485181b473SHeiner Kallweit }
7495181b473SHeiner Kallweit
rtl8226_match_phy_device(struct phy_device * phydev)7507a333af6SWilly Liu static int rtl8226_match_phy_device(struct phy_device *phydev)
7515181b473SHeiner Kallweit {
7525181b473SHeiner Kallweit return phydev->phy_id == RTL_GENERIC_PHYID &&
7535181b473SHeiner Kallweit rtlgen_supports_2_5gbps(phydev);
7545181b473SHeiner Kallweit }
7555181b473SHeiner Kallweit
rtlgen_resume(struct phy_device * phydev)756fee698d6SHeiner Kallweit static int rtlgen_resume(struct phy_device *phydev)
757fee698d6SHeiner Kallweit {
758fee698d6SHeiner Kallweit int ret = genphy_resume(phydev);
759fee698d6SHeiner Kallweit
760fee698d6SHeiner Kallweit /* Internal PHY's from RTL8168h up may not be instantly ready */
761fee698d6SHeiner Kallweit msleep(20);
762fee698d6SHeiner Kallweit
763fee698d6SHeiner Kallweit return ret;
764fee698d6SHeiner Kallweit }
765fee698d6SHeiner Kallweit
rtl9000a_config_init(struct phy_device * phydev)7662d8983f9SYuusuke Ashizuka static int rtl9000a_config_init(struct phy_device *phydev)
7672d8983f9SYuusuke Ashizuka {
7682d8983f9SYuusuke Ashizuka phydev->autoneg = AUTONEG_DISABLE;
7692d8983f9SYuusuke Ashizuka phydev->speed = SPEED_100;
7702d8983f9SYuusuke Ashizuka phydev->duplex = DUPLEX_FULL;
7712d8983f9SYuusuke Ashizuka
7722d8983f9SYuusuke Ashizuka return 0;
7732d8983f9SYuusuke Ashizuka }
7742d8983f9SYuusuke Ashizuka
rtl9000a_config_aneg(struct phy_device * phydev)7752d8983f9SYuusuke Ashizuka static int rtl9000a_config_aneg(struct phy_device *phydev)
7762d8983f9SYuusuke Ashizuka {
7772d8983f9SYuusuke Ashizuka int ret;
7782d8983f9SYuusuke Ashizuka u16 ctl = 0;
7792d8983f9SYuusuke Ashizuka
7802d8983f9SYuusuke Ashizuka switch (phydev->master_slave_set) {
7812d8983f9SYuusuke Ashizuka case MASTER_SLAVE_CFG_MASTER_FORCE:
7822d8983f9SYuusuke Ashizuka ctl |= CTL1000_AS_MASTER;
7832d8983f9SYuusuke Ashizuka break;
7842d8983f9SYuusuke Ashizuka case MASTER_SLAVE_CFG_SLAVE_FORCE:
7852d8983f9SYuusuke Ashizuka break;
7862d8983f9SYuusuke Ashizuka case MASTER_SLAVE_CFG_UNKNOWN:
7872d8983f9SYuusuke Ashizuka case MASTER_SLAVE_CFG_UNSUPPORTED:
7882d8983f9SYuusuke Ashizuka return 0;
7892d8983f9SYuusuke Ashizuka default:
7902d8983f9SYuusuke Ashizuka phydev_warn(phydev, "Unsupported Master/Slave mode\n");
7912d8983f9SYuusuke Ashizuka return -EOPNOTSUPP;
7922d8983f9SYuusuke Ashizuka }
7932d8983f9SYuusuke Ashizuka
7942d8983f9SYuusuke Ashizuka ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl);
7952d8983f9SYuusuke Ashizuka if (ret == 1)
7962d8983f9SYuusuke Ashizuka ret = genphy_soft_reset(phydev);
7972d8983f9SYuusuke Ashizuka
7982d8983f9SYuusuke Ashizuka return ret;
7992d8983f9SYuusuke Ashizuka }
8002d8983f9SYuusuke Ashizuka
rtl9000a_read_status(struct phy_device * phydev)8012d8983f9SYuusuke Ashizuka static int rtl9000a_read_status(struct phy_device *phydev)
8022d8983f9SYuusuke Ashizuka {
8032d8983f9SYuusuke Ashizuka int ret;
8042d8983f9SYuusuke Ashizuka
8052d8983f9SYuusuke Ashizuka phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
8062d8983f9SYuusuke Ashizuka phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
8072d8983f9SYuusuke Ashizuka
8082d8983f9SYuusuke Ashizuka ret = genphy_update_link(phydev);
8092d8983f9SYuusuke Ashizuka if (ret)
8102d8983f9SYuusuke Ashizuka return ret;
8112d8983f9SYuusuke Ashizuka
8122d8983f9SYuusuke Ashizuka ret = phy_read(phydev, MII_CTRL1000);
8132d8983f9SYuusuke Ashizuka if (ret < 0)
8142d8983f9SYuusuke Ashizuka return ret;
8152d8983f9SYuusuke Ashizuka if (ret & CTL1000_AS_MASTER)
8162d8983f9SYuusuke Ashizuka phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
8172d8983f9SYuusuke Ashizuka else
8182d8983f9SYuusuke Ashizuka phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
8192d8983f9SYuusuke Ashizuka
8202d8983f9SYuusuke Ashizuka ret = phy_read(phydev, MII_STAT1000);
8212d8983f9SYuusuke Ashizuka if (ret < 0)
8222d8983f9SYuusuke Ashizuka return ret;
8232d8983f9SYuusuke Ashizuka if (ret & LPA_1000MSRES)
8242d8983f9SYuusuke Ashizuka phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
8252d8983f9SYuusuke Ashizuka else
8262d8983f9SYuusuke Ashizuka phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
8272d8983f9SYuusuke Ashizuka
8282d8983f9SYuusuke Ashizuka return 0;
8292d8983f9SYuusuke Ashizuka }
8302d8983f9SYuusuke Ashizuka
rtl9000a_ack_interrupt(struct phy_device * phydev)8312d8983f9SYuusuke Ashizuka static int rtl9000a_ack_interrupt(struct phy_device *phydev)
8322d8983f9SYuusuke Ashizuka {
8332d8983f9SYuusuke Ashizuka int err;
8342d8983f9SYuusuke Ashizuka
8352d8983f9SYuusuke Ashizuka err = phy_read(phydev, RTL8211F_INSR);
8362d8983f9SYuusuke Ashizuka
8372d8983f9SYuusuke Ashizuka return (err < 0) ? err : 0;
8382d8983f9SYuusuke Ashizuka }
8392d8983f9SYuusuke Ashizuka
rtl9000a_config_intr(struct phy_device * phydev)8402d8983f9SYuusuke Ashizuka static int rtl9000a_config_intr(struct phy_device *phydev)
8412d8983f9SYuusuke Ashizuka {
8422d8983f9SYuusuke Ashizuka u16 val;
8432d8983f9SYuusuke Ashizuka int err;
8442d8983f9SYuusuke Ashizuka
8452d8983f9SYuusuke Ashizuka if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
8462d8983f9SYuusuke Ashizuka err = rtl9000a_ack_interrupt(phydev);
8472d8983f9SYuusuke Ashizuka if (err)
8482d8983f9SYuusuke Ashizuka return err;
8492d8983f9SYuusuke Ashizuka
8502d8983f9SYuusuke Ashizuka val = (u16)~RTL9000A_GINMR_LINK_STATUS;
8512d8983f9SYuusuke Ashizuka err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
8522d8983f9SYuusuke Ashizuka } else {
8532d8983f9SYuusuke Ashizuka val = ~0;
8542d8983f9SYuusuke Ashizuka err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
8552d8983f9SYuusuke Ashizuka if (err)
8562d8983f9SYuusuke Ashizuka return err;
8572d8983f9SYuusuke Ashizuka
8582d8983f9SYuusuke Ashizuka err = rtl9000a_ack_interrupt(phydev);
8592d8983f9SYuusuke Ashizuka }
8602d8983f9SYuusuke Ashizuka
8612d8983f9SYuusuke Ashizuka return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
8622d8983f9SYuusuke Ashizuka }
8632d8983f9SYuusuke Ashizuka
rtl9000a_handle_interrupt(struct phy_device * phydev)8642d8983f9SYuusuke Ashizuka static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev)
8652d8983f9SYuusuke Ashizuka {
8662d8983f9SYuusuke Ashizuka int irq_status;
8672d8983f9SYuusuke Ashizuka
8682d8983f9SYuusuke Ashizuka irq_status = phy_read(phydev, RTL8211F_INSR);
8692d8983f9SYuusuke Ashizuka if (irq_status < 0) {
8702d8983f9SYuusuke Ashizuka phy_error(phydev);
8712d8983f9SYuusuke Ashizuka return IRQ_NONE;
8722d8983f9SYuusuke Ashizuka }
8732d8983f9SYuusuke Ashizuka
8742d8983f9SYuusuke Ashizuka if (!(irq_status & RTL8211F_INER_LINK_STATUS))
8752d8983f9SYuusuke Ashizuka return IRQ_NONE;
8762d8983f9SYuusuke Ashizuka
8772d8983f9SYuusuke Ashizuka phy_trigger_machine(phydev);
8782d8983f9SYuusuke Ashizuka
8792d8983f9SYuusuke Ashizuka return IRQ_HANDLED;
8802d8983f9SYuusuke Ashizuka }
8812d8983f9SYuusuke Ashizuka
88271b9c4a8SJongsung Kim static struct phy_driver realtek_drvs[] = {
88371b9c4a8SJongsung Kim {
884ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x00008201),
88512959667SJonas Jensen .name = "RTL8201CP Ethernet",
886f3037c5aSHeiner Kallweit .read_page = rtl821x_read_page,
887f3037c5aSHeiner Kallweit .write_page = rtl821x_write_page,
88871b9c4a8SJongsung Kim }, {
889ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc816),
8900432e833SHolger Hoffstätte .name = "RTL8201F Fast Ethernet",
891513588ddSJassi Brar .config_intr = &rtl8201_config_intr,
89203829163SIoana Ciornei .handle_interrupt = rtl8201_handle_interrupt,
893513588ddSJassi Brar .suspend = genphy_suspend,
894513588ddSJassi Brar .resume = genphy_resume,
895d98c8ccdSHeiner Kallweit .read_page = rtl821x_read_page,
896d98c8ccdSHeiner Kallweit .write_page = rtl821x_write_page,
897513588ddSJassi Brar }, {
898f3284e01SHeiner Kallweit PHY_ID_MATCH_MODEL(0x001cc880),
899f3284e01SHeiner Kallweit .name = "RTL8208 Fast Ethernet",
900f3284e01SHeiner Kallweit .read_mmd = genphy_read_mmd_unsupported,
901f3284e01SHeiner Kallweit .write_mmd = genphy_write_mmd_unsupported,
902f3284e01SHeiner Kallweit .suspend = genphy_suspend,
903f3284e01SHeiner Kallweit .resume = genphy_resume,
904f3284e01SHeiner Kallweit .read_page = rtl821x_read_page,
905f3284e01SHeiner Kallweit .write_page = rtl821x_write_page,
906f3284e01SHeiner Kallweit }, {
907ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc910),
908d241d4aaSHeiner Kallweit .name = "RTL8211 Gigabit Ethernet",
909d241d4aaSHeiner Kallweit .config_aneg = rtl8211_config_aneg,
910d241d4aaSHeiner Kallweit .read_mmd = &genphy_read_mmd_unsupported,
911d241d4aaSHeiner Kallweit .write_mmd = &genphy_write_mmd_unsupported,
912daf3ddbeSHeiner Kallweit .read_page = rtl821x_read_page,
913daf3ddbeSHeiner Kallweit .write_page = rtl821x_write_page,
914d241d4aaSHeiner Kallweit }, {
915ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc912),
916ef3d9049SGiuseppe CAVALLARO .name = "RTL8211B Gigabit Ethernet",
917ef3d9049SGiuseppe CAVALLARO .config_intr = &rtl8211b_config_intr,
91803829163SIoana Ciornei .handle_interrupt = rtl821x_handle_interrupt,
9190231b1a0SKevin Hao .read_mmd = &genphy_read_mmd_unsupported,
9200231b1a0SKevin Hao .write_mmd = &genphy_write_mmd_unsupported,
921049ff57aSHeiner Kallweit .suspend = rtl8211b_suspend,
922049ff57aSHeiner Kallweit .resume = rtl8211b_resume,
923daf3ddbeSHeiner Kallweit .read_page = rtl821x_read_page,
924daf3ddbeSHeiner Kallweit .write_page = rtl821x_write_page,
92571b9c4a8SJongsung Kim }, {
926ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc913),
927cf87915cSHeiner Kallweit .name = "RTL8211C Gigabit Ethernet",
928cf87915cSHeiner Kallweit .config_init = rtl8211c_config_init,
929cf87915cSHeiner Kallweit .read_mmd = &genphy_read_mmd_unsupported,
930cf87915cSHeiner Kallweit .write_mmd = &genphy_write_mmd_unsupported,
931daf3ddbeSHeiner Kallweit .read_page = rtl821x_read_page,
932daf3ddbeSHeiner Kallweit .write_page = rtl821x_write_page,
933cf87915cSHeiner Kallweit }, {
934ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc914),
9350024f892SShaohui Xie .name = "RTL8211DN Gigabit Ethernet",
9360024f892SShaohui Xie .config_intr = rtl8211e_config_intr,
93703829163SIoana Ciornei .handle_interrupt = rtl821x_handle_interrupt,
9380024f892SShaohui Xie .suspend = genphy_suspend,
9390024f892SShaohui Xie .resume = genphy_resume,
940daf3ddbeSHeiner Kallweit .read_page = rtl821x_read_page,
941daf3ddbeSHeiner Kallweit .write_page = rtl821x_write_page,
9420024f892SShaohui Xie }, {
943ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc915),
944ef3d9049SGiuseppe CAVALLARO .name = "RTL8211E Gigabit Ethernet",
945f81dadbcSSerge Semin .config_init = &rtl8211e_config_init,
946ef3d9049SGiuseppe CAVALLARO .config_intr = &rtl8211e_config_intr,
94703829163SIoana Ciornei .handle_interrupt = rtl821x_handle_interrupt,
948ef3d9049SGiuseppe CAVALLARO .suspend = genphy_suspend,
949ef3d9049SGiuseppe CAVALLARO .resume = genphy_resume,
950daf3ddbeSHeiner Kallweit .read_page = rtl821x_read_page,
951daf3ddbeSHeiner Kallweit .write_page = rtl821x_write_page,
9523447cf2eSShengzhou Liu }, {
953ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc916),
9543447cf2eSShengzhou Liu .name = "RTL8211F Gigabit Ethernet",
9550a4355c2SJoakim Zhang .probe = rtl821x_probe,
9563447cf2eSShengzhou Liu .config_init = &rtl8211f_config_init,
9574826d2c4SAntonio Borneo .read_status = rtlgen_read_status,
9583447cf2eSShengzhou Liu .config_intr = &rtl8211f_config_intr,
95903829163SIoana Ciornei .handle_interrupt = rtl8211f_handle_interrupt,
96059e227e2SDetlev Casanova .suspend = rtl821x_suspend,
9616813cc8cSJoakim Zhang .resume = rtl821x_resume,
962d98c8ccdSHeiner Kallweit .read_page = rtl821x_read_page,
963d98c8ccdSHeiner Kallweit .write_page = rtl821x_write_page,
96459e227e2SDetlev Casanova .flags = PHY_ALWAYS_CALL_SUSPEND,
965d8545825SLinus Walleij }, {
966bb726b75SClark Wang PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID),
967bb726b75SClark Wang .name = "RTL8211F-VD Gigabit Ethernet",
968bb726b75SClark Wang .probe = rtl821x_probe,
969bb726b75SClark Wang .config_init = &rtl8211f_config_init,
970bb726b75SClark Wang .read_status = rtlgen_read_status,
971bb726b75SClark Wang .config_intr = &rtl8211f_config_intr,
972bb726b75SClark Wang .handle_interrupt = rtl8211f_handle_interrupt,
97359e227e2SDetlev Casanova .suspend = rtl821x_suspend,
974bb726b75SClark Wang .resume = rtl821x_resume,
975bb726b75SClark Wang .read_page = rtl821x_read_page,
976bb726b75SClark Wang .write_page = rtl821x_write_page,
97759e227e2SDetlev Casanova .flags = PHY_ALWAYS_CALL_SUSPEND,
978bb726b75SClark Wang }, {
9795181b473SHeiner Kallweit .name = "Generic FE-GE Realtek PHY",
9805181b473SHeiner Kallweit .match_phy_device = rtlgen_match_phy_device,
981d445dff2SHeiner Kallweit .read_status = rtlgen_read_status,
982f66ebd14SHeiner Kallweit .suspend = genphy_suspend,
983fee698d6SHeiner Kallweit .resume = rtlgen_resume,
984f66ebd14SHeiner Kallweit .read_page = rtl821x_read_page,
985f66ebd14SHeiner Kallweit .write_page = rtl821x_write_page,
9865b3f1395SHeiner Kallweit .read_mmd = rtlgen_read_mmd,
9875b3f1395SHeiner Kallweit .write_mmd = rtlgen_write_mmd,
988f66ebd14SHeiner Kallweit }, {
9897a333af6SWilly Liu .name = "RTL8226 2.5Gbps PHY",
9907a333af6SWilly Liu .match_phy_device = rtl8226_match_phy_device,
9917a333af6SWilly Liu .get_features = rtl822x_get_features,
9927a333af6SWilly Liu .config_aneg = rtl822x_config_aneg,
9937a333af6SWilly Liu .read_status = rtl822x_read_status,
994087f5b87SHeiner Kallweit .suspend = genphy_suspend,
995fee698d6SHeiner Kallweit .resume = rtlgen_resume,
996087f5b87SHeiner Kallweit .read_page = rtl821x_read_page,
997087f5b87SHeiner Kallweit .write_page = rtl821x_write_page,
9987a333af6SWilly Liu .read_mmd = rtl822x_read_mmd,
9997a333af6SWilly Liu .write_mmd = rtl822x_write_mmd,
1000087f5b87SHeiner Kallweit }, {
1001b3ba9ae8SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc840),
10027a333af6SWilly Liu .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
10037a333af6SWilly Liu .get_features = rtl822x_get_features,
10047a333af6SWilly Liu .config_aneg = rtl822x_config_aneg,
10057a333af6SWilly Liu .read_status = rtl822x_read_status,
1006b3ba9ae8SHeiner Kallweit .suspend = genphy_suspend,
1007b3ba9ae8SHeiner Kallweit .resume = rtlgen_resume,
1008b3ba9ae8SHeiner Kallweit .read_page = rtl821x_read_page,
1009b3ba9ae8SHeiner Kallweit .write_page = rtl821x_write_page,
10107a333af6SWilly Liu .read_mmd = rtl822x_read_mmd,
10117a333af6SWilly Liu .write_mmd = rtl822x_write_mmd,
1012b3ba9ae8SHeiner Kallweit }, {
101374d155beSWilly Liu PHY_ID_MATCH_EXACT(0x001cc838),
101474d155beSWilly Liu .name = "RTL8226-CG 2.5Gbps PHY",
101574d155beSWilly Liu .get_features = rtl822x_get_features,
101674d155beSWilly Liu .config_aneg = rtl822x_config_aneg,
101774d155beSWilly Liu .read_status = rtl822x_read_status,
101874d155beSWilly Liu .suspend = genphy_suspend,
101974d155beSWilly Liu .resume = rtlgen_resume,
102074d155beSWilly Liu .read_page = rtl821x_read_page,
102174d155beSWilly Liu .write_page = rtl821x_write_page,
102274d155beSWilly Liu }, {
102374d155beSWilly Liu PHY_ID_MATCH_EXACT(0x001cc848),
102474d155beSWilly Liu .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
102574d155beSWilly Liu .get_features = rtl822x_get_features,
102674d155beSWilly Liu .config_aneg = rtl822x_config_aneg,
102774d155beSWilly Liu .read_status = rtl822x_read_status,
102874d155beSWilly Liu .suspend = genphy_suspend,
102974d155beSWilly Liu .resume = rtlgen_resume,
103074d155beSWilly Liu .read_page = rtl821x_read_page,
103174d155beSWilly Liu .write_page = rtl821x_write_page,
103274d155beSWilly Liu }, {
103374d155beSWilly Liu PHY_ID_MATCH_EXACT(0x001cc849),
103474d155beSWilly Liu .name = "RTL8221B-VB-CG 2.5Gbps PHY",
103574d155beSWilly Liu .get_features = rtl822x_get_features,
103674d155beSWilly Liu .config_aneg = rtl822x_config_aneg,
103774d155beSWilly Liu .read_status = rtl822x_read_status,
103874d155beSWilly Liu .suspend = genphy_suspend,
103974d155beSWilly Liu .resume = rtlgen_resume,
104074d155beSWilly Liu .read_page = rtl821x_read_page,
104174d155beSWilly Liu .write_page = rtl821x_write_page,
104274d155beSWilly Liu }, {
104374d155beSWilly Liu PHY_ID_MATCH_EXACT(0x001cc84a),
104474d155beSWilly Liu .name = "RTL8221B-VM-CG 2.5Gbps PHY",
104574d155beSWilly Liu .get_features = rtl822x_get_features,
104674d155beSWilly Liu .config_aneg = rtl822x_config_aneg,
104774d155beSWilly Liu .read_status = rtl822x_read_status,
104874d155beSWilly Liu .suspend = genphy_suspend,
104974d155beSWilly Liu .resume = rtlgen_resume,
105074d155beSWilly Liu .read_page = rtl821x_read_page,
105174d155beSWilly Liu .write_page = rtl821x_write_page,
105274d155beSWilly Liu }, {
1053ca494936SHeiner Kallweit PHY_ID_MATCH_EXACT(0x001cc961),
1054d8545825SLinus Walleij .name = "RTL8366RB Gigabit Ethernet",
1055d8545825SLinus Walleij .config_init = &rtl8366rb_config_init,
10564c8e0459SLinus Walleij /* These interrupts are handled by the irq controller
10574c8e0459SLinus Walleij * embedded inside the RTL8366RB, they get unmasked when the
10584c8e0459SLinus Walleij * irq is requested and ACKed by reading the status register,
10594c8e0459SLinus Walleij * which is done by the irqchip code.
10604c8e0459SLinus Walleij */
10614c8e0459SLinus Walleij .config_intr = genphy_no_config_intr,
106203829163SIoana Ciornei .handle_interrupt = genphy_handle_interrupt_no_ack,
1063d8545825SLinus Walleij .suspend = genphy_suspend,
1064d8545825SLinus Walleij .resume = genphy_resume,
10652d8983f9SYuusuke Ashizuka }, {
10662d8983f9SYuusuke Ashizuka PHY_ID_MATCH_EXACT(0x001ccb00),
10672d8983f9SYuusuke Ashizuka .name = "RTL9000AA_RTL9000AN Ethernet",
10682d8983f9SYuusuke Ashizuka .features = PHY_BASIC_T1_FEATURES,
10692d8983f9SYuusuke Ashizuka .config_init = rtl9000a_config_init,
10702d8983f9SYuusuke Ashizuka .config_aneg = rtl9000a_config_aneg,
10712d8983f9SYuusuke Ashizuka .read_status = rtl9000a_read_status,
10722d8983f9SYuusuke Ashizuka .config_intr = rtl9000a_config_intr,
10732d8983f9SYuusuke Ashizuka .handle_interrupt = rtl9000a_handle_interrupt,
10742d8983f9SYuusuke Ashizuka .suspend = genphy_suspend,
10752d8983f9SYuusuke Ashizuka .resume = genphy_resume,
10762d8983f9SYuusuke Ashizuka .read_page = rtl821x_read_page,
10772d8983f9SYuusuke Ashizuka .write_page = rtl821x_write_page,
10782ca2969aSAlvin Šipraga }, {
10792ca2969aSAlvin Šipraga PHY_ID_MATCH_EXACT(0x001cc942),
10802ca2969aSAlvin Šipraga .name = "RTL8365MB-VC Gigabit Ethernet",
10812ca2969aSAlvin Šipraga /* Interrupt handling analogous to RTL8366RB */
10822ca2969aSAlvin Šipraga .config_intr = genphy_no_config_intr,
10832ca2969aSAlvin Šipraga .handle_interrupt = genphy_handle_interrupt_no_ack,
10842ca2969aSAlvin Šipraga .suspend = genphy_suspend,
10852ca2969aSAlvin Šipraga .resume = genphy_resume,
1086*b45cbfa2SMark Mentovai }, {
1087*b45cbfa2SMark Mentovai PHY_ID_MATCH_EXACT(0x001cc960),
1088*b45cbfa2SMark Mentovai .name = "RTL8366S Gigabit Ethernet",
1089*b45cbfa2SMark Mentovai .suspend = genphy_suspend,
1090*b45cbfa2SMark Mentovai .resume = genphy_resume,
1091*b45cbfa2SMark Mentovai .read_mmd = genphy_read_mmd_unsupported,
1092*b45cbfa2SMark Mentovai .write_mmd = genphy_write_mmd_unsupported,
109371b9c4a8SJongsung Kim },
1094097c2aa8SJohnson Leung };
1095097c2aa8SJohnson Leung
109650fd7150SJohan Hovold module_phy_driver(realtek_drvs);
10974e4f10f6SDavid Woodhouse
10983b73e842SHeiner Kallweit static const struct mdio_device_id __maybe_unused realtek_tbl[] = {
1099ca494936SHeiner Kallweit { PHY_ID_MATCH_VENDOR(0x001cc800) },
11004e4f10f6SDavid Woodhouse { }
11014e4f10f6SDavid Woodhouse };
11024e4f10f6SDavid Woodhouse
11034e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, realtek_tbl);
1104