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