source: SVN/rincon/u-boot/common/cmd_nand.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 2 years ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 26.5 KB
Line 
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 CONFIG_NAND_LEGACY
15/*
16 *
17 * New NAND support
18 *
19 */
20#include <common.h>
21#include <linux/mtd/mtd.h>
22
23#if defined(CONFIG_CMD_NAND)
24
25#include <command.h>
26#include <watchdog.h>
27#include <malloc.h>
28#include <asm/byteorder.h>
29#include <jffs2/jffs2.h>
30#include <nand.h>
31
32#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
33
34/* parition handling routines */
35int mtdparts_init(void);
36int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
37int find_dev_and_part(const char *id, struct mtd_device **dev,
38                      u8 *part_num, struct part_info **part);
39#endif
40
41static int nand_dump(nand_info_t *nand, ulong off, int only_oob)
42{
43        int i;
44        u_char *datbuf, *oobbuf, *p;
45
46        datbuf = malloc(nand->writesize + nand->oobsize);
47        oobbuf = malloc(nand->oobsize);
48        if (!datbuf || !oobbuf) {
49                puts("No memory for page buffer\n");
50                return 1;
51        }
52        off &= ~(nand->writesize - 1);
53        loff_t addr = (loff_t) off;
54        struct mtd_oob_ops ops;
55        memset(&ops, 0, sizeof(ops));
56        ops.datbuf = datbuf;
57        ops.oobbuf = oobbuf; /* must exist, but oob data will be appended to ops.datbuf */
58        ops.len = nand->writesize;
59        ops.ooblen = nand->oobsize;
60        ops.mode = MTD_OOB_RAW;
61        i = nand->read_oob(nand, addr, &ops);
62        if (i < 0) {
63                printf("Error (%d) reading page %08lx\n", i, off);
64                free(datbuf);
65                free(oobbuf);
66                return 1;
67        }
68        printf("Page %08lx dump:\n", off);
69        i = nand->writesize >> 4;
70        p = datbuf;
71
72        while (i--) {
73                if (!only_oob)
74                        printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
75                               "  %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], p[9], p[10], p[11], p[12], p[13], p[14],
78                               p[15]);
79                p += 16;
80        }
81        puts("OOB:\n");
82        i = nand->oobsize >> 3;
83        while (i--) {
84                printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
85                       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
86                p += 8;
87        }
88        free(datbuf);
89        free(oobbuf);
90
91        return 0;
92}
93
94/* ------------------------------------------------------------------------- */
95
96static inline int str2long(char *p, ulong *num)
97{
98        char *endptr;
99
100        *num = simple_strtoul(p, &endptr, 16);
101        return (*p != '\0' && *endptr == '\0') ? 1 : 0;
102}
103
104static int
105arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
106{
107        int idx = nand_curr_device;
108#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
109        struct mtd_device *dev;
110        struct part_info *part;
111        u8 pnum;
112
113        if (argc >= 1 && !(str2long(argv[0], off))) {
114                if ((mtdparts_init() == 0) &&
115                    (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) {
116                        if (dev->id->type != MTD_DEV_TYPE_NAND) {
117                                puts("not a NAND device\n");
118                                return -1;
119                        }
120                        *off = part->offset;
121                        if (argc >= 2) {
122                                if (!(str2long(argv[1], (ulong *)size))) {
123                                        printf("'%s' is not a number\n", argv[1]);
124                                        return -1;
125                                }
126                                if (*size > part->size)
127                                        *size = part->size;
128                        } else {
129                                *size = part->size;
130                        }
131                        idx = dev->id->num;
132                        *nand = nand_info[idx];
133                        goto out;
134                }
135        }
136#endif
137
138        if (argc >= 1) {
139                if (!(str2long(argv[0], off))) {
140                        printf("'%s' is not a number\n", argv[0]);
141                        return -1;
142                }
143        } else {
144                *off = 0;
145        }
146
147        if (argc >= 2) {
148                if (!(str2long(argv[1], (ulong *)size))) {
149                        printf("'%s' is not a number\n", argv[1]);
150                        return -1;
151                }
152        } else {
153                *size = nand->size - *off;
154        }
155
156#if  defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
157out:
158#endif
159        printf("device %d ", idx);
160        if (*size == nand->size)
161                puts("whole chip\n");
162        else
163                printf("offset 0x%lx, size 0x%x\n", *off, *size);
164        return 0;
165}
166
167int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
168{
169        int i, dev, ret = 0;
170        ulong addr, off;
171        size_t size;
172        char *cmd, *s;
173        nand_info_t *nand;
174#ifdef CFG_NAND_QUIET
175        int quiet = CFG_NAND_QUIET;
176#else
177        int quiet = 0;
178#endif
179        const char *quiet_str = getenv("quiet");
180
181        /* at least two arguments please */
182        if (argc < 2)
183                goto usage;
184
185        if (quiet_str)
186                quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
187
188        cmd = argv[1];
189
190        if (strcmp(cmd, "info") == 0) {
191
192                putc('\n');
193                for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
194                        if (nand_info[i].name)
195                                printf("Device %d: %s, sector size %u KiB\n",
196                                       i, nand_info[i].name,
197                                       nand_info[i].erasesize >> 10);
198                }
199                return 0;
200        }
201
202        if (strcmp(cmd, "device") == 0) {
203
204                if (argc < 3) {
205                        if ((nand_curr_device < 0) ||
206                            (nand_curr_device >= CFG_MAX_NAND_DEVICE))
207                                puts("\nno devices available\n");
208                        else
209                                printf("\nDevice %d: %s\n", nand_curr_device,
210                                       nand_info[nand_curr_device].name);
211                        return 0;
212                }
213                dev = (int)simple_strtoul(argv[2], NULL, 10);
214                if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
215                        puts("No such device\n");
216                        return 1;
217                }
218                printf("Device %d: %s", dev, nand_info[dev].name);
219                puts("... is now current device\n");
220                nand_curr_device = dev;
221
222#ifdef CFG_NAND_SELECT_DEVICE
223                /*
224                 * Select the chip in the board/cpu specific driver
225                 */
226                board_nand_select_device(nand_info[dev].priv, dev);
227#endif
228
229                return 0;
230        }
231
232        if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
233            strncmp(cmd, "dump", 4) != 0 &&
234            strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
235            strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
236            strcmp(cmd, "biterr") != 0 &&
237            strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
238                goto usage;
239
240        /* the following commands operate on the current device */
241        if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE ||
242            !nand_info[nand_curr_device].name) {
243                puts("\nno devices available\n");
244                return 1;
245        }
246        nand = &nand_info[nand_curr_device];
247
248        if (strcmp(cmd, "bad") == 0) {
249                printf("\nDevice %d bad blocks:\n", nand_curr_device);
250                for (off = 0; off < nand->size; off += nand->erasesize)
251                        if (nand_block_isbad(nand, off))
252                                printf("  %08lx\n", off);
253                return 0;
254        }
255
256        /*
257         * Syntax is:
258         *   0    1     2       3    4
259         *   nand erase [clean] [off size]
260         */
261        if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
262                nand_erase_options_t opts;
263                /* "clean" at index 2 means request to write cleanmarker */
264                int clean = argc > 2 && !strcmp("clean", argv[2]);
265                int o = clean ? 3 : 2;
266                int scrub = !strcmp(cmd, "scrub");
267
268                printf("\nNAND %s: ", scrub ? "scrub" : "erase");
269                /* skip first two or three arguments, look for offset and size */
270                if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
271                        return 1;
272
273                memset(&opts, 0, sizeof(opts));
274                opts.offset = off;
275                opts.length = size;
276                opts.jffs2  = clean;
277                opts.quiet  = quiet;
278
279                if (scrub) {
280                        puts("Warning: "
281                             "scrub option will erase all factory set "
282                             "bad blocks!\n"
283                             "         "
284                             "There is no reliable way to recover them.\n"
285                             "         "
286                             "Use this command only for testing purposes "
287                             "if you\n"
288                             "         "
289                             "are sure of what you are doing!\n"
290                             "\nReally scrub this NAND flash? <y/N>\n");
291
292                        if (getc() == 'y' && getc() == '\r') {
293                                opts.scrub = 1;
294                        } else {
295                                puts("scrub aborted\n");
296                                return -1;
297                        }
298                }
299                ret = nand_erase_opts(nand, &opts);
300                printf("%s\n", ret ? "ERROR" : "OK");
301
302                return ret == 0 ? 0 : 1;
303        }
304
305        if (strncmp(cmd, "dump", 4) == 0) {
306                if (argc < 3)
307                        goto usage;
308
309                s = strchr(cmd, '.');
310                off = (int)simple_strtoul(argv[2], NULL, 16);
311
312                if (s != NULL && strcmp(s, ".oob") == 0)
313                        ret = nand_dump(nand, off, 1);
314                else
315                        ret = nand_dump(nand, off, 0);
316
317                return ret == 0 ? 1 : 0;
318
319        }
320
321        if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
322                int read;
323
324                if (argc < 4)
325                        goto usage;
326
327                addr = (ulong)simple_strtoul(argv[2], NULL, 16);
328
329                read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
330                printf("\nNAND %s: ", read ? "read" : "write");
331                if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
332                        return 1;
333
334                s = strchr(cmd, '.');
335                if (!s || !strcmp(s, ".jffs2") ||
336                    !strcmp(s, ".e") || !strcmp(s, ".i")) {
337                        if (read)
338                                ret = nand_read_skip_bad(nand, off, &size,
339                                                         (u_char *)addr);
340                        else
341                                ret = nand_write_skip_bad(nand, off, &size,
342                                                          (u_char *)addr);
343                } else if (s != NULL && !strcmp(s, ".oob")) {
344                        /* out-of-band data */
345                        mtd_oob_ops_t ops = {
346                                .oobbuf = (u8 *)addr,
347                                .ooblen = size,
348                                .mode = MTD_OOB_RAW
349                        };
350
351                        if (read)
352                                ret = nand->read_oob(nand, off, &ops);
353                        else
354                                ret = nand->write_oob(nand, off, &ops);
355                } else {
356                        printf("Unknown nand command suffix '%s'.\n", s);
357                        return 1;
358                }
359
360                printf(" %d bytes %s: %s\n", size,
361                       read ? "read" : "written", ret ? "ERROR" : "OK");
362
363                return ret == 0 ? 0 : 1;
364        }
365
366        if (strcmp(cmd, "markbad") == 0) {
367                addr = (ulong)simple_strtoul(argv[2], NULL, 16);
368
369                int ret = nand->block_markbad(nand, addr);
370                if (ret == 0) {
371                        printf("block 0x%08lx successfully marked as bad\n",
372                               (ulong) addr);
373                        return 0;
374                } else {
375                        printf("block 0x%08lx NOT marked as bad! ERROR %d\n",
376                               (ulong) addr, ret);
377                }
378                return 1;
379        }
380
381        if (strcmp(cmd, "biterr") == 0) {
382                /* todo */
383                return 1;
384        }
385
386        if (strcmp(cmd, "lock") == 0) {
387                int tight  = 0;
388                int status = 0;
389                if (argc == 3) {
390                        if (!strcmp("tight", argv[2]))
391                                tight = 1;
392                        if (!strcmp("status", argv[2]))
393                                status = 1;
394                }
395/*
396 * ! BROKEN !
397 *
398 * TODO: must be implemented and tested by someone with HW
399 */
400#if 0
401                if (status) {
402                        ulong block_start = 0;
403                        ulong off;
404                        int last_status = -1;
405
406                        struct nand_chip *nand_chip = nand->priv;
407                        /* check the WP bit */
408                        nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);
409                        printf("device is %swrite protected\n",
410                               (nand_chip->read_byte(nand) & 0x80 ?
411                               "NOT " : ""));
412
413                        for (off = 0; off < nand->size; off += nand->writesize) {
414                                int s = nand_get_lock_status(nand, off);
415
416                                /* print message only if status has changed
417                                 * or at end of chip
418                                 */
419                                if (off == nand->size - nand->writesize
420                                    || (s != last_status && off != 0))  {
421
422                                        printf("%08lx - %08lx: %8d pages %s%s%s\n",
423                                               block_start,
424                                               off-1,
425                                               (off-block_start)/nand->writesize,
426                                               ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
427                                               ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
428                                               ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
429                                }
430
431                                last_status = s;
432                        }
433                } else {
434                        if (!nand_lock(nand, tight)) {
435                                puts("NAND flash successfully locked\n");
436                        } else {
437                                puts("Error locking NAND flash\n");
438                                return 1;
439                        }
440                }
441#endif
442                return 0;
443        }
444
445        if (strcmp(cmd, "unlock") == 0) {
446                if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
447                        return 1;
448
449/*
450 * ! BROKEN !
451 *
452 * TODO: must be implemented and tested by someone with HW
453 */
454#if 0
455                if (!nand_unlock(nand, off, size)) {
456                        puts("NAND flash successfully unlocked\n");
457                } else {
458                        puts("Error unlocking NAND flash, "
459                             "write and erase will probably fail\n");
460                        return 1;
461                }
462#endif
463                return 0;
464        }
465
466usage:
467        printf("Usage:\n%s\n", cmdtp->usage);
468        return 1;
469}
470
471U_BOOT_CMD(nand, 5, 1, do_nand,
472           "nand - NAND sub-system\n",
473           "info - show available NAND devices\n"
474           "nand device [dev] - show or set current device\n"
475           "nand read - addr off|partition size\n"
476           "nand write - addr off|partition size\n"
477           "    read/write 'size' bytes starting at offset 'off'\n"
478           "    to/from memory address 'addr', skipping bad blocks.\n"
479           "nand erase [clean] [off size] - erase 'size' bytes from\n"
480           "    offset 'off' (entire device if not specified)\n"
481           "nand bad - show bad blocks\n"
482           "nand dump[.oob] off - dump page\n"
483           "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
484           "nand markbad off - mark bad block at offset (UNSAFE)\n"
485           "nand biterr off - make a bit error at offset (UNSAFE)\n"
486           "nand lock [tight] [status]\n"
487           "    bring nand to lock state or display locked pages\n"
488           "nand unlock [offset] [size] - unlock section\n");
489
490static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
491                           ulong offset, ulong addr, char *cmd)
492{
493        int r;
494        char *ep, *s;
495        size_t cnt;
496        image_header_t *hdr;
497#if defined(CONFIG_FIT)
498        const void *fit_hdr = NULL;
499#endif
500
501        s = strchr(cmd, '.');
502        if (s != NULL &&
503            (strcmp(s, ".jffs2") && !strcmp(s, ".e") && !strcmp(s, ".i"))) {
504                printf("Unknown nand load suffix '%s'\n", s);
505                show_boot_progress(-53);
506                return 1;
507        }
508
509        printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);
510
511        cnt = nand->writesize;
512        r = nand_read(nand, offset, &cnt, (u_char *) addr);
513        if (r) {
514                puts("** Read error\n");
515                show_boot_progress (-56);
516                return 1;
517        }
518        show_boot_progress (56);
519
520        switch (genimg_get_format ((void *)addr)) {
521        case IMAGE_FORMAT_LEGACY:
522                hdr = (image_header_t *)addr;
523
524                show_boot_progress (57);
525                image_print_contents (hdr);
526
527                cnt = image_get_image_size (hdr);
528                break;
529#if defined(CONFIG_FIT)
530        case IMAGE_FORMAT_FIT:
531                fit_hdr = (const void *)addr;
532                puts ("Fit image detected...\n");
533
534                cnt = fit_get_size (fit_hdr);
535                break;
536#endif
537        default:
538                show_boot_progress (-57);
539                puts ("** Unknown image type\n");
540                return 1;
541        }
542        show_boot_progress (57);
543
544        /* FIXME: skip bad blocks */
545        r = nand_read(nand, offset, &cnt, (u_char *) addr);
546        if (r) {
547                puts("** Read error\n");
548                show_boot_progress (-58);
549                return 1;
550        }
551        show_boot_progress (58);
552
553#if defined(CONFIG_FIT)
554        /* This cannot be done earlier, we need complete FIT image in RAM first */
555        if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
556                if (!fit_check_format (fit_hdr)) {
557                        show_boot_progress (-150);
558                        puts ("** Bad FIT image format\n");
559                        return 1;
560                }
561                show_boot_progress (151);
562                fit_print_contents (fit_hdr);
563        }
564#endif
565
566        /* Loading ok, update default load address */
567
568        load_addr = addr;
569
570        /* Check if we should attempt an auto-start */
571        if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
572                char *local_args[2];
573                extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
574
575                local_args[0] = cmd;
576                local_args[1] = NULL;
577
578                printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
579
580                do_bootm(cmdtp, 0, 1, local_args);
581                return 1;
582        }
583        return 0;
584}
585
586int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
587{
588        char *boot_device = NULL;
589        int idx;
590        ulong addr, offset = 0;
591#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
592        struct mtd_device *dev;
593        struct part_info *part;
594        u8 pnum;
595
596        if (argc >= 2) {
597                char *p = (argc == 2) ? argv[1] : argv[2];
598                if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
599                    (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
600                        if (dev->id->type != MTD_DEV_TYPE_NAND) {
601                                puts("Not a NAND device\n");
602                                return 1;
603                        }
604                        if (argc > 3)
605                                goto usage;
606                        if (argc == 3)
607                                addr = simple_strtoul(argv[1], NULL, 16);
608                        else
609                                addr = CFG_LOAD_ADDR;
610                        return nand_load_image(cmdtp, &nand_info[dev->id->num],
611                                               part->offset, addr, argv[0]);
612                }
613        }
614#endif
615
616        show_boot_progress(52);
617        switch (argc) {
618        case 1:
619                addr = CFG_LOAD_ADDR;
620                boot_device = getenv("bootdevice");
621                break;
622        case 2:
623                addr = simple_strtoul(argv[1], NULL, 16);
624                boot_device = getenv("bootdevice");
625                break;
626        case 3:
627                addr = simple_strtoul(argv[1], NULL, 16);
628                boot_device = argv[2];
629                break;
630        case 4:
631                addr = simple_strtoul(argv[1], NULL, 16);
632                boot_device = argv[2];
633                offset = simple_strtoul(argv[3], NULL, 16);
634                break;
635        default:
636#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
637usage:
638#endif
639                printf("Usage:\n%s\n", cmdtp->usage);
640                show_boot_progress(-53);
641                return 1;
642        }
643
644        show_boot_progress(53);
645        if (!boot_device) {
646                puts("\n** No boot device **\n");
647                show_boot_progress(-54);
648                return 1;
649        }
650        show_boot_progress(54);
651
652        idx = simple_strtoul(boot_device, NULL, 16);
653
654        if (idx < 0 || idx >= CFG_MAX_NAND_DEVICE || !nand_info[idx].name) {
655                printf("\n** Device %d not available\n", idx);
656                show_boot_progress(-55);
657                return 1;
658        }
659        show_boot_progress(55);
660
661        return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]);
662}
663
664U_BOOT_CMD(nboot, 4, 1, do_nandboot,
665        "nboot   - boot from NAND device\n",
666        "[partition] | [[[loadAddr] dev] offset]\n");
667
668#endif
669
670#else /* CONFIG_NAND_LEGACY */
671/*
672 *
673 * Legacy NAND support - to be phased out
674 *
675 */
676#include <command.h>
677#include <malloc.h>
678#include <asm/io.h>
679#include <watchdog.h>
680
681#ifdef CONFIG_show_boot_progress
682# include <status_led.h>
683# define show_boot_progress(arg)        show_boot_progress(arg)
684#else
685# define show_boot_progress(arg)
686#endif
687
688#if defined(CONFIG_CMD_NAND)
689#include <linux/mtd/nand_legacy.h>
690#if 0
691#include <linux/mtd/nand_ids.h>
692#include <jffs2/jffs2.h>
693#endif
694
695#ifdef CONFIG_OMAP1510
696void archflashwp(void *archdata, int wp);
697#endif
698
699#define ROUND_DOWN(value,boundary)      ((value) & (~((boundary)-1)))
700
701#undef  NAND_DEBUG
702#undef  PSYCHO_DEBUG
703
704/* ****************** WARNING *********************
705 * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will
706 * erase (or at least attempt to erase) blocks that are marked
707 * bad. This can be very handy if you are _sure_ that the block
708 * is OK, say because you marked a good block bad to test bad
709 * block handling and you are done testing, or if you have
710 * accidentally marked blocks bad.
711 *
712 * Erasing factory marked bad blocks is a _bad_ idea. If the
713 * erase succeeds there is no reliable way to find them again,
714 * and attempting to program or erase bad blocks can affect
715 * the data in _other_ (good) blocks.
716 */
717#define  ALLOW_ERASE_BAD_DEBUG 0
718
719#define CONFIG_MTD_NAND_ECC  /* enable ECC */
720#define CONFIG_MTD_NAND_ECC_JFFS2
721
722/* bits for nand_legacy_rw() `cmd'; or together as needed */
723#define NANDRW_READ         0x01
724#define NANDRW_WRITE        0x00
725#define NANDRW_JFFS2        0x02
726#define NANDRW_JFFS2_SKIP   0x04
727
728/*
729 * Imports from nand_legacy.c
730 */
731extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
732extern int curr_device;
733extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs,
734                            size_t len, int clean);
735extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start,
736                         size_t len, size_t *retlen, u_char *buf);
737extern void nand_print(struct nand_chip *nand);
738extern void nand_print_bad(struct nand_chip *nand);
739extern int nand_read_oob(struct nand_chip *nand, size_t ofs,
740                               size_t len, size_t *retlen, u_char *buf);
741extern int nand_write_oob(struct nand_chip *nand, size_t ofs,
742                                size_t len, size_t *retlen, const u_char *buf);
743
744
745int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
746{
747        int rcode = 0;
748
749        switch (argc) {
750        case 0:
751        case 1:
752                printf ("Usage:\n%s\n", cmdtp->usage);
753                return 1;
754        case 2:
755                if (strcmp (argv[1], "info") == 0) {
756                        int i;
757
758                        putc ('\n');
759
760                        for (i = 0; i < CFG_MAX_NAND_DEVICE; ++i) {
761                                if (nand_dev_desc[i].ChipID ==
762                                    NAND_ChipID_UNKNOWN)
763                                        continue;       /* list only known devices */
764                                printf ("Device %d: ", i);
765                                nand_print (&nand_dev_desc[i]);
766                        }
767                        return 0;
768
769                } else if (strcmp (argv[1], "device") == 0) {
770                        if ((curr_device < 0)
771                            || (curr_device >= CFG_MAX_NAND_DEVICE)) {
772                                puts ("\nno devices available\n");
773                                return 1;
774                        }
775                        printf ("\nDevice %d: ", curr_device);
776                        nand_print (&nand_dev_desc[curr_device]);
777                        return 0;
778
779                } else if (strcmp (argv[1], "bad") == 0) {
780                        if ((curr_device < 0)
781                            || (curr_device >= CFG_MAX_NAND_DEVICE)) {
782                                puts ("\nno devices available\n");
783                                return 1;
784                        }
785                        printf ("\nDevice %d bad blocks:\n", curr_device);
786                        nand_print_bad (&nand_dev_desc[curr_device]);
787                        return 0;
788
789                }
790                printf ("Usage:\n%s\n", cmdtp->usage);
791                return 1;
792        case 3:
793                if (strcmp (argv[1], "device") == 0) {
794                        int dev = (int) simple_strtoul (argv[2], NULL, 10);
795
796                        printf ("\nDevice %d: ", dev);
797                        if (dev >= CFG_MAX_NAND_DEVICE) {
798                                puts ("unknown device\n");
799                                return 1;
800                        }
801                        nand_print (&nand_dev_desc[dev]);
802                        /*nand_print (dev); */
803
804                        if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
805                                return 1;
806                        }
807
808                        curr_device = dev;
809
810                        puts ("... is now current device\n");
811
812                        return 0;
813                } else if (strcmp (argv[1], "erase") == 0
814                           && strcmp (argv[2], "clean") == 0) {
815                        struct nand_chip *nand = &nand_dev_desc[curr_device];
816                        ulong off = 0;
817                        ulong size = nand->totlen;
818                        int ret;
819
820                        printf ("\nNAND erase: device %d offset %ld, size %ld ... ", curr_device, off, size);
821
822                        ret = nand_legacy_erase (nand, off, size, 1);
823
824                        printf ("%s\n", ret ? "ERROR" : "OK");
825
826                        return ret;
827                }
828
829                printf ("Usage:\n%s\n", cmdtp->usage);
830                return 1;
831        default:
832                /* at least 4 args */
833
834                if (strncmp (argv[1], "read", 4) == 0 ||
835                    strncmp (argv[1], "write", 5) == 0) {
836                        ulong addr = simple_strtoul (argv[2], NULL, 16);
837                        off_t off = simple_strtoul (argv[3], NULL, 16);
838                        size_t size = simple_strtoul (argv[4], NULL, 16);
839                        int cmd = (strncmp (argv[1], "read", 4) == 0) ?
840                                  NANDRW_READ : NANDRW_WRITE;
841                        size_t total;
842                        int ret;
843                        char *cmdtail = strchr (argv[1], '.');
844
845                        if (cmdtail && !strncmp (cmdtail, ".oob", 2)) {
846                                /* read out-of-band data */
847                                if (cmd & NANDRW_READ) {
848                                        ret = nand_read_oob (nand_dev_desc + curr_device,
849                                                             off, size, &total,
850                                                             (u_char *) addr);
851                                } else {
852                                        ret = nand_write_oob (nand_dev_desc + curr_device,
853                                                              off, size, &total,
854                                                              (u_char *) addr);
855                                }
856                                return ret;
857                        } else if (cmdtail && !strncmp (cmdtail, ".jffs2", 2))
858                                cmd |= NANDRW_JFFS2;    /* skip bad blocks */
859                        else if (cmdtail && !strncmp (cmdtail, ".jffs2s", 2)) {
860                                cmd |= NANDRW_JFFS2;    /* skip bad blocks (on read too) */
861                                if (cmd & NANDRW_READ)
862                                        cmd |= NANDRW_JFFS2_SKIP;       /* skip bad blocks (on read too) */
863                        }
864#ifdef SXNI855T
865                        /* need ".e" same as ".j" for compatibility with older units */
866                        else if (cmdtail && !strcmp (cmdtail, ".e"))
867                                cmd |= NANDRW_JFFS2;    /* skip bad blocks */
868#endif
869#ifdef CFG_NAND_SKIP_BAD_DOT_I
870                        /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */
871                        /* ".i" for image -> read skips bad block (no 0xff) */
872                        else if (cmdtail && !strcmp (cmdtail, ".i")) {
873                                cmd |= NANDRW_JFFS2;    /* skip bad blocks (on read too) */
874                                if (cmd & NANDRW_READ)
875                                        cmd |= NANDRW_JFFS2_SKIP;       /* skip bad blocks (on read too) */
876                        }
877#endif /* CFG_NAND_SKIP_BAD_DOT_I */
878                        else if (cmdtail) {
879                                printf ("Usage:\n%s\n", cmdtp->usage);
880                                return 1;
881                        }
882
883                        printf ("\nNAND %s: device %d offset %ld, size %lu ...\n",
884                                (cmd & NANDRW_READ) ? "read" : "write",
885                                curr_device, off, (ulong)size);
886
887                        ret = nand_legacy_rw (nand_dev_desc + curr_device,
888                                              cmd, off, size,
889                                              &total, (u_char *) addr);
890
891                        printf (" %d bytes %s: %s\n", total,
892                                (cmd & NANDRW_READ) ? "read" : "written",
893                                ret ? "ERROR" : "OK");
894
895                        return ret;
896                } else if (strcmp (argv[1], "erase") == 0 &&
897                           (argc == 4 || strcmp ("clean", argv[2]) == 0)) {
898                        int clean = argc == 5;
899                        ulong off =
900                                simple_strtoul (argv[2 + clean], NULL, 16);
901                        ulong size =
902                                simple_strtoul (argv[3 + clean], NULL, 16);
903                        int ret;
904
905                        printf ("\nNAND erase: device %d offset %ld, size %ld ...\n",
906                                curr_device, off, size);
907
908                        ret = nand_legacy_erase (nand_dev_desc + curr_device,
909                                                 off, size, clean);
910
911                        printf ("%s\n", ret ? "ERROR" : "OK");
912
913                        return ret;
914                } else {
915                        printf ("Usage:\n%s\n", cmdtp->usage);
916                        rcode = 1;
917                }
918
919                return rcode;
920        }
921}
922
923U_BOOT_CMD(
924        nand,   5,      1,      do_nand,
925        "nand    - legacy NAND sub-system\n",
926        "info  - show available NAND devices\n"
927        "nand device [dev] - show or set current device\n"
928        "nand read[.jffs2[s]]  addr off size\n"
929        "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
930        "    at offset `off' to/from memory address `addr'\n"
931        "nand erase [clean] [off size] - erase `size' bytes from\n"
932        "    offset `off' (entire device if not specified)\n"
933        "nand bad - show bad blocks\n"
934        "nand read.oob addr off size - read out-of-band data\n"
935        "nand write.oob addr off size - read out-of-band data\n"
936);
937
938int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
939{
940        char *boot_device = NULL;
941        char *ep;
942        int dev;
943        ulong cnt;
944        ulong addr;
945        ulong offset = 0;
946        image_header_t *hdr;
947        int rcode = 0;
948#if defined(CONFIG_FIT)
949        const void *fit_hdr = NULL;
950#endif
951
952        show_boot_progress (52);
953        switch (argc) {
954        case 1:
955                addr = CFG_LOAD_ADDR;
956                boot_device = getenv ("bootdevice");
957                break;
958        case 2:
959                addr = simple_strtoul(argv[1], NULL, 16);
960                boot_device = getenv ("bootdevice");
961                break;
962        case 3:
963                addr = simple_strtoul(argv[1], NULL, 16);
964                boot_device = argv[2];
965                break;
966        case 4:
967                addr = simple_strtoul(argv[1], NULL, 16);
968                boot_device = argv[2];
969                offset = simple_strtoul(argv[3], NULL, 16);
970                break;
971        default:
972                printf ("Usage:\n%s\n", cmdtp->usage);
973                show_boot_progress (-53);
974                return 1;
975        }
976
977        show_boot_progress (53);
978        if (!boot_device) {
979                puts ("\n** No boot device **\n");
980                show_boot_progress (-54);
981                return 1;
982        }
983        show_boot_progress (54);
984
985        dev = simple_strtoul(boot_device, &ep, 16);
986
987        if ((dev >= CFG_MAX_NAND_DEVICE) ||
988            (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) {
989                printf ("\n** Device %d not available\n", dev);
990                show_boot_progress (-55);
991                return 1;
992        }
993        show_boot_progress (55);
994
995        printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n",
996            dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
997            offset);
998
999        if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset,
1000                            SECTORSIZE, NULL, (u_char *)addr)) {
1001                printf ("** Read error on %d\n", dev);
1002                show_boot_progress (-56);
1003                return 1;
1004        }
1005        show_boot_progress (56);
1006
1007        switch (genimg_get_format ((void *)addr)) {
1008        case IMAGE_FORMAT_LEGACY:
1009                hdr = (image_header_t *)addr;
1010                image_print_contents (hdr);
1011
1012                cnt = image_get_image_size (hdr);
1013                cnt -= SECTORSIZE;
1014                break;
1015#if defined(CONFIG_FIT)
1016        case IMAGE_FORMAT_FIT:
1017                fit_hdr = (const void *)addr;
1018                puts ("Fit image detected...\n");
1019
1020                cnt = fit_get_size (fit_hdr);
1021                break;
1022#endif
1023        default:
1024                show_boot_progress (-57);
1025                puts ("** Unknown image type\n");
1026                return 1;
1027        }
1028        show_boot_progress (57);
1029
1030        if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ,
1031                            offset + SECTORSIZE, cnt, NULL,
1032                            (u_char *)(addr+SECTORSIZE))) {
1033                printf ("** Read error on %d\n", dev);
1034                show_boot_progress (-58);
1035                return 1;
1036        }
1037        show_boot_progress (58);
1038
1039#if defined(CONFIG_FIT)
1040        /* This cannot be done earlier, we need complete FIT image in RAM first */
1041        if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
1042                if (!fit_check_format (fit_hdr)) {
1043                        show_boot_progress (-150);
1044                        puts ("** Bad FIT image format\n");
1045                        return 1;
1046                }
1047                show_boot_progress (151);
1048                fit_print_contents (fit_hdr);
1049        }
1050#endif
1051
1052        /* Loading ok, update default load address */
1053
1054        load_addr = addr;
1055
1056        /* Check if we should attempt an auto-start */
1057        if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
1058                char *local_args[2];
1059                extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
1060
1061                local_args[0] = argv[0];
1062                local_args[1] = NULL;
1063
1064                printf ("Automatic boot of image at addr 0x%08lx ...\n", addr);
1065
1066                do_bootm (cmdtp, 0, 1, local_args);
1067                rcode = 1;
1068        }
1069        return rcode;
1070}
1071
1072U_BOOT_CMD(
1073        nboot,  4,      1,      do_nandboot,
1074        "nboot   - boot from NAND device\n",
1075        "loadAddr dev\n"
1076);
1077
1078#endif
1079
1080#endif /* CONFIG_NAND_LEGACY */
Note: See TracBrowser for help on using the repository browser.