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