uboot/drivers/net/mvmdio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Marvell International Ltd.
   4 * Author: Ken Ma<make@marvell.com>
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <dm/device-internal.h>
  10#include <dm/lists.h>
  11#include <miiphy.h>
  12#include <phy.h>
  13#include <asm/io.h>
  14#include <wait_bit.h>
  15
  16#define MVMDIO_SMI_DATA_SHIFT           0
  17#define MVMDIO_SMI_PHY_ADDR_SHIFT       16
  18#define MVMDIO_SMI_PHY_REG_SHIFT        21
  19#define MVMDIO_SMI_READ_OPERATION       BIT(26)
  20#define MVMDIO_SMI_WRITE_OPERATION      0
  21#define MVMDIO_SMI_READ_VALID           BIT(27)
  22#define MVMDIO_SMI_BUSY                 BIT(28)
  23
  24#define MVMDIO_XSMI_MGNT_REG            0x0
  25#define MVMDIO_XSMI_PHYADDR_SHIFT       16
  26#define MVMDIO_XSMI_DEVADDR_SHIFT       21
  27#define MVMDIO_XSMI_WRITE_OPERATION     (0x5 << 26)
  28#define MVMDIO_XSMI_READ_OPERATION      (0x7 << 26)
  29#define MVMDIO_XSMI_READ_VALID          BIT(29)
  30#define MVMDIO_XSMI_BUSY                BIT(30)
  31#define MVMDIO_XSMI_ADDR_REG            0x8
  32
  33enum mvmdio_bus_type {
  34        BUS_TYPE_SMI,
  35        BUS_TYPE_XSMI
  36};
  37
  38struct mvmdio_priv {
  39        void *mdio_base;
  40        enum mvmdio_bus_type type;
  41};
  42
  43static int mvmdio_smi_read(struct udevice *dev, int addr,
  44                           int devad, int reg)
  45{
  46        struct mvmdio_priv *priv = dev_get_priv(dev);
  47        u32 val;
  48        int ret;
  49
  50        if (devad != MDIO_DEVAD_NONE)
  51                return -EOPNOTSUPP;
  52
  53        ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
  54                                false, CONFIG_SYS_HZ, false);
  55        if (ret < 0)
  56                return ret;
  57
  58        writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
  59                (reg << MVMDIO_SMI_PHY_REG_SHIFT)  |
  60                MVMDIO_SMI_READ_OPERATION),
  61               priv->mdio_base);
  62
  63        ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
  64                                false, CONFIG_SYS_HZ, false);
  65        if (ret < 0)
  66                return ret;
  67
  68        val = readl(priv->mdio_base);
  69        if (!(val & MVMDIO_SMI_READ_VALID)) {
  70                pr_err("SMI bus read not valid\n");
  71                return -ENODEV;
  72        }
  73
  74        return val & GENMASK(15, 0);
  75}
  76
  77static int mvmdio_smi_write(struct udevice *dev, int addr, int devad,
  78                            int reg, u16 value)
  79{
  80        struct mvmdio_priv *priv = dev_get_priv(dev);
  81        int ret;
  82
  83        if (devad != MDIO_DEVAD_NONE)
  84                return -EOPNOTSUPP;
  85
  86        ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
  87                                false, CONFIG_SYS_HZ, false);
  88        if (ret < 0)
  89                return ret;
  90
  91        writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
  92                (reg << MVMDIO_SMI_PHY_REG_SHIFT)  |
  93                MVMDIO_SMI_WRITE_OPERATION            |
  94                (value << MVMDIO_SMI_DATA_SHIFT)),
  95               priv->mdio_base);
  96
  97        return 0;
  98}
  99
 100static int mvmdio_xsmi_read(struct udevice *dev, int addr,
 101                            int devad, int reg)
 102{
 103        struct mvmdio_priv *priv = dev_get_priv(dev);
 104        int ret;
 105
 106        if (devad == MDIO_DEVAD_NONE)
 107                return -EOPNOTSUPP;
 108
 109        ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
 110                                false, CONFIG_SYS_HZ, false);
 111        if (ret < 0)
 112                return ret;
 113
 114        writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
 115        writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
 116                (devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
 117                MVMDIO_XSMI_READ_OPERATION),
 118               priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
 119
 120        ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
 121                                false, CONFIG_SYS_HZ, false);
 122        if (ret < 0)
 123                return ret;
 124
 125        if (!(readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) &
 126              MVMDIO_XSMI_READ_VALID)) {
 127                pr_err("XSMI bus read not valid\n");
 128                return -ENODEV;
 129        }
 130
 131        return readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
 132}
 133
 134static int mvmdio_xsmi_write(struct udevice *dev, int addr, int devad,
 135                             int reg, u16 value)
 136{
 137        struct mvmdio_priv *priv = dev_get_priv(dev);
 138        int ret;
 139
 140        if (devad == MDIO_DEVAD_NONE)
 141                return -EOPNOTSUPP;
 142
 143        ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
 144                                false, CONFIG_SYS_HZ, false);
 145        if (ret < 0)
 146                return ret;
 147
 148        writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
 149        writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
 150                (devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
 151                MVMDIO_XSMI_WRITE_OPERATION | value),
 152               priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
 153
 154        return 0;
 155}
 156
 157static int mvmdio_read(struct udevice *dev, int addr, int devad, int reg)
 158{
 159        struct mvmdio_priv *priv = dev_get_priv(dev);
 160        int err = -ENOTSUPP;
 161
 162        switch (priv->type) {
 163        case BUS_TYPE_SMI:
 164                err = mvmdio_smi_read(dev, addr, devad, reg);
 165                break;
 166        case BUS_TYPE_XSMI:
 167                err = mvmdio_xsmi_read(dev, addr, devad, reg);
 168                break;
 169        }
 170
 171        return err;
 172}
 173
 174static int mvmdio_write(struct udevice *dev, int addr, int devad, int reg,
 175                        u16 value)
 176{
 177        struct mvmdio_priv *priv = dev_get_priv(dev);
 178        int err = -ENOTSUPP;
 179
 180        switch (priv->type) {
 181        case BUS_TYPE_SMI:
 182                err = mvmdio_smi_write(dev, addr, devad, reg, value);
 183                break;
 184        case BUS_TYPE_XSMI:
 185                err = mvmdio_xsmi_write(dev, addr, devad, reg, value);
 186                break;
 187        }
 188
 189        return err;
 190}
 191
 192/*
 193 * Name the device, we use the device tree node name.
 194 * This can be overwritten by MDIO class code if device-name property is
 195 * present.
 196 */
 197static int mvmdio_bind(struct udevice *dev)
 198{
 199        if (ofnode_valid(dev->node))
 200                device_set_name(dev, ofnode_get_name(dev->node));
 201
 202        return 0;
 203}
 204
 205/* Get device base address and type, either C22 SMII or C45 XSMI */
 206static int mvmdio_probe(struct udevice *dev)
 207{
 208        struct mvmdio_priv *priv = dev_get_priv(dev);
 209
 210        priv->mdio_base = (void *)dev_read_addr(dev);
 211        priv->type = (enum mvmdio_bus_type)dev_get_driver_data(dev);
 212
 213        return 0;
 214}
 215
 216static const struct mdio_ops mvmdio_ops = {
 217        .read = mvmdio_read,
 218        .write = mvmdio_write,
 219};
 220
 221static const struct udevice_id mvmdio_ids[] = {
 222        { .compatible = "marvell,orion-mdio", .data = BUS_TYPE_SMI },
 223        { .compatible = "marvell,xmdio", .data = BUS_TYPE_XSMI },
 224        { }
 225};
 226
 227U_BOOT_DRIVER(mvmdio) = {
 228        .name                   = "mvmdio",
 229        .id                     = UCLASS_MDIO,
 230        .of_match               = mvmdio_ids,
 231        .bind                   = mvmdio_bind,
 232        .probe                  = mvmdio_probe,
 233        .ops                    = &mvmdio_ops,
 234        .priv_auto_alloc_size   = sizeof(struct mvmdio_priv),
 235};
 236
 237