blob: bba48da4099fda91558008d77e19bf373cfc7341 [file] [log] [blame]
Andy Fleming9082eea2011-04-07 21:56:05 -05001/*
2 * RealTek PHY drivers
3 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02004 * SPDX-License-Identifier: GPL-2.0+
Andy Fleming9082eea2011-04-07 21:56:05 -05005 *
Codrin Ciubotariu3cee1382015-02-13 14:47:58 +02006 * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc.
Andy Fleming9082eea2011-04-07 21:56:05 -05007 * author Andy Fleming
Andy Fleming9082eea2011-04-07 21:56:05 -05008 */
9#include <config.h>
10#include <common.h>
11#include <phy.h>
12
13#define PHY_AUTONEGOTIATE_TIMEOUT 5000
14
Bhupesh Sharmac624d162013-07-18 13:58:20 +053015/* 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
Andy Fleming9082eea2011-04-07 21:56:05 -050023
Codrin Ciubotariu3cee1382015-02-13 14:47:58 +020024/* 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
Andy Fleming9082eea2011-04-07 21:56:05 -050031
Shengzhou Liu3d6af742015-03-12 18:54:59 +080032/* 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
Shengzhou Liu793ea942015-04-24 16:57:17 +080043#define MIIM_RTL8211F_TX_DELAY 0x100
Shengzhou Liu90712742015-05-21 18:07:35 +080044#define MIIM_RTL8211F_LCR 0x10
Shengzhou Liu3d6af742015-03-12 18:54:59 +080045
Bhupesh Sharmac624d162013-07-18 13:58:20 +053046/* RealTek RTL8211x */
47static int rtl8211x_config(struct phy_device *phydev)
Andy Fleming9082eea2011-04-07 21:56:05 -050048{
49 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
50
Codrin Ciubotariu3cee1382015-02-13 14:47:58 +020051 /* 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
Andy Fleming9082eea2011-04-07 21:56:05 -050060 genphy_config_aneg(phydev);
61
62 return 0;
63}
64
Shengzhou Liu793ea942015-04-24 16:57:17 +080065static 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
Shengzhou Liu90712742015-05-21 18:07:35 +080083 /* 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
Shengzhou Liu793ea942015-04-24 16:57:17 +080090 genphy_config_aneg(phydev);
91
92 return 0;
93}
94
Bhupesh Sharmac624d162013-07-18 13:58:20 +053095static int rtl8211x_parse_status(struct phy_device *phydev)
Andy Fleming9082eea2011-04-07 21:56:05 -050096{
97 unsigned int speed;
98 unsigned int mii_reg;
99
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530100 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
Andy Fleming9082eea2011-04-07 21:56:05 -0500101
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530102 if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
Andy Fleming9082eea2011-04-07 21:56:05 -0500103 int i = 0;
104
105 /* in case of timeout ->link is cleared */
106 phydev->link = 1;
107 puts("Waiting for PHY realtime link");
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530108 while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
Andy Fleming9082eea2011-04-07 21:56:05 -0500109 /* 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,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530120 MIIM_RTL8211x_PHY_STATUS);
Andy Fleming9082eea2011-04-07 21:56:05 -0500121 }
122 puts(" done\n");
123 udelay(500000); /* another 500 ms (results in faster booting) */
124 } else {
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530125 if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
Andy Fleming9082eea2011-04-07 21:56:05 -0500126 phydev->link = 1;
127 else
128 phydev->link = 0;
129 }
130
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530131 if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
Andy Fleming9082eea2011-04-07 21:56:05 -0500132 phydev->duplex = DUPLEX_FULL;
133 else
134 phydev->duplex = DUPLEX_HALF;
135
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530136 speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
Andy Fleming9082eea2011-04-07 21:56:05 -0500137
138 switch (speed) {
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530139 case MIIM_RTL8211x_PHYSTAT_GBIT:
Andy Fleming9082eea2011-04-07 21:56:05 -0500140 phydev->speed = SPEED_1000;
141 break;
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530142 case MIIM_RTL8211x_PHYSTAT_100:
Andy Fleming9082eea2011-04-07 21:56:05 -0500143 phydev->speed = SPEED_100;
144 break;
145 default:
146 phydev->speed = SPEED_10;
147 }
148
149 return 0;
150}
151
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800152static 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
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800194 return 0;
195}
196
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530197static int rtl8211x_startup(struct phy_device *phydev)
Andy Fleming9082eea2011-04-07 21:56:05 -0500198{
199 /* Read the Status (2x to make sure link is right) */
200 genphy_update_link(phydev);
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530201 rtl8211x_parse_status(phydev);
Andy Fleming9082eea2011-04-07 21:56:05 -0500202
203 return 0;
204}
205
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800206static 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
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530215/* Support for RTL8211B PHY */
Andy Fleming9082eea2011-04-07 21:56:05 -0500216static struct phy_driver RTL8211B_driver = {
217 .name = "RealTek RTL8211B",
218 .uid = 0x1cc910,
Bhupesh Sharma42205042013-09-01 04:40:52 +0530219 .mask = 0xffffff,
Andy Fleming9082eea2011-04-07 21:56:05 -0500220 .features = PHY_GBIT_FEATURES,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530221 .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 */
227static struct phy_driver RTL8211E_driver = {
228 .name = "RealTek RTL8211E",
229 .uid = 0x1cc915,
Bhupesh Sharma42205042013-09-01 04:40:52 +0530230 .mask = 0xffffff,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530231 .features = PHY_GBIT_FEATURES,
232 .config = &rtl8211x_config,
233 .startup = &rtl8211x_startup,
234 .shutdown = &genphy_shutdown,
235};
236
237/* Support for RTL8211DN PHY */
238static struct phy_driver RTL8211DN_driver = {
239 .name = "RealTek RTL8211DN",
240 .uid = 0x1cc914,
Bhupesh Sharma42205042013-09-01 04:40:52 +0530241 .mask = 0xffffff,
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530242 .features = PHY_GBIT_FEATURES,
243 .config = &rtl8211x_config,
244 .startup = &rtl8211x_startup,
Andy Fleming9082eea2011-04-07 21:56:05 -0500245 .shutdown = &genphy_shutdown,
246};
247
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800248/* Support for RTL8211F PHY */
249static struct phy_driver RTL8211F_driver = {
250 .name = "RealTek RTL8211F",
251 .uid = 0x1cc916,
252 .mask = 0xffffff,
253 .features = PHY_GBIT_FEATURES,
Shengzhou Liu793ea942015-04-24 16:57:17 +0800254 .config = &rtl8211f_config,
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800255 .startup = &rtl8211f_startup,
256 .shutdown = &genphy_shutdown,
257};
258
Andy Fleming9082eea2011-04-07 21:56:05 -0500259int phy_realtek_init(void)
260{
261 phy_register(&RTL8211B_driver);
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530262 phy_register(&RTL8211E_driver);
Shengzhou Liu3d6af742015-03-12 18:54:59 +0800263 phy_register(&RTL8211F_driver);
Bhupesh Sharmac624d162013-07-18 13:58:20 +0530264 phy_register(&RTL8211DN_driver);
Andy Fleming9082eea2011-04-07 21:56:05 -0500265
266 return 0;
267}