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