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