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