u-boot中nand-flash erase-cmd命令调用说明

loader\u-boot-2011.12\drivers\mtd\nand\nand_base.c
可以从mtd的结构体初始化关联出来,每一个mtd设备关联chip指针,最终调用flash硬件接口
mtd->read = nand_erase;  ->   nand_erase_nand(mtd, instr, 0); -> chip->erase_cmd(mtd, page & chip->pagemask);

loader\u-boot-2011.12\drivers\mtd\nand\nand_util.c
int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
{
	struct jffs2_unknown_node cleanmarker;
	erase_info_t erase;
	unsigned long erase_length, erased_length; /* in blocks */
	int bbtest = 1;
	int result;
	int percent_complete = -1;
	const char *mtd_device = meminfo->name;
	struct mtd_oob_ops oob_opts;
	struct nand_chip *chip = meminfo->priv;

	if ((opts->offset & (meminfo->writesize - 1)) != 0) {
		printf("Attempt to erase non page aligned data\n");
		return -1;
	}

	memset(&erase, 0, sizeof(erase));
	memset(&oob_opts, 0, sizeof(oob_opts));

	erase.mtd = meminfo;
	erase.len  = meminfo->erasesize;//64*2048
	erase.addr = opts->offset; //0x0
	erase_length = lldiv(opts->length /*0xe0000*/+ meminfo->erasesize - 1,
			     meminfo->erasesize);  (0xe0000 + 64*2048 - 1) / (64*2048)

	cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
	cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
	cleanmarker.totlen = cpu_to_je32(8);

	/* scrub option allows to erase badblock. To prevent internal
	 * check from erase() method, set block check method to dummy
	 * and disable bad block table while erasing.
	 */
	if (opts->scrub) {
		erase.scrub = opts->scrub;
		/*
		 * We don't need the bad block table anymore...
		 * after scrub, there are no bad blocks left!
		 */
		if (chip->bbt) {
			kfree(chip->bbt);
		}
		chip->bbt = NULL;
	}

	for (erased_length = 0;
	     erased_length < erase_length;
	     erase.addr += meminfo->erasesize) {

		WATCHDOG_RESET ();

		if (!opts->scrub && bbtest) {
			int ret = meminfo->block_isbad(meminfo, erase.addr);
			if (ret > 0) {
				if (!opts->quiet)
					printf("\rSkipping bad block at  "
					       "0x%08llx                 "
					       "                         \n",
					       erase.addr);

				if (!opts->spread)
					erased_length++;

				continue;

			} else if (ret < 0) {
				printf("\n%s: MTD get bad block failed: %d\n",
				       mtd_device,
				       ret);
				return -1;
			}
		}

		erased_length++;

		result = meminfo->erase(meminfo, &erase);
		if (result != 0) {
			printf("\n%s: MTD Erase failure: %d\n",
			       mtd_device, result);
			continue;
		}

		/* format for JFFS2 ? */
		if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
			chip->ops.ooblen = 8;
			chip->ops.datbuf = NULL;
			chip->ops.oobbuf = (uint8_t *)&cleanmarker;
			chip->ops.ooboffs = 0;
			chip->ops.mode = MTD_OOB_AUTO;

			result = meminfo->write_oob(meminfo,
			                            erase.addr,
			                            &chip->ops);
			if (result != 0) {
				printf("\n%s: MTD writeoob failure: %d\n",
				       mtd_device, result);
				continue;
			}
		}

		if (!opts->quiet) {
			unsigned long long n = erased_length * 100ULL;
			int percent;

			do_div(n, erase_length);
			percent = (int)n;

			/* output progress message only at whole percent
			 * steps to reduce the number of messages printed
			 * on (slow) serial consoles
			 */
			if (percent != percent_complete) {
				percent_complete = percent;

				printf("\rErasing at 0x%llx -- %3d%% complete.",
				       erase.addr, percent);

				if (opts->jffs2 && result == 0)
					printf(" Cleanmarker written at 0x%llx.",
					       erase.addr);
			}
		}
	}
	if (!opts->quiet)
		printf("\n");

	if (opts->scrub)
		chip->scan_bbt(meminfo);

	return 0;
}

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;

#if 0

static inline int str2off(const char *p, loff_t *num)
{
    char *endptr;
    *num = simple_strtoull(p, &endptr, 16);
    return *p != '\0' && *endptr == '\0';
}

static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize)
{
    nand_info_t *nand = (nand_info_t *)get_mtd_info();
    if (!str2off(arg, off))
        return get_part(arg, idx, off, maxsize);

    if (*off >= nand->size) {
        puts("Offset exceeds device limit\n");
        return -1;
    }

    *maxsize = nand->size - *off;
    return 0;
}

// spi_nand erase 0x0 0xe0000
//arg_off_size(argc - o/*4-2*/, argv + o/*argv+2*/, &dev, &off, &size)
static int arg_off_size(int argc-2, char *const argv[], int *idx,
            loff_t *off, loff_t *size)
{
    nand_info_t *nand = (nand_info_t *)get_mtd_info();
    int ret;
    loff_t maxsize = 0;

    if (argc == 0) {
        *off = 0;
        *size = nand->size;
        goto print;
    }

    ret = arg_off(argv[0], idx, off, &maxsize);
    if (ret)
        return ret;

    if (argc == 1) {
        *size = maxsize;
        goto print;
    }

    if (!str2off(argv[1], size)) { //size=0xe0000
        printf("'%s' is not a number\n", argv[1]);
        return -1;
    }

    if (*size > maxsize) {
        puts("Size exceeds partition or device limit\n");
        return -1;
    }

print:
    printf("device %d ", *idx);
    if (*size == nand->size)
        puts("whole chip\n");
    else
        printf("offset 0x%llx, size 0x%llx\n",
               (unsigned long long)*off, (unsigned long long)*size);
    return 0;
}

#endif
        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;
    }

    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, '.');

        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) {
                pagecount = (pagecount+(raw_unit_size-1))/raw_unit_size;
                printf("transfer size to %ld page(s),", pagecount);
            }

            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"
);
#测试结果-------擦除
Erasing at 0x20000 --  14% complete.
Erasing at 0x40000 --  28% complete.
Erasing at 0x60000 --  42% complete.
Erasing at 0x80000 --  57% complete.
Erasing at 0xa0000 --  71% complete.
Erasing at 0xc0000 --  85% complete.
Erasing at 0xe0000 -- 100% complete.

#include <stdio.h>
#include <string.h>

#define uint64_t  unsigned long int
#define uint32_t  unsigned  int
#define int64_t  long  int

uint32_t __div64_32(uint64_t *n, uint32_t base)
{
	uint64_t rem = *n;
	uint64_t b = base;
	uint64_t res, d = 1;
	uint32_t high = rem >> 32;

	/* Reduce the thing a bit first */
	res = 0;
	if (high >= base) {
		high /= base;
		res = (uint64_t) high << 32;
		rem -= (uint64_t) (high*base) << 32;
	}

	while ((int64_t)b > 0 && b < rem) {
		b = b+b;
		d = d+d;
	}

	do {
		if (rem >= b) {
			rem -= b;
			res += d;
		}
		b >>= 1;
		d >>= 1;
	} while (d);

	*n = res;
	return rem;
}
/* The unnecessary pointer compare is there
 * to check for type safety (n must be 64bit)
 */
# define do_div(n,base) ({				\
	uint32_t __base = (base);			\
	uint32_t __rem;					\
	(void)(((typeof((n)) *)0) == ((unsigned long *)0));	\
	if (((n) >> 32) == 0) {			\
		__rem = (unsigned int)(n) % __base;		\
		(n) = (unsigned int)(n) / __base;		\
	} else						\
		__rem = __div64_32(&(n), __base);	\
	__rem;						\
 })

/* Wrapper for do_div(). Doesn't modify dividend and returns
 * the result, not reminder.
 */
static  uint64_t lldiv(uint64_t dividend, uint32_t divisor)
{
	uint64_t __res = dividend;
	do_div(__res, divisor);
	return(__res);
}

int main()
{
	#if 0
	char *endptr=NULL;
	char *p="0x0";
	printf("p:%s.\n", p);
	int num = strtoull(p, &endptr, 16);
	printf("p:%s.\n", p);
	int value = ( *p != '\0' && *endptr == '\0');
	char aa='\0';
	printf("num:%d,value:%d,*p:%d,*endptr:%d,aa:%d.\n", num, value, *p,*endptr,aa);
	//p:0x0.
    //p:0x0.
    //num_value:0,value:1,*p:48,*endptr:0,aa:0.
    
	unsigned long erase_length = lldiv(0xe0000+ 131072- 1,
			     131072);	
	printf("erase_length:%#x.\n", erase_length);
	
	unsigned long n = 700; int bbb=7;
	int percent = do_div(n , bbb);
	printf("percent:%d, n:%llu.\n", percent, n);	
	#endif


	int erased_length = 0;
	int erase_length = 7 ;
	int percent = 0;
	int percent_complete = -1;	
	unsigned long n = 0;
	long long erase_addr = 0;
	
	for (erased_length = 0; erased_length < erase_length; ) 
	{
			erase_addr += 131072;
			erased_length++;
			#if 1		
			n = erased_length * 100ULL;					
			do_div(n, erase_length);
			percent = (int)n;
			#endif
			if (percent != percent_complete) 
			{
				percent_complete = percent;
				printf("\rErasing at 0x%llx -- %3d%% complete.",
				      erase_addr, percent);

			}
	}
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

the future c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值