uboot/cmd/nand.c
<<
>>
Prefs
   1/*
   2 * Driver for NAND support, Rick Bronson
   3 * borrowed heavily from:
   4 * (c) 1999 Machine Vision Holdings, Inc.
   5 * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
   6 *
   7 * Ported 'dynenv' to 'nand env.oob' command
   8 * (C) 2010 Nanometrics, Inc.
   9 * 'dynenv' -- Dynamic environment offset in NAND OOB
  10 * (C) Copyright 2006-2007 OpenMoko, Inc.
  11 * Added 16-bit nand support
  12 * (C) 2004 Texas Instruments
  13 *
  14 * Copyright 2010, 2012 Freescale Semiconductor
  15 * The portions of this file whose copyright is held by Freescale and which
  16 * are not considered a derived work of GPL v2-only code may be distributed
  17 * and/or modified under the terms of the GNU General Public License as
  18 * published by the Free Software Foundation; either version 2 of the
  19 * License, or (at your option) any later version.
  20 */
  21
  22#include <common.h>
  23#include <linux/mtd/mtd.h>
  24#include <command.h>
  25#include <console.h>
  26#include <watchdog.h>
  27#include <malloc.h>
  28#include <asm/byteorder.h>
  29#include <jffs2/jffs2.h>
  30#include <nand.h>
  31
  32#if defined(CONFIG_CMD_MTDPARTS)
  33
  34/* partition handling routines */
  35int mtdparts_init(void);
  36int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
  37int find_dev_and_part(const char *id, struct mtd_device **dev,
  38                      u8 *part_num, struct part_info **part);
  39#endif
  40
  41static int nand_dump(struct mtd_info *mtd, ulong off, int only_oob,
  42                     int repeat)
  43{
  44        int i;
  45        u_char *datbuf, *oobbuf, *p;
  46        static loff_t last;
  47        int ret = 0;
  48
  49        if (repeat)
  50                off = last + mtd->writesize;
  51
  52        last = off;
  53
  54        datbuf = memalign(ARCH_DMA_MINALIGN, mtd->writesize);
  55        if (!datbuf) {
  56                puts("No memory for page buffer\n");
  57                return 1;
  58        }
  59
  60        oobbuf = memalign(ARCH_DMA_MINALIGN, mtd->oobsize);
  61        if (!oobbuf) {
  62                puts("No memory for page buffer\n");
  63                ret = 1;
  64                goto free_dat;
  65        }
  66        off &= ~(mtd->writesize - 1);
  67        loff_t addr = (loff_t) off;
  68        struct mtd_oob_ops ops;
  69        memset(&ops, 0, sizeof(ops));
  70        ops.datbuf = datbuf;
  71        ops.oobbuf = oobbuf;
  72        ops.len = mtd->writesize;
  73        ops.ooblen = mtd->oobsize;
  74        ops.mode = MTD_OPS_RAW;
  75        i = mtd_read_oob(mtd, addr, &ops);
  76        if (i < 0) {
  77                printf("Error (%d) reading page %08lx\n", i, off);
  78                ret = 1;
  79                goto free_all;
  80        }
  81        printf("Page %08lx dump:\n", off);
  82
  83        if (!only_oob) {
  84                i = mtd->writesize >> 4;
  85                p = datbuf;
  86
  87                while (i--) {
  88                        printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
  89                               "  %02x %02x %02x %02x %02x %02x %02x %02x\n",
  90                               p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  91                               p[8], p[9], p[10], p[11], p[12], p[13], p[14],
  92                               p[15]);
  93                        p += 16;
  94                }
  95        }
  96
  97        puts("OOB:\n");
  98        i = mtd->oobsize >> 3;
  99        p = oobbuf;
 100        while (i--) {
 101                printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
 102                       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
 103                p += 8;
 104        }
 105
 106free_all:
 107        free(oobbuf);
 108free_dat:
 109        free(datbuf);
 110
 111        return ret;
 112}
 113
 114/* ------------------------------------------------------------------------- */
 115
 116static int set_dev(int dev)
 117{
 118        struct mtd_info *mtd = get_nand_dev_by_index(dev);
 119
 120        if (!mtd)
 121                return -ENODEV;
 122
 123        if (nand_curr_device == dev)
 124                return 0;
 125
 126        printf("Device %d: %s", dev, mtd->name);
 127        puts("... is now current device\n");
 128        nand_curr_device = dev;
 129
 130#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
 131        board_nand_select_device(mtd_to_nand(mtd), dev);
 132#endif
 133
 134        return 0;
 135}
 136
 137#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
 138static void print_status(ulong start, ulong end, ulong erasesize, int status)
 139{
 140        /*
 141         * Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is
 142         * not the same as others.  Instead of bit 1 being lock, it is
 143         * #lock_tight. To make the driver support either format, ignore bit 1
 144         * and use only bit 0 and bit 2.
 145         */
 146        printf("%08lx - %08lx: %08lx blocks %s%s%s\n",
 147                start,
 148                end - 1,
 149                (end - start) / erasesize,
 150                ((status & NAND_LOCK_STATUS_TIGHT) ?  "TIGHT " : ""),
 151                (!(status & NAND_LOCK_STATUS_UNLOCK) ?  "LOCK " : ""),
 152                ((status & NAND_LOCK_STATUS_UNLOCK) ?  "UNLOCK " : ""));
 153}
 154
 155static void do_nand_status(struct mtd_info *mtd)
 156{
 157        ulong block_start = 0;
 158        ulong off;
 159        int last_status = -1;
 160
 161        struct nand_chip *nand_chip = mtd_to_nand(mtd);
 162        /* check the WP bit */
 163        nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
 164        printf("device is %swrite protected\n",
 165                (nand_chip->read_byte(mtd) & 0x80 ?
 166                 "NOT " : ""));
 167
 168        for (off = 0; off < mtd->size; off += mtd->erasesize) {
 169                int s = nand_get_lock_status(mtd, off);
 170
 171                /* print message only if status has changed */
 172                if (s != last_status && off != 0) {
 173                        print_status(block_start, off, mtd->erasesize,
 174                                        last_status);
 175                        block_start = off;
 176                }
 177                last_status = s;
 178        }
 179        /* Print the last block info */
 180        print_status(block_start, off, mtd->erasesize, last_status);
 181}
 182#endif
 183
 184#ifdef CONFIG_ENV_OFFSET_OOB
 185unsigned long nand_env_oob_offset;
 186
 187int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
 188{
 189        int ret;
 190        uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
 191        struct mtd_info *mtd = get_nand_dev_by_index(0);
 192        char *cmd = argv[1];
 193
 194        if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !mtd) {
 195                puts("no devices available\n");
 196                return 1;
 197        }
 198
 199        set_dev(0);
 200
 201        if (!strcmp(cmd, "get")) {
 202                ret = get_nand_env_oob(mtd, &nand_env_oob_offset);
 203                if (ret)
 204                        return 1;
 205
 206                printf("0x%08lx\n", nand_env_oob_offset);
 207        } else if (!strcmp(cmd, "set")) {
 208                loff_t addr;
 209                loff_t maxsize;
 210                struct mtd_oob_ops ops;
 211                int idx = 0;
 212
 213                if (argc < 3)
 214                        goto usage;
 215
 216                mtd = get_nand_dev_by_index(idx);
 217                /* We don't care about size, or maxsize. */
 218                if (mtd_arg_off(argv[2], &idx, &addr, &maxsize, &maxsize,
 219                                MTD_DEV_TYPE_NAND, mtd->size)) {
 220                        puts("Offset or partition name expected\n");
 221                        return 1;
 222                }
 223                if (set_dev(idx)) {
 224                        puts("Offset or partition name expected\n");
 225                        return 1;
 226                }
 227
 228                if (idx != 0) {
 229                        puts("Partition not on first NAND device\n");
 230                        return 1;
 231                }
 232
 233                if (mtd->oobavail < ENV_OFFSET_SIZE) {
 234                        printf("Insufficient available OOB bytes:\n"
 235                               "%d OOB bytes available but %d required for "
 236                               "env.oob support\n",
 237                               mtd->oobavail, ENV_OFFSET_SIZE);
 238                        return 1;
 239                }
 240
 241                if ((addr & (mtd->erasesize - 1)) != 0) {
 242                        printf("Environment offset must be block-aligned\n");
 243                        return 1;
 244                }
 245
 246                ops.datbuf = NULL;
 247                ops.mode = MTD_OOB_AUTO;
 248                ops.ooboffs = 0;
 249                ops.ooblen = ENV_OFFSET_SIZE;
 250                ops.oobbuf = (void *) oob_buf;
 251
 252                oob_buf[0] = ENV_OOB_MARKER;
 253                oob_buf[1] = addr / mtd->erasesize;
 254
 255                ret = mtd->write_oob(mtd, ENV_OFFSET_SIZE, &ops);
 256                if (ret) {
 257                        printf("Error writing OOB block 0\n");
 258                        return ret;
 259                }
 260
 261                ret = get_nand_env_oob(mtd, &nand_env_oob_offset);
 262                if (ret) {
 263                        printf("Error reading env offset in OOB\n");
 264                        return ret;
 265                }
 266
 267                if (addr != nand_env_oob_offset) {
 268                        printf("Verification of env offset in OOB failed: "
 269                               "0x%08llx expected but got 0x%08lx\n",
 270                               (unsigned long long)addr, nand_env_oob_offset);
 271                        return 1;
 272                }
 273        } else {
 274                goto usage;
 275        }
 276
 277        return ret;
 278
 279usage:
 280        return CMD_RET_USAGE;
 281}
 282
 283#endif
 284
 285static void nand_print_and_set_info(int idx)
 286{
 287        struct mtd_info *mtd;
 288        struct nand_chip *chip;
 289
 290        mtd = get_nand_dev_by_index(idx);
 291        if (!mtd)
 292                return;
 293
 294        chip = mtd_to_nand(mtd);
 295        printf("Device %d: ", idx);
 296        if (chip->numchips > 1)
 297                printf("%dx ", chip->numchips);
 298        printf("%s, sector size %u KiB\n",
 299               mtd->name, mtd->erasesize >> 10);
 300        printf("  Page size   %8d b\n", mtd->writesize);
 301        printf("  OOB size    %8d b\n", mtd->oobsize);
 302        printf("  Erase size  %8d b\n", mtd->erasesize);
 303        printf("  subpagesize %8d b\n", chip->subpagesize);
 304        printf("  options     0x%08x\n", chip->options);
 305        printf("  bbt options 0x%08x\n", chip->bbt_options);
 306
 307        /* Set geometry info */
 308        env_set_hex("nand_writesize", mtd->writesize);
 309        env_set_hex("nand_oobsize", mtd->oobsize);
 310        env_set_hex("nand_erasesize", mtd->erasesize);
 311}
 312
 313static int raw_access(struct mtd_info *mtd, ulong addr, loff_t off,
 314                      ulong count, int read, int no_verify)
 315{
 316        int ret = 0;
 317
 318        while (count--) {
 319                /* Raw access */
 320                mtd_oob_ops_t ops = {
 321                        .datbuf = (u8 *)addr,
 322                        .oobbuf = ((u8 *)addr) + mtd->writesize,
 323                        .len = mtd->writesize,
 324                        .ooblen = mtd->oobsize,
 325                        .mode = MTD_OPS_RAW
 326                };
 327
 328                if (read) {
 329                        ret = mtd_read_oob(mtd, off, &ops);
 330                } else {
 331                        ret = mtd_write_oob(mtd, off, &ops);
 332                        if (!ret && !no_verify)
 333                                ret = nand_verify_page_oob(mtd, &ops, off);
 334                }
 335
 336                if (ret) {
 337                        printf("%s: error at offset %llx, ret %d\n",
 338                                __func__, (long long)off, ret);
 339                        break;
 340                }
 341
 342                addr += mtd->writesize + mtd->oobsize;
 343                off += mtd->writesize;
 344        }
 345
 346        return ret;
 347}
 348
 349/* Adjust a chip/partition size down for bad blocks so we don't
 350 * read/write past the end of a chip/partition by accident.
 351 */
 352static void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
 353{
 354        /* We grab the nand info object here fresh because this is usually
 355         * called after arg_off_size() which can change the value of dev.
 356         */
 357        struct mtd_info *mtd = get_nand_dev_by_index(dev);
 358        loff_t maxoffset = offset + *size;
 359        int badblocks = 0;
 360
 361        /* count badblocks in NAND from offset to offset + size */
 362        for (; offset < maxoffset; offset += mtd->erasesize) {
 363                if (nand_block_isbad(mtd, offset))
 364                        badblocks++;
 365        }
 366        /* adjust size if any bad blocks found */
 367        if (badblocks) {
 368                *size -= badblocks * mtd->erasesize;
 369                printf("size adjusted to 0x%llx (%d bad blocks)\n",
 370                       (unsigned long long)*size, badblocks);
 371        }
 372}
 373
 374static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 375{
 376        int i, ret = 0;
 377        ulong addr;
 378        loff_t off, size, maxsize;
 379        char *cmd, *s;
 380        struct mtd_info *mtd;
 381#ifdef CONFIG_SYS_NAND_QUIET
 382        int quiet = CONFIG_SYS_NAND_QUIET;
 383#else
 384        int quiet = 0;
 385#endif
 386        const char *quiet_str = env_get("quiet");
 387        int dev = nand_curr_device;
 388        int repeat = flag & CMD_FLAG_REPEAT;
 389
 390        /* at least two arguments please */
 391        if (argc < 2)
 392                goto usage;
 393
 394        if (quiet_str)
 395                quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
 396
 397        cmd = argv[1];
 398
 399        /* Only "dump" is repeatable. */
 400        if (repeat && strcmp(cmd, "dump"))
 401                return 0;
 402
 403        if (strcmp(cmd, "info") == 0) {
 404
 405                putc('\n');
 406                for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
 407                        nand_print_and_set_info(i);
 408                return 0;
 409        }
 410
 411        if (strcmp(cmd, "device") == 0) {
 412                if (argc < 3) {
 413                        putc('\n');
 414                        if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
 415                                puts("no devices available\n");
 416                        else
 417                                nand_print_and_set_info(dev);
 418                        return 0;
 419                }
 420
 421                dev = (int)simple_strtoul(argv[2], NULL, 10);
 422                set_dev(dev);
 423
 424                return 0;
 425        }
 426
 427#ifdef CONFIG_ENV_OFFSET_OOB
 428        /* this command operates only on the first nand device */
 429        if (strcmp(cmd, "env.oob") == 0)
 430                return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
 431#endif
 432
 433        /* The following commands operate on the current device, unless
 434         * overridden by a partition specifier.  Note that if somehow the
 435         * current device is invalid, it will have to be changed to a valid
 436         * one before these commands can run, even if a partition specifier
 437         * for another device is to be used.
 438         */
 439        mtd = get_nand_dev_by_index(dev);
 440        if (!mtd) {
 441                puts("\nno devices available\n");
 442                return 1;
 443        }
 444
 445        if (strcmp(cmd, "bad") == 0) {
 446                printf("\nDevice %d bad blocks:\n", dev);
 447                for (off = 0; off < mtd->size; off += mtd->erasesize)
 448                        if (nand_block_isbad(mtd, off))
 449                                printf("  %08llx\n", (unsigned long long)off);
 450                return 0;
 451        }
 452
 453        /*
 454         * Syntax is:
 455         *   0    1     2       3    4
 456         *   nand erase [clean] [off size]
 457         */
 458        if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
 459                nand_erase_options_t opts;
 460                /* "clean" at index 2 means request to write cleanmarker */
 461                int clean = argc > 2 && !strcmp("clean", argv[2]);
 462                int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
 463                int o = (clean || scrub_yes) ? 3 : 2;
 464                int scrub = !strncmp(cmd, "scrub", 5);
 465                int spread = 0;
 466                int args = 2;
 467                const char *scrub_warn =
 468                        "Warning: "
 469                        "scrub option will erase all factory set bad blocks!\n"
 470                        "         "
 471                        "There is no reliable way to recover them.\n"
 472                        "         "
 473                        "Use this command only for testing purposes if you\n"
 474                        "         "
 475                        "are sure of what you are doing!\n"
 476                        "\nReally scrub this NAND flash? <y/N>\n";
 477
 478                if (cmd[5] != 0) {
 479                        if (!strcmp(&cmd[5], ".spread")) {
 480                                spread = 1;
 481                        } else if (!strcmp(&cmd[5], ".part")) {
 482                                args = 1;
 483                        } else if (!strcmp(&cmd[5], ".chip")) {
 484                                args = 0;
 485                        } else {
 486                                goto usage;
 487                        }
 488                }
 489
 490                /*
 491                 * Don't allow missing arguments to cause full chip/partition
 492                 * erases -- easy to do accidentally, e.g. with a misspelled
 493                 * variable name.
 494                 */
 495                if (argc != o + args)
 496                        goto usage;
 497
 498                printf("\nNAND %s: ", cmd);
 499                /* skip first two or three arguments, look for offset and size */
 500                if (mtd_arg_off_size(argc - o, argv + o, &dev, &off, &size,
 501                                     &maxsize, MTD_DEV_TYPE_NAND,
 502                                     mtd->size) != 0)
 503                        return 1;
 504
 505                if (set_dev(dev))
 506                        return 1;
 507
 508                mtd = get_nand_dev_by_index(dev);
 509
 510                memset(&opts, 0, sizeof(opts));
 511                opts.offset = off;
 512                opts.length = size;
 513                opts.jffs2  = clean;
 514                opts.quiet  = quiet;
 515                opts.spread = spread;
 516
 517                if (scrub) {
 518                        if (scrub_yes) {
 519                                opts.scrub = 1;
 520                        } else {
 521                                puts(scrub_warn);
 522                                if (confirm_yesno()) {
 523                                        opts.scrub = 1;
 524                                } else {
 525                                        puts("scrub aborted\n");
 526                                        return 1;
 527                                }
 528                        }
 529                }
 530                ret = nand_erase_opts(mtd, &opts);
 531                printf("%s\n", ret ? "ERROR" : "OK");
 532
 533                return ret == 0 ? 0 : 1;
 534        }
 535
 536        if (strncmp(cmd, "dump", 4) == 0) {
 537                if (argc < 3)
 538                        goto usage;
 539
 540                off = (int)simple_strtoul(argv[2], NULL, 16);
 541                ret = nand_dump(mtd, off, !strcmp(&cmd[4], ".oob"), repeat);
 542
 543                return ret == 0 ? 1 : 0;
 544        }
 545
 546        if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
 547                size_t rwsize;
 548                ulong pagecount = 1;
 549                int read;
 550                int raw = 0;
 551                int no_verify = 0;
 552
 553                if (argc < 4)
 554                        goto usage;
 555
 556                addr = (ulong)simple_strtoul(argv[2], NULL, 16);
 557
 558                read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
 559                printf("\nNAND %s: ", read ? "read" : "write");
 560
 561                s = strchr(cmd, '.');
 562
 563                if (s && !strncmp(s, ".raw", 4)) {
 564                        raw = 1;
 565
 566                        if (!strcmp(s, ".raw.noverify"))
 567                                no_verify = 1;
 568
 569                        if (mtd_arg_off(argv[3], &dev, &off, &size, &maxsize,
 570                                        MTD_DEV_TYPE_NAND,
 571                                        mtd->size))
 572                                return 1;
 573
 574                        if (set_dev(dev))
 575                                return 1;
 576
 577                        mtd = get_nand_dev_by_index(dev);
 578
 579                        if (argc > 4 && !str2long(argv[4], &pagecount)) {
 580                                printf("'%s' is not a number\n", argv[4]);
 581                                return 1;
 582                        }
 583
 584                        if (pagecount * mtd->writesize > size) {
 585                                puts("Size exceeds partition or device limit\n");
 586                                return -1;
 587                        }
 588
 589                        rwsize = pagecount * (mtd->writesize + mtd->oobsize);
 590                } else {
 591                        if (mtd_arg_off_size(argc - 3, argv + 3, &dev, &off,
 592                                             &size, &maxsize,
 593                                             MTD_DEV_TYPE_NAND,
 594                                             mtd->size) != 0)
 595                                return 1;
 596
 597                        if (set_dev(dev))
 598                                return 1;
 599
 600                        /* size is unspecified */
 601                        if (argc < 5)
 602                                adjust_size_for_badblocks(&size, off, dev);
 603                        rwsize = size;
 604                }
 605
 606                mtd = get_nand_dev_by_index(dev);
 607
 608                if (!s || !strcmp(s, ".jffs2") ||
 609                    !strcmp(s, ".e") || !strcmp(s, ".i")) {
 610                        if (read)
 611                                ret = nand_read_skip_bad(mtd, off, &rwsize,
 612                                                         NULL, maxsize,
 613                                                         (u_char *)addr);
 614                        else
 615                                ret = nand_write_skip_bad(mtd, off, &rwsize,
 616                                                          NULL, maxsize,
 617                                                          (u_char *)addr,
 618                                                          WITH_WR_VERIFY);
 619#ifdef CONFIG_CMD_NAND_TRIMFFS
 620                } else if (!strcmp(s, ".trimffs")) {
 621                        if (read) {
 622                                printf("Unknown nand command suffix '%s'\n", s);
 623                                return 1;
 624                        }
 625                        ret = nand_write_skip_bad(mtd, off, &rwsize, NULL,
 626                                                maxsize, (u_char *)addr,
 627                                                WITH_DROP_FFS | WITH_WR_VERIFY);
 628#endif
 629                } else if (!strcmp(s, ".oob")) {
 630                        /* out-of-band data */
 631                        mtd_oob_ops_t ops = {
 632                                .oobbuf = (u8 *)addr,
 633                                .ooblen = rwsize,
 634                                .mode = MTD_OPS_RAW
 635                        };
 636
 637                        if (read)
 638                                ret = mtd_read_oob(mtd, off, &ops);
 639                        else
 640                                ret = mtd_write_oob(mtd, off, &ops);
 641                } else if (raw) {
 642                        ret = raw_access(mtd, addr, off, pagecount, read,
 643                                         no_verify);
 644                } else {
 645                        printf("Unknown nand command suffix '%s'.\n", s);
 646                        return 1;
 647                }
 648
 649                printf(" %zu bytes %s: %s\n", rwsize,
 650                       read ? "read" : "written", ret ? "ERROR" : "OK");
 651
 652                return ret == 0 ? 0 : 1;
 653        }
 654
 655#ifdef CONFIG_CMD_NAND_TORTURE
 656        if (strcmp(cmd, "torture") == 0) {
 657                loff_t endoff;
 658                unsigned int failed = 0, passed = 0;
 659
 660                if (argc < 3)
 661                        goto usage;
 662
 663                if (!str2off(argv[2], &off)) {
 664                        puts("Offset is not a valid number\n");
 665                        return 1;
 666                }
 667
 668                size = mtd->erasesize;
 669                if (argc > 3) {
 670                        if (!str2off(argv[3], &size)) {
 671                                puts("Size is not a valid number\n");
 672                                return 1;
 673                        }
 674                }
 675
 676                endoff = off + size;
 677                if (endoff > mtd->size) {
 678                        puts("Arguments beyond end of NAND\n");
 679                        return 1;
 680                }
 681
 682                off = round_down(off, mtd->erasesize);
 683                endoff = round_up(endoff, mtd->erasesize);
 684                size = endoff - off;
 685                printf("\nNAND torture: device %d offset 0x%llx size 0x%llx (block size 0x%x)\n",
 686                       dev, off, size, mtd->erasesize);
 687                while (off < endoff) {
 688                        ret = nand_torture(mtd, off);
 689                        if (ret) {
 690                                failed++;
 691                                printf("  block at 0x%llx failed\n", off);
 692                        } else {
 693                                passed++;
 694                        }
 695                        off += mtd->erasesize;
 696                }
 697                printf(" Passed: %u, failed: %u\n", passed, failed);
 698                return failed != 0;
 699        }
 700#endif
 701
 702        if (strcmp(cmd, "markbad") == 0) {
 703                argc -= 2;
 704                argv += 2;
 705
 706                if (argc <= 0)
 707                        goto usage;
 708
 709                while (argc > 0) {
 710                        addr = simple_strtoul(*argv, NULL, 16);
 711
 712                        if (mtd_block_markbad(mtd, addr)) {
 713                                printf("block 0x%08lx NOT marked "
 714                                        "as bad! ERROR %d\n",
 715                                        addr, ret);
 716                                ret = 1;
 717                        } else {
 718                                printf("block 0x%08lx successfully "
 719                                        "marked as bad\n",
 720                                        addr);
 721                        }
 722                        --argc;
 723                        ++argv;
 724                }
 725                return ret;
 726        }
 727
 728        if (strcmp(cmd, "biterr") == 0) {
 729                /* todo */
 730                return 1;
 731        }
 732
 733#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
 734        if (strcmp(cmd, "lock") == 0) {
 735                int tight = 0;
 736                int status = 0;
 737                if (argc == 3) {
 738                        if (!strcmp("tight", argv[2]))
 739                                tight = 1;
 740                        if (!strcmp("status", argv[2]))
 741                                status = 1;
 742                }
 743                if (status) {
 744                        do_nand_status(mtd);
 745                } else {
 746                        if (!nand_lock(mtd, tight)) {
 747                                puts("NAND flash successfully locked\n");
 748                        } else {
 749                                puts("Error locking NAND flash\n");
 750                                return 1;
 751                        }
 752                }
 753                return 0;
 754        }
 755
 756        if (strncmp(cmd, "unlock", 5) == 0) {
 757                int allexcept = 0;
 758
 759                s = strchr(cmd, '.');
 760
 761                if (s && !strcmp(s, ".allexcept"))
 762                        allexcept = 1;
 763
 764                if (mtd_arg_off_size(argc - 2, argv + 2, &dev, &off, &size,
 765                                     &maxsize, MTD_DEV_TYPE_NAND,
 766                                     mtd->size) < 0)
 767                        return 1;
 768
 769                if (set_dev(dev))
 770                        return 1;
 771
 772                mtd = get_nand_dev_by_index(dev);
 773
 774                if (!nand_unlock(mtd, off, size, allexcept)) {
 775                        puts("NAND flash successfully unlocked\n");
 776                } else {
 777                        puts("Error unlocking NAND flash, "
 778                             "write and erase will probably fail\n");
 779                        return 1;
 780                }
 781                return 0;
 782        }
 783#endif
 784
 785usage:
 786        return CMD_RET_USAGE;
 787}
 788
 789#ifdef CONFIG_SYS_LONGHELP
 790static char nand_help_text[] =
 791        "info - show available NAND devices\n"
 792        "nand device [dev] - show or set current device\n"
 793        "nand read - addr off|partition size\n"
 794        "nand write - addr off|partition size\n"
 795        "    read/write 'size' bytes starting at offset 'off'\n"
 796        "    to/from memory address 'addr', skipping bad blocks.\n"
 797        "nand read.raw - addr off|partition [count]\n"
 798        "nand write.raw[.noverify] - addr off|partition [count]\n"
 799        "    Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"
 800#ifdef CONFIG_CMD_NAND_TRIMFFS
 801        "nand write.trimffs - addr off|partition size\n"
 802        "    write 'size' bytes starting at offset 'off' from memory address\n"
 803        "    'addr', skipping bad blocks and dropping any pages at the end\n"
 804        "    of eraseblocks that contain only 0xFF\n"
 805#endif
 806        "nand erase[.spread] [clean] off size - erase 'size' bytes "
 807        "from offset 'off'\n"
 808        "    With '.spread', erase enough for given file size, otherwise,\n"
 809        "    'size' includes skipped bad blocks.\n"
 810        "nand erase.part [clean] partition - erase entire mtd partition'\n"
 811        "nand erase.chip [clean] - erase entire chip'\n"
 812        "nand bad - show bad blocks\n"
 813        "nand dump[.oob] off - dump page\n"
 814#ifdef CONFIG_CMD_NAND_TORTURE
 815        "nand torture off - torture one block at offset\n"
 816        "nand torture off [size] - torture blocks from off to off+size\n"
 817#endif
 818        "nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
 819        "    really clean NAND erasing bad blocks (UNSAFE)\n"
 820        "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
 821        "nand biterr off - make a bit error at offset (UNSAFE)"
 822#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
 823        "\n"
 824        "nand lock [tight] [status]\n"
 825        "    bring nand to lock state or display locked pages\n"
 826        "nand unlock[.allexcept] [offset] [size] - unlock section"
 827#endif
 828#ifdef CONFIG_ENV_OFFSET_OOB
 829        "\n"
 830        "nand env.oob - environment offset in OOB of block 0 of"
 831        "    first device.\n"
 832        "nand env.oob set off|partition - set enviromnent offset\n"
 833        "nand env.oob get - get environment offset"
 834#endif
 835        "";
 836#endif
 837
 838U_BOOT_CMD(
 839        nand, CONFIG_SYS_MAXARGS, 1, do_nand,
 840        "NAND sub-system", nand_help_text
 841);
 842
 843static int nand_load_image(cmd_tbl_t *cmdtp, struct mtd_info *mtd,
 844                           ulong offset, ulong addr, char *cmd)
 845{
 846        int r;
 847        char *s;
 848        size_t cnt;
 849#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
 850        image_header_t *hdr;
 851#endif
 852#if defined(CONFIG_FIT)
 853        const void *fit_hdr = NULL;
 854#endif
 855
 856        s = strchr(cmd, '.');
 857        if (s != NULL &&
 858            (strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
 859                printf("Unknown nand load suffix '%s'\n", s);
 860                bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
 861                return 1;
 862        }
 863
 864        printf("\nLoading from %s, offset 0x%lx\n", mtd->name, offset);
 865
 866        cnt = mtd->writesize;
 867        r = nand_read_skip_bad(mtd, offset, &cnt, NULL, mtd->size,
 868                               (u_char *)addr);
 869        if (r) {
 870                puts("** Read error\n");
 871                bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ);
 872                return 1;
 873        }
 874        bootstage_mark(BOOTSTAGE_ID_NAND_HDR_READ);
 875
 876        switch (genimg_get_format ((void *)addr)) {
 877#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
 878        case IMAGE_FORMAT_LEGACY:
 879                hdr = (image_header_t *)addr;
 880
 881                bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
 882                image_print_contents (hdr);
 883
 884                cnt = image_get_image_size (hdr);
 885                break;
 886#endif
 887#if defined(CONFIG_FIT)
 888        case IMAGE_FORMAT_FIT:
 889                fit_hdr = (const void *)addr;
 890                puts ("Fit image detected...\n");
 891
 892                cnt = fit_get_size (fit_hdr);
 893                break;
 894#endif
 895        default:
 896                bootstage_error(BOOTSTAGE_ID_NAND_TYPE);
 897                puts ("** Unknown image type\n");
 898                return 1;
 899        }
 900        bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
 901
 902        r = nand_read_skip_bad(mtd, offset, &cnt, NULL, mtd->size,
 903                               (u_char *)addr);
 904        if (r) {
 905                puts("** Read error\n");
 906                bootstage_error(BOOTSTAGE_ID_NAND_READ);
 907                return 1;
 908        }
 909        bootstage_mark(BOOTSTAGE_ID_NAND_READ);
 910
 911#if defined(CONFIG_FIT)
 912        /* This cannot be done earlier, we need complete FIT image in RAM first */
 913        if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
 914                if (!fit_check_format (fit_hdr)) {
 915                        bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ);
 916                        puts ("** Bad FIT image format\n");
 917                        return 1;
 918                }
 919                bootstage_mark(BOOTSTAGE_ID_NAND_FIT_READ_OK);
 920                fit_print_contents (fit_hdr);
 921        }
 922#endif
 923
 924        /* Loading ok, update default load address */
 925
 926        load_addr = addr;
 927
 928        return bootm_maybe_autostart(cmdtp, cmd);
 929}
 930
 931static int do_nandboot(cmd_tbl_t *cmdtp, int flag, int argc,
 932                       char * const argv[])
 933{
 934        char *boot_device = NULL;
 935        int idx;
 936        ulong addr, offset = 0;
 937        struct mtd_info *mtd;
 938#if defined(CONFIG_CMD_MTDPARTS)
 939        struct mtd_device *dev;
 940        struct part_info *part;
 941        u8 pnum;
 942
 943        if (argc >= 2) {
 944                char *p = (argc == 2) ? argv[1] : argv[2];
 945                if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
 946                    (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
 947                        if (dev->id->type != MTD_DEV_TYPE_NAND) {
 948                                puts("Not a NAND device\n");
 949                                return 1;
 950                        }
 951                        if (argc > 3)
 952                                goto usage;
 953                        if (argc == 3)
 954                                addr = simple_strtoul(argv[1], NULL, 16);
 955                        else
 956                                addr = CONFIG_SYS_LOAD_ADDR;
 957
 958                        mtd = get_nand_dev_by_index(dev->id->num);
 959                        return nand_load_image(cmdtp, mtd, part->offset,
 960                                               addr, argv[0]);
 961                }
 962        }
 963#endif
 964
 965        bootstage_mark(BOOTSTAGE_ID_NAND_PART);
 966        switch (argc) {
 967        case 1:
 968                addr = CONFIG_SYS_LOAD_ADDR;
 969                boot_device = env_get("bootdevice");
 970                break;
 971        case 2:
 972                addr = simple_strtoul(argv[1], NULL, 16);
 973                boot_device = env_get("bootdevice");
 974                break;
 975        case 3:
 976                addr = simple_strtoul(argv[1], NULL, 16);
 977                boot_device = argv[2];
 978                break;
 979        case 4:
 980                addr = simple_strtoul(argv[1], NULL, 16);
 981                boot_device = argv[2];
 982                offset = simple_strtoul(argv[3], NULL, 16);
 983                break;
 984        default:
 985#if defined(CONFIG_CMD_MTDPARTS)
 986usage:
 987#endif
 988                bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
 989                return CMD_RET_USAGE;
 990        }
 991        bootstage_mark(BOOTSTAGE_ID_NAND_SUFFIX);
 992
 993        if (!boot_device) {
 994                puts("\n** No boot device **\n");
 995                bootstage_error(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
 996                return 1;
 997        }
 998        bootstage_mark(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
 999
1000        idx = simple_strtoul(boot_device, NULL, 16);
1001
1002        mtd = get_nand_dev_by_index(idx);
1003        if (!mtd) {
1004                printf("\n** Device %d not available\n", idx);
1005                bootstage_error(BOOTSTAGE_ID_NAND_AVAILABLE);
1006                return 1;
1007        }
1008        bootstage_mark(BOOTSTAGE_ID_NAND_AVAILABLE);
1009
1010        return nand_load_image(cmdtp, mtd, offset, addr, argv[0]);
1011}
1012
1013U_BOOT_CMD(nboot, 4, 1, do_nandboot,
1014        "boot from NAND device",
1015        "[partition] | [[[loadAddr] dev] offset]"
1016);
1017