1 | // SPDX-License-Identifier: GPL-2.0+ |
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 | #include <linux/bitops.h> |
11 | #include <linux/of.h> |
12 | #include <linux/phy.h> |
13 | #include <linux/module.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/clk.h> |
16 | |
17 | #define RTL821x_PHYSR 0x11 |
18 | #define RTL821x_PHYSR_DUPLEX BIT(13) |
19 | #define RTL821x_PHYSR_SPEED GENMASK(15, 14) |
20 | |
21 | #define RTL821x_INER 0x12 |
22 | #define RTL8211B_INER_INIT 0x6400 |
23 | #define RTL8211E_INER_LINK_STATUS BIT(10) |
24 | #define RTL8211F_INER_LINK_STATUS BIT(4) |
25 | |
26 | #define RTL821x_INSR 0x13 |
27 | |
28 | #define RTL821x_EXT_PAGE_SELECT 0x1e |
29 | #define RTL821x_PAGE_SELECT 0x1f |
30 | |
31 | #define RTL8211F_PHYCR1 0x18 |
32 | #define RTL8211F_PHYCR2 0x19 |
33 | #define RTL8211F_INSR 0x1d |
34 | |
35 | #define RTL8211F_TX_DELAY BIT(8) |
36 | #define RTL8211F_RX_DELAY BIT(3) |
37 | |
38 | #define RTL8211F_ALDPS_PLL_OFF BIT(1) |
39 | #define RTL8211F_ALDPS_ENABLE BIT(2) |
40 | #define RTL8211F_ALDPS_XTAL_OFF BIT(12) |
41 | |
42 | #define RTL8211E_CTRL_DELAY BIT(13) |
43 | #define RTL8211E_TX_DELAY BIT(12) |
44 | #define RTL8211E_RX_DELAY BIT(11) |
45 | |
46 | #define RTL8211F_CLKOUT_EN BIT(0) |
47 | |
48 | #define RTL8201F_ISR 0x1e |
49 | #define RTL8201F_ISR_ANERR BIT(15) |
50 | #define RTL8201F_ISR_DUPLEX BIT(13) |
51 | #define RTL8201F_ISR_LINK BIT(11) |
52 | #define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ |
53 | RTL8201F_ISR_DUPLEX | \ |
54 | RTL8201F_ISR_LINK) |
55 | #define RTL8201F_IER 0x13 |
56 | |
57 | #define RTL8366RB_POWER_SAVE 0x15 |
58 | #define RTL8366RB_POWER_SAVE_ON BIT(12) |
59 | |
60 | #define RTL_SUPPORTS_5000FULL BIT(14) |
61 | #define RTL_SUPPORTS_2500FULL BIT(13) |
62 | #define RTL_SUPPORTS_10000FULL BIT(0) |
63 | #define RTL_ADV_2500FULL BIT(7) |
64 | #define RTL_LPADV_10000FULL BIT(11) |
65 | #define RTL_LPADV_5000FULL BIT(6) |
66 | #define RTL_LPADV_2500FULL BIT(5) |
67 | |
68 | #define RTL9000A_GINMR 0x14 |
69 | #define RTL9000A_GINMR_LINK_STATUS BIT(4) |
70 | |
71 | #define RTLGEN_SPEED_MASK 0x0630 |
72 | |
73 | #define RTL_GENERIC_PHYID 0x001cc800 |
74 | #define RTL_8211FVD_PHYID 0x001cc878 |
75 | |
76 | MODULE_DESCRIPTION("Realtek PHY driver" ); |
77 | MODULE_AUTHOR("Johnson Leung" ); |
78 | MODULE_LICENSE("GPL" ); |
79 | |
80 | struct rtl821x_priv { |
81 | u16 phycr1; |
82 | u16 phycr2; |
83 | bool has_phycr2; |
84 | struct clk *clk; |
85 | }; |
86 | |
87 | static int rtl821x_read_page(struct phy_device *phydev) |
88 | { |
89 | return __phy_read(phydev, RTL821x_PAGE_SELECT); |
90 | } |
91 | |
92 | static int rtl821x_write_page(struct phy_device *phydev, int page) |
93 | { |
94 | return __phy_write(phydev, RTL821x_PAGE_SELECT, val: page); |
95 | } |
96 | |
97 | static int rtl821x_probe(struct phy_device *phydev) |
98 | { |
99 | struct device *dev = &phydev->mdio.dev; |
100 | struct rtl821x_priv *priv; |
101 | u32 phy_id = phydev->drv->phy_id; |
102 | int ret; |
103 | |
104 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
105 | if (!priv) |
106 | return -ENOMEM; |
107 | |
108 | priv->clk = devm_clk_get_optional_enabled(dev, NULL); |
109 | if (IS_ERR(ptr: priv->clk)) |
110 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->clk), |
111 | fmt: "failed to get phy clock\n" ); |
112 | |
113 | ret = phy_read_paged(phydev, page: 0xa43, RTL8211F_PHYCR1); |
114 | if (ret < 0) |
115 | return ret; |
116 | |
117 | priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF); |
118 | if (of_property_read_bool(np: dev->of_node, propname: "realtek,aldps-enable" )) |
119 | priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF; |
120 | |
121 | priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); |
122 | if (priv->has_phycr2) { |
123 | ret = phy_read_paged(phydev, page: 0xa43, RTL8211F_PHYCR2); |
124 | if (ret < 0) |
125 | return ret; |
126 | |
127 | priv->phycr2 = ret & RTL8211F_CLKOUT_EN; |
128 | if (of_property_read_bool(np: dev->of_node, propname: "realtek,clkout-disable" )) |
129 | priv->phycr2 &= ~RTL8211F_CLKOUT_EN; |
130 | } |
131 | |
132 | phydev->priv = priv; |
133 | |
134 | return 0; |
135 | } |
136 | |
137 | static int rtl8201_ack_interrupt(struct phy_device *phydev) |
138 | { |
139 | int err; |
140 | |
141 | err = phy_read(phydev, RTL8201F_ISR); |
142 | |
143 | return (err < 0) ? err : 0; |
144 | } |
145 | |
146 | static int rtl821x_ack_interrupt(struct phy_device *phydev) |
147 | { |
148 | int err; |
149 | |
150 | err = phy_read(phydev, RTL821x_INSR); |
151 | |
152 | return (err < 0) ? err : 0; |
153 | } |
154 | |
155 | static int rtl8211f_ack_interrupt(struct phy_device *phydev) |
156 | { |
157 | int err; |
158 | |
159 | err = phy_read_paged(phydev, page: 0xa43, RTL8211F_INSR); |
160 | |
161 | return (err < 0) ? err : 0; |
162 | } |
163 | |
164 | static int rtl8201_config_intr(struct phy_device *phydev) |
165 | { |
166 | u16 val; |
167 | int err; |
168 | |
169 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { |
170 | err = rtl8201_ack_interrupt(phydev); |
171 | if (err) |
172 | return err; |
173 | |
174 | val = BIT(13) | BIT(12) | BIT(11); |
175 | err = phy_write_paged(phydev, page: 0x7, RTL8201F_IER, val); |
176 | } else { |
177 | val = 0; |
178 | err = phy_write_paged(phydev, page: 0x7, RTL8201F_IER, val); |
179 | if (err) |
180 | return err; |
181 | |
182 | err = rtl8201_ack_interrupt(phydev); |
183 | } |
184 | |
185 | return err; |
186 | } |
187 | |
188 | static int rtl8211b_config_intr(struct phy_device *phydev) |
189 | { |
190 | int err; |
191 | |
192 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { |
193 | err = rtl821x_ack_interrupt(phydev); |
194 | if (err) |
195 | return err; |
196 | |
197 | err = phy_write(phydev, RTL821x_INER, |
198 | RTL8211B_INER_INIT); |
199 | } else { |
200 | err = phy_write(phydev, RTL821x_INER, val: 0); |
201 | if (err) |
202 | return err; |
203 | |
204 | err = rtl821x_ack_interrupt(phydev); |
205 | } |
206 | |
207 | return err; |
208 | } |
209 | |
210 | static int rtl8211e_config_intr(struct phy_device *phydev) |
211 | { |
212 | int err; |
213 | |
214 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { |
215 | err = rtl821x_ack_interrupt(phydev); |
216 | if (err) |
217 | return err; |
218 | |
219 | err = phy_write(phydev, RTL821x_INER, |
220 | RTL8211E_INER_LINK_STATUS); |
221 | } else { |
222 | err = phy_write(phydev, RTL821x_INER, val: 0); |
223 | if (err) |
224 | return err; |
225 | |
226 | err = rtl821x_ack_interrupt(phydev); |
227 | } |
228 | |
229 | return err; |
230 | } |
231 | |
232 | static int rtl8211f_config_intr(struct phy_device *phydev) |
233 | { |
234 | u16 val; |
235 | int err; |
236 | |
237 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { |
238 | err = rtl8211f_ack_interrupt(phydev); |
239 | if (err) |
240 | return err; |
241 | |
242 | val = RTL8211F_INER_LINK_STATUS; |
243 | err = phy_write_paged(phydev, page: 0xa42, RTL821x_INER, val); |
244 | } else { |
245 | val = 0; |
246 | err = phy_write_paged(phydev, page: 0xa42, RTL821x_INER, val); |
247 | if (err) |
248 | return err; |
249 | |
250 | err = rtl8211f_ack_interrupt(phydev); |
251 | } |
252 | |
253 | return err; |
254 | } |
255 | |
256 | static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev) |
257 | { |
258 | int irq_status; |
259 | |
260 | irq_status = phy_read(phydev, RTL8201F_ISR); |
261 | if (irq_status < 0) { |
262 | phy_error(phydev); |
263 | return IRQ_NONE; |
264 | } |
265 | |
266 | if (!(irq_status & RTL8201F_ISR_MASK)) |
267 | return IRQ_NONE; |
268 | |
269 | phy_trigger_machine(phydev); |
270 | |
271 | return IRQ_HANDLED; |
272 | } |
273 | |
274 | static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev) |
275 | { |
276 | int irq_status, irq_enabled; |
277 | |
278 | irq_status = phy_read(phydev, RTL821x_INSR); |
279 | if (irq_status < 0) { |
280 | phy_error(phydev); |
281 | return IRQ_NONE; |
282 | } |
283 | |
284 | irq_enabled = phy_read(phydev, RTL821x_INER); |
285 | if (irq_enabled < 0) { |
286 | phy_error(phydev); |
287 | return IRQ_NONE; |
288 | } |
289 | |
290 | if (!(irq_status & irq_enabled)) |
291 | return IRQ_NONE; |
292 | |
293 | phy_trigger_machine(phydev); |
294 | |
295 | return IRQ_HANDLED; |
296 | } |
297 | |
298 | static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) |
299 | { |
300 | int irq_status; |
301 | |
302 | irq_status = phy_read_paged(phydev, page: 0xa43, RTL8211F_INSR); |
303 | if (irq_status < 0) { |
304 | phy_error(phydev); |
305 | return IRQ_NONE; |
306 | } |
307 | |
308 | if (!(irq_status & RTL8211F_INER_LINK_STATUS)) |
309 | return IRQ_NONE; |
310 | |
311 | phy_trigger_machine(phydev); |
312 | |
313 | return IRQ_HANDLED; |
314 | } |
315 | |
316 | static int rtl8211_config_aneg(struct phy_device *phydev) |
317 | { |
318 | int ret; |
319 | |
320 | ret = genphy_config_aneg(phydev); |
321 | if (ret < 0) |
322 | return ret; |
323 | |
324 | /* Quirk was copied from vendor driver. Unfortunately it includes no |
325 | * description of the magic numbers. |
326 | */ |
327 | if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) { |
328 | phy_write(phydev, regnum: 0x17, val: 0x2138); |
329 | phy_write(phydev, regnum: 0x0e, val: 0x0260); |
330 | } else { |
331 | phy_write(phydev, regnum: 0x17, val: 0x2108); |
332 | phy_write(phydev, regnum: 0x0e, val: 0x0000); |
333 | } |
334 | |
335 | return 0; |
336 | } |
337 | |
338 | static int rtl8211c_config_init(struct phy_device *phydev) |
339 | { |
340 | /* RTL8211C has an issue when operating in Gigabit slave mode */ |
341 | return phy_set_bits(phydev, MII_CTRL1000, |
342 | CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER); |
343 | } |
344 | |
345 | static int rtl8211f_config_init(struct phy_device *phydev) |
346 | { |
347 | struct rtl821x_priv *priv = phydev->priv; |
348 | struct device *dev = &phydev->mdio.dev; |
349 | u16 val_txdly, val_rxdly; |
350 | int ret; |
351 | |
352 | ret = phy_modify_paged_changed(phydev, page: 0xa43, RTL8211F_PHYCR1, |
353 | RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, |
354 | set: priv->phycr1); |
355 | if (ret < 0) { |
356 | dev_err(dev, "aldps mode configuration failed: %pe\n" , |
357 | ERR_PTR(ret)); |
358 | return ret; |
359 | } |
360 | |
361 | switch (phydev->interface) { |
362 | case PHY_INTERFACE_MODE_RGMII: |
363 | val_txdly = 0; |
364 | val_rxdly = 0; |
365 | break; |
366 | |
367 | case PHY_INTERFACE_MODE_RGMII_RXID: |
368 | val_txdly = 0; |
369 | val_rxdly = RTL8211F_RX_DELAY; |
370 | break; |
371 | |
372 | case PHY_INTERFACE_MODE_RGMII_TXID: |
373 | val_txdly = RTL8211F_TX_DELAY; |
374 | val_rxdly = 0; |
375 | break; |
376 | |
377 | case PHY_INTERFACE_MODE_RGMII_ID: |
378 | val_txdly = RTL8211F_TX_DELAY; |
379 | val_rxdly = RTL8211F_RX_DELAY; |
380 | break; |
381 | |
382 | default: /* the rest of the modes imply leaving delay as is. */ |
383 | return 0; |
384 | } |
385 | |
386 | ret = phy_modify_paged_changed(phydev, page: 0xd08, regnum: 0x11, RTL8211F_TX_DELAY, |
387 | set: val_txdly); |
388 | if (ret < 0) { |
389 | dev_err(dev, "Failed to update the TX delay register\n" ); |
390 | return ret; |
391 | } else if (ret) { |
392 | dev_dbg(dev, |
393 | "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n" , |
394 | val_txdly ? "Enabling" : "Disabling" ); |
395 | } else { |
396 | dev_dbg(dev, |
397 | "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n" , |
398 | val_txdly ? "enabled" : "disabled" ); |
399 | } |
400 | |
401 | ret = phy_modify_paged_changed(phydev, page: 0xd08, regnum: 0x15, RTL8211F_RX_DELAY, |
402 | set: val_rxdly); |
403 | if (ret < 0) { |
404 | dev_err(dev, "Failed to update the RX delay register\n" ); |
405 | return ret; |
406 | } else if (ret) { |
407 | dev_dbg(dev, |
408 | "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n" , |
409 | val_rxdly ? "Enabling" : "Disabling" ); |
410 | } else { |
411 | dev_dbg(dev, |
412 | "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n" , |
413 | val_rxdly ? "enabled" : "disabled" ); |
414 | } |
415 | |
416 | if (priv->has_phycr2) { |
417 | ret = phy_modify_paged(phydev, page: 0xa43, RTL8211F_PHYCR2, |
418 | RTL8211F_CLKOUT_EN, set: priv->phycr2); |
419 | if (ret < 0) { |
420 | dev_err(dev, "clkout configuration failed: %pe\n" , |
421 | ERR_PTR(ret)); |
422 | return ret; |
423 | } |
424 | } |
425 | |
426 | return genphy_soft_reset(phydev); |
427 | } |
428 | |
429 | static int rtl821x_suspend(struct phy_device *phydev) |
430 | { |
431 | struct rtl821x_priv *priv = phydev->priv; |
432 | int ret = 0; |
433 | |
434 | if (!phydev->wol_enabled) { |
435 | ret = genphy_suspend(phydev); |
436 | |
437 | if (ret) |
438 | return ret; |
439 | |
440 | clk_disable_unprepare(clk: priv->clk); |
441 | } |
442 | |
443 | return ret; |
444 | } |
445 | |
446 | static int rtl821x_resume(struct phy_device *phydev) |
447 | { |
448 | struct rtl821x_priv *priv = phydev->priv; |
449 | int ret; |
450 | |
451 | if (!phydev->wol_enabled) |
452 | clk_prepare_enable(clk: priv->clk); |
453 | |
454 | ret = genphy_resume(phydev); |
455 | if (ret < 0) |
456 | return ret; |
457 | |
458 | msleep(msecs: 20); |
459 | |
460 | return 0; |
461 | } |
462 | |
463 | static int rtl8211e_config_init(struct phy_device *phydev) |
464 | { |
465 | int ret = 0, oldpage; |
466 | u16 val; |
467 | |
468 | /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ |
469 | switch (phydev->interface) { |
470 | case PHY_INTERFACE_MODE_RGMII: |
471 | val = RTL8211E_CTRL_DELAY | 0; |
472 | break; |
473 | case PHY_INTERFACE_MODE_RGMII_ID: |
474 | val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; |
475 | break; |
476 | case PHY_INTERFACE_MODE_RGMII_RXID: |
477 | val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY; |
478 | break; |
479 | case PHY_INTERFACE_MODE_RGMII_TXID: |
480 | val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY; |
481 | break; |
482 | default: /* the rest of the modes imply leaving delays as is. */ |
483 | return 0; |
484 | } |
485 | |
486 | /* According to a sample driver there is a 0x1c config register on the |
487 | * 0xa4 extension page (0x7) layout. It can be used to disable/enable |
488 | * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. |
489 | * The configuration register definition: |
490 | * 14 = reserved |
491 | * 13 = Force Tx RX Delay controlled by bit12 bit11, |
492 | * 12 = RX Delay, 11 = TX Delay |
493 | * 10:0 = Test && debug settings reserved by realtek |
494 | */ |
495 | oldpage = phy_select_page(phydev, page: 0x7); |
496 | if (oldpage < 0) |
497 | goto err_restore_page; |
498 | |
499 | ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, val: 0xa4); |
500 | if (ret) |
501 | goto err_restore_page; |
502 | |
503 | ret = __phy_modify(phydev, regnum: 0x1c, RTL8211E_CTRL_DELAY |
504 | | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, |
505 | set: val); |
506 | |
507 | err_restore_page: |
508 | return phy_restore_page(phydev, oldpage, ret); |
509 | } |
510 | |
511 | static int rtl8211b_suspend(struct phy_device *phydev) |
512 | { |
513 | phy_write(phydev, MII_MMD_DATA, BIT(9)); |
514 | |
515 | return genphy_suspend(phydev); |
516 | } |
517 | |
518 | static int rtl8211b_resume(struct phy_device *phydev) |
519 | { |
520 | phy_write(phydev, MII_MMD_DATA, val: 0); |
521 | |
522 | return genphy_resume(phydev); |
523 | } |
524 | |
525 | static int rtl8366rb_config_init(struct phy_device *phydev) |
526 | { |
527 | int ret; |
528 | |
529 | ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE, |
530 | RTL8366RB_POWER_SAVE_ON); |
531 | if (ret) { |
532 | dev_err(&phydev->mdio.dev, |
533 | "error enabling power management\n" ); |
534 | } |
535 | |
536 | return ret; |
537 | } |
538 | |
539 | /* get actual speed to cover the downshift case */ |
540 | static int rtlgen_get_speed(struct phy_device *phydev) |
541 | { |
542 | int val; |
543 | |
544 | if (!phydev->link) |
545 | return 0; |
546 | |
547 | val = phy_read_paged(phydev, page: 0xa43, regnum: 0x12); |
548 | if (val < 0) |
549 | return val; |
550 | |
551 | switch (val & RTLGEN_SPEED_MASK) { |
552 | case 0x0000: |
553 | phydev->speed = SPEED_10; |
554 | break; |
555 | case 0x0010: |
556 | phydev->speed = SPEED_100; |
557 | break; |
558 | case 0x0020: |
559 | phydev->speed = SPEED_1000; |
560 | break; |
561 | case 0x0200: |
562 | phydev->speed = SPEED_10000; |
563 | break; |
564 | case 0x0210: |
565 | phydev->speed = SPEED_2500; |
566 | break; |
567 | case 0x0220: |
568 | phydev->speed = SPEED_5000; |
569 | break; |
570 | default: |
571 | break; |
572 | } |
573 | |
574 | return 0; |
575 | } |
576 | |
577 | static int rtlgen_read_status(struct phy_device *phydev) |
578 | { |
579 | int ret; |
580 | |
581 | ret = genphy_read_status(phydev); |
582 | if (ret < 0) |
583 | return ret; |
584 | |
585 | return rtlgen_get_speed(phydev); |
586 | } |
587 | |
588 | static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) |
589 | { |
590 | int ret; |
591 | |
592 | if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { |
593 | rtl821x_write_page(phydev, page: 0xa5c); |
594 | ret = __phy_read(phydev, regnum: 0x12); |
595 | rtl821x_write_page(phydev, page: 0); |
596 | } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { |
597 | rtl821x_write_page(phydev, page: 0xa5d); |
598 | ret = __phy_read(phydev, regnum: 0x10); |
599 | rtl821x_write_page(phydev, page: 0); |
600 | } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { |
601 | rtl821x_write_page(phydev, page: 0xa5d); |
602 | ret = __phy_read(phydev, regnum: 0x11); |
603 | rtl821x_write_page(phydev, page: 0); |
604 | } else { |
605 | ret = -EOPNOTSUPP; |
606 | } |
607 | |
608 | return ret; |
609 | } |
610 | |
611 | static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, |
612 | u16 val) |
613 | { |
614 | int ret; |
615 | |
616 | if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { |
617 | rtl821x_write_page(phydev, page: 0xa5d); |
618 | ret = __phy_write(phydev, regnum: 0x10, val); |
619 | rtl821x_write_page(phydev, page: 0); |
620 | } else { |
621 | ret = -EOPNOTSUPP; |
622 | } |
623 | |
624 | return ret; |
625 | } |
626 | |
627 | static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) |
628 | { |
629 | int ret = rtlgen_read_mmd(phydev, devnum, regnum); |
630 | |
631 | if (ret != -EOPNOTSUPP) |
632 | return ret; |
633 | |
634 | if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { |
635 | rtl821x_write_page(phydev, page: 0xa6e); |
636 | ret = __phy_read(phydev, regnum: 0x16); |
637 | rtl821x_write_page(phydev, page: 0); |
638 | } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { |
639 | rtl821x_write_page(phydev, page: 0xa6d); |
640 | ret = __phy_read(phydev, regnum: 0x12); |
641 | rtl821x_write_page(phydev, page: 0); |
642 | } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { |
643 | rtl821x_write_page(phydev, page: 0xa6d); |
644 | ret = __phy_read(phydev, regnum: 0x10); |
645 | rtl821x_write_page(phydev, page: 0); |
646 | } |
647 | |
648 | return ret; |
649 | } |
650 | |
651 | static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, |
652 | u16 val) |
653 | { |
654 | int ret = rtlgen_write_mmd(phydev, devnum, regnum, val); |
655 | |
656 | if (ret != -EOPNOTSUPP) |
657 | return ret; |
658 | |
659 | if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { |
660 | rtl821x_write_page(phydev, page: 0xa6d); |
661 | ret = __phy_write(phydev, regnum: 0x12, val); |
662 | rtl821x_write_page(phydev, page: 0); |
663 | } |
664 | |
665 | return ret; |
666 | } |
667 | |
668 | static int rtl822x_get_features(struct phy_device *phydev) |
669 | { |
670 | int val; |
671 | |
672 | val = phy_read_paged(phydev, page: 0xa61, regnum: 0x13); |
673 | if (val < 0) |
674 | return val; |
675 | |
676 | linkmode_mod_bit(nr: ETHTOOL_LINK_MODE_2500baseT_Full_BIT, |
677 | addr: phydev->supported, set: val & RTL_SUPPORTS_2500FULL); |
678 | linkmode_mod_bit(nr: ETHTOOL_LINK_MODE_5000baseT_Full_BIT, |
679 | addr: phydev->supported, set: val & RTL_SUPPORTS_5000FULL); |
680 | linkmode_mod_bit(nr: ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
681 | addr: phydev->supported, set: val & RTL_SUPPORTS_10000FULL); |
682 | |
683 | return genphy_read_abilities(phydev); |
684 | } |
685 | |
686 | static int rtl822x_config_aneg(struct phy_device *phydev) |
687 | { |
688 | int ret = 0; |
689 | |
690 | if (phydev->autoneg == AUTONEG_ENABLE) { |
691 | u16 adv2500 = 0; |
692 | |
693 | if (linkmode_test_bit(nr: ETHTOOL_LINK_MODE_2500baseT_Full_BIT, |
694 | addr: phydev->advertising)) |
695 | adv2500 = RTL_ADV_2500FULL; |
696 | |
697 | ret = phy_modify_paged_changed(phydev, page: 0xa5d, regnum: 0x12, |
698 | RTL_ADV_2500FULL, set: adv2500); |
699 | if (ret < 0) |
700 | return ret; |
701 | } |
702 | |
703 | return __genphy_config_aneg(phydev, changed: ret); |
704 | } |
705 | |
706 | static int rtl822x_read_status(struct phy_device *phydev) |
707 | { |
708 | int ret; |
709 | |
710 | if (phydev->autoneg == AUTONEG_ENABLE) { |
711 | int lpadv = phy_read_paged(phydev, page: 0xa5d, regnum: 0x13); |
712 | |
713 | if (lpadv < 0) |
714 | return lpadv; |
715 | |
716 | linkmode_mod_bit(nr: ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
717 | addr: phydev->lp_advertising, set: lpadv & RTL_LPADV_10000FULL); |
718 | linkmode_mod_bit(nr: ETHTOOL_LINK_MODE_5000baseT_Full_BIT, |
719 | addr: phydev->lp_advertising, set: lpadv & RTL_LPADV_5000FULL); |
720 | linkmode_mod_bit(nr: ETHTOOL_LINK_MODE_2500baseT_Full_BIT, |
721 | addr: phydev->lp_advertising, set: lpadv & RTL_LPADV_2500FULL); |
722 | } |
723 | |
724 | ret = genphy_read_status(phydev); |
725 | if (ret < 0) |
726 | return ret; |
727 | |
728 | return rtlgen_get_speed(phydev); |
729 | } |
730 | |
731 | static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) |
732 | { |
733 | int val; |
734 | |
735 | phy_write(phydev, RTL821x_PAGE_SELECT, val: 0xa61); |
736 | val = phy_read(phydev, regnum: 0x13); |
737 | phy_write(phydev, RTL821x_PAGE_SELECT, val: 0); |
738 | |
739 | return val >= 0 && val & RTL_SUPPORTS_2500FULL; |
740 | } |
741 | |
742 | static int rtlgen_match_phy_device(struct phy_device *phydev) |
743 | { |
744 | return phydev->phy_id == RTL_GENERIC_PHYID && |
745 | !rtlgen_supports_2_5gbps(phydev); |
746 | } |
747 | |
748 | static int rtl8226_match_phy_device(struct phy_device *phydev) |
749 | { |
750 | return phydev->phy_id == RTL_GENERIC_PHYID && |
751 | rtlgen_supports_2_5gbps(phydev); |
752 | } |
753 | |
754 | static int rtlgen_resume(struct phy_device *phydev) |
755 | { |
756 | int ret = genphy_resume(phydev); |
757 | |
758 | /* Internal PHY's from RTL8168h up may not be instantly ready */ |
759 | msleep(msecs: 20); |
760 | |
761 | return ret; |
762 | } |
763 | |
764 | static int rtl9000a_config_init(struct phy_device *phydev) |
765 | { |
766 | phydev->autoneg = AUTONEG_DISABLE; |
767 | phydev->speed = SPEED_100; |
768 | phydev->duplex = DUPLEX_FULL; |
769 | |
770 | return 0; |
771 | } |
772 | |
773 | static int rtl9000a_config_aneg(struct phy_device *phydev) |
774 | { |
775 | int ret; |
776 | u16 ctl = 0; |
777 | |
778 | switch (phydev->master_slave_set) { |
779 | case MASTER_SLAVE_CFG_MASTER_FORCE: |
780 | ctl |= CTL1000_AS_MASTER; |
781 | break; |
782 | case MASTER_SLAVE_CFG_SLAVE_FORCE: |
783 | break; |
784 | case MASTER_SLAVE_CFG_UNKNOWN: |
785 | case MASTER_SLAVE_CFG_UNSUPPORTED: |
786 | return 0; |
787 | default: |
788 | phydev_warn(phydev, "Unsupported Master/Slave mode\n" ); |
789 | return -EOPNOTSUPP; |
790 | } |
791 | |
792 | ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, set: ctl); |
793 | if (ret == 1) |
794 | ret = genphy_soft_reset(phydev); |
795 | |
796 | return ret; |
797 | } |
798 | |
799 | static int rtl9000a_read_status(struct phy_device *phydev) |
800 | { |
801 | int ret; |
802 | |
803 | phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; |
804 | phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; |
805 | |
806 | ret = genphy_update_link(phydev); |
807 | if (ret) |
808 | return ret; |
809 | |
810 | ret = phy_read(phydev, MII_CTRL1000); |
811 | if (ret < 0) |
812 | return ret; |
813 | if (ret & CTL1000_AS_MASTER) |
814 | phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; |
815 | else |
816 | phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; |
817 | |
818 | ret = phy_read(phydev, MII_STAT1000); |
819 | if (ret < 0) |
820 | return ret; |
821 | if (ret & LPA_1000MSRES) |
822 | phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; |
823 | else |
824 | phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; |
825 | |
826 | return 0; |
827 | } |
828 | |
829 | static int rtl9000a_ack_interrupt(struct phy_device *phydev) |
830 | { |
831 | int err; |
832 | |
833 | err = phy_read(phydev, RTL8211F_INSR); |
834 | |
835 | return (err < 0) ? err : 0; |
836 | } |
837 | |
838 | static int rtl9000a_config_intr(struct phy_device *phydev) |
839 | { |
840 | u16 val; |
841 | int err; |
842 | |
843 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { |
844 | err = rtl9000a_ack_interrupt(phydev); |
845 | if (err) |
846 | return err; |
847 | |
848 | val = (u16)~RTL9000A_GINMR_LINK_STATUS; |
849 | err = phy_write_paged(phydev, page: 0xa42, RTL9000A_GINMR, val); |
850 | } else { |
851 | val = ~0; |
852 | err = phy_write_paged(phydev, page: 0xa42, RTL9000A_GINMR, val); |
853 | if (err) |
854 | return err; |
855 | |
856 | err = rtl9000a_ack_interrupt(phydev); |
857 | } |
858 | |
859 | return phy_write_paged(phydev, page: 0xa42, RTL9000A_GINMR, val); |
860 | } |
861 | |
862 | static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) |
863 | { |
864 | int irq_status; |
865 | |
866 | irq_status = phy_read(phydev, RTL8211F_INSR); |
867 | if (irq_status < 0) { |
868 | phy_error(phydev); |
869 | return IRQ_NONE; |
870 | } |
871 | |
872 | if (!(irq_status & RTL8211F_INER_LINK_STATUS)) |
873 | return IRQ_NONE; |
874 | |
875 | phy_trigger_machine(phydev); |
876 | |
877 | return IRQ_HANDLED; |
878 | } |
879 | |
880 | static struct phy_driver realtek_drvs[] = { |
881 | { |
882 | PHY_ID_MATCH_EXACT(0x00008201), |
883 | .name = "RTL8201CP Ethernet" , |
884 | .read_page = rtl821x_read_page, |
885 | .write_page = rtl821x_write_page, |
886 | }, { |
887 | PHY_ID_MATCH_EXACT(0x001cc816), |
888 | .name = "RTL8201F Fast Ethernet" , |
889 | .config_intr = &rtl8201_config_intr, |
890 | .handle_interrupt = rtl8201_handle_interrupt, |
891 | .suspend = genphy_suspend, |
892 | .resume = genphy_resume, |
893 | .read_page = rtl821x_read_page, |
894 | .write_page = rtl821x_write_page, |
895 | }, { |
896 | PHY_ID_MATCH_MODEL(0x001cc880), |
897 | .name = "RTL8208 Fast Ethernet" , |
898 | .read_mmd = genphy_read_mmd_unsupported, |
899 | .write_mmd = genphy_write_mmd_unsupported, |
900 | .suspend = genphy_suspend, |
901 | .resume = genphy_resume, |
902 | .read_page = rtl821x_read_page, |
903 | .write_page = rtl821x_write_page, |
904 | }, { |
905 | PHY_ID_MATCH_EXACT(0x001cc910), |
906 | .name = "RTL8211 Gigabit Ethernet" , |
907 | .config_aneg = rtl8211_config_aneg, |
908 | .read_mmd = &genphy_read_mmd_unsupported, |
909 | .write_mmd = &genphy_write_mmd_unsupported, |
910 | .read_page = rtl821x_read_page, |
911 | .write_page = rtl821x_write_page, |
912 | }, { |
913 | PHY_ID_MATCH_EXACT(0x001cc912), |
914 | .name = "RTL8211B Gigabit Ethernet" , |
915 | .config_intr = &rtl8211b_config_intr, |
916 | .handle_interrupt = rtl821x_handle_interrupt, |
917 | .read_mmd = &genphy_read_mmd_unsupported, |
918 | .write_mmd = &genphy_write_mmd_unsupported, |
919 | .suspend = rtl8211b_suspend, |
920 | .resume = rtl8211b_resume, |
921 | .read_page = rtl821x_read_page, |
922 | .write_page = rtl821x_write_page, |
923 | }, { |
924 | PHY_ID_MATCH_EXACT(0x001cc913), |
925 | .name = "RTL8211C Gigabit Ethernet" , |
926 | .config_init = rtl8211c_config_init, |
927 | .read_mmd = &genphy_read_mmd_unsupported, |
928 | .write_mmd = &genphy_write_mmd_unsupported, |
929 | .read_page = rtl821x_read_page, |
930 | .write_page = rtl821x_write_page, |
931 | }, { |
932 | PHY_ID_MATCH_EXACT(0x001cc914), |
933 | .name = "RTL8211DN Gigabit Ethernet" , |
934 | .config_intr = rtl8211e_config_intr, |
935 | .handle_interrupt = rtl821x_handle_interrupt, |
936 | .suspend = genphy_suspend, |
937 | .resume = genphy_resume, |
938 | .read_page = rtl821x_read_page, |
939 | .write_page = rtl821x_write_page, |
940 | }, { |
941 | PHY_ID_MATCH_EXACT(0x001cc915), |
942 | .name = "RTL8211E Gigabit Ethernet" , |
943 | .config_init = &rtl8211e_config_init, |
944 | .config_intr = &rtl8211e_config_intr, |
945 | .handle_interrupt = rtl821x_handle_interrupt, |
946 | .suspend = genphy_suspend, |
947 | .resume = genphy_resume, |
948 | .read_page = rtl821x_read_page, |
949 | .write_page = rtl821x_write_page, |
950 | }, { |
951 | PHY_ID_MATCH_EXACT(0x001cc916), |
952 | .name = "RTL8211F Gigabit Ethernet" , |
953 | .probe = rtl821x_probe, |
954 | .config_init = &rtl8211f_config_init, |
955 | .read_status = rtlgen_read_status, |
956 | .config_intr = &rtl8211f_config_intr, |
957 | .handle_interrupt = rtl8211f_handle_interrupt, |
958 | .suspend = rtl821x_suspend, |
959 | .resume = rtl821x_resume, |
960 | .read_page = rtl821x_read_page, |
961 | .write_page = rtl821x_write_page, |
962 | .flags = PHY_ALWAYS_CALL_SUSPEND, |
963 | }, { |
964 | PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), |
965 | .name = "RTL8211F-VD Gigabit Ethernet" , |
966 | .probe = rtl821x_probe, |
967 | .config_init = &rtl8211f_config_init, |
968 | .read_status = rtlgen_read_status, |
969 | .config_intr = &rtl8211f_config_intr, |
970 | .handle_interrupt = rtl8211f_handle_interrupt, |
971 | .suspend = rtl821x_suspend, |
972 | .resume = rtl821x_resume, |
973 | .read_page = rtl821x_read_page, |
974 | .write_page = rtl821x_write_page, |
975 | .flags = PHY_ALWAYS_CALL_SUSPEND, |
976 | }, { |
977 | .name = "Generic FE-GE Realtek PHY" , |
978 | .match_phy_device = rtlgen_match_phy_device, |
979 | .read_status = rtlgen_read_status, |
980 | .suspend = genphy_suspend, |
981 | .resume = rtlgen_resume, |
982 | .read_page = rtl821x_read_page, |
983 | .write_page = rtl821x_write_page, |
984 | .read_mmd = rtlgen_read_mmd, |
985 | .write_mmd = rtlgen_write_mmd, |
986 | }, { |
987 | .name = "RTL8226 2.5Gbps PHY" , |
988 | .match_phy_device = rtl8226_match_phy_device, |
989 | .get_features = rtl822x_get_features, |
990 | .config_aneg = rtl822x_config_aneg, |
991 | .read_status = rtl822x_read_status, |
992 | .suspend = genphy_suspend, |
993 | .resume = rtlgen_resume, |
994 | .read_page = rtl821x_read_page, |
995 | .write_page = rtl821x_write_page, |
996 | .read_mmd = rtl822x_read_mmd, |
997 | .write_mmd = rtl822x_write_mmd, |
998 | }, { |
999 | PHY_ID_MATCH_EXACT(0x001cc840), |
1000 | .name = "RTL8226B_RTL8221B 2.5Gbps PHY" , |
1001 | .get_features = rtl822x_get_features, |
1002 | .config_aneg = rtl822x_config_aneg, |
1003 | .read_status = rtl822x_read_status, |
1004 | .suspend = genphy_suspend, |
1005 | .resume = rtlgen_resume, |
1006 | .read_page = rtl821x_read_page, |
1007 | .write_page = rtl821x_write_page, |
1008 | .read_mmd = rtl822x_read_mmd, |
1009 | .write_mmd = rtl822x_write_mmd, |
1010 | }, { |
1011 | PHY_ID_MATCH_EXACT(0x001cc838), |
1012 | .name = "RTL8226-CG 2.5Gbps PHY" , |
1013 | .get_features = rtl822x_get_features, |
1014 | .config_aneg = rtl822x_config_aneg, |
1015 | .read_status = rtl822x_read_status, |
1016 | .suspend = genphy_suspend, |
1017 | .resume = rtlgen_resume, |
1018 | .read_page = rtl821x_read_page, |
1019 | .write_page = rtl821x_write_page, |
1020 | }, { |
1021 | PHY_ID_MATCH_EXACT(0x001cc848), |
1022 | .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY" , |
1023 | .get_features = rtl822x_get_features, |
1024 | .config_aneg = rtl822x_config_aneg, |
1025 | .read_status = rtl822x_read_status, |
1026 | .suspend = genphy_suspend, |
1027 | .resume = rtlgen_resume, |
1028 | .read_page = rtl821x_read_page, |
1029 | .write_page = rtl821x_write_page, |
1030 | }, { |
1031 | PHY_ID_MATCH_EXACT(0x001cc849), |
1032 | .name = "RTL8221B-VB-CG 2.5Gbps PHY" , |
1033 | .get_features = rtl822x_get_features, |
1034 | .config_aneg = rtl822x_config_aneg, |
1035 | .read_status = rtl822x_read_status, |
1036 | .suspend = genphy_suspend, |
1037 | .resume = rtlgen_resume, |
1038 | .read_page = rtl821x_read_page, |
1039 | .write_page = rtl821x_write_page, |
1040 | }, { |
1041 | PHY_ID_MATCH_EXACT(0x001cc84a), |
1042 | .name = "RTL8221B-VM-CG 2.5Gbps PHY" , |
1043 | .get_features = rtl822x_get_features, |
1044 | .config_aneg = rtl822x_config_aneg, |
1045 | .read_status = rtl822x_read_status, |
1046 | .suspend = genphy_suspend, |
1047 | .resume = rtlgen_resume, |
1048 | .read_page = rtl821x_read_page, |
1049 | .write_page = rtl821x_write_page, |
1050 | }, { |
1051 | PHY_ID_MATCH_EXACT(0x001cc961), |
1052 | .name = "RTL8366RB Gigabit Ethernet" , |
1053 | .config_init = &rtl8366rb_config_init, |
1054 | /* These interrupts are handled by the irq controller |
1055 | * embedded inside the RTL8366RB, they get unmasked when the |
1056 | * irq is requested and ACKed by reading the status register, |
1057 | * which is done by the irqchip code. |
1058 | */ |
1059 | .config_intr = genphy_no_config_intr, |
1060 | .handle_interrupt = genphy_handle_interrupt_no_ack, |
1061 | .suspend = genphy_suspend, |
1062 | .resume = genphy_resume, |
1063 | }, { |
1064 | PHY_ID_MATCH_EXACT(0x001ccb00), |
1065 | .name = "RTL9000AA_RTL9000AN Ethernet" , |
1066 | .features = PHY_BASIC_T1_FEATURES, |
1067 | .config_init = rtl9000a_config_init, |
1068 | .config_aneg = rtl9000a_config_aneg, |
1069 | .read_status = rtl9000a_read_status, |
1070 | .config_intr = rtl9000a_config_intr, |
1071 | .handle_interrupt = rtl9000a_handle_interrupt, |
1072 | .suspend = genphy_suspend, |
1073 | .resume = genphy_resume, |
1074 | .read_page = rtl821x_read_page, |
1075 | .write_page = rtl821x_write_page, |
1076 | }, { |
1077 | PHY_ID_MATCH_EXACT(0x001cc942), |
1078 | .name = "RTL8365MB-VC Gigabit Ethernet" , |
1079 | /* Interrupt handling analogous to RTL8366RB */ |
1080 | .config_intr = genphy_no_config_intr, |
1081 | .handle_interrupt = genphy_handle_interrupt_no_ack, |
1082 | .suspend = genphy_suspend, |
1083 | .resume = genphy_resume, |
1084 | }, |
1085 | }; |
1086 | |
1087 | module_phy_driver(realtek_drvs); |
1088 | |
1089 | static const struct mdio_device_id __maybe_unused realtek_tbl[] = { |
1090 | { PHY_ID_MATCH_VENDOR(0x001cc800) }, |
1091 | { } |
1092 | }; |
1093 | |
1094 | MODULE_DEVICE_TABLE(mdio, realtek_tbl); |
1095 | |