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