cmd_nand: some infrastructure fixes and refactoring
[platform/kernel/u-boot.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 (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 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 = !strcmp(cmd, "scrub");
458
459                 printf("\nNAND %s: ", scrub ? "scrub" : "erase");
460                 /* skip first two or three arguments, look for offset and size */
461                 if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0)
462                         return 1;
463
464                 nand = &nand_info[dev];
465
466                 memset(&opts, 0, sizeof(opts));
467                 opts.offset = off;
468                 opts.length = size;
469                 opts.jffs2  = clean;
470                 opts.quiet  = quiet;
471
472                 if (scrub) {
473                         puts("Warning: "
474                              "scrub option will erase all factory set "
475                              "bad blocks!\n"
476                              "         "
477                              "There is no reliable way to recover them.\n"
478                              "         "
479                              "Use this command only for testing purposes "
480                              "if you\n"
481                              "         "
482                              "are sure of what you are doing!\n"
483                              "\nReally scrub this NAND flash? <y/N>\n");
484
485                         if (getc() == 'y') {
486                                 puts("y");
487                                 if (getc() == '\r')
488                                         opts.scrub = 1;
489                                 else {
490                                         puts("scrub aborted\n");
491                                         return -1;
492                                 }
493                         } else {
494                                 puts("scrub aborted\n");
495                                 return -1;
496                         }
497                 }
498                 ret = nand_erase_opts(nand, &opts);
499                 printf("%s\n", ret ? "ERROR" : "OK");
500
501                 return ret == 0 ? 0 : 1;
502         }
503
504         if (strncmp(cmd, "dump", 4) == 0) {
505                 if (argc < 3)
506                         goto usage;
507
508                 s = strchr(cmd, '.');
509                 off = (int)simple_strtoul(argv[2], NULL, 16);
510
511                 if (s != NULL && strcmp(s, ".oob") == 0)
512                         ret = nand_dump(nand, off, 1);
513                 else
514                         ret = nand_dump(nand, off, 0);
515
516                 return ret == 0 ? 1 : 0;
517
518         }
519
520         if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
521                 size_t rwsize;
522                 int read;
523
524                 if (argc < 4)
525                         goto usage;
526
527                 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
528
529                 read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
530                 printf("\nNAND %s: ", read ? "read" : "write");
531                 if (arg_off_size(argc - 3, argv + 3, &dev, &off, &size) != 0)
532                         return 1;
533
534                 nand = &nand_info[dev];
535                 rwsize = size;
536
537                 s = strchr(cmd, '.');
538                 if (!s || !strcmp(s, ".jffs2") ||
539                     !strcmp(s, ".e") || !strcmp(s, ".i")) {
540                         if (read)
541                                 ret = nand_read_skip_bad(nand, off, &rwsize,
542                                                          (u_char *)addr);
543                         else
544                                 ret = nand_write_skip_bad(nand, off, &rwsize,
545                                                           (u_char *)addr);
546                 } else if (!strcmp(s, ".oob")) {
547                         /* out-of-band data */
548                         mtd_oob_ops_t ops = {
549                                 .oobbuf = (u8 *)addr,
550                                 .ooblen = rwsize,
551                                 .mode = MTD_OOB_RAW
552                         };
553
554                         if (read)
555                                 ret = nand->read_oob(nand, off, &ops);
556                         else
557                                 ret = nand->write_oob(nand, off, &ops);
558                 } else {
559                         printf("Unknown nand command suffix '%s'.\n", s);
560                         return 1;
561                 }
562
563                 printf(" %zu bytes %s: %s\n", rwsize,
564                        read ? "read" : "written", ret ? "ERROR" : "OK");
565
566                 return ret == 0 ? 0 : 1;
567         }
568
569         if (strcmp(cmd, "markbad") == 0) {
570                 argc -= 2;
571                 argv += 2;
572
573                 if (argc <= 0)
574                         goto usage;
575
576                 while (argc > 0) {
577                         addr = simple_strtoul(*argv, NULL, 16);
578
579                         if (nand->block_markbad(nand, addr)) {
580                                 printf("block 0x%08lx NOT marked "
581                                         "as bad! ERROR %d\n",
582                                         addr, ret);
583                                 ret = 1;
584                         } else {
585                                 printf("block 0x%08lx successfully "
586                                         "marked as bad\n",
587                                         addr);
588                         }
589                         --argc;
590                         ++argv;
591                 }
592                 return ret;
593         }
594
595         if (strcmp(cmd, "biterr") == 0) {
596                 /* todo */
597                 return 1;
598         }
599
600 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
601         if (strcmp(cmd, "lock") == 0) {
602                 int tight = 0;
603                 int status = 0;
604                 if (argc == 3) {
605                         if (!strcmp("tight", argv[2]))
606                                 tight = 1;
607                         if (!strcmp("status", argv[2]))
608                                 status = 1;
609                 }
610                 if (status) {
611                         do_nand_status(nand);
612                 } else {
613                         if (!nand_lock(nand, tight)) {
614                                 puts("NAND flash successfully locked\n");
615                         } else {
616                                 puts("Error locking NAND flash\n");
617                                 return 1;
618                         }
619                 }
620                 return 0;
621         }
622
623         if (strcmp(cmd, "unlock") == 0) {
624                 if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
625                         return 1;
626
627                 if (!nand_unlock(&nand_info[dev], off, size)) {
628                         puts("NAND flash successfully unlocked\n");
629                 } else {
630                         puts("Error unlocking NAND flash, "
631                              "write and erase will probably fail\n");
632                         return 1;
633                 }
634                 return 0;
635         }
636 #endif
637
638 usage:
639         return cmd_usage(cmdtp);
640 }
641
642 U_BOOT_CMD(
643         nand, CONFIG_SYS_MAXARGS, 1, do_nand,
644         "NAND sub-system",
645         "info - show available NAND devices\n"
646         "nand device [dev] - show or set current device\n"
647         "nand read - addr off|partition size\n"
648         "nand write - addr off|partition size\n"
649         "    read/write 'size' bytes starting at offset 'off'\n"
650         "    to/from memory address 'addr', skipping bad blocks.\n"
651         "nand erase [clean] [off size] - erase 'size' bytes from\n"
652         "    offset 'off' (entire device if not specified)\n"
653         "nand bad - show bad blocks\n"
654         "nand dump[.oob] off - dump page\n"
655         "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
656         "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
657         "nand biterr off - make a bit error at offset (UNSAFE)"
658 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
659         "\n"
660         "nand lock [tight] [status]\n"
661         "    bring nand to lock state or display locked pages\n"
662         "nand unlock [offset] [size] - unlock section"
663 #endif
664 #ifdef CONFIG_ENV_OFFSET_OOB
665         "\n"
666         "nand env.oob - environment offset in OOB of block 0 of"
667         "    first device.\n"
668         "nand env.oob set off|partition - set enviromnent offset\n"
669         "nand env.oob get - get environment offset"
670 #endif
671 );
672
673 static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
674                            ulong offset, ulong addr, char *cmd)
675 {
676         int r;
677         char *ep, *s;
678         size_t cnt;
679         image_header_t *hdr;
680 #if defined(CONFIG_FIT)
681         const void *fit_hdr = NULL;
682 #endif
683
684         s = strchr(cmd, '.');
685         if (s != NULL &&
686             (strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
687                 printf("Unknown nand load suffix '%s'\n", s);
688                 show_boot_progress(-53);
689                 return 1;
690         }
691
692         printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);
693
694         cnt = nand->writesize;
695         r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
696         if (r) {
697                 puts("** Read error\n");
698                 show_boot_progress (-56);
699                 return 1;
700         }
701         show_boot_progress (56);
702
703         switch (genimg_get_format ((void *)addr)) {
704         case IMAGE_FORMAT_LEGACY:
705                 hdr = (image_header_t *)addr;
706
707                 show_boot_progress (57);
708                 image_print_contents (hdr);
709
710                 cnt = image_get_image_size (hdr);
711                 break;
712 #if defined(CONFIG_FIT)
713         case IMAGE_FORMAT_FIT:
714                 fit_hdr = (const void *)addr;
715                 puts ("Fit image detected...\n");
716
717                 cnt = fit_get_size (fit_hdr);
718                 break;
719 #endif
720         default:
721                 show_boot_progress (-57);
722                 puts ("** Unknown image type\n");
723                 return 1;
724         }
725         show_boot_progress (57);
726
727         r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
728         if (r) {
729                 puts("** Read error\n");
730                 show_boot_progress (-58);
731                 return 1;
732         }
733         show_boot_progress (58);
734
735 #if defined(CONFIG_FIT)
736         /* This cannot be done earlier, we need complete FIT image in RAM first */
737         if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
738                 if (!fit_check_format (fit_hdr)) {
739                         show_boot_progress (-150);
740                         puts ("** Bad FIT image format\n");
741                         return 1;
742                 }
743                 show_boot_progress (151);
744                 fit_print_contents (fit_hdr);
745         }
746 #endif
747
748         /* Loading ok, update default load address */
749
750         load_addr = addr;
751
752         /* Check if we should attempt an auto-start */
753         if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
754                 char *local_args[2];
755                 extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
756
757                 local_args[0] = cmd;
758                 local_args[1] = NULL;
759
760                 printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
761
762                 do_bootm(cmdtp, 0, 1, local_args);
763                 return 1;
764         }
765         return 0;
766 }
767
768 int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
769 {
770         char *boot_device = NULL;
771         int idx;
772         ulong addr, offset = 0;
773 #if defined(CONFIG_CMD_MTDPARTS)
774         struct mtd_device *dev;
775         struct part_info *part;
776         u8 pnum;
777
778         if (argc >= 2) {
779                 char *p = (argc == 2) ? argv[1] : argv[2];
780                 if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
781                     (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
782                         if (dev->id->type != MTD_DEV_TYPE_NAND) {
783                                 puts("Not a NAND device\n");
784                                 return 1;
785                         }
786                         if (argc > 3)
787                                 goto usage;
788                         if (argc == 3)
789                                 addr = simple_strtoul(argv[1], NULL, 16);
790                         else
791                                 addr = CONFIG_SYS_LOAD_ADDR;
792                         return nand_load_image(cmdtp, &nand_info[dev->id->num],
793                                                part->offset, addr, argv[0]);
794                 }
795         }
796 #endif
797
798         show_boot_progress(52);
799         switch (argc) {
800         case 1:
801                 addr = CONFIG_SYS_LOAD_ADDR;
802                 boot_device = getenv("bootdevice");
803                 break;
804         case 2:
805                 addr = simple_strtoul(argv[1], NULL, 16);
806                 boot_device = getenv("bootdevice");
807                 break;
808         case 3:
809                 addr = simple_strtoul(argv[1], NULL, 16);
810                 boot_device = argv[2];
811                 break;
812         case 4:
813                 addr = simple_strtoul(argv[1], NULL, 16);
814                 boot_device = argv[2];
815                 offset = simple_strtoul(argv[3], NULL, 16);
816                 break;
817         default:
818 #if defined(CONFIG_CMD_MTDPARTS)
819 usage:
820 #endif
821                 show_boot_progress(-53);
822                 return cmd_usage(cmdtp);
823         }
824
825         show_boot_progress(53);
826         if (!boot_device) {
827                 puts("\n** No boot device **\n");
828                 show_boot_progress(-54);
829                 return 1;
830         }
831         show_boot_progress(54);
832
833         idx = simple_strtoul(boot_device, NULL, 16);
834
835         if (idx < 0 || idx >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[idx].name) {
836                 printf("\n** Device %d not available\n", idx);
837                 show_boot_progress(-55);
838                 return 1;
839         }
840         show_boot_progress(55);
841
842         return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]);
843 }
844
845 U_BOOT_CMD(nboot, 4, 1, do_nandboot,
846         "boot from NAND device",
847         "[partition] | [[[loadAddr] dev] offset]"
848 );