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