]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_mem.c
* Patch by Gridish Shlomi, 30 Aug 2004:
[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 int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
257 {
258         ulong   addr1, addr2, count, ngood;
259         int     size;
260         int     rcode = 0;
261
262         if (argc != 4) {
263                 printf ("Usage:\n%s\n", cmdtp->usage);
264                 return 1;
265         }
266
267         /* Check for size specification.
268         */
269         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
270                 return 1;
271
272         addr1 = simple_strtoul(argv[1], NULL, 16);
273         addr1 += base_address;
274
275         addr2 = simple_strtoul(argv[2], NULL, 16);
276         addr2 += base_address;
277
278         count = simple_strtoul(argv[3], NULL, 16);
279
280 #ifdef CONFIG_HAS_DATAFLASH
281         if (addr_dataflash(addr1) | addr_dataflash(addr2)){
282                 puts ("Comparison with DataFlash space not supported.\n\r");
283                 return 0;
284         }
285 #endif
286
287         ngood = 0;
288
289         while (count-- > 0) {
290                 if (size == 4) {
291                         ulong word1 = *(ulong *)addr1;
292                         ulong word2 = *(ulong *)addr2;
293                         if (word1 != word2) {
294                                 printf("word at 0x%08lx (0x%08lx) "
295                                         "!= word at 0x%08lx (0x%08lx)\n",
296                                         addr1, word1, addr2, word2);
297                                 rcode = 1;
298                                 break;
299                         }
300                 }
301                 else if (size == 2) {
302                         ushort hword1 = *(ushort *)addr1;
303                         ushort hword2 = *(ushort *)addr2;
304                         if (hword1 != hword2) {
305                                 printf("halfword at 0x%08lx (0x%04x) "
306                                         "!= halfword at 0x%08lx (0x%04x)\n",
307                                         addr1, hword1, addr2, hword2);
308                                 rcode = 1;
309                                 break;
310                         }
311                 }
312                 else {
313                         u_char byte1 = *(u_char *)addr1;
314                         u_char byte2 = *(u_char *)addr2;
315                         if (byte1 != byte2) {
316                                 printf("byte at 0x%08lx (0x%02x) "
317                                         "!= byte at 0x%08lx (0x%02x)\n",
318                                         addr1, byte1, addr2, byte2);
319                                 rcode = 1;
320                                 break;
321                         }
322                 }
323                 ngood++;
324                 addr1 += size;
325                 addr2 += size;
326         }
327
328         printf("Total of %ld %s%s were the same\n",
329                 ngood, size == 4 ? "word" : size == 2 ? "halfword" : "byte",
330                 ngood == 1 ? "" : "s");
331         return rcode;
332 }
333
334 int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
335 {
336         ulong   addr, dest, count;
337         int     size;
338
339         if (argc != 4) {
340                 printf ("Usage:\n%s\n", cmdtp->usage);
341                 return 1;
342         }
343
344         /* Check for size specification.
345         */
346         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
347                 return 1;
348
349         addr = simple_strtoul(argv[1], NULL, 16);
350         addr += base_address;
351
352         dest = simple_strtoul(argv[2], NULL, 16);
353         dest += base_address;
354
355         count = simple_strtoul(argv[3], NULL, 16);
356
357         if (count == 0) {
358                 puts ("Zero length ???\n");
359                 return 1;
360         }
361
362 #ifndef CFG_NO_FLASH
363         /* check if we are copying to Flash */
364         if ( (addr2info(dest) != NULL)
365 #ifdef CONFIG_HAS_DATAFLASH
366            && (!addr_dataflash(addr))
367 #endif
368            ) {
369                 int rc;
370
371                 puts ("Copy to Flash... ");
372
373                 rc = flash_write ((uchar *)addr, dest, count*size);
374                 if (rc != 0) {
375                         flash_perror (rc);
376                         return (1);
377                 }
378                 puts ("done\n");
379                 return 0;
380         }
381 #endif
382
383 #if (CONFIG_COMMANDS & CFG_CMD_MMC)
384         if (mmc2info(dest)) {
385                 int rc;
386
387                 puts ("Copy to MMC... ");
388                 switch (rc = mmc_write ((uchar *)addr, dest, count*size)) {
389                 case 0:
390                         putc ('\n');
391                         return 1;
392                 case -1:
393                         puts ("failed\n");
394                         return 1;
395                 default:
396                         printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
397                         return 1;
398                 }
399                 puts ("done\n");
400                 return 0;
401         }
402
403         if (mmc2info(addr)) {
404                 int rc;
405
406                 puts ("Copy from MMC... ");
407                 switch (rc = mmc_read (addr, (uchar *)dest, count*size)) {
408                 case 0:
409                         putc ('\n');
410                         return 1;
411                 case -1:
412                         puts ("failed\n");
413                         return 1;
414                 default:
415                         printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
416                         return 1;
417                 }
418                 puts ("done\n");
419                 return 0;
420         }
421 #endif
422
423 #ifdef CONFIG_HAS_DATAFLASH
424         /* Check if we are copying from RAM or Flash to DataFlash */
425         if (addr_dataflash(dest) && !addr_dataflash(addr)){
426                 int rc;
427
428                 puts ("Copy to DataFlash... ");
429
430                 rc = write_dataflash (dest, addr, count*size);
431
432                 if (rc != 1) {
433                         dataflash_perror (rc);
434                         return (1);
435                 }
436                 puts ("done\n");
437                 return 0;
438         }
439
440         /* Check if we are copying from DataFlash to RAM */
441         if (addr_dataflash(addr) && !addr_dataflash(dest) && (addr2info(dest)==NULL) ){
442                 int rc;
443                 rc = read_dataflash(addr, count * size, (char *) dest);
444                 if (rc != 1) {
445                         dataflash_perror (rc);
446                         return (1);
447                 }
448                 return 0;
449         }
450
451         if (addr_dataflash(addr) && addr_dataflash(dest)){
452                 puts ("Unsupported combination of source/destination.\n\r");
453                 return 1;
454         }
455 #endif
456
457         while (count-- > 0) {
458                 if (size == 4)
459                         *((ulong  *)dest) = *((ulong  *)addr);
460                 else if (size == 2)
461                         *((ushort *)dest) = *((ushort *)addr);
462                 else
463                         *((u_char *)dest) = *((u_char *)addr);
464                 addr += size;
465                 dest += size;
466         }
467         return 0;
468 }
469
470 int do_mem_base (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
471 {
472         if (argc > 1) {
473                 /* Set new base address.
474                 */
475                 base_address = simple_strtoul(argv[1], NULL, 16);
476         }
477         /* Print the current base address.
478         */
479         printf("Base Address: 0x%08lx\n", base_address);
480         return 0;
481 }
482
483 int do_mem_loop (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
484 {
485         ulong   addr, length, i, junk;
486         int     size;
487         volatile uint   *longp;
488         volatile ushort *shortp;
489         volatile u_char *cp;
490
491         if (argc < 3) {
492                 printf ("Usage:\n%s\n", cmdtp->usage);
493                 return 1;
494         }
495
496         /* Check for a size spefication.
497          * Defaults to long if no or incorrect specification.
498          */
499         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
500                 return 1;
501
502         /* Address is always specified.
503         */
504         addr = simple_strtoul(argv[1], NULL, 16);
505
506         /* Length is the number of objects, not number of bytes.
507         */
508         length = simple_strtoul(argv[2], NULL, 16);
509
510         /* We want to optimize the loops to run as fast as possible.
511          * If we have only one object, just run infinite loops.
512          */
513         if (length == 1) {
514                 if (size == 4) {
515                         longp = (uint *)addr;
516                         for (;;)
517                                 i = *longp;
518                 }
519                 if (size == 2) {
520                         shortp = (ushort *)addr;
521                         for (;;)
522                                 i = *shortp;
523                 }
524                 cp = (u_char *)addr;
525                 for (;;)
526                         i = *cp;
527         }
528
529         if (size == 4) {
530                 for (;;) {
531                         longp = (uint *)addr;
532                         i = length;
533                         while (i-- > 0)
534                                 junk = *longp++;
535                 }
536         }
537         if (size == 2) {
538                 for (;;) {
539                         shortp = (ushort *)addr;
540                         i = length;
541                         while (i-- > 0)
542                                 junk = *shortp++;
543                 }
544         }
545         for (;;) {
546                 cp = (u_char *)addr;
547                 i = length;
548                 while (i-- > 0)
549                         junk = *cp++;
550         }
551 }
552
553 #ifdef CONFIG_LOOPW
554 int do_mem_loopw (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
555 {
556         ulong   addr, length, i, data;
557         int     size;
558         volatile uint   *longp;
559         volatile ushort *shortp;
560         volatile u_char *cp;
561
562         if (argc < 4) {
563                 printf ("Usage:\n%s\n", cmdtp->usage);
564                 return 1;
565         }
566
567         /* Check for a size spefication.
568          * Defaults to long if no or incorrect specification.
569          */
570         if ((size = cmd_get_data_size(argv[0], 4)) < 0)
571                 return 1;
572
573         /* Address is always specified.
574         */
575         addr = simple_strtoul(argv[1], NULL, 16);
576
577         /* Length is the number of objects, not number of bytes.
578         */
579         length = simple_strtoul(argv[2], NULL, 16);
580
581         /* data to write */
582         data = simple_strtoul(argv[3], NULL, 16);
583
584         /* We want to optimize the loops to run as fast as possible.
585          * If we have only one object, just run infinite loops.
586          */
587         if (length == 1) {
588                 if (size == 4) {
589                         longp = (uint *)addr;
590                         for (;;)
591                                 *longp = data;
592                                         }
593                 if (size == 2) {
594                         shortp = (ushort *)addr;
595                         for (;;)
596                                 *shortp = data;
597                 }
598                 cp = (u_char *)addr;
599                 for (;;)
600                         *cp = data;
601         }
602
603         if (size == 4) {
604                 for (;;) {
605                         longp = (uint *)addr;
606                         i = length;
607                         while (i-- > 0)
608                                 *longp++ = data;
609                 }
610         }
611         if (size == 2) {
612                 for (;;) {
613                         shortp = (ushort *)addr;
614                         i = length;
615                         while (i-- > 0)
616                                 *shortp++ = data;
617                 }
618         }
619         for (;;) {
620                 cp = (u_char *)addr;
621                 i = length;
622                 while (i-- > 0)
623                         *cp++ = data;
624         }
625 }
626 #endif /* CONFIG_LOOPW */
627
628 /*
629  * Perform a memory test. A more complete alternative test can be
630  * configured using CFG_ALT_MEMTEST. The complete test loops until
631  * interrupted by ctrl-c or by a failure of one of the sub-tests.
632  */
633 int do_mem_mtest (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
634 {
635         vu_long *addr, *start, *end;
636         ulong   val;
637         ulong   readback;
638
639 #if defined(CFG_ALT_MEMTEST)
640         vu_long addr_mask;
641         vu_long offset;
642         vu_long test_offset;
643         vu_long pattern;
644         vu_long temp;
645         vu_long anti_pattern;
646         vu_long num_words;
647 #if defined(CFG_MEMTEST_SCRATCH)
648         vu_long *dummy = (vu_long*)CFG_MEMTEST_SCRATCH;
649 #else
650         vu_long *dummy = NULL;
651 #endif
652         int     j;
653         int iterations = 1;
654
655         static const ulong bitpattern[] = {
656                 0x00000001,     /* single bit */
657                 0x00000003,     /* two adjacent bits */
658                 0x00000007,     /* three adjacent bits */
659                 0x0000000F,     /* four adjacent bits */
660                 0x00000005,     /* two non-adjacent bits */
661                 0x00000015,     /* three non-adjacent bits */
662                 0x00000055,     /* four non-adjacent bits */
663                 0xaaaaaaaa,     /* alternating 1/0 */
664         };
665 #else
666         ulong   incr;
667         ulong   pattern;
668         int     rcode = 0;
669 #endif
670
671         if (argc > 1) {
672                 start = (ulong *)simple_strtoul(argv[1], NULL, 16);
673         } else {
674                 start = (ulong *)CFG_MEMTEST_START;
675         }
676
677         if (argc > 2) {
678                 end = (ulong *)simple_strtoul(argv[2], NULL, 16);
679         } else {
680                 end = (ulong *)(CFG_MEMTEST_END);
681         }
682
683         if (argc > 3) {
684                 pattern = (ulong)simple_strtoul(argv[3], NULL, 16);
685         } else {
686                 pattern = 0;
687         }
688
689 #if defined(CFG_ALT_MEMTEST)
690         printf ("Testing %08x ... %08x:\n", (uint)start, (uint)end);
691         PRINTF("%s:%d: start 0x%p end 0x%p\n",
692                 __FUNCTION__, __LINE__, start, end);
693
694         for (;;) {
695                 if (ctrlc()) {
696                         putc ('\n');
697                         return 1;
698                 }
699
700                 printf("Iteration: %6d\r", iterations);
701                 PRINTF("Iteration: %6d\n", iterations);
702                 iterations++;
703
704                 /*
705                  * Data line test: write a pattern to the first
706                  * location, write the 1's complement to a 'parking'
707                  * address (changes the state of the data bus so a
708                  * floating bus doen't give a false OK), and then
709                  * read the value back. Note that we read it back
710                  * into a variable because the next time we read it,
711                  * it might be right (been there, tough to explain to
712                  * the quality guys why it prints a failure when the
713                  * "is" and "should be" are obviously the same in the
714                  * error message).
715                  *
716                  * Rather than exhaustively testing, we test some
717                  * patterns by shifting '1' bits through a field of
718                  * '0's and '0' bits through a field of '1's (i.e.
719                  * pattern and ~pattern).
720                  */
721                 addr = start;
722                 for (j = 0; j < sizeof(bitpattern)/sizeof(bitpattern[0]); j++) {
723                     val = bitpattern[j];
724                     for(; val != 0; val <<= 1) {
725                         *addr  = val;
726                         *dummy  = ~val; /* clear the test data off of the bus */
727                         readback = *addr;
728                         if(readback != val) {
729                              printf ("FAILURE (data line): "
730                                 "expected %08lx, actual %08lx\n",
731                                           val, readback);
732                         }
733                         *addr  = ~val;
734                         *dummy  = val;
735                         readback = *addr;
736                         if(readback != ~val) {
737                             printf ("FAILURE (data line): "
738                                 "Is %08lx, should be %08lx\n",
739                                         readback, ~val);
740                         }
741                     }
742                 }
743
744                 /*
745                  * Based on code whose Original Author and Copyright
746                  * information follows: Copyright (c) 1998 by Michael
747                  * Barr. This software is placed into the public
748                  * domain and may be used for any purpose. However,
749                  * this notice must not be changed or removed and no
750                  * warranty is either expressed or implied by its
751                  * publication or distribution.
752                  */
753
754                 /*
755                  * Address line test
756                  *
757                  * Description: Test the address bus wiring in a
758                  *              memory region by performing a walking
759                  *              1's test on the relevant bits of the
760                  *              address and checking for aliasing.
761                  *              This test will find single-bit
762                  *              address failures such as stuck -high,
763                  *              stuck-low, and shorted pins. The base
764                  *              address and size of the region are
765                  *              selected by the caller.
766                  *
767                  * Notes:       For best results, the selected base
768                  *              address should have enough LSB 0's to
769                  *              guarantee single address bit changes.
770                  *              For example, to test a 64-Kbyte
771                  *              region, select a base address on a
772                  *              64-Kbyte boundary. Also, select the
773                  *              region size as a power-of-two if at
774                  *              all possible.
775                  *
776                  * Returns:     0 if the test succeeds, 1 if the test fails.
777                  *
778                  * ## NOTE ##   Be sure to specify start and end
779                  *              addresses such that addr_mask has
780                  *              lots of bits set. For example an
781                  *              address range of 01000000 02000000 is
782                  *              bad while a range of 01000000
783                  *              01ffffff is perfect.
784                  */
785                 addr_mask = ((ulong)end - (ulong)start)/sizeof(vu_long);
786                 pattern = (vu_long) 0xaaaaaaaa;
787                 anti_pattern = (vu_long) 0x55555555;
788
789                 PRINTF("%s:%d: addr mask = 0x%.8lx\n",
790                         __FUNCTION__, __LINE__,
791                         addr_mask);
792                 /*
793                  * Write the default pattern at each of the
794                  * power-of-two offsets.
795                  */
796                 for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
797                         start[offset] = pattern;
798                 }
799
800                 /*
801                  * Check for address bits stuck high.
802                  */
803                 test_offset = 0;
804                 start[test_offset] = anti_pattern;
805
806                 for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
807                     temp = start[offset];
808                     if (temp != pattern) {
809                         printf ("\nFAILURE: Address bit stuck high @ 0x%.8lx:"
810                                 " expected 0x%.8lx, actual 0x%.8lx\n",
811                                 (ulong)&start[offset], pattern, temp);
812                         return 1;
813                     }
814                 }
815                 start[test_offset] = pattern;
816
817                 /*
818                  * Check for addr bits stuck low or shorted.
819                  */
820                 for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) {
821                     start[test_offset] = anti_pattern;
822
823                     for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
824                         temp = start[offset];
825                         if ((temp != pattern) && (offset != test_offset)) {
826                             printf ("\nFAILURE: Address bit stuck low or shorted @"
827                                 " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n",
828                                 (ulong)&start[offset], pattern, temp);
829                             return 1;
830                         }
831                     }
832                     start[test_offset] = pattern;
833                 }
834
835                 /*
836                  * Description: Test the integrity of a physical
837                  *              memory device by performing an
838                  *              increment/decrement test over the
839                  *              entire region. In the process every
840                  *              storage bit in the device is tested
841                  *              as a zero and a one. The base address
842                  *              and the size of the region are
843                  *              selected by the caller.
844                  *
845                  * Returns:     0 if the test succeeds, 1 if the test fails.
846                  */
847                 num_words = ((ulong)end - (ulong)start)/sizeof(vu_long) + 1;
848
849                 /*
850                  * Fill memory with a known pattern.
851                  */
852                 for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
853                         start[offset] = pattern;
854                 }
855
856                 /*
857                  * Check each location and invert it for the second pass.
858                  */
859                 for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
860                     temp = start[offset];
861                     if (temp != pattern) {
862                         printf ("\nFAILURE (read/write) @ 0x%.8lx:"
863                                 " expected 0x%.8lx, actual 0x%.8lx)\n",
864                                 (ulong)&start[offset], pattern, temp);
865                         return 1;
866                     }
867
868                     anti_pattern = ~pattern;
869                     start[offset] = anti_pattern;
870                 }
871
872                 /*
873                  * Check each location for the inverted pattern and zero it.
874                  */
875                 for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
876                     anti_pattern = ~pattern;
877                     temp = start[offset];
878                     if (temp != anti_pattern) {
879                         printf ("\nFAILURE (read/write): @ 0x%.8lx:"
880                                 " expected 0x%.8lx, actual 0x%.8lx)\n",
881                                 (ulong)&start[offset], anti_pattern, temp);
882                         return 1;
883                     }
884                     start[offset] = 0;
885                 }
886         }
887
888 #else /* The original, quickie test */
889         incr = 1;
890         for (;;) {
891                 if (ctrlc()) {
892                         putc ('\n');
893                         return 1;
894                 }
895
896                 printf ("\rPattern %08lX  Writing..."
897                         "%12s"
898                         "\b\b\b\b\b\b\b\b\b\b",
899                         pattern, "");
900
901                 for (addr=start,val=pattern; addr<end; addr++) {
902                         *addr = val;
903                         val  += incr;
904                 }
905
906                 puts ("Reading...");
907
908                 for (addr=start,val=pattern; addr<end; addr++) {
909                         readback = *addr;
910                         if (readback != val) {
911                                 printf ("\nMem error @ 0x%08X: "
912                                         "found %08lX, expected %08lX\n",
913                                         (uint)addr, readback, val);
914                                 rcode = 1;
915                         }
916                         val += incr;
917                 }
918
919                 /*
920                  * Flip the pattern each time to make lots of zeros and
921                  * then, the next time, lots of ones.  We decrement
922                  * the "negative" patterns and increment the "positive"
923                  * patterns to preserve this feature.
924                  */
925                 if(pattern & 0x80000000) {
926                         pattern = -pattern;     /* complement & increment */
927                 }
928                 else {
929                         pattern = ~pattern;
930                 }
931                 incr = -incr;
932         }
933         return rcode;
934 #endif
935 }
936
937
938 /* Modify memory.
939  *
940  * Syntax:
941  *      mm{.b, .w, .l} {addr}
942  *      nm{.b, .w, .l} {addr}
943  */
944 static int
945 mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[])
946 {
947         ulong   addr, i;
948         int     nbytes, size;
949         extern char console_buffer[];
950
951         if (argc != 2) {
952                 printf ("Usage:\n%s\n", cmdtp->usage);
953                 return 1;
954         }
955
956 #ifdef CONFIG_BOOT_RETRY_TIME
957         reset_cmd_timeout();    /* got a good command to get here */
958 #endif
959         /* We use the last specified parameters, unless new ones are
960          * entered.
961          */
962         addr = mm_last_addr;
963         size = mm_last_size;
964
965         if ((flag & CMD_FLAG_REPEAT) == 0) {
966                 /* New command specified.  Check for a size specification.
967                  * Defaults to long if no or incorrect specification.
968                  */
969                 if ((size = cmd_get_data_size(argv[0], 4)) < 0)
970                         return 1;
971
972                 /* Address is specified since argc > 1
973                 */
974                 addr = simple_strtoul(argv[1], NULL, 16);
975                 addr += base_address;
976         }
977
978 #ifdef CONFIG_HAS_DATAFLASH
979         if (addr_dataflash(addr)){
980                 puts ("Can't modify DataFlash in place. Use cp instead.\n\r");
981                 return 0;
982         }
983 #endif
984
985         /* Print the address, followed by value.  Then accept input for
986          * the next value.  A non-converted value exits.
987          */
988         do {
989                 printf("%08lx:", addr);
990                 if (size == 4)
991                         printf(" %08x", *((uint   *)addr));
992                 else if (size == 2)
993                         printf(" %04x", *((ushort *)addr));
994                 else
995                         printf(" %02x", *((u_char *)addr));
996
997                 nbytes = readline (" ? ");
998                 if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
999                         /* <CR> pressed as only input, don't modify current
1000                          * location and move to next. "-" pressed will go back.
1001                          */
1002                         if (incrflag)
1003                                 addr += nbytes ? -size : size;
1004                         nbytes = 1;
1005 #ifdef CONFIG_BOOT_RETRY_TIME
1006                         reset_cmd_timeout(); /* good enough to not time out */
1007 #endif
1008                 }
1009 #ifdef CONFIG_BOOT_RETRY_TIME
1010                 else if (nbytes == -2) {
1011                         break;  /* timed out, exit the command  */
1012                 }
1013 #endif
1014                 else {
1015                         char *endp;
1016                         i = simple_strtoul(console_buffer, &endp, 16);
1017                         nbytes = endp - console_buffer;
1018                         if (nbytes) {
1019 #ifdef CONFIG_BOOT_RETRY_TIME
1020                                 /* good enough to not time out
1021                                  */
1022                                 reset_cmd_timeout();
1023 #endif
1024                                 if (size == 4)
1025                                         *((uint   *)addr) = i;
1026                                 else if (size == 2)
1027                                         *((ushort *)addr) = i;
1028                                 else
1029                                         *((u_char *)addr) = i;
1030                                 if (incrflag)
1031                                         addr += size;
1032                         }
1033                 }
1034         } while (nbytes);
1035
1036         mm_last_addr = addr;
1037         mm_last_size = size;
1038         return 0;
1039 }
1040
1041 #ifndef CONFIG_CRC32_VERIFY
1042
1043 int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1044 {
1045         ulong addr, length;
1046         ulong crc;
1047         ulong *ptr;
1048
1049         if (argc < 3) {
1050                 printf ("Usage:\n%s\n", cmdtp->usage);
1051                 return 1;
1052         }
1053
1054         addr = simple_strtoul (argv[1], NULL, 16);
1055         addr += base_address;
1056
1057         length = simple_strtoul (argv[2], NULL, 16);
1058
1059         crc = crc32 (0, (const uchar *) addr, length);
1060
1061         printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
1062                         addr, addr + length - 1, crc);
1063
1064         if (argc > 3) {
1065                 ptr = (ulong *) simple_strtoul (argv[3], NULL, 16);
1066                 *ptr = crc;
1067         }
1068
1069         return 0;
1070 }
1071
1072 #else   /* CONFIG_CRC32_VERIFY */
1073
1074 int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1075 {
1076         ulong addr, length;
1077         ulong crc;
1078         ulong *ptr;
1079         ulong vcrc;
1080         int verify;
1081         int ac;
1082         char **av;
1083
1084         if (argc < 3) {
1085   usage:
1086                 printf ("Usage:\n%s\n", cmdtp->usage);
1087                 return 1;
1088         }
1089
1090         av = argv + 1;
1091         ac = argc - 1;
1092         if (strcmp(*av, "-v") == 0) {
1093                 verify = 1;
1094                 av++;
1095                 ac--;
1096                 if (ac < 3)
1097                         goto usage;
1098         } else
1099                 verify = 0;
1100
1101         addr = simple_strtoul(*av++, NULL, 16);
1102         addr += base_address;
1103         length = simple_strtoul(*av++, NULL, 16);
1104
1105         crc = crc32(0, (const uchar *) addr, length);
1106
1107         if (!verify) {
1108                 printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
1109                                 addr, addr + length - 1, crc);
1110                 if (ac > 2) {
1111                         ptr = (ulong *) simple_strtoul (*av++, NULL, 16);
1112                         *ptr = crc;
1113                 }
1114         } else {
1115                 vcrc = simple_strtoul(*av++, NULL, 16);
1116                 if (vcrc != crc) {
1117                         printf ("CRC32 for %08lx ... %08lx ==> %08lx != %08lx ** ERROR **\n",
1118                                         addr, addr + length - 1, crc, vcrc);
1119                         return 1;
1120                 }
1121         }
1122
1123         return 0;
1124
1125 }
1126 #endif  /* CONFIG_CRC32_VERIFY */
1127
1128 /**************************************************/
1129 #if (CONFIG_COMMANDS & CFG_CMD_MEMORY)
1130 U_BOOT_CMD(
1131         md,     3,     1,      do_mem_md,
1132         "md      - memory display\n",
1133         "[.b, .w, .l] address [# of objects]\n    - memory display\n"
1134 );
1135
1136
1137 U_BOOT_CMD(
1138         mm,     2,      1,       do_mem_mm,
1139         "mm      - memory modify (auto-incrementing)\n",
1140         "[.b, .w, .l] address\n" "    - memory modify, auto increment address\n"
1141 );
1142
1143
1144 U_BOOT_CMD(
1145         nm,     2,          1,          do_mem_nm,
1146         "nm      - memory modify (constant address)\n",
1147         "[.b, .w, .l] address\n    - memory modify, read and keep address\n"
1148 );
1149
1150 U_BOOT_CMD(
1151         mw,    4,    1,     do_mem_mw,
1152         "mw      - memory write (fill)\n",
1153         "[.b, .w, .l] address value [count]\n    - write memory\n"
1154 );
1155
1156 U_BOOT_CMD(
1157         cp,    4,    1,    do_mem_cp,
1158         "cp      - memory copy\n",
1159         "[.b, .w, .l] source target count\n    - copy memory\n"
1160 );
1161
1162 U_BOOT_CMD(
1163         cmp,    4,     1,     do_mem_cmp,
1164         "cmp     - memory compare\n",
1165         "[.b, .w, .l] addr1 addr2 count\n    - compare memory\n"
1166 );
1167
1168 #ifndef CONFIG_CRC32_VERIFY
1169
1170 U_BOOT_CMD(
1171         crc32,    4,    1,     do_mem_crc,
1172         "crc32   - checksum calculation\n",
1173         "address count [addr]\n    - compute CRC32 checksum [save at addr]\n"
1174 );
1175
1176 #else   /* CONFIG_CRC32_VERIFY */
1177
1178 U_BOOT_CMD(
1179         crc32,    5,    1,     do_mem_crc,
1180         "crc32   - checksum calculation\n",
1181         "address count [addr]\n    - compute CRC32 checksum [save at addr]\n"
1182         "-v address count crc\n    - verify crc of memory area\n"
1183 );
1184
1185 #endif  /* CONFIG_CRC32_VERIFY */
1186
1187 U_BOOT_CMD(
1188         base,    2,    1,     do_mem_base,
1189         "base    - print or set address offset\n",
1190         "\n    - print address offset for memory commands\n"
1191         "base off\n    - set address offset for memory commands to 'off'\n"
1192 );
1193
1194 U_BOOT_CMD(
1195         loop,    3,    1,    do_mem_loop,
1196         "loop    - infinite loop on address range\n",
1197         "[.b, .w, .l] address number_of_objects\n"
1198         "    - loop on a set of addresses\n"
1199 );
1200
1201 #ifdef CONFIG_LOOPW
1202 U_BOOT_CMD(
1203         loopw,    4,    1,    do_mem_loopw,
1204         "loopw   - infinite write loop on address range\n",
1205         "[.b, .w, .l] address number_of_objects data_to_write\n"
1206         "    - loop on a set of addresses\n"
1207 );
1208 #endif /* CONFIG_LOOPW */
1209
1210 U_BOOT_CMD(
1211         mtest,    4,    1,     do_mem_mtest,
1212         "mtest   - simple RAM test\n",
1213         "[start [end [pattern]]]\n"
1214         "    - simple RAM read/write test\n"
1215 );
1216
1217 #endif
1218 #endif  /* CFG_CMD_MEMORY */