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 /* 88E1111 Extended PHY Specific Control Register */ 47 #define MIIM_88E1111_PHY_EXT_CR 0x14 48 #define MIIM_88E1111_RX_DELAY 0x80 49 #define MIIM_88E1111_TX_DELAY 0x2 50 51 /* 88E1111 Extended PHY Specific Status Register */ 52 #define MIIM_88E1111_PHY_EXT_SR 0x1b 53 #define MIIM_88E1111_HWCFG_MODE_MASK 0xf 54 #define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb 55 #define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3 56 #define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4 57 #define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9 58 #define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000 59 #define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000 60 61 #define MIIM_88E1111_COPPER 0 62 #define MIIM_88E1111_FIBER 1 63 64 /* 88E1118 PHY defines */ 65 #define MIIM_88E1118_PHY_PAGE 22 66 #define MIIM_88E1118_PHY_LED_PAGE 3 67 68 /* 88E1121 PHY LED Control Register */ 69 #define MIIM_88E1121_PHY_LED_CTRL 16 70 #define MIIM_88E1121_PHY_LED_PAGE 3 71 #define MIIM_88E1121_PHY_LED_DEF 0x0030 72 73 /* 88E1121 PHY IRQ Enable/Status Register */ 74 #define MIIM_88E1121_PHY_IRQ_EN 18 75 #define MIIM_88E1121_PHY_IRQ_STATUS 19 76 77 #define MIIM_88E1121_PHY_PAGE 22 78 79 /* 88E1145 Extended PHY Specific Control Register */ 80 #define MIIM_88E1145_PHY_EXT_CR 20 81 #define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 82 #define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 83 84 #define MIIM_88E1145_PHY_LED_CONTROL 24 85 #define MIIM_88E1145_PHY_LED_DIRECT 0x4100 86 87 #define MIIM_88E1145_PHY_PAGE 29 88 #define MIIM_88E1145_PHY_CAL_OV 30 89 90 #define MIIM_88E1149_PHY_PAGE 29 91 92 /* Marvell 88E1011S */ 93 static int m88e1011s_config(struct phy_device *phydev) 94 { 95 /* Reset and configure the PHY */ 96 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 97 98 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); 99 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); 100 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); 101 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0); 102 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 103 104 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 105 106 genphy_config_aneg(phydev); 107 108 return 0; 109 } 110 111 /* Parse the 88E1011's status register for speed and duplex 112 * information 113 */ 114 static uint m88e1xxx_parse_status(struct phy_device *phydev) 115 { 116 unsigned int speed; 117 unsigned int mii_reg; 118 119 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS); 120 121 if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) && 122 !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { 123 int i = 0; 124 125 puts("Waiting for PHY realtime link"); 126 while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { 127 /* Timeout reached ? */ 128 if (i > PHY_AUTONEGOTIATE_TIMEOUT) { 129 puts(" TIMEOUT !\n"); 130 phydev->link = 0; 131 break; 132 } 133 134 if ((i++ % 1000) == 0) 135 putc('.'); 136 udelay(1000); 137 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, 138 MIIM_88E1xxx_PHY_STATUS); 139 } 140 puts(" done\n"); 141 udelay(500000); /* another 500 ms (results in faster booting) */ 142 } else { 143 if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) 144 phydev->link = 1; 145 else 146 phydev->link = 0; 147 } 148 149 if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX) 150 phydev->duplex = DUPLEX_FULL; 151 else 152 phydev->duplex = DUPLEX_HALF; 153 154 speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED; 155 156 switch (speed) { 157 case MIIM_88E1xxx_PHYSTAT_GBIT: 158 phydev->speed = SPEED_1000; 159 break; 160 case MIIM_88E1xxx_PHYSTAT_100: 161 phydev->speed = SPEED_100; 162 break; 163 default: 164 phydev->speed = SPEED_10; 165 break; 166 } 167 168 return 0; 169 } 170 171 static int m88e1011s_startup(struct phy_device *phydev) 172 { 173 genphy_update_link(phydev); 174 m88e1xxx_parse_status(phydev); 175 176 return 0; 177 } 178 179 /* Marvell 88E1111S */ 180 static int m88e1111s_config(struct phy_device *phydev) 181 { 182 int reg; 183 int timeout; 184 185 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 186 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || 187 (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || 188 (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { 189 reg = phy_read(phydev, 190 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); 191 if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || 192 (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) { 193 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); 194 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 195 reg &= ~MIIM_88E1111_TX_DELAY; 196 reg |= MIIM_88E1111_RX_DELAY; 197 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 198 reg &= ~MIIM_88E1111_RX_DELAY; 199 reg |= MIIM_88E1111_TX_DELAY; 200 } 201 202 phy_write(phydev, 203 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); 204 205 reg = phy_read(phydev, 206 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); 207 208 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); 209 210 if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES) 211 reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII; 212 else 213 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII; 214 215 phy_write(phydev, 216 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); 217 } 218 219 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 220 reg = phy_read(phydev, 221 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); 222 223 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); 224 reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; 225 reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; 226 227 phy_write(phydev, MDIO_DEVAD_NONE, 228 MIIM_88E1111_PHY_EXT_SR, reg); 229 } 230 231 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 232 reg = phy_read(phydev, 233 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); 234 reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); 235 phy_write(phydev, 236 MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); 237 238 reg = phy_read(phydev, MDIO_DEVAD_NONE, 239 MIIM_88E1111_PHY_EXT_SR); 240 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | 241 MIIM_88E1111_HWCFG_FIBER_COPPER_RES); 242 reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; 243 phy_write(phydev, MDIO_DEVAD_NONE, 244 MIIM_88E1111_PHY_EXT_SR, reg); 245 246 /* soft reset */ 247 timeout = 1000; 248 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 249 udelay(1000); 250 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 251 while ((reg & BMCR_RESET) && --timeout) { 252 udelay(1000); 253 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 254 } 255 if (!timeout) 256 printf("%s: phy soft reset timeout\n", __func__); 257 258 reg = phy_read(phydev, MDIO_DEVAD_NONE, 259 MIIM_88E1111_PHY_EXT_SR); 260 reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | 261 MIIM_88E1111_HWCFG_FIBER_COPPER_RES); 262 reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI | 263 MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; 264 phy_write(phydev, MDIO_DEVAD_NONE, 265 MIIM_88E1111_PHY_EXT_SR, reg); 266 } 267 268 /* soft reset */ 269 timeout = 1000; 270 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); 271 udelay(1000); 272 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 273 while ((reg & BMCR_RESET) && --timeout) { 274 udelay(1000); 275 reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 276 } 277 if (!timeout) 278 printf("%s: phy soft reset timeout\n", __func__); 279 280 genphy_config_aneg(phydev); 281 282 phy_reset(phydev); 283 284 return 0; 285 } 286 287 /* Marvell 88E1118 */ 288 static int m88e1118_config(struct phy_device *phydev) 289 { 290 /* Change Page Number */ 291 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002); 292 /* Delay RGMII TX and RX */ 293 phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); 294 /* Change Page Number */ 295 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003); 296 /* Adjust LED control */ 297 phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); 298 /* Change Page Number */ 299 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); 300 301 genphy_config_aneg(phydev); 302 303 phy_reset(phydev); 304 305 return 0; 306 } 307 308 static int m88e1118_startup(struct phy_device *phydev) 309 { 310 /* Change Page Number */ 311 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); 312 313 genphy_update_link(phydev); 314 m88e1xxx_parse_status(phydev); 315 316 return 0; 317 } 318 319 /* Marvell 88E1121R */ 320 static int m88e1121_config(struct phy_device *phydev) 321 { 322 int pg; 323 324 /* Configure the PHY */ 325 genphy_config_aneg(phydev); 326 327 /* Switch the page to access the led register */ 328 pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE); 329 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, 330 MIIM_88E1121_PHY_LED_PAGE); 331 /* Configure leds */ 332 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL, 333 MIIM_88E1121_PHY_LED_DEF); 334 /* Restore the page pointer */ 335 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg); 336 337 /* Disable IRQs and de-assert interrupt */ 338 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0); 339 phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS); 340 341 return 0; 342 } 343 344 /* Marvell 88E1145 */ 345 static int m88e1145_config(struct phy_device *phydev) 346 { 347 int reg; 348 349 /* Errata E0, E1 */ 350 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b); 351 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f); 352 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016); 353 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da); 354 355 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR, 356 MIIM_88E1xxx_PHY_MDI_X_AUTO); 357 358 reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR); 359 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 360 reg |= MIIM_M88E1145_RGMII_RX_DELAY | 361 MIIM_M88E1145_RGMII_TX_DELAY; 362 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); 363 364 genphy_config_aneg(phydev); 365 366 phy_reset(phydev); 367 368 return 0; 369 } 370 371 static int m88e1145_startup(struct phy_device *phydev) 372 { 373 genphy_update_link(phydev); 374 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL, 375 MIIM_88E1145_PHY_LED_DIRECT); 376 m88e1xxx_parse_status(phydev); 377 378 return 0; 379 } 380 381 /* Marvell 88E1149S */ 382 static int m88e1149_config(struct phy_device *phydev) 383 { 384 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f); 385 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); 386 phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5); 387 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); 388 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 389 390 genphy_config_aneg(phydev); 391 392 phy_reset(phydev); 393 394 return 0; 395 } 396 397 398 static struct phy_driver M88E1011S_driver = { 399 .name = "Marvell 88E1011S", 400 .uid = 0x1410c60, 401 .mask = 0xffffff0, 402 .features = PHY_GBIT_FEATURES, 403 .config = &m88e1011s_config, 404 .startup = &m88e1011s_startup, 405 .shutdown = &genphy_shutdown, 406 }; 407 408 static struct phy_driver M88E1111S_driver = { 409 .name = "Marvell 88E1111S", 410 .uid = 0x1410cc0, 411 .mask = 0xffffff0, 412 .features = PHY_GBIT_FEATURES, 413 .config = &m88e1111s_config, 414 .startup = &m88e1011s_startup, 415 .shutdown = &genphy_shutdown, 416 }; 417 418 static struct phy_driver M88E1118_driver = { 419 .name = "Marvell 88E1118", 420 .uid = 0x1410e10, 421 .mask = 0xffffff0, 422 .features = PHY_GBIT_FEATURES, 423 .config = &m88e1118_config, 424 .startup = &m88e1118_startup, 425 .shutdown = &genphy_shutdown, 426 }; 427 428 static struct phy_driver M88E1118R_driver = { 429 .name = "Marvell 88E1118R", 430 .uid = 0x1410e40, 431 .mask = 0xffffff0, 432 .features = PHY_GBIT_FEATURES, 433 .config = &m88e1118_config, 434 .startup = &m88e1118_startup, 435 .shutdown = &genphy_shutdown, 436 }; 437 438 static struct phy_driver M88E1121R_driver = { 439 .name = "Marvell 88E1121R", 440 .uid = 0x1410cb0, 441 .mask = 0xffffff0, 442 .features = PHY_GBIT_FEATURES, 443 .config = &m88e1121_config, 444 .startup = &genphy_startup, 445 .shutdown = &genphy_shutdown, 446 }; 447 448 static struct phy_driver M88E1145_driver = { 449 .name = "Marvell 88E1145", 450 .uid = 0x1410cd0, 451 .mask = 0xffffff0, 452 .features = PHY_GBIT_FEATURES, 453 .config = &m88e1145_config, 454 .startup = &m88e1145_startup, 455 .shutdown = &genphy_shutdown, 456 }; 457 458 static struct phy_driver M88E1149S_driver = { 459 .name = "Marvell 88E1149S", 460 .uid = 0x1410ca0, 461 .mask = 0xffffff0, 462 .features = PHY_GBIT_FEATURES, 463 .config = &m88e1149_config, 464 .startup = &m88e1011s_startup, 465 .shutdown = &genphy_shutdown, 466 }; 467 468 static struct phy_driver M88E1518_driver = { 469 .name = "Marvell 88E1518", 470 .uid = 0x1410dd1, 471 .mask = 0xffffff0, 472 .features = PHY_GBIT_FEATURES, 473 .config = &m88e1111s_config, 474 .startup = &m88e1011s_startup, 475 .shutdown = &genphy_shutdown, 476 }; 477 478 int phy_marvell_init(void) 479 { 480 phy_register(&M88E1149S_driver); 481 phy_register(&M88E1145_driver); 482 phy_register(&M88E1121R_driver); 483 phy_register(&M88E1118_driver); 484 phy_register(&M88E1118R_driver); 485 phy_register(&M88E1111S_driver); 486 phy_register(&M88E1011S_driver); 487 phy_register(&M88E1518_driver); 488 489 return 0; 490 } 491