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