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