arm/lib/board.c
board_init_r()
{
……
nand_init();
env_relocate();
……
}
common\env_common.c
void env_relocate(void)
{
……
env_relocate_spec();
……
}
common\env_nand.c
void env_relocate_spec(void)
{
readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
}
drivers/mtd/nand/nand_base.c
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{
……
if (nand_block_isbad(&nand_info[0], offset))
{}
……
}
drivers/mtd/nand/nand_base.c
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{
return nand_block_checkbad(mtd, offs, 1, 0);
}
drivers/mtd/nand/nand_base.c
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
{
chip->scan_bbt(mtd);
/* Return info from the table */
return nand_isbad_bbt(mtd, ofs, allowbbt);
}
drivers/mtd/nand/nand_bbt.c
int nand_default_bbt(struct mtd_info *mtd)
{
if (!this->badblock_pattern)
nand_create_default_bbt_descr(this);
return nand_scan_bbt(mtd, this->badblock_pattern);
}
drivers/mtd/nand/nand_bbt.c
int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
//为bbt表分配内存
nand_memory_bbt(mtd, bd)
}
drivers/mtd/nand/nand_bbt.c
static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
bd->options &= ~NAND_BBT_SCANEMPTY;
return create_bbt(mtd, this->buffers->databuf, bd, -1);
}
比如对于一个 Samsuny KF2G08 256M的nand,共有2048个Block,其中每个块的共有64页,一个页的大小为2048+64Byte,即一个页中主存储区的大小2048Byte, spare 区域的大小为64Byte,其中的OOB信息就存储在spare区域。对于 large page型的nand,即一个页的主存储区大于512Byte的nand,一个块是否为好坏,用这个块的第一个page和第二个page的spare区的第一个字节来标记,若这两个块中spare区中的第一个字节值都为0xFF则该坏为好坏,否则为坏块,nand_chip->bbt数组的大小,本例中为512Byte。大小的计算方法为:512 * 8 / 2 = 2048。即用两个bit表示一个块是好的还是坏的。
create_bbt中有一个循环,通过调用scan_block_fast()对每一个块是否完好的信息进行读取,并进行判断,若为坏块,填充对应的bbt数组。scan_block_fast()最终会调用nand_read_oob_std()进行真正OOB信息读取。在读取到信息之后,nand_scan_fast中调用 check_short_pattern进行判断读取到的OOB信息,该信息中的第1个字节反映了是否为坏块。若为坏块,则返回非零到create_bbt函数中,在create_bbt中往nand_chip->bbt 这个数组中填充该块是否为坏块。一个坏块标记占用2个bit,uboot中用两个bit "11"来标志对应的坏为坏块。两个bit "00"标志对应的块为好坏。
最后读取完整个nand的OOB信息后,通过nand_isbad_bbt用来判断指定的块是否为坏坏。
spare区中存储的是OOB信息,一个block中的第一个page和第二个page的spare区中的第一个字节用来保存块是否完好的信息外,spare区的其它内容为ECC校验信息,用来表示主存储区的数据的校验值,每512个Byte会生成一个校验值,一个校验值为3个Byte,可以用此来判断讲到的数据是否反转。
nand_read_buf用来一个一个读取字节内容。
create_bbt 0 len 2, chip -1
create_bbt 1 scanlen 0, readlen 1
create_bbt 2 from 0x00000000, numblocks 0x00001000
create_bbt 4 from 0x00000000, buf[0] 0, len 0x00000002
scan_block_fast j 0, offs 0x00000000, len 2 , ops.ooblen 64
nand_read_oob 0 from 0x00000000
nand_do_read_oob 0 chip->oob_poi[0] 0, page 0x00000000, sndcmd 1, len 64, readlen 64
nand_command_lp column 0x00000800, ctrl 0x00000005
nand_command_lp page_addr 0x00000000, ctrl 0x00000005
nand_read_oob_std 0 NAND_CMD_READOOB 0x00000050, page 0, sndcmd 1
nand_read_buf buf:f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
nand_read_oob_std 1 chip->oob_poi[0] f0, mtd->oobsize 0x00000040
nand_do_read_oob 1 chip->oob_poi[0] f0, page 0x00000000, sndcmd 0, len 64
nand_do_read_oob 2 buf[0] 0, sndcmd 0
nand_read_oob 1 from 0x00000000, ret 0
check_short_pattern 0 td->len 1, p[td->offs + i] f0, td->pattern[i] ff
create_bbt 5 from 0x00000000, buf[0] f0, len 0x00000002, ret 1
create_bbt 6, this->bbt[i >> 3] 0
****####create_bbt 7, i 0x00000000, i>>1 0x00000000, bbt[i>>3] 3, Bad eraseblock 0 at 0x000000000000, ret 1, mtd->ecc_stats.badblocks 1