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