xref: /openbmc/u-boot/drivers/net/phy/realtek.c (revision 704744f8)
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  * Copyright 2016 Karsten Merker <merker@debian.org>
9  */
10 #include <config.h>
11 #include <common.h>
12 #include <linux/bitops.h>
13 #include <phy.h>
14 
15 #define PHY_RTL8211x_FORCE_MASTER BIT(1)
16 #define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
17 
18 #define PHY_AUTONEGOTIATE_TIMEOUT 5000
19 
20 /* RTL8211x 1000BASE-T Control Register */
21 #define MIIM_RTL8211x_CTRL1000T_MSCE BIT(12);
22 #define MIIM_RTL8211x_CTRL1000T_MASTER BIT(11);
23 
24 /* RTL8211x PHY Status Register */
25 #define MIIM_RTL8211x_PHY_STATUS       0x11
26 #define MIIM_RTL8211x_PHYSTAT_SPEED    0xc000
27 #define MIIM_RTL8211x_PHYSTAT_GBIT     0x8000
28 #define MIIM_RTL8211x_PHYSTAT_100      0x4000
29 #define MIIM_RTL8211x_PHYSTAT_DUPLEX   0x2000
30 #define MIIM_RTL8211x_PHYSTAT_SPDDONE  0x0800
31 #define MIIM_RTL8211x_PHYSTAT_LINK     0x0400
32 
33 /* RTL8211x PHY Interrupt Enable Register */
34 #define MIIM_RTL8211x_PHY_INER         0x12
35 #define MIIM_RTL8211x_PHY_INTR_ENA     0x9f01
36 #define MIIM_RTL8211x_PHY_INTR_DIS     0x0000
37 
38 /* RTL8211x PHY Interrupt Status Register */
39 #define MIIM_RTL8211x_PHY_INSR         0x13
40 
41 /* RTL8211F PHY Status Register */
42 #define MIIM_RTL8211F_PHY_STATUS       0x1a
43 #define MIIM_RTL8211F_AUTONEG_ENABLE   0x1000
44 #define MIIM_RTL8211F_PHYSTAT_SPEED    0x0030
45 #define MIIM_RTL8211F_PHYSTAT_GBIT     0x0020
46 #define MIIM_RTL8211F_PHYSTAT_100      0x0010
47 #define MIIM_RTL8211F_PHYSTAT_DUPLEX   0x0008
48 #define MIIM_RTL8211F_PHYSTAT_SPDDONE  0x0800
49 #define MIIM_RTL8211F_PHYSTAT_LINK     0x0004
50 
51 #define MIIM_RTL8211E_CONFREG           0x1c
52 #define MIIM_RTL8211E_CONFREG_TXD		0x0002
53 #define MIIM_RTL8211E_CONFREG_RXD		0x0004
54 #define MIIM_RTL8211E_CONFREG_MAGIC		0xb400	/* Undocumented */
55 
56 #define MIIM_RTL8211E_EXT_PAGE_SELECT  0x1e
57 
58 #define MIIM_RTL8211F_PAGE_SELECT      0x1f
59 #define MIIM_RTL8211F_TX_DELAY		0x100
60 #define MIIM_RTL8211F_LCR		0x10
61 
62 static int rtl8211b_probe(struct phy_device *phydev)
63 {
64 #ifdef CONFIG_RTL8211X_PHY_FORCE_MASTER
65 	phydev->flags |= PHY_RTL8211x_FORCE_MASTER;
66 #endif
67 
68 	return 0;
69 }
70 
71 static int rtl8211e_probe(struct phy_device *phydev)
72 {
73 #ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
74 	phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
75 #endif
76 
77 	return 0;
78 }
79 
80 /* RealTek RTL8211x */
81 static int rtl8211x_config(struct phy_device *phydev)
82 {
83 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
84 
85 	/* mask interrupt at init; if the interrupt is
86 	 * needed indeed, it should be explicitly enabled
87 	 */
88 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER,
89 		  MIIM_RTL8211x_PHY_INTR_DIS);
90 
91 	if (phydev->flags & PHY_RTL8211x_FORCE_MASTER) {
92 		unsigned int reg;
93 
94 		reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
95 		/* force manual master/slave configuration */
96 		reg |= MIIM_RTL8211x_CTRL1000T_MSCE;
97 		/* force master mode */
98 		reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
99 		phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
100 	}
101 	if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) {
102 		unsigned int reg;
103 
104 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
105 			  7);
106 		phy_write(phydev, MDIO_DEVAD_NONE,
107 			  MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
108 		reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
109 		/* Ensure both internal delays are turned off */
110 		reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD);
111 		/* Flip the magic undocumented bits */
112 		reg |= MIIM_RTL8211E_CONFREG_MAGIC;
113 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg);
114 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
115 			  0);
116 	}
117 	/* read interrupt status just to clear it */
118 	phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
119 
120 	genphy_config_aneg(phydev);
121 
122 	return 0;
123 }
124 
125 static int rtl8211f_config(struct phy_device *phydev)
126 {
127 	u16 reg;
128 
129 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
130 
131 	phy_write(phydev, MDIO_DEVAD_NONE,
132 		  MIIM_RTL8211F_PAGE_SELECT, 0xd08);
133 	reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11);
134 
135 	/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
136 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
137 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
138 		reg |= MIIM_RTL8211F_TX_DELAY;
139 	else
140 		reg &= ~MIIM_RTL8211F_TX_DELAY;
141 
142 	phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg);
143 	/* restore to default page 0 */
144 	phy_write(phydev, MDIO_DEVAD_NONE,
145 		  MIIM_RTL8211F_PAGE_SELECT, 0x0);
146 
147 	/* Set green LED for Link, yellow LED for Active */
148 	phy_write(phydev, MDIO_DEVAD_NONE,
149 		  MIIM_RTL8211F_PAGE_SELECT, 0xd04);
150 	phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
151 	phy_write(phydev, MDIO_DEVAD_NONE,
152 		  MIIM_RTL8211F_PAGE_SELECT, 0x0);
153 
154 	genphy_config_aneg(phydev);
155 
156 	return 0;
157 }
158 
159 static int rtl8211x_parse_status(struct phy_device *phydev)
160 {
161 	unsigned int speed;
162 	unsigned int mii_reg;
163 
164 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
165 
166 	if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
167 		int i = 0;
168 
169 		/* in case of timeout ->link is cleared */
170 		phydev->link = 1;
171 		puts("Waiting for PHY realtime link");
172 		while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
173 			/* Timeout reached ? */
174 			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
175 				puts(" TIMEOUT !\n");
176 				phydev->link = 0;
177 				break;
178 			}
179 
180 			if ((i++ % 1000) == 0)
181 				putc('.');
182 			udelay(1000);	/* 1 ms */
183 			mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
184 					MIIM_RTL8211x_PHY_STATUS);
185 		}
186 		puts(" done\n");
187 		udelay(500000);	/* another 500 ms (results in faster booting) */
188 	} else {
189 		if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
190 			phydev->link = 1;
191 		else
192 			phydev->link = 0;
193 	}
194 
195 	if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
196 		phydev->duplex = DUPLEX_FULL;
197 	else
198 		phydev->duplex = DUPLEX_HALF;
199 
200 	speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
201 
202 	switch (speed) {
203 	case MIIM_RTL8211x_PHYSTAT_GBIT:
204 		phydev->speed = SPEED_1000;
205 		break;
206 	case MIIM_RTL8211x_PHYSTAT_100:
207 		phydev->speed = SPEED_100;
208 		break;
209 	default:
210 		phydev->speed = SPEED_10;
211 	}
212 
213 	return 0;
214 }
215 
216 static int rtl8211f_parse_status(struct phy_device *phydev)
217 {
218 	unsigned int speed;
219 	unsigned int mii_reg;
220 	int i = 0;
221 
222 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43);
223 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS);
224 
225 	phydev->link = 1;
226 	while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) {
227 		if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
228 			puts(" TIMEOUT !\n");
229 			phydev->link = 0;
230 			break;
231 		}
232 
233 		if ((i++ % 1000) == 0)
234 			putc('.');
235 		udelay(1000);
236 		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
237 				   MIIM_RTL8211F_PHY_STATUS);
238 	}
239 
240 	if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX)
241 		phydev->duplex = DUPLEX_FULL;
242 	else
243 		phydev->duplex = DUPLEX_HALF;
244 
245 	speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED);
246 
247 	switch (speed) {
248 	case MIIM_RTL8211F_PHYSTAT_GBIT:
249 		phydev->speed = SPEED_1000;
250 		break;
251 	case MIIM_RTL8211F_PHYSTAT_100:
252 		phydev->speed = SPEED_100;
253 		break;
254 	default:
255 		phydev->speed = SPEED_10;
256 	}
257 
258 	return 0;
259 }
260 
261 static int rtl8211x_startup(struct phy_device *phydev)
262 {
263 	int ret;
264 
265 	/* Read the Status (2x to make sure link is right) */
266 	ret = genphy_update_link(phydev);
267 	if (ret)
268 		return ret;
269 
270 	return rtl8211x_parse_status(phydev);
271 }
272 
273 static int rtl8211e_startup(struct phy_device *phydev)
274 {
275 	int ret;
276 
277 	ret = genphy_update_link(phydev);
278 	if (ret)
279 		return ret;
280 
281 	return genphy_parse_link(phydev);
282 }
283 
284 static int rtl8211f_startup(struct phy_device *phydev)
285 {
286 	int ret;
287 
288 	/* Read the Status (2x to make sure link is right) */
289 	ret = genphy_update_link(phydev);
290 	if (ret)
291 		return ret;
292 	/* Read the Status (2x to make sure link is right) */
293 
294 	return rtl8211f_parse_status(phydev);
295 }
296 
297 /* Support for RTL8211B PHY */
298 static struct phy_driver RTL8211B_driver = {
299 	.name = "RealTek RTL8211B",
300 	.uid = 0x1cc912,
301 	.mask = 0xffffff,
302 	.features = PHY_GBIT_FEATURES,
303 	.probe = &rtl8211b_probe,
304 	.config = &rtl8211x_config,
305 	.startup = &rtl8211x_startup,
306 	.shutdown = &genphy_shutdown,
307 };
308 
309 /* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
310 static struct phy_driver RTL8211E_driver = {
311 	.name = "RealTek RTL8211E",
312 	.uid = 0x1cc915,
313 	.mask = 0xffffff,
314 	.features = PHY_GBIT_FEATURES,
315 	.probe = &rtl8211e_probe,
316 	.config = &rtl8211x_config,
317 	.startup = &rtl8211e_startup,
318 	.shutdown = &genphy_shutdown,
319 };
320 
321 /* Support for RTL8211DN PHY */
322 static struct phy_driver RTL8211DN_driver = {
323 	.name = "RealTek RTL8211DN",
324 	.uid = 0x1cc914,
325 	.mask = 0xffffff,
326 	.features = PHY_GBIT_FEATURES,
327 	.config = &rtl8211x_config,
328 	.startup = &rtl8211x_startup,
329 	.shutdown = &genphy_shutdown,
330 };
331 
332 /* Support for RTL8211F PHY */
333 static struct phy_driver RTL8211F_driver = {
334 	.name = "RealTek RTL8211F",
335 	.uid = 0x1cc916,
336 	.mask = 0xffffff,
337 	.features = PHY_GBIT_FEATURES,
338 	.config = &rtl8211f_config,
339 	.startup = &rtl8211f_startup,
340 	.shutdown = &genphy_shutdown,
341 };
342 
343 int phy_realtek_init(void)
344 {
345 	phy_register(&RTL8211B_driver);
346 	phy_register(&RTL8211E_driver);
347 	phy_register(&RTL8211F_driver);
348 	phy_register(&RTL8211DN_driver);
349 
350 	return 0;
351 }
352