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