0
点赞
收藏
分享

微信扫一扫

u-boot中nand-flash read/write-raw-cmd命令调用说明

律楷粑粑 2022-02-03 阅读 25
int do_spi_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
	int ret = 0;
    ulong addr;
    loff_t off, size;
	char *cmd, *s;
    nand_info_t *nand = (nand_info_t *)get_mtd_info();
#ifdef CONFIG_SYS_NAND_QUIET
    int quiet = CONFIG_SYS_NAND_QUIET;
#else
    int quiet = 0;
#endif
    const char *quiet_str = getenv("quiet");
    int dev = nand_curr_device;
    int repeat = flag & CMD_FLAG_REPEAT;

	/* at least two arguments please */
	if (argc<2)
		goto usage;

    if (quiet_str)
        quiet = simple_strtoul(quiet_str, NULL, 0) != 0;

	cmd = argv[1];

    /* Only "dump" is repeatable. */
    if (repeat && strcmp(cmd, "dump"))
        return 0;

    if (strcmp(cmd, "info") == 0) {
		spi_nand_info();
		return 0;
    }

    if (strcmp(cmd, "device") == 0) {
        if (argc < 3) {
            putc('\n');
            if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
                puts("no devices available\n");
            else
                nand_print_and_set_info(dev);
            return 0;
        }

        dev = (int)simple_strtoul(argv[2], NULL, 10);
        set_dev(dev);

        return 0;
    }

    if (strcmp(cmd, "bad") == 0) {
        printf("\nDevice %d bad blocks:\n", dev);
        for (off = 0; off < nand->size; off += nand->erasesize){
            if (nand_block_isbad(nand, off))
                printf("  %08llx\n", (unsigned long long)off);
        }
        printf("NAND size is  %08llx, Erase size is  %08x\n",nand->size, nand->erasesize);
			return 0;
		}

    /*
     * Syntax is:
     *   0    1     2       3    4
     *   nand erase [clean] [off size]
     *   spi_nand erase 0x0 0xe0000
     */
    if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
        nand_erase_options_t opts;
        /* "clean" at index 2 means request to write cleanmarker */
        int clean = argc > 2 && !strcmp("clean", argv[2]); //0
        int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);//0
        int o = (clean || scrub_yes) ? 3 : 2; //2
        int scrub = !strncmp(cmd, "scrub", 5);//0
        int spread = 0;
        int args = 2;
        const char *scrub_warn =
            "Warning: "
            "scrub option will erase all factory set bad blocks!\n"
            "         "
            "There is no reliable way to recover them.\n"
            "         "
            "Use this command only for testing purposes if you\n"
            "         "
            "are sure of what you are doing!\n"
            "\nReally scrub this NAND flash? <y/N>\n";

        if (cmd[5] != 0) {
            if (!strcmp(&cmd[5], ".spread")) {
                spread = 1;
            } else if (!strcmp(&cmd[5], ".part")) {
                args = 1;
            } else if (!strcmp(&cmd[5], ".chip")) {
                args = 0;
            } else {
                goto usage;
            }
        }

        /*
         * Don't allow missing arguments to cause full chip/partition
         * erases -- easy to do accidentally, e.g. with a misspelled
         * variable name.
         */
        if (argc != o + args)
            goto usage;

        printf("\nNAND %s: ", cmd);
        /* skip first two or three arguments, look for offset and size */
        if (arg_off_size(argc - o/*4-2*/, argv + o/*argv+2*/, &dev, &off, &size) != 0)
            return 1;

        //nand = &nand_info[dev];

        memset(&opts, 0, sizeof(opts));
        opts.offset = off;//0x0
        opts.length = size;//0xe0000
        opts.jffs2  = clean;//0
        opts.quiet  = quiet;//0
        opts.spread = spread;//0

        if (scrub/*0*/)) {
            if (!scrub_yes)
                puts(scrub_warn);

            if (scrub_yes)
                opts.scrub = 1;
            else if (getc() == 'y') {
                puts("y");
                if (getc() == '\r')
                    opts.scrub = 1;
                else {
                    puts("scrub aborted\n");
                    return -1;
                }
            } else {
                puts("scrub aborted\n");
                return -1;
            }
        }
        ret = nand_erase_opts(nand, &opts);
        printf("%s\n", ret ? "ERROR" : "OK");

        return ret == 0 ? 0 : 1;
    }

    if (strncmp(cmd, "dump", 4) == 0) {
        if (argc < 3)
            goto usage;

        off = (int)simple_strtoul(argv[2], NULL, 16);
        ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat);

        return ret == 0 ? 1 : 0;
    }

    //spi_nand write.raw 0x81000000 0x0 0xe0000
    if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
        size_t rwsize;
        ulong pagecount = 1;
        int read;
        int raw = 0;
        int no_verify = 0;

        if (argc < 4)
            goto usage;

        addr = (ulong)simple_strtoul(argv[2], NULL, 16);

        read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
        printf("\nNAND %s: ", read ? "read" : "write");

		s = strchr(cmd, '.');
		  spi_nand write.raw.size 0x81000000 0x0 0xe0000
        if (s && !strncmp(s, ".raw", 4)) {
            char *_s = s;
            int raw_size = 0;
            uint32_t raw_unit_size = nand->writesize + nand->oobsize;
            raw = 1;

            while(_s) {
                _s = strchr(_s+1, '.');
                if (_s && !strncmp(_s, ".noverify", 9)) {
                    no_verify = 1;
                } else if (_s && !strncmp(_s, ".size", 5)) {
                    raw_size = 1;
                }
            }
            if (arg_off(argv[3], &dev, &off, &size))
                return 1;

            if (set_dev(dev))
                return 1;


            if (argc > 4 && !str2long(argv[4], &pagecount)) {
                printf("'%s' is not a number\n", argv[4]);
                return 1;
            }

            if (raw_size) { //(0xe0000 + 2048 + 24 - 1) / (2048 + 24) = 448页,448/64 = 7块
                pagecount = (pagecount+(raw_unit_size-1))/raw_unit_size;
                printf("transfer size to %ld page(s),", pagecount);
            }
				
			#是否超出flash最大存储空间大小
            if (pagecount * nand->writesize > size) {
                puts("Size exceeds partition or device limit\n");
                return -1;
            }

            rwsize = pagecount * (raw_unit_size);
		} else {
            if (arg_off_size(argc - 3, argv + 3, &dev, &off,
                         &size) != 0)
                return 1;

            if (set_dev(dev))
                return 1;

            /* size is unspecified */
            if (argc < 5)
                adjust_size_for_badblocks(&size, off, dev);
            rwsize = size;
        }
        if (!s || !strcmp(s, ".jffs2") ||
            !strcmp(s, ".e") || !strcmp(s, ".i")) {
            if (read)
                ret = nand_read_skip_bad(nand, off, &rwsize,
                             (u_char *)addr);
            else
                ret = nand_write_skip_bad(nand, off, &rwsize,
                              (u_char *)addr, 0);
#ifdef CONFIG_CMD_NAND_TRIMFFS
        } else if (!strcmp(s, ".trimffs")) {
            if (read) {
                printf("Unknown nand command suffix '%s'\n", s);
                return 1;
            }
            ret = nand_write_skip_bad(nand, off, &rwsize,
                        (u_char *)addr,
                        WITH_DROP_FFS);
#endif
#ifdef CONFIG_CMD_NAND_YAFFS
        } else if (!strcmp(s, ".yaffs")) {
            if (read) {
                printf("Unknown nand command suffix '%s'.\n", s);
                return 1;
            }
            ret = nand_write_skip_bad(nand, off, &rwsize,
                        (u_char *)addr, WITH_YAFFS_OOB);
#endif
        } else if (!strcmp(s, ".oob")) {
            /* out-of-band data */
            mtd_oob_ops_t ops = {
                .oobbuf = (u8 *)addr,
                .ooblen = rwsize,
                .mode = MTD_OOB_RAW
            };

            if (read)
                ret = nand->read_oob(nand, off, &ops);
            else
                ret = nand->write_oob(nand, off, &ops);
        } else if (raw) {
            ret = raw_access(nand, addr, off, pagecount, read,
                     no_verify);
        } else {
            printf("Unknown nand command suffix '%s'.\n", s);
            return 1;
		}

        printf(" %zu bytes %s: %s\n", rwsize,
               read ? "read" : "written", ret ? "ERROR" : "OK");

        return ret == 0 ? 0 : 1;
    }

    if (strcmp(cmd, "markbad") == 0) {
        argc -= 2;
        argv += 2;

        if (argc <= 0)
            goto usage;

        while (argc > 0) {
            addr = simple_strtoul(*argv, NULL, 16);

            if (nand->block_markbad(nand, addr)) {
                printf("block 0x%08lx NOT marked "
                    "as bad! ERROR %d\n",
                    addr, ret);
                ret = 1;
            } else {
                printf("block 0x%08lx successfully "
                    "marked as bad\n",
                    addr);
            }
            --argc;
            ++argv;
        }
		return ret;
	}

    if (strcmp(cmd, "biterr") == 0) {
        /* todo */
        return 1;
    }

usage:
	return cmd_usage(cmdtp);
}

U_BOOT_CMD(
    spi_nand, CONFIG_SYS_MAXARGS, 1, do_spi_nand,
	"SPI-NAND sub-system",
	"info - show available NAND devices\n"
    "spi_nand device [dev] - show or set current device\n"
    "spi_nand read - addr off|partition size\n"
    "spi_nand write - addr off|partition size\n"
	"    read/write 'size' bytes starting at offset 'off'\n"
    "    to/from memory address 'addr', skipping bad blocks.\n"
    "spi_nand read.raw - addr off|partition [count]\n"
    "spi_nand write.raw[.noverify] - addr off|partition [count]\n"
    "    Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"
    "    'count' is the page count\n"
#ifdef CONFIG_CMD_NAND_TRIMFFS
    "spi_nand write.trimffs - addr off|partition size\n"
    "    write 'size' bytes starting at offset 'off' from memory address\n"
    "    'addr', skipping bad blocks and dropping any pages at the end\n"
    "    of eraseblocks that contain only 0xFF\n"
#endif
#ifdef CONFIG_CMD_NAND_YAFFS
    "spi_nand write.yaffs - addr off|partition size\n"
    "    write 'size' bytes starting at offset 'off' with yaffs format\n"
    "    from memory address 'addr', skipping bad blocks.\n"
#endif
    "spi_nand erase[.spread] [clean] off size - erase 'size' bytes "
	"from offset 'off'\n"
    "    With '.spread', erase enough for given file size, otherwise,\n"
    "    'size' includes skipped bad blocks.\n"
    "spi_nand erase.part [clean] partition - erase entire mtd partition'\n"
    "spi_nand erase.chip [clean] - erase entire chip'\n"
    "spi_nand bad - show bad blocks\n"
    "spi_nand dump[.oob] off - dump page\n"
    "spi_nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
    "    really clean NAND erasing bad blocks (UNSAFE)\n"
    "spi_nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
    "spi_nand biterr off - make a bit error at offset (UNSAFE)"
);

U_BOOT_CMD(
    nand, CONFIG_SYS_MAXARGS, 1, do_spi_nand,
    "NAND sub-system",
    "alias spi_nand"
);
举报

相关推荐

0 条评论