1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /* drivers/net/phy/realtek.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Driver for Realtek PHYs
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Author: Johnson Leung <r58129@freescale.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Copyright (c) 2004 Freescale Semiconductor, Inc.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun #include <linux/bitops.h>
11*4882a593Smuzhiyun #include <linux/phy.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/delay.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #define RTL821x_PHYSR 0x11
16*4882a593Smuzhiyun #define RTL821x_PHYSR_DUPLEX BIT(13)
17*4882a593Smuzhiyun #define RTL821x_PHYSR_SPEED GENMASK(15, 14)
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define RTL821x_INER 0x12
20*4882a593Smuzhiyun #define RTL8211B_INER_INIT 0x6400
21*4882a593Smuzhiyun #define RTL8211E_INER_LINK_STATUS BIT(10)
22*4882a593Smuzhiyun #define RTL8211F_INER_LINK_STATUS BIT(4)
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define RTL821x_INSR 0x13
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define RTL821x_EXT_PAGE_SELECT 0x1e
27*4882a593Smuzhiyun #define RTL821x_PAGE_SELECT 0x1f
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define RTL8211F_PHYCR1 0x18
30*4882a593Smuzhiyun #define RTL8211F_INSR 0x1d
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define RTL8211F_TX_DELAY BIT(8)
33*4882a593Smuzhiyun #define RTL8211F_RX_DELAY BIT(3)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define RTL8211F_ALDPS_PLL_OFF BIT(1)
36*4882a593Smuzhiyun #define RTL8211F_ALDPS_ENABLE BIT(2)
37*4882a593Smuzhiyun #define RTL8211F_ALDPS_XTAL_OFF BIT(12)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define RTL8211E_CTRL_DELAY BIT(13)
40*4882a593Smuzhiyun #define RTL8211E_TX_DELAY BIT(12)
41*4882a593Smuzhiyun #define RTL8211E_RX_DELAY BIT(11)
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define RTL8201F_ISR 0x1e
44*4882a593Smuzhiyun #define RTL8201F_IER 0x13
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define RTL8366RB_POWER_SAVE 0x15
47*4882a593Smuzhiyun #define RTL8366RB_POWER_SAVE_ON BIT(12)
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #define RTL_SUPPORTS_5000FULL BIT(14)
50*4882a593Smuzhiyun #define RTL_SUPPORTS_2500FULL BIT(13)
51*4882a593Smuzhiyun #define RTL_SUPPORTS_10000FULL BIT(0)
52*4882a593Smuzhiyun #define RTL_ADV_2500FULL BIT(7)
53*4882a593Smuzhiyun #define RTL_LPADV_10000FULL BIT(11)
54*4882a593Smuzhiyun #define RTL_LPADV_5000FULL BIT(6)
55*4882a593Smuzhiyun #define RTL_LPADV_2500FULL BIT(5)
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #define RTLGEN_SPEED_MASK 0x0630
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #define RTL_GENERIC_PHYID 0x001cc800
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun MODULE_DESCRIPTION("Realtek PHY driver");
62*4882a593Smuzhiyun MODULE_AUTHOR("Johnson Leung");
63*4882a593Smuzhiyun MODULE_LICENSE("GPL");
64*4882a593Smuzhiyun
rtl821x_read_page(struct phy_device * phydev)65*4882a593Smuzhiyun static int rtl821x_read_page(struct phy_device *phydev)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun return __phy_read(phydev, RTL821x_PAGE_SELECT);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
rtl821x_write_page(struct phy_device * phydev,int page)70*4882a593Smuzhiyun static int rtl821x_write_page(struct phy_device *phydev, int page)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
rtl8201_ack_interrupt(struct phy_device * phydev)75*4882a593Smuzhiyun static int rtl8201_ack_interrupt(struct phy_device *phydev)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun int err;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun err = phy_read(phydev, RTL8201F_ISR);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun return (err < 0) ? err : 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
rtl821x_ack_interrupt(struct phy_device * phydev)84*4882a593Smuzhiyun static int rtl821x_ack_interrupt(struct phy_device *phydev)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun int err;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun err = phy_read(phydev, RTL821x_INSR);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun return (err < 0) ? err : 0;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
rtl8211f_ack_interrupt(struct phy_device * phydev)93*4882a593Smuzhiyun static int rtl8211f_ack_interrupt(struct phy_device *phydev)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun int err;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun return (err < 0) ? err : 0;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
rtl8201_config_intr(struct phy_device * phydev)102*4882a593Smuzhiyun static int rtl8201_config_intr(struct phy_device *phydev)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun u16 val;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
107*4882a593Smuzhiyun val = BIT(13) | BIT(12) | BIT(11);
108*4882a593Smuzhiyun else
109*4882a593Smuzhiyun val = 0;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun return phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
rtl8211b_config_intr(struct phy_device * phydev)114*4882a593Smuzhiyun static int rtl8211b_config_intr(struct phy_device *phydev)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun int err;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
119*4882a593Smuzhiyun err = phy_write(phydev, RTL821x_INER,
120*4882a593Smuzhiyun RTL8211B_INER_INIT);
121*4882a593Smuzhiyun else
122*4882a593Smuzhiyun err = phy_write(phydev, RTL821x_INER, 0);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun return err;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
rtl8211e_config_intr(struct phy_device * phydev)127*4882a593Smuzhiyun static int rtl8211e_config_intr(struct phy_device *phydev)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun int err;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
132*4882a593Smuzhiyun err = phy_write(phydev, RTL821x_INER,
133*4882a593Smuzhiyun RTL8211E_INER_LINK_STATUS);
134*4882a593Smuzhiyun else
135*4882a593Smuzhiyun err = phy_write(phydev, RTL821x_INER, 0);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun return err;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
rtl8211f_config_intr(struct phy_device * phydev)140*4882a593Smuzhiyun static int rtl8211f_config_intr(struct phy_device *phydev)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun u16 val;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
145*4882a593Smuzhiyun val = RTL8211F_INER_LINK_STATUS;
146*4882a593Smuzhiyun else
147*4882a593Smuzhiyun val = 0;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
rtl8211_config_aneg(struct phy_device * phydev)152*4882a593Smuzhiyun static int rtl8211_config_aneg(struct phy_device *phydev)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun int ret;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun ret = genphy_config_aneg(phydev);
157*4882a593Smuzhiyun if (ret < 0)
158*4882a593Smuzhiyun return ret;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* Quirk was copied from vendor driver. Unfortunately it includes no
161*4882a593Smuzhiyun * description of the magic numbers.
162*4882a593Smuzhiyun */
163*4882a593Smuzhiyun if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
164*4882a593Smuzhiyun phy_write(phydev, 0x17, 0x2138);
165*4882a593Smuzhiyun phy_write(phydev, 0x0e, 0x0260);
166*4882a593Smuzhiyun } else {
167*4882a593Smuzhiyun phy_write(phydev, 0x17, 0x2108);
168*4882a593Smuzhiyun phy_write(phydev, 0x0e, 0x0000);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
rtl8211c_config_init(struct phy_device * phydev)174*4882a593Smuzhiyun static int rtl8211c_config_init(struct phy_device *phydev)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun /* RTL8211C has an issue when operating in Gigabit slave mode */
177*4882a593Smuzhiyun return phy_set_bits(phydev, MII_CTRL1000,
178*4882a593Smuzhiyun CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
rtl8211f_config_init(struct phy_device * phydev)181*4882a593Smuzhiyun static int rtl8211f_config_init(struct phy_device *phydev)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun struct device *dev = &phydev->mdio.dev;
184*4882a593Smuzhiyun u16 val_txdly, val_rxdly;
185*4882a593Smuzhiyun u16 val;
186*4882a593Smuzhiyun int ret;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun val = RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_XTAL_OFF;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun phy_write(phydev, 0x1f, 0xd04);
191*4882a593Smuzhiyun phy_write(phydev, 0x10, 0x6d68);
192*4882a593Smuzhiyun phy_write(phydev, 0x11, 0x600b);
193*4882a593Smuzhiyun phy_write(phydev, 0x1f, 0xa42);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, val, val);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun switch (phydev->interface) {
198*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII:
199*4882a593Smuzhiyun val_txdly = 0;
200*4882a593Smuzhiyun val_rxdly = 0;
201*4882a593Smuzhiyun break;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_RXID:
204*4882a593Smuzhiyun val_txdly = 0;
205*4882a593Smuzhiyun val_rxdly = RTL8211F_RX_DELAY;
206*4882a593Smuzhiyun break;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_TXID:
209*4882a593Smuzhiyun val_txdly = RTL8211F_TX_DELAY;
210*4882a593Smuzhiyun val_rxdly = 0;
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_ID:
214*4882a593Smuzhiyun val_txdly = RTL8211F_TX_DELAY;
215*4882a593Smuzhiyun val_rxdly = RTL8211F_RX_DELAY;
216*4882a593Smuzhiyun break;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun default: /* the rest of the modes imply leaving delay as is. */
219*4882a593Smuzhiyun return 0;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
223*4882a593Smuzhiyun val_txdly);
224*4882a593Smuzhiyun if (ret < 0) {
225*4882a593Smuzhiyun dev_err(dev, "Failed to update the TX delay register\n");
226*4882a593Smuzhiyun return ret;
227*4882a593Smuzhiyun } else if (ret) {
228*4882a593Smuzhiyun dev_dbg(dev,
229*4882a593Smuzhiyun "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
230*4882a593Smuzhiyun val_txdly ? "Enabling" : "Disabling");
231*4882a593Smuzhiyun } else {
232*4882a593Smuzhiyun dev_dbg(dev,
233*4882a593Smuzhiyun "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
234*4882a593Smuzhiyun val_txdly ? "enabled" : "disabled");
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
238*4882a593Smuzhiyun val_rxdly);
239*4882a593Smuzhiyun if (ret < 0) {
240*4882a593Smuzhiyun dev_err(dev, "Failed to update the RX delay register\n");
241*4882a593Smuzhiyun return ret;
242*4882a593Smuzhiyun } else if (ret) {
243*4882a593Smuzhiyun dev_dbg(dev,
244*4882a593Smuzhiyun "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
245*4882a593Smuzhiyun val_rxdly ? "Enabling" : "Disabling");
246*4882a593Smuzhiyun } else {
247*4882a593Smuzhiyun dev_dbg(dev,
248*4882a593Smuzhiyun "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
249*4882a593Smuzhiyun val_rxdly ? "enabled" : "disabled");
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun return 0;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
rtl821x_resume(struct phy_device * phydev)255*4882a593Smuzhiyun static int rtl821x_resume(struct phy_device *phydev)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun int ret;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ret = genphy_resume(phydev);
260*4882a593Smuzhiyun if (ret < 0)
261*4882a593Smuzhiyun return ret;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun msleep(20);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun return 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
rtl8211e_config_init(struct phy_device * phydev)268*4882a593Smuzhiyun static int rtl8211e_config_init(struct phy_device *phydev)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun int ret = 0, oldpage;
271*4882a593Smuzhiyun u16 val;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
274*4882a593Smuzhiyun switch (phydev->interface) {
275*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII:
276*4882a593Smuzhiyun val = RTL8211E_CTRL_DELAY | 0;
277*4882a593Smuzhiyun break;
278*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_ID:
279*4882a593Smuzhiyun val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
280*4882a593Smuzhiyun break;
281*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_RXID:
282*4882a593Smuzhiyun val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
283*4882a593Smuzhiyun break;
284*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_TXID:
285*4882a593Smuzhiyun val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
286*4882a593Smuzhiyun break;
287*4882a593Smuzhiyun default: /* the rest of the modes imply leaving delays as is. */
288*4882a593Smuzhiyun return 0;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* According to a sample driver there is a 0x1c config register on the
292*4882a593Smuzhiyun * 0xa4 extension page (0x7) layout. It can be used to disable/enable
293*4882a593Smuzhiyun * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
294*4882a593Smuzhiyun * The configuration register definition:
295*4882a593Smuzhiyun * 14 = reserved
296*4882a593Smuzhiyun * 13 = Force Tx RX Delay controlled by bit12 bit11,
297*4882a593Smuzhiyun * 12 = RX Delay, 11 = TX Delay
298*4882a593Smuzhiyun * 10:0 = Test && debug settings reserved by realtek
299*4882a593Smuzhiyun */
300*4882a593Smuzhiyun oldpage = phy_select_page(phydev, 0x7);
301*4882a593Smuzhiyun if (oldpage < 0)
302*4882a593Smuzhiyun goto err_restore_page;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
305*4882a593Smuzhiyun if (ret)
306*4882a593Smuzhiyun goto err_restore_page;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
309*4882a593Smuzhiyun | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
310*4882a593Smuzhiyun val);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun err_restore_page:
313*4882a593Smuzhiyun return phy_restore_page(phydev, oldpage, ret);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
rtl8211b_suspend(struct phy_device * phydev)316*4882a593Smuzhiyun static int rtl8211b_suspend(struct phy_device *phydev)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun phy_write(phydev, MII_MMD_DATA, BIT(9));
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun return genphy_suspend(phydev);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
rtl8211b_resume(struct phy_device * phydev)323*4882a593Smuzhiyun static int rtl8211b_resume(struct phy_device *phydev)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun phy_write(phydev, MII_MMD_DATA, 0);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun return genphy_resume(phydev);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
rtl8366rb_config_init(struct phy_device * phydev)330*4882a593Smuzhiyun static int rtl8366rb_config_init(struct phy_device *phydev)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun int ret;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
335*4882a593Smuzhiyun RTL8366RB_POWER_SAVE_ON);
336*4882a593Smuzhiyun if (ret) {
337*4882a593Smuzhiyun dev_err(&phydev->mdio.dev,
338*4882a593Smuzhiyun "error enabling power management\n");
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun return ret;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun /* get actual speed to cover the downshift case */
rtlgen_get_speed(struct phy_device * phydev)345*4882a593Smuzhiyun static int rtlgen_get_speed(struct phy_device *phydev)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun int val;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun if (!phydev->link)
350*4882a593Smuzhiyun return 0;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun val = phy_read_paged(phydev, 0xa43, 0x12);
353*4882a593Smuzhiyun if (val < 0)
354*4882a593Smuzhiyun return val;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun switch (val & RTLGEN_SPEED_MASK) {
357*4882a593Smuzhiyun case 0x0000:
358*4882a593Smuzhiyun phydev->speed = SPEED_10;
359*4882a593Smuzhiyun break;
360*4882a593Smuzhiyun case 0x0010:
361*4882a593Smuzhiyun phydev->speed = SPEED_100;
362*4882a593Smuzhiyun break;
363*4882a593Smuzhiyun case 0x0020:
364*4882a593Smuzhiyun phydev->speed = SPEED_1000;
365*4882a593Smuzhiyun break;
366*4882a593Smuzhiyun case 0x0200:
367*4882a593Smuzhiyun phydev->speed = SPEED_10000;
368*4882a593Smuzhiyun break;
369*4882a593Smuzhiyun case 0x0210:
370*4882a593Smuzhiyun phydev->speed = SPEED_2500;
371*4882a593Smuzhiyun break;
372*4882a593Smuzhiyun case 0x0220:
373*4882a593Smuzhiyun phydev->speed = SPEED_5000;
374*4882a593Smuzhiyun break;
375*4882a593Smuzhiyun default:
376*4882a593Smuzhiyun break;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
rtlgen_read_status(struct phy_device * phydev)382*4882a593Smuzhiyun static int rtlgen_read_status(struct phy_device *phydev)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun int ret;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun ret = genphy_read_status(phydev);
387*4882a593Smuzhiyun if (ret < 0)
388*4882a593Smuzhiyun return ret;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun return rtlgen_get_speed(phydev);
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
rtlgen_read_mmd(struct phy_device * phydev,int devnum,u16 regnum)393*4882a593Smuzhiyun static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun int ret;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
398*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa5c);
399*4882a593Smuzhiyun ret = __phy_read(phydev, 0x12);
400*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
401*4882a593Smuzhiyun } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
402*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa5d);
403*4882a593Smuzhiyun ret = __phy_read(phydev, 0x10);
404*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
405*4882a593Smuzhiyun } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) {
406*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa5d);
407*4882a593Smuzhiyun ret = __phy_read(phydev, 0x11);
408*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
409*4882a593Smuzhiyun } else {
410*4882a593Smuzhiyun ret = -EOPNOTSUPP;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun return ret;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
rtlgen_write_mmd(struct phy_device * phydev,int devnum,u16 regnum,u16 val)416*4882a593Smuzhiyun static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
417*4882a593Smuzhiyun u16 val)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun int ret;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
422*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa5d);
423*4882a593Smuzhiyun ret = __phy_write(phydev, 0x10, val);
424*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
425*4882a593Smuzhiyun } else {
426*4882a593Smuzhiyun ret = -EOPNOTSUPP;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun return ret;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
rtl822x_read_mmd(struct phy_device * phydev,int devnum,u16 regnum)432*4882a593Smuzhiyun static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun int ret = rtlgen_read_mmd(phydev, devnum, regnum);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (ret != -EOPNOTSUPP)
437*4882a593Smuzhiyun return ret;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) {
440*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa6e);
441*4882a593Smuzhiyun ret = __phy_read(phydev, 0x16);
442*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
443*4882a593Smuzhiyun } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
444*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa6d);
445*4882a593Smuzhiyun ret = __phy_read(phydev, 0x12);
446*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
447*4882a593Smuzhiyun } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) {
448*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa6d);
449*4882a593Smuzhiyun ret = __phy_read(phydev, 0x10);
450*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun return ret;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
rtl822x_write_mmd(struct phy_device * phydev,int devnum,u16 regnum,u16 val)456*4882a593Smuzhiyun static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
457*4882a593Smuzhiyun u16 val)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun int ret = rtlgen_write_mmd(phydev, devnum, regnum, val);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun if (ret != -EOPNOTSUPP)
462*4882a593Smuzhiyun return ret;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
465*4882a593Smuzhiyun rtl821x_write_page(phydev, 0xa6d);
466*4882a593Smuzhiyun ret = __phy_write(phydev, 0x12, val);
467*4882a593Smuzhiyun rtl821x_write_page(phydev, 0);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun return ret;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
rtl822x_get_features(struct phy_device * phydev)473*4882a593Smuzhiyun static int rtl822x_get_features(struct phy_device *phydev)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun int val;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun val = phy_read_paged(phydev, 0xa61, 0x13);
478*4882a593Smuzhiyun if (val < 0)
479*4882a593Smuzhiyun return val;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
482*4882a593Smuzhiyun phydev->supported, val & RTL_SUPPORTS_2500FULL);
483*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
484*4882a593Smuzhiyun phydev->supported, val & RTL_SUPPORTS_5000FULL);
485*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
486*4882a593Smuzhiyun phydev->supported, val & RTL_SUPPORTS_10000FULL);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun return genphy_read_abilities(phydev);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
rtl822x_config_aneg(struct phy_device * phydev)491*4882a593Smuzhiyun static int rtl822x_config_aneg(struct phy_device *phydev)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun int ret = 0;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (phydev->autoneg == AUTONEG_ENABLE) {
496*4882a593Smuzhiyun u16 adv2500 = 0;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
499*4882a593Smuzhiyun phydev->advertising))
500*4882a593Smuzhiyun adv2500 = RTL_ADV_2500FULL;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
503*4882a593Smuzhiyun RTL_ADV_2500FULL, adv2500);
504*4882a593Smuzhiyun if (ret < 0)
505*4882a593Smuzhiyun return ret;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun return __genphy_config_aneg(phydev, ret);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
rtl822x_read_status(struct phy_device * phydev)511*4882a593Smuzhiyun static int rtl822x_read_status(struct phy_device *phydev)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun int ret;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun if (phydev->autoneg == AUTONEG_ENABLE) {
516*4882a593Smuzhiyun int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (lpadv < 0)
519*4882a593Smuzhiyun return lpadv;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
522*4882a593Smuzhiyun phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL);
523*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
524*4882a593Smuzhiyun phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL);
525*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
526*4882a593Smuzhiyun phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun ret = genphy_read_status(phydev);
530*4882a593Smuzhiyun if (ret < 0)
531*4882a593Smuzhiyun return ret;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun return rtlgen_get_speed(phydev);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun
rtlgen_supports_2_5gbps(struct phy_device * phydev)536*4882a593Smuzhiyun static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun int val;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61);
541*4882a593Smuzhiyun val = phy_read(phydev, 0x13);
542*4882a593Smuzhiyun phy_write(phydev, RTL821x_PAGE_SELECT, 0);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun return val >= 0 && val & RTL_SUPPORTS_2500FULL;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
rtlgen_match_phy_device(struct phy_device * phydev)547*4882a593Smuzhiyun static int rtlgen_match_phy_device(struct phy_device *phydev)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun return phydev->phy_id == RTL_GENERIC_PHYID &&
550*4882a593Smuzhiyun !rtlgen_supports_2_5gbps(phydev);
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
rtl8226_match_phy_device(struct phy_device * phydev)553*4882a593Smuzhiyun static int rtl8226_match_phy_device(struct phy_device *phydev)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun return phydev->phy_id == RTL_GENERIC_PHYID &&
556*4882a593Smuzhiyun rtlgen_supports_2_5gbps(phydev);
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
rtlgen_resume(struct phy_device * phydev)559*4882a593Smuzhiyun static int rtlgen_resume(struct phy_device *phydev)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun int ret = genphy_resume(phydev);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun /* Internal PHY's from RTL8168h up may not be instantly ready */
564*4882a593Smuzhiyun msleep(20);
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun return ret;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
rtl9010a_config_init(struct phy_device * phydev)569*4882a593Smuzhiyun static int rtl9010a_config_init(struct phy_device *phydev)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun phydev->autoneg = AUTONEG_DISABLE;
572*4882a593Smuzhiyun phydev->speed = SPEED_1000;
573*4882a593Smuzhiyun phydev->duplex = DUPLEX_FULL;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun return 0;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
rtl9010a_config_aneg(struct phy_device * phydev)578*4882a593Smuzhiyun static int rtl9010a_config_aneg(struct phy_device *phydev)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun return 0;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
rtl9010a_get_features(struct phy_device * phydev)583*4882a593Smuzhiyun static int rtl9010a_get_features(struct phy_device *phydev)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
586*4882a593Smuzhiyun phydev->supported);
587*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
588*4882a593Smuzhiyun phydev->supported);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun return 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
rtl9010a_read_status(struct phy_device * phydev)593*4882a593Smuzhiyun static int rtl9010a_read_status(struct phy_device *phydev)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun int ret;
596*4882a593Smuzhiyun u16 val;
597*4882a593Smuzhiyun int link_status, local_status, remote_status;
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun ret = genphy_read_status(phydev);
600*4882a593Smuzhiyun if (ret < 0)
601*4882a593Smuzhiyun return ret;
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun val = phy_read(phydev, 0x01);
604*4882a593Smuzhiyun val = phy_read(phydev, 0x01);
605*4882a593Smuzhiyun link_status = val & 0x0004 ? 1 : 0;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun if (phydev->speed == SPEED_1000) {
608*4882a593Smuzhiyun val = phy_read(phydev, 0x0a);
609*4882a593Smuzhiyun local_status = val & 0x2000 ? 1 : 0;
610*4882a593Smuzhiyun remote_status = val & 0x1000 ? 1 : 0;
611*4882a593Smuzhiyun } else {
612*4882a593Smuzhiyun phy_write(phydev, 0x1f, 0xa64);
613*4882a593Smuzhiyun val = phy_read(phydev, 0x17);
614*4882a593Smuzhiyun local_status = val & 0x0004 ? 1 : 0;
615*4882a593Smuzhiyun remote_status = val & 0x0400 ? 1 : 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun if (link_status && local_status && remote_status)
619*4882a593Smuzhiyun phydev->link = 1;
620*4882a593Smuzhiyun else
621*4882a593Smuzhiyun phydev->link = 0;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun return 0;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun static struct phy_driver realtek_drvs[] = {
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x00008201),
629*4882a593Smuzhiyun .name = "RTL8201CP Ethernet",
630*4882a593Smuzhiyun .read_page = rtl821x_read_page,
631*4882a593Smuzhiyun .write_page = rtl821x_write_page,
632*4882a593Smuzhiyun }, {
633*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc816),
634*4882a593Smuzhiyun .name = "RTL8201F Fast Ethernet",
635*4882a593Smuzhiyun .ack_interrupt = &rtl8201_ack_interrupt,
636*4882a593Smuzhiyun .config_intr = &rtl8201_config_intr,
637*4882a593Smuzhiyun .suspend = genphy_suspend,
638*4882a593Smuzhiyun .resume = genphy_resume,
639*4882a593Smuzhiyun .read_page = rtl821x_read_page,
640*4882a593Smuzhiyun .write_page = rtl821x_write_page,
641*4882a593Smuzhiyun }, {
642*4882a593Smuzhiyun PHY_ID_MATCH_MODEL(0x001cc880),
643*4882a593Smuzhiyun .name = "RTL8208 Fast Ethernet",
644*4882a593Smuzhiyun .read_mmd = genphy_read_mmd_unsupported,
645*4882a593Smuzhiyun .write_mmd = genphy_write_mmd_unsupported,
646*4882a593Smuzhiyun .suspend = genphy_suspend,
647*4882a593Smuzhiyun .resume = genphy_resume,
648*4882a593Smuzhiyun .read_page = rtl821x_read_page,
649*4882a593Smuzhiyun .write_page = rtl821x_write_page,
650*4882a593Smuzhiyun }, {
651*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc910),
652*4882a593Smuzhiyun .name = "RTL8211 Gigabit Ethernet",
653*4882a593Smuzhiyun .config_aneg = rtl8211_config_aneg,
654*4882a593Smuzhiyun .read_mmd = &genphy_read_mmd_unsupported,
655*4882a593Smuzhiyun .write_mmd = &genphy_write_mmd_unsupported,
656*4882a593Smuzhiyun .read_page = rtl821x_read_page,
657*4882a593Smuzhiyun .write_page = rtl821x_write_page,
658*4882a593Smuzhiyun }, {
659*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc912),
660*4882a593Smuzhiyun .name = "RTL8211B Gigabit Ethernet",
661*4882a593Smuzhiyun .ack_interrupt = &rtl821x_ack_interrupt,
662*4882a593Smuzhiyun .config_intr = &rtl8211b_config_intr,
663*4882a593Smuzhiyun .read_mmd = &genphy_read_mmd_unsupported,
664*4882a593Smuzhiyun .write_mmd = &genphy_write_mmd_unsupported,
665*4882a593Smuzhiyun .suspend = rtl8211b_suspend,
666*4882a593Smuzhiyun .resume = rtl8211b_resume,
667*4882a593Smuzhiyun .read_page = rtl821x_read_page,
668*4882a593Smuzhiyun .write_page = rtl821x_write_page,
669*4882a593Smuzhiyun }, {
670*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc913),
671*4882a593Smuzhiyun .name = "RTL8211C Gigabit Ethernet",
672*4882a593Smuzhiyun .config_init = rtl8211c_config_init,
673*4882a593Smuzhiyun .read_mmd = &genphy_read_mmd_unsupported,
674*4882a593Smuzhiyun .write_mmd = &genphy_write_mmd_unsupported,
675*4882a593Smuzhiyun .read_page = rtl821x_read_page,
676*4882a593Smuzhiyun .write_page = rtl821x_write_page,
677*4882a593Smuzhiyun }, {
678*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc914),
679*4882a593Smuzhiyun .name = "RTL8211DN Gigabit Ethernet",
680*4882a593Smuzhiyun .ack_interrupt = rtl821x_ack_interrupt,
681*4882a593Smuzhiyun .config_intr = rtl8211e_config_intr,
682*4882a593Smuzhiyun .suspend = genphy_suspend,
683*4882a593Smuzhiyun .resume = genphy_resume,
684*4882a593Smuzhiyun .read_page = rtl821x_read_page,
685*4882a593Smuzhiyun .write_page = rtl821x_write_page,
686*4882a593Smuzhiyun }, {
687*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc915),
688*4882a593Smuzhiyun .name = "RTL8211E Gigabit Ethernet",
689*4882a593Smuzhiyun .config_init = &rtl8211e_config_init,
690*4882a593Smuzhiyun .ack_interrupt = &rtl821x_ack_interrupt,
691*4882a593Smuzhiyun .config_intr = &rtl8211e_config_intr,
692*4882a593Smuzhiyun .suspend = genphy_suspend,
693*4882a593Smuzhiyun .resume = genphy_resume,
694*4882a593Smuzhiyun .read_page = rtl821x_read_page,
695*4882a593Smuzhiyun .write_page = rtl821x_write_page,
696*4882a593Smuzhiyun }, {
697*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc916),
698*4882a593Smuzhiyun .name = "RTL8211F Gigabit Ethernet",
699*4882a593Smuzhiyun .config_init = &rtl8211f_config_init,
700*4882a593Smuzhiyun .read_status = rtlgen_read_status,
701*4882a593Smuzhiyun .ack_interrupt = &rtl8211f_ack_interrupt,
702*4882a593Smuzhiyun .config_intr = &rtl8211f_config_intr,
703*4882a593Smuzhiyun .suspend = genphy_suspend,
704*4882a593Smuzhiyun .resume = rtl821x_resume,
705*4882a593Smuzhiyun .read_page = rtl821x_read_page,
706*4882a593Smuzhiyun .write_page = rtl821x_write_page,
707*4882a593Smuzhiyun }, {
708*4882a593Smuzhiyun .name = "Generic FE-GE Realtek PHY",
709*4882a593Smuzhiyun .match_phy_device = rtlgen_match_phy_device,
710*4882a593Smuzhiyun .read_status = rtlgen_read_status,
711*4882a593Smuzhiyun .suspend = genphy_suspend,
712*4882a593Smuzhiyun .resume = rtlgen_resume,
713*4882a593Smuzhiyun .read_page = rtl821x_read_page,
714*4882a593Smuzhiyun .write_page = rtl821x_write_page,
715*4882a593Smuzhiyun .read_mmd = rtlgen_read_mmd,
716*4882a593Smuzhiyun .write_mmd = rtlgen_write_mmd,
717*4882a593Smuzhiyun }, {
718*4882a593Smuzhiyun .name = "RTL8226 2.5Gbps PHY",
719*4882a593Smuzhiyun .match_phy_device = rtl8226_match_phy_device,
720*4882a593Smuzhiyun .get_features = rtl822x_get_features,
721*4882a593Smuzhiyun .config_aneg = rtl822x_config_aneg,
722*4882a593Smuzhiyun .read_status = rtl822x_read_status,
723*4882a593Smuzhiyun .suspend = genphy_suspend,
724*4882a593Smuzhiyun .resume = rtlgen_resume,
725*4882a593Smuzhiyun .read_page = rtl821x_read_page,
726*4882a593Smuzhiyun .write_page = rtl821x_write_page,
727*4882a593Smuzhiyun .read_mmd = rtl822x_read_mmd,
728*4882a593Smuzhiyun .write_mmd = rtl822x_write_mmd,
729*4882a593Smuzhiyun }, {
730*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc840),
731*4882a593Smuzhiyun .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
732*4882a593Smuzhiyun .get_features = rtl822x_get_features,
733*4882a593Smuzhiyun .config_aneg = rtl822x_config_aneg,
734*4882a593Smuzhiyun .read_status = rtl822x_read_status,
735*4882a593Smuzhiyun .suspend = genphy_suspend,
736*4882a593Smuzhiyun .resume = rtlgen_resume,
737*4882a593Smuzhiyun .read_page = rtl821x_read_page,
738*4882a593Smuzhiyun .write_page = rtl821x_write_page,
739*4882a593Smuzhiyun .read_mmd = rtl822x_read_mmd,
740*4882a593Smuzhiyun .write_mmd = rtl822x_write_mmd,
741*4882a593Smuzhiyun }, {
742*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001cc961),
743*4882a593Smuzhiyun .name = "RTL8366RB Gigabit Ethernet",
744*4882a593Smuzhiyun .config_init = &rtl8366rb_config_init,
745*4882a593Smuzhiyun /* These interrupts are handled by the irq controller
746*4882a593Smuzhiyun * embedded inside the RTL8366RB, they get unmasked when the
747*4882a593Smuzhiyun * irq is requested and ACKed by reading the status register,
748*4882a593Smuzhiyun * which is done by the irqchip code.
749*4882a593Smuzhiyun */
750*4882a593Smuzhiyun .ack_interrupt = genphy_no_ack_interrupt,
751*4882a593Smuzhiyun .config_intr = genphy_no_config_intr,
752*4882a593Smuzhiyun .suspend = genphy_suspend,
753*4882a593Smuzhiyun .resume = genphy_resume,
754*4882a593Smuzhiyun }, {
755*4882a593Smuzhiyun PHY_ID_MATCH_EXACT(0x001ccb30),
756*4882a593Smuzhiyun .name = "RTL9010AA_RTL9010AR_RTL9010AS Ethernet",
757*4882a593Smuzhiyun .config_init = rtl9010a_config_init,
758*4882a593Smuzhiyun .config_aneg = rtl9010a_config_aneg,
759*4882a593Smuzhiyun .read_status = rtl9010a_read_status,
760*4882a593Smuzhiyun .get_features = rtl9010a_get_features,
761*4882a593Smuzhiyun .suspend = genphy_suspend,
762*4882a593Smuzhiyun .resume = genphy_resume,
763*4882a593Smuzhiyun .read_page = rtl821x_read_page,
764*4882a593Smuzhiyun .write_page = rtl821x_write_page,
765*4882a593Smuzhiyun },
766*4882a593Smuzhiyun };
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun module_phy_driver(realtek_drvs);
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun static const struct mdio_device_id __maybe_unused realtek_tbl[] = {
771*4882a593Smuzhiyun { PHY_ID_MATCH_VENDOR(0x001cc800) },
772*4882a593Smuzhiyun { PHY_ID_MATCH_VENDOR(0x001ccb30) },
773*4882a593Smuzhiyun { }
774*4882a593Smuzhiyun };
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun MODULE_DEVICE_TABLE(mdio, realtek_tbl);
777