加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Nand flash uboot 驱动研究

发布时间:2020-12-15 07:18:16 所属栏目:百科 来源:网络整理
导读:nand flash初始化 一. ?在lib_arm/board.c中调用了函数nand_init()初始化nand flash: 二. ?nand_flash()定义在drivers/mtd/nand/nand.c中, 在nand_flash()中调用nand_init_chip(),在nand_init_chip()中会调用两个函数, 一个是board_nand_init(),用于初始

nand flash初始化

一.?在lib_arm/board.c中调用了函数nand_init()初始化nand flash:
二.?nand_flash()定义在drivers/mtd/nand/nand.c中, 在nand_flash()中调用nand_init_chip(),在nand_init_chip()中会调用两个函数, 一个是board_nand_init(),用于初始化flash的部分信息, 填充结构体mtd_info mtd,接着会调用nand_scan(),nand_scan()函数会继续填充结构体mtd, 最后会调用this->scan_bbt (mtd), 即:nand_default_bbt(mtd),扫描整个flash, 查找坏块,但是找到坏块以后如何标记的目前还不知道,这时初始化完成。
三.?首先我们看一个函数:board_nand_init(nand):

185 int board_nand_init(struct nand_chip *nand)
186 {
187 u_int32_t cfg;
188 u_int8_t tacls,twrph0,twrph1;
189 S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
190
191 DEBUGN("board_nand_init()n");
192
193 /*
194 * if you have any question,please refer to
195 * /media/study/data/datasheet/cpu/S3C2440A datasheet.pdf
196 * page 7-21 (228/604)
197 * regist:CLKCON addr:0x4C00 000C
198 * description:Clock generator control register.
199 * bit 4:Control HCLK into NAND flash Controller block.
200 * 0 ==> Disable,1 ==> Enable.
201 */
202 clk_power->CLKCON |= (1 << 4); // enable clock,
203
204 twrph0 = 6; twrph1 = 2; tacls = 0;
// nand flash interface init,you can refer to datasheet.
205 cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);
206 NFCONF = cfg;
207 cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);
208 NFCONT = cfg;
209 /* initialize nand_chip data structure */
210 /* dancy note:
211 * set IO_ADDR_R and IO_ADDR_W to 0x4e000010;
212 * because 0x4E00 0010 is NAND Flash data register.
213 */
214 nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
215 /* read_buf and write_buf are default */
216 /* read_byte and write_byte are default */
217 /* hwcontrol always must be implemented */
218 /*函数s3c2410_hwcontrol使用来设置HW的, 如信号CE,也是设置
/*IO_ADDR_W指向的register地址。*/
219 nand->hwcontrol = s3c2410_hwcontrol;
220 nand->dev_ready = s3c2410_dev_ready;
221
222 nand->eccmode = NAND_ECC_SOFT;
//NAND_ECC_SOFT和NAND_ECC_NONE的区别是,NAND_ECC_NONE不会check ECC。
223 //nand->eccmode = NAND_ECC_NONE;
/*这个ECC先去掉,否则你使用nand write命令和nand read会boot 不起内核*/
224 nand->options = 0;
225 DEBUGN("end of nand_initn");
226
227 return 0;
228 }

看函数:s3c2410_hwcontrol()

 80 static void s3c2410_hwcontrol(struct mtd_info *mtd,int cmd)
81 {
82 struct nand_chip *chip = mtd->priv;
83
84 DEBUGN("hwcontrol(): 0x%02x: ",cmd);
85
109 switch (cmd) {
110 /* dancy note:
111 * select NAND flash chip by clean pin CS0.
114 */
115 case NAND_CTL_SETNCE:
116 /*
117 * dancy modify:
118 * orig: NFCONT &= ~S3C2440_NFCONT_nCE;
119 */
120 NFCONT &= ~S3C2440_NFCONT_nCE;
121 DEBUGN("NFCONT=0x%08xn",NFCONT);
122 break;
123 case NAND_CTL_CLRNCE:
124 /*
125 * dancy modify:
126 * orig: NFCONT &= ~S3C2440_NFCONT_nCE;
127 */
128 NFCONT |= S3C2440_NFCONT_nCE;
129 DEBUGN("NFCONT=0x%08xn",NFCONT);
130 break;
/*下面两个case也算是配置HW,也是为了使用同一个函数this->write_byte也就是*/
/*nand_write_byte函数,使用同一个函数,将写地址指向不同的register,来实现*/
/*同一个函数,当通过hwcontrol配置以后,实现不同的功能。*/
131 case NAND_CTL_SETALE:
/*NF_BASE + S3C2440_ADDR_NALE is NAND Flash memory command value*/
132 chip->IO_ADDR_W = NF_BASE + S3C2440_ADDR_NALE;
133 DEBUGN("SETALEn");
134 break;
135 case NAND_CTL_SETCLE:
/*NF_BASE + S3C2440_ADDR_NCLE is NAND Flash command set register*/
136 chip->IO_ADDR_W = NF_BASE + S3C2440_ADDR_NCLE;
137 DEBUGN("SETCLEn");
138 break;
139 default:
/*NF_BASE + 0x10 是data的register--- NAND Flash data register*/
140 chip->IO_ADDR_W = NF_BASE + 0x10; //注意是0x10
141 break;
142 }
143 return?;
144 }

接着研究一下扫描flash的全过程,会设置也会填充mtd:

如果是small page:
this->cmdfunc = nand_command;
如果是big page:
this->cmdfunc = nand_command_lp;
this->waitfunc = nand_wait;
this->select_chip = nand_select_chip;
this->write_byte = busw?? nand_write_byte16?: nand_write_byte;
//但是使用nand_write_byte
this->read_byte = busw?? nand_read_byte16?: nand_read_byte;
this->write_word = nand_write_word;
this->read_word = nand_read_word;
this->block_bad = nand_block_bad;
this->block_markbad = nand_default_block_markbad;
this->write_buf = busw?? nand_write_buf16?: nand_write_buf;
this->read_buf = busw?? nand_read_buf16?: nand_read_buf;
this->verify_buf = busw?? nand_verify_buf16?: nand_verify_buf;
this->scan_bbt = nand_default_bbt;

接着使用命令NAND_CMD_READID读取flash的ID号,会在现支持的flash列表nand_flash_ids中查找现在的flash, 定义在drivers/mtd/nand/nand_ids.c中:
最后找到的是{"NAND 128MiB 3,3V 8-bit",0xF1,128,NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}。
根据flash的型号设置flash的固有的参数:
最后设置的结果为:

page size?:mtd->oobblock = 1024 << (extid & 0x3) = 2K
Redundant Area Size: mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock / 512) = 16*4=64
erase size:mtd->erasesize = (64 * 1024) << (extid & 0x03)=64*1024 << 1 = 128K
busw = 0
this->page_shift = ffs(mtd->oobblock) - 1 = ffs(2048) = 0xb = 11; // how does "ffs" work.
this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1 = ffs(131072) -1 = 0x11 = 17
this->chip_shift = ffs(this->chipsize) - 1 = ffs(134217728)-1 = 0x1b = 27
this->badblockpos = mtd->oobblock > 512??
NAND_LARGE_BADBLOCK_POS?: NAND_SMALL_BADBLOCK_POS = NAND_LARGE_BADBLOCK_POS
len = mtd->oobsize << (this->phys_erase_shift - this->page_shift)
= 64 << (17 - 11) = 64 << 6 = 4096; this->oob_buf = kmalloc (len,GFP_KERNEL);
led = len = mtd->oobblock + mtd->oobsize = 2048 + 64 = 2112?;
this->data_buf = kmalloc (len,GFP_KERNEL);
this->autooob = &nand_oob_64;
mtd->oobavail += this->autooob->oobfree[i][1]; //???????????????
this->eccsize = 256
this->eccbytes = 3;
this->calculate_ecc = nand_calculate_ecc;
this->correct_data = nand_correct_data;
this->eccsteps = mtd->oobblock / 256 = 2048 / 256 = 8;
//作用:需要执行8次来作ECC校验, 每次只能对256byte作校验。
this->pagebuf = -1;
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
mtd->ecctype = MTD_ECC_SW;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_ecc = nand_read_ecc;
mtd->write_ecc = nand_write_ecc;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
this->erase_cmd = single_erase_cmd;

最后调用:

2730     return this->scan_bbt (mtd);    //也就是nand_default_bbt(mtd)

这个函数还没有研究, 以后研究。


常用部分函数

在nand_scan函数中会check是small page还是big page的flash:

2450         /* Do not replace user supplied command function?! */
2451 if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
2452 this->cmdfunc = nand_command_lp;

如果是big page,使用nand_command_lp来对flash操作。
1. nand_command

/**
* nand_command - [DEFAULT] Send command to NAND device
* @mtd: MTD device structure
* @command: the command to be sent
* @column: the column address for this command,-1 if none
* @page_addr: the page address for this command,-1 if none
*
* Send command to NAND device. This function is used for small page
* devices (256/512 Bytes per page)
*/
static void nand_command (struct mtd_info *mtd,unsigned command,int column,int page_addr)
{
register struct nand_chip *this = mtd->priv;

/* Begin command latch cycle */
this->hwcontrol(mtd,NAND_CTL_SETCLE); //选择写入S3C2410_NFCMD寄存器
/*
* Write out the command to the device.
*/
/* 指令NAND_CMD_SEQIN只有在small page上,而且随机写的时候才可以用到,下面在将write oob的时候还会介绍。*/
if (command == NAND_CMD_SEQIN) {
int readcmd;

if (column >= mtd->oobblock) { //读/写位置超出512,读oob_data
/* OOB area */
column -= mtd->oobblock;
readcmd = NAND_CMD_READOOB;
} else if (column < 256) { //读/写位置在前256,使用read0命令
/* First 256 bytes --> READ0 */
readcmd = NAND_CMD_READ0;
} else { //读/写位置在后256,使用read1命令
column -= 256;
readcmd = NAND_CMD_READ1;
}
this->write_byte(mtd,readcmd); //写入具体命令
}
this->write_byte(mtd,command);

/* Set ALE and clear CLE to start address cycle */
this->hwcontrol(mtd,NAND_CTL_CLRCLE);

if (column?!= -1 || page_addr?!= -1) {
/*将chip->IO_ADDR_W 指向 NF_BASE + S3C2440_ADDR_NALE,*/
/*下面的this->write_byte是直接向IO_ADDR_W写值的,这样就实现了同一个函数*/
/*既可以写指令,也可以地址,也可以写数据*/
132 chip->IO_ADDR_W = NF_BASE + S3C2440_ADDR_NALE;*/
this->hwcontrol(mtd,NAND_CTL_SETALE); //选择写入S3C2410_NFADDR寄存器

/* Serially input address */
if (column?!= -1) {
/* Adjust columns for 16 bit buswidth */
if (this->options & NAND_BUSWIDTH_16)
column >>= 1;
this->write_byte(mtd,column); //写入列地址
}
if (page_addr?!= -1) { //写入页地址(分三个字节写入)
this->write_byte(mtd,(unsigned char) (page_addr & 0xff));
this->write_byte(mtd,(unsigned char) ((page_addr >> 8) & 0xff));
/* One more address cycle for devices > 32MiB */
if (this->chipsize > (32 << 20))
this->write_byte(mtd,(unsigned char) ((page_addr >> 16) & 0x0f));
}
/* Latch in address */
/* 锁存地址 */
this->hwcontrol(mtd,NAND_CTL_CLRALE);
}

/*
* program and erase have their own busy handlers
* status and sequential in needs no delay
*/
switch (command) {

case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
return;

case NAND_CMD_RESET: //复位操作
// 等待nand flash become ready
if (this->dev_ready) //判断nand flash 是否busy(1:ready 0:busy)
break;
udelay(this->chip_delay);
this->hwcontrol(mtd,NAND_CTL_SETCLE);
this->write_byte(mtd,NAND_CMD_STATUS);
this->hwcontrol(mtd,NAND_CTL_CLRCLE);
while (?!(this->read_byte(mtd) & NAND_STATUS_READY));
return;

/* This applies to read commands */
default:
/*
* If we don't have access to the busy pin,we apply the given
* command delay
*/
if (!this->dev_ready) {
udelay (this->chip_delay);//稍作延迟
return;
}
}
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
ndelay (100);

nand_wait_ready(mtd);
}

同理nand_command_lp,只是对地址的操作不一样, 机制也有点不一样,下面有区别的时候会介绍到。


uboot 读nand flash

共提供了三个函数读取flash, 三个函数功能都不一样, 所有函数的定义在drivers/mtd/nand/nand_base.c中


nand_read_raw

只是读取, 不做ECC check。

int nand_read_raw (struct mtd_info *mtd,uint8_t *buf,loff_t from,size_t len,size_t ooblen)
{
struct nand_chip *this = mtd->priv;
int page = (int) (from >> this->page_shift); // 要读取的值所在的page, 一个page 2K。
int chip = (int) (from >> this->chip_shift);
int sndcmd = 1;
int cnt = 0;
int pagesize = mtd->oobblock + mtd->oobsize; //一个page的大小, 包括ECC的值。
int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;

/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
MTDDEBUG (MTD_DEBUG_LEVEL0,
"nand_read_raw: Attempt read beyond end of devicen");
return -EINVAL;
}

/* Grab the lock and see if the device is available */
nand_get_device (this,mtd,FL_READING);

this->select_chip (mtd,chip);

/* Add requested oob length */
len += ooblen;

while (len) {
if (sndcmd)
this->cmdfunc (mtd,NAND_CMD_READ0,page & this->pagemask); //nand_command
sndcmd = 0;

this->read_buf (mtd,&buf[cnt],pagesize);
//nand_read_buf(),读取的长度2K+64byge。
len -= pagesize;
cnt += pagesize;
page++;

if (!this->dev_ready)
udelay (this->chip_delay);
else
while (!this->dev_ready(mtd));

/* Check,if the chip supports auto page increment */
if (!NAND_CANAUTOINCR(this) ||?!(page & blockcheck))
sndcmd = 1;
}

/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
return 0;
}

nand_read_ecc

读取数值后, 会做ECC check, check读取的值是不是正确的。
和函数nand_read_raw的区别是:

1275         case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1276 this->read_buf(mtd,data_poi,end); // nand_read_buf
1277 for (i = 0,datidx = 0; eccsteps; eccsteps--,i+=3,datidx += ecc)
1278 this->calculate_ecc(mtd,&data_poi[datidx],&ecc_calc[i]); //nand_calculate_ecc

第1276行, 只读取2K的大小,然后调用calculate_ecc计算ecc, 放在ecc_calc中:

1308         /* read oobdata */
1309 this->read_buf(mtd,&oob_data[mtd->oobsize - oobreadlen],oobreadlen); //nand_read_buf

然后再读取64byte ecc的值,

1316         for (j = 0; j < oobsel->eccbytes; j++)
1317 ecc_code[j] = oob_data[oob_config[j]];
1319 /* correct data,if neccecary */
1320 for (i = 0,j = 0,datidx = 0; i < this->eccsteps; i++,datidx += ecc) {
1321 ecc_status = this->correct_data(mtd,&ecc_code[j],&ecc_calc[j]);

check读出的值到底是对的还是错的。


nand_read_oob

和函数nand_read_ecc一样,使用this->cmdfunc (mtd,NAND_CMD_READOOB,0x0,page & this->pagemask);读取oob,使用的指令为NAND_CMD_READOOB, 是自己定义的一个指令, 在flash中肯定是没有的, 在nand_command_lp中, 如果使用的是指令NAND_CMD_READOOB,会自动转换为NAND_CMD_READ0,然后将列地址加上mtd->oobblock也就是一个page的大小2K,不加上oob的空间。
如果是small page 的处理方式有不一样了, 在flash中存在NAND_CMD_READOOB=0x50的指令,直接使用就可以了,但是列地址就是相对于oob的地址,不是相对于page的起始地址。

654     /* Emulate NAND_CMD_READOOB*/
655 if (command == NAND_CMD_READOOB){
656 column +=mtd->oobblock;
657 command = NAND_CMD_READ0;
658 }


uboot 写nand flash

同样也提供了三个函数, 三个函数功能都不一样, 所有函数的定义在drivers/mtd/nand/nand_base.c中


nand_write

这个函数直接调用nand_write_ecc,只是最后两个参数为NULL, 就是不计算ECC。

return (nand_write_ecc (mtd,to,len,retlen,buf,NULL,NULL));  

nand_write_ecc

这个函数会调用nand_write_page, 对整个page进行操作:
从中

922     switch (eccmode) {
923 /* No ecc,write all */
924 case NAND_ECC_NONE:
925 // printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommendedn");
926 this->write_buf(mtd,this->data_poi,mtd->oobblock);
927 break;
928
929 /* Software ecc 3/256,write all */
930 case NAND_ECC_SOFT:
931 for (; eccsteps; eccsteps--) {
932 this->calculate_ecc(mtd,&this->data_poi[datidx],ecc_code);
933 for (i = 0; i < 3; i++,eccidx++)
934 oob_buf[oob_config[eccidx]] = ecc_code[i];
935 datidx += this->eccsize;
936 }
937 this->write_buf(mtd,mtd->oobblock);
938 break;
………………
958 /* Write out OOB data */
959 if (this->options & NAND_HWECC_SYNDROME)
960 this->write_buf(mtd,&oob_buf[oobsel->eccbytes],mtd->oobsize - oobsel->eccbytes);
961 else
962 this->write_buf(mtd,oob_buf,mtd->oobsize);
963
964 /* Send command to actually program the data */
965 this->cmdfunc (mtd,cached?? NAND_CMD_CACHEDPROG?: NAND_CMD_PAGEPROG,-1,-1);

可以看出来, 不管你选择的是哪种ECC校验方式, 都会向ECC空间中写值,只不过,如果选择NAND_ECC_NONE不会计算ECC的值, 而选择NAND_ECC_SOFT会调用this->calculate_ecc计算。然后写入flash。
写完成以后还会调用nand_verify_pages做verify.


nand_write_oob

从code上来看,small page 和big page 写oob的方式也是不一样的,这里将的oob是只有oob,没有data:
small page:
在写的时候会check写的地址是什么,如果大于512,会先写入一个NAND_CMD_READOOB=0x50的指令,列地址该为oob的相对地址, 如果大于256会写入一个NAND_CMD_READ1的指令,将列地址改为相对于后半个page的地址,如果小于256,会写一个 NAND_CMD_READ0。

554     if (command == NAND_CMD_SEQIN){
555 intreadcmd;
556
557 if (column >= mtd->oobblock){
558 /* OOB area */
559 column -= mtd->oobblock;
560 readcmd = NAND_CMD_READOOB;
561 } else if (column < 256) { // 当随机写的时候可以用到
562 /* First 256 bytes --> READ0 */
563 readcmd = NAND_CMD_READ0;
564 } else {
565 column -= 256;
566 readcmd = NAND_CMD_READ1;
567 }
568 this->write_byte(mtd,readcmd);
569 }
570 this->write_byte(mtd,command);

而big page就不一样了,直接写,不需要地址转换,地址就是page的起始地址。

1864   this->cmdfunc (mtd,NAND_CMD_SEQIN,mtd->oobblock + column,page & this->pagemask);
1865 /* write data */
1866 this->write_buf(mtd,len);

uboot 擦nand flash

执行过程:nand_erase() ==> nand_erase_nand() ==> nand_block_checkbad() ==> this->erase_cmd(single_erase_cmd)().
nand_block_checkbad() ==> nand_isbad_bbt()?: 在看函数nand_isbad_bbt()函数之前,先看一个标记ecc的函数:

static int nand_default_block_markbad(struct mtd_info *mtd,loff_t ofs)
{
struct nand_chip *this = mtd->priv;
u_char buf[2] = {0,0};
size_t retlen;
int block;

/* Get block number */
block = ((int) ofs) >> this->bbt_erase_shift;
if (this->bbt)
this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
/*
这个暂时不是很好说:内核维护一个标志bad block表,使用2bit来表示1block。
这个表在开机的时候通过扫描nand flash每个block的头两页的oob数据来生成,
发现坏块后至相应的block标志位为非零(有时候至3,但有时候至1,还没搞明白有什么不同)
*/

/* Do we have a flash based bad block table?? */
if (this->options & NAND_USE_FLASH_BBT)//samsun nand flash不属于这种,暂时不去研究,以后同
return nand_update_bbt (mtd,ofs);

/* We write two bytes,so we dont have to mess with 16 bit access */
ofs += mtd->oobsize + (this->badblockpos & ~0x01);//???????????????
return nand_write_oob (mtd,ofs,2,&retlen,buf);
}

nand_isbad_bbt函数

1024 /**
1025 * nand_isbad_bbt - [NAND Interface] Check if a block is bad
1026 * @mtd: MTD device structure
1027 * @offs: offset in the device
1028 * @allowbbt: allow access to bad block table region
1029 *
1030 */
1031 int nand_isbad_bbt (struct mtd_info *mtd,loff_t offs,int allowbbt)
1032 {
1033 struct nand_chip *this = mtd->priv;
1034 int block;
1035 uint8_t res;
1036
1037 /* Get block number * 2 */
1038 block = (int) (offs >> (this->bbt_erase_shift - 1));
1039 res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
1040
1041 printf("[dancy log|%s:%d].n",__func__,__LINE__);
1042 MTDDEBUG (MTD_DEBUG_LEVEL2,"nand_isbad_bbt(): bbt info for offs 0x%08x: "
1043 "(block?%d) 0x%02xn",(unsigned int)offs,res,block >> 1);
1044
1045 switch ((int)res) {
1046 case 0x00: return 0;
1047 case 0x01: return 1;
1048 case 0x02: return allowbbt?? 0?: 1;
1049 }
1050 return 1;
1051 }

他的计算过程不是很明白, 当不是坏块是res计算值为0, 否则为坏块。
在函数 nand_block_checkbad 中还有一个分支,

531     if (!this->bbt)
532 return this->block_bad(mtd,getchip); //nand_block_bad

this->bbt是在nand_default_bbt() ==> nand_scan_bbt()中分配空间的, nand_default_bbt()是在nand_scan的最后调用的,也就是说,如果我把nand_scan()函数的最后return this->scan_bbt (mtd)注释掉, this->bbt就不会分配空间了, 也就会执行this->block_bad检测该block是不是坏块。
nand_block_bad工作原理:
在函数中,先调用this->cmdfunc (mtd,this->badblockpos,page); 命令为NAND_CMD_READOOB, this->badblockpos在init的时候是这样赋值的,

2464 this->badblockpos = mtd->oobblock > 512??
2465 NAND_LARGE_BADBLOCK_POS:NAND_SMALL_BADBLOCK_POS;
//NAND_LARGE_BADBLOCK_POS=0,NAND_SMALL_BADBLOCK_POS=5,
//也就是说, 如果是large page, check第2048个byte似乎不是0xff,
//如果是small page会check第517个byte是不是0xff.
459 if (this->read_byte(mtd)?!= 0xff) //nand_read_byte
460 res = 1;

如果是坏块的话, 就不允许擦除。
调用擦flash。

2128 static void single_erase_cmd (struct mtd_info *mtd,int page)
2129 {
2130 struct nand_chip *this = mtd->priv;
2131 /* Send commands to erase a block */
2132 this->cmdfunc (mtd,NAND_CMD_ERASE1,page);
2133 this->cmdfunc (mtd,NAND_CMD_ERASE2,-1);
2134 }
uboot nand flash子命令详探

关于nand flash 命令,为了以后看起来方便,我有单独写了一节:Nand flash uboot 命令详解


启动linux

在启动之前从nand flash拷贝到sdram中在common/image.c的nand_read_kernel函数里:
函数调用过程:nand_read()(common/env_nand.c) ==> nand_read_ecc()(drivers/mtd/nand/nand_base.c)中。
函数nand_read_ecc()是会check ecc的,所以,在刚刚开始的时候,如果我在选择NAND_ECC_NONE写flash, 选择NAND_ECC_SOFT读flash, 这时,kernel的数据会一点也读取不出来。

linux ecc校验


http://blog.chinaunix.net/uid-14833587-id-76512.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读