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