source: SVN/rincon/u-boot/common/miiphyutil.c

Last change on this file was 55, checked in by Tim Harvey, 23 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 11.8 KB
Line 
1/*
2 * (C) Copyright 2001
3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * This provides a bit-banged interface to the ethernet MII management
26 * channel.
27 */
28
29#include <common.h>
30#include <miiphy.h>
31
32#include <asm/types.h>
33#include <linux/list.h>
34#include <malloc.h>
35#include <net.h>
36
37/* local debug macro */
38#undef MII_DEBUG
39
40#undef debug
41#ifdef MII_DEBUG
42#define debug(fmt,args...)      printf (fmt ,##args)
43#else
44#define debug(fmt,args...)
45#endif /* MII_DEBUG */
46
47struct mii_dev {
48        struct list_head link;
49        char *name;
50        int (*read) (char *devname, unsigned char addr,
51                     unsigned char reg, unsigned short *value);
52        int (*write) (char *devname, unsigned char addr,
53                      unsigned char reg, unsigned short value);
54};
55
56static struct list_head mii_devs;
57static struct mii_dev *current_mii;
58
59/*****************************************************************************
60 *
61 * Initialize global data. Need to be called before any other miiphy routine.
62 */
63void miiphy_init ()
64{
65        INIT_LIST_HEAD (&mii_devs);
66        current_mii = NULL;
67}
68
69/*****************************************************************************
70 *
71 * Register read and write MII access routines for the device <name>.
72 */
73void miiphy_register (char *name,
74                      int (*read) (char *devname, unsigned char addr,
75                                   unsigned char reg, unsigned short *value),
76                      int (*write) (char *devname, unsigned char addr,
77                                    unsigned char reg, unsigned short value))
78{
79        struct list_head *entry;
80        struct mii_dev *new_dev;
81        struct mii_dev *miidev;
82        unsigned int name_len;
83
84        /* check if we have unique name */
85        list_for_each (entry, &mii_devs) {
86                miidev = list_entry (entry, struct mii_dev, link);
87                if (strcmp (miidev->name, name) == 0) {
88                        printf ("miiphy_register: non unique device name "
89                                "'%s'\n", name);
90                        return;
91                }
92        }
93
94        /* allocate memory */
95        name_len = strlen (name);
96        new_dev =
97            (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1);
98
99        if (new_dev == NULL) {
100                printf ("miiphy_register: cannot allocate memory for '%s'\n",
101                        name);
102                return;
103        }
104        memset (new_dev, 0, sizeof (struct mii_dev) + name_len);
105
106        /* initalize mii_dev struct fields */
107        INIT_LIST_HEAD (&new_dev->link);
108        new_dev->read = read;
109        new_dev->write = write;
110        new_dev->name = (char *)(new_dev + 1);
111        strncpy (new_dev->name, name, name_len);
112        new_dev->name[name_len] = '\0';
113
114        debug ("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
115               new_dev->name, new_dev->read, new_dev->write);
116
117        /* add it to the list */
118        list_add_tail (&new_dev->link, &mii_devs);
119
120        if (!current_mii)
121                current_mii = new_dev;
122}
123
124int miiphy_set_current_dev (char *devname)
125{
126        struct list_head *entry;
127        struct mii_dev *dev;
128
129        list_for_each (entry, &mii_devs) {
130                dev = list_entry (entry, struct mii_dev, link);
131
132                if (strcmp (devname, dev->name) == 0) {
133                        current_mii = dev;
134                        return 0;
135                }
136        }
137
138        printf ("No such device: %s\n", devname);
139        return 1;
140}
141
142char *miiphy_get_current_dev ()
143{
144        if (current_mii)
145                return current_mii->name;
146
147        return NULL;
148}
149
150/*****************************************************************************
151 *
152 * Read to variable <value> from the PHY attached to device <devname>,
153 * use PHY address <addr> and register <reg>.
154 *
155 * Returns:
156 *   0 on success
157 */
158int miiphy_read (char *devname, unsigned char addr, unsigned char reg,
159                 unsigned short *value)
160{
161        struct list_head *entry;
162        struct mii_dev *dev;
163        int found_dev = 0;
164        int read_ret = 0;
165
166        if (!devname) {
167                printf ("NULL device name!\n");
168                return 1;
169        }
170
171        list_for_each (entry, &mii_devs) {
172                dev = list_entry (entry, struct mii_dev, link);
173
174                if (strcmp (devname, dev->name) == 0) {
175                        found_dev = 1;
176                        read_ret = dev->read (devname, addr, reg, value);
177                        break;
178                }
179        }
180
181        if (found_dev == 0)
182                printf ("No such device: %s\n", devname);
183
184        return ((found_dev) ? read_ret : 1);
185}
186
187/*****************************************************************************
188 *
189 * Write <value> to the PHY attached to device <devname>,
190 * use PHY address <addr> and register <reg>.
191 *
192 * Returns:
193 *   0 on success
194 */
195int miiphy_write (char *devname, unsigned char addr, unsigned char reg,
196                  unsigned short value)
197{
198        struct list_head *entry;
199        struct mii_dev *dev;
200        int found_dev = 0;
201        int write_ret = 0;
202
203        if (!devname) {
204                printf ("NULL device name!\n");
205                return 1;
206        }
207
208        list_for_each (entry, &mii_devs) {
209                dev = list_entry (entry, struct mii_dev, link);
210
211                if (strcmp (devname, dev->name) == 0) {
212                        found_dev = 1;
213                        write_ret = dev->write (devname, addr, reg, value);
214                        break;
215                }
216        }
217
218        if (found_dev == 0)
219                printf ("No such device: %s\n", devname);
220
221        return ((found_dev) ? write_ret : 1);
222}
223
224/*****************************************************************************
225 *
226 * Print out list of registered MII capable devices.
227 */
228void miiphy_listdev (void)
229{
230        struct list_head *entry;
231        struct mii_dev *dev;
232
233        puts ("MII devices: ");
234        list_for_each (entry, &mii_devs) {
235                dev = list_entry (entry, struct mii_dev, link);
236                printf ("'%s' ", dev->name);
237        }
238        puts ("\n");
239
240        if (current_mii)
241                printf ("Current device: '%s'\n", current_mii->name);
242}
243
244/*****************************************************************************
245 *
246 * Read the OUI, manufacture's model number, and revision number.
247 *
248 * OUI:     22 bits (unsigned int)
249 * Model:    6 bits (unsigned char)
250 * Revision: 4 bits (unsigned char)
251 *
252 * Returns:
253 *   0 on success
254 */
255int miiphy_info (char *devname, unsigned char addr, unsigned int *oui,
256                 unsigned char *model, unsigned char *rev)
257{
258        unsigned int reg = 0;
259        unsigned short tmp;
260
261        if (miiphy_read (devname, addr, PHY_PHYIDR2, &tmp) != 0) {
262                debug ("PHY ID register 2 read failed\n");
263                return (-1);
264        }
265        reg = tmp;
266
267        debug ("PHY_PHYIDR2 @ 0x%x = 0x%04x\n", addr, reg);
268
269        if (reg == 0xFFFF) {
270                /* No physical device present at this address */
271                return (-1);
272        }
273
274        if (miiphy_read (devname, addr, PHY_PHYIDR1, &tmp) != 0) {
275                debug ("PHY ID register 1 read failed\n");
276                return (-1);
277        }
278        reg |= tmp << 16;
279        debug ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
280
281        *oui = (reg >> 10);
282        *model = (unsigned char)((reg >> 4) & 0x0000003F);
283        *rev = (unsigned char)(reg & 0x0000000F);
284        return (0);
285}
286
287/*****************************************************************************
288 *
289 * Reset the PHY.
290 * Returns:
291 *   0 on success
292 */
293int miiphy_reset (char *devname, unsigned char addr)
294{
295        unsigned short reg;
296        int loop_cnt;
297
298        if (miiphy_read (devname, addr, PHY_BMCR, &reg) != 0) {
299                debug ("PHY status read failed\n");
300                return (-1);
301        }
302        if (miiphy_write (devname, addr, PHY_BMCR, reg | 0x8000) != 0) {
303                debug ("PHY reset failed\n");
304                return (-1);
305        }
306#ifdef CONFIG_PHY_RESET_DELAY
307        udelay (CONFIG_PHY_RESET_DELAY);        /* Intel LXT971A needs this */
308#endif
309        /*
310         * Poll the control register for the reset bit to go to 0 (it is
311         * auto-clearing).  This should happen within 0.5 seconds per the
312         * IEEE spec.
313         */
314        loop_cnt = 0;
315        reg = 0x8000;
316        while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) {
317                if (miiphy_read (devname, addr, PHY_BMCR, &reg) != 0) {
318                        debug ("PHY status read failed\n");
319                        return (-1);
320                }
321        }
322        if ((reg & 0x8000) == 0) {
323                return (0);
324        } else {
325                puts ("PHY reset timed out\n");
326                return (-1);
327        }
328        return (0);
329}
330
331/*****************************************************************************
332 *
333 * Determine the ethernet speed (10/100/1000).  Return 10 on error.
334 */
335int miiphy_speed (char *devname, unsigned char addr)
336{
337        u16 bmcr, anlpar;
338
339#if defined(CONFIG_PHY_GIGE)
340        u16 btsr;
341
342        /*
343         * Check for 1000BASE-X.  If it is supported, then assume that the speed
344         * is 1000.
345         */
346        if (miiphy_is_1000base_x (devname, addr)) {
347                return _1000BASET;
348        }
349        /*
350         * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
351         */
352        /* Check for 1000BASE-T. */
353        if (miiphy_read (devname, addr, PHY_1000BTSR, &btsr)) {
354                printf ("PHY 1000BT status");
355                goto miiphy_read_failed;
356        }
357        if (btsr != 0xFFFF &&
358            (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) {
359                return _1000BASET;
360        }
361#endif /* CONFIG_PHY_GIGE */
362
363        /* Check Basic Management Control Register first. */
364        if (miiphy_read (devname, addr, PHY_BMCR, &bmcr)) {
365                printf ("PHY speed");
366                goto miiphy_read_failed;
367        }
368        /* Check if auto-negotiation is on. */
369        if (bmcr & PHY_BMCR_AUTON) {
370                /* Get auto-negotiation results. */
371                if (miiphy_read (devname, addr, PHY_ANLPAR, &anlpar)) {
372                        printf ("PHY AN speed");
373                        goto miiphy_read_failed;
374                }
375                return (anlpar & PHY_ANLPAR_100) ? _100BASET : _10BASET;
376        }
377        /* Get speed from basic control settings. */
378        return (bmcr & PHY_BMCR_100MB) ? _100BASET : _10BASET;
379
380      miiphy_read_failed:
381        printf (" read failed, assuming 10BASE-T\n");
382        return _10BASET;
383}
384
385/*****************************************************************************
386 *
387 * Determine full/half duplex.  Return half on error.
388 */
389int miiphy_duplex (char *devname, unsigned char addr)
390{
391        u16 bmcr, anlpar;
392
393#if defined(CONFIG_PHY_GIGE)
394        u16 btsr;
395
396        /* Check for 1000BASE-X. */
397        if (miiphy_is_1000base_x (devname, addr)) {
398                /* 1000BASE-X */
399                if (miiphy_read (devname, addr, PHY_ANLPAR, &anlpar)) {
400                        printf ("1000BASE-X PHY AN duplex");
401                        goto miiphy_read_failed;
402                }
403        }
404        /*
405         * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
406         */
407        /* Check for 1000BASE-T. */
408        if (miiphy_read (devname, addr, PHY_1000BTSR, &btsr)) {
409                printf ("PHY 1000BT status");
410                goto miiphy_read_failed;
411        }
412        if (btsr != 0xFFFF) {
413                if (btsr & PHY_1000BTSR_1000FD) {
414                        return FULL;
415                } else if (btsr & PHY_1000BTSR_1000HD) {
416                        return HALF;
417                }
418        }
419#endif /* CONFIG_PHY_GIGE */
420
421        /* Check Basic Management Control Register first. */
422        if (miiphy_read (devname, addr, PHY_BMCR, &bmcr)) {
423                puts ("PHY duplex");
424                goto miiphy_read_failed;
425        }
426        /* Check if auto-negotiation is on. */
427        if (bmcr & PHY_BMCR_AUTON) {
428                /* Get auto-negotiation results. */
429                if (miiphy_read (devname, addr, PHY_ANLPAR, &anlpar)) {
430                        puts ("PHY AN duplex");
431                        goto miiphy_read_failed;
432                }
433                return (anlpar & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) ?
434                    FULL : HALF;
435        }
436        /* Get speed from basic control settings. */
437        return (bmcr & PHY_BMCR_DPLX) ? FULL : HALF;
438
439      miiphy_read_failed:
440        printf (" read failed, assuming half duplex\n");
441        return HALF;
442}
443
444/*****************************************************************************
445 *
446 * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/
447 * 1000BASE-T, or on error.
448 */
449int miiphy_is_1000base_x (char *devname, unsigned char addr)
450{
451#if defined(CONFIG_PHY_GIGE)
452        u16 exsr;
453
454        if (miiphy_read (devname, addr, PHY_EXSR, &exsr)) {
455                printf ("PHY extended status read failed, assuming no "
456                        "1000BASE-X\n");
457                return 0;
458        }
459        return 0 != (exsr & (PHY_EXSR_1000XF | PHY_EXSR_1000XH));
460#else
461        return 0;
462#endif
463}
464
465#ifdef CFG_FAULT_ECHO_LINK_DOWN
466/*****************************************************************************
467 *
468 * Determine link status
469 */
470int miiphy_link (char *devname, unsigned char addr)
471{
472        unsigned short reg;
473
474        /* dummy read; needed to latch some phys */
475        (void)miiphy_read (devname, addr, PHY_BMSR, &reg);
476        if (miiphy_read (devname, addr, PHY_BMSR, &reg)) {
477                puts ("PHY_BMSR read failed, assuming no link\n");
478                return (0);
479        }
480
481        /* Determine if a link is active */
482        if ((reg & PHY_BMSR_LS) != 0) {
483                return (1);
484        } else {
485                return (0);
486        }
487}
488#endif
Note: See TracBrowser for help on using the repository browser.