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