]>
Commit | Line | Data |
---|---|---|
9082eeac AF |
1 | /* |
2 | * RealTek PHY drivers | |
3 | * | |
1a459660 | 4 | * SPDX-License-Identifier: GPL-2.0+ |
9082eeac | 5 | * |
3cee1388 | 6 | * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc. |
9082eeac | 7 | * author Andy Fleming |
9082eeac AF |
8 | */ |
9 | #include <config.h> | |
10 | #include <common.h> | |
11 | #include <phy.h> | |
12 | ||
13 | #define PHY_AUTONEGOTIATE_TIMEOUT 5000 | |
14 | ||
c624d168 BS |
15 | /* RTL8211x PHY Status Register */ |
16 | #define MIIM_RTL8211x_PHY_STATUS 0x11 | |
17 | #define MIIM_RTL8211x_PHYSTAT_SPEED 0xc000 | |
18 | #define MIIM_RTL8211x_PHYSTAT_GBIT 0x8000 | |
19 | #define MIIM_RTL8211x_PHYSTAT_100 0x4000 | |
20 | #define MIIM_RTL8211x_PHYSTAT_DUPLEX 0x2000 | |
21 | #define MIIM_RTL8211x_PHYSTAT_SPDDONE 0x0800 | |
22 | #define MIIM_RTL8211x_PHYSTAT_LINK 0x0400 | |
23 | ||
3cee1388 CC |
24 | /* RTL8211x PHY Interrupt Enable Register */ |
25 | #define MIIM_RTL8211x_PHY_INER 0x12 | |
26 | #define MIIM_RTL8211x_PHY_INTR_ENA 0x9f01 | |
27 | #define MIIM_RTL8211x_PHY_INTR_DIS 0x0000 | |
28 | ||
29 | /* RTL8211x PHY Interrupt Status Register */ | |
30 | #define MIIM_RTL8211x_PHY_INSR 0x13 | |
c624d168 BS |
31 | |
32 | /* RealTek RTL8211x */ | |
33 | static int rtl8211x_config(struct phy_device *phydev) | |
9082eeac AF |
34 | { |
35 | phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); | |
36 | ||
3cee1388 CC |
37 | /* mask interrupt at init; if the interrupt is |
38 | * needed indeed, it should be explicitly enabled | |
39 | */ | |
40 | phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER, | |
41 | MIIM_RTL8211x_PHY_INTR_DIS); | |
42 | ||
43 | /* read interrupt status just to clear it */ | |
44 | phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER); | |
45 | ||
9082eeac AF |
46 | genphy_config_aneg(phydev); |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
c624d168 | 51 | static int rtl8211x_parse_status(struct phy_device *phydev) |
9082eeac AF |
52 | { |
53 | unsigned int speed; | |
54 | unsigned int mii_reg; | |
55 | ||
c624d168 | 56 | mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS); |
9082eeac | 57 | |
c624d168 | 58 | if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { |
9082eeac AF |
59 | int i = 0; |
60 | ||
61 | /* in case of timeout ->link is cleared */ | |
62 | phydev->link = 1; | |
63 | puts("Waiting for PHY realtime link"); | |
c624d168 | 64 | while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { |
9082eeac AF |
65 | /* Timeout reached ? */ |
66 | if (i > PHY_AUTONEGOTIATE_TIMEOUT) { | |
67 | puts(" TIMEOUT !\n"); | |
68 | phydev->link = 0; | |
69 | break; | |
70 | } | |
71 | ||
72 | if ((i++ % 1000) == 0) | |
73 | putc('.'); | |
74 | udelay(1000); /* 1 ms */ | |
75 | mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, | |
c624d168 | 76 | MIIM_RTL8211x_PHY_STATUS); |
9082eeac AF |
77 | } |
78 | puts(" done\n"); | |
79 | udelay(500000); /* another 500 ms (results in faster booting) */ | |
80 | } else { | |
c624d168 | 81 | if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK) |
9082eeac AF |
82 | phydev->link = 1; |
83 | else | |
84 | phydev->link = 0; | |
85 | } | |
86 | ||
c624d168 | 87 | if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX) |
9082eeac AF |
88 | phydev->duplex = DUPLEX_FULL; |
89 | else | |
90 | phydev->duplex = DUPLEX_HALF; | |
91 | ||
c624d168 | 92 | speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED); |
9082eeac AF |
93 | |
94 | switch (speed) { | |
c624d168 | 95 | case MIIM_RTL8211x_PHYSTAT_GBIT: |
9082eeac AF |
96 | phydev->speed = SPEED_1000; |
97 | break; | |
c624d168 | 98 | case MIIM_RTL8211x_PHYSTAT_100: |
9082eeac AF |
99 | phydev->speed = SPEED_100; |
100 | break; | |
101 | default: | |
102 | phydev->speed = SPEED_10; | |
103 | } | |
104 | ||
105 | return 0; | |
106 | } | |
107 | ||
c624d168 | 108 | static int rtl8211x_startup(struct phy_device *phydev) |
9082eeac AF |
109 | { |
110 | /* Read the Status (2x to make sure link is right) */ | |
111 | genphy_update_link(phydev); | |
c624d168 | 112 | rtl8211x_parse_status(phydev); |
9082eeac AF |
113 | |
114 | return 0; | |
115 | } | |
116 | ||
c624d168 | 117 | /* Support for RTL8211B PHY */ |
9082eeac AF |
118 | static struct phy_driver RTL8211B_driver = { |
119 | .name = "RealTek RTL8211B", | |
120 | .uid = 0x1cc910, | |
42205047 | 121 | .mask = 0xffffff, |
9082eeac | 122 | .features = PHY_GBIT_FEATURES, |
c624d168 BS |
123 | .config = &rtl8211x_config, |
124 | .startup = &rtl8211x_startup, | |
125 | .shutdown = &genphy_shutdown, | |
126 | }; | |
127 | ||
128 | /* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */ | |
129 | static struct phy_driver RTL8211E_driver = { | |
130 | .name = "RealTek RTL8211E", | |
131 | .uid = 0x1cc915, | |
42205047 | 132 | .mask = 0xffffff, |
c624d168 BS |
133 | .features = PHY_GBIT_FEATURES, |
134 | .config = &rtl8211x_config, | |
135 | .startup = &rtl8211x_startup, | |
136 | .shutdown = &genphy_shutdown, | |
137 | }; | |
138 | ||
139 | /* Support for RTL8211DN PHY */ | |
140 | static struct phy_driver RTL8211DN_driver = { | |
141 | .name = "RealTek RTL8211DN", | |
142 | .uid = 0x1cc914, | |
42205047 | 143 | .mask = 0xffffff, |
c624d168 BS |
144 | .features = PHY_GBIT_FEATURES, |
145 | .config = &rtl8211x_config, | |
146 | .startup = &rtl8211x_startup, | |
9082eeac AF |
147 | .shutdown = &genphy_shutdown, |
148 | }; | |
149 | ||
150 | int phy_realtek_init(void) | |
151 | { | |
152 | phy_register(&RTL8211B_driver); | |
c624d168 BS |
153 | phy_register(&RTL8211E_driver); |
154 | phy_register(&RTL8211DN_driver); | |
9082eeac AF |
155 | |
156 | return 0; | |
157 | } |