uboot/drivers/net/phy/ti.c
<<
>>
Prefs
   1/*
   2 * TI PHY drivers
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0
   5 *
   6 */
   7#include <common.h>
   8#include <phy.h>
   9#include <linux/compat.h>
  10#include <malloc.h>
  11
  12#include <fdtdec.h>
  13#include <dm.h>
  14#include <dt-bindings/net/ti-dp83867.h>
  15
  16DECLARE_GLOBAL_DATA_PTR;
  17
  18/* TI DP83867 */
  19#define DP83867_DEVADDR         0x1f
  20
  21#define MII_DP83867_PHYCTRL     0x10
  22#define MII_DP83867_MICR        0x12
  23#define MII_DP83867_CFG2        0x14
  24#define MII_DP83867_BISCR       0x16
  25#define DP83867_CTRL            0x1f
  26
  27/* Extended Registers */
  28#define DP83867_RGMIICTL        0x0032
  29#define DP83867_RGMIIDCTL       0x0086
  30#define DP83867_IO_MUX_CFG      0x0170
  31
  32#define DP83867_SW_RESET        BIT(15)
  33#define DP83867_SW_RESTART      BIT(14)
  34
  35/* MICR Interrupt bits */
  36#define MII_DP83867_MICR_AN_ERR_INT_EN          BIT(15)
  37#define MII_DP83867_MICR_SPEED_CHNG_INT_EN      BIT(14)
  38#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN   BIT(13)
  39#define MII_DP83867_MICR_PAGE_RXD_INT_EN        BIT(12)
  40#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN    BIT(11)
  41#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN   BIT(10)
  42#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN   BIT(8)
  43#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
  44#define MII_DP83867_MICR_WOL_INT_EN             BIT(3)
  45#define MII_DP83867_MICR_XGMII_ERR_INT_EN       BIT(2)
  46#define MII_DP83867_MICR_POL_CHNG_INT_EN        BIT(1)
  47#define MII_DP83867_MICR_JABBER_INT_EN          BIT(0)
  48
  49/* RGMIICTL bits */
  50#define DP83867_RGMII_TX_CLK_DELAY_EN           BIT(1)
  51#define DP83867_RGMII_RX_CLK_DELAY_EN           BIT(0)
  52
  53/* PHY CTRL bits */
  54#define DP83867_PHYCR_FIFO_DEPTH_SHIFT          14
  55#define DP83867_MDI_CROSSOVER           5
  56#define DP83867_MDI_CROSSOVER_AUTO      2
  57#define DP83867_MDI_CROSSOVER_MDIX      2
  58#define DP83867_PHYCTRL_SGMIIEN                 0x0800
  59#define DP83867_PHYCTRL_RXFIFO_SHIFT    12
  60#define DP83867_PHYCTRL_TXFIFO_SHIFT    14
  61
  62/* RGMIIDCTL bits */
  63#define DP83867_RGMII_TX_CLK_DELAY_SHIFT        4
  64
  65/* CFG2 bits */
  66#define MII_DP83867_CFG2_SPEEDOPT_10EN          0x0040
  67#define MII_DP83867_CFG2_SGMII_AUTONEGEN        0x0080
  68#define MII_DP83867_CFG2_SPEEDOPT_ENH           0x0100
  69#define MII_DP83867_CFG2_SPEEDOPT_CNT           0x0800
  70#define MII_DP83867_CFG2_SPEEDOPT_INTLOW        0x2000
  71#define MII_DP83867_CFG2_MASK                   0x003F
  72
  73#define MII_MMD_CTRL    0x0d /* MMD Access Control Register */
  74#define MII_MMD_DATA    0x0e /* MMD Access Data Register */
  75
  76/* MMD Access Control register fields */
  77#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
  78#define MII_MMD_CTRL_ADDR       0x0000 /* Address */
  79#define MII_MMD_CTRL_NOINCR     0x4000 /* no post increment */
  80#define MII_MMD_CTRL_INCR_RDWT  0x8000 /* post increment on reads & writes */
  81#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
  82
  83/* User setting - can be taken from DTS */
  84#define DEFAULT_RX_ID_DELAY     DP83867_RGMIIDCTL_2_25_NS
  85#define DEFAULT_TX_ID_DELAY     DP83867_RGMIIDCTL_2_75_NS
  86#define DEFAULT_FIFO_DEPTH      DP83867_PHYCR_FIFO_DEPTH_4_B_NIB
  87
  88/* IO_MUX_CFG bits */
  89#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL    0x1f
  90
  91#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX     0x0
  92#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN     0x1f
  93
  94struct dp83867_private {
  95        int rx_id_delay;
  96        int tx_id_delay;
  97        int fifo_depth;
  98        int io_impedance;
  99};
 100
 101/**
 102 * phy_read_mmd_indirect - reads data from the MMD registers
 103 * @phydev: The PHY device bus
 104 * @prtad: MMD Address
 105 * @devad: MMD DEVAD
 106 * @addr: PHY address on the MII bus
 107 *
 108 * Description: it reads data from the MMD registers (clause 22 to access to
 109 * clause 45) of the specified phy address.
 110 * To read these registers we have:
 111 * 1) Write reg 13 // DEVAD
 112 * 2) Write reg 14 // MMD Address
 113 * 3) Write reg 13 // MMD Data Command for MMD DEVAD
 114 * 3) Read  reg 14 // Read MMD data
 115 */
 116int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
 117                          int devad, int addr)
 118{
 119        int value = -1;
 120
 121        /* Write the desired MMD Devad */
 122        phy_write(phydev, addr, MII_MMD_CTRL, devad);
 123
 124        /* Write the desired MMD register address */
 125        phy_write(phydev, addr, MII_MMD_DATA, prtad);
 126
 127        /* Select the Function : DATA with no post increment */
 128        phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
 129
 130        /* Read the content of the MMD's selected register */
 131        value = phy_read(phydev, addr, MII_MMD_DATA);
 132        return value;
 133}
 134
 135/**
 136 * phy_write_mmd_indirect - writes data to the MMD registers
 137 * @phydev: The PHY device
 138 * @prtad: MMD Address
 139 * @devad: MMD DEVAD
 140 * @addr: PHY address on the MII bus
 141 * @data: data to write in the MMD register
 142 *
 143 * Description: Write data from the MMD registers of the specified
 144 * phy address.
 145 * To write these registers we have:
 146 * 1) Write reg 13 // DEVAD
 147 * 2) Write reg 14 // MMD Address
 148 * 3) Write reg 13 // MMD Data Command for MMD DEVAD
 149 * 3) Write reg 14 // Write MMD data
 150 */
 151void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
 152                            int devad, int addr, u32 data)
 153{
 154        /* Write the desired MMD Devad */
 155        phy_write(phydev, addr, MII_MMD_CTRL, devad);
 156
 157        /* Write the desired MMD register address */
 158        phy_write(phydev, addr, MII_MMD_DATA, prtad);
 159
 160        /* Select the Function : DATA with no post increment */
 161        phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
 162
 163        /* Write the data into MMD's selected register */
 164        phy_write(phydev, addr, MII_MMD_DATA, data);
 165}
 166
 167#if defined(CONFIG_DM_ETH)
 168/**
 169 * dp83867_data_init - Convenience function for setting PHY specific data
 170 *
 171 * @phydev: the phy_device struct
 172 */
 173static int dp83867_of_init(struct phy_device *phydev)
 174{
 175        struct dp83867_private *dp83867 = phydev->priv;
 176        struct udevice *dev = phydev->dev;
 177        int node = dev_of_offset(dev);
 178        const void *fdt = gd->fdt_blob;
 179
 180        if (fdtdec_get_bool(fdt, node, "ti,max-output-impedance"))
 181                dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
 182        else if (fdtdec_get_bool(fdt, node, "ti,min-output-impedance"))
 183                dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN;
 184        else
 185                dp83867->io_impedance = -EINVAL;
 186
 187        dp83867->rx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
 188                                 "ti,rx-internal-delay", -1);
 189
 190        dp83867->tx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
 191                                 "ti,tx-internal-delay", -1);
 192
 193        dp83867->fifo_depth = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
 194                                 "ti,fifo-depth", -1);
 195
 196        return 0;
 197}
 198#else
 199static int dp83867_of_init(struct phy_device *phydev)
 200{
 201        struct dp83867_private *dp83867 = phydev->priv;
 202
 203        dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY;
 204        dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY;
 205        dp83867->fifo_depth = DEFAULT_FIFO_DEPTH;
 206        dp83867->io_impedance = -EINVAL;
 207
 208        return 0;
 209}
 210#endif
 211
 212static int dp83867_config(struct phy_device *phydev)
 213{
 214        struct dp83867_private *dp83867;
 215        unsigned int val, delay, cfg2;
 216        int ret;
 217
 218        if (!phydev->priv) {
 219                dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL);
 220                if (!dp83867)
 221                        return -ENOMEM;
 222
 223                phydev->priv = dp83867;
 224                ret = dp83867_of_init(phydev);
 225                if (ret)
 226                        goto err_out;
 227        } else {
 228                dp83867 = (struct dp83867_private *)phydev->priv;
 229        }
 230
 231        /* Restart the PHY.  */
 232        val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL);
 233        phy_write(phydev, MDIO_DEVAD_NONE, DP83867_CTRL,
 234                  val | DP83867_SW_RESTART);
 235
 236        if (phy_interface_is_rgmii(phydev)) {
 237                ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
 238                        (DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) |
 239                        (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
 240                if (ret)
 241                        goto err_out;
 242        } else if (phy_interface_is_sgmii(phydev)) {
 243                phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
 244                          (BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000));
 245
 246                cfg2 = phy_read(phydev, phydev->addr, MII_DP83867_CFG2);
 247                cfg2 &= MII_DP83867_CFG2_MASK;
 248                cfg2 |= (MII_DP83867_CFG2_SPEEDOPT_10EN |
 249                         MII_DP83867_CFG2_SGMII_AUTONEGEN |
 250                         MII_DP83867_CFG2_SPEEDOPT_ENH |
 251                         MII_DP83867_CFG2_SPEEDOPT_CNT |
 252                         MII_DP83867_CFG2_SPEEDOPT_INTLOW);
 253                phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG2, cfg2);
 254
 255                phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
 256                                       DP83867_DEVADDR, phydev->addr, 0x0);
 257
 258                phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
 259                          DP83867_PHYCTRL_SGMIIEN |
 260                          (DP83867_MDI_CROSSOVER_MDIX <<
 261                          DP83867_MDI_CROSSOVER) |
 262                          (dp83867->fifo_depth << DP83867_PHYCTRL_RXFIFO_SHIFT) |
 263                          (dp83867->fifo_depth << DP83867_PHYCTRL_TXFIFO_SHIFT));
 264                phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0);
 265        }
 266
 267        if (phy_interface_is_rgmii(phydev)) {
 268                val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
 269                                            DP83867_DEVADDR, phydev->addr);
 270
 271                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
 272                        val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
 273                                DP83867_RGMII_RX_CLK_DELAY_EN);
 274
 275                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
 276                        val |= DP83867_RGMII_TX_CLK_DELAY_EN;
 277
 278                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
 279                        val |= DP83867_RGMII_RX_CLK_DELAY_EN;
 280
 281                phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
 282                                       DP83867_DEVADDR, phydev->addr, val);
 283
 284                delay = (dp83867->rx_id_delay |
 285                         (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
 286
 287                phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
 288                                       DP83867_DEVADDR, phydev->addr, delay);
 289
 290                if (dp83867->io_impedance >= 0) {
 291                        val = phy_read_mmd_indirect(phydev,
 292                                                    DP83867_IO_MUX_CFG,
 293                                                    DP83867_DEVADDR,
 294                                                    phydev->addr);
 295                        val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
 296                        val |= dp83867->io_impedance &
 297                               DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
 298                        phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
 299                                               DP83867_DEVADDR, phydev->addr,
 300                                               val);
 301                }
 302        }
 303
 304        genphy_config_aneg(phydev);
 305        return 0;
 306
 307err_out:
 308        kfree(dp83867);
 309        return ret;
 310}
 311
 312static struct phy_driver DP83867_driver = {
 313        .name = "TI DP83867",
 314        .uid = 0x2000a231,
 315        .mask = 0xfffffff0,
 316        .features = PHY_GBIT_FEATURES,
 317        .config = &dp83867_config,
 318        .startup = &genphy_startup,
 319        .shutdown = &genphy_shutdown,
 320};
 321
 322int phy_ti_init(void)
 323{
 324        phy_register(&DP83867_driver);
 325        return 0;
 326}
 327