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 45 /* RealTek RTL8211x */ 46 static int rtl8211x_config(struct phy_device *phydev) 47 { 48 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 49 50 /* mask interrupt at init; if the interrupt is 51 * needed indeed, it should be explicitly enabled 52 */ 53 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER, 54 MIIM_RTL8211x_PHY_INTR_DIS); 55 56 /* read interrupt status just to clear it */ 57 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER); 58 59 genphy_config_aneg(phydev); 60 61 return 0; 62 } 63 64 static int rtl8211f_config(struct phy_device *phydev) 65 { 66 u16 reg; 67 68 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 69 70 if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { 71 /* enable TXDLY */ 72 phy_write(phydev, MDIO_DEVAD_NONE, 73 MIIM_RTL8211F_PAGE_SELECT, 0xd08); 74 reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11); 75 reg |= MIIM_RTL8211F_TX_DELAY; 76 phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg); 77 /* restore to default page 0 */ 78 phy_write(phydev, MDIO_DEVAD_NONE, 79 MIIM_RTL8211F_PAGE_SELECT, 0x0); 80 } 81 82 genphy_config_aneg(phydev); 83 84 return 0; 85 } 86 87 static int rtl8211x_parse_status(struct phy_device *phydev) 88 { 89 unsigned int speed; 90 unsigned int mii_reg; 91 92 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS); 93 94 if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { 95 int i = 0; 96 97 /* in case of timeout ->link is cleared */ 98 phydev->link = 1; 99 puts("Waiting for PHY realtime link"); 100 while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) { 101 /* Timeout reached ? */ 102 if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 103 puts(" TIMEOUT !\n"); 104 phydev->link = 0; 105 break; 106 } 107 108 if ((i++ % 1000) == 0) 109 putc('.'); 110 udelay(1000); /* 1 ms */ 111 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 112 MIIM_RTL8211x_PHY_STATUS); 113 } 114 puts(" done\n"); 115 udelay(500000); /* another 500 ms (results in faster booting) */ 116 } else { 117 if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK) 118 phydev->link = 1; 119 else 120 phydev->link = 0; 121 } 122 123 if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX) 124 phydev->duplex = DUPLEX_FULL; 125 else 126 phydev->duplex = DUPLEX_HALF; 127 128 speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED); 129 130 switch (speed) { 131 case MIIM_RTL8211x_PHYSTAT_GBIT: 132 phydev->speed = SPEED_1000; 133 break; 134 case MIIM_RTL8211x_PHYSTAT_100: 135 phydev->speed = SPEED_100; 136 break; 137 default: 138 phydev->speed = SPEED_10; 139 } 140 141 return 0; 142 } 143 144 static int rtl8211f_parse_status(struct phy_device *phydev) 145 { 146 unsigned int speed; 147 unsigned int mii_reg; 148 int i = 0; 149 150 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43); 151 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS); 152 153 phydev->link = 1; 154 while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) { 155 if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 156 puts(" TIMEOUT !\n"); 157 phydev->link = 0; 158 break; 159 } 160 161 if ((i++ % 1000) == 0) 162 putc('.'); 163 udelay(1000); 164 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 165 MIIM_RTL8211F_PHY_STATUS); 166 } 167 168 if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX) 169 phydev->duplex = DUPLEX_FULL; 170 else 171 phydev->duplex = DUPLEX_HALF; 172 173 speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED); 174 175 switch (speed) { 176 case MIIM_RTL8211F_PHYSTAT_GBIT: 177 phydev->speed = SPEED_1000; 178 break; 179 case MIIM_RTL8211F_PHYSTAT_100: 180 phydev->speed = SPEED_100; 181 break; 182 default: 183 phydev->speed = SPEED_10; 184 } 185 186 return 0; 187 } 188 189 static int rtl8211x_startup(struct phy_device *phydev) 190 { 191 /* Read the Status (2x to make sure link is right) */ 192 genphy_update_link(phydev); 193 rtl8211x_parse_status(phydev); 194 195 return 0; 196 } 197 198 static int rtl8211f_startup(struct phy_device *phydev) 199 { 200 /* Read the Status (2x to make sure link is right) */ 201 genphy_update_link(phydev); 202 rtl8211f_parse_status(phydev); 203 204 return 0; 205 } 206 207 /* Support for RTL8211B PHY */ 208 static struct phy_driver RTL8211B_driver = { 209 .name = "RealTek RTL8211B", 210 .uid = 0x1cc910, 211 .mask = 0xffffff, 212 .features = PHY_GBIT_FEATURES, 213 .config = &rtl8211x_config, 214 .startup = &rtl8211x_startup, 215 .shutdown = &genphy_shutdown, 216 }; 217 218 /* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */ 219 static struct phy_driver RTL8211E_driver = { 220 .name = "RealTek RTL8211E", 221 .uid = 0x1cc915, 222 .mask = 0xffffff, 223 .features = PHY_GBIT_FEATURES, 224 .config = &rtl8211x_config, 225 .startup = &rtl8211x_startup, 226 .shutdown = &genphy_shutdown, 227 }; 228 229 /* Support for RTL8211DN PHY */ 230 static struct phy_driver RTL8211DN_driver = { 231 .name = "RealTek RTL8211DN", 232 .uid = 0x1cc914, 233 .mask = 0xffffff, 234 .features = PHY_GBIT_FEATURES, 235 .config = &rtl8211x_config, 236 .startup = &rtl8211x_startup, 237 .shutdown = &genphy_shutdown, 238 }; 239 240 /* Support for RTL8211F PHY */ 241 static struct phy_driver RTL8211F_driver = { 242 .name = "RealTek RTL8211F", 243 .uid = 0x1cc916, 244 .mask = 0xffffff, 245 .features = PHY_GBIT_FEATURES, 246 .config = &rtl8211f_config, 247 .startup = &rtl8211f_startup, 248 .shutdown = &genphy_shutdown, 249 }; 250 251 int phy_realtek_init(void) 252 { 253 phy_register(&RTL8211B_driver); 254 phy_register(&RTL8211E_driver); 255 phy_register(&RTL8211F_driver); 256 phy_register(&RTL8211DN_driver); 257 258 return 0; 259 } 260