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 <dm.h> 8#include <dm/device-internal.h> 9#include <dm/lists.h> 10#include <miiphy.h> 11#include <phy.h> 12#include <asm/io.h> 13#include <wait_bit.h> 14#include <linux/bitops.h> 15#include <linux/printk.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 = dev_read_addr_ptr(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