u-boot中NAND flash的MTD驱动移植 三

转载地址:http://blog.sina.com.cn/s/blog_87f8cc4e0102vbxf.html

2)struct nand_chip的变量定义

struct nand_chip数据结构的变量在drivers/nand/nand.c中定义为:

static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];

该变量nand_chip[i]的指针将作为函数

static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr) 被nand_init()调用时的第二个实参被引用如下:nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);

在函数nand_init_chip()中&nand_chip[i]将被复制给mtd数据结构中的成员priv,如下 mtd->priv = nand;

所以,mtd->priv实际上就是数据结构struct nand_chip变量指针。

 

3)struct nand_chip的操作(初始化)

对struct nand_chip的初始化操作都在函数nand_scan()中完成。该函数是初始化MTD设备的核心函数。我们将在后面详细分析它。

值得注意的是:在nand_scan()中struct nand_chip的函数指针会被初始化为相应的在driver/nand/nand_base.c定义的通用函数,虽说MTD驱动对绝大多数的NAND flash芯片支持都很好但是少部分通用函数可能还是会需要修改,而且涉及到底层硬件操作的函数MTD不可能提供通用的函数,所以要在移植MTD驱动时自行编写,这也是移植的一个重要内容。这些函数包括:hwcontrol、dev_ready、select_chip等。

 

3、 数据结构struct nand_flash_dev分析

这个数据结构主要描述的是具体的NAND flash芯片型号。这个数据结构比较简单,它在include/linux/mtd/nand.h中被声明定义为一个结构体:

struct nand_flash_dev {

char *name; //NAND flash的名称

int id; //NAND flashd 的设备ID

unsigned long pagesize;//页面大小,单位为KB

unsigned long chipsize;//芯片容量,单位为MB

unsigned long erasesize;//擦除单位大小

unsigned long options;// NAND flashd的扩展功能配置及位宽配置

};

结构体struct nand_flash_dev在drivers/mtd/nand_ids.c中这个数据结构被定义为一个结构体数组并被初始化。其中包含的每一个数组元素即为MTD驱动支持的NAND flashd芯片型号。初始化如下:

struct nand_flash_dev nand_flash_ids[] = {

………………………………………………………….

{"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},

{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

 

{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

 

{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

 

 

{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

 

 

{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

{NULL,}

};

这里列出来的只有很少的一部分数组元素,其中加粗的元素就是HY27UF082G2B对应的nand_flash_dev结构体。可知HY27UF082G2B的设备ID为DA,芯片容量为256MB,页面大小和擦除单元大小为0表示这些数据需要从芯片中读取。要强调的是:移植MTD驱动

时一定要确定要移植的NAND flash芯片在这里有对应的nand_flash_dev结构体,没有的话要自行添加。在nand_scan()中,会先读出芯片的设备ID再到该结构体数组中逐个对比,如果没有找到匹配项则会导致在nand_scan()初始化失败返回。

 

4)u-boot中MTD对NAND flash的初始化流程及源码分析

对NAND flash初始化的核心内容就是对以上分析的三个数据结构(结构体)进行初始化。注意这三个数据结构均为结构体,且在变量定义的时候都被定义为结构体数组。每一个NAND flash芯片分别对应三个结构体数组中的一个数组元素。对一个NAND flash的初始化就是对三个结构体数组元素初始化。在这三个数组元素(就是结构体)中包含了 1、 MTD驱动的接口函数、底层操作函数、坏块管理函数、ECC校验函数的函数指针,这

些函数大部分为在nand_base.c中实现的通用函数,少部分涉及底层硬件操作的函数由用户编写;

2、 支持这些函数的必要数据结构,如坏块表、读写缓冲区等

3、 一些重要的参数,这些参数由flash_dev nand_flash_ids提供或者有ReadID操作直接提

供或基于这些参数运算获得。

4.1)流程分析

对NAND flash的这些参数和函数指针的初始化由函数nand_init()完成,该函数在lib_arm/board.c中的函数start_armboot()中被调用,调用代码如下:

#if (CONFIG_COMMANDS & CFG_CMD_NAND)

puts ("NAND: ");

nand_init();

#endif

由上可知:必须第一好宏开关:CONFIG_COMMANDS & CFG_CMD_NAND(也就是NAND命令的宏定义)nand_init()才会被执行。所以移植时一定要注意。

NAND flash的初始化函数nand_init()在drivers/nand/nand.c中被定义,代码如下: void nand_init(void)

{

int i;

unsigned int size = 0;

for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {

nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);

size += nand_info[i].size;

if (nand_curr_device == -1)

nand_curr_device = i;

}

printf("%lu MiB\n", size / (1024 * 1024));

 

#ifdef CFG_NAND_SELECT_DEVICE

// Select the chip in the board/cpu specific driver

board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device); #endif

}

整个函数比较简单,实现的功能就是:

1、 计算板上NAND flash芯片的总容量(如果只有一片则就是芯片容量),并打印;

2、 循环调用nand_init_chip()初始化板上所有NAND flash芯片,如果只有一片则只调用一次。注意调用nand_init_chip()时的实参;

3、 如果定义了宏CFG_NAND_SELECT_DEVICE,则调用函数board_nand_select_device();该函数在u-boot中未空实现,如果用户移植需要在初始化是选择特定的NAND flash芯片初始化可以在这个函数中实现,如果不需要则不要关注此函数。

经过上面的分析可知:在nand_init()函数中初始化工作的实质是调用函数nand_init_chip(),该函数在drivers/nand/nand.c中被定义,代码如下:

static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr) {

mtd->priv = nand;

 

nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;

board_nand_init(nand);

 

if (nand_scan(mtd, 1) == 0) {

if (!mtd->name)

mtd->name = (char *)default_nand_name;

} else

mtd->name = NULL;

 

}

整个函数的代码还是很简单,实现的功能为:

1、 初始化数据结构mtd_info中的priv,使其指向数据结构nand_chip;

2、 初始化数据结构nand_chip中的IO_ADDR_R、IO_ADDR_W为base_addr,跟一下base_addr可知,base_addr就是CFG_NAND_BASE,这里的初始化没有实际意义,在后续的初始化中被重新初始化,但是在移植时仍要定义宏CFG_NAND_BASE,为0即可;

3、 调用函数board_nand_init(nand),该函数在u-boot中没有函数定义,只有一个函数原型:extern void board_nand_init(struct nand_chip *nand);所以移植时用户要自行编写该函数。该函数实现涉及底层硬件操作函数的函数指针初始化,这些函数需要用户自行编写。这方面后续会有详细分析。

4、 调用函数nand_scan(mtd, 1),该函数是整个NAND flash初始化的核心,它完成了三个数据机构中绝大部分的参数和函数指针的初始化。

至此,可以通过一个图表来描述NAND flash的初始化流程了,如下图:

 

board_nand_init ()、nand_scan ()完成NAND flash的实际初始化工作,下面将对这两个函数做详细的分析;

u-boot中NAND <wbr>flash的MTD驱动移植(转) <wbr>三
 

4.2)nand_scan ()源码分析:

该函数在drivers/nand/nand_base.c中定义,这个函数很复杂、代码很长,分析是只挑些重点的代码分析:

int nand_scan (struct mtd_info *mtd, int maxchips)

{

int i, j, nand_maf_id, nand_dev_id, busw;

struct nand_chip *this = mtd->priv;

// mtd->priv在board_init_chip()函数中被初始化为数据结构nand_chip的变量nand_chip[i],所以这里的this指针指向的就是变量nand_chip[i]。

busw = this->options & NAND_BUSWIDTH_16;

//位宽设置,options bit1设置为0是busw为0,表示位宽为8。且必须先在board_nand_init()初始化options。在board_nand_init()初始化的options仅仅起到指示位宽的作用,options会在该函数后续被初始化为nand_flash_ids[i].options。如果用户需要配置扩展功能只能在nand_flash_ids[i].options配置。

 

if (!this->chip_delay)

this->chip_delay = 20;

// chip_delay为NAND flash芯片的TR 该参数可在芯片datasheet中查到,HY27UF082G2B为小于25us

if (this->cmdfunc == NULL)

this->cmdfunc = nand_command;

// cmdfunc指向的函数要求实现功能为写一个命令字或者还有一个地址,注: nand_command函数针对小页面nandflash,大页面nandflash写命令字函数为nand_command_pl()。这个语句的意思为:如果用户没有在board_nand_init()初始化该函数指针,则使用MTD在nand_base.c中实现的通用函数。

 

if (this->waitfunc == NULL)

this->waitfunc = nand_wait;

//该函数指针指向的函数为烧写、擦除超时处理使用MTD提供的通用函数即可。MTD在nand_base.c中提供了许多相关的通用函数。

if (!this->select_chip)

this->select_chip = nand_select_chip;

//该函数指针指向的函数为片选芯片函数,由于该函数涉及底层寄存器操作,所以该函数需要用户自行实现,并在board_nand_init()中初始化该函数指针。

if (!this->write_byte)

this->write_byte = busw ? nand_write_byte16 : nand_write_byte;

if (!this->read_byte)

this->read_byte = busw ? nand_read_byte16 : nand_read_byte;

//以下两个语句是根据芯片位宽选择向nandflash控制器寄存器读写一个字节函数,使用MTD提供的通用函数即可

if (!this->write_word)

this->write_word = nand_write_word;

if (!this->read_word)

this->read_word = nand_read_word;

//向nandflash控制器寄存器读写一个字函数指针初始化,使用MTD提供的通用函数即可

if (!this->block_bad)

this->block_bad = nand_block_bad;

//读坏块标记函数初始化,使用MTD提供的通用函数即可

if (!this->block_markbad)

this->block_markbad = nand_default_block_markbad;

//坏块标记函数,使用MTD提供的通用函数即可

if (!this->write_buf)

this->write_buf = busw ? nand_write_buf16 : nand_write_buf;

if (!this->read_buf)

this->read_buf = busw ? nand_read_buf16 : nand_read_buf;

//以上两个个函数指针指向的函数为读写缓冲区函数,这些函数用一个for循环读写NFDATA。使用MTD提供的通用函数即可

if (!this->verify_buf)

this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;

//核对缓冲区函数函数指针初始化,使用MTD提供的通用函数即可

if (!this->scan_bbt)

this->scan_bbt = nand_default_bbt;

//创建坏块表函数函数指针初始化,使用MTD提供的通用函数即可

this->select_chip(mtd, 0);

//执行片选函数

this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);

//写READID命令字及后续命令地址

nand_maf_id = this->read_byte(mtd);

nand_dev_id = this->read_byte(mtd);

//读芯片的厂商ID及设备ID

for (i = 0; nand_flash_ids[i].name != NULL; i++) {

if (nand_dev_id != nand_flash_ids[i].id)

continue;

//在 nand_flash_ids[i]中查找是否有符合本设备ID的nand_flash_ids结构体,如果没有则继续查找,如果有则进行一些的mtd_info及nand_chip参数初始化处理。

if (!mtd->name) mtd->name = nand_flash_ids[i].name;//赋值MTD设备名称

this->chipsize = nand_flash_ids[i].chipsize << 20;//赋值芯片容量,单位为MB

 

if (!nand_flash_ids[i].pagesize) {如果nand_flash_ids数据不全(有含0项),则根据读ID获得的数据初始化mtd_info及nand_chip参数。

int extid;

 

extid = this->read_byte(mtd); //丢弃第三个读ID数据

extid = this->read_byte(mtd); //获取第四个读ID数据


mtd->oobblock = 1024 << (extid & 0x3);
extid >>= 2;
mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512);
extid >>= 2;

mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;

busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
}
else
{//否则使用nand_flash_ids提供的数据来初始化mtd_info及nand_chip参数

mtd->erasesize = nand_flash_ids[i].erasesize;
mtd->oobblock = nand_flash_ids[i].pagesize;// oobblock指页面大小,单位为KB
mtd->oobsize = mtd->oobblock / 32;
busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
//检查用户的位宽设置,如果不一致则打印出错信息,并返回初始化失败
if (busw != (this->options & NAND_BUSWIDTH_16))
{
printk (KERN_INFO "NAND device: Manufacturer ID:" " 0xx, Chip ID: 0xx (%s %s)\n",
nand_maf_id, nand_dev_id, nand_manuf_ids[i].name , mtd->name);
printk (KERN_WARNING "NAND bus width %d instead %d bit\n",
(this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8);
 this->select_chip(mtd, -1); //取消片选
 return 1;
 }
 //计算页面容量、擦除块容量、芯片容量的移位数
 this->page_shift = ffs(mtd->oobblock) - 1;
 this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
 this->chip_shift = ffs(this->chipsize) - 1;
 //指定坏块标记位置,大页面的在第一页oob区的bit0,小页面的在第一页的bit5
 this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;

//将nand_flash_ids[i].options设置的功能配置参数赋值给this->options
this->options &= ~NAND_CHIPOPTIONS_MSK;
this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;

this->options |= NAND_NO_AUTOINCR;//添加NAND_NO_AUTOINCR功能

 if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;

//清除NAND_SAMSUNG_LP_OPTIONS功能

 

//如果芯片支持多层同时擦除操作,则使用MTD提供的多层同时擦除函数初始化erase_cmd,否则使用单块擦除函数

if (this->options & NAND_4PAGE_ARRAY)

this->erase_cmd = multi_erase_cmd; else

this->erase_cmd = single_erase_cmd;

 

//如果芯片为大页面nandflash则使用大页面写命令字函数nand_command_lp if (mtd->oobblock > 512 && this->cmdfunc == nand_command)

this->cmdfunc = nand_command_lp;

 

for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {

if (nand_manuf_ids[j].id == nand_maf_id)

break;

}

break;

}

//如果在nand_manuf_ids中没有找到芯片对应的ID则返回,初始化失败。所以用户在移植MTD时一定要先确认nand_manuf_ids是否有符合自己板上NAND芯片ID的项目,如果没有则需自行添加

if (!nand_flash_ids[i].name) {

printk (KERN_WARNING "No NAND device found!!!\n");

this->select_chip(mtd, -1);

return 1;

}

//检测板上nandflash芯片数,如果不止1片则打印相关信息,并将片数赋值给i

for (i=1; i < maxchips; i++) {

this->select_chip(mtd, i);

 

 

this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);

 

 

 if (nand_maf_id != this->read_byte(mtd) || nand_dev_id != this->read_byte(mtd))
 break;
 }
 if (i > 1)
 printk(KERN_INFO "%d NAND chips detected\n", i);
 //分配oob缓冲区空间,并置位已分配标志位
 if (!this->oob_buf)
 {
 size_t len;
 len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
 this->oob_buf = kmalloc (len, GFP_KERNEL);
 if (!this->oob_buf)
 {//分配失败,返回,初始化失败
 printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
 return -ENOMEM;
 }
 this->options |= NAND_OOBBUF_ALLOC;//置位已分配标志位
 }
 //分配数据缓冲区空间,并置位已分配标志位
 if (!this->data_buf)
 {
 size_t len;
 len = mtd->oobblock + mtd->oobsize;//分配空间大小为一个页面加oob区大小
 this->data_buf = kmalloc (len, GFP_KERNEL);
 if (!this->data_buf)
 {
 if (this->options & NAND_OOBBUF_ALLOC) kfree (this->oob_buf);
 printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
 return -ENOMEM;
 }
 this->options |= NAND_DATABUF_ALLOC;
 }
 this->numchips = i; //初始化nandflash物理芯片数

mtd->size = i * this->chipsize;//计算板上nandflash总容量

this->pagemask = (this->chipsize >> this->page_shift) - 1;//芯片容量转换为页数

memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));

//如果用户没有在board_nand_init()中初始化oob区布局设计结构体指针,则根据芯片oob区的大小分配MTD在drivers/nand/nand_base.c中默认的oob区布局设计结构体,其中64byte

u-boot中NAND <wbr>flash的MTD驱动移植(转) <wbr>三
 

oob区默认的布局设计结构体为:

if (!this->autooob) {

switch (mtd->oobsize) {

case 8:

this->autooob = &nand_oob_8;

break;

case 16:

this->autooob = &nand_oob_16;

break;

case 64:

this->autooob = &nand_oob_64;

break;

default:

printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize);

}

}

 

//初始化oobavail,除去ecc校验和坏块标记所占据的字节,其他的oobfree区的字节数就是oobavail

if (this->options & NAND_BUSWIDTH_16) {

mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);

if (this->autooob->eccbytes & 0x01)

mtd->oobavail--;

} else

mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);

 

this->eccsize = 256; //ECC算法能校验的数据长度,使用MTD提供的nand_calculate_ecc时,能校验的数据长度为256字节。此处默认为该值,使用硬件校验时会在后面另行赋值。

this->eccbytes = 3; //ECC算法的校验码长度,使用MTD提供的nand_calculate_ecc时,校验码长度为3字节。

 

switch (this->eccmode) {// eccmode,ECC校验型式。这个值一定要在board_nand_init()中提前初始化,在include/linux/mtd/nand.h中定义了许多与ECC校验型式有关的宏,如果芯片没有硬件校验功能则一般使用软件校验,eccmode应赋值为NAND_ECC_SOFT,使用软件ECC校验

case NAND_ECC_HW12_2048:

if (mtd->oobblock < 2048) {

printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",

mtd->oobblock);

this->eccmode = NAND_ECC_SOFT;

this->calculate_ecc = nand_calculate_ecc;

this->correct_data = nand_correct_data;

} else

this->eccsize = 2048;

break;

 

case NAND_ECC_HW3_512:

case NAND_ECC_HW6_512:

case NAND_ECC_HW8_512:

if (mtd->oobblock == 256) {

printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");

this->eccmode = NAND_ECC_SOFT;

this->calculate_ecc = nand_calculate_ecc;

this->correct_data = nand_correct_data;

} else

this->eccsize = 512;

break;

 

case NAND_ECC_HW3_256:

break;

 

case NAND_ECC_NONE:

printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");

this->eccmode = NAND_ECC_NONE;

break;

 

case NAND_ECC_SOFT:

this->calculate_ecc = nand_calculate_ecc;

//使用软件ECC校验时,使用MTD提供的校验函数nand_calculate_ecc

this->correct_data = nand_correct_data;

//使用软件ECC校验时,使用MTD提供的纠正函数nand_correct_data

break;

 

default:

printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);

}

 

//使用硬件校验时,根据不同硬件校验类型赋值eccbyte

switch (this->eccmode) {

case NAND_ECC_HW12_2048:

this->eccbytes += 4;

case NAND_ECC_HW8_512:

this->eccbytes += 2;

case NAND_ECC_HW6_512:

this->eccbytes += 3;

case NAND_ECC_HW3_512:

case NAND_ECC_HW3_256:

if (this->calculate_ecc && this->correct_data && this->enable_hwecc)

break;

printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");

 

}

 

mtd->eccsize = this->eccsize;

 

//根据ECC校验类型及页面大小,赋值校验步数eccsteps。使用软件校验,页面大小为2048byte时,eccsteps为8

switch (this->eccmode) {

case NAND_ECC_HW12_2048:

this->eccsteps = mtd->oobblock / 2048;

break;

case NAND_ECC_HW3_512:

case NAND_ECC_HW6_512:

case NAND_ECC_HW8_512:

this->eccsteps = mtd->oobblock / 512;

break;

case NAND_ECC_HW3_256:

case NAND_ECC_SOFT:

this->eccsteps = mtd->oobblock / 256;

break;

 

case NAND_ECC_NONE:

this->eccsteps = 1;

break;

}

 

this->select_chip(mtd, -1); //取消片选

 

this->pagebuf = -1;

//初始化mtd_info结构体中的成员,包括MTD驱动的接口函数和一些参数

mtd->type = MTD_NANDFLASH; //初始化MTD设备类型为NAND

mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;

mtd->ecctype = MTD_ECC_SW;

mtd->erase = nand_erase; //初始化擦除接口函数为MTD默认提供的nand_erase

mtd->point = NULL;

mtd->unpoint = NULL;

mtd->read = nand_read; //初始化读接口函数为MTD默认提供的nand_read

mtd->write = nand_write; //初始化写口函数为MTD默认提供的nand_write

mtd->read_ecc = nand_read_ecc; //初始化读ecc接口函数(实质上该函数才是真正的读接口函数,不但能读ECC还能读nandflash中数据)为MTD默认提供的nand_read_ecc

mtd->write_ecc = nand_write_ecc; ////初始化写ecc接口函数(实质上该函数才是真正的读接口函数,不但能读ECC还能读nandflash中数据)为MTD默认提供的nand_write_ecc mtd->read_oob = nand_read_oob; //初始化读oob接口函数为MTD默认提供的nand_read_oob

mtd->write_oob = nand_write_oob; //初始化写oob接口函数为MTD默认提供的nand_write_oob

mtd->block_isbad = nand_block_isbad; //初始化坏块标志读取接口函数

mtd->block_markbad = nand_block_markbad; //初始化标记坏块接口函数为MTD默认提供的nand_write_oob

 

//赋值oob区布局设计

memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));

//调用scan_bbt (mtd)搜寻、创建坏块表

return this->scan_bbt (mtd);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值