uboot/drivers/net/phy/micrel_ksz90x1.c
<<
>>
Prefs
   1/*
   2 * Micrel PHY drivers
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 *
   6 * Copyright 2010-2011 Freescale Semiconductor, Inc.
   7 * author Andy Fleming
   8 * (C) 2012 NetModule AG, David Andrey, added KSZ9031
   9 * (C) Copyright 2017 Adaptrum, Inc.
  10 * Written by Alexandru Gagniuc <alex.g@adaptrum.com> for Adaptrum, Inc.
  11 */
  12
  13#include <config.h>
  14#include <common.h>
  15#include <dm.h>
  16#include <errno.h>
  17#include <micrel.h>
  18#include <phy.h>
  19
  20DECLARE_GLOBAL_DATA_PTR;
  21
  22/*
  23 * KSZ9021 - KSZ9031 common
  24 */
  25
  26#define MII_KSZ90xx_PHY_CTL             0x1f
  27#define MIIM_KSZ90xx_PHYCTL_1000        (1 << 6)
  28#define MIIM_KSZ90xx_PHYCTL_100         (1 << 5)
  29#define MIIM_KSZ90xx_PHYCTL_10          (1 << 4)
  30#define MIIM_KSZ90xx_PHYCTL_DUPLEX      (1 << 3)
  31
  32/* KSZ9021 PHY Registers */
  33#define MII_KSZ9021_EXTENDED_CTRL       0x0b
  34#define MII_KSZ9021_EXTENDED_DATAW      0x0c
  35#define MII_KSZ9021_EXTENDED_DATAR      0x0d
  36
  37#define CTRL1000_PREFER_MASTER          (1 << 10)
  38#define CTRL1000_CONFIG_MASTER          (1 << 11)
  39#define CTRL1000_MANUAL_CONFIG          (1 << 12)
  40
  41/* KSZ9031 PHY Registers */
  42#define MII_KSZ9031_MMD_ACCES_CTRL      0x0d
  43#define MII_KSZ9031_MMD_REG_DATA        0x0e
  44
  45static int ksz90xx_startup(struct phy_device *phydev)
  46{
  47        unsigned phy_ctl;
  48        int ret;
  49
  50        ret = genphy_update_link(phydev);
  51        if (ret)
  52                return ret;
  53
  54        phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL);
  55
  56        if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX)
  57                phydev->duplex = DUPLEX_FULL;
  58        else
  59                phydev->duplex = DUPLEX_HALF;
  60
  61        if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000)
  62                phydev->speed = SPEED_1000;
  63        else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100)
  64                phydev->speed = SPEED_100;
  65        else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10)
  66                phydev->speed = SPEED_10;
  67        return 0;
  68}
  69
  70/* Common OF config bits for KSZ9021 and KSZ9031 */
  71#ifdef CONFIG_DM_ETH
  72struct ksz90x1_reg_field {
  73        const char      *name;
  74        const u8        size;   /* Size of the bitfield, in bits */
  75        const u8        off;    /* Offset from bit 0 */
  76        const u8        dflt;   /* Default value */
  77};
  78
  79struct ksz90x1_ofcfg {
  80        const u16                       reg;
  81        const u16                       devad;
  82        const struct ksz90x1_reg_field  *grp;
  83        const u16                       grpsz;
  84};
  85
  86static const struct ksz90x1_reg_field ksz90x1_rxd_grp[] = {
  87        { "rxd0-skew-ps", 4, 0, 0x7 }, { "rxd1-skew-ps", 4, 4, 0x7 },
  88        { "rxd2-skew-ps", 4, 8, 0x7 }, { "rxd3-skew-ps", 4, 12, 0x7 }
  89};
  90
  91static const struct ksz90x1_reg_field ksz90x1_txd_grp[] = {
  92        { "txd0-skew-ps", 4, 0, 0x7 }, { "txd1-skew-ps", 4, 4, 0x7 },
  93        { "txd2-skew-ps", 4, 8, 0x7 }, { "txd3-skew-ps", 4, 12, 0x7 },
  94};
  95
  96static const struct ksz90x1_reg_field ksz9021_clk_grp[] = {
  97        { "txen-skew-ps", 4, 0, 0x7 }, { "txc-skew-ps", 4, 4, 0x7 },
  98        { "rxdv-skew-ps", 4, 8, 0x7 }, { "rxc-skew-ps", 4, 12, 0x7 },
  99};
 100
 101static const struct ksz90x1_reg_field ksz9031_ctl_grp[] = {
 102        { "txen-skew-ps", 4, 0, 0x7 }, { "rxdv-skew-ps", 4, 4, 0x7 }
 103};
 104
 105static const struct ksz90x1_reg_field ksz9031_clk_grp[] = {
 106        { "rxc-skew-ps", 5, 0, 0xf }, { "txc-skew-ps", 5, 5, 0xf }
 107};
 108
 109static int ksz90x1_of_config_group(struct phy_device *phydev,
 110                                   struct ksz90x1_ofcfg *ofcfg)
 111{
 112        struct udevice *dev = phydev->dev;
 113        struct phy_driver *drv = phydev->drv;
 114        const int ps_to_regval = 60;
 115        int val[4];
 116        int i, changed = 0, offset, max;
 117        u16 regval = 0;
 118
 119        if (!drv || !drv->writeext)
 120                return -EOPNOTSUPP;
 121
 122        for (i = 0; i < ofcfg->grpsz; i++) {
 123                val[i] = dev_read_u32_default(dev, ofcfg->grp[i].name, ~0);
 124                offset = ofcfg->grp[i].off;
 125                if (val[i] == -1) {
 126                        /* Default register value for KSZ9021 */
 127                        regval |= ofcfg->grp[i].dflt << offset;
 128                } else {
 129                        changed = 1;    /* Value was changed in OF */
 130                        /* Calculate the register value and fix corner cases */
 131                        if (val[i] > ps_to_regval * 0xf) {
 132                                max = (1 << ofcfg->grp[i].size) - 1;
 133                                regval |= max << offset;
 134                        } else {
 135                                regval |= (val[i] / ps_to_regval) << offset;
 136                        }
 137                }
 138        }
 139
 140        if (!changed)
 141                return 0;
 142
 143        return drv->writeext(phydev, 0, ofcfg->devad, ofcfg->reg, regval);
 144}
 145
 146static int ksz9021_of_config(struct phy_device *phydev)
 147{
 148        struct ksz90x1_ofcfg ofcfg[] = {
 149                { MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, 0, ksz90x1_rxd_grp, 4 },
 150                { MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, 0, ksz90x1_txd_grp, 4 },
 151                { MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, 0, ksz9021_clk_grp, 4 },
 152        };
 153        int i, ret = 0;
 154
 155        for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
 156                ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
 157                if (ret)
 158                        return ret;
 159        }
 160
 161        return 0;
 162}
 163
 164static int ksz9031_of_config(struct phy_device *phydev)
 165{
 166        struct ksz90x1_ofcfg ofcfg[] = {
 167                { MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW, 2, ksz9031_ctl_grp, 2 },
 168                { MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW, 2, ksz90x1_rxd_grp, 4 },
 169                { MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW, 2, ksz90x1_txd_grp, 4 },
 170                { MII_KSZ9031_EXT_RGMII_CLOCK_SKEW, 2, ksz9031_clk_grp, 2 },
 171        };
 172        int i, ret = 0;
 173
 174        for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
 175                ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
 176                if (ret)
 177                        return ret;
 178        }
 179
 180        return 0;
 181}
 182
 183static int ksz9031_center_flp_timing(struct phy_device *phydev)
 184{
 185        struct phy_driver *drv = phydev->drv;
 186        int ret = 0;
 187
 188        if (!drv || !drv->writeext)
 189                return -EOPNOTSUPP;
 190
 191        ret = drv->writeext(phydev, 0, 0, MII_KSZ9031_FLP_BURST_TX_LO, 0x1A80);
 192        if (ret)
 193                return ret;
 194
 195        ret = drv->writeext(phydev, 0, 0, MII_KSZ9031_FLP_BURST_TX_HI, 0x6);
 196        return ret;
 197}
 198
 199#else /* !CONFIG_DM_ETH */
 200static int ksz9021_of_config(struct phy_device *phydev)
 201{
 202        return 0;
 203}
 204
 205static int ksz9031_of_config(struct phy_device *phydev)
 206{
 207        return 0;
 208}
 209
 210static int ksz9031_center_flp_timing(struct phy_device *phydev)
 211{
 212        return 0;
 213}
 214#endif
 215
 216/*
 217 * KSZ9021
 218 */
 219int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val)
 220{
 221        /* extended registers */
 222        phy_write(phydev, MDIO_DEVAD_NONE,
 223                  MII_KSZ9021_EXTENDED_CTRL, regnum | 0x8000);
 224        return phy_write(phydev, MDIO_DEVAD_NONE,
 225                         MII_KSZ9021_EXTENDED_DATAW, val);
 226}
 227
 228int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum)
 229{
 230        /* extended registers */
 231        phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum);
 232        return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR);
 233}
 234
 235
 236static int ksz9021_phy_extread(struct phy_device *phydev, int addr, int devaddr,
 237                               int regnum)
 238{
 239        return ksz9021_phy_extended_read(phydev, regnum);
 240}
 241
 242static int ksz9021_phy_extwrite(struct phy_device *phydev, int addr,
 243                                int devaddr, int regnum, u16 val)
 244{
 245        return ksz9021_phy_extended_write(phydev, regnum, val);
 246}
 247
 248static int ksz9021_config(struct phy_device *phydev)
 249{
 250        unsigned ctrl1000 = 0;
 251        const unsigned master = CTRL1000_PREFER_MASTER |
 252        CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG;
 253        unsigned features = phydev->drv->features;
 254        int ret;
 255
 256        ret = ksz9021_of_config(phydev);
 257        if (ret)
 258                return ret;
 259
 260        if (env_get("disable_giga"))
 261                features &= ~(SUPPORTED_1000baseT_Half |
 262                SUPPORTED_1000baseT_Full);
 263        /* force master mode for 1000BaseT due to chip errata */
 264        if (features & SUPPORTED_1000baseT_Half)
 265                ctrl1000 |= ADVERTISE_1000HALF | master;
 266        if (features & SUPPORTED_1000baseT_Full)
 267                ctrl1000 |= ADVERTISE_1000FULL | master;
 268        phydev->advertising = features;
 269        phydev->supported = features;
 270        phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000);
 271        genphy_config_aneg(phydev);
 272        genphy_restart_aneg(phydev);
 273        return 0;
 274}
 275
 276static struct phy_driver ksz9021_driver = {
 277        .name = "Micrel ksz9021",
 278        .uid  = 0x221610,
 279        .mask = 0xfffff0,
 280        .features = PHY_GBIT_FEATURES,
 281        .config = &ksz9021_config,
 282        .startup = &ksz90xx_startup,
 283        .shutdown = &genphy_shutdown,
 284        .writeext = &ksz9021_phy_extwrite,
 285        .readext = &ksz9021_phy_extread,
 286};
 287
 288/*
 289 * KSZ9031
 290 */
 291int ksz9031_phy_extended_write(struct phy_device *phydev,
 292                               int devaddr, int regnum, u16 mode, u16 val)
 293{
 294        /*select register addr for mmd*/
 295        phy_write(phydev, MDIO_DEVAD_NONE,
 296                  MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
 297        /*select register for mmd*/
 298        phy_write(phydev, MDIO_DEVAD_NONE,
 299                  MII_KSZ9031_MMD_REG_DATA, regnum);
 300        /*setup mode*/
 301        phy_write(phydev, MDIO_DEVAD_NONE,
 302                  MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr));
 303        /*write the value*/
 304        return  phy_write(phydev, MDIO_DEVAD_NONE,
 305                          MII_KSZ9031_MMD_REG_DATA, val);
 306}
 307
 308int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
 309                              int regnum, u16 mode)
 310{
 311        phy_write(phydev, MDIO_DEVAD_NONE,
 312                  MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
 313        phy_write(phydev, MDIO_DEVAD_NONE,
 314                  MII_KSZ9031_MMD_REG_DATA, regnum);
 315        phy_write(phydev, MDIO_DEVAD_NONE,
 316                  MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode));
 317        return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA);
 318}
 319
 320static int ksz9031_phy_extread(struct phy_device *phydev, int addr, int devaddr,
 321                               int regnum)
 322{
 323        return ksz9031_phy_extended_read(phydev, devaddr, regnum,
 324                                         MII_KSZ9031_MOD_DATA_NO_POST_INC);
 325}
 326
 327static int ksz9031_phy_extwrite(struct phy_device *phydev, int addr,
 328                                int devaddr, int regnum, u16 val)
 329{
 330        return ksz9031_phy_extended_write(phydev, devaddr, regnum,
 331                                          MII_KSZ9031_MOD_DATA_POST_INC_RW, val);
 332}
 333
 334static int ksz9031_config(struct phy_device *phydev)
 335{
 336        int ret;
 337
 338        ret = ksz9031_of_config(phydev);
 339        if (ret)
 340                return ret;
 341        ret = ksz9031_center_flp_timing(phydev);
 342        if (ret)
 343                return ret;
 344
 345        /* add an option to disable the gigabit feature of this PHY */
 346        if (env_get("disable_giga")) {
 347                unsigned features;
 348                unsigned bmcr;
 349
 350                /* disable speed 1000 in features supported by the PHY */
 351                features = phydev->drv->features;
 352                features &= ~(SUPPORTED_1000baseT_Half |
 353                                SUPPORTED_1000baseT_Full);
 354                phydev->advertising = phydev->supported = features;
 355
 356                /* disable speed 1000 in Basic Control Register */
 357                bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
 358                bmcr &= ~(1 << 6);
 359                phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr);
 360
 361                /* disable speed 1000 in 1000Base-T Control Register */
 362                phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, 0);
 363
 364                /* start autoneg */
 365                genphy_config_aneg(phydev);
 366                genphy_restart_aneg(phydev);
 367
 368                return 0;
 369        }
 370
 371        return genphy_config(phydev);
 372}
 373
 374static struct phy_driver ksz9031_driver = {
 375        .name = "Micrel ksz9031",
 376        .uid  = 0x221620,
 377        .mask = 0xfffff0,
 378        .features = PHY_GBIT_FEATURES,
 379        .config   = &ksz9031_config,
 380        .startup  = &ksz90xx_startup,
 381        .shutdown = &genphy_shutdown,
 382        .writeext = &ksz9031_phy_extwrite,
 383        .readext = &ksz9031_phy_extread,
 384};
 385
 386int phy_micrel_ksz90x1_init(void)
 387{
 388        phy_register(&ksz9021_driver);
 389        phy_register(&ksz9031_driver);
 390        return 0;
 391}
 392