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 
34 enum mvmdio_bus_type {
35 	BUS_TYPE_SMI,
36 	BUS_TYPE_XSMI
37 };
38 
39 struct mvmdio_priv {
40 	void *mdio_base;
41 	enum mvmdio_bus_type type;
42 };
43 
mvmdio_smi_read(struct udevice * dev,int addr,int devad,int reg)44 static 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 
mvmdio_smi_write(struct udevice * dev,int addr,int devad,int reg,u16 value)78 static 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 
mvmdio_xsmi_read(struct udevice * dev,int addr,int devad,int reg)101 static 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 
mvmdio_xsmi_write(struct udevice * dev,int addr,int devad,int reg,u16 value)135 static 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 
mvmdio_read(struct udevice * dev,int addr,int devad,int reg)158 static 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 
mvmdio_write(struct udevice * dev,int addr,int devad,int reg,u16 value)175 static 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  */
mvmdio_bind(struct udevice * dev)198 static 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 */
mvmdio_probe(struct udevice * dev)207 static 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 
217 static const struct mdio_ops mvmdio_ops = {
218 	.read = mvmdio_read,
219 	.write = mvmdio_write,
220 };
221 
222 static 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 
228 U_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