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