123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2018 Marvell International Ltd.
- * Author: Ken Ma<make@marvell.com>
- */
- #include <common.h>
- #include <dm.h>
- #include <dm/device-internal.h>
- #include <dm/lists.h>
- #include <miiphy.h>
- #include <phy.h>
- #include <asm/io.h>
- #include <wait_bit.h>
- #include <linux/bitops.h>
- #define MVMDIO_SMI_DATA_SHIFT 0
- #define MVMDIO_SMI_PHY_ADDR_SHIFT 16
- #define MVMDIO_SMI_PHY_REG_SHIFT 21
- #define MVMDIO_SMI_READ_OPERATION BIT(26)
- #define MVMDIO_SMI_WRITE_OPERATION 0
- #define MVMDIO_SMI_READ_VALID BIT(27)
- #define MVMDIO_SMI_BUSY BIT(28)
- #define MVMDIO_XSMI_MGNT_REG 0x0
- #define MVMDIO_XSMI_PHYADDR_SHIFT 16
- #define MVMDIO_XSMI_DEVADDR_SHIFT 21
- #define MVMDIO_XSMI_WRITE_OPERATION (0x5 << 26)
- #define MVMDIO_XSMI_READ_OPERATION (0x7 << 26)
- #define MVMDIO_XSMI_READ_VALID BIT(29)
- #define MVMDIO_XSMI_BUSY BIT(30)
- #define MVMDIO_XSMI_ADDR_REG 0x8
- enum mvmdio_bus_type {
- BUS_TYPE_SMI,
- BUS_TYPE_XSMI
- };
- struct mvmdio_priv {
- void *mdio_base;
- enum mvmdio_bus_type type;
- };
- static int mvmdio_smi_read(struct udevice *dev, int addr,
- int devad, int reg)
- {
- struct mvmdio_priv *priv = dev_get_priv(dev);
- u32 val;
- int ret;
- if (devad != MDIO_DEVAD_NONE)
- return -EOPNOTSUPP;
- ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
- false, CONFIG_SYS_HZ, false);
- if (ret < 0)
- return ret;
- writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
- (reg << MVMDIO_SMI_PHY_REG_SHIFT) |
- MVMDIO_SMI_READ_OPERATION),
- priv->mdio_base);
- ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
- false, CONFIG_SYS_HZ, false);
- if (ret < 0)
- return ret;
- val = readl(priv->mdio_base);
- if (!(val & MVMDIO_SMI_READ_VALID)) {
- pr_err("SMI bus read not valid\n");
- return -ENODEV;
- }
- return val & GENMASK(15, 0);
- }
- static int mvmdio_smi_write(struct udevice *dev, int addr, int devad,
- int reg, u16 value)
- {
- struct mvmdio_priv *priv = dev_get_priv(dev);
- int ret;
- if (devad != MDIO_DEVAD_NONE)
- return -EOPNOTSUPP;
- ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
- false, CONFIG_SYS_HZ, false);
- if (ret < 0)
- return ret;
- writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
- (reg << MVMDIO_SMI_PHY_REG_SHIFT) |
- MVMDIO_SMI_WRITE_OPERATION |
- (value << MVMDIO_SMI_DATA_SHIFT)),
- priv->mdio_base);
- return 0;
- }
- static int mvmdio_xsmi_read(struct udevice *dev, int addr,
- int devad, int reg)
- {
- struct mvmdio_priv *priv = dev_get_priv(dev);
- int ret;
- if (devad == MDIO_DEVAD_NONE)
- return -EOPNOTSUPP;
- ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
- false, CONFIG_SYS_HZ, false);
- if (ret < 0)
- return ret;
- writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
- writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
- (devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
- MVMDIO_XSMI_READ_OPERATION),
- priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
- ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
- false, CONFIG_SYS_HZ, false);
- if (ret < 0)
- return ret;
- if (!(readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) &
- MVMDIO_XSMI_READ_VALID)) {
- pr_err("XSMI bus read not valid\n");
- return -ENODEV;
- }
- return readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
- }
- static int mvmdio_xsmi_write(struct udevice *dev, int addr, int devad,
- int reg, u16 value)
- {
- struct mvmdio_priv *priv = dev_get_priv(dev);
- int ret;
- if (devad == MDIO_DEVAD_NONE)
- return -EOPNOTSUPP;
- ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
- false, CONFIG_SYS_HZ, false);
- if (ret < 0)
- return ret;
- writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
- writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
- (devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
- MVMDIO_XSMI_WRITE_OPERATION | value),
- priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
- return 0;
- }
- static int mvmdio_read(struct udevice *dev, int addr, int devad, int reg)
- {
- struct mvmdio_priv *priv = dev_get_priv(dev);
- int err = -ENOTSUPP;
- switch (priv->type) {
- case BUS_TYPE_SMI:
- err = mvmdio_smi_read(dev, addr, devad, reg);
- break;
- case BUS_TYPE_XSMI:
- err = mvmdio_xsmi_read(dev, addr, devad, reg);
- break;
- }
- return err;
- }
- static int mvmdio_write(struct udevice *dev, int addr, int devad, int reg,
- u16 value)
- {
- struct mvmdio_priv *priv = dev_get_priv(dev);
- int err = -ENOTSUPP;
- switch (priv->type) {
- case BUS_TYPE_SMI:
- err = mvmdio_smi_write(dev, addr, devad, reg, value);
- break;
- case BUS_TYPE_XSMI:
- err = mvmdio_xsmi_write(dev, addr, devad, reg, value);
- break;
- }
- return err;
- }
- /*
- * Name the device, we use the device tree node name.
- * This can be overwritten by MDIO class code if device-name property is
- * present.
- */
- static int mvmdio_bind(struct udevice *dev)
- {
- if (ofnode_valid(dev->node))
- device_set_name(dev, ofnode_get_name(dev->node));
- return 0;
- }
- /* Get device base address and type, either C22 SMII or C45 XSMI */
- static int mvmdio_probe(struct udevice *dev)
- {
- struct mvmdio_priv *priv = dev_get_priv(dev);
- priv->mdio_base = (void *)dev_read_addr(dev);
- priv->type = (enum mvmdio_bus_type)dev_get_driver_data(dev);
- return 0;
- }
- static const struct mdio_ops mvmdio_ops = {
- .read = mvmdio_read,
- .write = mvmdio_write,
- };
- static const struct udevice_id mvmdio_ids[] = {
- { .compatible = "marvell,orion-mdio", .data = BUS_TYPE_SMI },
- { .compatible = "marvell,xmdio", .data = BUS_TYPE_XSMI },
- { }
- };
- U_BOOT_DRIVER(mvmdio) = {
- .name = "mvmdio",
- .id = UCLASS_MDIO,
- .of_match = mvmdio_ids,
- .bind = mvmdio_bind,
- .probe = mvmdio_probe,
- .ops = &mvmdio_ops,
- .priv_auto_alloc_size = sizeof(struct mvmdio_priv),
- };
|