xref: /openbmc/u-boot/drivers/net/phy/realtek.c (revision 5be93569)
1 /*
2  * RealTek PHY drivers
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  *
6  * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc.
7  * author Andy Fleming
8  */
9 #include <config.h>
10 #include <common.h>
11 #include <phy.h>
12 
13 #define PHY_AUTONEGOTIATE_TIMEOUT 5000
14 
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 
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
31 
32 /* RTL8211F PHY Status Register */
33 #define MIIM_RTL8211F_PHY_STATUS       0x1a
34 #define MIIM_RTL8211F_AUTONEG_ENABLE   0x1000
35 #define MIIM_RTL8211F_PHYSTAT_SPEED    0x0030
36 #define MIIM_RTL8211F_PHYSTAT_GBIT     0x0020
37 #define MIIM_RTL8211F_PHYSTAT_100      0x0010
38 #define MIIM_RTL8211F_PHYSTAT_DUPLEX   0x0008
39 #define MIIM_RTL8211F_PHYSTAT_SPDDONE  0x0800
40 #define MIIM_RTL8211F_PHYSTAT_LINK     0x0004
41 
42 #define MIIM_RTL8211F_PAGE_SELECT      0x1f
43 #define MIIM_RTL8211F_TX_DELAY		0x100
44 #define MIIM_RTL8211F_LCR		0x10
45 
46 /* RealTek RTL8211x */
47 static int rtl8211x_config(struct phy_device *phydev)
48 {
49 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
50 
51 	/* mask interrupt at init; if the interrupt is
52 	 * needed indeed, it should be explicitly enabled
53 	 */
54 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER,
55 		  MIIM_RTL8211x_PHY_INTR_DIS);
56 
57 	/* read interrupt status just to clear it */
58 	phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
59 
60 	genphy_config_aneg(phydev);
61 
62 	return 0;
63 }
64 
65 static int rtl8211f_config(struct phy_device *phydev)
66 {
67 	u16 reg;
68 
69 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
70 
71 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
72 		/* enable TXDLY */
73 		phy_write(phydev, MDIO_DEVAD_NONE,
74 			  MIIM_RTL8211F_PAGE_SELECT, 0xd08);
75 		reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11);
76 		reg |= MIIM_RTL8211F_TX_DELAY;
77 		phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg);
78 		/* restore to default page 0 */
79 		phy_write(phydev, MDIO_DEVAD_NONE,
80 			  MIIM_RTL8211F_PAGE_SELECT, 0x0);
81 	}
82 
83 	/* Set green LED for Link, yellow LED for Active */
84 	phy_write(phydev, MDIO_DEVAD_NONE,
85 		  MIIM_RTL8211F_PAGE_SELECT, 0xd04);
86 	phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
87 	phy_write(phydev, MDIO_DEVAD_NONE,
88 		  MIIM_RTL8211F_PAGE_SELECT, 0x0);
89 
90 	genphy_config_aneg(phydev);
91 
92 	return 0;
93 }
94 
95 static int rtl8211x_parse_status(struct phy_device *phydev)
96 {
97 	unsigned int speed;
98 	unsigned int mii_reg;
99 
100 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
101 
102 	if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
103 		int i = 0;
104 
105 		/* in case of timeout ->link is cleared */
106 		phydev->link = 1;
107 		puts("Waiting for PHY realtime link");
108 		while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
109 			/* Timeout reached ? */
110 			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
111 				puts(" TIMEOUT !\n");
112 				phydev->link = 0;
113 				break;
114 			}
115 
116 			if ((i++ % 1000) == 0)
117 				putc('.');
118 			udelay(1000);	/* 1 ms */
119 			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
120 					MIIM_RTL8211x_PHY_STATUS);
121 		}
122 		puts(" done\n");
123 		udelay(500000);	/* another 500 ms (results in faster booting) */
124 	} else {
125 		if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
126 			phydev->link = 1;
127 		else
128 			phydev->link = 0;
129 	}
130 
131 	if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
132 		phydev->duplex = DUPLEX_FULL;
133 	else
134 		phydev->duplex = DUPLEX_HALF;
135 
136 	speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
137 
138 	switch (speed) {
139 	case MIIM_RTL8211x_PHYSTAT_GBIT:
140 		phydev->speed = SPEED_1000;
141 		break;
142 	case MIIM_RTL8211x_PHYSTAT_100:
143 		phydev->speed = SPEED_100;
144 		break;
145 	default:
146 		phydev->speed = SPEED_10;
147 	}
148 
149 	return 0;
150 }
151 
152 static int rtl8211f_parse_status(struct phy_device *phydev)
153 {
154 	unsigned int speed;
155 	unsigned int mii_reg;
156 	int i = 0;
157 
158 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43);
159 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS);
160 
161 	phydev->link = 1;
162 	while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) {
163 		if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
164 			puts(" TIMEOUT !\n");
165 			phydev->link = 0;
166 			break;
167 		}
168 
169 		if ((i++ % 1000) == 0)
170 			putc('.');
171 		udelay(1000);
172 		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
173 				   MIIM_RTL8211F_PHY_STATUS);
174 	}
175 
176 	if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX)
177 		phydev->duplex = DUPLEX_FULL;
178 	else
179 		phydev->duplex = DUPLEX_HALF;
180 
181 	speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED);
182 
183 	switch (speed) {
184 	case MIIM_RTL8211F_PHYSTAT_GBIT:
185 		phydev->speed = SPEED_1000;
186 		break;
187 	case MIIM_RTL8211F_PHYSTAT_100:
188 		phydev->speed = SPEED_100;
189 		break;
190 	default:
191 		phydev->speed = SPEED_10;
192 	}
193 
194 	return 0;
195 }
196 
197 static int rtl8211x_startup(struct phy_device *phydev)
198 {
199 	/* Read the Status (2x to make sure link is right) */
200 	genphy_update_link(phydev);
201 	rtl8211x_parse_status(phydev);
202 
203 	return 0;
204 }
205 
206 static int rtl8211f_startup(struct phy_device *phydev)
207 {
208 	/* Read the Status (2x to make sure link is right) */
209 	genphy_update_link(phydev);
210 	rtl8211f_parse_status(phydev);
211 
212 	return 0;
213 }
214 
215 /* Support for RTL8211B PHY */
216 static struct phy_driver RTL8211B_driver = {
217 	.name = "RealTek RTL8211B",
218 	.uid = 0x1cc910,
219 	.mask = 0xffffff,
220 	.features = PHY_GBIT_FEATURES,
221 	.config = &rtl8211x_config,
222 	.startup = &rtl8211x_startup,
223 	.shutdown = &genphy_shutdown,
224 };
225 
226 /* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
227 static struct phy_driver RTL8211E_driver = {
228 	.name = "RealTek RTL8211E",
229 	.uid = 0x1cc915,
230 	.mask = 0xffffff,
231 	.features = PHY_GBIT_FEATURES,
232 	.config = &rtl8211x_config,
233 	.startup = &rtl8211x_startup,
234 	.shutdown = &genphy_shutdown,
235 };
236 
237 /* Support for RTL8211DN PHY */
238 static struct phy_driver RTL8211DN_driver = {
239 	.name = "RealTek RTL8211DN",
240 	.uid = 0x1cc914,
241 	.mask = 0xffffff,
242 	.features = PHY_GBIT_FEATURES,
243 	.config = &rtl8211x_config,
244 	.startup = &rtl8211x_startup,
245 	.shutdown = &genphy_shutdown,
246 };
247 
248 /* Support for RTL8211F PHY */
249 static struct phy_driver RTL8211F_driver = {
250 	.name = "RealTek RTL8211F",
251 	.uid = 0x1cc916,
252 	.mask = 0xffffff,
253 	.features = PHY_GBIT_FEATURES,
254 	.config = &rtl8211f_config,
255 	.startup = &rtl8211f_startup,
256 	.shutdown = &genphy_shutdown,
257 };
258 
259 int phy_realtek_init(void)
260 {
261 	phy_register(&RTL8211B_driver);
262 	phy_register(&RTL8211E_driver);
263 	phy_register(&RTL8211F_driver);
264 	phy_register(&RTL8211DN_driver);
265 
266 	return 0;
267 }
268