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