uboot/drivers/net/phy/realtek.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * RealTek PHY drivers
   4 *
   5 * Copyright 2010-2011, 2015 Freescale Semiconductor, Inc.
   6 * author Andy Fleming
   7 * Copyright 2016 Karsten Merker <merker@debian.org>
   8 */
   9#include <common.h>
  10#include <linux/bitops.h>
  11#include <phy.h>
  12#include <linux/delay.h>
  13
  14#define PHY_RTL8211x_FORCE_MASTER BIT(1)
  15#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
  16#define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3)
  17
  18#define PHY_AUTONEGOTIATE_TIMEOUT 5000
  19
  20/* RTL8211x 1000BASE-T Control Register */
  21#define MIIM_RTL8211x_CTRL1000T_MSCE BIT(12);
  22#define MIIM_RTL8211x_CTRL1000T_MASTER BIT(11);
  23
  24/* RTL8211x PHY Status Register */
  25#define MIIM_RTL8211x_PHY_STATUS       0x11
  26#define MIIM_RTL8211x_PHYSTAT_SPEED    0xc000
  27#define MIIM_RTL8211x_PHYSTAT_GBIT     0x8000
  28#define MIIM_RTL8211x_PHYSTAT_100      0x4000
  29#define MIIM_RTL8211x_PHYSTAT_DUPLEX   0x2000
  30#define MIIM_RTL8211x_PHYSTAT_SPDDONE  0x0800
  31#define MIIM_RTL8211x_PHYSTAT_LINK     0x0400
  32
  33/* RTL8211x PHY Interrupt Enable Register */
  34#define MIIM_RTL8211x_PHY_INER         0x12
  35#define MIIM_RTL8211x_PHY_INTR_ENA     0x9f01
  36#define MIIM_RTL8211x_PHY_INTR_DIS     0x0000
  37
  38/* RTL8211x PHY Interrupt Status Register */
  39#define MIIM_RTL8211x_PHY_INSR         0x13
  40
  41/* RTL8211F PHY Status Register */
  42#define MIIM_RTL8211F_PHY_STATUS       0x1a
  43#define MIIM_RTL8211F_AUTONEG_ENABLE   0x1000
  44#define MIIM_RTL8211F_PHYSTAT_SPEED    0x0030
  45#define MIIM_RTL8211F_PHYSTAT_GBIT     0x0020
  46#define MIIM_RTL8211F_PHYSTAT_100      0x0010
  47#define MIIM_RTL8211F_PHYSTAT_DUPLEX   0x0008
  48#define MIIM_RTL8211F_PHYSTAT_SPDDONE  0x0800
  49#define MIIM_RTL8211F_PHYSTAT_LINK     0x0004
  50
  51#define MIIM_RTL8211E_CONFREG           0x1c
  52#define MIIM_RTL8211E_CONFREG_TXD               0x0002
  53#define MIIM_RTL8211E_CONFREG_RXD               0x0004
  54#define MIIM_RTL8211E_CONFREG_MAGIC             0xb400  /* Undocumented */
  55
  56#define MIIM_RTL8211E_EXT_PAGE_SELECT  0x1e
  57
  58#define MIIM_RTL8211F_PAGE_SELECT      0x1f
  59#define MIIM_RTL8211F_TX_DELAY          0x100
  60#define MIIM_RTL8211F_RX_DELAY          0x8
  61#define MIIM_RTL8211F_LCR               0x10
  62
  63static int rtl8211f_phy_extread(struct phy_device *phydev, int addr,
  64                                int devaddr, int regnum)
  65{
  66        int oldpage = phy_read(phydev, MDIO_DEVAD_NONE,
  67                               MIIM_RTL8211F_PAGE_SELECT);
  68        int val;
  69
  70        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, devaddr);
  71        val = phy_read(phydev, MDIO_DEVAD_NONE, regnum);
  72        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, oldpage);
  73
  74        return val;
  75}
  76
  77static int rtl8211f_phy_extwrite(struct phy_device *phydev, int addr,
  78                                 int devaddr, int regnum, u16 val)
  79{
  80        int oldpage = phy_read(phydev, MDIO_DEVAD_NONE,
  81                               MIIM_RTL8211F_PAGE_SELECT);
  82
  83        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, devaddr);
  84        phy_write(phydev, MDIO_DEVAD_NONE, regnum, val);
  85        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, oldpage);
  86
  87        return 0;
  88}
  89
  90static int rtl8211b_probe(struct phy_device *phydev)
  91{
  92#ifdef CONFIG_RTL8211X_PHY_FORCE_MASTER
  93        phydev->flags |= PHY_RTL8211x_FORCE_MASTER;
  94#endif
  95
  96        return 0;
  97}
  98
  99static int rtl8211e_probe(struct phy_device *phydev)
 100{
 101#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
 102        phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
 103#endif
 104
 105        return 0;
 106}
 107
 108static int rtl8211f_probe(struct phy_device *phydev)
 109{
 110#ifdef CONFIG_RTL8211F_PHY_FORCE_EEE_RXC_ON
 111        phydev->flags |= PHY_RTL8211F_FORCE_EEE_RXC_ON;
 112#endif
 113
 114        return 0;
 115}
 116
 117/* RealTek RTL8211x */
 118static int rtl8211x_config(struct phy_device *phydev)
 119{
 120        phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
 121
 122        /* mask interrupt at init; if the interrupt is
 123         * needed indeed, it should be explicitly enabled
 124         */
 125        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER,
 126                  MIIM_RTL8211x_PHY_INTR_DIS);
 127
 128        if (phydev->flags & PHY_RTL8211x_FORCE_MASTER) {
 129                unsigned int reg;
 130
 131                reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
 132                /* force manual master/slave configuration */
 133                reg |= MIIM_RTL8211x_CTRL1000T_MSCE;
 134                /* force master mode */
 135                reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
 136                phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
 137        }
 138        if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) {
 139                unsigned int reg;
 140
 141                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
 142                          7);
 143                phy_write(phydev, MDIO_DEVAD_NONE,
 144                          MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
 145                reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
 146                /* Ensure both internal delays are turned off */
 147                reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD);
 148                /* Flip the magic undocumented bits */
 149                reg |= MIIM_RTL8211E_CONFREG_MAGIC;
 150                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg);
 151                phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
 152                          0);
 153        }
 154        /* read interrupt status just to clear it */
 155        phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
 156
 157        genphy_config_aneg(phydev);
 158
 159        return 0;
 160}
 161
 162static int rtl8211f_config(struct phy_device *phydev)
 163{
 164        u16 reg;
 165
 166        if (phydev->flags & PHY_RTL8211F_FORCE_EEE_RXC_ON) {
 167                unsigned int reg;
 168
 169                reg = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
 170                reg &= ~MDIO_PCS_CTRL1_CLKSTOP_EN;
 171                phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, reg);
 172        }
 173
 174        phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
 175
 176        phy_write(phydev, MDIO_DEVAD_NONE,
 177                  MIIM_RTL8211F_PAGE_SELECT, 0xd08);
 178        reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x11);
 179
 180        /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
 181        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
 182            phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
 183                reg |= MIIM_RTL8211F_TX_DELAY;
 184        else
 185                reg &= ~MIIM_RTL8211F_TX_DELAY;
 186
 187        phy_write(phydev, MDIO_DEVAD_NONE, 0x11, reg);
 188
 189        /* enable RX-delay for rgmii-id and rgmii-rxid, otherwise disable it */
 190        reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x15);
 191        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
 192            phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
 193                reg |= MIIM_RTL8211F_RX_DELAY;
 194        else
 195                reg &= ~MIIM_RTL8211F_RX_DELAY;
 196        phy_write(phydev, MDIO_DEVAD_NONE, 0x15, reg);
 197
 198        /* restore to default page 0 */
 199        phy_write(phydev, MDIO_DEVAD_NONE,
 200                  MIIM_RTL8211F_PAGE_SELECT, 0x0);
 201
 202        /* Set green LED for Link, yellow LED for Active */
 203        phy_write(phydev, MDIO_DEVAD_NONE,
 204                  MIIM_RTL8211F_PAGE_SELECT, 0xd04);
 205        phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x617f);
 206        phy_write(phydev, MDIO_DEVAD_NONE,
 207                  MIIM_RTL8211F_PAGE_SELECT, 0x0);
 208
 209        genphy_config_aneg(phydev);
 210
 211        return 0;
 212}
 213
 214static int rtl8211x_parse_status(struct phy_device *phydev)
 215{
 216        unsigned int speed;
 217        unsigned int mii_reg;
 218
 219        mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_STATUS);
 220
 221        if (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
 222                int i = 0;
 223
 224                /* in case of timeout ->link is cleared */
 225                phydev->link = 1;
 226                puts("Waiting for PHY realtime link");
 227                while (!(mii_reg & MIIM_RTL8211x_PHYSTAT_SPDDONE)) {
 228                        /* Timeout reached ? */
 229                        if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
 230                                puts(" TIMEOUT !\n");
 231                                phydev->link = 0;
 232                                break;
 233                        }
 234
 235                        if ((i++ % 1000) == 0)
 236                                putc('.');
 237                        udelay(1000);   /* 1 ms */
 238                        mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
 239                                        MIIM_RTL8211x_PHY_STATUS);
 240                }
 241                puts(" done\n");
 242                udelay(500000); /* another 500 ms (results in faster booting) */
 243        } else {
 244                if (mii_reg & MIIM_RTL8211x_PHYSTAT_LINK)
 245                        phydev->link = 1;
 246                else
 247                        phydev->link = 0;
 248        }
 249
 250        if (mii_reg & MIIM_RTL8211x_PHYSTAT_DUPLEX)
 251                phydev->duplex = DUPLEX_FULL;
 252        else
 253                phydev->duplex = DUPLEX_HALF;
 254
 255        speed = (mii_reg & MIIM_RTL8211x_PHYSTAT_SPEED);
 256
 257        switch (speed) {
 258        case MIIM_RTL8211x_PHYSTAT_GBIT:
 259                phydev->speed = SPEED_1000;
 260                break;
 261        case MIIM_RTL8211x_PHYSTAT_100:
 262                phydev->speed = SPEED_100;
 263                break;
 264        default:
 265                phydev->speed = SPEED_10;
 266        }
 267
 268        return 0;
 269}
 270
 271static int rtl8211f_parse_status(struct phy_device *phydev)
 272{
 273        unsigned int speed;
 274        unsigned int mii_reg;
 275        int i = 0;
 276
 277        phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0xa43);
 278        mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PHY_STATUS);
 279
 280        phydev->link = 1;
 281        while (!(mii_reg & MIIM_RTL8211F_PHYSTAT_LINK)) {
 282                if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
 283                        puts(" TIMEOUT !\n");
 284                        phydev->link = 0;
 285                        break;
 286                }
 287
 288                if ((i++ % 1000) == 0)
 289                        putc('.');
 290                udelay(1000);
 291                mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
 292                                   MIIM_RTL8211F_PHY_STATUS);
 293        }
 294
 295        if (mii_reg & MIIM_RTL8211F_PHYSTAT_DUPLEX)
 296                phydev->duplex = DUPLEX_FULL;
 297        else
 298                phydev->duplex = DUPLEX_HALF;
 299
 300        speed = (mii_reg & MIIM_RTL8211F_PHYSTAT_SPEED);
 301
 302        switch (speed) {
 303        case MIIM_RTL8211F_PHYSTAT_GBIT:
 304                phydev->speed = SPEED_1000;
 305                break;
 306        case MIIM_RTL8211F_PHYSTAT_100:
 307                phydev->speed = SPEED_100;
 308                break;
 309        default:
 310                phydev->speed = SPEED_10;
 311        }
 312
 313        return 0;
 314}
 315
 316static int rtl8211x_startup(struct phy_device *phydev)
 317{
 318        int ret;
 319
 320        /* Read the Status (2x to make sure link is right) */
 321        ret = genphy_update_link(phydev);
 322        if (ret)
 323                return ret;
 324
 325        return rtl8211x_parse_status(phydev);
 326}
 327
 328static int rtl8211e_startup(struct phy_device *phydev)
 329{
 330        int ret;
 331
 332        ret = genphy_update_link(phydev);
 333        if (ret)
 334                return ret;
 335
 336        return genphy_parse_link(phydev);
 337}
 338
 339static int rtl8211f_startup(struct phy_device *phydev)
 340{
 341        int ret;
 342
 343        /* Read the Status (2x to make sure link is right) */
 344        ret = genphy_update_link(phydev);
 345        if (ret)
 346                return ret;
 347        /* Read the Status (2x to make sure link is right) */
 348
 349        return rtl8211f_parse_status(phydev);
 350}
 351
 352/* Support for RTL8211B PHY */
 353static struct phy_driver RTL8211B_driver = {
 354        .name = "RealTek RTL8211B",
 355        .uid = 0x1cc912,
 356        .mask = 0xffffff,
 357        .features = PHY_GBIT_FEATURES,
 358        .probe = &rtl8211b_probe,
 359        .config = &rtl8211x_config,
 360        .startup = &rtl8211x_startup,
 361        .shutdown = &genphy_shutdown,
 362};
 363
 364/* Support for RTL8211E-VB-CG, RTL8211E-VL-CG and RTL8211EG-VB-CG PHYs */
 365static struct phy_driver RTL8211E_driver = {
 366        .name = "RealTek RTL8211E",
 367        .uid = 0x1cc915,
 368        .mask = 0xffffff,
 369        .features = PHY_GBIT_FEATURES,
 370        .probe = &rtl8211e_probe,
 371        .config = &rtl8211x_config,
 372        .startup = &rtl8211e_startup,
 373        .shutdown = &genphy_shutdown,
 374};
 375
 376/* Support for RTL8211DN PHY */
 377static struct phy_driver RTL8211DN_driver = {
 378        .name = "RealTek RTL8211DN",
 379        .uid = 0x1cc914,
 380        .mask = 0xffffff,
 381        .features = PHY_GBIT_FEATURES,
 382        .config = &rtl8211x_config,
 383        .startup = &rtl8211x_startup,
 384        .shutdown = &genphy_shutdown,
 385};
 386
 387/* Support for RTL8211F PHY */
 388static struct phy_driver RTL8211F_driver = {
 389        .name = "RealTek RTL8211F",
 390        .uid = 0x1cc916,
 391        .mask = 0xffffff,
 392        .features = PHY_GBIT_FEATURES,
 393        .probe = &rtl8211f_probe,
 394        .config = &rtl8211f_config,
 395        .startup = &rtl8211f_startup,
 396        .shutdown = &genphy_shutdown,
 397        .readext = &rtl8211f_phy_extread,
 398        .writeext = &rtl8211f_phy_extwrite,
 399};
 400
 401int phy_realtek_init(void)
 402{
 403        phy_register(&RTL8211B_driver);
 404        phy_register(&RTL8211E_driver);
 405        phy_register(&RTL8211F_driver);
 406        phy_register(&RTL8211DN_driver);
 407
 408        return 0;
 409}
 410