]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_mem.c
memory commands "mdc" and "mwc" added for cyclic read/write
[karo-tx-uboot.git] / common / cmd_mem.c
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
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  * Memory Functions
26  *
27  * Copied from FADS ROM, Dan Malek (dmalek@jlc.net)
28  */
29
30 #include <common.h>
31 #include <command.h>
32 #if (CONFIG_COMMANDS & CFG_CMD_MMC)
33 #include <mmc.h>
34 #endif
35 #ifdef CONFIG_HAS_DATAFLASH
36 #include <dataflash.h>
37 #endif
38
39 #if (CONFIG_COMMANDS & (CFG_CMD_MEMORY  | \
40                         CFG_CMD_I2C     | \
41                         CFG_CMD_ITEST   | \
42                         CFG_CMD_PCI     | \
43                         CMD_CMD_PORTIO  ) )
44 int cmd_get_data_size(char* arg, int default_size)
45 {
46         /* Check for a size specification .b, .w or .l.
47          */
48         int len = strlen(arg);
49         if (len > 2 && arg[len-2] == '.') {
50                 switch(arg[len-1]) {
51                 case 'b':
52                         return 1;
53                 case 'w':
54                         return 2;
55                 case 'l':
56                         return 4;
57                 case 's':
58                         return -2;
59                 default:
60                         return -1;
61                 }
62         }
63         return default_size;
64 }
65 #endif
66
67 #if (CONFIG_COMMANDS & CFG_CMD_MEMORY)
68
69 #ifdef  CMD_MEM_DEBUG
70 #define PRINTF(fmt,args...)     printf (fmt ,##args)
71 #else
72 #define PRINTF(fmt,args...)
73 #endif
74
75 static int mod_mem(cmd_tbl_t *, int, int, int, char *[]);
76
77 /* Display values from last command.
78  * Memory modify remembered values are different from display memory.
79  */
80 uint    dp_last_addr, dp_last_size;
81 uint    dp_last_length = 0x40;
82 uint    mm_last_addr, mm_last_size;
83
84 static  ulong   base_address = 0;
85
86 /* Memory Display
87  *
88  * Syntax:
89  *      md{.b, .w, .l} {addr} {len}
90  */
91 #define DISP_LINE_LEN   16
92 int do_mem_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
93 {
94         ulong   addr, length;
95         ulong   i, nbytes, linebytes;
96         u_char  *cp;
97         int     size;
98         int rc = 0;
99
100         /* We use the last specified parameters, unless new ones are
101          * entered.
102          */
103         addr = dp_last_addr;
104         size = dp_last_size;
105         length = dp_last_length;
106
107         if (argc < 2) {
108                 printf ("Usage:\n%s\n", cmdtp->usage);
109                 return 1;
110         }
111
112         if ((flag & CMD_FLAG_REPEAT) == 0) {
113                 /* New command specified.  Check for a size specification.
114                  * Defaults to long if no or incorrect specification.
115                  */
116                 if ((size = cmd_get_data_size(argv[0], 4)) < 0)
117                         return 1;
118
119                 /* Address is specified since argc > 1
120                 */
121                 addr = simple_strtoul(argv[1], NULL, 16);
122                 addr += base_address;
123
124                 /* If another parameter, it is the length to display.
125                  * Length is the number of objects, not number of bytes.
126                  */
127                 if (argc > 2)
128                         length = simple_strtoul(argv[2], NULL, 16);
129         }
130
131         /* Print the lines.
132          *
133          * We buffer all read data, so we can make sure data is read only
134          * once, and all accesses are with the specified bus width.
135          */
136         nbytes = length * size;
137         do {
138                 char    linebuf[DISP_LINE_LEN];
139                 uint    *uip = (uint   *)linebuf;
140                 ushort  *usp = (ushort *)linebuf;
141                 u_char  *ucp = (u_char *)linebuf;
142 #ifdef CONFIG_HAS_DATAFLASH
143                 int rc;
144 #endif
145                 printf("%08lx:", addr);
146                 linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
147
148 #ifdef CONFIG_HAS_DATAFLASH
149                 if ((rc = read_dataflash(addr, (linebytes/size)*size, linebuf)) == DATAFLASH_OK){
150                         /* if outside dataflash */
151                         /*if (rc != 1) {
152                                 dataflash_perror (rc);
153                                 return (1);
154                         }*/
155                         for (i=0; i<linebytes; i+= size) {
156                                 if (size == 4) {
157                                         printf(" %08x", *uip++);
158                                 } else if (size == 2) {
159                                         printf(" %04x", *usp++);
160                                 } else {
161                                         printf(" %02x", *ucp++);
162                                 }
163                                 addr += size;
164                         }
165
166                 } else {        /* addr does not correspond to DataFlash */
167 #endif
168                 for (i=0; i<linebytes; i+= size) {
169                         if (size == 4) {
170                                 printf(" %08x", (*uip++ = *((uint *)addr)));
171                         } else if (size == 2) {
172                                 printf(" %04x", (*usp++ = *((ushort *)addr)));
173                         } else {
174                                 printf(" %02x", (*ucp++ = *((u_char *)addr)));
175                         }
176                         addr += size;
177                 }
178 #ifdef CONFIG_HAS_DATAFLASH
179                 }
180 #endif
181                 puts ("    ");
182                 cp = linebuf;
183                 for (i=0; i<linebytes; i++) {
184                         if ((*cp < 0x20) || (*cp > 0x7e))
185                                 putc ('.');
186                         else
187                                 printf("%c", *cp);
188                         cp++;
189                 }
190                 putc ('\n');
191                 nbytes -= linebytes;
192                 if (ctrlc()) {
193                         rc = 1;
194                         break;
195                 }
196         } while (nbytes > 0);
197
198         dp_last_addr = addr;
199         dp_last_length = length;
200         dp_last_size = size;
201         return (rc);
202 }
203
204 int do_mem_mm ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
205 {
206         return mod_mem (cmdtp, 1, flag, argc, argv);
207 }
208 int do_mem_nm ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
209 {
210         return mod_mem (cmdtp, 0, flag, argc, argv);
211 }
212
213 int do_mem_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
214 {
215         ulong   addr, writeval, count;
216         int     size;
217
218         if ((argc < 3) || (argc > 4)) {
219                 printf ("Usage:\n%s\n", cmdtp->usage);
220                 return 1;
221         }
222
223         /* Check for size specification.
224         */
225         if ((size = cmd_get_data_size(argv[0], 4)) < 1)
226                 return 1;
227
228         /* Address is specified since argc > 1
229         */
230         addr = simple_strtoul(argv[1], NULL, 16);
231         addr += base_address;
232
233         /* Get the value to write.
234         */
235         writeval = simple_strtoul(argv[2], NULL, 16);
236
237         /* Count ? */
238         if (argc == 4) {
239                 count = simple_strtoul(argv[3], NULL, 16);
240         } else {
241                 count = 1;
242         }
243
244         while (count-- > 0) {
245                 if (size == 4)
246                         *((ulong  *)addr) = (ulong )writeval;
247                 else if (size == 2)
248                         *((ushort *)addr) = (ushort)writeval;
249                 else
250                         *((u_char *)addr) = (u_char)writeval;
251                 addr += size;
252         }
253         return 0;
254 }
255
256 #ifdef CONFIG_MX_CYCLIC
257 int do_mem_mdc ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
258 {
259         int i;
260         ulong count;
261
262         if (argc < 4) {
263                 printf ("Usage:\n%s\n", cmdtp->usage);
264                 return 1;
265         }
266
267         count = simple_strtoul(argv[3], NULL, 10);
268
269         for (;;) {
270                 do_mem_md (NULL, 0, 3, argv);
271
272                 /* delay for <count> ms... */
273                 for (i=0; i<count; i++)
274                         udelay (1000);
275
276                 /* check for ctrl-c to abort... */
277                 if (ctrlc()) {
278                         puts("Abort\n");
279                         return 0;
280                 }
281         }
282
283         return 0;
284 }
285
286 int do_mem_mwc ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
287 {
288         int i;
289         ulong count;
290
291         if (argc < 4) {
292                 printf ("Usage:\n%s\n", cmdtp->usage);
293                 return 1;
294         }
295
296         count = simple_strtoul(argv[3], NULL, 10);
297
298         for (;;) {
299                 do_mem_mw (NULL, 0, 3, argv);
300
301                 /* delay for <count> ms... */
302                 for (i=0; i<count; i++)
303                         udelay (1000);
304
305                 /* check for ctrl-c to abort... */
306                 if (ctrlc()) {
307                         puts("Abort\n");
308                         return 0;
309                 }
310         }
311
312         return 0;
313 }
314 #endif /* CONFIG_MX_CYCLIC */
315
316 int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
317 {
318         ulong   addr1, addr2, count, ngood;
319         int     size;
320         int     rcode = 0;
321
322         if (argc != 4) {
323                 printf ("Usage:\n%s\n", cmdtp->usage);
324                 return 1;
325         }
326
327         /* Check for size specification.
328         */
329         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
330                 return 1;
331
332         addr1 = simple_strtoul(argv[1], NULL, 16);
333         addr1 += base_address;
334
335         addr2 = simple_strtoul(argv[2], NULL, 16);
336         addr2 += base_address;
337
338         count = simple_strtoul(argv[3], NULL, 16);
339
340 #ifdef CONFIG_HAS_DATAFLASH
341         if (addr_dataflash(addr1) | addr_dataflash(addr2)){
342                 puts ("Comparison with DataFlash space not supported.\n\r");
343                 return 0;
344         }
345 #endif
346
347         ngood = 0;
348
349         while (count-- > 0) {
350                 if (size == 4) {
351                         ulong word1 = *(ulong *)addr1;
352                         ulong word2 = *(ulong *)addr2;
353                         if (word1 != word2) {
354                                 printf("word at 0x%08lx (0x%08lx) "
355                                         "!= word at 0x%08lx (0x%08lx)\n",
356                                         addr1, word1, addr2, word2);
357                                 rcode = 1;
358                                 break;
359                         }
360                 }
361                 else if (size == 2) {
362                         ushort hword1 = *(ushort *)addr1;
363                         ushort hword2 = *(ushort *)addr2;
364                         if (hword1 != hword2) {
365                                 printf("halfword at 0x%08lx (0x%04x) "
366                                         "!= halfword at 0x%08lx (0x%04x)\n",
367                                         addr1, hword1, addr2, hword2);
368                                 rcode = 1;
369                                 break;
370                         }
371                 }
372                 else {
373                         u_char byte1 = *(u_char *)addr1;
374                         u_char byte2 = *(u_char *)addr2;
375                         if (byte1 != byte2) {
376                                 printf("byte at 0x%08lx (0x%02x) "
377                                         "!= byte at 0x%08lx (0x%02x)\n",
378                                         addr1, byte1, addr2, byte2);
379                                 rcode = 1;
380                                 break;
381                         }
382                 }
383                 ngood++;
384                 addr1 += size;
385                 addr2 += size;
386         }
387
388         printf("Total of %ld %s%s were the same\n",
389                 ngood, size == 4 ? "word" : size == 2 ? "halfword" : "byte",
390                 ngood == 1 ? "" : "s");
391         return rcode;
392 }
393
394 int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
395 {
396         ulong   addr, dest, count;
397         int     size;
398
399         if (argc != 4) {
400                 printf ("Usage:\n%s\n", cmdtp->usage);
401                 return 1;
402         }
403
404         /* Check for size specification.
405         */
406         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
407                 return 1;
408
409         addr = simple_strtoul(argv[1], NULL, 16);
410         addr += base_address;
411
412         dest = simple_strtoul(argv[2], NULL, 16);
413         dest += base_address;
414
415         count = simple_strtoul(argv[3], NULL, 16);
416
417         if (count == 0) {
418                 puts ("Zero length ???\n");
419                 return 1;
420         }
421
422 #ifndef CFG_NO_FLASH
423         /* check if we are copying to Flash */
424         if ( (addr2info(dest) != NULL)
425 #ifdef CONFIG_HAS_DATAFLASH
426            && (!addr_dataflash(addr))
427 #endif
428            ) {
429                 int rc;
430
431                 puts ("Copy to Flash... ");
432
433                 rc = flash_write ((uchar *)addr, dest, count*size);
434                 if (rc != 0) {
435                         flash_perror (rc);
436                         return (1);
437                 }
438                 puts ("done\n");
439                 return 0;
440         }
441 #endif
442
443 #if (CONFIG_COMMANDS & CFG_CMD_MMC)
444         if (mmc2info(dest)) {
445                 int rc;
446
447                 puts ("Copy to MMC... ");
448                 switch (rc = mmc_write ((uchar *)addr, dest, count*size)) {
449                 case 0:
450                         putc ('\n');
451                         return 1;
452                 case -1:
453                         puts ("failed\n");
454                         return 1;
455                 default:
456                         printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
457                         return 1;
458                 }
459                 puts ("done\n");
460                 return 0;
461         }
462
463         if (mmc2info(addr)) {
464                 int rc;
465
466                 puts ("Copy from MMC... ");
467                 switch (rc = mmc_read (addr, (uchar *)dest, count*size)) {
468                 case 0:
469                         putc ('\n');
470                         return 1;
471                 case -1:
472                         puts ("failed\n");
473                         return 1;
474                 default:
475                         printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
476                         return 1;
477                 }
478                 puts ("done\n");
479                 return 0;
480         }
481 #endif
482
483 #ifdef CONFIG_HAS_DATAFLASH
484         /* Check if we are copying from RAM or Flash to DataFlash */
485         if (addr_dataflash(dest) && !addr_dataflash(addr)){
486                 int rc;
487
488                 puts ("Copy to DataFlash... ");
489
490                 rc = write_dataflash (dest, addr, count*size);
491
492                 if (rc != 1) {
493                         dataflash_perror (rc);
494                         return (1);
495                 }
496                 puts ("done\n");
497                 return 0;
498         }
499
500         /* Check if we are copying from DataFlash to RAM */
501         if (addr_dataflash(addr) && !addr_dataflash(dest) && (addr2info(dest)==NULL) ){
502                 int rc;
503                 rc = read_dataflash(addr, count * size, (char *) dest);
504                 if (rc != 1) {
505                         dataflash_perror (rc);
506                         return (1);
507                 }
508                 return 0;
509         }
510
511         if (addr_dataflash(addr) && addr_dataflash(dest)){
512                 puts ("Unsupported combination of source/destination.\n\r");
513                 return 1;
514         }
515 #endif
516
517         while (count-- > 0) {
518                 if (size == 4)
519                         *((ulong  *)dest) = *((ulong  *)addr);
520                 else if (size == 2)
521                         *((ushort *)dest) = *((ushort *)addr);
522                 else
523                         *((u_char *)dest) = *((u_char *)addr);
524                 addr += size;
525                 dest += size;
526         }
527         return 0;
528 }
529
530 int do_mem_base (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
531 {
532         if (argc > 1) {
533                 /* Set new base address.
534                 */
535                 base_address = simple_strtoul(argv[1], NULL, 16);
536         }
537         /* Print the current base address.
538         */
539         printf("Base Address: 0x%08lx\n", base_address);
540         return 0;
541 }
542
543 int do_mem_loop (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
544 {
545         ulong   addr, length, i, junk;
546         int     size;
547         volatile uint   *longp;
548         volatile ushort *shortp;
549         volatile u_char *cp;
550
551         if (argc < 3) {
552                 printf ("Usage:\n%s\n", cmdtp->usage);
553                 return 1;
554         }
555
556         /* Check for a size spefication.
557          * Defaults to long if no or incorrect specification.
558          */
559         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
560                 return 1;
561
562         /* Address is always specified.
563         */
564         addr = simple_strtoul(argv[1], NULL, 16);
565
566         /* Length is the number of objects, not number of bytes.
567         */
568         length = simple_strtoul(argv[2], NULL, 16);
569
570         /* We want to optimize the loops to run as fast as possible.
571          * If we have only one object, just run infinite loops.
572          */
573         if (length == 1) {
574                 if (size == 4) {
575                         longp = (uint *)addr;
576                         for (;;)
577                                 i = *longp;
578                 }
579                 if (size == 2) {
580                         shortp = (ushort *)addr;
581                         for (;;)
582                                 i = *shortp;
583                 }
584                 cp = (u_char *)addr;
585                 for (;;)
586                         i = *cp;
587         }
588
589         if (size == 4) {
590                 for (;;) {
591                         longp = (uint *)addr;
592                         i = length;
593                         while (i-- > 0)
594                                 junk = *longp++;
595                 }
596         }
597         if (size == 2) {
598                 for (;;) {
599                         shortp = (ushort *)addr;
600                         i = length;
601                         while (i-- > 0)
602                                 junk = *shortp++;
603                 }
604         }
605         for (;;) {
606                 cp = (u_char *)addr;
607                 i = length;
608                 while (i-- > 0)
609                         junk = *cp++;
610         }
611 }
612
613 #ifdef CONFIG_LOOPW
614 int do_mem_loopw (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
615 {
616         ulong   addr, length, i, data;
617         int     size;
618         volatile uint   *longp;
619         volatile ushort *shortp;
620         volatile u_char *cp;
621
622         if (argc < 4) {
623                 printf ("Usage:\n%s\n", cmdtp->usage);
624                 return 1;
625         }
626
627         /* Check for a size spefication.
628          * Defaults to long if no or incorrect specification.
629          */
630         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
631                 return 1;
632
633         /* Address is always specified.
634         */
635         addr = simple_strtoul(argv[1], NULL, 16);
636
637         /* Length is the number of objects, not number of bytes.
638         */
639         length = simple_strtoul(argv[2], NULL, 16);
640
641         /* data to write */
642         data = simple_strtoul(argv[3], NULL, 16);
643
644         /* We want to optimize the loops to run as fast as possible.
645          * If we have only one object, just run infinite loops.
646          */
647         if (length == 1) {
648                 if (size == 4) {
649                         longp = (uint *)addr;
650                         for (;;)
651                                 *longp = data;
652                                         }
653                 if (size == 2) {
654                         shortp = (ushort *)addr;
655                         for (;;)
656                                 *shortp = data;
657                 }
658                 cp = (u_char *)addr;
659                 for (;;)
660                         *cp = data;
661         }
662
663         if (size == 4) {
664                 for (;;) {
665                         longp = (uint *)addr;
666                         i = length;
667                         while (i-- > 0)
668                                 *longp++ = data;
669                 }
670         }
671         if (size == 2) {
672                 for (;;) {
673                         shortp = (ushort *)addr;
674                         i = length;
675                         while (i-- > 0)
676                                 *shortp++ = data;
677                 }
678         }
679         for (;;) {
680                 cp = (u_char *)addr;
681                 i = length;
682                 while (i-- > 0)
683                         *cp++ = data;
684         }
685 }
686 #endif /* CONFIG_LOOPW */
687
688 /*
689  * Perform a memory test. A more complete alternative test can be
690  * configured using CFG_ALT_MEMTEST. The complete test loops until
691  * interrupted by ctrl-c or by a failure of one of the sub-tests.
692  */
693 int do_mem_mtest (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
694 {
695         vu_long *addr, *start, *end;
696         ulong   val;
697         ulong   readback;
698
699 #if defined(CFG_ALT_MEMTEST)
700         vu_long addr_mask;
701         vu_long offset;
702         vu_long test_offset;
703         vu_long pattern;
704         vu_long temp;
705         vu_long anti_pattern;
706         vu_long num_words;
707 #if defined(CFG_MEMTEST_SCRATCH)
708         vu_long *dummy = (vu_long*)CFG_MEMTEST_SCRATCH;
709 #else
710         vu_long *dummy = NULL;
711 #endif
712         int     j;
713         int iterations = 1;
714
715         static const ulong bitpattern[] = {
716                 0x00000001,     /* single bit */
717                 0x00000003,     /* two adjacent bits */
718                 0x00000007,     /* three adjacent bits */
719                 0x0000000F,     /* four adjacent bits */
720                 0x00000005,     /* two non-adjacent bits */
721                 0x00000015,     /* three non-adjacent bits */
722                 0x00000055,     /* four non-adjacent bits */
723                 0xaaaaaaaa,     /* alternating 1/0 */
724         };
725 #else
726         ulong   incr;
727         ulong   pattern;
728         int     rcode = 0;
729 #endif
730
731         if (argc > 1) {
732                 start = (ulong *)simple_strtoul(argv[1], NULL, 16);
733         } else {
734                 start = (ulong *)CFG_MEMTEST_START;
735         }
736
737         if (argc > 2) {
738                 end = (ulong *)simple_strtoul(argv[2], NULL, 16);
739         } else {
740                 end = (ulong *)(CFG_MEMTEST_END);
741         }
742
743         if (argc > 3) {
744                 pattern = (ulong)simple_strtoul(argv[3], NULL, 16);
745         } else {
746                 pattern = 0;
747         }
748
749 #if defined(CFG_ALT_MEMTEST)
750         printf ("Testing %08x ... %08x:\n", (uint)start, (uint)end);
751         PRINTF("%s:%d: start 0x%p end 0x%p\n",
752                 __FUNCTION__, __LINE__, start, end);
753
754         for (;;) {
755                 if (ctrlc()) {
756                         putc ('\n');
757                         return 1;
758                 }
759
760                 printf("Iteration: %6d\r", iterations);
761                 PRINTF("Iteration: %6d\n", iterations);
762                 iterations++;
763
764                 /*
765                  * Data line test: write a pattern to the first
766                  * location, write the 1's complement to a 'parking'
767                  * address (changes the state of the data bus so a
768                  * floating bus doen't give a false OK), and then
769                  * read the value back. Note that we read it back
770                  * into a variable because the next time we read it,
771                  * it might be right (been there, tough to explain to
772                  * the quality guys why it prints a failure when the
773                  * "is" and "should be" are obviously the same in the
774                  * error message).
775                  *
776                  * Rather than exhaustively testing, we test some
777                  * patterns by shifting '1' bits through a field of
778                  * '0's and '0' bits through a field of '1's (i.e.
779                  * pattern and ~pattern).
780                  */
781                 addr = start;
782                 for (j = 0; j < sizeof(bitpattern)/sizeof(bitpattern[0]); j++) {
783                     val = bitpattern[j];
784                     for(; val != 0; val <<= 1) {
785                         *addr  = val;
786                         *dummy  = ~val; /* clear the test data off of the bus */
787                         readback = *addr;
788                         if(readback != val) {
789                              printf ("FAILURE (data line): "
790                                 "expected %08lx, actual %08lx\n",
791                                           val, readback);
792                         }
793                         *addr  = ~val;
794                         *dummy  = val;
795                         readback = *addr;
796                         if(readback != ~val) {
797                             printf ("FAILURE (data line): "
798                                 "Is %08lx, should be %08lx\n",
799                                         readback, ~val);
800                         }
801                     }
802                 }
803
804                 /*
805                  * Based on code whose Original Author and Copyright
806                  * information follows: Copyright (c) 1998 by Michael
807                  * Barr. This software is placed into the public
808                  * domain and may be used for any purpose. However,
809                  * this notice must not be changed or removed and no
810                  * warranty is either expressed or implied by its
811                  * publication or distribution.
812                  */
813
814                 /*
815                  * Address line test
816                  *
817                  * Description: Test the address bus wiring in a
818                  *              memory region by performing a walking
819                  *              1's test on the relevant bits of the
820                  *              address and checking for aliasing.
821                  *              This test will find single-bit
822                  *              address failures such as stuck -high,
823                  *              stuck-low, and shorted pins. The base
824                  *              address and size of the region are
825                  *              selected by the caller.
826                  *
827                  * Notes:       For best results, the selected base
828                  *              address should have enough LSB 0's to
829                  *              guarantee single address bit changes.
830                  *              For example, to test a 64-Kbyte
831                  *              region, select a base address on a
832                  *              64-Kbyte boundary. Also, select the
833                  *              region size as a power-of-two if at
834                  *              all possible.
835                  *
836                  * Returns:     0 if the test succeeds, 1 if the test fails.
837                  *
838                  * ## NOTE ##   Be sure to specify start and end
839                  *              addresses such that addr_mask has
840                  *              lots of bits set. For example an
841                  *              address range of 01000000 02000000 is
842                  *              bad while a range of 01000000
843                  *              01ffffff is perfect.
844                  */
845                 addr_mask = ((ulong)end - (ulong)start)/sizeof(vu_long);
846                 pattern = (vu_long) 0xaaaaaaaa;
847                 anti_pattern = (vu_long) 0x55555555;
848
849                 PRINTF("%s:%d: addr mask = 0x%.8lx\n",
850                         __FUNCTION__, __LINE__,
851                         addr_mask);
852                 /*
853                  * Write the default pattern at each of the
854                  * power-of-two offsets.
855                  */
856                 for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
857                         start[offset] = pattern;
858                 }
859
860                 /*
861                  * Check for address bits stuck high.
862                  */
863                 test_offset = 0;
864                 start[test_offset] = anti_pattern;
865
866                 for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
867                     temp = start[offset];
868                     if (temp != pattern) {
869                         printf ("\nFAILURE: Address bit stuck high @ 0x%.8lx:"
870                                 " expected 0x%.8lx, actual 0x%.8lx\n",
871                                 (ulong)&start[offset], pattern, temp);
872                         return 1;
873                     }
874                 }
875                 start[test_offset] = pattern;
876
877                 /*
878                  * Check for addr bits stuck low or shorted.
879                  */
880                 for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) {
881                     start[test_offset] = anti_pattern;
882
883                     for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
884                         temp = start[offset];
885                         if ((temp != pattern) && (offset != test_offset)) {
886                             printf ("\nFAILURE: Address bit stuck low or shorted @"
887                                 " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n",
888                                 (ulong)&start[offset], pattern, temp);
889                             return 1;
890                         }
891                     }
892                     start[test_offset] = pattern;
893                 }
894
895                 /*
896                  * Description: Test the integrity of a physical
897                  *              memory device by performing an
898                  *              increment/decrement test over the
899                  *              entire region. In the process every
900                  *              storage bit in the device is tested
901                  *              as a zero and a one. The base address
902                  *              and the size of the region are
903                  *              selected by the caller.
904                  *
905                  * Returns:     0 if the test succeeds, 1 if the test fails.
906                  */
907                 num_words = ((ulong)end - (ulong)start)/sizeof(vu_long) + 1;
908
909                 /*
910                  * Fill memory with a known pattern.
911                  */
912                 for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
913                         start[offset] = pattern;
914                 }
915
916                 /*
917                  * Check each location and invert it for the second pass.
918                  */
919                 for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
920                     temp = start[offset];
921                     if (temp != pattern) {
922                         printf ("\nFAILURE (read/write) @ 0x%.8lx:"
923                                 " expected 0x%.8lx, actual 0x%.8lx)\n",
924                                 (ulong)&start[offset], pattern, temp);
925                         return 1;
926                     }
927
928                     anti_pattern = ~pattern;
929                     start[offset] = anti_pattern;
930                 }
931
932                 /*
933                  * Check each location for the inverted pattern and zero it.
934                  */
935                 for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
936                     anti_pattern = ~pattern;
937                     temp = start[offset];
938                     if (temp != anti_pattern) {
939                         printf ("\nFAILURE (read/write): @ 0x%.8lx:"
940                                 " expected 0x%.8lx, actual 0x%.8lx)\n",
941                                 (ulong)&start[offset], anti_pattern, temp);
942                         return 1;
943                     }
944                     start[offset] = 0;
945                 }
946         }
947
948 #else /* The original, quickie test */
949         incr = 1;
950         for (;;) {
951                 if (ctrlc()) {
952                         putc ('\n');
953                         return 1;
954                 }
955
956                 printf ("\rPattern %08lX  Writing..."
957                         "%12s"
958                         "\b\b\b\b\b\b\b\b\b\b",
959                         pattern, "");
960
961                 for (addr=start,val=pattern; addr<end; addr++) {
962                         *addr = val;
963                         val  += incr;
964                 }
965
966                 puts ("Reading...");
967
968                 for (addr=start,val=pattern; addr<end; addr++) {
969                         readback = *addr;
970                         if (readback != val) {
971                                 printf ("\nMem error @ 0x%08X: "
972                                         "found %08lX, expected %08lX\n",
973                                         (uint)addr, readback, val);
974                                 rcode = 1;
975                         }
976                         val += incr;
977                 }
978
979                 /*
980                  * Flip the pattern each time to make lots of zeros and
981                  * then, the next time, lots of ones.  We decrement
982                  * the "negative" patterns and increment the "positive"
983                  * patterns to preserve this feature.
984                  */
985                 if(pattern & 0x80000000) {
986                         pattern = -pattern;     /* complement & increment */
987                 }
988                 else {
989                         pattern = ~pattern;
990                 }
991                 incr = -incr;
992         }
993         return rcode;
994 #endif
995 }
996
997
998 /* Modify memory.
999  *
1000  * Syntax:
1001  *      mm{.b, .w, .l} {addr}
1002  *      nm{.b, .w, .l} {addr}
1003  */
1004 static int
1005 mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[])
1006 {
1007         ulong   addr, i;
1008         int     nbytes, size;
1009         extern char console_buffer[];
1010
1011         if (argc != 2) {
1012                 printf ("Usage:\n%s\n", cmdtp->usage);
1013                 return 1;
1014         }
1015
1016 #ifdef CONFIG_BOOT_RETRY_TIME
1017         reset_cmd_timeout();    /* got a good command to get here */
1018 #endif
1019         /* We use the last specified parameters, unless new ones are
1020          * entered.
1021          */
1022         addr = mm_last_addr;
1023         size = mm_last_size;
1024
1025         if ((flag & CMD_FLAG_REPEAT) == 0) {
1026                 /* New command specified.  Check for a size specification.
1027                  * Defaults to long if no or incorrect specification.
1028                  */
1029                 if ((size = cmd_get_data_size(argv[0], 4)) < 0)
1030                         return 1;
1031
1032                 /* Address is specified since argc > 1
1033                 */
1034                 addr = simple_strtoul(argv[1], NULL, 16);
1035                 addr += base_address;
1036         }
1037
1038 #ifdef CONFIG_HAS_DATAFLASH
1039         if (addr_dataflash(addr)){
1040                 puts ("Can't modify DataFlash in place. Use cp instead.\n\r");
1041                 return 0;
1042         }
1043 #endif
1044
1045         /* Print the address, followed by value.  Then accept input for
1046          * the next value.  A non-converted value exits.
1047          */
1048         do {
1049                 printf("%08lx:", addr);
1050                 if (size == 4)
1051                         printf(" %08x", *((uint   *)addr));
1052                 else if (size == 2)
1053                         printf(" %04x", *((ushort *)addr));
1054                 else
1055                         printf(" %02x", *((u_char *)addr));
1056
1057                 nbytes = readline (" ? ");
1058                 if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
1059                         /* <CR> pressed as only input, don't modify current
1060                          * location and move to next. "-" pressed will go back.
1061                          */
1062                         if (incrflag)
1063                                 addr += nbytes ? -size : size;
1064                         nbytes = 1;
1065 #ifdef CONFIG_BOOT_RETRY_TIME
1066                         reset_cmd_timeout(); /* good enough to not time out */
1067 #endif
1068                 }
1069 #ifdef CONFIG_BOOT_RETRY_TIME
1070                 else if (nbytes == -2) {
1071                         break;  /* timed out, exit the command  */
1072                 }
1073 #endif
1074                 else {
1075                         char *endp;
1076                         i = simple_strtoul(console_buffer, &endp, 16);
1077                         nbytes = endp - console_buffer;
1078                         if (nbytes) {
1079 #ifdef CONFIG_BOOT_RETRY_TIME
1080                                 /* good enough to not time out
1081                                  */
1082                                 reset_cmd_timeout();
1083 #endif
1084                                 if (size == 4)
1085                                         *((uint   *)addr) = i;
1086                                 else if (size == 2)
1087                                         *((ushort *)addr) = i;
1088                                 else
1089                                         *((u_char *)addr) = i;
1090                                 if (incrflag)
1091                                         addr += size;
1092                         }
1093                 }
1094         } while (nbytes);
1095
1096         mm_last_addr = addr;
1097         mm_last_size = size;
1098         return 0;
1099 }
1100
1101 #ifndef CONFIG_CRC32_VERIFY
1102
1103 int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1104 {
1105         ulong addr, length;
1106         ulong crc;
1107         ulong *ptr;
1108
1109         if (argc < 3) {
1110                 printf ("Usage:\n%s\n", cmdtp->usage);
1111                 return 1;
1112         }
1113
1114         addr = simple_strtoul (argv[1], NULL, 16);
1115         addr += base_address;
1116
1117         length = simple_strtoul (argv[2], NULL, 16);
1118
1119         crc = crc32 (0, (const uchar *) addr, length);
1120
1121         printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
1122                         addr, addr + length - 1, crc);
1123
1124         if (argc > 3) {
1125                 ptr = (ulong *) simple_strtoul (argv[3], NULL, 16);
1126                 *ptr = crc;
1127         }
1128
1129         return 0;
1130 }
1131
1132 #else   /* CONFIG_CRC32_VERIFY */
1133
1134 int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1135 {
1136         ulong addr, length;
1137         ulong crc;
1138         ulong *ptr;
1139         ulong vcrc;
1140         int verify;
1141         int ac;
1142         char **av;
1143
1144         if (argc < 3) {
1145   usage:
1146                 printf ("Usage:\n%s\n", cmdtp->usage);
1147                 return 1;
1148         }
1149
1150         av = argv + 1;
1151         ac = argc - 1;
1152         if (strcmp(*av, "-v") == 0) {
1153                 verify = 1;
1154                 av++;
1155                 ac--;
1156                 if (ac < 3)
1157                         goto usage;
1158         } else
1159                 verify = 0;
1160
1161         addr = simple_strtoul(*av++, NULL, 16);
1162         addr += base_address;
1163         length = simple_strtoul(*av++, NULL, 16);
1164
1165         crc = crc32(0, (const uchar *) addr, length);
1166
1167         if (!verify) {
1168                 printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
1169                                 addr, addr + length - 1, crc);
1170                 if (ac > 2) {
1171                         ptr = (ulong *) simple_strtoul (*av++, NULL, 16);
1172                         *ptr = crc;
1173                 }
1174         } else {
1175                 vcrc = simple_strtoul(*av++, NULL, 16);
1176                 if (vcrc != crc) {
1177                         printf ("CRC32 for %08lx ... %08lx ==> %08lx != %08lx ** ERROR **\n",
1178                                         addr, addr + length - 1, crc, vcrc);
1179                         return 1;
1180                 }
1181         }
1182
1183         return 0;
1184
1185 }
1186 #endif  /* CONFIG_CRC32_VERIFY */
1187
1188 /**************************************************/
1189 #if (CONFIG_COMMANDS & CFG_CMD_MEMORY)
1190 U_BOOT_CMD(
1191         md,     3,     1,      do_mem_md,
1192         "md      - memory display\n",
1193         "[.b, .w, .l] address [# of objects]\n    - memory display\n"
1194 );
1195
1196
1197 U_BOOT_CMD(
1198         mm,     2,      1,       do_mem_mm,
1199         "mm      - memory modify (auto-incrementing)\n",
1200         "[.b, .w, .l] address\n" "    - memory modify, auto increment address\n"
1201 );
1202
1203
1204 U_BOOT_CMD(
1205         nm,     2,          1,          do_mem_nm,
1206         "nm      - memory modify (constant address)\n",
1207         "[.b, .w, .l] address\n    - memory modify, read and keep address\n"
1208 );
1209
1210 U_BOOT_CMD(
1211         mw,    4,    1,     do_mem_mw,
1212         "mw      - memory write (fill)\n",
1213         "[.b, .w, .l] address value [count]\n    - write memory\n"
1214 );
1215
1216 U_BOOT_CMD(
1217         cp,    4,    1,    do_mem_cp,
1218         "cp      - memory copy\n",
1219         "[.b, .w, .l] source target count\n    - copy memory\n"
1220 );
1221
1222 U_BOOT_CMD(
1223         cmp,    4,     1,     do_mem_cmp,
1224         "cmp     - memory compare\n",
1225         "[.b, .w, .l] addr1 addr2 count\n    - compare memory\n"
1226 );
1227
1228 #ifndef CONFIG_CRC32_VERIFY
1229
1230 U_BOOT_CMD(
1231         crc32,    4,    1,     do_mem_crc,
1232         "crc32   - checksum calculation\n",
1233         "address count [addr]\n    - compute CRC32 checksum [save at addr]\n"
1234 );
1235
1236 #else   /* CONFIG_CRC32_VERIFY */
1237
1238 U_BOOT_CMD(
1239         crc32,    5,    1,     do_mem_crc,
1240         "crc32   - checksum calculation\n",
1241         "address count [addr]\n    - compute CRC32 checksum [save at addr]\n"
1242         "-v address count crc\n    - verify crc of memory area\n"
1243 );
1244
1245 #endif  /* CONFIG_CRC32_VERIFY */
1246
1247 U_BOOT_CMD(
1248         base,    2,    1,     do_mem_base,
1249         "base    - print or set address offset\n",
1250         "\n    - print address offset for memory commands\n"
1251         "base off\n    - set address offset for memory commands to 'off'\n"
1252 );
1253
1254 U_BOOT_CMD(
1255         loop,    3,    1,    do_mem_loop,
1256         "loop    - infinite loop on address range\n",
1257         "[.b, .w, .l] address number_of_objects\n"
1258         "    - loop on a set of addresses\n"
1259 );
1260
1261 #ifdef CONFIG_LOOPW
1262 U_BOOT_CMD(
1263         loopw,    4,    1,    do_mem_loopw,
1264         "loopw   - infinite write loop on address range\n",
1265         "[.b, .w, .l] address number_of_objects data_to_write\n"
1266         "    - loop on a set of addresses\n"
1267 );
1268 #endif /* CONFIG_LOOPW */
1269
1270 U_BOOT_CMD(
1271         mtest,    4,    1,     do_mem_mtest,
1272         "mtest   - simple RAM test\n",
1273         "[start [end [pattern]]]\n"
1274         "    - simple RAM read/write test\n"
1275 );
1276
1277 #ifdef CONFIG_MX_CYCLIC
1278 U_BOOT_CMD(
1279         mdc,     4,     1,      do_mem_mdc,
1280         "mdc     - memory display cyclic\n",
1281         "[.b, .w, .l] address count delay(ms)\n    - memory display cyclic\n"
1282 );
1283
1284 U_BOOT_CMD(
1285         mwc,     4,     1,      do_mem_mwc,
1286         "mwc     - memory write cyclic\n",
1287         "[.b, .w, .l] address value delay(ms)\n    - memory write cyclic\n"
1288 );
1289 #endif /* CONFIG_MX_CYCLIC */
1290
1291 #endif
1292 #endif  /* CFG_CMD_MEMORY */