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