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