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