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