]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_nand.c
* Support for FDT in uImage format, error when using FDT from flash
[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  * Added 16-bit nand support
8  * (C) 2004 Texas Instruments
9  */
10
11 #include <common.h>
12
13
14 #ifndef CFG_NAND_LEGACY
15 /*
16  *
17  * New NAND support
18  *
19  */
20 #include <common.h>
21
22 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
23
24 #include <command.h>
25 #include <watchdog.h>
26 #include <malloc.h>
27 #include <asm/byteorder.h>
28
29 #ifdef CONFIG_SHOW_BOOT_PROGRESS
30 # include <status_led.h>
31 # define SHOW_BOOT_PROGRESS(arg)        show_boot_progress(arg)
32 #else
33 # define SHOW_BOOT_PROGRESS(arg)
34 #endif
35
36 #include <jffs2/jffs2.h>
37 #include <nand.h>
38
39 extern nand_info_t nand_info[];       /* info for NAND chips */
40
41 static int nand_dump_oob(nand_info_t *nand, ulong off)
42 {
43         return 0;
44 }
45
46 static int nand_dump(nand_info_t *nand, ulong off)
47 {
48         int i;
49         u_char *buf, *p;
50
51         buf = malloc(nand->oobblock + nand->oobsize);
52         if (!buf) {
53                 puts("No memory for page buffer\n");
54                 return 1;
55         }
56         off &= ~(nand->oobblock - 1);
57         i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize);
58         if (i < 0) {
59                 printf("Error (%d) reading page %08x\n", i, off);
60                 free(buf);
61                 return 1;
62         }
63         printf("Page %08x dump:\n", off);
64         i = nand->oobblock >> 4; p = buf;
65         while (i--) {
66                 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x"
67                         "  %02x %02x %02x %02x %02x %02x %02x %02x\n",
68                         p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
69                         p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
70                 p += 16;
71         }
72         puts("OOB:\n");
73         i = nand->oobsize >> 3;
74         while (i--) {
75                 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
76                         p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
77                 p += 8;
78         }
79         free(buf);
80
81         return 0;
82 }
83
84 /* ------------------------------------------------------------------------- */
85
86 static void
87 arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize)
88 {
89         *off = 0;
90         *size = 0;
91
92 #if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART)
93         if (argc >= 1 && strcmp(argv[0], "partition") == 0) {
94                 int part_num;
95                 struct part_info *part;
96                 const char *partstr;
97
98                 if (argc >= 2)
99                         partstr = argv[1];
100                 else
101                         partstr = getenv("partition");
102
103                 if (partstr)
104                         part_num = (int)simple_strtoul(partstr, NULL, 10);
105                 else
106                         part_num = 0;
107
108                 part = jffs2_part_info(part_num);
109                 if (part == NULL) {
110                         printf("\nInvalid partition %d\n", part_num);
111                         return;
112                 }
113                 *size = part->size;
114                 *off = (ulong)part->offset;
115         } else
116 #endif
117         {
118                 if (argc >= 1)
119                         *off = (ulong)simple_strtoul(argv[0], NULL, 16);
120                 else
121                         *off = 0;
122
123                 if (argc >= 2)
124                         *size = (ulong)simple_strtoul(argv[1], NULL, 16);
125                 else
126                         *size = totsize - *off;
127
128         }
129
130 }
131
132 int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
133 {
134         int i, dev, ret;
135         ulong addr, off, size;
136         char *cmd, *s;
137         nand_info_t *nand;
138
139         /* at least two arguments please */
140         if (argc < 2)
141                 goto usage;
142
143         cmd = argv[1];
144
145         if (strcmp(cmd, "info") == 0) {
146
147                 putc('\n');
148                 for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
149                         if (nand_info[i].name)
150                                 printf("Device %d: %s, sector size %lu KiB\n",
151                                         i, nand_info[i].name,
152                                         nand_info[i].erasesize >> 10);
153                 }
154                 return 0;
155         }
156
157         if (strcmp(cmd, "device") == 0) {
158
159                 if (argc < 3) {
160                         if ((nand_curr_device < 0) ||
161                             (nand_curr_device >= CFG_MAX_NAND_DEVICE))
162                                 puts("\nno devices available\n");
163                         else
164                                 printf("\nDevice %d: %s\n", nand_curr_device,
165                                         nand_info[nand_curr_device].name);
166                         return 0;
167                 }
168                 dev = (int)simple_strtoul(argv[2], NULL, 10);
169                 if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
170                         puts("No such device\n");
171                         return 1;
172                 }
173                 printf("Device %d: %s", dev, nand_info[dev].name);
174                 puts("... is now current device\n");
175                 nand_curr_device = dev;
176                 return 0;
177         }
178
179         if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
180             strncmp(cmd, "dump", 4) != 0 &&
181             strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0)
182                 goto usage;
183
184         /* the following commands operate on the current device */
185         if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE ||
186             !nand_info[nand_curr_device].name) {
187                 puts("\nno devices available\n");
188                 return 1;
189         }
190         nand = &nand_info[nand_curr_device];
191
192         if (strcmp(cmd, "bad") == 0) {
193                 printf("\nDevice %d bad blocks:\n", nand_curr_device);
194                 for (off = 0; off < nand->size; off += nand->erasesize)
195                         if (nand_block_isbad(nand, off))
196                                 printf("  %08x\n", off);
197                 return 0;
198         }
199
200         if (strcmp(cmd, "erase") == 0) {
201                 arg_off_size(argc - 2, argv + 2, &off, &size, nand->size);
202                 if (off == 0 && size == 0)
203                         return 1;
204
205                 printf("\nNAND erase: device %d offset 0x%x, size 0x%x ",
206                        nand_curr_device, off, size);
207                 ret = nand_erase(nand, off, size);
208                 printf("%s\n", ret ? "ERROR" : "OK");
209
210                 return ret == 0 ? 0 : 1;
211         }
212
213         if (strncmp(cmd, "dump", 4) == 0) {
214                 if (argc < 3)
215                         goto usage;
216
217                 s = strchr(cmd, '.');
218                 off = (int)simple_strtoul(argv[2], NULL, 16);
219
220                 if (s != NULL && strcmp(s, ".oob") == 0)
221                         ret = nand_dump_oob(nand, off);
222                 else
223                         ret = nand_dump(nand, off);
224
225                 return ret == 0 ? 1 : 0;
226
227         }
228
229         /* read write */
230         if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
231                 if (argc < 4)
232                         goto usage;
233 /*
234                 s = strchr(cmd, '.');
235                 clean = CLEAN_NONE;
236                 if (s != NULL) {
237                         if (strcmp(s, ".jffs2") == 0 || strcmp(s, ".e") == 0
238                             || strcmp(s, ".i"))
239                                 clean = CLEAN_JFFS2;
240                 }
241 */
242                 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
243
244                 arg_off_size(argc - 3, argv + 3, &off, &size, nand->size);
245                 if (off == 0 && size == 0)
246                         return 1;
247
248                 i = strncmp(cmd, "read", 4) == 0;       /* 1 = read, 0 = write */
249                 printf("\nNAND %s: device %d offset %u, size %u ... ",
250                        i ? "read" : "write", nand_curr_device, off, size);
251
252                 if (i)
253                         ret = nand_read(nand, off, &size, (u_char *)addr);
254                 else
255                         ret = nand_write(nand, off, &size, (u_char *)addr);
256
257                 printf(" %d bytes %s: %s\n", size,
258                        i ? "read" : "written", ret ? "ERROR" : "OK");
259
260                 return ret == 0 ? 0 : 1;
261         }
262 usage:
263         printf("Usage:\n%s\n", cmdtp->usage);
264         return 1;
265 }
266
267 U_BOOT_CMD(nand, 5, 1, do_nand,
268         "nand    - NAND sub-system\n",
269         "info                  - show available NAND devices\n"
270         "nand device [dev]     - show or set current device\n"
271         "nand read[.jffs2]     - addr off size\n"
272         "nand write[.jffs2]    - addr off size - read/write `size' bytes starting\n"
273         "    at offset `off' to/from memory address `addr'\n"
274         "nand erase [clean] [off size] - erase `size' bytes from\n"
275         "    offset `off' (entire device if not specified)\n"
276         "nand bad - show bad blocks\n"
277         "nand dump[.oob] off - dump page\n"
278         "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
279         "nand markbad off - mark bad block at offset (UNSAFE)\n"
280         "nand biterr off - make a bit error at offset (UNSAFE)\n");
281
282 int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
283 {
284         char *boot_device = NULL;
285         char *ep;
286         int dev;
287         int r;
288         ulong addr, cnt, offset = 0;
289         image_header_t *hdr;
290         nand_info_t *nand;
291
292         switch (argc) {
293         case 1:
294                 addr = CFG_LOAD_ADDR;
295                 boot_device = getenv("bootdevice");
296                 break;
297         case 2:
298                 addr = simple_strtoul(argv[1], NULL, 16);
299                 boot_device = getenv("bootdevice");
300                 break;
301         case 3:
302                 addr = simple_strtoul(argv[1], NULL, 16);
303                 boot_device = argv[2];
304                 break;
305         case 4:
306                 addr = simple_strtoul(argv[1], NULL, 16);
307                 boot_device = argv[2];
308                 offset = simple_strtoul(argv[3], NULL, 16);
309                 break;
310         default:
311                 printf("Usage:\n%s\n", cmdtp->usage);
312                 SHOW_BOOT_PROGRESS(-1);
313                 return 1;
314         }
315
316         if (!boot_device) {
317                 puts("\n** No boot device **\n");
318                 SHOW_BOOT_PROGRESS(-1);
319                 return 1;
320         }
321
322         dev = simple_strtoul(boot_device, &ep, 16);
323
324         if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
325                 printf("\n** Device %d not available\n", dev);
326                 SHOW_BOOT_PROGRESS(-1);
327                 return 1;
328         }
329
330         nand = &nand_info[dev];
331         printf("\nLoading from device %d: %s (offset 0x%lx)\n",
332                dev, nand->name, offset);
333
334         cnt = nand->oobblock;
335         r = nand_read(nand, offset, &cnt, (u_char *) addr);
336         if (r) {
337                 printf("** Read error on %d\n", dev);
338                 SHOW_BOOT_PROGRESS(-1);
339                 return 1;
340         }
341
342         hdr = (image_header_t *) addr;
343
344         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
345                 printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
346                 SHOW_BOOT_PROGRESS(-1);
347                 return 1;
348         }
349
350         print_image_hdr(hdr);
351
352         cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t));
353
354         r = nand_read(nand, offset, &cnt, (u_char *) addr);
355         if (r) {
356                 printf("** Read error on %d\n", dev);
357                 SHOW_BOOT_PROGRESS(-1);
358                 return 1;
359         }
360
361         /* Loading ok, update default load address */
362
363         load_addr = addr;
364
365         /* Check if we should attempt an auto-start */
366         if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
367                 char *local_args[2];
368                 extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
369
370                 local_args[0] = argv[0];
371                 local_args[1] = NULL;
372
373                 printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
374
375                 do_bootm(cmdtp, 0, 1, local_args);
376                 return 1;
377         }
378         return 0;
379 }
380
381 U_BOOT_CMD(nboot, 4, 1, do_nandboot,
382         "nboot   - boot from NAND device\n", "loadAddr dev\n");
383
384
385 #endif                          /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
386
387 #else /* CFG_NAND_LEGACY */
388 /*
389  *
390  * Legacy NAND support - to be phased out
391  *
392  */
393 #include <command.h>
394 #include <malloc.h>
395 #include <asm/io.h>
396 #include <watchdog.h>
397
398 #ifdef CONFIG_SHOW_BOOT_PROGRESS
399 # include <status_led.h>
400 # define SHOW_BOOT_PROGRESS(arg)        show_boot_progress(arg)
401 #else
402 # define SHOW_BOOT_PROGRESS(arg)
403 #endif
404
405 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
406 #include <linux/mtd/nand_legacy.h>
407 #if 0
408 #include <linux/mtd/nand_ids.h>
409 #include <jffs2/jffs2.h>
410 #endif
411
412 #ifdef CONFIG_OMAP1510
413 void archflashwp(void *archdata, int wp);
414 #endif
415
416 #define ROUND_DOWN(value,boundary)      ((value) & (~((boundary)-1)))
417
418 #undef  NAND_DEBUG
419 #undef  PSYCHO_DEBUG
420
421 /* ****************** WARNING *********************
422  * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will
423  * erase (or at least attempt to erase) blocks that are marked
424  * bad. This can be very handy if you are _sure_ that the block
425  * is OK, say because you marked a good block bad to test bad
426  * block handling and you are done testing, or if you have
427  * accidentally marked blocks bad.
428  *
429  * Erasing factory marked bad blocks is a _bad_ idea. If the
430  * erase succeeds there is no reliable way to find them again,
431  * and attempting to program or erase bad blocks can affect
432  * the data in _other_ (good) blocks.
433  */
434 #define  ALLOW_ERASE_BAD_DEBUG 0
435
436 #define CONFIG_MTD_NAND_ECC  /* enable ECC */
437 #define CONFIG_MTD_NAND_ECC_JFFS2
438
439 /* bits for nand_legacy_rw() `cmd'; or together as needed */
440 #define NANDRW_READ     0x01
441 #define NANDRW_WRITE    0x00
442 #define NANDRW_JFFS2    0x02
443 #define NANDRW_JFFS2_SKIP       0x04
444
445 /*
446  * Imports from nand_legacy.c
447  */
448 extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
449 extern int curr_device;
450 extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs,
451                             size_t len, int clean);
452 extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start,
453                          size_t len, size_t *retlen, u_char *buf);
454 extern void nand_print(struct nand_chip *nand);
455 extern void nand_print_bad(struct nand_chip *nand);
456 extern int nand_read_oob(struct nand_chip *nand, size_t ofs,
457                                size_t len, size_t *retlen, u_char *buf);
458 extern int nand_write_oob(struct nand_chip *nand, size_t ofs,
459                                 size_t len, size_t *retlen, const u_char *buf);
460
461
462 int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
463 {
464     int rcode = 0;
465
466     switch (argc) {
467     case 0:
468     case 1:
469         printf ("Usage:\n%s\n", cmdtp->usage);
470         return 1;
471     case 2:
472         if (strcmp(argv[1],"info") == 0) {
473                 int i;
474
475                 putc ('\n');
476
477                 for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) {
478                         if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN)
479                                 continue; /* list only known devices */
480                         printf ("Device %d: ", i);
481                         nand_print(&nand_dev_desc[i]);
482                 }
483                 return 0;
484
485         } else if (strcmp(argv[1],"device") == 0) {
486                 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
487                         puts ("\nno devices available\n");
488                         return 1;
489                 }
490                 printf ("\nDevice %d: ", curr_device);
491                 nand_print(&nand_dev_desc[curr_device]);
492                 return 0;
493
494         } else if (strcmp(argv[1],"bad") == 0) {
495                 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
496                         puts ("\nno devices available\n");
497                         return 1;
498                 }
499                 printf ("\nDevice %d bad blocks:\n", curr_device);
500                 nand_print_bad(&nand_dev_desc[curr_device]);
501                 return 0;
502
503         }
504         printf ("Usage:\n%s\n", cmdtp->usage);
505         return 1;
506     case 3:
507         if (strcmp(argv[1],"device") == 0) {
508                 int dev = (int)simple_strtoul(argv[2], NULL, 10);
509
510                 printf ("\nDevice %d: ", dev);
511                 if (dev >= CFG_MAX_NAND_DEVICE) {
512                         puts ("unknown device\n");
513                         return 1;
514                 }
515                 nand_print(&nand_dev_desc[dev]);
516                 /*nand_print (dev);*/
517
518                 if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
519                         return 1;
520                 }
521
522                 curr_device = dev;
523
524                 puts ("... is now current device\n");
525
526                 return 0;
527         }
528         else if (strcmp(argv[1],"erase") == 0 && strcmp(argv[2], "clean") == 0) {
529                 struct nand_chip* nand = &nand_dev_desc[curr_device];
530                 ulong off = 0;
531                 ulong size = nand->totlen;
532                 int ret;
533
534                 printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
535                         curr_device, off, size);
536
537                 ret = nand_legacy_erase (nand, off, size, 1);
538
539                 printf("%s\n", ret ? "ERROR" : "OK");
540
541                 return ret;
542         }
543
544         printf ("Usage:\n%s\n", cmdtp->usage);
545         return 1;
546     default:
547         /* at least 4 args */
548
549         if (strncmp(argv[1], "read", 4) == 0 ||
550             strncmp(argv[1], "write", 5) == 0) {
551                 ulong addr = simple_strtoul(argv[2], NULL, 16);
552                 ulong off  = simple_strtoul(argv[3], NULL, 16);
553                 ulong size = simple_strtoul(argv[4], NULL, 16);
554                 int cmd    = (strncmp(argv[1], "read", 4) == 0) ?
555                                 NANDRW_READ : NANDRW_WRITE;
556                 int ret, total;
557                 char* cmdtail = strchr(argv[1], '.');
558
559                 if (cmdtail && !strncmp(cmdtail, ".oob", 2)) {
560                         /* read out-of-band data */
561                         if (cmd & NANDRW_READ) {
562                                 ret = nand_read_oob(nand_dev_desc + curr_device,
563                                                     off, size, (size_t *)&total,
564                                                     (u_char*)addr);
565                         }
566                         else {
567                                 ret = nand_write_oob(nand_dev_desc + curr_device,
568                                                      off, size, (size_t *)&total,
569                                                      (u_char*)addr);
570                         }
571                         return ret;
572                 }
573                 else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2))
574                         cmd |= NANDRW_JFFS2;    /* skip bad blocks */
575                 else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 2)) {
576                         cmd |= NANDRW_JFFS2;    /* skip bad blocks (on read too) */
577                         if (cmd & NANDRW_READ)
578                                 cmd |= NANDRW_JFFS2_SKIP;       /* skip bad blocks (on read too) */
579                 }
580 #ifdef SXNI855T
581                 /* need ".e" same as ".j" for compatibility with older units */
582                 else if (cmdtail && !strcmp(cmdtail, ".e"))
583                         cmd |= NANDRW_JFFS2;    /* skip bad blocks */
584 #endif
585 #ifdef CFG_NAND_SKIP_BAD_DOT_I
586                 /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */
587                 /* ".i" for image -> read skips bad block (no 0xff) */
588                 else if (cmdtail && !strcmp(cmdtail, ".i")) {
589                         cmd |= NANDRW_JFFS2;    /* skip bad blocks (on read too) */
590                         if (cmd & NANDRW_READ)
591                                 cmd |= NANDRW_JFFS2_SKIP;       /* skip bad blocks (on read too) */
592                 }
593 #endif /* CFG_NAND_SKIP_BAD_DOT_I */
594                 else if (cmdtail) {
595                         printf ("Usage:\n%s\n", cmdtp->usage);
596                         return 1;
597                 }
598
599                 printf ("\nNAND %s: device %d offset %ld, size %ld ... ",
600                         (cmd & NANDRW_READ) ? "read" : "write",
601                         curr_device, off, size);
602
603                 ret = nand_legacy_rw(nand_dev_desc + curr_device, cmd, off, size,
604                              (size_t *)&total, (u_char*)addr);
605
606                 printf (" %d bytes %s: %s\n", total,
607                         (cmd & NANDRW_READ) ? "read" : "written",
608                         ret ? "ERROR" : "OK");
609
610                 return ret;
611         } else if (strcmp(argv[1],"erase") == 0 &&
612                    (argc == 4 || strcmp("clean", argv[2]) == 0)) {
613                 int clean = argc == 5;
614                 ulong off = simple_strtoul(argv[2 + clean], NULL, 16);
615                 ulong size = simple_strtoul(argv[3 + clean], NULL, 16);
616                 int ret;
617
618                 printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
619                         curr_device, off, size);
620
621                 ret = nand_legacy_erase (nand_dev_desc + curr_device,
622                                         off, size, clean);
623
624                 printf("%s\n", ret ? "ERROR" : "OK");
625
626                 return ret;
627         } else {
628                 printf ("Usage:\n%s\n", cmdtp->usage);
629                 rcode = 1;
630         }
631
632         return rcode;
633     }
634 }
635
636 U_BOOT_CMD(
637         nand,   5,      1,      do_nand,
638         "nand    - NAND sub-system\n",
639         "info  - show available NAND devices\n"
640         "nand device [dev] - show or set current device\n"
641         "nand read[.jffs2[s]]  addr off size\n"
642         "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
643         "    at offset `off' to/from memory address `addr'\n"
644         "nand erase [clean] [off size] - erase `size' bytes from\n"
645         "    offset `off' (entire device if not specified)\n"
646         "nand bad - show bad blocks\n"
647         "nand read.oob addr off size - read out-of-band data\n"
648         "nand write.oob addr off size - read out-of-band data\n"
649 );
650
651 int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
652 {
653         char *boot_device = NULL;
654         char *ep;
655         int dev;
656         ulong cnt;
657         ulong addr;
658         ulong offset = 0;
659         image_header_t *hdr;
660         int rcode = 0;
661         switch (argc) {
662         case 1:
663                 addr = CFG_LOAD_ADDR;
664                 boot_device = getenv ("bootdevice");
665                 break;
666         case 2:
667                 addr = simple_strtoul(argv[1], NULL, 16);
668                 boot_device = getenv ("bootdevice");
669                 break;
670         case 3:
671                 addr = simple_strtoul(argv[1], NULL, 16);
672                 boot_device = argv[2];
673                 break;
674         case 4:
675                 addr = simple_strtoul(argv[1], NULL, 16);
676                 boot_device = argv[2];
677                 offset = simple_strtoul(argv[3], NULL, 16);
678                 break;
679         default:
680                 printf ("Usage:\n%s\n", cmdtp->usage);
681                 SHOW_BOOT_PROGRESS (-1);
682                 return 1;
683         }
684
685         if (!boot_device) {
686                 puts ("\n** No boot device **\n");
687                 SHOW_BOOT_PROGRESS (-1);
688                 return 1;
689         }
690
691         dev = simple_strtoul(boot_device, &ep, 16);
692
693         if ((dev >= CFG_MAX_NAND_DEVICE) ||
694             (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) {
695                 printf ("\n** Device %d not available\n", dev);
696                 SHOW_BOOT_PROGRESS (-1);
697                 return 1;
698         }
699
700         printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n",
701                 dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
702                 offset);
703
704         if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset,
705                         SECTORSIZE, NULL, (u_char *)addr)) {
706                 printf ("** Read error on %d\n", dev);
707                 SHOW_BOOT_PROGRESS (-1);
708                 return 1;
709         }
710
711         hdr = (image_header_t *)addr;
712
713         if (ntohl(hdr->ih_magic) == IH_MAGIC) {
714
715                 print_image_hdr (hdr);
716
717                 cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
718                 cnt -= SECTORSIZE;
719         } else {
720                 printf ("\n** Bad Magic Number 0x%x **\n", ntohl(hdr->ih_magic));
721                 SHOW_BOOT_PROGRESS (-1);
722                 return 1;
723         }
724
725         if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ,
726                         offset + SECTORSIZE, cnt, NULL,
727                         (u_char *)(addr+SECTORSIZE))) {
728                 printf ("** Read error on %d\n", dev);
729                 SHOW_BOOT_PROGRESS (-1);
730                 return 1;
731         }
732
733         /* Loading ok, update default load address */
734
735         load_addr = addr;
736
737         /* Check if we should attempt an auto-start */
738         if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
739                 char *local_args[2];
740                 extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
741
742                 local_args[0] = argv[0];
743                 local_args[1] = NULL;
744
745                 printf ("Automatic boot of image at addr 0x%08lx ...\n", addr);
746
747                 do_bootm (cmdtp, 0, 1, local_args);
748                 rcode = 1;
749         }
750         return rcode;
751 }
752
753 U_BOOT_CMD(
754         nboot,  4,      1,      do_nandboot,
755         "nboot   - boot from NAND device\n",
756         "loadAddr dev\n"
757 );
758
759 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
760
761 #endif /* CFG_NAND_LEGACY */