本文主要分析uboot中nand flash初始化部分的代码,主要是driver/mtd/nand/nand.c中的nand_init()函数。nand flash bbt建立部分的代码后面再分析。
(一)和nand flash 相关的参数
#define CONFIG_CMD_NAND 1
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE 0xB0000000
#define CONFIG_SYS_NAND_ALE_ADDR (1 << 10)
#define CONFIG_SYS_NAND_CLE_ADDR (1 << 12)
#define CONFIG_SYS_NO_FLASH 1
#define CONFIG_ENV_IS_IN_NAND 1
#define CONFIG_ENV_OFFSET 0x40000
#define CONFIG_ENV_OFFSET_REDUND 0x60000
#define CONFIG_ENV_OVERWRITE 1
#define NAND_MAX_CHIPS 1
#define CONFIG_SYS_NAND_RB_BIT 18
#define CONFIG_SYS_NAND_RB_PORT 0xC2104200
(二)初始化
-->nand_scan driver/mtd/nand/nand_base.c
一、start_armboot()和nand_init()
void start_armboot (void)
{
...
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ")//注释1
nand_init(); /* go init the NAND */
#endif
...
}
void nand_init(void)
{
int i;
unsigned int size = 0;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { //注释2
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);//注释 3 4 5
size += nand_info[i].size / 1024; //注释6
if (nand_curr_device == -1) //注释7
nand_curr_device = i;
}
printf("%u MiB\n", size / 1024);//注释1
}
2. CONFIG_SYS_MAX_NAND_DEVICE表示系统有几块nand设备,一般只有1块。
该宏定义会影响下面数组的大小:
nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE];
3.有两个主要的数据结构struct mtd_info和 struct nand_chip。里面存放着nand flash
的size,erasesize,writesize,oobsize,ecc布局等属性,和操作nand flash所需
的read,write,erase等函数。nand_chip中变量的含义的详细注释在
Include/linux/mtd/nand.h中。初始化的目的就是初始化这两个数据结构。
4. Nand_info和mtd_info同义,typedef struct mtd_info nand_info_t;
5. base_address是nand flash的基地址,和硬件有关。可以通过定义
CONFIG_SYS_NAND_BASE_LIST或者 CONFIG_SYS_NAND_BASE
来设置 base_address的值。
6.nand_info.size是整个MTD的大小(Total size of the MTD),单位是Byte。
当系统只有一个nand flash作为静态存储器时,该变量等于nand flash的总大小。
7.nand_curr_device表示正在使用的nand flash在数组nand_info[]中的位置。
用户想要显示当前nand flash的信息时,可以在uboot命令行输入
#nand device
二、nand_init_chip()
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
ulong base_addr)
{
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
int __attribute__((unused)) i = 0;
if (maxchips < 1)
maxchips = 1;
//建立两个重要数据结构之间的关系。mtd_info的priv指针指向nand_chip
mtd->priv = nand;
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;//设置读写地址
//初始化与硬件相关的函数,如片选,cmd_ctrl等函数
if (board_nand_init(nand) == 0) {
//利用片选,cmd_ctrl等函数,读取nand flash的信息,并存放在mtd_info和nand_chip数据结构中。
if (nand_scan(mtd, maxchips) == 0) {
if (!mtd->name) //nand_scan会设置该变量,若没设置,就用默认值
mtd->name = (char *)default_nand_name;
#ifndef CONFIG_RELOC_FIXUP_WORKS
else
mtd->name += gd->reloc_off;
#endif
#ifdef CONFIG_MTD_DEVICE
/*
* Add MTD device so that we can reference it later
* via the mtdcore infrastructure (e.g. ubi).
*/
//若定义 CONFIG_MTD_DEVICE,则强制修改mtd->name为”nandx”
sprintf(dev_name[i], "nand%d", i);
mtd->name = dev_name[i++];
add_mtd_device(mtd);//在数组mtd_table中查找一个空闲位置,并占用之。
#endif
} else
mtd->name = NULL;
} else {
mtd->name = NULL;
mtd->size = 0;
}
}
三、board_nand_init()
board_nand_init()函数主要初始化与硬件相关的函数,如片选,cmd_ctrl等函数。
当我们移植uboot nand flash代码时,主要工作就是修改或者重写该函数。
下面代码中的”yyy”,一般是指板子型号或者具体nand flash的型号。
int board_nand_init(struct nand_chip *nand)
{
nand->cmd_ctrl = yyy_nand_hwcontrol;// 注释1
nand->dev_ready = yyy_nand_readybusy;// 注释2
nand->select_chip = yyy_nand_select_chip;
nand->chip_delay = 100; // 注释3
nand->ecc.mode = NAND_ECC_SOFT; // 注释4
nand->options = NAND_USE_FLASH_BBT | NAND_NO_READRDY;// 注释5
}
就是由nand->cmd_ctrl函数来实现。
本例中,yyy_nand_hwcontrol()源码大致如下:
static void yyy_nand_hwcontrol(struct mtd_info *mtd, int dat,unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
void *IO_ADDR_W = chip->IO_ADDR_W;
if (ctrl & NAND_CLE) // flash的CLE引脚接在CPU的ADDR21引脚
IO_ADDR_W += CONFIG_SYS_NAND_CLE_ADDR;
if (ctrl & NAND_ALE) // flash的ALE引脚接在CPU的ADDR24引脚
IO_ADDR_W += CONFIG_SYS_NAND_ALE_ADDR;
if (dat != NAND_CMD_NONE) {
if (chip->options & NAND_BUSWIDTH_16)//flash数据线宽度是8 还是16
writew((unsigned short)dat, IO_ADDR_W);
else
writeb((unsigned char)dat, IO_ADDR_W);
}
}
因为ctrl 等于NAND_CLE,所以NAND_CMD_RESET会发到
(IO_ADDR_W + CONFIG_SYS_NAND_CLE_ADDR)地址上,即ADDR21会出现高电平,
刚好满足发送命令时,CLE引脚是高电平的条件。
2.该函数可以为空,即不检测nand flash的R/B引脚。而通过读取状态寄存器
来判断flash是否空闲,或者不检测flash是否空闲,而仅仅等待一段时间。
3.等待时间,需要参考flash的数据手册,不能太小,否则会出错。
有次设置太小,导致读取环境变量和内核时总是提示ecc错误。
4.计算ECC的方式,很重要
5.设置BBT存放方式,读操作时是否检测R/B状态等,很重要。
四、Nand_scan()
Nand_scan()函数分为两部分。
int nand_scan(struct mtd_info *mtd, int maxchips)
{
int ret;
ret = nand_scan_ident(mtd, maxchips);
if (!ret)
ret = nand_scan_tail(mtd);
return ret;
}
首先将mtd_info和 nand_chip中还没初始化的函数,初始化为默认函数,
然后读取flash的ID,获取flash的信息,并计算出flash的总容量,块大小等信息,
并根据这些信息将mtd_info和 nand_chip设置为合适的值。
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
{
int i, busw, nand_maf_id;
struct nand_chip *chip = mtd->priv;
struct nand_flash_dev *type;
/* Get buswidth to select the correct functions */
busw = chip->options & NAND_BUSWIDTH_16;//判断flash数据总线的宽度
/* Set the default functions */
nand_set_defaults(chip, busw);见六
/* Read the flash type */
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);见七
if (IS_ERR(type)) {
chip->select_chip(mtd, -1);
return PTR_ERR(type);
}
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
if (nand_maf_id != chip->read_byte(mtd) ||
type->id != chip->read_byte(mtd))
break;
}
/* Store the number of chips and calc total size for mtd */
chip->numchips = i;
mtd->size = i * chip->chipsize;
//只有一块nand flash时,i等于1,mtd总大小就等于flash的总容量。
return 0;
}
将nand_chip中还没初始化的函数初始化为默认值。
static void nand_set_defaults(struct nand_chip *chip, int busw)
{
/* check for proper chip_delay setup, set 20us if not */
if (!chip->chip_delay)
chip->chip_delay = 20;
/* check, if a user supplied command function given */
//仔细研究下nand_command,会有助于理解chip->chip_delay和chip->dev_ready函数的
//含义,如果是大页flash,nand_get_flash_type()会将chip->cmdfunc 修改为
//nand_command_lp()
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;
/* check, if a user supplied wait function given */
if (chip->waitfunc == NULL)
chip->waitfunc = nand_wait;
if (!chip->select_chip)
chip->select_chip = nand_select_chip;
if (!chip->read_byte)
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
if (!chip->read_word)
chip->read_word = nand_read_word;
if (!chip->block_bad)
chip->block_bad = nand_block_bad;
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->verify_buf)
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
}
}
七、nand_get_flash_type()
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
struct nand_chip *chip,
int busw, int *maf_id)
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
int tmp_id, tmp_manf;
/* Select the device */
chip->select_chip(mtd, 0);
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up
*/
//调用nand_command(),reset flash。
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);//读取 flash ID
/* Read manufacturer and device IDs */
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
/* Try again to make sure, as some systems the bus-hold or other
* interface concerns can cause random data which looks like a
* possibly credible NAND flash to appear. If the two results do
* not match, ignore the device completely.
*/
//再次读取 flash ID
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
tmp_manf = chip->read_byte(mtd);
tmp_id = chip->read_byte(mtd);
//比较两次所读的 flash ID是否一致
if (tmp_manf != *maf_id || tmp_id != dev_id) {
printk(KERN_INFO "%s: second ID read did not match "
"%02x,%02x against %02x,%02x\n", __func__,
*maf_id, dev_id, tmp_manf, tmp_id);
return ERR_PTR(-ENODEV);
}
/*nand_flash_ids[]保存着uboot所支持的nand flash的
*name,id,pagesize,chipsize,erasesize,options 等信息。
*下面的for循环,从该数组中查找和自身ID相等的元素
*/
/* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (dev_id == nand_flash_ids[i].id) {
type = &nand_flash_ids[i];
break;
}
}
if (!type) {
/* supress warning if there is no nand */
if (*maf_id != 0x00 && *maf_id != 0xff &&
dev_id != 0x00 && dev_id != 0xff)
printk(KERN_INFO "%s: unknown NAND device: "
"Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
__func__, *maf_id, dev_id);
return ERR_PTR(-ENODEV);
}
//找到了,如“ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},”
//设置mtd->name,该变量有可能被强制修改为nandx
if (!mtd->name)
mtd->name = type->name;
//根据数组中的参数,设置flash的总容量,128M
chip->chipsize = (uint64_t)type->chipsize << 20;
//若pagesize为0,表示需要继续读取ID,从ID中计算其他参数,而不是从
//nand_flash_ids[]中获取。
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
int extid;
/* The 3rd id byte holds MLC / multichip data */
chip->cellinfo = chip->read_byte(mtd);
/* The 4th id byte is the important one */
// 4th id byte的含义见图一,本例用的nand flash是K9F1G08Q0A,读取到的是0x15,
extid = chip->read_byte(mtd);
/* Calc pagesize */
//bit0,bit1为0,pagesize就是1024<<1=1024;为1,pagesize就是1024<<1=2048
//writesize等于pagesize,因为每次写都是以页为单位。2048
mtd->writesize = 1024 << (extid & 0x3);
extid >>= 2;
/* Calc oobsize */
//writesize>>9算出几个512bytes,每512bytes对应8个还是16个oob区是由
//(8 << (extid & 0x01))算得,两者相乘就得oob的总大小,16*4=64
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
//块大小或者擦除大小 64*1024*2=128KB
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
//总线宽度为8
busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
} else {
/*
* Old devices have chip data hardcoded in the device id table
*/
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
busw = type->options & NAND_BUSWIDTH_16;
}
/* Try to identify manufacturer */
//根据制造商ID,获取制造商名称,0xec对应Samsung
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct !
*/
if (busw != (chip->options & NAND_BUSWIDTH_16)) {
printk(KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
return ERR_PTR(-EINVAL);
}
/* Calculate the address shift from the page size */
//给出一个地址,利用该变量可以直接得出 该地址是第几页。
//如 realpage = (int)(address>> chip->page_shift);
chip->page_shift = ffs(mtd->writesize) - 1;
/* Convert chipsize to number of pages per chip -1. */
//chip->pagemask是总页数减1,用来防止要读写的页号不超过总页数
// page = realpage & chip->pagemask;
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
//给出一个地址,利用该变量可以直接得出 该地址是第几块。
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
//给出一个地址,利用该变量可以直接得出 该地址是第几个flash设备。
if (chip->chipsize & 0xffffffff)
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
else
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
/* Set the bad block position */
//坏块位置,后面讲到ECC时会用到
chip->badblockpos = mtd->writesize > 512 ?
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
//设置chip->options
/* Get chip options, preserve non chip based options */
chip->options &= ~NAND_CHIPOPTIONS_MSK;
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
/*
* Set chip as a default. Board drivers can override it, if necessary
*/
chip->options |= NAND_NO_AUTOINCR;
/* Check if chip is a not a samsung device. Do not clear the
* options for chips which are not having an extended id.
*/
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
//修改默认的函数为合适的函数
/* Check for AND chips with 4 page planes */
if (chip->options & NAND_4PAGE_ARRAY)
chip->erase_cmd = multi_erase_cmd;
else
chip->erase_cmd = single_erase_cmd;
//如果是大页flash,则修改chip->cmdfunc 为 nand_command_lp()
/* Do not replace user supplied command function ! */
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
nand_manuf_ids[maf_idx].name, type->name);
return type;
}
图一
七、nand_scan_tail()
nand_scan_tail()继续初始化mtd_info和nand_info数据结构,主要初始化和ECC有关的变量和函数。
int nand_scan_tail(struct mtd_info *mtd)
{
int i;
struct nand_chip *chip = mtd->priv;
//分配buffers,用于临时存放从flash读取的数据,见nand_do_read_ops()函数
if (!(chip->options & NAND_OWN_BUFFERS))
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
if (!chip->buffers)
return -ENOMEM;
//oob紧跟着数据存放
/* Set the internal oob buffer location, just after the page data */
chip->oob_poi = chip->buffers->databuf + mtd->writesize;
/*
* If no default placement scheme is given, select an appropriate one
*/
if (!chip->ecc.layout) {
switch (mtd->oobsize) {
case 8:
chip->ecc.layout = &nand_oob_8;
break;
case 16:
chip->ecc.layout = &nand_oob_16;
break;
case 64:
chip->ecc.layout = &nand_oob_64;//注释1
break;
case 128:
chip->ecc.layout = &nand_oob_128;
break;
default:
printk(KERN_WARNING "No oob scheme defined for "
"oobsize %d\n", mtd->oobsize);
}
}
//初始化和ECC有关的函数
if (!chip->write_page)
chip->write_page = nand_write_page;
/*
* check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
*/
switch (chip->ecc.mode) {
case NAND_ECC_HW_OOB_FIRST:
/* Similar to NAND_ECC_HW, but a separate read_page handle */
if (!chip->ecc.calculate || !chip->ecc.correct ||
!chip->ecc.hwctl) {
printk(KERN_WARNING "No ECC functions supplied, "
"Hardware ECC not possible\n");
BUG();
}
if (!chip->ecc.read_page)
chip->ecc.read_page = nand_read_page_hwecc_oob_first;
case NAND_ECC_HW:
/* Use standard hwecc read page function ? */
if (!chip->ecc.read_page)
chip->ecc.read_page = nand_read_page_hwecc;
if (!chip->ecc.write_page)
chip->ecc.write_page = nand_write_page_hwecc;
if (!chip->ecc.read_page_raw)
chip->ecc.read_page_raw = nand_read_page_raw;
if (!chip->ecc.write_page_raw)
chip->ecc.write_page_raw = nand_write_page_raw;
if (!chip->ecc.read_oob)
chip->ecc.read_oob = nand_read_oob_std;
if (!chip->ecc.write_oob)
chip->ecc.write_oob = nand_write_oob_std;
case NAND_ECC_HW_SYNDROME:
if ((!chip->ecc.calculate || !chip->ecc.correct ||
!chip->ecc.hwctl) &&
(!chip->ecc.read_page ||
chip->ecc.read_page == nand_read_page_hwecc ||
!chip->ecc.write_page ||
chip->ecc.write_page == nand_write_page_hwecc)) {
printk(KERN_WARNING "No ECC functions supplied, "
"Hardware ECC not possible\n");
BUG();
}
/* Use standard syndrome read/write page function ? */
if (!chip->ecc.read_page)
chip->ecc.read_page = nand_read_page_syndrome;
if (!chip->ecc.write_page)
chip->ecc.write_page = nand_write_page_syndrome;
if (!chip->ecc.read_page_raw)
chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
if (!chip->ecc.write_page_raw)
chip->ecc.write_page_raw = nand_write_page_raw_syndrome;
if (!chip->ecc.read_oob)
chip->ecc.read_oob = nand_read_oob_syndrome;
if (!chip->ecc.write_oob)
chip->ecc.write_oob = nand_write_oob_syndrome;
if (mtd->writesize >= chip->ecc.size)
break;
printk(KERN_WARNING "%d byte HW ECC not possible on "
"%d byte page size, fallback to SW ECC\n",
chip->ecc.size, mtd->writesize);
chip->ecc.mode = NAND_ECC_SOFT;
case NAND_ECC_SOFT:
chip->ecc.calculate = nand_calculate_ecc;
chip->ecc.correct = nand_correct_data;
chip->ecc.read_page = nand_read_page_swecc;
chip->ecc.read_subpage = nand_read_subpage;
chip->ecc.write_page = nand_write_page_swecc;
chip->ecc.read_page_raw = nand_read_page_raw;
chip->ecc.write_page_raw = nand_write_page_raw;
chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = 256;//每256bit 产生3bit的ECC
chip->ecc.bytes = 3;
break;
case NAND_ECC_NONE:
printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
"This is not recommended !!\n");
chip->ecc.read_page = nand_read_page_raw;
chip->ecc.write_page = nand_write_page_raw;
chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.read_page_raw = nand_read_page_raw;
chip->ecc.write_page_raw = nand_write_page_raw;
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = mtd->writesize;
chip->ecc.bytes = 0;
break;
default:
printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
chip->ecc.mode);
BUG();
}
/*
* The number of bytes available for a client to place data into
* the out of band area
*/
//可用的oob大小,即nand_oob_64中所设置的>oobfree的总和,本例是38bit
chip->ecc.layout->oobavail = 0;
for (i = 0; chip->ecc.layout->oobfree[i].length
&& i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
chip->ecc.layout->oobavail +=
chip->ecc.layout->oobfree[i].length;
mtd->oobavail = chip->ecc.layout->oobavail;
/*
* Set the number of read / write steps for one page depending on ECC
* mode
*/
chip->ecc.steps = mtd->writesize / chip->ecc.size;
if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
printk(KERN_WARNING "Invalid ecc parameters\n");
BUG();
}
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
/*
* Allow subpage writes up to ecc.steps. Not possible for MLC
* FLASH.
*/
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
switch(chip->ecc.steps) {
case 2:
mtd->subpage_sft = 1;
break;
case 4:
case 8:
case 16:
mtd->subpage_sft = 2;
break;
}
}
//计算子页大小,即每次读flash时,最小需要读取的数据。为了检测数据是否有误,需
//要至少读取一个单位的ECC对应的数据大小。
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
/* Initialize state */
chip->state = FL_READY;
/* De-select the device */
chip->select_chip(mtd, -1);
//该变量应该是表示chip->buffers中的数据是第几页的数据。
//读flash之前,需要先判断所读的页的数据是否已在chip->buffers中,是则,直接从
//buffers中读取
/* Invalidate the pagebuffer reference */
chip->pagebuf = -1;
//设置默认函数和变量
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
mtd->suspend = nand_suspend;
mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
/* propagate ecc.layout to mtd_info */
mtd->ecclayout = chip->ecc.layout;
//如果定义NAND_SKIP_BBTSCAN,则设置BBT“已扫描过”。以后会跳过BBT扫描,
/* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN)
chip->options |= NAND_BBT_SCANNED;
return 0;
}
1.本例oobsize等于64,从下面结构可以看出oob区的结构
static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 2,
.length = 38}}
};
前两位有其他作用,从第2位开始,到第39位,一共38位是空闲的。从40位到63位共24位存放ECC数据,每256bytes对应3bytesECC,一页2048bytes,共24bytesECC。