1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2009 Industrie Dial Face S.p.A.
4 * Luigi 'Comio' Mantellini <luigi.mantellini@idf-hit.com>
5 *
6 * (C) Copyright 2001
7 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
8 */
9
10/*
11 * This provides a bit-banged interface to the ethernet MII management
12 * channel.
13 */
14
15#include <common.h>
16#include <ioports.h>
17#include <ppc_asm.tmpl>
18#include <miiphy.h>
19#include <asm/global_data.h>
20
21#ifndef CONFIG_BITBANGMII_MULTI
22
23/*
24 * If CONFIG_BITBANGMII_MULTI is not defined we use a
25 * compatibility layer with the previous miiphybb implementation
26 * based on macros usage.
27 *
28 */
29static int bb_mii_init_wrap(struct bb_miiphy_bus *bus)
30{
31#ifdef MII_INIT
32	MII_INIT;
33#endif
34	return 0;
35}
36
37static int bb_mdio_active_wrap(struct bb_miiphy_bus *bus)
38{
39#ifdef MDIO_DECLARE
40	MDIO_DECLARE;
41#endif
42	MDIO_ACTIVE;
43	return 0;
44}
45
46static int bb_mdio_tristate_wrap(struct bb_miiphy_bus *bus)
47{
48#ifdef MDIO_DECLARE
49	MDIO_DECLARE;
50#endif
51	MDIO_TRISTATE;
52	return 0;
53}
54
55static int bb_set_mdio_wrap(struct bb_miiphy_bus *bus, int v)
56{
57#ifdef MDIO_DECLARE
58	MDIO_DECLARE;
59#endif
60	MDIO(v);
61	return 0;
62}
63
64static int bb_get_mdio_wrap(struct bb_miiphy_bus *bus, int *v)
65{
66#ifdef MDIO_DECLARE
67	MDIO_DECLARE;
68#endif
69	*v = MDIO_READ;
70	return 0;
71}
72
73static int bb_set_mdc_wrap(struct bb_miiphy_bus *bus, int v)
74{
75#ifdef MDC_DECLARE
76	MDC_DECLARE;
77#endif
78	MDC(v);
79	return 0;
80}
81
82static int bb_delay_wrap(struct bb_miiphy_bus *bus)
83{
84	MIIDELAY;
85	return 0;
86}
87
88struct bb_miiphy_bus bb_miiphy_buses[] = {
89	{
90		.name = BB_MII_DEVNAME,
91		.init = bb_mii_init_wrap,
92		.mdio_active = bb_mdio_active_wrap,
93		.mdio_tristate = bb_mdio_tristate_wrap,
94		.set_mdio = bb_set_mdio_wrap,
95		.get_mdio = bb_get_mdio_wrap,
96		.set_mdc = bb_set_mdc_wrap,
97		.delay = bb_delay_wrap,
98	}
99};
100
101int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
102			  sizeof(bb_miiphy_buses[0]);
103#endif
104
105int bb_miiphy_init(void)
106{
107	int i;
108
109	for (i = 0; i < bb_miiphy_buses_num; i++)
110		if (bb_miiphy_buses[i].init != NULL)
111			bb_miiphy_buses[i].init(&bb_miiphy_buses[i]);
112
113	return 0;
114}
115
116static inline struct bb_miiphy_bus *bb_miiphy_getbus(const char *devname)
117{
118#ifdef CONFIG_BITBANGMII_MULTI
119	int i;
120
121	/* Search the correct bus */
122	for (i = 0; i < bb_miiphy_buses_num; i++) {
123		if (!strcmp(bb_miiphy_buses[i].name, devname)) {
124			return &bb_miiphy_buses[i];
125		}
126	}
127	return NULL;
128#else
129	/* We have just one bitbanging bus */
130	return &bb_miiphy_buses[0];
131#endif
132}
133
134/*****************************************************************************
135 *
136 * Utility to send the preamble, address, and register (common to read
137 * and write).
138 */
139static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
140		       unsigned char addr, unsigned char reg)
141{
142	int j;
143
144	/*
145	 * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
146	 * The IEEE spec says this is a PHY optional requirement.  The AMD
147	 * 79C874 requires one after power up and one after a MII communications
148	 * error.  This means that we are doing more preambles than we need,
149	 * but it is safer and will be much more robust.
150	 */
151
152	bus->mdio_active(bus);
153	bus->set_mdio(bus, 1);
154	for (j = 0; j < 32; j++) {
155		bus->set_mdc(bus, 0);
156		bus->delay(bus);
157		bus->set_mdc(bus, 1);
158		bus->delay(bus);
159	}
160
161	/* send the start bit (01) and the read opcode (10) or write (10) */
162	bus->set_mdc(bus, 0);
163	bus->set_mdio(bus, 0);
164	bus->delay(bus);
165	bus->set_mdc(bus, 1);
166	bus->delay(bus);
167	bus->set_mdc(bus, 0);
168	bus->set_mdio(bus, 1);
169	bus->delay(bus);
170	bus->set_mdc(bus, 1);
171	bus->delay(bus);
172	bus->set_mdc(bus, 0);
173	bus->set_mdio(bus, read);
174	bus->delay(bus);
175	bus->set_mdc(bus, 1);
176	bus->delay(bus);
177	bus->set_mdc(bus, 0);
178	bus->set_mdio(bus, !read);
179	bus->delay(bus);
180	bus->set_mdc(bus, 1);
181	bus->delay(bus);
182
183	/* send the PHY address */
184	for (j = 0; j < 5; j++) {
185		bus->set_mdc(bus, 0);
186		if ((addr & 0x10) == 0) {
187			bus->set_mdio(bus, 0);
188		} else {
189			bus->set_mdio(bus, 1);
190		}
191		bus->delay(bus);
192		bus->set_mdc(bus, 1);
193		bus->delay(bus);
194		addr <<= 1;
195	}
196
197	/* send the register address */
198	for (j = 0; j < 5; j++) {
199		bus->set_mdc(bus, 0);
200		if ((reg & 0x10) == 0) {
201			bus->set_mdio(bus, 0);
202		} else {
203			bus->set_mdio(bus, 1);
204		}
205		bus->delay(bus);
206		bus->set_mdc(bus, 1);
207		bus->delay(bus);
208		reg <<= 1;
209	}
210}
211
212/*****************************************************************************
213 *
214 * Read a MII PHY register.
215 *
216 * Returns:
217 *   0 on success
218 */
219int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg)
220{
221	unsigned short rdreg; /* register working value */
222	int v;
223	int j; /* counter */
224	struct bb_miiphy_bus *bus;
225
226	bus = bb_miiphy_getbus(miidev->name);
227	if (bus == NULL) {
228		return -1;
229	}
230
231	miiphy_pre (bus, 1, addr, reg);
232
233	/* tri-state our MDIO I/O pin so we can read */
234	bus->set_mdc(bus, 0);
235	bus->mdio_tristate(bus);
236	bus->delay(bus);
237	bus->set_mdc(bus, 1);
238	bus->delay(bus);
239
240	/* check the turnaround bit: the PHY should be driving it to zero */
241	bus->get_mdio(bus, &v);
242	if (v != 0) {
243		/* puts ("PHY didn't drive TA low\n"); */
244		for (j = 0; j < 32; j++) {
245			bus->set_mdc(bus, 0);
246			bus->delay(bus);
247			bus->set_mdc(bus, 1);
248			bus->delay(bus);
249		}
250		/* There is no PHY, return */
251		return -1;
252	}
253
254	bus->set_mdc(bus, 0);
255	bus->delay(bus);
256
257	/* read 16 bits of register data, MSB first */
258	rdreg = 0;
259	for (j = 0; j < 16; j++) {
260		bus->set_mdc(bus, 1);
261		bus->delay(bus);
262		rdreg <<= 1;
263		bus->get_mdio(bus, &v);
264		rdreg |= (v & 0x1);
265		bus->set_mdc(bus, 0);
266		bus->delay(bus);
267	}
268
269	bus->set_mdc(bus, 1);
270	bus->delay(bus);
271	bus->set_mdc(bus, 0);
272	bus->delay(bus);
273	bus->set_mdc(bus, 1);
274	bus->delay(bus);
275
276#ifdef DEBUG
277	printf("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, rdreg);
278#endif
279
280	return rdreg;
281}
282
283
284/*****************************************************************************
285 *
286 * Write a MII PHY register.
287 *
288 * Returns:
289 *   0 on success
290 */
291int bb_miiphy_write(struct mii_dev *miidev, int addr, int devad, int reg,
292		    u16 value)
293{
294	struct bb_miiphy_bus *bus;
295	int j;			/* counter */
296
297	bus = bb_miiphy_getbus(miidev->name);
298	if (bus == NULL) {
299		/* Bus not found! */
300		return -1;
301	}
302
303	miiphy_pre (bus, 0, addr, reg);
304
305	/* send the turnaround (10) */
306	bus->set_mdc(bus, 0);
307	bus->set_mdio(bus, 1);
308	bus->delay(bus);
309	bus->set_mdc(bus, 1);
310	bus->delay(bus);
311	bus->set_mdc(bus, 0);
312	bus->set_mdio(bus, 0);
313	bus->delay(bus);
314	bus->set_mdc(bus, 1);
315	bus->delay(bus);
316
317	/* write 16 bits of register data, MSB first */
318	for (j = 0; j < 16; j++) {
319		bus->set_mdc(bus, 0);
320		if ((value & 0x00008000) == 0) {
321			bus->set_mdio(bus, 0);
322		} else {
323			bus->set_mdio(bus, 1);
324		}
325		bus->delay(bus);
326		bus->set_mdc(bus, 1);
327		bus->delay(bus);
328		value <<= 1;
329	}
330
331	/*
332	 * Tri-state the MDIO line.
333	 */
334	bus->mdio_tristate(bus);
335	bus->set_mdc(bus, 0);
336	bus->delay(bus);
337	bus->set_mdc(bus, 1);
338	bus->delay(bus);
339
340	return 0;
341}
342