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