]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_mii.c
Add ADI Blackfin support
[karo-tx-uboot.git] / common / cmd_mii.c
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  * MII Utilities
26  */
27
28 #include <common.h>
29 #include <command.h>
30
31 #if (CONFIG_COMMANDS & CFG_CMD_MII)
32 #include <miiphy.h>
33
34 #ifdef CONFIG_TERSE_MII
35 /*
36  * Display values from last command.
37  */
38 uint last_op;
39 uint last_addr;
40 uint last_data;
41 uint last_reg;
42
43 /*
44  * MII device/info/read/write
45  *
46  * Syntax:
47  *  mii device {devname}
48  *  mii info   {addr}
49  *  mii read   {addr} {reg}
50  *  mii write  {addr} {reg} {data}
51  */
52 int do_mii (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
53 {
54         char            op;
55         unsigned char   addr, reg;
56         unsigned short  data;
57         int             rcode = 0;
58         char            *devname;
59
60 #if defined(CONFIG_8xx) || defined(CONFIG_MCF52x2)
61         mii_init ();
62 #endif
63
64         /*
65          * We use the last specified parameters, unless new ones are
66          * entered.
67          */
68         op   = last_op;
69         addr = last_addr;
70         data = last_data;
71         reg  = last_reg;
72
73         if ((flag & CMD_FLAG_REPEAT) == 0) {
74                 op = argv[1][0];
75                 if (argc >= 3)
76                         addr = simple_strtoul (argv[2], NULL, 16);
77                 if (argc >= 4)
78                         reg  = simple_strtoul (argv[3], NULL, 16);
79                 if (argc >= 5)
80                         data = simple_strtoul (argv[4], NULL, 16);
81         }
82
83         /* use current device */
84         devname = miiphy_get_current_dev();
85
86         /*
87          * check device/read/write/list.
88          */
89         if (op == 'i') {
90                 unsigned char j, start, end;
91                 unsigned int oui;
92                 unsigned char model;
93                 unsigned char rev;
94
95                 /*
96                  * Look for any and all PHYs.  Valid addresses are 0..31.
97                  */
98                 if (argc >= 3) {
99                         start = addr; end = addr + 1;
100                 } else {
101                         start = 0; end = 31;
102                 }
103
104                 for (j = start; j < end; j++) {
105                         if (miiphy_info (devname, j, &oui, &model, &rev) == 0) {
106                                 printf ("PHY 0x%02X: "
107                                         "OUI = 0x%04X, "
108                                         "Model = 0x%02X, "
109                                         "Rev = 0x%02X, "
110                                         "%3dbaseT, %s\n",
111                                         j, oui, model, rev,
112                                         miiphy_speed (devname, j),
113                                         (miiphy_duplex (devname, j) == FULL)
114                                                 ? "FDX" : "HDX");
115                         } else {
116                                 puts ("Error reading info from the PHY\n");
117                         }
118                 }
119         } else if (op == 'r') {
120                 if (miiphy_read (devname, addr, reg, &data) != 0) {
121                         puts ("Error reading from the PHY\n");
122                         rcode = 1;
123                 } else {
124                         printf ("%04X\n", data & 0x0000FFFF);
125                 }
126         } else if (op == 'w') {
127                 if (miiphy_write (devname, addr, reg, data) != 0) {
128                         puts ("Error writing to the PHY\n");
129                         rcode = 1;
130                 }
131         } else if (op == 'd') {
132                 if (argc == 2)
133                         miiphy_listdev ();
134                 else
135                         miiphy_set_current_dev (argv[2]);
136         } else {
137                 printf ("Usage:\n%s\n", cmdtp->usage);
138                 return 1;
139         }
140
141         /*
142          * Save the parameters for repeats.
143          */
144         last_op = op;
145         last_addr = addr;
146         last_data = data;
147         last_reg = reg;
148
149         return rcode;
150 }
151
152 /***************************************************/
153
154 U_BOOT_CMD(
155         mii,    5,      1,      do_mii,
156         "mii     - MII utility commands\n",
157         "device                     - list available devices\n"
158         "mii device <devname>           - set current device\n"
159         "mii info   <addr>              - display MII PHY info\n"
160         "mii read   <addr> <reg>        - read  MII PHY <addr> register <reg>\n"
161         "mii write  <addr> <reg> <data> - write MII PHY <addr> register <reg>\n"
162 );
163
164 #else /* ! CONFIG_TERSE_MII ================================================= */
165
166 typedef struct _MII_reg_desc_t {
167         ushort regno;
168         char * name;
169 } MII_reg_desc_t;
170
171 MII_reg_desc_t reg_0_5_desc_tbl[] = {
172         { 0,   "PHY control register"                },
173         { 1,   "PHY status register"                 },
174         { 2,   "PHY ID 1 register"                   },
175         { 3,   "PHY ID 2 register"                   },
176         { 4,   "Autonegotiation advertisement register" },
177         { 5,   "Autonegotiation partner abilities register" },
178 };
179
180 typedef struct _MII_field_desc_t {
181         ushort hi;
182         ushort lo;
183         ushort mask;
184         char * name;
185 } MII_field_desc_t;
186
187 MII_field_desc_t reg_0_desc_tbl[] = {
188         { 15, 15, 0x01, "reset"                        },
189         { 14, 14, 0x01, "loopback"                     },
190         { 13,  6, 0x81, "speed selection"              }, /* special */
191         { 12, 12, 0x01, "A/N enable"                   },
192         { 11, 11, 0x01, "power-down"                   },
193         { 10, 10, 0x01, "isolate"                      },
194         {  9,  9, 0x01, "restart A/N"                  },
195         {  8,  8, 0x01, "duplex"                       }, /* special */
196         {  7,  7, 0x01, "collision test enable"        },
197         {  5,  0, 0x3f, "(reserved)"                   }
198 };
199
200 MII_field_desc_t reg_1_desc_tbl[] = {
201         { 15, 15, 0x01, "100BASE-T4 able"              },
202         { 14, 14, 0x01, "100BASE-X  full duplex able"  },
203         { 13, 13, 0x01, "100BASE-X  half duplex able"  },
204         { 12, 12, 0x01, "10 Mbps    full duplex able"  },
205         { 11, 11, 0x01, "10 Mbps    half duplex able"  },
206         { 10, 10, 0x01, "100BASE-T2 full duplex able"  },
207         {  9,  9, 0x01, "100BASE-T2 half duplex able"  },
208         {  8,  8, 0x01, "extended status"              },
209         {  7,  7, 0x01, "(reserved)"                   },
210         {  6,  6, 0x01, "MF preamble suppression"      },
211         {  5,  5, 0x01, "A/N complete"                 },
212         {  4,  4, 0x01, "remote fault"                 },
213         {  3,  3, 0x01, "A/N able"                     },
214         {  2,  2, 0x01, "link status"                  },
215         {  1,  1, 0x01, "jabber detect"                },
216         {  0,  0, 0x01, "extended capabilities"        },
217 };
218
219 MII_field_desc_t reg_2_desc_tbl[] = {
220         { 15,  0, 0xffff, "OUI portion"                },
221 };
222
223 MII_field_desc_t reg_3_desc_tbl[] = {
224         { 15, 10, 0x3f, "OUI portion"                },
225         {  9,  4, 0x3f, "manufacturer part number"   },
226         {  3,  0, 0x0f, "manufacturer rev. number"   },
227 };
228
229 MII_field_desc_t reg_4_desc_tbl[] = {
230         { 15, 15, 0x01, "next page able"               },
231         { 14, 14, 0x01, "reserved"                     },
232         { 13, 13, 0x01, "remote fault"                 },
233         { 12, 12, 0x01, "reserved"                     },
234         { 11, 11, 0x01, "asymmetric pause"             },
235         { 10, 10, 0x01, "pause enable"                 },
236         {  9,  9, 0x01, "100BASE-T4 able"              },
237         {  8,  8, 0x01, "100BASE-TX full duplex able"  },
238         {  7,  7, 0x01, "100BASE-TX able"              },
239         {  6,  6, 0x01, "10BASE-T   full duplex able"  },
240         {  5,  5, 0x01, "10BASE-T   able"              },
241         {  4,  0, 0x1f, "xxx to do"                    },
242 };
243
244 MII_field_desc_t reg_5_desc_tbl[] = {
245         { 15, 15, 0x01, "next page able"               },
246         { 14, 14, 0x01, "acknowledge"                  },
247         { 13, 13, 0x01, "remote fault"                 },
248         { 12, 12, 0x01, "(reserved)"                   },
249         { 11, 11, 0x01, "asymmetric pause able"        },
250         { 10, 10, 0x01, "pause able"                   },
251         {  9,  9, 0x01, "100BASE-T4 able"              },
252         {  8,  8, 0x01, "100BASE-X full duplex able"   },
253         {  7,  7, 0x01, "100BASE-TX able"              },
254         {  6,  6, 0x01, "10BASE-T full duplex able"    },
255         {  5,  5, 0x01, "10BASE-T able"                },
256         {  4,  0, 0x1f, "xxx to do"                    },
257 };
258
259 #define DESC0LEN (sizeof(reg_0_desc_tbl)/sizeof(reg_0_desc_tbl[0]))
260 #define DESC1LEN (sizeof(reg_1_desc_tbl)/sizeof(reg_1_desc_tbl[0]))
261 #define DESC2LEN (sizeof(reg_2_desc_tbl)/sizeof(reg_2_desc_tbl[0]))
262 #define DESC3LEN (sizeof(reg_3_desc_tbl)/sizeof(reg_3_desc_tbl[0]))
263 #define DESC4LEN (sizeof(reg_4_desc_tbl)/sizeof(reg_4_desc_tbl[0]))
264 #define DESC5LEN (sizeof(reg_5_desc_tbl)/sizeof(reg_5_desc_tbl[0]))
265
266 typedef struct _MII_field_desc_and_len_t {
267         MII_field_desc_t * pdesc;
268         ushort len;
269 } MII_field_desc_and_len_t;
270
271 MII_field_desc_and_len_t desc_and_len_tbl[] = {
272         { reg_0_desc_tbl, DESC0LEN },
273         { reg_1_desc_tbl, DESC1LEN },
274         { reg_2_desc_tbl, DESC2LEN },
275         { reg_3_desc_tbl, DESC3LEN },
276         { reg_4_desc_tbl, DESC4LEN },
277         { reg_5_desc_tbl, DESC5LEN },
278 };
279
280 static void dump_reg(
281         ushort             regval,
282         MII_reg_desc_t   * prd,
283         MII_field_desc_and_len_t * pdl);
284
285 static int special_field(
286         ushort regno,
287         MII_field_desc_t * pdesc,
288         ushort regval);
289
290 void MII_dump_0_to_5(
291         ushort regvals[6],
292         uchar reglo,
293         uchar reghi)
294 {
295         ulong i;
296
297         for (i = 0; i < 6; i++) {
298                 if ((reglo <= i) && (i <= reghi))
299                         dump_reg(regvals[i], &reg_0_5_desc_tbl[i],
300                                 &desc_and_len_tbl[i]);
301         }
302 }
303
304 static void dump_reg(
305         ushort             regval,
306         MII_reg_desc_t   * prd,
307         MII_field_desc_and_len_t * pdl)
308 {
309         ulong i;
310         ushort mask_in_place;
311         MII_field_desc_t * pdesc;
312
313         printf("%u.     (%04hx)                 -- %s --\n",
314                 prd->regno, regval, prd->name);
315
316         for (i = 0; i < pdl->len; i++) {
317                 pdesc = &pdl->pdesc[i];
318
319                 mask_in_place = pdesc->mask << pdesc->lo;
320
321                 printf("  (%04hx:%04hx) %u.",
322                         mask_in_place,
323                         regval & mask_in_place,
324                         prd->regno);
325
326                 if (special_field(prd->regno, pdesc, regval)) {
327                 }
328                 else {
329                         if (pdesc->hi == pdesc->lo)
330                                 printf("%2u   ", pdesc->lo);
331                         else
332                                 printf("%2u-%2u", pdesc->hi, pdesc->lo);
333                         printf(" = %5u    %s",
334                                 (regval & mask_in_place) >> pdesc->lo,
335                                 pdesc->name);
336                 }
337                 printf("\n");
338
339         }
340         printf("\n");
341 }
342
343 /* Special fields:
344 ** 0.6,13
345 ** 0.8
346 ** 2.15-0
347 ** 3.15-0
348 ** 4.4-0
349 ** 5.4-0
350 */
351
352 static int special_field(
353         ushort regno,
354         MII_field_desc_t * pdesc,
355         ushort regval)
356 {
357         if ((regno == 0) && (pdesc->lo == 6)) {
358                 ushort speed_bits = regval & PHY_BMCR_SPEED_MASK;
359                 printf("%2u,%2u =   b%u%u    speed selection = %s Mbps",
360                         6, 13,
361                         (regval >>  6) & 1,
362                         (regval >> 13) & 1,
363                         speed_bits == PHY_BMCR_1000_MBPS ? "1000" :
364                         speed_bits == PHY_BMCR_100_MBPS  ? "100" :
365                         speed_bits == PHY_BMCR_10_MBPS   ? "10" :
366                         "???");
367                 return 1;
368         }
369
370         else if ((regno == 0) && (pdesc->lo == 8)) {
371                 printf("%2u    = %5u    duplex = %s",
372                         pdesc->lo,
373                         (regval >>  pdesc->lo) & 1,
374                         ((regval >> pdesc->lo) & 1) ? "full" : "half");
375                 return 1;
376         }
377
378         else if ((regno == 4) && (pdesc->lo == 0)) {
379                 ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
380                 printf("%2u-%2u = %5u    selector = %s",
381                         pdesc->hi, pdesc->lo, sel_bits,
382                         sel_bits == PHY_ANLPAR_PSB_802_3 ?
383                                 "IEEE 802.3" :
384                         sel_bits == PHY_ANLPAR_PSB_802_9 ?
385                                 "IEEE 802.9 ISLAN-16T" :
386                         "???");
387                 return 1;
388         }
389
390         else if ((regno == 5) && (pdesc->lo == 0)) {
391                 ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
392                 printf("%2u-%2u =     %u    selector = %s",
393                         pdesc->hi, pdesc->lo, sel_bits,
394                         sel_bits == PHY_ANLPAR_PSB_802_3 ?
395                                 "IEEE 802.3" :
396                         sel_bits == PHY_ANLPAR_PSB_802_9 ?
397                                 "IEEE 802.9 ISLAN-16T" :
398                         "???");
399                 return 1;
400         }
401
402         return 0;
403 }
404
405 char last_op[2];
406 uint last_data;
407 uint last_addr_lo;
408 uint last_addr_hi;
409 uint last_reg_lo;
410 uint last_reg_hi;
411
412 static void extract_range(
413         char * input,
414         unsigned char * plo,
415         unsigned char * phi)
416 {
417         char * end;
418         *plo = simple_strtoul(input, &end, 16);
419         if (*end == '-') {
420                 end++;
421                 *phi = simple_strtoul(end, NULL, 16);
422         }
423         else {
424                 *phi = *plo;
425         }
426 }
427
428 /* ---------------------------------------------------------------- */
429 int do_mii (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
430 {
431         char            op[2];
432         unsigned char   addrlo, addrhi, reglo, reghi;
433         unsigned char   addr, reg;
434         unsigned short  data;
435         int             rcode = 0;
436         char            *devname;
437
438 #ifdef CONFIG_8xx
439         mii_init ();
440 #endif
441
442         /*
443          * We use the last specified parameters, unless new ones are
444          * entered.
445          */
446         op[0] = last_op[0];
447         op[1] = last_op[1];
448         addrlo = last_addr_lo;
449         addrhi = last_addr_hi;
450         reglo  = last_reg_lo;
451         reghi  = last_reg_hi;
452         data   = last_data;
453
454         if ((flag & CMD_FLAG_REPEAT) == 0) {
455                 op[0] = argv[1][0];
456                 if (strlen(argv[1]) > 1)
457                         op[1] = argv[1][1];
458                 else
459                         op[1] = '\0';
460
461                 if (argc >= 3)
462                         extract_range(argv[2], &addrlo, &addrhi);
463                 if (argc >= 4)
464                         extract_range(argv[3], &reglo, &reghi);
465                 if (argc >= 5)
466                         data = simple_strtoul (argv[4], NULL, 16);
467         }
468
469         /* use current device */
470         devname = miiphy_get_current_dev();
471
472         /*
473          * check info/read/write.
474          */
475         if (op[0] == 'i') {
476                 unsigned char j, start, end;
477                 unsigned int oui;
478                 unsigned char model;
479                 unsigned char rev;
480
481                 /*
482                  * Look for any and all PHYs.  Valid addresses are 0..31.
483                  */
484                 if (argc >= 3) {
485                         start = addrlo; end = addrhi;
486                 } else {
487                         start = 0; end = 31;
488                 }
489
490                 for (j = start; j <= end; j++) {
491                         if (miiphy_info (devname, j, &oui, &model, &rev) == 0) {
492                                 printf("PHY 0x%02X: "
493                                         "OUI = 0x%04X, "
494                                         "Model = 0x%02X, "
495                                         "Rev = 0x%02X, "
496                                         "%3dbaseT, %s\n",
497                                         j, oui, model, rev,
498                                         miiphy_speed (devname, j),
499                                         (miiphy_duplex (devname, j) == FULL)
500                                                 ? "FDX" : "HDX");
501                         } else {
502                                 puts ("Error reading info from the PHY\n");
503                         }
504                 }
505         } else if (op[0] == 'r') {
506                 for (addr = addrlo; addr <= addrhi; addr++) {
507                         for (reg = reglo; reg <= reghi; reg++) {
508                                 data = 0xffff;
509                                 if (miiphy_read (devname, addr, reg, &data) != 0) {
510                                         printf(
511                                         "Error reading from the PHY addr=%02x reg=%02x\n",
512                                                 addr, reg);
513                                         rcode = 1;
514                                 } else {
515                                         if ((addrlo != addrhi) || (reglo != reghi))
516                                                 printf("addr=%02x reg=%02x data=",
517                                                         (uint)addr, (uint)reg);
518                                         printf("%04X\n", data & 0x0000FFFF);
519                                 }
520                         }
521                         if ((addrlo != addrhi) && (reglo != reghi))
522                                 printf("\n");
523                 }
524         } else if (op[0] == 'w') {
525                 for (addr = addrlo; addr <= addrhi; addr++) {
526                         for (reg = reglo; reg <= reghi; reg++) {
527                                 if (miiphy_write (devname, addr, reg, data) != 0) {
528                                         printf("Error writing to the PHY addr=%02x reg=%02x\n",
529                                                 addr, reg);
530                                         rcode = 1;
531                                 }
532                         }
533                 }
534         } else if (strncmp(op, "du", 2) == 0) {
535                 ushort regs[6];
536                 int ok = 1;
537                 if ((reglo > 5) || (reghi > 5)) {
538                         printf(
539                                 "The MII dump command only formats the "
540                                 "standard MII registers, 0-5.\n");
541                         return 1;
542                 }
543                 for (addr = addrlo; addr <= addrhi; addr++) {
544                         for (reg = reglo; reg < reghi + 1; reg++) {
545                                 if (miiphy_read(devname, addr, reg, &regs[reg]) != 0) {
546                                         ok = 0;
547                                         printf(
548                                         "Error reading from the PHY addr=%02x reg=%02x\n",
549                                                 addr, reg);
550                                         rcode = 1;
551                                 }
552                         }
553                         if (ok)
554                                 MII_dump_0_to_5(regs, reglo, reghi);
555                         printf("\n");
556                 }
557         } else if (strncmp(op, "de", 2) == 0) {
558                 if (argc == 2)
559                         miiphy_listdev ();
560                 else
561                         miiphy_set_current_dev (argv[2]);
562         } else {
563                 printf("Usage:\n%s\n", cmdtp->usage);
564                 return 1;
565         }
566
567         /*
568          * Save the parameters for repeats.
569          */
570         last_op[0] = op[0];
571         last_op[1] = op[1];
572         last_addr_lo = addrlo;
573         last_addr_hi = addrhi;
574         last_reg_lo  = reglo;
575         last_reg_hi  = reghi;
576         last_data    = data;
577
578         return rcode;
579 }
580
581 /***************************************************/
582
583 U_BOOT_CMD(
584         mii,    5,      1,      do_mii,
585         "mii     - MII utility commands\n",
586         "device                     - list available devices\n"
587         "mii device <devname>           - set current device\n"
588         "mii info   <addr>              - display MII PHY info\n"
589         "mii read   <addr> <reg>        - read  MII PHY <addr> register <reg>\n"
590         "mii write  <addr> <reg> <data> - write MII PHY <addr> register <reg>\n"
591         "mii dump   <addr> <reg>        - pretty-print <addr> <reg> (0-5 only)\n"
592         "Addr and/or reg may be ranges, e.g. 2-7.\n"
593 );
594
595 #endif /* CONFIG_TERSE_MII */
596
597 #endif /* CFG_CMD_MII */