uboot/cmd/mem.c
<<
>>
Prefs
   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
  27DECLARE_GLOBAL_DATA_PTR;
  28
  29#ifndef CONFIG_SYS_MEMTEST_SCRATCH
  30#define CONFIG_SYS_MEMTEST_SCRATCH 0
  31#endif
  32
  33static 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 */
  38static ulong    dp_last_addr, dp_last_size;
  39static ulong    dp_last_length = 0x40;
  40static ulong    mm_last_addr, mm_last_size;
  41
  42static  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
  50static 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
 100static 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}
 104static 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
 109static 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
 170static 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
 197static 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
 225static 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
 306static 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
 354static 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
 368static 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
 466static 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
 572static 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
 796static 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 */
 860static 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 */
 959static int
 960mod_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
1064static 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/**************************************************/
1089U_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
1100U_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
1111U_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
1121U_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
1131U_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
1141U_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
1155U_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
1163U_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
1181static 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
1190U_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
1197U_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
1208U_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
1220U_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
1228U_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
1238U_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
1250U_BOOT_CMD(
1251        meminfo,        3,      1,      do_mem_info,
1252        "display memory information",
1253        ""
1254);
1255#endif
1256