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