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

基于MTD的NANDFLASH设备驱动底层实现原理分析(五)

发布时间:2020-12-15 07:10:14 所属栏目:百科 来源:网络整理
导读:Linux内核在MTD的下层实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c)因此芯片级的驱动实现不再需要我们关心mtd中的那些成员函数了主题转移到nand_chip数据结构中 先了解了解nand_chip结构体 struct nand_chip { ?? ?void? __iomem?? ?*IO_ADDR_R;??? /
Linux内核在MTD的下层实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c)因此芯片级的驱动实现不再需要我们关心mtd中的那些成员函数了主题转移到nand_chip数据结构中

先了解了解nand_chip结构体

struct nand_chip {
?? ?void? __iomem?? ?*IO_ADDR_R;??? //读8位I/O线的地址
?? ?void? __iomem?? ?*IO_ADDR_W;?? //写8位I/O线的地址
??? uint8_t?? ??? ?(*read_byte)(struct mtd_info *mtd);//从芯片读一个字节
?? ?u16?? ??? ?(*read_word)(struct mtd_info *mtd);//从芯片读一个字
?? ?void?? ??? ?(*write_buf)(struct mtd_info *mtd,const uint8_t *buf,int len);//将缓冲区的数据写入芯片
?? ?void?? ??? ?(*read_buf)(struct mtd_info *mtd,uint8_t *buf,int len);//将芯片中的数据独到缓冲区中

??? int?? ??? ?(*verify_buf)(struct mtd_info *mtd,int len); //验证芯片和写入缓冲区中的数据

?? int ? ? ? ? (*block_bad)(struct mtd_info *mtd,loff_t ofs,int getchip);//检查是否坏块
?? ?int?? ??? ?(*block_markbad)(struct mtd_info *mtd,loff_t ofs);//标记坏块

??? void?? ??? ?(*select_chip)(struct mtd_info *mtd,int chip);????????? //实现选中芯片
?? ?void?? ??? ?(*cmd_ctrl)(struct mtd_info *mtd,int dat,???????????????
?? ??? ??? ??? ???? unsigned int ctrl);//控制ALE/CLE/nCE,也用于写命令和地址
?? ?int?? ??? ?(*dev_ready)(struct mtd_info *mtd);//设备就绪
?? ?void?? ??? ?(*cmdfunc)(struct mtd_info *mtd,unsigned command,int column,int page_addr); //实现命令发送

??? int?? ??? ?(*waitfunc)(struct mtd_info *mtd,struct nand_chip *this);
?? ?void?? ??? ?(*erase_cmd)(struct mtd_info *mtd,int page);//擦除命令的处理
?? ?int?? ??? ?(*scan_bbt)(struct mtd_info *mtd);//扫描坏块
?? ?int?? ??? ?(*errstat)(struct mtd_info *mtd,struct nand_chip *this,int state,int status,int page);

??? int?? ??? ?(*write_page)(struct mtd_info *mtd,struct nand_chip *chip,
?? ??? ??? ??? ?????? const uint8_t *buf,int page,int cached,int raw);//写一页

??? int?? ??? ?chip_delay;//有板决定的延迟时间
?? unsigned int?? ?options;//与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等,至于这些选项具体表示什么含义,可以参考<linux/mtd/nand.h>,那里有较为详细的说明;

?? ?int?? ??? ?page_shift;//用位表示的NAND芯片的page大小,如某片NAND芯片的一个page有512个字节,那么page_shift就是9;
?? ?int?? ??? ?phys_erase_shift;//用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14;
?? ?int?? ??? ?bbt_erase_shift;//用位表示的bad block table的大小,通常一个bbt占用一个block,所以bbt_erase_shift通常与phys_erase_shift相等;
?? ?int?? ??? ?chip_shift;用位表示的NAND芯片的容量;
?? ?int?? ??? ?numchips;表示系统中有多少片NAND芯片;
?? ?uint64_t?? ?chipsize;//NAND芯片的大小;
?? ?int?? ??? ?pagemask;//计算page number时的掩码,总是等于chipsize/page大小- 1;
?? ?int?? ??? ?pagebuf;用来保存当前读取的NAND芯片的page number,这样一来,下次读取的数据若还是属于同一个page,就不必再从NAND芯片读取了,而是从data_buf中直接得到;
?? ?int?? ??? ?subpagesize;
?? ?uint8_t?? ??? ?cellinfo;
?? ?int?? ??? ?badblockpos;
?? ?int?? ??? ?badblockbits;

?? ?flstate_t?? ?state;

?? ?uint8_t?? ??? ?*oob_poi;
?? ?struct nand_hw_control? *controller;
?? ?struct nand_ecclayout?? ?*ecclayout;

?? ?struct nand_ecc_ctrl ecc;
?? ?struct nand_buffers *buffers;
?? ?struct nand_hw_control hwcontrol;

?? ?struct mtd_oob_ops ops;

?? ?uint8_t?? ??? ?*bbt;
?? ?struct nand_bbt_descr?? ?*bbt_td;
?? ?struct nand_bbt_descr?? ?*bbt_md;

?? ?struct nand_bbt_descr?? ?*badblock_pattern;

?? ?void?? ??? ?*priv;

};


这上面有一个与ECC相关的结构体?struct nand_ecc_ctrl

struct nand_ecc_ctrl {
?? ?nand_ecc_modes_t?? ?mode;
?? ?int?? ??? ??? ?steps;
?? ?int?? ??? ??? ?size;
?? ?int?? ??? ??? ?bytes;
?? ?int?? ??? ??? ?total;
?? ?int?? ??? ??? ?prepad;
?? ?int?? ??? ??? ?postpad;
?? ?struct nand_ecclayout?? ?*layout;
?? ?void?? ??? ??? ?(*hwctl)(struct mtd_info *mtd,int mode);/**控制硬件ECC*/
?? ?int?? ??? ??? ?(*calculate)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ????? const uint8_t *dat,
?? ??? ??? ??? ??? ????? uint8_t *ecc_code);/**根据data计算ecc值**/
?? ?int?? ??? ??? ?(*correct)(struct mtd_info *mtd,uint8_t *dat,
?? ??? ??? ??? ??? ??? uint8_t *read_ecc,
?? ??? ??? ??? ??? ??? uint8_t *calc_ecc);
?? ?int?? ??? ??? ?(*read_page_raw)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ??? ? struct nand_chip *chip,
?? ??? ??? ??? ??? ??? ? uint8_t *buf,int page);/**向NANDFLASH芯片读一个页的原始数据*/
?? ?void?? ??? ??? ?(*write_page_raw)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ??? ?? struct nand_chip *chip,
?? ??? ??? ??? ??? ??? ?? const uint8_t *buf);
?? ?int?? ??? ??? ?(*read_page)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ????? struct nand_chip *chip,
?? ??? ??? ??? ??? ????? uint8_t *buf,int page);/**读一个页但包含ecc校验*/
?? ?int?? ??? ??? ?(*read_subpage)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ????? uint32_t offs,uint32_t len,
?? ??? ??? ??? ??? ????? uint8_t *buf);
?? ?void?? ??? ??? ?(*write_page)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ?????? struct nand_chip *chip,
?? ??? ??? ??? ??? ?????? const uint8_t *buf);
?? ?int?? ??? ??? ?(*read_oob)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ???? struct nand_chip *chip,
?? ??? ??? ??? ??? ???? int page,
?? ??? ??? ??? ??? ???? int sndcmd);/**读OOB但不包含MAIN部分**/
?? ?int?? ??? ??? ?(*write_oob)(struct mtd_info *mtd,
?? ??? ??? ??? ??? ????? int page);
};


hwctl:这个函数用来控制硬件产生ecc,其实它主要的工作就是控制NAND controller向NAND芯片发出NAND_ECC_READ、NAND_ECC_WRITE和NAND_ECC_READSYN等命令,与struct nand_chip结构体中的cmdfunc类似,只不过发起的命令是ECC相关的罢了;
?
calculate:根据data计算ecc值;
?
correct:根据ecc值,判断读写数据时是否有错误发生,若有错,则立即试着纠正,纠正失败则返回错误;
?
read_page_raw和write_page_raw:从NAND芯片中读取一个page的原始数据和向NAND芯片写入一个page的原始数据,所谓的原始数据,即不对读写的数据做ecc处理,该读写什么值就读写什么值。另外,这两个函数会读写整个page中的所有内容,即不但会读写一个page中MAIN部分,还会读写OOB部分。
?
read_page和write_page:与read_page_raw和write_page_raw类似,但不同的是,read_page和write_page在读写过程中会加入ecc的计算,校验,和纠正等处理。
read_oob和write_oob:读写oob中的内容,不包括MAIN部分。
?
其实,以上提到的这几个read_xxx和write_xxx函数,最终都会调用struct nand_chip中的read_buf和write_buf这两个函数,所以如果没有特殊需求的话,我认为不必自己实现,使用MTD提供的default的函数即可。


下面这个结构体用来ECC在oob中布局的一个结构体。

struct nand_ecclayout {
?? ?__u32 eccbytes;//ecc字节数,对于512字节/page的NANDflash,eccbytes=3,如果需要额外用到oob中的数据,那么也可以大于3.
?? ?__u32 eccpos[64];ECC数据在oob中的位置,这里之所以是个64字节的数组,是因为对于2K/页NAND来说,它的oob64个字节。而对于512字节/pageNAND来说,可以而且只可以定义它的前16个字节。
?? ?__u32 oobavail;OOB中可用的字节数,不需要对该成员赋值,MTD会根据其他三个成员计算出来
?? ?struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];//显示定义空闲的OOB字节
};

大家都知道OOB但是OOB里面究竟存了些什么,0)">OOB主要用来存储两种信息:坏块信息和ECC数据,对于小页的NANDFLASH一般坏块占据一个字节(并且是在第6个字节),ECC占3个字节,上面这个结构体就是起到了这个作用告诉那些与操作ECC无关的函数,在OOB区域里那部分是来存储ECC的(不可他用),那些字节是空闲的

(编辑:李大同)

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

    推荐文章
      热点阅读