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
intnand_erase_opts(nand_info_t*meminfo,constnand_erase_options_t*opts){structjffs2_unknown_node cleanmarker;erase_info_t erase;unsignedlong erase_length, erased_length;/* in blocks */int bbtest =1;int result;int percent_complete =-1;constchar*mtd_device = meminfo->name;structmtd_oob_ops oob_opts;structnand_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;}elseif(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){unsignedlonglong 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);return0;}intdo_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();#ifdefCONFIG_SYS_NAND_QUIETint quiet = CONFIG_SYS_NAND_QUIET;#elseint quiet =0;#endifconstchar*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"))return0;if(strcmp(cmd,"info")==0){spi_nand_info();return0;}if(strcmp(cmd,"device")==0){if(argc <3){putc('\n');if(dev <0|| dev >= CONFIG_SYS_MAX_NAND_DEVICE)puts("no devices available\n");elsenand_print_and_set_info(dev);return0;}
dev =(int)simple_strtoul(argv[2],NULL,10);set_dev(dev);return0;}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",(unsignedlonglong)off);}printf("NAND size is %08llx, Erase size is %08x\n",nand->size, nand->erasesize);return0;}/*
* 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]);//0int scrub_yes = argc >2&&!strcmp("-y", argv[2]);//0int o =(clean || scrub_yes)?3:2;//2int scrub =!strncmp(cmd,"scrub",5);//0int spread =0;int args =2;constchar*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;}elseif(!strcmp(&cmd[5],".part")){
args =1;}elseif(!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;#if0staticinlineintstr2off(constchar*p,loff_t*num){char*endptr;*num =simple_strtoull(p,&endptr,16);return*p !='\0'&&*endptr =='\0';}staticintarg_off(constchar*arg,int*idx,loff_t*off,loff_t*maxsize){nand_info_t*nand =(nand_info_t*)get_mtd_info();if(!str2off(arg, off))returnget_part(arg, idx, off, maxsize);if(*off >= nand->size){puts("Offset exceeds device limit\n");return-1;}*maxsize = nand->size -*off;return0;}// spi_nand erase 0x0 0xe0000//arg_off_size(argc - o/*4-2*/, argv + o/*argv+2*/, &dev, &off, &size)staticintarg_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=0xe0000printf("'%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");elseprintf("offset 0x%llx, size 0x%llx\n",(unsignedlonglong)*off,(unsignedlonglong)*size);return0;}#endifprintf("\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)return1;//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;//0if(scrub/*0*/)){if(!scrub_yes)puts(scrub_warn);if(scrub_yes)
opts.scrub =1;elseif(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;}elseif(_s &&!strncmp(_s,".size",5)){
raw_size =1;}}if(arg_off(argv[3],&dev,&off,&size))return1;if(set_dev(dev))return1;if(argc >4&&!str2long(argv[4],&pagecount)){printf("'%s' is not a number\n", argv[4]);return1;}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)return1;if(set_dev(dev))return1;/* 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);#ifdefCONFIG_CMD_NAND_TRIMFFS}elseif(!strcmp(s,".trimffs")){if(read){printf("Unknown nand command suffix '%s'\n", s);return1;}
ret =nand_write_skip_bad(nand, off,&rwsize,(u_char *)addr,
WITH_DROP_FFS);#endif#ifdefCONFIG_CMD_NAND_YAFFS}elseif(!strcmp(s,".yaffs")){if(read){printf("Unknown nand command suffix '%s'.\n", s);return1;}
ret =nand_write_skip_bad(nand, off,&rwsize,(u_char *)addr, WITH_YAFFS_OOB);#endif}elseif(!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);}elseif(raw){
ret =raw_access(nand, addr, off, pagecount, read,
no_verify);}else{printf("Unknown nand command suffix '%s'.\n", s);return1;}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 */return1;}
usage:returncmd_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"#ifdefCONFIG_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#ifdefCONFIG_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>#defineuint64_tunsignedlongint#defineuint32_tunsignedint#defineint64_tlongintuint32_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)
*/#definedo_div(n,base)({\uint32_t __base =(base);\uint32_t __rem;\(void)(((typeof((n))*)0)==((unsignedlong*)0));\if(((n)>>32)==0){\__rem =(unsignedint)(n)% __base;\(n)=(unsignedint)(n)/ __base;\}else\__rem =__div64_32(&(n), __base);\__rem;\})/* Wrapper for do_div(). Doesn't modify dividend and returns
* the result, not reminder.
*/staticuint64_tlldiv(uint64_t dividend,uint32_t divisor){uint64_t __res = dividend;do_div(__res, divisor);return(__res);}intmain(){#if0char*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.unsignedlong erase_length =lldiv(0xe0000+131072-1,131072);printf("erase_length:%#x.\n", erase_length);unsignedlong n =700;int bbb=7;int percent =do_div(n , bbb);printf("percent:%d, n:%llu.\n", percent, n);#endifint erased_length =0;int erase_length =7;int percent =0;int percent_complete =-1;unsignedlong n =0;longlong erase_addr =0;for(erased_length =0; erased_length < erase_length;){
erase_addr +=131072;
erased_length++;#if1
n = erased_length *100ULL;do_div(n, erase_length);
percent =(int)n;#endifif(percent != percent_complete){
percent_complete = percent;printf("\rErasing at 0x%llx -- %3d%% complete.",
erase_addr, percent);}}return0;}