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

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

3.4.2)MTD驱动结构及流程分析

MTD的驱动结构是围绕三个重要的数据结构展开的, 分析一个数据结构就包含了三个方面:

1、 数据结构的结构声明;

2、 数据结构的变量定义;

3、 数据结构的操作;

下面我们就MTD驱动的三个数据结构在这三方面分别分析。MTD驱动的三个重要数据结构是:struct mtd_info、struct nand_chip、struct nand_flash_dev。

1、数据结构struct mtd_info分析

该数据结构是MTD设备操作的通用接口,主要针对的是MTD设备。这其中包含了大量的描述MTD设备的基本数据和对MTD设备操作函数的函数指针。要强调的是:包含的这些函数指针指向的函数是MTD驱动提供的接口函数(每一个驱动程序的最终目的就是提供一些接口函数实现对底层硬件设备的操作),这些函数是在整个MTD驱动框架中层次最高的函数,他们可以在应用程序中直接调用实现对MTD设备底层硬件的操作。如:static int nand_read_ecc ()。它实现了对NAND flash的读操作。这些函数一般是都在u-boot源码目录下的driver/nand/nand_base.c中实现的通用操作函数。MTD驱动保证这些通用的操作函数支持对各种NAND flash芯片的操作。下面就数据结构的三个方面来具体分析struct mtd_info:

 

1) struct mtd_info的结构声明

该结构在include/linux/mtd/nand.h中做了结构声明,去掉一些编译选项、无关成员和原有注释后声明,并添加了一些重要成员的住时候,其源码如下:

struct mtd_info {

u_char type; //MTD设备类型,norflash还是NAND flash

u_int32_t flags; //MTD设备的性能描述

u_int32_t size; //MTD设备的容量

u_int32_t erasesize; //擦除单位大小

 

u_int32_t oobblock; //NAND flash 页面容量

u_int32_t oobsize; //NAND flash OOB区容量

u_int32_t oobavail; //文件系统可用的oobfree区字节数

u_int32_t ecctype; //ECC校验类型

u_int32_t eccsize;

 

int (*erase) (struct mtd_info *mtd, struct erase_info *instr);

//擦除功能函数的函数指针

int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); //读功能函数的函数指针

int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);

//写功能函数的函数指针

int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);

(实际上NAND flash读操作是在这个函数中 //NAND flash特有的读ECC功能函数

完成的)函数指针

int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);

//NAND flash特有的写ECC功能函数(实际上NAND flash写操作是在这个函数中完成的)函数指针

int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);

//NAND flash 读oob区功能函数的函数指针

int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);

//NAND flash 写oob区功能函数的函数指针

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

 

int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);

int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);

 

void *priv; //这个指针指向MTD驱动中另一个重要的数据结构struct nand_chip };

 

2) struct mtd_info的变量定义

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

nand_info_t nand_info[CFG_MAX_NAND_DEVICE];

其中有:typedef struct mtd_info nand_info_t 可知nand_info就是mtd_info,CFG_MAX_NAND_DEVICE为在include/configs/fl2440.h中必须配置的参数,它表示开发板上NAND flash的物理片数。这个变量将在nand_init()调用函数static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr)时,作为该函数的第一个实参调用,如下:

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

在MTD框架内几乎所有的函数都会有一个形参struct mtd_info *mtd,这个形参的实际值就是&nand_info[i],所以MTD框架内的函数中mtd指针指向的是在drivers/nand/nand.c中定义的变量

nand_info[i]的指针。尤其是nand_scan()函数中,大量用到了mtd这个指针来指向变量nand_info[i]。

如:mtd->write = nand_write;mtd->read_ecc = nand_read_ecc;mtd->write_ecc = nand_write_ecc;等。

3)对struct mtd_info操作(初始化)

数据结构struct mtd_info是一个简单的结构体,对它的操作比较简单。无非就是对其结构体中的成员变量进行初始化。对struct mtd_info的初始化都在函数nand_scan()中完成。该函数是初始化MTD设备的核心函数。我们将在后面详细分析它。

题外话:对一个数据结构的操作绝不仅仅是初始化,如链表,对它的操作除初始化外还包括了链表管理,如:链表成员的添加、删除等操作。这样的操作更复杂,一般通过专门的函数来实现。

 

2、 数据结构struct nand_chip分析

这个数据结构从结构名nand_chip就可以知道它主要针对MTD设备中NAND flash的描述。在这个数据结构中包含了许多参数和函数指针。其中的成员大致可以分为以下几类: 1、 与芯片有关的参数

如:page_shift、phys_erase_shift、bbt_erase_shift、chip_shift、chipsize、numchips

2、与坏块管理、ECC校验及oob区管理有关的参数:

如: eccmode、eccsize、eccbyte、eccsteps、calculate_ecc、oob_buf、oobdirty、autooob、bbt、badblockpos、bbt_td、bbt_md、badblock_pattern 3、与NAND flash控制器寄存器操作有关的参数

如:IO_ADDR_R、IO_ADDR_W

4、与NAND flash控制器寄存器操作有关的函数指针

如:read_byte、write_byte、read_word、write_word、hwcontrol、dev_ready、cmdfunc、select_chip

5、与NAND flash操作功能有关的函数指针

如:write_buf、read_buf、verify_buf、waitfunc、erase_cmd

6、与坏块管理、ECC校验及oob区管理有关的函数指针:

如:block_bad、block_markbad、calculate_ecc、correct_data、enable_hwecc、scan_bbt

综上,nand_chip主要包括了MTD驱动的低层和底层硬件操作函数的函数指针以及坏块管理、ECC校验和oob区管理需要相关函数的函数指针,这些指针指向的函数一部分在u-boot源码目录下的driver/nand/nand_base.c定义为通用函数,一部分需要用户在移植时自行编写。那些需要用户自行编写在后续的分析将会提到。nand_chip还包括了一些参数,这些参数与具体芯片型号及坏块管理策略有关,它们会在nand_scan()函数中被初始化。 1)struct nand_chip的结构声明

它在include/linux/mtd/nand.h中被声明定义,去掉一些编译选项、无关成员及原有注释,添加一些注释后如下;

struct nand_chip {

void __iomem *IO_ADDR_R; //NAND flash控制器的寄存器读访问指针, void __iomem *IO_ADDR_W; //NAND flash控制器的寄存器写访问指针,

u_char (*read_byte)(struct mtd_info *mtd);

//写一字节到NAND flash控制器的寄存器函数的函数指针

void (*write_byte)(struct mtd_info *mtd, u_char byte);

//从NAND flash控制器的寄存器读一字节函数的函数指针

 

u16 (*read_word)(struct mtd_info *mtd); //读字函数指针

void (*write_word)(struct mtd_info *mtd, u16 word); //写字函数指针

 

//读写缓冲区函数指针,所谓缓冲区无非就是自行定义的一个数组

void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);

void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);

 

int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);

//缓存校验韩式指针,验证从Flash中读取的内容是否与缓存中一致

void (*select_chip)(struct mtd_info *mtd, int chip);

//芯片片选函数指针,由于涉及底层寄存器操作该函数在移植时一般要自己编写 int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);

//读取坏块标记函数指针

int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);

//标记坏块函数指针

void (*hwcontrol)(struct mtd_info *mtd, int cmd);

//寄存器访问控制函数指针,该函数根据第二个参数cmd使O_ADDR_R/W指向不同的寄存器

int (*dev_ready)(struct mtd_info *mtd);

//设备状态读取函数指针,该函数读取NAND flash控制器的NFSTAT的bit0,获取R/B状态

void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);

//向NAND flash写一个命令字,如果形参column、page_addr不都为-1则还向NAND flash写一个地址

int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);

//操作超时处理函数指针,该函数根据命令的不同设定不同的超时时间并时刻检

查R/B位直到R/B状态进入Ready状态否则为操作超时。

int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); //ECC编码计算函数指针,该函数通过软件算法计算256字节的3字节ECC编码 int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);

//ECC检测纠正函数,该函数检测并纠正256字节块中的1位错误。

void (*enable_hwecc)(struct mtd_info *mtd, int mode);

//使能硬件计算ECC码函数指针

void (*erase_cmd)(struct mtd_info *mtd, int page);

//擦除指定块函数的函数指针

int (*scan_bbt)(struct mtd_info *mtd);

//坏块标记表创建函数指针

int eccmode;// ECC的计算方法, NAND_ECC_SOFT时意指软件运算,即采用calculate_ecc进行运算,利用correct_data进行校正

int eccsize;// ECC校准的数据长度,用calculate_ecc进行校准时,数据长度固定为256字节

int eccbytes;// ECC校验码字节数,软件校准时为3字节

int eccsteps;// ECC校验的步数,当FLASH每页的字节数为512字节,而calculate_ecc每次仅能校验256字节,则需要两步才能校验完成。

int chip_delay;// 等待时间,一般用于等待Flash的R/B管脚

int page_shift;// 页的地址移位数,当为512(2^9)字节的空间,其该值为9 int phys_erase_shift;// 块的地址移位数

int bbt_erase_shift;// 在bbt表中,相间隔两个内容之间的地址差的位数,也即是块的地址位数

int chip_shift;// 芯片总的地址位数

u_char *data_buf; //数据缓冲区指针

u_char *oob_buf;//oob缓冲区指针

int oobdirty;// 表示oob_buf内是否有内容,如为0表示oob_buf为空(0xFF),为1表示oob_buf中已有内容

u_char *data_poi;// 指向一个临时使用的数据区

unsigned int options;

//MTD驱动中配置NAND FALSH芯片的扩展功能,如NAND_IS_AND、NAND_USE_FLASH_BBT、NAND_COPYBACK等等和重要参数,如位宽NAND_BUSWIDTH_16。上述的这些宏在include/linux/mtd/nand.h均有定义,这些宏的定义能保证当它们进行或运算是能保证options能同时接受这些扩展功能和参数。及options某bit位为1时则使用对应的扩展功能。如有:

#define NAND_COPYBACK 0x00000010

那么如果options的bit4位为1则使用copyback功能,在MTD中大量使用了这种技巧,需要注意

int badblockpos;// 坏块标记的位置。当芯片为小页面NAND flashs时值为NAND_SMALL_BADBLOCK_POS(即为5);为大页面时值为NAND_BIG _BADBLOCK_POS(即为0)

 

int numchips;//开发板上NAND flash芯片的片数 unsigned long chipsize;// 芯片的容量

int

int pagemask;//页地址掩码 pagebuf;// 存储Data_buf内的相关的页号

 

struct nand_oobinfo *autooob;

// oob区布局设计结构体指针。从功能上看,oob区和数据存储区一样可以存储数据,但是oob区一般不会用于存储数据,而是做为坏块标记和ECC校验数据存储。其中坏块标记位置一般有约定俗成的位置,而oob区的布局设计有很多不同的设计,MTD使用一个结构体来描述这种设计,oob区布局设计结构体在include/linux/mtd/mtd_abi.h中定义如下:

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

其中useecc 为使用ECC校验标志,eccbyte为ECC校验的位数,eccpos为ECC校验所存的位号,oobfree为OOB中ECC未使用到的字节(起始地址+长度)

uint8_t *bbt;// 指向内存中坏块表的指针

struct nand_bbt_descr *bbt_td;// 用以Flash中坏块表搜索的相关描述

truct nand_bbt_descr *bbt_md;// 上述描述的镜像

struct nand_hw_control *controller;// 用以实现互锁操作,此处并未使用

void *priv;//用途不明

};

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值