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>
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
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.
23 #include <bootstage.h>
25 #include <asm/cache.h>
26 #include <linux/mtd/mtd.h>
32 #include <asm/byteorder.h>
33 #include <jffs2/jffs2.h>
36 #include "legacy-mtd-utils.h"
38 #if defined(CONFIG_CMD_MTDPARTS)
40 /* partition handling routines */
41 int mtdparts_init(void);
42 int find_dev_and_part(const char *id, struct mtd_device **dev,
43 u8 *part_num, struct part_info **part);
46 static int nand_dump(struct mtd_info *mtd, ulong off, int only_oob,
50 u_char *datbuf, *oobbuf, *p;
55 off = last + mtd->writesize;
59 datbuf = memalign(ARCH_DMA_MINALIGN, mtd->writesize);
61 puts("No memory for page buffer\n");
65 oobbuf = memalign(ARCH_DMA_MINALIGN, mtd->oobsize);
67 puts("No memory for page buffer\n");
71 off &= ~(mtd->writesize - 1);
72 loff_t addr = (loff_t) off;
73 struct mtd_oob_ops ops;
74 memset(&ops, 0, sizeof(ops));
77 ops.len = mtd->writesize;
78 ops.ooblen = mtd->oobsize;
79 ops.mode = MTD_OPS_RAW;
80 i = mtd_read_oob(mtd, addr, &ops);
82 printf("Error (%d) reading page %08lx\n", i, off);
86 printf("Page %08lx dump:\n", off);
89 i = mtd->writesize >> 4;
93 printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
94 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
95 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
96 p[8], p[9], p[10], p[11], p[12], p[13], p[14],
103 i = mtd->oobsize >> 3;
106 printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
107 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
119 /* ------------------------------------------------------------------------- */
121 static int set_dev(int dev)
123 struct mtd_info *mtd = get_nand_dev_by_index(dev);
128 if (nand_curr_device == dev)
131 printf("Device %d: %s", dev, mtd->name);
132 puts("... is now current device\n");
133 nand_curr_device = dev;
135 #ifdef CONFIG_SYS_NAND_SELECT_DEVICE
136 board_nand_select_device(mtd_to_nand(mtd), dev);
142 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
143 static void print_status(ulong start, ulong end, ulong erasesize, int status)
146 * Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is
147 * not the same as others. Instead of bit 1 being lock, it is
148 * #lock_tight. To make the driver support either format, ignore bit 1
149 * and use only bit 0 and bit 2.
151 printf("%08lx - %08lx: %08lx blocks %s%s%s\n",
154 (end - start) / erasesize,
155 ((status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
156 (!(status & NAND_LOCK_STATUS_UNLOCK) ? "LOCK " : ""),
157 ((status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
160 static void do_nand_status(struct mtd_info *mtd)
162 ulong block_start = 0;
164 int last_status = -1;
166 struct nand_chip *nand_chip = mtd_to_nand(mtd);
167 /* check the WP bit */
168 nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
169 printf("device is %swrite protected\n",
170 (nand_chip->read_byte(mtd) & 0x80 ?
173 for (off = 0; off < mtd->size; off += mtd->erasesize) {
174 int s = nand_get_lock_status(mtd, off);
176 /* print message only if status has changed */
177 if (s != last_status && off != 0) {
178 print_status(block_start, off, mtd->erasesize,
184 /* Print the last block info */
185 print_status(block_start, off, mtd->erasesize, last_status);
189 #ifdef CONFIG_ENV_OFFSET_OOB
190 unsigned long nand_env_oob_offset;
192 int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
195 uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
196 struct mtd_info *mtd = get_nand_dev_by_index(0);
199 if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !mtd) {
200 puts("no devices available\n");
206 if (!strcmp(cmd, "get")) {
207 ret = get_nand_env_oob(mtd, &nand_env_oob_offset);
211 printf("0x%08lx\n", nand_env_oob_offset);
212 } else if (!strcmp(cmd, "set")) {
215 struct mtd_oob_ops ops;
221 mtd = get_nand_dev_by_index(idx);
222 /* We don't care about size, or maxsize. */
223 if (mtd_arg_off(argv[2], &idx, &addr, &maxsize, &maxsize,
224 MTD_DEV_TYPE_NAND, mtd->size)) {
225 puts("Offset or partition name expected\n");
229 puts("Offset or partition name expected\n");
234 puts("Partition not on first NAND device\n");
238 if (mtd->oobavail < ENV_OFFSET_SIZE) {
239 printf("Insufficient available OOB bytes:\n"
240 "%d OOB bytes available but %d required for "
242 mtd->oobavail, ENV_OFFSET_SIZE);
246 if ((addr & (mtd->erasesize - 1)) != 0) {
247 printf("Environment offset must be block-aligned\n");
252 ops.mode = MTD_OOB_AUTO;
254 ops.ooblen = ENV_OFFSET_SIZE;
255 ops.oobbuf = (void *) oob_buf;
257 oob_buf[0] = ENV_OOB_MARKER;
258 oob_buf[1] = addr / mtd->erasesize;
260 ret = mtd->write_oob(mtd, ENV_OFFSET_SIZE, &ops);
262 printf("Error writing OOB block 0\n");
266 ret = get_nand_env_oob(mtd, &nand_env_oob_offset);
268 printf("Error reading env offset in OOB\n");
272 if (addr != nand_env_oob_offset) {
273 printf("Verification of env offset in OOB failed: "
274 "0x%08llx expected but got 0x%08lx\n",
275 (unsigned long long)addr, nand_env_oob_offset);
285 return CMD_RET_USAGE;
290 static void nand_print_and_set_info(int idx)
292 struct mtd_info *mtd;
293 struct nand_chip *chip;
295 mtd = get_nand_dev_by_index(idx);
299 chip = mtd_to_nand(mtd);
300 printf("Device %d: ", idx);
301 if (chip->numchips > 1)
302 printf("%dx ", chip->numchips);
303 printf("%s, sector size %u KiB\n",
304 mtd->name, mtd->erasesize >> 10);
305 printf(" Page size %8d b\n", mtd->writesize);
306 printf(" OOB size %8d b\n", mtd->oobsize);
307 printf(" Erase size %8d b\n", mtd->erasesize);
308 printf(" subpagesize %8d b\n", chip->subpagesize);
309 printf(" options 0x%08x\n", chip->options);
310 printf(" bbt options 0x%08x\n", chip->bbt_options);
312 /* Set geometry info */
313 env_set_hex("nand_writesize", mtd->writesize);
314 env_set_hex("nand_oobsize", mtd->oobsize);
315 env_set_hex("nand_erasesize", mtd->erasesize);
318 static int raw_access(struct mtd_info *mtd, ulong addr, loff_t off,
319 ulong count, int read, int no_verify)
325 mtd_oob_ops_t ops = {
326 .datbuf = (u8 *)addr,
327 .oobbuf = ((u8 *)addr) + mtd->writesize,
328 .len = mtd->writesize,
329 .ooblen = mtd->oobsize,
334 ret = mtd_read_oob(mtd, off, &ops);
336 ret = mtd_write_oob(mtd, off, &ops);
337 if (!ret && !no_verify)
338 ret = nand_verify_page_oob(mtd, &ops, off);
342 printf("%s: error at offset %llx, ret %d\n",
343 __func__, (long long)off, ret);
347 addr += mtd->writesize + mtd->oobsize;
348 off += mtd->writesize;
354 /* Adjust a chip/partition size down for bad blocks so we don't
355 * read/write past the end of a chip/partition by accident.
357 static void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
359 /* We grab the nand info object here fresh because this is usually
360 * called after arg_off_size() which can change the value of dev.
362 struct mtd_info *mtd = get_nand_dev_by_index(dev);
363 loff_t maxoffset = offset + *size;
366 /* count badblocks in NAND from offset to offset + size */
367 for (; offset < maxoffset; offset += mtd->erasesize) {
368 if (nand_block_isbad(mtd, offset))
371 /* adjust size if any bad blocks found */
373 *size -= badblocks * mtd->erasesize;
374 printf("size adjusted to 0x%llx (%d bad blocks)\n",
375 (unsigned long long)*size, badblocks);
379 static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
383 loff_t off, size, maxsize;
385 struct mtd_info *mtd;
386 #ifdef CONFIG_SYS_NAND_QUIET
387 int quiet = CONFIG_SYS_NAND_QUIET;
391 const char *quiet_str = env_get("quiet");
392 int dev = nand_curr_device;
393 int repeat = flag & CMD_FLAG_REPEAT;
395 /* at least two arguments please */
400 quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
404 /* Only "dump" is repeatable. */
405 if (repeat && strcmp(cmd, "dump"))
408 if (strcmp(cmd, "info") == 0) {
411 for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
412 nand_print_and_set_info(i);
416 if (strcmp(cmd, "device") == 0) {
419 if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
420 puts("no devices available\n");
422 nand_print_and_set_info(dev);
426 dev = (int)simple_strtoul(argv[2], NULL, 10);
432 #ifdef CONFIG_ENV_OFFSET_OOB
433 /* this command operates only on the first nand device */
434 if (strcmp(cmd, "env.oob") == 0)
435 return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
438 /* The following commands operate on the current device, unless
439 * overridden by a partition specifier. Note that if somehow the
440 * current device is invalid, it will have to be changed to a valid
441 * one before these commands can run, even if a partition specifier
442 * for another device is to be used.
444 mtd = get_nand_dev_by_index(dev);
446 puts("\nno devices available\n");
450 if (strcmp(cmd, "bad") == 0) {
451 printf("\nDevice %d bad blocks:\n", dev);
452 for (off = 0; off < mtd->size; off += mtd->erasesize)
453 if (nand_block_isbad(mtd, off))
454 printf(" %08llx\n", (unsigned long long)off);
461 * nand erase [clean] [off size]
463 if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
464 nand_erase_options_t opts;
465 /* "clean" at index 2 means request to write cleanmarker */
466 int clean = argc > 2 && !strcmp("clean", argv[2]);
467 int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
468 int o = (clean || scrub_yes) ? 3 : 2;
469 int scrub = !strncmp(cmd, "scrub", 5);
472 const char *scrub_warn =
474 "scrub option will erase all factory set bad blocks!\n"
476 "There is no reliable way to recover them.\n"
478 "Use this command only for testing purposes if you\n"
480 "are sure of what you are doing!\n"
481 "\nReally scrub this NAND flash? <y/N>\n";
484 if (!strcmp(&cmd[5], ".spread")) {
486 } else if (!strcmp(&cmd[5], ".part")) {
488 } else if (!strcmp(&cmd[5], ".chip")) {
496 * Don't allow missing arguments to cause full chip/partition
497 * erases -- easy to do accidentally, e.g. with a misspelled
500 if (argc != o + args)
503 printf("\nNAND %s: ", cmd);
504 /* skip first two or three arguments, look for offset and size */
505 if (mtd_arg_off_size(argc - o, argv + o, &dev, &off, &size,
506 &maxsize, MTD_DEV_TYPE_NAND,
513 mtd = get_nand_dev_by_index(dev);
515 memset(&opts, 0, sizeof(opts));
520 opts.spread = spread;
527 if (confirm_yesno()) {
530 puts("scrub aborted\n");
535 ret = nand_erase_opts(mtd, &opts);
536 printf("%s\n", ret ? "ERROR" : "OK");
538 return ret == 0 ? 0 : 1;
541 if (strncmp(cmd, "dump", 4) == 0) {
545 off = (int)simple_strtoul(argv[2], NULL, 16);
546 ret = nand_dump(mtd, off, !strcmp(&cmd[4], ".oob"), repeat);
548 return ret == 0 ? 1 : 0;
551 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
561 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
563 read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
564 printf("\nNAND %s: ", read ? "read" : "write");
566 s = strchr(cmd, '.');
568 if (s && !strncmp(s, ".raw", 4)) {
571 if (!strcmp(s, ".raw.noverify"))
574 if (mtd_arg_off(argv[3], &dev, &off, &size, &maxsize,
582 mtd = get_nand_dev_by_index(dev);
584 if (argc > 4 && !str2long(argv[4], &pagecount)) {
585 printf("'%s' is not a number\n", argv[4]);
589 if (pagecount * mtd->writesize > size) {
590 puts("Size exceeds partition or device limit\n");
594 rwsize = pagecount * (mtd->writesize + mtd->oobsize);
596 if (mtd_arg_off_size(argc - 3, argv + 3, &dev, &off,
605 /* size is unspecified */
607 adjust_size_for_badblocks(&size, off, dev);
611 mtd = get_nand_dev_by_index(dev);
613 if (!s || !strcmp(s, ".jffs2") ||
614 !strcmp(s, ".e") || !strcmp(s, ".i")) {
616 ret = nand_read_skip_bad(mtd, off, &rwsize,
620 ret = nand_write_skip_bad(mtd, off, &rwsize,
624 #ifdef CONFIG_CMD_NAND_TRIMFFS
625 } else if (!strcmp(s, ".trimffs")) {
627 printf("Unknown nand command suffix '%s'\n", s);
630 ret = nand_write_skip_bad(mtd, off, &rwsize, NULL,
631 maxsize, (u_char *)addr,
632 WITH_DROP_FFS | WITH_WR_VERIFY);
634 } else if (!strcmp(s, ".oob")) {
635 /* out-of-band data */
636 mtd_oob_ops_t ops = {
637 .oobbuf = (u8 *)addr,
643 ret = mtd_read_oob(mtd, off, &ops);
645 ret = mtd_write_oob(mtd, off, &ops);
647 ret = raw_access(mtd, addr, off, pagecount, read,
650 printf("Unknown nand command suffix '%s'.\n", s);
654 printf(" %zu bytes %s: %s\n", rwsize,
655 read ? "read" : "written", ret ? "ERROR" : "OK");
657 return ret == 0 ? 0 : 1;
660 #ifdef CONFIG_CMD_NAND_TORTURE
661 if (strcmp(cmd, "torture") == 0) {
663 unsigned int failed = 0, passed = 0;
668 if (!str2off(argv[2], &off)) {
669 puts("Offset is not a valid number\n");
673 size = mtd->erasesize;
675 if (!str2off(argv[3], &size)) {
676 puts("Size is not a valid number\n");
682 if (endoff > mtd->size) {
683 puts("Arguments beyond end of NAND\n");
687 off = round_down(off, mtd->erasesize);
688 endoff = round_up(endoff, mtd->erasesize);
690 printf("\nNAND torture: device %d offset 0x%llx size 0x%llx (block size 0x%x)\n",
691 dev, off, size, mtd->erasesize);
692 while (off < endoff) {
693 ret = nand_torture(mtd, off);
696 printf(" block at 0x%llx failed\n", off);
700 off += mtd->erasesize;
702 printf(" Passed: %u, failed: %u\n", passed, failed);
707 if (strcmp(cmd, "markbad") == 0) {
715 addr = simple_strtoul(*argv, NULL, 16);
717 if (mtd_block_markbad(mtd, addr)) {
718 printf("block 0x%08lx NOT marked "
719 "as bad! ERROR %d\n",
723 printf("block 0x%08lx successfully "
733 if (strcmp(cmd, "biterr") == 0) {
738 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
739 if (strcmp(cmd, "lock") == 0) {
743 if (!strcmp("tight", argv[2]))
745 if (!strcmp("status", argv[2]))
751 if (!nand_lock(mtd, tight)) {
752 puts("NAND flash successfully locked\n");
754 puts("Error locking NAND flash\n");
761 if (strncmp(cmd, "unlock", 5) == 0) {
764 s = strchr(cmd, '.');
766 if (s && !strcmp(s, ".allexcept"))
769 if (mtd_arg_off_size(argc - 2, argv + 2, &dev, &off, &size,
770 &maxsize, MTD_DEV_TYPE_NAND,
777 mtd = get_nand_dev_by_index(dev);
779 if (!nand_unlock(mtd, off, size, allexcept)) {
780 puts("NAND flash successfully unlocked\n");
782 puts("Error unlocking NAND flash, "
783 "write and erase will probably fail\n");
791 return CMD_RET_USAGE;
794 #ifdef CONFIG_SYS_LONGHELP
795 static char nand_help_text[] =
796 "info - show available NAND devices\n"
797 "nand device [dev] - show or set current device\n"
798 "nand read - addr off|partition size\n"
799 "nand write - addr off|partition size\n"
800 " read/write 'size' bytes starting at offset 'off'\n"
801 " to/from memory address 'addr', skipping bad blocks.\n"
802 "nand read.raw - addr off|partition [count]\n"
803 "nand write.raw[.noverify] - addr off|partition [count]\n"
804 " Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"
805 #ifdef CONFIG_CMD_NAND_TRIMFFS
806 "nand write.trimffs - addr off|partition size\n"
807 " write 'size' bytes starting at offset 'off' from memory address\n"
808 " 'addr', skipping bad blocks and dropping any pages at the end\n"
809 " of eraseblocks that contain only 0xFF\n"
811 "nand erase[.spread] [clean] off size - erase 'size' bytes "
812 "from offset 'off'\n"
813 " With '.spread', erase enough for given file size, otherwise,\n"
814 " 'size' includes skipped bad blocks.\n"
815 "nand erase.part [clean] partition - erase entire mtd partition'\n"
816 "nand erase.chip [clean] - erase entire chip'\n"
817 "nand bad - show bad blocks\n"
818 "nand dump[.oob] off - dump page\n"
819 #ifdef CONFIG_CMD_NAND_TORTURE
820 "nand torture off - torture one block at offset\n"
821 "nand torture off [size] - torture blocks from off to off+size\n"
823 "nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
824 " really clean NAND erasing bad blocks (UNSAFE)\n"
825 "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
826 "nand biterr off - make a bit error at offset (UNSAFE)"
827 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
829 "nand lock [tight] [status]\n"
830 " bring nand to lock state or display locked pages\n"
831 "nand unlock[.allexcept] [offset] [size] - unlock section"
833 #ifdef CONFIG_ENV_OFFSET_OOB
835 "nand env.oob - environment offset in OOB of block 0 of"
837 "nand env.oob set off|partition - set enviromnent offset\n"
838 "nand env.oob get - get environment offset"
844 nand, CONFIG_SYS_MAXARGS, 1, do_nand,
845 "NAND sub-system", nand_help_text
848 static int nand_load_image(cmd_tbl_t *cmdtp, struct mtd_info *mtd,
849 ulong offset, ulong addr, char *cmd)
854 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
857 #if defined(CONFIG_FIT)
858 const void *fit_hdr = NULL;
861 s = strchr(cmd, '.');
863 (strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
864 printf("Unknown nand load suffix '%s'\n", s);
865 bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
869 printf("\nLoading from %s, offset 0x%lx\n", mtd->name, offset);
871 cnt = mtd->writesize;
872 r = nand_read_skip_bad(mtd, offset, &cnt, NULL, mtd->size,
875 puts("** Read error\n");
876 bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ);
879 bootstage_mark(BOOTSTAGE_ID_NAND_HDR_READ);
881 switch (genimg_get_format ((void *)addr)) {
882 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
883 case IMAGE_FORMAT_LEGACY:
884 hdr = (image_header_t *)addr;
886 bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
887 image_print_contents (hdr);
889 cnt = image_get_image_size (hdr);
892 #if defined(CONFIG_FIT)
893 case IMAGE_FORMAT_FIT:
894 fit_hdr = (const void *)addr;
895 puts ("Fit image detected...\n");
897 cnt = fit_get_size (fit_hdr);
901 bootstage_error(BOOTSTAGE_ID_NAND_TYPE);
902 puts ("** Unknown image type\n");
905 bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
907 r = nand_read_skip_bad(mtd, offset, &cnt, NULL, mtd->size,
910 puts("** Read error\n");
911 bootstage_error(BOOTSTAGE_ID_NAND_READ);
914 bootstage_mark(BOOTSTAGE_ID_NAND_READ);
916 #if defined(CONFIG_FIT)
917 /* This cannot be done earlier, we need complete FIT image in RAM first */
918 if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
919 if (!fit_check_format (fit_hdr)) {
920 bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ);
921 puts ("** Bad FIT image format\n");
924 bootstage_mark(BOOTSTAGE_ID_NAND_FIT_READ_OK);
925 fit_print_contents (fit_hdr);
929 /* Loading ok, update default load address */
931 image_load_addr = addr;
933 return bootm_maybe_autostart(cmdtp, cmd);
936 static int do_nandboot(cmd_tbl_t *cmdtp, int flag, int argc,
939 char *boot_device = NULL;
941 ulong addr, offset = 0;
942 struct mtd_info *mtd;
943 #if defined(CONFIG_CMD_MTDPARTS)
944 struct mtd_device *dev;
945 struct part_info *part;
949 char *p = (argc == 2) ? argv[1] : argv[2];
950 if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
951 (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
952 if (dev->id->type != MTD_DEV_TYPE_NAND) {
953 puts("Not a NAND device\n");
959 addr = simple_strtoul(argv[1], NULL, 16);
961 addr = CONFIG_SYS_LOAD_ADDR;
963 mtd = get_nand_dev_by_index(dev->id->num);
964 return nand_load_image(cmdtp, mtd, part->offset,
970 bootstage_mark(BOOTSTAGE_ID_NAND_PART);
973 addr = CONFIG_SYS_LOAD_ADDR;
974 boot_device = env_get("bootdevice");
977 addr = simple_strtoul(argv[1], NULL, 16);
978 boot_device = env_get("bootdevice");
981 addr = simple_strtoul(argv[1], NULL, 16);
982 boot_device = argv[2];
985 addr = simple_strtoul(argv[1], NULL, 16);
986 boot_device = argv[2];
987 offset = simple_strtoul(argv[3], NULL, 16);
990 #if defined(CONFIG_CMD_MTDPARTS)
993 bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
994 return CMD_RET_USAGE;
996 bootstage_mark(BOOTSTAGE_ID_NAND_SUFFIX);
999 puts("\n** No boot device **\n");
1000 bootstage_error(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
1003 bootstage_mark(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
1005 idx = simple_strtoul(boot_device, NULL, 16);
1007 mtd = get_nand_dev_by_index(idx);
1009 printf("\n** Device %d not available\n", idx);
1010 bootstage_error(BOOTSTAGE_ID_NAND_AVAILABLE);
1013 bootstage_mark(BOOTSTAGE_ID_NAND_AVAILABLE);
1015 return nand_load_image(cmdtp, mtd, offset, addr, argv[0]);
1018 U_BOOT_CMD(nboot, 4, 1, do_nandboot,
1019 "boot from NAND device",
1020 "[partition] | [[[loadAddr] dev] offset]"