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