Re-factoring the legacy NAND code (legacy NAND now only in board-specific
[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  * 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
447 /*
448  * Imports from nand_legacy.c
449  */
450 extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
451 extern int curr_device;
452 extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs,
453                             size_t len, int clean);
454 extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start,
455                          size_t len, size_t *retlen, u_char *buf);
456 extern void nand_print(struct nand_chip *nand);
457 extern void nand_print_bad(struct nand_chip *nand);
458 extern int nand_read_oob(struct nand_chip *nand, size_t ofs,
459                                size_t len, size_t *retlen, u_char *buf);
460 extern int nand_write_oob(struct nand_chip *nand, size_t ofs,
461                                 size_t len, size_t *retlen, const u_char *buf);
462
463
464 int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
465 {
466     int rcode = 0;
467
468     switch (argc) {
469     case 0:
470     case 1:
471         printf ("Usage:\n%s\n", cmdtp->usage);
472         return 1;
473     case 2:
474         if (strcmp(argv[1],"info") == 0) {
475                 int i;
476
477                 putc ('\n');
478
479                 for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) {
480                         if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN)
481                                 continue; /* list only known devices */
482                         printf ("Device %d: ", i);
483                         nand_print(&nand_dev_desc[i]);
484                 }
485                 return 0;
486
487         } else if (strcmp(argv[1],"device") == 0) {
488                 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
489                         puts ("\nno devices available\n");
490                         return 1;
491                 }
492                 printf ("\nDevice %d: ", curr_device);
493                 nand_print(&nand_dev_desc[curr_device]);
494                 return 0;
495
496         } else if (strcmp(argv[1],"bad") == 0) {
497                 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
498                         puts ("\nno devices available\n");
499                         return 1;
500                 }
501                 printf ("\nDevice %d bad blocks:\n", curr_device);
502                 nand_print_bad(&nand_dev_desc[curr_device]);
503                 return 0;
504
505         }
506         printf ("Usage:\n%s\n", cmdtp->usage);
507         return 1;
508     case 3:
509         if (strcmp(argv[1],"device") == 0) {
510                 int dev = (int)simple_strtoul(argv[2], NULL, 10);
511
512                 printf ("\nDevice %d: ", dev);
513                 if (dev >= CFG_MAX_NAND_DEVICE) {
514                         puts ("unknown device\n");
515                         return 1;
516                 }
517                 nand_print(&nand_dev_desc[dev]);
518                 /*nand_print (dev);*/
519
520                 if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
521                         return 1;
522                 }
523
524                 curr_device = dev;
525
526                 puts ("... is now current device\n");
527
528                 return 0;
529         }
530         else if (strcmp(argv[1],"erase") == 0 && strcmp(argv[2], "clean") == 0) {
531                 struct nand_chip* nand = &nand_dev_desc[curr_device];
532                 ulong off = 0;
533                 ulong size = nand->totlen;
534                 int ret;
535
536                 printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
537                         curr_device, off, size);
538
539                 ret = nand_legacy_erase (nand, off, size, 1);
540
541                 printf("%s\n", ret ? "ERROR" : "OK");
542
543                 return ret;
544         }
545
546         printf ("Usage:\n%s\n", cmdtp->usage);
547         return 1;
548     default:
549         /* at least 4 args */
550
551         if (strncmp(argv[1], "read", 4) == 0 ||
552             strncmp(argv[1], "write", 5) == 0) {
553                 ulong addr = simple_strtoul(argv[2], NULL, 16);
554                 ulong off  = simple_strtoul(argv[3], NULL, 16);
555                 ulong size = simple_strtoul(argv[4], NULL, 16);
556                 int cmd    = (strncmp(argv[1], "read", 4) == 0) ?
557                                 NANDRW_READ : NANDRW_WRITE;
558                 int ret, total;
559                 char* cmdtail = strchr(argv[1], '.');
560
561                 if (cmdtail && !strncmp(cmdtail, ".oob", 2)) {
562                         /* read out-of-band data */
563                         if (cmd & NANDRW_READ) {
564                                 ret = nand_read_oob(nand_dev_desc + curr_device,
565                                                     off, size, (size_t *)&total,
566                                                     (u_char*)addr);
567                         }
568                         else {
569                                 ret = nand_write_oob(nand_dev_desc + curr_device,
570                                                      off, size, (size_t *)&total,
571                                                      (u_char*)addr);
572                         }
573                         return ret;
574                 }
575                 else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2))
576                         cmd |= NANDRW_JFFS2;    /* skip bad blocks */
577                 else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 2)) {
578                         cmd |= NANDRW_JFFS2;    /* skip bad blocks (on read too) */
579                         if (cmd & NANDRW_READ)
580                                 cmd |= NANDRW_JFFS2_SKIP;       /* skip bad blocks (on read too) */
581                 }
582 #ifdef SXNI855T
583                 /* need ".e" same as ".j" for compatibility with older units */
584                 else if (cmdtail && !strcmp(cmdtail, ".e"))
585                         cmd |= NANDRW_JFFS2;    /* skip bad blocks */
586 #endif
587 #ifdef CFG_NAND_SKIP_BAD_DOT_I
588                 /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */
589                 /* ".i" for image -> read skips bad block (no 0xff) */
590                 else if (cmdtail && !strcmp(cmdtail, ".i")) {
591                         cmd |= NANDRW_JFFS2;    /* skip bad blocks (on read too) */
592                         if (cmd & NANDRW_READ)
593                                 cmd |= NANDRW_JFFS2_SKIP;       /* skip bad blocks (on read too) */
594                 }
595 #endif /* CFG_NAND_SKIP_BAD_DOT_I */
596                 else if (cmdtail) {
597                         printf ("Usage:\n%s\n", cmdtp->usage);
598                         return 1;
599                 }
600
601                 printf ("\nNAND %s: device %d offset %ld, size %ld ... ",
602                         (cmd & NANDRW_READ) ? "read" : "write",
603                         curr_device, off, size);
604
605                 ret = nand_legacy_rw(nand_dev_desc + curr_device, cmd, off, size,
606                              (size_t *)&total, (u_char*)addr);
607
608                 printf (" %d bytes %s: %s\n", total,
609                         (cmd & NANDRW_READ) ? "read" : "written",
610                         ret ? "ERROR" : "OK");
611
612                 return ret;
613         } else if (strcmp(argv[1],"erase") == 0 &&
614                    (argc == 4 || strcmp("clean", argv[2]) == 0)) {
615                 int clean = argc == 5;
616                 ulong off = simple_strtoul(argv[2 + clean], NULL, 16);
617                 ulong size = simple_strtoul(argv[3 + clean], NULL, 16);
618                 int ret;
619
620                 printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
621                         curr_device, off, size);
622
623                 ret = nand_legacy_erase (nand_dev_desc + curr_device,
624                                         off, size, clean);
625
626                 printf("%s\n", ret ? "ERROR" : "OK");
627
628                 return ret;
629         } else {
630                 printf ("Usage:\n%s\n", cmdtp->usage);
631                 rcode = 1;
632         }
633
634         return rcode;
635     }
636 }
637
638 U_BOOT_CMD(
639         nand,   5,      1,      do_nand,
640         "nand    - NAND sub-system\n",
641         "info  - show available NAND devices\n"
642         "nand device [dev] - show or set current device\n"
643         "nand read[.jffs2[s]]  addr off size\n"
644         "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
645         "    at offset `off' to/from memory address `addr'\n"
646         "nand erase [clean] [off size] - erase `size' bytes from\n"
647         "    offset `off' (entire device if not specified)\n"
648         "nand bad - show bad blocks\n"
649         "nand read.oob addr off size - read out-of-band data\n"
650         "nand write.oob addr off size - read out-of-band data\n"
651 );
652
653 int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
654 {
655         char *boot_device = NULL;
656         char *ep;
657         int dev;
658         ulong cnt;
659         ulong addr;
660         ulong offset = 0;
661         image_header_t *hdr;
662         int rcode = 0;
663         switch (argc) {
664         case 1:
665                 addr = CFG_LOAD_ADDR;
666                 boot_device = getenv ("bootdevice");
667                 break;
668         case 2:
669                 addr = simple_strtoul(argv[1], NULL, 16);
670                 boot_device = getenv ("bootdevice");
671                 break;
672         case 3:
673                 addr = simple_strtoul(argv[1], NULL, 16);
674                 boot_device = argv[2];
675                 break;
676         case 4:
677                 addr = simple_strtoul(argv[1], NULL, 16);
678                 boot_device = argv[2];
679                 offset = simple_strtoul(argv[3], NULL, 16);
680                 break;
681         default:
682                 printf ("Usage:\n%s\n", cmdtp->usage);
683                 SHOW_BOOT_PROGRESS (-1);
684                 return 1;
685         }
686
687         if (!boot_device) {
688                 puts ("\n** No boot device **\n");
689                 SHOW_BOOT_PROGRESS (-1);
690                 return 1;
691         }
692
693         dev = simple_strtoul(boot_device, &ep, 16);
694
695         if ((dev >= CFG_MAX_NAND_DEVICE) ||
696             (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) {
697                 printf ("\n** Device %d not available\n", dev);
698                 SHOW_BOOT_PROGRESS (-1);
699                 return 1;
700         }
701
702         printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n",
703                 dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
704                 offset);
705
706         if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset,
707                         SECTORSIZE, NULL, (u_char *)addr)) {
708                 printf ("** Read error on %d\n", dev);
709                 SHOW_BOOT_PROGRESS (-1);
710                 return 1;
711         }
712
713         hdr = (image_header_t *)addr;
714
715         if (ntohl(hdr->ih_magic) == IH_MAGIC) {
716
717                 print_image_hdr (hdr);
718
719                 cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
720                 cnt -= SECTORSIZE;
721         } else {
722                 printf ("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
723                 SHOW_BOOT_PROGRESS (-1);
724                 return 1;
725         }
726
727         if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ,
728                         offset + SECTORSIZE, cnt, NULL,
729                         (u_char *)(addr+SECTORSIZE))) {
730                 printf ("** Read error on %d\n", dev);
731                 SHOW_BOOT_PROGRESS (-1);
732                 return 1;
733         }
734
735         /* Loading ok, update default load address */
736
737         load_addr = addr;
738
739         /* Check if we should attempt an auto-start */
740         if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
741                 char *local_args[2];
742                 extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
743
744                 local_args[0] = argv[0];
745                 local_args[1] = NULL;
746
747                 printf ("Automatic boot of image at addr 0x%08lx ...\n", addr);
748
749                 do_bootm (cmdtp, 0, 1, local_args);
750                 rcode = 1;
751         }
752         return rcode;
753 }
754
755 U_BOOT_CMD(
756         nboot,  4,      1,      do_nandboot,
757         "nboot   - boot from NAND device\n",
758         "loadAddr dev\n"
759 );
760
761 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
762
763 #endif /* CFG_NAND_LEGACY */