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