blob: a2a41f95190c9d6482e855bd62ca38309ab298b3 [file] [log] [blame]
Markus Gothefba38bf2024-11-19 08:26:44 -06001// SPDX-License-Identifier: GPL-2.0
2/*
3 * GPIO based MDIO bitbang driver.
4 *
5 * Copyright 2024 Markus Gothe <markus.gothe@genexis.eu>
6 *
7 * This file is based on the Linux kernel drivers drivers/net/phy/mdio-gpio.c
8 * and drivers/net/phy/mdio-bitbang.c which have the following copyrights:
9 *
10 * Copyright (c) 2008 CSE Semaphore Belgium.
11 * by Laurent Pinchart <laurentp@cse-semaphore.com>
12 *
13 * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
14 *
15 * Author: Scott Wood <scottwood@freescale.com>
16 * Copyright (c) 2007 Freescale Semiconductor
17 *
18 * Copyright (c) 2003 Intracom S.A.
19 * by Pantelis Antoniou <panto@intracom.gr>
20 *
21 * 2005 (c) MontaVista Software, Inc.
22 * Vitaly Bordug <vbordug@ru.mvista.com>
23 */
24
25#include <dm.h>
26#include <log.h>
27#include <miiphy.h>
28#include <asm/gpio.h>
29#include <linux/bitops.h>
30#include <linux/delay.h>
31#include <linux/mdio.h>
32
33#define MDIO_READ 2
34#define MDIO_WRITE 1
35
36#define MDIO_C45 BIT(15)
37#define MDIO_C45_ADDR (MDIO_C45 | 0)
38#define MDIO_C45_READ (MDIO_C45 | 3)
39#define MDIO_C45_WRITE (MDIO_C45 | 1)
40
41/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY
42 * is done twice per period.
43 */
44#define MDIO_DELAY 250
45
46/* The PHY may take up to 300 ns to produce data, plus some margin
47 * for error.
48 */
49#define MDIO_READ_DELAY 350
50
51#define MDIO_GPIO_MDC 0
52#define MDIO_GPIO_MDIO 1
53#define MDIO_GPIO_MDO 2
54
55struct mdio_gpio_priv {
56 struct gpio_desc mdc, mdio, mdo;
57};
58
59static void mdio_dir(struct udevice *mdio_dev, int dir)
60{
61 struct mdio_gpio_priv *priv = dev_get_priv(mdio_dev);
62
63 if (dm_gpio_is_valid(&priv->mdo)) {
64 /* Separate output pin. Always set its value to high
65 * when changing direction. If direction is input,
66 * assume the pin serves as pull-up. If direction is
67 * output, the default value is high.
68 */
69 dm_gpio_set_value(&priv->mdo, 1);
70 return;
71 }
72
73 if (dir)
74 dm_gpio_set_dir_flags(&priv->mdio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
75 else
76 dm_gpio_set_dir_flags(&priv->mdio, GPIOD_IS_IN);
77}
78
79static int mdio_get(struct udevice *mdio_dev)
80{
81 struct mdio_gpio_priv *priv = dev_get_priv(mdio_dev);
82
83 return dm_gpio_get_value(&priv->mdio);
84}
85
86static void mdio_set(struct udevice *mdio_dev, int what)
87{
88 struct mdio_gpio_priv *priv = dev_get_priv(mdio_dev);
89
90 if (dm_gpio_is_valid(&priv->mdo))
91 dm_gpio_set_value(&priv->mdo, what);
92 else
93 dm_gpio_set_value(&priv->mdio, what);
94}
95
96static void mdc_set(struct udevice *mdio_dev, int what)
97{
98 struct mdio_gpio_priv *priv = dev_get_priv(mdio_dev);
99
100 dm_gpio_set_value(&priv->mdc, what);
101}
102
103/* MDIO must already be configured as output. */
104static void mdio_gpio_send_bit(struct udevice *mdio_dev, int val)
105{
106 mdio_set(mdio_dev, val);
107 ndelay(MDIO_DELAY);
108 mdc_set(mdio_dev, 1);
109 ndelay(MDIO_DELAY);
110 mdc_set(mdio_dev, 0);
111}
112
113/* MDIO must already be configured as input. */
114static int mdio_gpio_get_bit(struct udevice *mdio_dev)
115{
116 ndelay(MDIO_DELAY);
117 mdc_set(mdio_dev, 1);
118 ndelay(MDIO_READ_DELAY);
119 mdc_set(mdio_dev, 0);
120
121 return mdio_get(mdio_dev);
122}
123
124/* MDIO must already be configured as output. */
125static void mdio_gpio_send_num(struct udevice *mdio_dev, u16 val, int bits)
126{
127 int i;
128
129 for (i = bits - 1; i >= 0; i--)
130 mdio_gpio_send_bit(mdio_dev, (val >> i) & 1);
131}
132
133/* MDIO must already be configured as input. */
134static u16 mdio_gpio_get_num(struct udevice *mdio_dev, int bits)
135{
136 int i;
137 u16 ret = 0;
138
139 for (i = bits - 1; i >= 0; i--) {
140 ret <<= 1;
141 ret |= mdio_gpio_get_bit(mdio_dev);
142 }
143
144 return ret;
145}
146
147/* Utility to send the preamble, address, and
148 * register (common to read and write).
149 */
150static void mdio_gpio_cmd(struct udevice *mdio_dev, int op, u8 phy, u8 reg)
151{
152 int i;
153
154 mdio_dir(mdio_dev, 1);
155
156 /*
157 * Send a 32 bit preamble ('1's) with an extra '1' bit for good
158 * measure. The IEEE spec says this is a PHY optional
159 * requirement. The AMD 79C874 requires one after power up and
160 * one after a MII communications error. This means that we are
161 * doing more preambles than we need, but it is safer and will be
162 * much more robust.
163 */
164 for (i = 0; i < 32; i++)
165 mdio_gpio_send_bit(mdio_dev, 1);
166
167 /*
168 * Send the start bit (01) and the read opcode (10) or write (01).
169 * Clause 45 operation uses 00 for the start and 11, 10 for
170 * read/write.
171 */
172 mdio_gpio_send_bit(mdio_dev, 0);
173 if (op & MDIO_C45)
174 mdio_gpio_send_bit(mdio_dev, 0);
175 else
176 mdio_gpio_send_bit(mdio_dev, 1);
177 mdio_gpio_send_bit(mdio_dev, (op >> 1) & 1);
178 mdio_gpio_send_bit(mdio_dev, (op >> 0) & 1);
179
180 mdio_gpio_send_num(mdio_dev, phy, 5);
181 mdio_gpio_send_num(mdio_dev, reg, 5);
182}
183
184/*
185 * In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the
186 * lower 16 bits of the 21 bit address. This transfer is done identically to a
187 * MDIO_WRITE except for a different code. To enable clause 45 mode or
188 * MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices
189 * can exist on the same bus. Normal devices should ignore the MDIO_ADDR
190 * phase.
191 */
192static int mdio_gpio_cmd_addr(struct udevice *mdio_dev, int phy, u32 dev_addr, u32 reg)
193{
194 mdio_gpio_cmd(mdio_dev, MDIO_C45_ADDR, phy, dev_addr);
195
196 /* send the turnaround (10) */
197 mdio_gpio_send_bit(mdio_dev, 1);
198 mdio_gpio_send_bit(mdio_dev, 0);
199
200 mdio_gpio_send_num(mdio_dev, reg, 16);
201
202 mdio_dir(mdio_dev, 0);
203 mdio_gpio_get_bit(mdio_dev);
204
205 return dev_addr;
206}
207
208static int mdio_gpio_read(struct udevice *mdio_dev, int addr, int devad, int reg)
209{
210 int ret, i;
211
212 if (devad != MDIO_DEVAD_NONE) {
213 reg = mdio_gpio_cmd_addr(mdio_dev, addr, devad, reg);
214 mdio_gpio_cmd(mdio_dev, MDIO_C45_READ, addr, reg);
215 } else {
216 mdio_gpio_cmd(mdio_dev, MDIO_READ, addr, reg);
217 }
218
219 mdio_dir(mdio_dev, 0);
220
221 /* check the turnaround bit: the PHY should be driving it to zero.
222 */
223 if (mdio_gpio_get_bit(mdio_dev) != 0) {
224 /* PHY didn't drive TA low -- flush any bits it
225 * may be trying to send.
226 */
227 for (i = 0; i < 32; i++)
228 mdio_gpio_get_bit(mdio_dev);
229
230 return 0xffff;
231 }
232
233 ret = mdio_gpio_get_num(mdio_dev, 16);
234 mdio_gpio_get_bit(mdio_dev);
235
236 return ret;
237}
238
239static int mdio_gpio_write(struct udevice *mdio_dev, int addr, int devad, int reg, u16 val)
240{
241 if (devad != MDIO_DEVAD_NONE) {
242 reg = mdio_gpio_cmd_addr(mdio_dev, addr, devad, reg);
243 mdio_gpio_cmd(mdio_dev, MDIO_C45_WRITE, addr, reg);
244 } else {
245 mdio_gpio_cmd(mdio_dev, MDIO_WRITE, addr, reg);
246 }
247
248 /* send the turnaround (10) */
249 mdio_gpio_send_bit(mdio_dev, 1);
250 mdio_gpio_send_bit(mdio_dev, 0);
251
252 mdio_gpio_send_num(mdio_dev, val, 16);
253
254 mdio_dir(mdio_dev, 0);
255 mdio_gpio_get_bit(mdio_dev);
256
257 return 0;
258}
259
260static const struct mdio_ops mdio_gpio_ops = {
261 .read = mdio_gpio_read,
262 .write = mdio_gpio_write,
263 .reset = NULL,
264};
265
266/*
267 * Name the device, we use the device tree node name.
268 * This can be overwritten by MDIO class code if device-name property is
269 * present.
270 */
271static int mdio_gpio_bind(struct udevice *mdio_dev)
272{
273 if (ofnode_valid(dev_ofnode(mdio_dev)))
274 device_set_name(mdio_dev, ofnode_get_name(dev_ofnode(mdio_dev)));
275
276 return 0;
277}
278
279static int mdio_gpio_probe(struct udevice *mdio_dev)
280{
281 struct mdio_gpio_priv *priv = dev_get_priv(mdio_dev);
282 int ret = 0;
283
284 ret = gpio_request_by_name(mdio_dev, "gpios", MDIO_GPIO_MDC, &priv->mdc, GPIOD_IS_OUT);
285 if (ret)
286 return ret;
287
288 ret = gpio_request_by_name(mdio_dev, "gpios", MDIO_GPIO_MDIO, &priv->mdio, GPIOD_IS_IN);
289 if (ret)
290 return ret;
291
292 ret = gpio_request_by_name(mdio_dev, "gpios", MDIO_GPIO_MDO, &priv->mdo, GPIOD_IS_OUT);
293 if (ret && ret != -ENOENT)
294 return ret;
295
296 return 0;
297}
298
299static const struct udevice_id mdio_gpio_ids[] = {
300 { .compatible = "virtual,mdio-gpio" },
301 { /* sentinel */ }
302};
303
304U_BOOT_DRIVER(gpio_mdio) = {
305 .name = "gpio_mdio",
306 .id = UCLASS_MDIO,
307 .of_match = mdio_gpio_ids,
308 .bind = mdio_gpio_bind,
309 .probe = mdio_gpio_probe,
310 .ops = &mdio_gpio_ops,
311 .plat_auto = sizeof(struct mdio_perdev_priv),
312 .priv_auto = sizeof(struct mdio_gpio_priv),
313};