blob: b3e6578df9acbf26878dd00ba9a95cebc3c7ce86 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Andy Fleming9082eea2011-04-07 21:56:05 -05002/*
3 * RealTek PHY drivers
4 *
Codrin Ciubotariu3cee1382015-02-13 14:47:58 +02005 * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc.
Andy Fleming9082eea2011-04-07 21:56:05 -05006 * author Andy Fleming
Karsten Merker563d8d92016-03-21 20:29:07 +01007 * Copyright 2016 Karsten Merker <merker@debian.org>
Andy Fleming9082eea2011-04-07 21:56:05 -05008 */
Andy Fleming9082eea2011-04-07 21:56:05 -05009#include <common.h>
oliver@schinagl.nl020f6762016-11-08 17:38:57 +010010#include <linux/bitops.h>
Andy Fleming9082eea2011-04-07 21:56:05 -050011#include <phy.h>
12
oliver@schinagl.nlcebf3f52016-11-08 17:38:59 +010013#define PHY_RTL8211x_FORCE_MASTER BIT(1)
kevans@FreeBSD.org66526e72018-02-14 17:02:15 -060014#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
oliver@schinagl.nlcebf3f52016-11-08 17:38:59 +010015
Andy Fleming9082eea2011-04-07 21:56:05 -050016#define PHY_AUTONEGOTIATE_TIMEOUT 5000
17
Michael Haas525d1872016-03-25 18:22:50 +010018/* RTL8211x 1000BASE-T Control Register */
oliver@schinagl.nl020f6762016-11-08 17:38:57 +010019#define MIIM_RTL8211x_CTRL1000T_MSCE BIT(12);
oliver@schinagl.nlcbe40e12016-11-08 17:38:58 +010020#define MIIM_RTL8211x_CTRL1000T_MASTER BIT(11);
Michael Haas525d1872016-03-25 18:22:50 +010021
Bhupesh Sharmac624d162013-07-18 13:58:20 +053022/* RTL8211x PHY Status Register */
23#define MIIM_RTL8211x_PHY_STATUS 0x11
24#define MIIM_RTL8211x_PHYSTAT_SPEED 0xc000
25#define MIIM_RTL8211x_PHYSTAT_GBIT 0x8000
26#define MIIM_RTL8211x_PHYSTAT_100 0x4000
27#define MIIM_RTL8211x_PHYSTAT_DUPLEX 0x2000
28#define MIIM_RTL8211x_PHYSTAT_SPDDONE 0x0800
29#define MIIM_RTL8211x_PHYSTAT_LINK 0x0400
Andy Fleming9082eea2011-04-07 21:56:05 -050030
Codrin Ciubotariu3cee1382015-02-13 14:47:58 +020031/* RTL8211x PHY Interrupt Enable Register */
32#define MIIM_RTL8211x_PHY_INER 0x12
33#define MIIM_RTL8211x_PHY_INTR_ENA 0x9f01
34#define MIIM_RTL8211x_PHY_INTR_DIS 0x0000
35
36/* RTL8211x PHY Interrupt Status Register */
37#define MIIM_RTL8211x_PHY_INSR 0x13
Andy Fleming9082eea2011-04-07 21:56:05 -050038
Shengzhou Liu3d6af742015-03-12 18:54:59 +080039/* RTL8211F PHY Status Register */
40#define MIIM_RTL8211F_PHY_STATUS 0x1a
41#define MIIM_RTL8211F_AUTONEG_ENABLE 0x1000
42#define MIIM_RTL8211F_PHYSTAT_SPEED 0x0030
43#define MIIM_RTL8211F_PHYSTAT_GBIT 0x0020
44#define MIIM_RTL8211F_PHYSTAT_100 0x0010
45#define MIIM_RTL8211F_PHYSTAT_DUPLEX 0x0008
46#define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800
47#define MIIM_RTL8211F_PHYSTAT_LINK 0x0004
48
kevans@FreeBSD.org66526e72018-02-14 17:02:15 -060049#define MIIM_RTL8211E_CONFREG 0x1c
50#define MIIM_RTL8211E_CONFREG_TXD 0x0002
51#define MIIM_RTL8211E_CONFREG_RXD 0x0004
52#define MIIM_RTL8211E_CONFREG_MAGIC 0xb400 /* Undocumented */
53
54#define MIIM_RTL8211E_EXT_PAGE_SELECT 0x1e
55
Shengzhou Liu3d6af742015-03-12 18:54:59 +080056#define MIIM_RTL8211F_PAGE_SELECT 0x1f
Shengzhou Liu793ea942015-04-24 16:57:17 +080057#define MIIM_RTL8211F_TX_DELAY 0x100
Shengzhou Liu90712742015-05-21 18:07:35 +080058#define MIIM_RTL8211F_LCR 0x10
Shengzhou Liu3d6af742015-03-12 18:54:59 +080059
oliver@schinagl.nlcebf3f52016-11-08 17:38:59 +010060static int rtl8211b_probe(struct phy_device *phydev)
61{
62#ifdef CONFIG_RTL8211X_PHY_FORCE_MASTER
63 phydev->flags |= PHY_RTL8211x_FORCE_MASTER;
64#endif
65
66 return 0;
67}
68
kevans@FreeBSD.org66526e72018-02-14 17:02:15 -060069static int rtl8211e_probe(struct phy_device *phydev)
70{
71#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
72 phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
73#endif
74
75 return 0;
76}
77
Bhupesh Sharmac624d162013-07-18 13:58:20 +053078/* RealTek RTL8211x */
79static int rtl8211x_config(struct phy_device *phydev)
Andy Fleming9082eea2011-04-07 21:56:05 -050080{
81 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
82
Codrin Ciubotariu3cee1382015-02-13 14:47:58 +020083 /* mask interrupt at init; if the interrupt is
84 * needed indeed, it should be explicitly enabled
85 */
86 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER,
87 MIIM_RTL8211x_PHY_INTR_DIS);
oliver@schinagl.nlcebf3f52016-11-08 17:38:59 +010088
89 if (phydev->flags & PHY_RTL8211x_FORCE_MASTER) {
90 unsigned int reg;
91
92 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
93 /* force manual master/slave configuration */
94 reg |= MIIM_RTL8211x_CTRL1000T_MSCE;
95 /* force master mode */
96 reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
97 phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
98 }
kevans@FreeBSD.org66526e72018-02-14 17:02:15 -060099 if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) {
100 unsigned int reg;
101
102 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
103 7);
104 phy_write(phydev, MDIO_DEVAD_NONE,
105 MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
106 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
107 /* Ensure both internal delays are turned off */
108 reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD);
109 /* Flip the magic undocumented bits */
110 reg |= MIIM_RTL8211E_CONFREG_MAGIC;
111 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg);
112 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
113 0);
114 }
Codrin Ciubotariu3cee1382015-02-13 14:47:58 +0200115 /* read interrupt status just to clear it */
116 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
117
Andy Fleming9082eea2011-04-07 21:56:05 -0500118 genphy_config_aneg(phydev);
119
120 return 0;
121}
122
Shengzhou Liu793ea942015-04-24 16:57:17 +0800123static int rtl8211f_config(struct phy_device *phydev)
124{
125 u16 reg;
126
127 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
128
Madalin Bucur05b29aa2017-08-18 11:35:24 +0300129 phy_write(phydev, MDIO_DEVAD_NONE,
130 MIIM_RTL8211F_PAGE_SELECT, 0xd08);
131 reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11);
132
133 /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
134 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
135 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
Shengzhou Liu793ea942015-04-24 16:57:17 +0800136 reg |= MIIM_RTL8211F_TX_DELAY;
Madalin Bucur05b29aa2017-08-18 11:35:24 +0300137 else
138 reg &= ~MIIM_RTL8211F_TX_DELAY;
139
140 phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg);
141 /* restore to default page 0 */
142 phy_write(phydev, MDIO_DEVAD_NONE,
143 MIIM_RTL8211F_PAGE_SELECT, 0x0);
Shengzhou Liu793ea942015-04-24 16:57:17 +0800144
Shengzhou Liu90712742015-05-21 18:07:35 +0800145 /* Set green LED for Link, yellow LED for Active */
146 phy_write(phydev, MDIO_DEVAD_NONE,
147 MIIM_RTL8211F_PAGE_SELECT, 0xd04);
148 phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
149 phy_write(phydev, MDIO_DEVAD_NONE,
150 MIIM_RTL8211F_PAGE_SELECT, 0x0);
151
Shengzhou Liu793ea942015-04-24 16:57:17 +0800152 genphy_config_aneg(phydev);
153
154 return 0;
155}
156
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530157static int rtl8211x_parse_status(struct phy_device *phydev)
Andy Fleming9082eea2011-04-07 21:56:05 -0500158{
159 unsigned int speed;
160 unsigned int mii_reg;
161
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530162 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
Andy Fleming9082eea2011-04-07 21:56:05 -0500163
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530164 if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
Andy Fleming9082eea2011-04-07 21:56:05 -0500165 int i = 0;
166
167 /* in case of timeout ->link is cleared */
168 phydev->link = 1;
169 puts("Waiting for PHY realtime link");
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530170 while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
Andy Fleming9082eea2011-04-07 21:56:05 -0500171 /* Timeout reached ? */
172 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
173 puts(" TIMEOUT !\n");
174 phydev->link = 0;
175 break;
176 }
177
178 if ((i++ % 1000) == 0)
179 putc('.');
180 udelay(1000); /* 1 ms */
181 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530182 MIIM_RTL8211x_PHY_STATUS);
Andy Fleming9082eea2011-04-07 21:56:05 -0500183 }
184 puts(" done\n");
185 udelay(500000); /* another 500 ms (results in faster booting) */
186 } else {
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530187 if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
Andy Fleming9082eea2011-04-07 21:56:05 -0500188 phydev->link = 1;
189 else
190 phydev->link = 0;
191 }
192
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530193 if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
Andy Fleming9082eea2011-04-07 21:56:05 -0500194 phydev->duplex = DUPLEX_FULL;
195 else
196 phydev->duplex = DUPLEX_HALF;
197
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530198 speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
Andy Fleming9082eea2011-04-07 21:56:05 -0500199
200 switch (speed) {
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530201 case MIIM_RTL8211x_PHYSTAT_GBIT:
Andy Fleming9082eea2011-04-07 21:56:05 -0500202 phydev->speed = SPEED_1000;
203 break;
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530204 case MIIM_RTL8211x_PHYSTAT_100:
Andy Fleming9082eea2011-04-07 21:56:05 -0500205 phydev->speed = SPEED_100;
206 break;
207 default:
208 phydev->speed = SPEED_10;
209 }
210
211 return 0;
212}
213
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800214static int rtl8211f_parse_status(struct phy_device *phydev)
215{
216 unsigned int speed;
217 unsigned int mii_reg;
218 int i = 0;
219
220 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43);
221 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS);
222
223 phydev->link = 1;
224 while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) {
225 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
226 puts(" TIMEOUT !\n");
227 phydev->link = 0;
228 break;
229 }
230
231 if ((i++ % 1000) == 0)
232 putc('.');
233 udelay(1000);
234 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
235 MIIM_RTL8211F_PHY_STATUS);
236 }
237
238 if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX)
239 phydev->duplex = DUPLEX_FULL;
240 else
241 phydev->duplex = DUPLEX_HALF;
242
243 speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED);
244
245 switch (speed) {
246 case MIIM_RTL8211F_PHYSTAT_GBIT:
247 phydev->speed = SPEED_1000;
248 break;
249 case MIIM_RTL8211F_PHYSTAT_100:
250 phydev->speed = SPEED_100;
251 break;
252 default:
253 phydev->speed = SPEED_10;
254 }
255
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800256 return 0;
257}
258
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530259static int rtl8211x_startup(struct phy_device *phydev)
Andy Fleming9082eea2011-04-07 21:56:05 -0500260{
Michal Simekb733c272016-05-18 12:46:12 +0200261 int ret;
Andy Fleming9082eea2011-04-07 21:56:05 -0500262
Michal Simekb733c272016-05-18 12:46:12 +0200263 /* Read the Status (2x to make sure link is right) */
264 ret = genphy_update_link(phydev);
265 if (ret)
266 return ret;
267
268 return rtl8211x_parse_status(phydev);
Andy Fleming9082eea2011-04-07 21:56:05 -0500269}
270
Michal Simek6a10bc52016-02-13 10:31:32 +0100271static int rtl8211e_startup(struct phy_device *phydev)
272{
Michal Simekb733c272016-05-18 12:46:12 +0200273 int ret;
Michal Simek6a10bc52016-02-13 10:31:32 +0100274
Michal Simekb733c272016-05-18 12:46:12 +0200275 ret = genphy_update_link(phydev);
276 if (ret)
277 return ret;
278
279 return genphy_parse_link(phydev);
Michal Simek6a10bc52016-02-13 10:31:32 +0100280}
281
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800282static int rtl8211f_startup(struct phy_device *phydev)
283{
Michal Simekb733c272016-05-18 12:46:12 +0200284 int ret;
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800285
Michal Simekb733c272016-05-18 12:46:12 +0200286 /* Read the Status (2x to make sure link is right) */
287 ret = genphy_update_link(phydev);
288 if (ret)
289 return ret;
290 /* Read the Status (2x to make sure link is right) */
291
292 return rtl8211f_parse_status(phydev);
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800293}
294
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530295/* Support for RTL8211B PHY */
Andy Fleming9082eea2011-04-07 21:56:05 -0500296static struct phy_driver RTL8211B_driver = {
297 .name = "RealTek RTL8211B",
Karsten Merker563d8d92016-03-21 20:29:07 +0100298 .uid = 0x1cc912,
Bhupesh Sharma42205042013-09-01 04:40:52 +0530299 .mask = 0xffffff,
Andy Fleming9082eea2011-04-07 21:56:05 -0500300 .features = PHY_GBIT_FEATURES,
oliver@schinagl.nlcebf3f52016-11-08 17:38:59 +0100301 .probe = &rtl8211b_probe,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530302 .config = &rtl8211x_config,
303 .startup = &rtl8211x_startup,
304 .shutdown = &genphy_shutdown,
305};
306
307/* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
308static struct phy_driver RTL8211E_driver = {
309 .name = "RealTek RTL8211E",
310 .uid = 0x1cc915,
Bhupesh Sharma42205042013-09-01 04:40:52 +0530311 .mask = 0xffffff,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530312 .features = PHY_GBIT_FEATURES,
kevans@FreeBSD.org66526e72018-02-14 17:02:15 -0600313 .probe = &rtl8211e_probe,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530314 .config = &rtl8211x_config,
Michal Simek6a10bc52016-02-13 10:31:32 +0100315 .startup = &rtl8211e_startup,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530316 .shutdown = &genphy_shutdown,
317};
318
319/* Support for RTL8211DN PHY */
320static struct phy_driver RTL8211DN_driver = {
321 .name = "RealTek RTL8211DN",
322 .uid = 0x1cc914,
Bhupesh Sharma42205042013-09-01 04:40:52 +0530323 .mask = 0xffffff,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530324 .features = PHY_GBIT_FEATURES,
325 .config = &rtl8211x_config,
326 .startup = &rtl8211x_startup,
Andy Fleming9082eea2011-04-07 21:56:05 -0500327 .shutdown = &genphy_shutdown,
328};
329
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800330/* Support for RTL8211F PHY */
331static struct phy_driver RTL8211F_driver = {
332 .name = "RealTek RTL8211F",
333 .uid = 0x1cc916,
334 .mask = 0xffffff,
335 .features = PHY_GBIT_FEATURES,
Shengzhou Liu793ea942015-04-24 16:57:17 +0800336 .config = &rtl8211f_config,
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800337 .startup = &rtl8211f_startup,
338 .shutdown = &genphy_shutdown,
339};
340
Andy Fleming9082eea2011-04-07 21:56:05 -0500341int phy_realtek_init(void)
342{
343 phy_register(&RTL8211B_driver);
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530344 phy_register(&RTL8211E_driver);
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800345 phy_register(&RTL8211F_driver);
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530346 phy_register(&RTL8211DN_driver);
Andy Fleming9082eea2011-04-07 21:56:05 -0500347
348 return 0;
349}