栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

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

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

loaderu-boot-2011.12driversmtdnandnand_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; 
	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 datan");
		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 + 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);

	
	if (opts->scrub) {
		erase.scrub = opts->scrub;
		
		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: %dn",
				       mtd_device,
				       ret);
				return -1;
			}
		}

		erased_length++;

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

		
		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: %dn",
				       mtd_device, result);
				continue;
			}
		}

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

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

			
			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;

	
	if (argc<2)
		goto usage;

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

	cmd = argv[1];

    
    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 availablen");
            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("  %08llxn", (unsigned long long)off);
        }
        printf("NAND size is  %08llx, Erase size is  %08xn",nand->size, nand->erasesize);
			return 0;
		}

    
    if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
        nand_erase_options_t opts;
        
        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 youn"
            "         "
            "are sure of what you are doing!n"
            "nReally scrub this NAND flash? 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;
            }
        }

        
        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 != '' && *endptr == '';
}

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 limitn");
        return -1;
    }

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

// spi_nand erase 0x0 0xe0000
//arg_off_size(argc - o, argv + o, &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 numbern", argv[1]);
        return -1;
    }

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

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

#endif
        printf("nNAND %s: ", cmd);
        
        if (arg_off_size(argc - o, argv + o, &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)) {
            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 abortedn");
                    return -1;
                }
            } else {
                puts("scrub abortedn");
                return -1;
            }
        }
        ret = nand_erase_opts(nand, &opts);
        printf("%sn", 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; 
        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 numbern", 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 limitn");
                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;

            
            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")) {
            
            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: %sn", 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 %dn",
                    addr, ret);
                ret = 1;
            } else {
                printf("block 0x%08lx successfully "
                    "marked as badn",
                    addr);
            }
            --argc;
            ++argv;
        }
		return ret;
	}

    if (strcmp(cmd, "biterr") == 0) {
        
        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 devicesn"
    "spi_nand device [dev] - show or set current devicen"
    "spi_nand read - addr off|partition sizen"
    "spi_nand write - addr off|partition sizen"
	"    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 countn"
#ifdef CONFIG_CMD_NAND_TRIMFFS
    "spi_nand write.trimffs - addr off|partition sizen"
    "    write 'size' bytes starting at offset 'off' from memory addressn"
    "    'addr', skipping bad blocks and dropping any pages at the endn"
    "    of eraseblocks that contain only 0xFFn"
#endif
#ifdef CONFIG_CMD_NAND_YAFFS
    "spi_nand write.yaffs - addr off|partition sizen"
    "    write 'size' bytes starting at offset 'off' with yaffs formatn"
    "    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 blocksn"
    "spi_nand dump[.oob] off - dump pagen"
    "spi_nand scrub [-y] off size | scrub.part partition | scrub.chipn"
    "    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 
#include 

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

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

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


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 != '' && *endptr == '');
	char aa='';
	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;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/728667.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号