uboot/drivers/net/phy/vitesse.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Vitesse PHY drivers
   4 *
   5 * Copyright 2010-2014 Freescale Semiconductor, Inc.
   6 * Original Author: Andy Fleming
   7 * Add vsc8662 phy support - Priyanka Jain
   8 */
   9#include <common.h>
  10#include <miiphy.h>
  11
  12/* Cicada Auxiliary Control/Status Register */
  13#define MIIM_CIS82xx_AUX_CONSTAT        0x1c
  14#define MIIM_CIS82xx_AUXCONSTAT_INIT    0x0004
  15#define MIIM_CIS82xx_AUXCONSTAT_DUPLEX  0x0020
  16#define MIIM_CIS82xx_AUXCONSTAT_SPEED   0x0018
  17#define MIIM_CIS82xx_AUXCONSTAT_GBIT    0x0010
  18#define MIIM_CIS82xx_AUXCONSTAT_100     0x0008
  19
  20/* Cicada Extended Control Register 1 */
  21#define MIIM_CIS82xx_EXT_CON1           0x17
  22#define MIIM_CIS8201_EXTCON1_INIT       0x0000
  23
  24/* Cicada 8204 Extended PHY Control Register 1 */
  25#define MIIM_CIS8204_EPHY_CON           0x17
  26#define MIIM_CIS8204_EPHYCON_INIT       0x0006
  27#define MIIM_CIS8204_EPHYCON_RGMII      0x1100
  28
  29/* Cicada 8204 Serial LED Control Register */
  30#define MIIM_CIS8204_SLED_CON           0x1b
  31#define MIIM_CIS8204_SLEDCON_INIT       0x1115
  32
  33/* Vitesse VSC8601 Extended PHY Control Register 1 */
  34#define MII_VSC8601_EPHY_CTL            0x17
  35#define MII_VSC8601_EPHY_CTL_RGMII_SKEW (1 << 8)
  36
  37#define PHY_EXT_PAGE_ACCESS    0x1f
  38#define PHY_EXT_PAGE_ACCESS_GENERAL     0x10
  39#define PHY_EXT_PAGE_ACCESS_EXTENDED3   0x3
  40
  41/* Vitesse VSC8574 control register */
  42#define MIIM_VSC8574_MAC_SERDES_CON     0x10
  43#define MIIM_VSC8574_MAC_SERDES_ANEG    0x80
  44#define MIIM_VSC8574_GENERAL18          0x12
  45#define MIIM_VSC8574_GENERAL19          0x13
  46
  47/* Vitesse VSC8574 gerenal purpose register 18 */
  48#define MIIM_VSC8574_18G_SGMII          0x80f0
  49#define MIIM_VSC8574_18G_QSGMII         0x80e0
  50#define MIIM_VSC8574_18G_CMDSTAT        0x8000
  51
  52/* Vitesse VSC8514 control register */
  53#define MIIM_VSC8514_MAC_SERDES_CON     0x10
  54#define MIIM_VSC8514_GENERAL18          0x12
  55#define MIIM_VSC8514_GENERAL19          0x13
  56#define MIIM_VSC8514_GENERAL23          0x17
  57
  58/* Vitesse VSC8514 gerenal purpose register 18 */
  59#define MIIM_VSC8514_18G_QSGMII         0x80e0
  60#define MIIM_VSC8514_18G_CMDSTAT        0x8000
  61
  62/* Vitesse VSC8664 Control/Status Register */
  63#define MIIM_VSC8664_SERDES_AND_SIGDET  0x13
  64#define MIIM_VSC8664_ADDITIONAL_DEV     0x16
  65#define MIIM_VSC8664_EPHY_CON           0x17
  66#define MIIM_VSC8664_LED_CON            0x1E
  67
  68#define PHY_EXT_PAGE_ACCESS_EXTENDED    0x0001
  69
  70/* CIS8201 */
  71static int vitesse_config(struct phy_device *phydev)
  72{
  73        /* Override PHY config settings */
  74        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
  75                        MIIM_CIS82xx_AUXCONSTAT_INIT);
  76        /* Set up the interface mode */
  77        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1,
  78                        MIIM_CIS8201_EXTCON1_INIT);
  79
  80        genphy_config_aneg(phydev);
  81
  82        return 0;
  83}
  84
  85static int vitesse_parse_status(struct phy_device *phydev)
  86{
  87        int speed;
  88        int mii_reg;
  89
  90        mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT);
  91
  92        if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX)
  93                phydev->duplex = DUPLEX_FULL;
  94        else
  95                phydev->duplex = DUPLEX_HALF;
  96
  97        speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED;
  98        switch (speed) {
  99        case MIIM_CIS82xx_AUXCONSTAT_GBIT:
 100                phydev->speed = SPEED_1000;
 101                break;
 102        case MIIM_CIS82xx_AUXCONSTAT_100:
 103                phydev->speed = SPEED_100;
 104                break;
 105        default:
 106                phydev->speed = SPEED_10;
 107                break;
 108        }
 109
 110        return 0;
 111}
 112
 113static int vitesse_startup(struct phy_device *phydev)
 114{
 115        int ret;
 116
 117        ret = genphy_update_link(phydev);
 118        if (ret)
 119                return ret;
 120        return vitesse_parse_status(phydev);
 121}
 122
 123static int cis8204_config(struct phy_device *phydev)
 124{
 125        /* Override PHY config settings */
 126        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
 127                        MIIM_CIS82xx_AUXCONSTAT_INIT);
 128
 129        genphy_config_aneg(phydev);
 130
 131        if (phy_interface_is_rgmii(phydev))
 132                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
 133                                MIIM_CIS8204_EPHYCON_INIT |
 134                                MIIM_CIS8204_EPHYCON_RGMII);
 135        else
 136                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
 137                                MIIM_CIS8204_EPHYCON_INIT);
 138
 139        return 0;
 140}
 141
 142/* Vitesse VSC8601 */
 143/* This adds a skew for both TX and RX clocks, so the skew should only be
 144 * applied to "rgmii-id" interfaces. It may not work as expected
 145 * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */
 146static int vsc8601_add_skew(struct phy_device *phydev)
 147{
 148        int ret;
 149
 150        ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL);
 151        if (ret < 0)
 152                return ret;
 153
 154        ret |= MII_VSC8601_EPHY_CTL_RGMII_SKEW;
 155        return phy_write(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL, ret);
 156}
 157
 158static int vsc8601_config(struct phy_device *phydev)
 159{
 160        int ret = 0;
 161
 162        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
 163                ret = vsc8601_add_skew(phydev);
 164
 165        if (ret < 0)
 166                return ret;
 167
 168        return genphy_config_aneg(phydev);
 169}
 170
 171static int vsc8574_config(struct phy_device *phydev)
 172{
 173        u32 val;
 174        /* configure register 19G for MAC */
 175        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
 176                  PHY_EXT_PAGE_ACCESS_GENERAL);
 177
 178        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19);
 179        if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
 180                /* set bit 15:14 to '01' for QSGMII mode */
 181                val = (val & 0x3fff) | (1 << 14);
 182                phy_write(phydev, MDIO_DEVAD_NONE,
 183                          MIIM_VSC8574_GENERAL19, val);
 184                /* Enable 4 ports MAC QSGMII */
 185                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
 186                          MIIM_VSC8574_18G_QSGMII);
 187        } else {
 188                /* set bit 15:14 to '00' for SGMII mode */
 189                val = val & 0x3fff;
 190                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val);
 191                /* Enable 4 ports MAC SGMII */
 192                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
 193                          MIIM_VSC8574_18G_SGMII);
 194        }
 195        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
 196        /* When bit 15 is cleared the command has completed */
 197        while (val & MIIM_VSC8574_18G_CMDSTAT)
 198                val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
 199
 200        /* Enable Serdes Auto-negotiation */
 201        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
 202                  PHY_EXT_PAGE_ACCESS_EXTENDED3);
 203        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON);
 204        val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
 205        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val);
 206
 207        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
 208
 209        genphy_config_aneg(phydev);
 210
 211        return 0;
 212}
 213
 214static int vsc8514_config(struct phy_device *phydev)
 215{
 216        u32 val;
 217        int timeout = 1000000;
 218
 219        /* configure register to access 19G */
 220        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
 221                  PHY_EXT_PAGE_ACCESS_GENERAL);
 222
 223        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19);
 224        if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
 225                /* set bit 15:14 to '01' for QSGMII mode */
 226                val = (val & 0x3fff) | (1 << 14);
 227                phy_write(phydev, MDIO_DEVAD_NONE,
 228                          MIIM_VSC8514_GENERAL19, val);
 229                /* Enable 4 ports MAC QSGMII */
 230                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18,
 231                          MIIM_VSC8514_18G_QSGMII);
 232        } else {
 233                /*TODO Add SGMII functionality once spec sheet
 234                 * for VSC8514 defines complete functionality
 235                 */
 236        }
 237
 238        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
 239        /* When bit 15 is cleared the command has completed */
 240        while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--)
 241                val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
 242
 243        if (0 == timeout) {
 244                printf("PHY 8514 config failed\n");
 245                return -1;
 246        }
 247
 248        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
 249
 250        /* configure register to access 23 */
 251        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23);
 252        /* set bits 10:8 to '000' */
 253        val = (val & 0xf8ff);
 254        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val);
 255
 256        /* Enable Serdes Auto-negotiation */
 257        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
 258                  PHY_EXT_PAGE_ACCESS_EXTENDED3);
 259        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON);
 260        val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
 261        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val);
 262        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
 263
 264        genphy_config_aneg(phydev);
 265
 266        return 0;
 267}
 268
 269static int vsc8664_config(struct phy_device *phydev)
 270{
 271        u32 val;
 272
 273        /* Enable MAC interface auto-negotiation */
 274        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
 275        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON);
 276        val |= (1 << 13);
 277        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val);
 278
 279        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
 280                  PHY_EXT_PAGE_ACCESS_EXTENDED);
 281        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET);
 282        val |= (1 << 11);
 283        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val);
 284        phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
 285
 286        /* Enable LED blink */
 287        val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON);
 288        val &= ~(1 << 2);
 289        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val);
 290
 291        genphy_config_aneg(phydev);
 292
 293        return 0;
 294}
 295
 296static struct phy_driver VSC8211_driver = {
 297        .name   = "Vitesse VSC8211",
 298        .uid    = 0xfc4b0,
 299        .mask   = 0xffff0,
 300        .features = PHY_GBIT_FEATURES,
 301        .config = &vitesse_config,
 302        .startup = &vitesse_startup,
 303        .shutdown = &genphy_shutdown,
 304};
 305
 306static struct phy_driver VSC8221_driver = {
 307        .name = "Vitesse VSC8221",
 308        .uid = 0xfc550,
 309        .mask = 0xffff0,
 310        .features = PHY_GBIT_FEATURES,
 311        .config = &genphy_config_aneg,
 312        .startup = &vitesse_startup,
 313        .shutdown = &genphy_shutdown,
 314};
 315
 316static struct phy_driver VSC8244_driver = {
 317        .name = "Vitesse VSC8244",
 318        .uid = 0xfc6c0,
 319        .mask = 0xffff0,
 320        .features = PHY_GBIT_FEATURES,
 321        .config = &genphy_config_aneg,
 322        .startup = &vitesse_startup,
 323        .shutdown = &genphy_shutdown,
 324};
 325
 326static struct phy_driver VSC8234_driver = {
 327        .name = "Vitesse VSC8234",
 328        .uid = 0xfc620,
 329        .mask = 0xffff0,
 330        .features = PHY_GBIT_FEATURES,
 331        .config = &genphy_config_aneg,
 332        .startup = &vitesse_startup,
 333        .shutdown = &genphy_shutdown,
 334};
 335
 336static struct phy_driver VSC8574_driver = {
 337        .name = "Vitesse VSC8574",
 338        .uid = 0x704a0,
 339        .mask = 0xffff0,
 340        .features = PHY_GBIT_FEATURES,
 341        .config = &vsc8574_config,
 342        .startup = &vitesse_startup,
 343        .shutdown = &genphy_shutdown,
 344};
 345
 346static struct phy_driver VSC8514_driver = {
 347        .name = "Vitesse VSC8514",
 348        .uid = 0x70670,
 349        .mask = 0xffff0,
 350        .features = PHY_GBIT_FEATURES,
 351        .config = &vsc8514_config,
 352        .startup = &vitesse_startup,
 353        .shutdown = &genphy_shutdown,
 354};
 355
 356static struct phy_driver VSC8584_driver = {
 357        .name = "Vitesse VSC8584",
 358        .uid = 0x707c0,
 359        .mask = 0xffff0,
 360        .features = PHY_GBIT_FEATURES,
 361        .config = &vsc8574_config,
 362        .startup = &vitesse_startup,
 363        .shutdown = &genphy_shutdown,
 364};
 365
 366static struct phy_driver VSC8601_driver = {
 367        .name = "Vitesse VSC8601",
 368        .uid = 0x70420,
 369        .mask = 0xffff0,
 370        .features = PHY_GBIT_FEATURES,
 371        .config = &vsc8601_config,
 372        .startup = &vitesse_startup,
 373        .shutdown = &genphy_shutdown,
 374};
 375
 376static struct phy_driver VSC8641_driver = {
 377        .name = "Vitesse VSC8641",
 378        .uid = 0x70430,
 379        .mask = 0xffff0,
 380        .features = PHY_GBIT_FEATURES,
 381        .config = &genphy_config_aneg,
 382        .startup = &vitesse_startup,
 383        .shutdown = &genphy_shutdown,
 384};
 385
 386static struct phy_driver VSC8662_driver = {
 387        .name = "Vitesse VSC8662",
 388        .uid = 0x70660,
 389        .mask = 0xffff0,
 390        .features = PHY_GBIT_FEATURES,
 391        .config = &genphy_config_aneg,
 392        .startup = &vitesse_startup,
 393        .shutdown = &genphy_shutdown,
 394};
 395
 396static struct phy_driver VSC8664_driver = {
 397        .name = "Vitesse VSC8664",
 398        .uid = 0x70660,
 399        .mask = 0xffff0,
 400        .features = PHY_GBIT_FEATURES,
 401        .config = &vsc8664_config,
 402        .startup = &vitesse_startup,
 403        .shutdown = &genphy_shutdown,
 404};
 405
 406/* Vitesse bought Cicada, so we'll put these here */
 407static struct phy_driver cis8201_driver = {
 408        .name = "CIS8201",
 409        .uid = 0xfc410,
 410        .mask = 0xffff0,
 411        .features = PHY_GBIT_FEATURES,
 412        .config = &vitesse_config,
 413        .startup = &vitesse_startup,
 414        .shutdown = &genphy_shutdown,
 415};
 416
 417static struct phy_driver cis8204_driver = {
 418        .name = "Cicada Cis8204",
 419        .uid = 0xfc440,
 420        .mask = 0xffff0,
 421        .features = PHY_GBIT_FEATURES,
 422        .config = &cis8204_config,
 423        .startup = &vitesse_startup,
 424        .shutdown = &genphy_shutdown,
 425};
 426
 427int phy_vitesse_init(void)
 428{
 429        phy_register(&VSC8641_driver);
 430        phy_register(&VSC8601_driver);
 431        phy_register(&VSC8234_driver);
 432        phy_register(&VSC8244_driver);
 433        phy_register(&VSC8211_driver);
 434        phy_register(&VSC8221_driver);
 435        phy_register(&VSC8574_driver);
 436        phy_register(&VSC8584_driver);
 437        phy_register(&VSC8514_driver);
 438        phy_register(&VSC8662_driver);
 439        phy_register(&VSC8664_driver);
 440        phy_register(&cis8201_driver);
 441        phy_register(&cis8204_driver);
 442
 443        return 0;
 444}
 445