1 /* 2 * Marvell PHY drivers 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of 7 * the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 * MA 02111-1307 USA 18 * 19 * Copyright 2010-2011 Freescale Semiconductor, Inc. 20 * author Andy Fleming 21 * 22 */ 23 #include <config.h> 24 #include <common.h> 25 #include <phy.h> 26 27 #define PHY_AUTONEGOTIATE_TIMEOUT 5000 28 29 /* 88E1011 PHY Status Register */ 30 #define MIIM_88E1xxx_PHY_STATUS 0x11 31 #define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000 32 #define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000 33 #define MIIM_88E1xxx_PHYSTAT_100 0x4000 34 #define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000 35 #define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800 36 #define MIIM_88E1xxx_PHYSTAT_LINK 0x0400 37 38 #define MIIM_88E1xxx_PHY_SCR 0x10 39 #define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060 40 41 /* 88E1111 PHY LED Control Register */ 42 #define MIIM_88E1111_PHY_LED_CONTROL 24 43 #define MIIM_88E1111_PHY_LED_DIRECT 0x4100 44 #define MIIM_88E1111_PHY_LED_COMBINE 0x411C 45 46 /* 88E1118 PHY defines */ 47 #define MIIM_88E1118_PHY_PAGE 22 48 #define MIIM_88E1118_PHY_LED_PAGE 3 49 50 /* 88E1121 PHY LED Control Register */ 51 #define MIIM_88E1121_PHY_LED_CTRL 16 52 #define MIIM_88E1121_PHY_LED_PAGE 3 53 #define MIIM_88E1121_PHY_LED_DEF 0x0030 54 55 /* 88E1121 PHY IRQ Enable/Status Register */ 56 #define MIIM_88E1121_PHY_IRQ_EN 18 57 #define MIIM_88E1121_PHY_IRQ_STATUS 19 58 59 #define MIIM_88E1121_PHY_PAGE 22 60 61 /* 88E1145 Extended PHY Specific Control Register */ 62 #define MIIM_88E1145_PHY_EXT_CR 20 63 #define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 64 #define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 65 66 #define MIIM_88E1145_PHY_LED_CONTROL 24 67 #define MIIM_88E1145_PHY_LED_DIRECT 0x4100 68 69 #define MIIM_88E1145_PHY_PAGE 29 70 #define MIIM_88E1145_PHY_CAL_OV 30 71 72 #define MIIM_88E1149_PHY_PAGE 29 73 74 /* Marvell 88E1011S */ 75 static int m88e1011s_config(struct phy_device *phydev) 76 { 77 /* Reset and configure the PHY */ 78 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 79 80 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); 81 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); 82 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); 83 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0); 84 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 85 86 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 87 88 genphy_config_aneg(phydev); 89 90 return 0; 91 } 92 93 /* Parse the 88E1011's status register for speed and duplex 94 * information 95 */ 96 static uint m88e1xxx_parse_status(struct phy_device *phydev) 97 { 98 unsigned int speed; 99 unsigned int mii_reg; 100 101 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS); 102 103 if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) && 104 !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { 105 int i = 0; 106 107 puts("Waiting for PHY realtime link"); 108 while (!(mii_reg & MIIM_88E1xxx_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); 119 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 120 MIIM_88E1xxx_PHY_STATUS); 121 } 122 puts(" done\n"); 123 udelay(500000); /* another 500 ms (results in faster booting) */ 124 } else { 125 if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) 126 phydev->link = 1; 127 else 128 phydev->link = 0; 129 } 130 131 if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX) 132 phydev->duplex = DUPLEX_FULL; 133 else 134 phydev->duplex = DUPLEX_HALF; 135 136 speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED; 137 138 switch (speed) { 139 case MIIM_88E1xxx_PHYSTAT_GBIT: 140 phydev->speed = SPEED_1000; 141 break; 142 case MIIM_88E1xxx_PHYSTAT_100: 143 phydev->speed = SPEED_100; 144 break; 145 default: 146 phydev->speed = SPEED_10; 147 break; 148 } 149 150 return 0; 151 } 152 153 static int m88e1011s_startup(struct phy_device *phydev) 154 { 155 genphy_update_link(phydev); 156 m88e1xxx_parse_status(phydev); 157 158 return 0; 159 } 160 161 /* Marvell 88E1111S */ 162 static int m88e1111s_config(struct phy_device *phydev) 163 { 164 int reg; 165 166 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 167 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || 168 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || 169 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { 170 reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x1b); 171 reg = (reg & 0xfff0) | 0xb; 172 phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, reg); 173 } else { 174 phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, 0x1f); 175 } 176 177 phy_write(phydev, MDIO_DEVAD_NONE, 0x14, 0x0cd2); 178 179 genphy_config_aneg(phydev); 180 181 phy_reset(phydev); 182 183 return 0; 184 } 185 186 /* Marvell 88E1118 */ 187 static int m88e1118_config(struct phy_device *phydev) 188 { 189 /* Change Page Number */ 190 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002); 191 /* Delay RGMII TX and RX */ 192 phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); 193 /* Change Page Number */ 194 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003); 195 /* Adjust LED control */ 196 phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); 197 /* Change Page Number */ 198 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); 199 200 genphy_config_aneg(phydev); 201 202 phy_reset(phydev); 203 204 return 0; 205 } 206 207 static int m88e1118_startup(struct phy_device *phydev) 208 { 209 /* Change Page Number */ 210 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); 211 212 genphy_update_link(phydev); 213 m88e1xxx_parse_status(phydev); 214 215 return 0; 216 } 217 218 /* Marvell 88E1121R */ 219 static int m88e1121_config(struct phy_device *phydev) 220 { 221 int pg; 222 223 /* Configure the PHY */ 224 genphy_config_aneg(phydev); 225 226 /* Switch the page to access the led register */ 227 pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE); 228 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, 229 MIIM_88E1121_PHY_LED_PAGE); 230 /* Configure leds */ 231 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL, 232 MIIM_88E1121_PHY_LED_DEF); 233 /* Restore the page pointer */ 234 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg); 235 236 /* Disable IRQs and de-assert interrupt */ 237 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0); 238 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS); 239 240 return 0; 241 } 242 243 /* Marvell 88E1145 */ 244 static int m88e1145_config(struct phy_device *phydev) 245 { 246 int reg; 247 248 /* Errata E0, E1 */ 249 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b); 250 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f); 251 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016); 252 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da); 253 254 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR, 255 MIIM_88E1xxx_PHY_MDI_X_AUTO); 256 257 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR); 258 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 259 reg |= MIIM_M88E1145_RGMII_RX_DELAY | 260 MIIM_M88E1145_RGMII_TX_DELAY; 261 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); 262 263 genphy_config_aneg(phydev); 264 265 phy_reset(phydev); 266 267 return 0; 268 } 269 270 static int m88e1145_startup(struct phy_device *phydev) 271 { 272 genphy_update_link(phydev); 273 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL, 274 MIIM_88E1145_PHY_LED_DIRECT); 275 m88e1xxx_parse_status(phydev); 276 277 return 0; 278 } 279 280 /* Marvell 88E1149S */ 281 static int m88e1149_config(struct phy_device *phydev) 282 { 283 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f); 284 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); 285 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5); 286 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); 287 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 288 289 genphy_config_aneg(phydev); 290 291 phy_reset(phydev); 292 293 return 0; 294 } 295 296 297 static struct phy_driver M88E1011S_driver = { 298 .name = "Marvell 88E1011S", 299 .uid = 0x1410c60, 300 .mask = 0xffffff0, 301 .features = PHY_GBIT_FEATURES, 302 .config = &m88e1011s_config, 303 .startup = &m88e1011s_startup, 304 .shutdown = &genphy_shutdown, 305 }; 306 307 static struct phy_driver M88E1111S_driver = { 308 .name = "Marvell 88E1111S", 309 .uid = 0x1410cc0, 310 .mask = 0xffffff0, 311 .features = PHY_GBIT_FEATURES, 312 .config = &m88e1111s_config, 313 .startup = &m88e1011s_startup, 314 .shutdown = &genphy_shutdown, 315 }; 316 317 static struct phy_driver M88E1118_driver = { 318 .name = "Marvell 88E1118", 319 .uid = 0x1410e10, 320 .mask = 0xffffff0, 321 .features = PHY_GBIT_FEATURES, 322 .config = &m88e1118_config, 323 .startup = &m88e1118_startup, 324 .shutdown = &genphy_shutdown, 325 }; 326 327 static struct phy_driver M88E1121R_driver = { 328 .name = "Marvell 88E1121R", 329 .uid = 0x1410cb0, 330 .mask = 0xffffff0, 331 .features = PHY_GBIT_FEATURES, 332 .config = &m88e1121_config, 333 .startup = &genphy_startup, 334 .shutdown = &genphy_shutdown, 335 }; 336 337 static struct phy_driver M88E1145_driver = { 338 .name = "Marvell 88E1145", 339 .uid = 0x1410cd0, 340 .mask = 0xffffff0, 341 .features = PHY_GBIT_FEATURES, 342 .config = &m88e1145_config, 343 .startup = &m88e1145_startup, 344 .shutdown = &genphy_shutdown, 345 }; 346 347 static struct phy_driver M88E1149S_driver = { 348 .name = "Marvell 88E1149S", 349 .uid = 0x1410ca0, 350 .mask = 0xffffff0, 351 .features = PHY_GBIT_FEATURES, 352 .config = &m88e1149_config, 353 .startup = &m88e1011s_startup, 354 .shutdown = &genphy_shutdown, 355 }; 356 357 int phy_marvell_init(void) 358 { 359 phy_register(&M88E1149S_driver); 360 phy_register(&M88E1145_driver); 361 phy_register(&M88E1121R_driver); 362 phy_register(&M88E1118_driver); 363 phy_register(&M88E1111S_driver); 364 phy_register(&M88E1011S_driver); 365 366 return 0; 367 } 368