uboot/drivers/net/phy/marvell.c
<<
>>
Prefs
   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 */
  93static 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 */
 114static 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
 171static 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 */
 180static 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 */
 288static 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
 308static 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 */
 320static 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 */
 345static 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
 371static 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 */
 382static 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
 398static 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
 408static 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
 418static 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
 428static struct phy_driver M88E1121R_driver = {
 429        .name = "Marvell 88E1121R",
 430        .uid = 0x1410cb0,
 431        .mask = 0xffffff0,
 432        .features = PHY_GBIT_FEATURES,
 433        .config = &m88e1121_config,
 434        .startup = &genphy_startup,
 435        .shutdown = &genphy_shutdown,
 436};
 437
 438static struct phy_driver M88E1145_driver = {
 439        .name = "Marvell 88E1145",
 440        .uid = 0x1410cd0,
 441        .mask = 0xffffff0,
 442        .features = PHY_GBIT_FEATURES,
 443        .config = &m88e1145_config,
 444        .startup = &m88e1145_startup,
 445        .shutdown = &genphy_shutdown,
 446};
 447
 448static struct phy_driver M88E1149S_driver = {
 449        .name = "Marvell 88E1149S",
 450        .uid = 0x1410ca0,
 451        .mask = 0xffffff0,
 452        .features = PHY_GBIT_FEATURES,
 453        .config = &m88e1149_config,
 454        .startup = &m88e1011s_startup,
 455        .shutdown = &genphy_shutdown,
 456};
 457
 458int phy_marvell_init(void)
 459{
 460        phy_register(&M88E1149S_driver);
 461        phy_register(&M88E1145_driver);
 462        phy_register(&M88E1121R_driver);
 463        phy_register(&M88E1118_driver);
 464        phy_register(&M88E1111S_driver);
 465        phy_register(&M88E1011S_driver);
 466
 467        return 0;
 468}
 469