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