blob: 635acf5844e3e73c89b751a6f820b6949fb6affb [file] [log] [blame]
Andy Fleming60ca78b2011-04-07 21:56:05 -05001/*
2 * RealTek PHY drivers
3 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02004 * SPDX-License-Identifier: GPL-2.0+
Andy Fleming60ca78b2011-04-07 21:56:05 -05005 *
Codrin Ciubotariude947a12015-02-13 14:47:58 +02006 * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc.
Andy Fleming60ca78b2011-04-07 21:56:05 -05007 * author Andy Fleming
Karsten Merker10800de2016-03-21 20:29:07 +01008 * Copyright 2016 Karsten Merker <merker@debian.org>
Andy Fleming60ca78b2011-04-07 21:56:05 -05009 */
10#include <config.h>
11#include <common.h>
oliver@schinagl.nlec1b26f2016-11-08 17:38:57 +010012#include <linux/bitops.h>
Andy Fleming60ca78b2011-04-07 21:56:05 -050013#include <phy.h>
14
oliver@schinagl.nl6a250902016-11-08 17:38:59 +010015#define PHY_RTL8211x_FORCE_MASTER BIT(1)
16
Andy Fleming60ca78b2011-04-07 21:56:05 -050017#define PHY_AUTONEGOTIATE_TIMEOUT 5000
18
Michael Haas0cf2b4e2016-03-25 18:22:50 +010019/* RTL8211x 1000BASE-T Control Register */
oliver@schinagl.nlec1b26f2016-11-08 17:38:57 +010020#define MIIM_RTL8211x_CTRL1000T_MSCE BIT(12);
oliver@schinagl.nl1beb7352016-11-08 17:38:58 +010021#define MIIM_RTL8211x_CTRL1000T_MASTER BIT(11);
Michael Haas0cf2b4e2016-03-25 18:22:50 +010022
Bhupesh Sharma85eb7802013-07-18 13:58:20 +053023/* RTL8211x PHY Status Register */
24#define MIIM_RTL8211x_PHY_STATUS 0x11
25#define MIIM_RTL8211x_PHYSTAT_SPEED 0xc000
26#define MIIM_RTL8211x_PHYSTAT_GBIT 0x8000
27#define MIIM_RTL8211x_PHYSTAT_100 0x4000
28#define MIIM_RTL8211x_PHYSTAT_DUPLEX 0x2000
29#define MIIM_RTL8211x_PHYSTAT_SPDDONE 0x0800
30#define MIIM_RTL8211x_PHYSTAT_LINK 0x0400
Andy Fleming60ca78b2011-04-07 21:56:05 -050031
Codrin Ciubotariude947a12015-02-13 14:47:58 +020032/* RTL8211x PHY Interrupt Enable Register */
33#define MIIM_RTL8211x_PHY_INER 0x12
34#define MIIM_RTL8211x_PHY_INTR_ENA 0x9f01
35#define MIIM_RTL8211x_PHY_INTR_DIS 0x0000
36
37/* RTL8211x PHY Interrupt Status Register */
38#define MIIM_RTL8211x_PHY_INSR 0x13
Andy Fleming60ca78b2011-04-07 21:56:05 -050039
Shengzhou Liu210f17f2015-03-12 18:54:59 +080040/* RTL8211F PHY Status Register */
41#define MIIM_RTL8211F_PHY_STATUS 0x1a
42#define MIIM_RTL8211F_AUTONEG_ENABLE 0x1000
43#define MIIM_RTL8211F_PHYSTAT_SPEED 0x0030
44#define MIIM_RTL8211F_PHYSTAT_GBIT 0x0020
45#define MIIM_RTL8211F_PHYSTAT_100 0x0010
46#define MIIM_RTL8211F_PHYSTAT_DUPLEX 0x0008
47#define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800
48#define MIIM_RTL8211F_PHYSTAT_LINK 0x0004
49
50#define MIIM_RTL8211F_PAGE_SELECT 0x1f
Shengzhou Liu67500892015-04-24 16:57:17 +080051#define MIIM_RTL8211F_TX_DELAY 0x100
Shengzhou Liu5487fc62015-05-21 18:07:35 +080052#define MIIM_RTL8211F_LCR 0x10
Shengzhou Liu210f17f2015-03-12 18:54:59 +080053
oliver@schinagl.nl6a250902016-11-08 17:38:59 +010054static int rtl8211b_probe(struct phy_device *phydev)
55{
56#ifdef CONFIG_RTL8211X_PHY_FORCE_MASTER
57 phydev->flags |= PHY_RTL8211x_FORCE_MASTER;
58#endif
59
60 return 0;
61}
62
Bhupesh Sharma85eb7802013-07-18 13:58:20 +053063/* RealTek RTL8211x */
64static int rtl8211x_config(struct phy_device *phydev)
Andy Fleming60ca78b2011-04-07 21:56:05 -050065{
66 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
67
Codrin Ciubotariude947a12015-02-13 14:47:58 +020068 /* mask interrupt at init; if the interrupt is
69 * needed indeed, it should be explicitly enabled
70 */
71 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER,
72 MIIM_RTL8211x_PHY_INTR_DIS);
oliver@schinagl.nl6a250902016-11-08 17:38:59 +010073
74 if (phydev->flags & PHY_RTL8211x_FORCE_MASTER) {
75 unsigned int reg;
76
77 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
78 /* force manual master/slave configuration */
79 reg |= MIIM_RTL8211x_CTRL1000T_MSCE;
80 /* force master mode */
81 reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
82 phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
83 }
Codrin Ciubotariude947a12015-02-13 14:47:58 +020084 /* read interrupt status just to clear it */
85 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
86
Andy Fleming60ca78b2011-04-07 21:56:05 -050087 genphy_config_aneg(phydev);
88
89 return 0;
90}
91
Shengzhou Liu67500892015-04-24 16:57:17 +080092static int rtl8211f_config(struct phy_device *phydev)
93{
94 u16 reg;
95
96 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
97
98 if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
99 /* enable TXDLY */
100 phy_write(phydev, MDIO_DEVAD_NONE,
101 MIIM_RTL8211F_PAGE_SELECT, 0xd08);
102 reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11);
103 reg |= MIIM_RTL8211F_TX_DELAY;
104 phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg);
105 /* restore to default page 0 */
106 phy_write(phydev, MDIO_DEVAD_NONE,
107 MIIM_RTL8211F_PAGE_SELECT, 0x0);
108 }
109
Shengzhou Liu5487fc62015-05-21 18:07:35 +0800110 /* Set green LED for Link, yellow LED for Active */
111 phy_write(phydev, MDIO_DEVAD_NONE,
112 MIIM_RTL8211F_PAGE_SELECT, 0xd04);
113 phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
114 phy_write(phydev, MDIO_DEVAD_NONE,
115 MIIM_RTL8211F_PAGE_SELECT, 0x0);
116
Shengzhou Liu67500892015-04-24 16:57:17 +0800117 genphy_config_aneg(phydev);
118
119 return 0;
120}
121
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530122static int rtl8211x_parse_status(struct phy_device *phydev)
Andy Fleming60ca78b2011-04-07 21:56:05 -0500123{
124 unsigned int speed;
125 unsigned int mii_reg;
126
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530127 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500128
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530129 if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500130 int i = 0;
131
132 /* in case of timeout ->link is cleared */
133 phydev->link = 1;
134 puts("Waiting for PHY realtime link");
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530135 while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500136 /* Timeout reached ? */
137 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
138 puts(" TIMEOUT !\n");
139 phydev->link = 0;
140 break;
141 }
142
143 if ((i++ % 1000) == 0)
144 putc('.');
145 udelay(1000); /* 1 ms */
146 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530147 MIIM_RTL8211x_PHY_STATUS);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500148 }
149 puts(" done\n");
150 udelay(500000); /* another 500 ms (results in faster booting) */
151 } else {
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530152 if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
Andy Fleming60ca78b2011-04-07 21:56:05 -0500153 phydev->link = 1;
154 else
155 phydev->link = 0;
156 }
157
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530158 if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
Andy Fleming60ca78b2011-04-07 21:56:05 -0500159 phydev->duplex = DUPLEX_FULL;
160 else
161 phydev->duplex = DUPLEX_HALF;
162
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530163 speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500164
165 switch (speed) {
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530166 case MIIM_RTL8211x_PHYSTAT_GBIT:
Andy Fleming60ca78b2011-04-07 21:56:05 -0500167 phydev->speed = SPEED_1000;
168 break;
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530169 case MIIM_RTL8211x_PHYSTAT_100:
Andy Fleming60ca78b2011-04-07 21:56:05 -0500170 phydev->speed = SPEED_100;
171 break;
172 default:
173 phydev->speed = SPEED_10;
174 }
175
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800176 return 0;
177}
178
179static int rtl8211f_parse_status(struct phy_device *phydev)
180{
181 unsigned int speed;
182 unsigned int mii_reg;
183 int i = 0;
184
185 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43);
186 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS);
187
188 phydev->link = 1;
189 while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) {
190 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
191 puts(" TIMEOUT !\n");
192 phydev->link = 0;
193 break;
194 }
195
196 if ((i++ % 1000) == 0)
197 putc('.');
198 udelay(1000);
199 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
200 MIIM_RTL8211F_PHY_STATUS);
201 }
202
203 if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX)
204 phydev->duplex = DUPLEX_FULL;
205 else
206 phydev->duplex = DUPLEX_HALF;
207
208 speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED);
209
210 switch (speed) {
211 case MIIM_RTL8211F_PHYSTAT_GBIT:
212 phydev->speed = SPEED_1000;
213 break;
214 case MIIM_RTL8211F_PHYSTAT_100:
215 phydev->speed = SPEED_100;
216 break;
217 default:
218 phydev->speed = SPEED_10;
219 }
220
Andy Fleming60ca78b2011-04-07 21:56:05 -0500221 return 0;
222}
223
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530224static int rtl8211x_startup(struct phy_device *phydev)
Andy Fleming60ca78b2011-04-07 21:56:05 -0500225{
Michal Simek5ff89662016-05-18 12:46:12 +0200226 int ret;
227
Andy Fleming60ca78b2011-04-07 21:56:05 -0500228 /* Read the Status (2x to make sure link is right) */
Michal Simek5ff89662016-05-18 12:46:12 +0200229 ret = genphy_update_link(phydev);
230 if (ret)
231 return ret;
Andy Fleming60ca78b2011-04-07 21:56:05 -0500232
Michal Simek5ff89662016-05-18 12:46:12 +0200233 return rtl8211x_parse_status(phydev);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500234}
235
Michal Simekbdf0b722016-02-13 10:31:32 +0100236static int rtl8211e_startup(struct phy_device *phydev)
237{
Michal Simek5ff89662016-05-18 12:46:12 +0200238 int ret;
239
240 ret = genphy_update_link(phydev);
241 if (ret)
242 return ret;
Michal Simekbdf0b722016-02-13 10:31:32 +0100243
Michal Simek5ff89662016-05-18 12:46:12 +0200244 return genphy_parse_link(phydev);
Michal Simekbdf0b722016-02-13 10:31:32 +0100245}
246
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800247static int rtl8211f_startup(struct phy_device *phydev)
248{
Michal Simek5ff89662016-05-18 12:46:12 +0200249 int ret;
250
251 /* Read the Status (2x to make sure link is right) */
252 ret = genphy_update_link(phydev);
253 if (ret)
254 return ret;
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800255 /* Read the Status (2x to make sure link is right) */
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800256
Michal Simek5ff89662016-05-18 12:46:12 +0200257 return rtl8211f_parse_status(phydev);
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800258}
259
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530260/* Support for RTL8211B PHY */
Andy Fleming60ca78b2011-04-07 21:56:05 -0500261static struct phy_driver RTL8211B_driver = {
262 .name = "RealTek RTL8211B",
Karsten Merker10800de2016-03-21 20:29:07 +0100263 .uid = 0x1cc912,
Bhupesh Sharmaad4cd952013-09-01 04:40:52 +0530264 .mask = 0xffffff,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500265 .features = PHY_GBIT_FEATURES,
oliver@schinagl.nl6a250902016-11-08 17:38:59 +0100266 .probe = &rtl8211b_probe,
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530267 .config = &rtl8211x_config,
268 .startup = &rtl8211x_startup,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500269 .shutdown = &genphy_shutdown,
270};
271
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530272/* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
273static struct phy_driver RTL8211E_driver = {
274 .name = "RealTek RTL8211E",
275 .uid = 0x1cc915,
Bhupesh Sharmaad4cd952013-09-01 04:40:52 +0530276 .mask = 0xffffff,
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530277 .features = PHY_GBIT_FEATURES,
278 .config = &rtl8211x_config,
Michal Simekbdf0b722016-02-13 10:31:32 +0100279 .startup = &rtl8211e_startup,
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530280 .shutdown = &genphy_shutdown,
281};
282
283/* Support for RTL8211DN PHY */
284static struct phy_driver RTL8211DN_driver = {
285 .name = "RealTek RTL8211DN",
286 .uid = 0x1cc914,
Bhupesh Sharmaad4cd952013-09-01 04:40:52 +0530287 .mask = 0xffffff,
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530288 .features = PHY_GBIT_FEATURES,
289 .config = &rtl8211x_config,
290 .startup = &rtl8211x_startup,
291 .shutdown = &genphy_shutdown,
292};
293
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800294/* Support for RTL8211F PHY */
295static struct phy_driver RTL8211F_driver = {
296 .name = "RealTek RTL8211F",
297 .uid = 0x1cc916,
298 .mask = 0xffffff,
299 .features = PHY_GBIT_FEATURES,
Shengzhou Liu67500892015-04-24 16:57:17 +0800300 .config = &rtl8211f_config,
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800301 .startup = &rtl8211f_startup,
302 .shutdown = &genphy_shutdown,
303};
304
Andy Fleming60ca78b2011-04-07 21:56:05 -0500305int phy_realtek_init(void)
306{
307 phy_register(&RTL8211B_driver);
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530308 phy_register(&RTL8211E_driver);
Shengzhou Liu210f17f2015-03-12 18:54:59 +0800309 phy_register(&RTL8211F_driver);
Bhupesh Sharma85eb7802013-07-18 13:58:20 +0530310 phy_register(&RTL8211DN_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500311
312 return 0;
313}