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 <linux/mtd/mtd.h>
28 #include <asm/byteorder.h>
29 #include <jffs2/jffs2.h>
32 #if defined(CONFIG_CMD_MTDPARTS)
34 /* partition handling routines */
35 int mtdparts_init(void);
36 int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
37 int find_dev_and_part(const char *id, struct mtd_device **dev,
38 u8 *part_num, struct part_info **part);
41 static int nand_dump(struct mtd_info *mtd, ulong off, int only_oob,
45 u_char *datbuf, *oobbuf, *p;
50 off = last + mtd->writesize;
54 datbuf = memalign(ARCH_DMA_MINALIGN, mtd->writesize);
56 puts("No memory for page buffer\n");
60 oobbuf = memalign(ARCH_DMA_MINALIGN, mtd->oobsize);
62 puts("No memory for page buffer\n");
66 off &= ~(mtd->writesize - 1);
67 loff_t addr = (loff_t) off;
68 struct mtd_oob_ops ops;
69 memset(&ops, 0, sizeof(ops));
72 ops.len = mtd->writesize;
73 ops.ooblen = mtd->oobsize;
74 ops.mode = MTD_OPS_RAW;
75 i = mtd_read_oob(mtd, addr, &ops);
77 printf("Error (%d) reading page %08lx\n", i, off);
81 printf("Page %08lx dump:\n", off);
84 i = mtd->writesize >> 4;
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],
98 i = mtd->oobsize >> 3;
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]);
114 /* ------------------------------------------------------------------------- */
116 static int set_dev(int dev)
118 if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev]) {
119 puts("No such device\n");
123 if (nand_curr_device == dev)
126 printf("Device %d: %s", dev, nand_info[dev]->name);
127 puts("... is now current device\n");
128 nand_curr_device = dev;
130 #ifdef CONFIG_SYS_NAND_SELECT_DEVICE
131 board_nand_select_device(nand_info[dev]->priv, dev);
137 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
138 static void print_status(ulong start, ulong end, ulong erasesize, int status)
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.
146 printf("%08lx - %08lx: %08lx blocks %s%s%s\n",
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 " : ""));
155 static void do_nand_status(struct mtd_info *mtd)
157 ulong block_start = 0;
159 int last_status = -1;
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 ?
168 for (off = 0; off < mtd->size; off += mtd->erasesize) {
169 int s = nand_get_lock_status(mtd, off);
171 /* print message only if status has changed */
172 if (s != last_status && off != 0) {
173 print_status(block_start, off, mtd->erasesize,
179 /* Print the last block info */
180 print_status(block_start, off, mtd->erasesize, last_status);
184 #ifdef CONFIG_ENV_OFFSET_OOB
185 unsigned long nand_env_oob_offset;
187 int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
190 uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
191 struct mtd_info *mtd = nand_info[0];
194 if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !mtd) {
195 puts("no devices available\n");
201 if (!strcmp(cmd, "get")) {
202 ret = get_nand_env_oob(mtd, &nand_env_oob_offset);
206 printf("0x%08lx\n", nand_env_oob_offset);
207 } else if (!strcmp(cmd, "set")) {
210 struct mtd_oob_ops ops;
216 /* We don't care about size, or maxsize. */
217 if (mtd_arg_off(argv[2], &idx, &addr, &maxsize, &maxsize,
218 MTD_DEV_TYPE_NAND, nand_info[idx]->size)) {
219 puts("Offset or partition name expected\n");
223 puts("Offset or partition name expected\n");
228 puts("Partition not on first NAND device\n");
232 if (mtd->oobavail < ENV_OFFSET_SIZE) {
233 printf("Insufficient available OOB bytes:\n"
234 "%d OOB bytes available but %d required for "
236 mtd->oobavail, ENV_OFFSET_SIZE);
240 if ((addr & (mtd->erasesize - 1)) != 0) {
241 printf("Environment offset must be block-aligned\n");
246 ops.mode = MTD_OOB_AUTO;
248 ops.ooblen = ENV_OFFSET_SIZE;
249 ops.oobbuf = (void *) oob_buf;
251 oob_buf[0] = ENV_OOB_MARKER;
252 oob_buf[1] = addr / mtd->erasesize;
254 ret = mtd->write_oob(mtd, ENV_OFFSET_SIZE, &ops);
256 printf("Error writing OOB block 0\n");
260 ret = get_nand_env_oob(mtd, &nand_env_oob_offset);
262 printf("Error reading env offset in OOB\n");
266 if (addr != nand_env_oob_offset) {
267 printf("Verification of env offset in OOB failed: "
268 "0x%08llx expected but got 0x%08lx\n",
269 (unsigned long long)addr, nand_env_oob_offset);
279 return CMD_RET_USAGE;
284 static void nand_print_and_set_info(int idx)
286 struct mtd_info *mtd = nand_info[idx];
287 struct nand_chip *chip = mtd_to_nand(mtd);
289 printf("Device %d: ", idx);
290 if (chip->numchips > 1)
291 printf("%dx ", chip->numchips);
292 printf("%s, sector size %u KiB\n",
293 mtd->name, mtd->erasesize >> 10);
294 printf(" Page size %8d b\n", mtd->writesize);
295 printf(" OOB size %8d b\n", mtd->oobsize);
296 printf(" Erase size %8d b\n", mtd->erasesize);
297 printf(" subpagesize %8d b\n", chip->subpagesize);
298 printf(" options 0x%8x\n", chip->options);
299 printf(" bbt options 0x%8x\n", chip->bbt_options);
301 /* Set geometry info */
302 setenv_hex("nand_writesize", mtd->writesize);
303 setenv_hex("nand_oobsize", mtd->oobsize);
304 setenv_hex("nand_erasesize", mtd->erasesize);
307 static int raw_access(struct mtd_info *mtd, ulong addr, loff_t off,
308 ulong count, int read, int no_verify)
314 mtd_oob_ops_t ops = {
315 .datbuf = (u8 *)addr,
316 .oobbuf = ((u8 *)addr) + mtd->writesize,
317 .len = mtd->writesize,
318 .ooblen = mtd->oobsize,
323 ret = mtd_read_oob(mtd, off, &ops);
325 ret = mtd_write_oob(mtd, off, &ops);
326 if (!ret && !no_verify)
327 ret = nand_verify_page_oob(mtd, &ops, off);
331 printf("%s: error at offset %llx, ret %d\n",
332 __func__, (long long)off, ret);
336 addr += mtd->writesize + mtd->oobsize;
337 off += mtd->writesize;
343 /* Adjust a chip/partition size down for bad blocks so we don't
344 * read/write past the end of a chip/partition by accident.
346 static void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
348 /* We grab the nand info object here fresh because this is usually
349 * called after arg_off_size() which can change the value of dev.
351 struct mtd_info *mtd = nand_info[dev];
352 loff_t maxoffset = offset + *size;
355 /* count badblocks in NAND from offset to offset + size */
356 for (; offset < maxoffset; offset += mtd->erasesize) {
357 if (nand_block_isbad(mtd, offset))
360 /* adjust size if any bad blocks found */
362 *size -= badblocks * mtd->erasesize;
363 printf("size adjusted to 0x%llx (%d bad blocks)\n",
364 (unsigned long long)*size, badblocks);
368 static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
372 loff_t off, size, maxsize;
374 struct mtd_info *mtd;
375 #ifdef CONFIG_SYS_NAND_QUIET
376 int quiet = CONFIG_SYS_NAND_QUIET;
380 const char *quiet_str = getenv("quiet");
381 int dev = nand_curr_device;
382 int repeat = flag & CMD_FLAG_REPEAT;
384 /* at least two arguments please */
389 quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
393 /* Only "dump" is repeatable. */
394 if (repeat && strcmp(cmd, "dump"))
397 if (strcmp(cmd, "info") == 0) {
400 for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
402 nand_print_and_set_info(i);
407 if (strcmp(cmd, "device") == 0) {
410 if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
411 puts("no devices available\n");
413 nand_print_and_set_info(dev);
417 dev = (int)simple_strtoul(argv[2], NULL, 10);
423 #ifdef CONFIG_ENV_OFFSET_OOB
424 /* this command operates only on the first nand device */
425 if (strcmp(cmd, "env.oob") == 0)
426 return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
429 /* The following commands operate on the current device, unless
430 * overridden by a partition specifier. Note that if somehow the
431 * current device is invalid, it will have to be changed to a valid
432 * one before these commands can run, even if a partition specifier
433 * for another device is to be used.
435 if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
437 puts("\nno devices available\n");
440 mtd = nand_info[dev];
442 if (strcmp(cmd, "bad") == 0) {
443 printf("\nDevice %d bad blocks:\n", dev);
444 for (off = 0; off < mtd->size; off += mtd->erasesize)
445 if (nand_block_isbad(mtd, off))
446 printf(" %08llx\n", (unsigned long long)off);
453 * nand erase [clean] [off size]
455 if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
456 nand_erase_options_t opts;
457 /* "clean" at index 2 means request to write cleanmarker */
458 int clean = argc > 2 && !strcmp("clean", argv[2]);
459 int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
460 int o = (clean || scrub_yes) ? 3 : 2;
461 int scrub = !strncmp(cmd, "scrub", 5);
464 const char *scrub_warn =
466 "scrub option will erase all factory set bad blocks!\n"
468 "There is no reliable way to recover them.\n"
470 "Use this command only for testing purposes if you\n"
472 "are sure of what you are doing!\n"
473 "\nReally scrub this NAND flash? <y/N>\n";
476 if (!strcmp(&cmd[5], ".spread")) {
478 } else if (!strcmp(&cmd[5], ".part")) {
480 } else if (!strcmp(&cmd[5], ".chip")) {
488 * Don't allow missing arguments to cause full chip/partition
489 * erases -- easy to do accidentally, e.g. with a misspelled
492 if (argc != o + args)
495 printf("\nNAND %s: ", cmd);
496 /* skip first two or three arguments, look for offset and size */
497 if (mtd_arg_off_size(argc - o, argv + o, &dev, &off, &size,
498 &maxsize, MTD_DEV_TYPE_NAND,
499 nand_info[dev]->size) != 0)
505 mtd = nand_info[dev];
507 memset(&opts, 0, sizeof(opts));
512 opts.spread = spread;
519 if (confirm_yesno()) {
522 puts("scrub aborted\n");
527 ret = nand_erase_opts(mtd, &opts);
528 printf("%s\n", ret ? "ERROR" : "OK");
530 return ret == 0 ? 0 : 1;
533 if (strncmp(cmd, "dump", 4) == 0) {
537 off = (int)simple_strtoul(argv[2], NULL, 16);
538 ret = nand_dump(mtd, off, !strcmp(&cmd[4], ".oob"), repeat);
540 return ret == 0 ? 1 : 0;
543 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
553 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
555 read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
556 printf("\nNAND %s: ", read ? "read" : "write");
558 s = strchr(cmd, '.');
560 if (s && !strncmp(s, ".raw", 4)) {
563 if (!strcmp(s, ".raw.noverify"))
566 if (mtd_arg_off(argv[3], &dev, &off, &size, &maxsize,
568 nand_info[dev]->size))
574 mtd = nand_info[dev];
576 if (argc > 4 && !str2long(argv[4], &pagecount)) {
577 printf("'%s' is not a number\n", argv[4]);
581 if (pagecount * mtd->writesize > size) {
582 puts("Size exceeds partition or device limit\n");
586 rwsize = pagecount * (mtd->writesize + mtd->oobsize);
588 if (mtd_arg_off_size(argc - 3, argv + 3, &dev, &off,
591 nand_info[dev]->size) != 0)
597 /* size is unspecified */
599 adjust_size_for_badblocks(&size, off, dev);
603 mtd = nand_info[dev];
605 if (!s || !strcmp(s, ".jffs2") ||
606 !strcmp(s, ".e") || !strcmp(s, ".i")) {
608 ret = nand_read_skip_bad(mtd, off, &rwsize,
612 ret = nand_write_skip_bad(mtd, off, &rwsize,
616 #ifdef CONFIG_CMD_NAND_TRIMFFS
617 } else if (!strcmp(s, ".trimffs")) {
619 printf("Unknown nand command suffix '%s'\n", s);
622 ret = nand_write_skip_bad(mtd, off, &rwsize, NULL,
623 maxsize, (u_char *)addr,
624 WITH_DROP_FFS | WITH_WR_VERIFY);
626 } else if (!strcmp(s, ".oob")) {
627 /* out-of-band data */
628 mtd_oob_ops_t ops = {
629 .oobbuf = (u8 *)addr,
635 ret = mtd_read_oob(mtd, off, &ops);
637 ret = mtd_write_oob(mtd, off, &ops);
639 ret = raw_access(mtd, addr, off, pagecount, read,
642 printf("Unknown nand command suffix '%s'.\n", s);
646 printf(" %zu bytes %s: %s\n", rwsize,
647 read ? "read" : "written", ret ? "ERROR" : "OK");
649 return ret == 0 ? 0 : 1;
652 #ifdef CONFIG_CMD_NAND_TORTURE
653 if (strcmp(cmd, "torture") == 0) {
655 unsigned int failed = 0, passed = 0;
660 if (!str2off(argv[2], &off)) {
661 puts("Offset is not a valid number\n");
665 size = mtd->erasesize;
667 if (!str2off(argv[3], &size)) {
668 puts("Size is not a valid number\n");
674 if (endoff > mtd->size) {
675 puts("Arguments beyond end of NAND\n");
679 off = round_down(off, mtd->erasesize);
680 endoff = round_up(endoff, mtd->erasesize);
682 printf("\nNAND torture: device %d offset 0x%llx size 0x%llx (block size 0x%x)\n",
683 dev, off, size, mtd->erasesize);
684 while (off < endoff) {
685 ret = nand_torture(mtd, off);
688 printf(" block at 0x%llx failed\n", off);
692 off += mtd->erasesize;
694 printf(" Passed: %u, failed: %u\n", passed, failed);
699 if (strcmp(cmd, "markbad") == 0) {
707 addr = simple_strtoul(*argv, NULL, 16);
709 if (mtd_block_markbad(mtd, addr)) {
710 printf("block 0x%08lx NOT marked "
711 "as bad! ERROR %d\n",
715 printf("block 0x%08lx successfully "
725 if (strcmp(cmd, "biterr") == 0) {
730 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
731 if (strcmp(cmd, "lock") == 0) {
735 if (!strcmp("tight", argv[2]))
737 if (!strcmp("status", argv[2]))
743 if (!nand_lock(mtd, tight)) {
744 puts("NAND flash successfully locked\n");
746 puts("Error locking NAND flash\n");
753 if (strncmp(cmd, "unlock", 5) == 0) {
756 s = strchr(cmd, '.');
758 if (s && !strcmp(s, ".allexcept"))
761 if (mtd_arg_off_size(argc - 2, argv + 2, &dev, &off, &size,
762 &maxsize, MTD_DEV_TYPE_NAND,
763 nand_info[dev]->size) < 0)
769 if (!nand_unlock(nand_info[dev], off, size, allexcept)) {
770 puts("NAND flash successfully unlocked\n");
772 puts("Error unlocking NAND flash, "
773 "write and erase will probably fail\n");
781 return CMD_RET_USAGE;
784 #ifdef CONFIG_SYS_LONGHELP
785 static char nand_help_text[] =
786 "info - show available NAND devices\n"
787 "nand device [dev] - show or set current device\n"
788 "nand read - addr off|partition size\n"
789 "nand write - addr off|partition size\n"
790 " read/write 'size' bytes starting at offset 'off'\n"
791 " to/from memory address 'addr', skipping bad blocks.\n"
792 "nand read.raw - addr off|partition [count]\n"
793 "nand write.raw[.noverify] - addr off|partition [count]\n"
794 " Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"
795 #ifdef CONFIG_CMD_NAND_TRIMFFS
796 "nand write.trimffs - addr off|partition size\n"
797 " write 'size' bytes starting at offset 'off' from memory address\n"
798 " 'addr', skipping bad blocks and dropping any pages at the end\n"
799 " of eraseblocks that contain only 0xFF\n"
801 "nand erase[.spread] [clean] off size - erase 'size' bytes "
802 "from offset 'off'\n"
803 " With '.spread', erase enough for given file size, otherwise,\n"
804 " 'size' includes skipped bad blocks.\n"
805 "nand erase.part [clean] partition - erase entire mtd partition'\n"
806 "nand erase.chip [clean] - erase entire chip'\n"
807 "nand bad - show bad blocks\n"
808 "nand dump[.oob] off - dump page\n"
809 #ifdef CONFIG_CMD_NAND_TORTURE
810 "nand torture off - torture one block at offset\n"
811 "nand torture off [size] - torture blocks from off to off+size\n"
813 "nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
814 " really clean NAND erasing bad blocks (UNSAFE)\n"
815 "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
816 "nand biterr off - make a bit error at offset (UNSAFE)"
817 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
819 "nand lock [tight] [status]\n"
820 " bring nand to lock state or display locked pages\n"
821 "nand unlock[.allexcept] [offset] [size] - unlock section"
823 #ifdef CONFIG_ENV_OFFSET_OOB
825 "nand env.oob - environment offset in OOB of block 0 of"
827 "nand env.oob set off|partition - set enviromnent offset\n"
828 "nand env.oob get - get environment offset"
834 nand, CONFIG_SYS_MAXARGS, 1, do_nand,
835 "NAND sub-system", nand_help_text
838 static int nand_load_image(cmd_tbl_t *cmdtp, struct mtd_info *mtd,
839 ulong offset, ulong addr, char *cmd)
844 #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
847 #if defined(CONFIG_FIT)
848 const void *fit_hdr = NULL;
851 s = strchr(cmd, '.');
853 (strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
854 printf("Unknown nand load suffix '%s'\n", s);
855 bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
859 printf("\nLoading from %s, offset 0x%lx\n", mtd->name, offset);
861 cnt = mtd->writesize;
862 r = nand_read_skip_bad(mtd, offset, &cnt, NULL, mtd->size,
865 puts("** Read error\n");
866 bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ);
869 bootstage_mark(BOOTSTAGE_ID_NAND_HDR_READ);
871 switch (genimg_get_format ((void *)addr)) {
872 #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
873 case IMAGE_FORMAT_LEGACY:
874 hdr = (image_header_t *)addr;
876 bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
877 image_print_contents (hdr);
879 cnt = image_get_image_size (hdr);
882 #if defined(CONFIG_FIT)
883 case IMAGE_FORMAT_FIT:
884 fit_hdr = (const void *)addr;
885 puts ("Fit image detected...\n");
887 cnt = fit_get_size (fit_hdr);
891 bootstage_error(BOOTSTAGE_ID_NAND_TYPE);
892 puts ("** Unknown image type\n");
895 bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
897 r = nand_read_skip_bad(mtd, offset, &cnt, NULL, mtd->size,
900 puts("** Read error\n");
901 bootstage_error(BOOTSTAGE_ID_NAND_READ);
904 bootstage_mark(BOOTSTAGE_ID_NAND_READ);
906 #if defined(CONFIG_FIT)
907 /* This cannot be done earlier, we need complete FIT image in RAM first */
908 if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
909 if (!fit_check_format (fit_hdr)) {
910 bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ);
911 puts ("** Bad FIT image format\n");
914 bootstage_mark(BOOTSTAGE_ID_NAND_FIT_READ_OK);
915 fit_print_contents (fit_hdr);
919 /* Loading ok, update default load address */
923 return bootm_maybe_autostart(cmdtp, cmd);
926 static int do_nandboot(cmd_tbl_t *cmdtp, int flag, int argc,
929 char *boot_device = NULL;
931 ulong addr, offset = 0;
932 #if defined(CONFIG_CMD_MTDPARTS)
933 struct mtd_device *dev;
934 struct part_info *part;
938 char *p = (argc == 2) ? argv[1] : argv[2];
939 if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
940 (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
941 if (dev->id->type != MTD_DEV_TYPE_NAND) {
942 puts("Not a NAND device\n");
948 addr = simple_strtoul(argv[1], NULL, 16);
950 addr = CONFIG_SYS_LOAD_ADDR;
951 return nand_load_image(cmdtp, nand_info[dev->id->num],
952 part->offset, addr, argv[0]);
957 bootstage_mark(BOOTSTAGE_ID_NAND_PART);
960 addr = CONFIG_SYS_LOAD_ADDR;
961 boot_device = getenv("bootdevice");
964 addr = simple_strtoul(argv[1], NULL, 16);
965 boot_device = getenv("bootdevice");
968 addr = simple_strtoul(argv[1], NULL, 16);
969 boot_device = argv[2];
972 addr = simple_strtoul(argv[1], NULL, 16);
973 boot_device = argv[2];
974 offset = simple_strtoul(argv[3], NULL, 16);
977 #if defined(CONFIG_CMD_MTDPARTS)
980 bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
981 return CMD_RET_USAGE;
983 bootstage_mark(BOOTSTAGE_ID_NAND_SUFFIX);
986 puts("\n** No boot device **\n");
987 bootstage_error(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
990 bootstage_mark(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
992 idx = simple_strtoul(boot_device, NULL, 16);
994 if (idx < 0 || idx >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[idx]) {
995 printf("\n** Device %d not available\n", idx);
996 bootstage_error(BOOTSTAGE_ID_NAND_AVAILABLE);
999 bootstage_mark(BOOTSTAGE_ID_NAND_AVAILABLE);
1001 return nand_load_image(cmdtp, nand_info[idx], offset, addr, argv[0]);
1004 U_BOOT_CMD(nboot, 4, 1, do_nandboot,
1005 "boot from NAND device",
1006 "[partition] | [[[loadAddr] dev] offset]"