blob: 2645b263518c94a5a8a4184627acc04cc1c6cc08 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001/*
2 * drivers/net/phy/realtek.c
3 *
4 * Driver for Realtek PHYs
5 *
6 * Author: Johnson Leung <r58129@freescale.com>
7 *
8 * Copyright (c) 2004 Freescale Semiconductor, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16#include <linux/bitops.h>
17#include <linux/phy.h>
18#include <linux/module.h>
19
20#define RTL821x_PHYSR 0x11
21#define RTL821x_PHYSR_DUPLEX BIT(13)
22#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
23
24#define RTL821x_INER 0x12
25#define RTL8211B_INER_INIT 0x6400
26#define RTL8211E_INER_LINK_STATUS BIT(10)
27#define RTL8211F_INER_LINK_STATUS BIT(4)
28
29#define RTL821x_INSR 0x13
30
31#define RTL821x_PAGE_SELECT 0x1f
32
33#define RTL8211F_INSR 0x1d
34
35#define RTL8211F_TX_DELAY BIT(8)
36
37#define RTL8201F_ISR 0x1e
38#define RTL8201F_IER 0x13
39
40#define RTL8366RB_POWER_SAVE 0x15
41#define RTL8366RB_POWER_SAVE_ON BIT(12)
42
43MODULE_DESCRIPTION("Realtek PHY driver");
44MODULE_AUTHOR("Johnson Leung");
45MODULE_LICENSE("GPL");
46
47static int rtl821x_read_page(struct phy_device *phydev)
48{
49 return __phy_read(phydev, RTL821x_PAGE_SELECT);
50}
51
52static int rtl821x_write_page(struct phy_device *phydev, int page)
53{
54 return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
55}
56
57static int rtl8201_ack_interrupt(struct phy_device *phydev)
58{
59 int err;
60
61 err = phy_read(phydev, RTL8201F_ISR);
62
63 return (err < 0) ? err : 0;
64}
65
66static int rtl821x_ack_interrupt(struct phy_device *phydev)
67{
68 int err;
69
70 err = phy_read(phydev, RTL821x_INSR);
71
72 return (err < 0) ? err : 0;
73}
74
75static int rtl8211f_ack_interrupt(struct phy_device *phydev)
76{
77 int err;
78
79 err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
80
81 return (err < 0) ? err : 0;
82}
83
84static int rtl8201_config_intr(struct phy_device *phydev)
85{
86 u16 val;
87
88 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
89 val = BIT(13) | BIT(12) | BIT(11);
90 else
91 val = 0;
92
93 return phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
94}
95
96static int rtl8211b_config_intr(struct phy_device *phydev)
97{
98 int err;
99
100 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
101 err = phy_write(phydev, RTL821x_INER,
102 RTL8211B_INER_INIT);
103 else
104 err = phy_write(phydev, RTL821x_INER, 0);
105
106 return err;
107}
108
109static int rtl8211e_config_intr(struct phy_device *phydev)
110{
111 int err;
112
113 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
114 err = phy_write(phydev, RTL821x_INER,
115 RTL8211E_INER_LINK_STATUS);
116 else
117 err = phy_write(phydev, RTL821x_INER, 0);
118
119 return err;
120}
121
122static int rtl8211f_config_intr(struct phy_device *phydev)
123{
124 u16 val;
125
126 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
127 val = RTL8211F_INER_LINK_STATUS;
128 else
129 val = 0;
130
131 return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
132}
133
134static int rtl8211_config_aneg(struct phy_device *phydev)
135{
136 int ret;
137
138 ret = genphy_config_aneg(phydev);
139 if (ret < 0)
140 return ret;
141
142 /* Quirk was copied from vendor driver. Unfortunately it includes no
143 * description of the magic numbers.
144 */
145 if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
146 phy_write(phydev, 0x17, 0x2138);
147 phy_write(phydev, 0x0e, 0x0260);
148 } else {
149 phy_write(phydev, 0x17, 0x2108);
150 phy_write(phydev, 0x0e, 0x0000);
151 }
152
153 return 0;
154}
155
156static int rtl8211c_config_init(struct phy_device *phydev)
157{
158 /* RTL8211C has an issue when operating in Gigabit slave mode */
159 phy_set_bits(phydev, MII_CTRL1000,
160 CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
161
162 return genphy_config_init(phydev);
163}
164
165static int rtl8211f_config_init(struct phy_device *phydev)
166{
167 int ret;
168 u16 val = 0;
169
170 ret = genphy_config_init(phydev);
171 if (ret < 0)
172 return ret;
173
174 /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
175 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
176 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
177 val = RTL8211F_TX_DELAY;
178
179 phy_write_paged(phydev, 0x0A43, 0x1B, 0xdc84);/*modify by chencheng*/
180 phy_write_paged(phydev, 0x0A43, 0x1C,0x7180);/*modify by chencheng*/
181
182 return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val);
183}
184
185static int rtl8211b_suspend(struct phy_device *phydev)
186{
187 phy_write(phydev, MII_MMD_DATA, BIT(9));
188
189 return genphy_suspend(phydev);
190}
191
192static int rtl8211b_resume(struct phy_device *phydev)
193{
194 phy_write(phydev, MII_MMD_DATA, 0);
195
196 return genphy_resume(phydev);
197}
198
199static int rtl8366rb_config_init(struct phy_device *phydev)
200{
201 int ret;
202
203 ret = genphy_config_init(phydev);
204 if (ret < 0)
205 return ret;
206
207 ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
208 RTL8366RB_POWER_SAVE_ON);
209 if (ret) {
210 dev_err(&phydev->mdio.dev,
211 "error enabling power management\n");
212 }
213
214 return ret;
215}
216
217static struct phy_driver realtek_drvs[] = {
218 {
219 .phy_id = 0x00008201,
220 .name = "RTL8201CP Ethernet",
221 .phy_id_mask = 0x0000ffff,
222 .features = PHY_BASIC_FEATURES,
223 .flags = PHY_HAS_INTERRUPT,
224 }, {
225 .phy_id = 0x001cc816,
226 .name = "RTL8201F Fast Ethernet",
227 .phy_id_mask = 0x001fffff,
228 .features = PHY_BASIC_FEATURES,
229 .flags = PHY_HAS_INTERRUPT,
230 .ack_interrupt = &rtl8201_ack_interrupt,
231 .config_intr = &rtl8201_config_intr,
232 .suspend = genphy_suspend,
233 .resume = genphy_resume,
234 .read_page = rtl821x_read_page,
235 .write_page = rtl821x_write_page,
236 }, {
237 .phy_id = 0x001cc910,
238 .name = "RTL8211 Gigabit Ethernet",
239 .phy_id_mask = 0x001fffff,
240 .features = PHY_GBIT_FEATURES,
241 .config_aneg = rtl8211_config_aneg,
242 .read_mmd = &genphy_read_mmd_unsupported,
243 .write_mmd = &genphy_write_mmd_unsupported,
244 }, {
245 .phy_id = 0x001cc912,
246 .name = "RTL8211B Gigabit Ethernet",
247 .phy_id_mask = 0x001fffff,
248 .features = PHY_GBIT_FEATURES,
249 .flags = PHY_HAS_INTERRUPT,
250 .ack_interrupt = &rtl821x_ack_interrupt,
251 .config_intr = &rtl8211b_config_intr,
252 .read_mmd = &genphy_read_mmd_unsupported,
253 .write_mmd = &genphy_write_mmd_unsupported,
254 .suspend = rtl8211b_suspend,
255 .resume = rtl8211b_resume,
256 }, {
257 .phy_id = 0x001cc913,
258 .name = "RTL8211C Gigabit Ethernet",
259 .phy_id_mask = 0x001fffff,
260 .features = PHY_GBIT_FEATURES,
261 .config_init = rtl8211c_config_init,
262 .read_mmd = &genphy_read_mmd_unsupported,
263 .write_mmd = &genphy_write_mmd_unsupported,
264 }, {
265 .phy_id = 0x001cc914,
266 .name = "RTL8211DN Gigabit Ethernet",
267 .phy_id_mask = 0x001fffff,
268 .features = PHY_GBIT_FEATURES,
269 .flags = PHY_HAS_INTERRUPT,
270 .ack_interrupt = rtl821x_ack_interrupt,
271 .config_intr = rtl8211e_config_intr,
272 .suspend = genphy_suspend,
273 .resume = genphy_resume,
274 }, {
275 .phy_id = 0x001cc915,
276 .name = "RTL8211E Gigabit Ethernet",
277 .phy_id_mask = 0x001fffff,
278 .features = PHY_GBIT_FEATURES,
279 .flags = PHY_HAS_INTERRUPT,
280 .ack_interrupt = &rtl821x_ack_interrupt,
281 .config_intr = &rtl8211e_config_intr,
282 .suspend = genphy_suspend,
283 .resume = genphy_resume,
284 }, {
285 .phy_id = 0x001cc916,
286 .name = "RTL8211F Gigabit Ethernet",
287 .phy_id_mask = 0x001fffff,
288 .features = PHY_GBIT_FEATURES,
289 .flags = PHY_HAS_INTERRUPT,
290 .config_init = &rtl8211f_config_init,
291 .ack_interrupt = &rtl8211f_ack_interrupt,
292 .config_intr = &rtl8211f_config_intr,
293 .suspend = genphy_suspend,
294 .resume = genphy_resume,
295 .read_page = rtl821x_read_page,
296 .write_page = rtl821x_write_page,
297 }, {
298 .phy_id = 0x001cc961,
299 .name = "RTL8366RB Gigabit Ethernet",
300 .phy_id_mask = 0x001fffff,
301 .features = PHY_GBIT_FEATURES,
302 .flags = PHY_HAS_INTERRUPT,
303 .config_init = &rtl8366rb_config_init,
304 .suspend = genphy_suspend,
305 .resume = genphy_resume,
306 },
307};
308
309module_phy_driver(realtek_drvs);
310
311static struct mdio_device_id __maybe_unused realtek_tbl[] = {
312 { 0x001cc816, 0x001fffff },
313 { 0x001cc910, 0x001fffff },
314 { 0x001cc912, 0x001fffff },
315 { 0x001cc913, 0x001fffff },
316 { 0x001cc914, 0x001fffff },
317 { 0x001cc915, 0x001fffff },
318 { 0x001cc916, 0x001fffff },
319 { 0x001cc961, 0x001fffff },
320 { }
321};
322
323MODULE_DEVICE_TABLE(mdio, realtek_tbl);