Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1433696
  • 博文数量: 1334
  • 博客积分: 645
  • 博客等级: 上士
  • 技术积分: 5762
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-25 16:56
文章分类

全部博文(1334)

文章存档

2014年(108)

2013年(1059)

2012年(169)

分类: LINUX

2013-02-21 05:05:10

原文地址:NAND Falsh驱动分析 作者:leon_yu

1.驱动结构:

Linux系统中,用MTD(Memory Technology Device,内存技术设备)系统用来建立Flash针对Linux的统一、抽象的接口,Flash驱动及接口分为4层。

①硬件驱动层:负责FLASH硬件设备的读写,擦除。LinuxMTDNORFLASHdrivers/mtd/chips子目录下,NANDdrivers/mtd/nand/目录下

MTD原始设备层:包括两部分,一是MTD原始设备的通用代码,另一部分是各个特定的FLASH的数据,如分区

MTD设备层

基于MTD原始设备层,Linux系统定义MTD的块设备(设备号31)和字符设备(设备号90),MTD字符设备定义在mtdchar.cMTD快设备则是定义了一个描述MTD块设备的结构体mtdblk_dev,并声明了一个名为mtdblks的指针数组,这个数组中的每一个mtdblk_devmtd_table中的每一个mtd_info一一对应

④设备节点:通过mknod/dev目录下建立MTD块设备节点31,字符设备节点90。用户通过访问此设备节点访问MTD设备。

2.数据结构

Mtd_info用于描述MTD原始设备,这其中定义了大量关于MTD的数据和操作函数。每个分区被认为是一个mtd_info,如果有两个MTD原始设备,每个有3个分区,在系统中就有6mtd_info结构体,这些mtd_info指针被存放在mtd_table数组里。

mtd_infotype字段表示底层物理设备类型,如MTD_RAM,MTD_NORFlash, MTD_NANDFlash,.

Flag字段表示MTD_ERASEABLE(可擦除)MTD_WRITEB_WRITEABLE(可编程)MTD_XIP(可片内执行),MTD_OOB(NAND带外数据)MTD_ECC(支持自动ECC)。

Mtd_info中的read(),write(),read_oob(),wreite_oob(),这些函数对NAND,NOR是透明的。

添加和删除MTD设备:

int add_mtd_device(struct mtd_info *mtd);

int del_mtd_device (struct mtd_info *mtd);

.mtd_part结构,用于描述分区,其mtd_info成员用于描述本分区,它会被加入到mtd_table中,其他部分成员由其主分区mtd_part->master决定,主分区(涵盖所有分区)不作为一个MTD原始设备加入mtd_table

struct mtd_part {

         struct mtd_info mtd; //分区信息(大部分有其master决定)

         struct mtd_info *master;//该分区的主分区

         u_int32_t offset;     //该分区的偏移地址

         int index;   //分区号

         struct list_head list;

         int registered;

};

.mtd_partion会在MTD原始设备层调用add_mtd_partions()时传递分区信息用,

struct mtd_partition {

         char *name;                            /* identifier string */

         u_int32_t size;                        /* partition size */

         u_int32_t offset;           /* offset within the master MTD space */

         u_int32_t mask_flags;            /* master MTD flags to mask out for this partition */

         struct nand_ecclayout *ecclayout;   /* out of band layout for this partition (NAND only)*/

         struct mtd_info **mtdp;                  /* pointer to store the MTD object */

};

Flash驱动中使用两个函数注册和注销分区

int add_mtd_partitions(struct mtd_info *master,

                          const struct mtd_partition *parts,

                          int nbparts)

int del_mtd_partitions(struct mtd_info *master);

 

add_mtd_partitions()会对每一个新建分区建立一个新的mtd_part结构体,将其加入mtd_partitions中,并调用add_mtd_device()将此分区作为MTD设备加入mtd_table中,成功返回0,如分配mtd_part时内存不足,则返回-ENOMEMadd_mtd_partitions()新建的mtd_part需要依赖传入的mtd_partion参数对其初始化。

del_mtd_partitions()作用是对于mtd_partions上的每一个分区,若它的主分区是master,则将它从mtd_partionsmtd_table中删除并释放掉,这个函数会调用del_mtd_device()

3.Nor flash驱动:

只需要定义具体的内存映射情况结构体map_info并使用指定接口类型调用do_map_probe()map_infoNOR flash驱动的核心,它指定了NOR的基址,位宽,大小等信息以及flash的读写函数,甚至NOR驱动代码本质上可以被认为是根据map_info探测芯片的过程

NOR Flash驱动主要工作:

定义map_info的实例,初始化其中的成员,根据目标板的情况为name,size,bankwidthphys赋值

如果Flash要分区,则定义mtd_partition数组,将实际电路板中Flash分区信息记录与其中

map_info和探测的接口类型为参数(“cif_probe”,”jedec_probe”)为参数调用do_map_probe(),探测Flash得到mtd_info.

Do_map_probe会根据传入的参数name通过get_mtd_chip_driver()得到具体的MTD驱动,调用与接口对应的probe()函数探测设备,利用map_info中的配置,do_map_probe()可以自动支持CFIJEDEC接口的Flash芯片,MTD以后会自动采用适当的命令参数对flash进行读写或擦除

在模块初始化时以mtd_info为参数调用add_mtd_deviece()或以mtd_info,mtd_partition数据以及分区数为参数调用add_mtd_partitions()注册设备或分区。当然,在这之前可以调用parse_mtd_partitions()查看flash是否已有分区信息,并将查看出的分区信息通过add_mtd_partition()注册

在模块卸载时调用“反函数”删除设备或分区

4.NAND FLASH驱动

Linux内核在MTD下层实现了通用的NAND驱动(主要通过driver/mtd/nand/nand_base.c实现),因此芯片级的NAND驱动不用再实现mtd_info中的read,write_oob()等函数,主题转移到nand_chip数据结构。

MTDnand_chip结构表示一个NAND芯片,这个结构体包含了NAND的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制

如果flash要分区,则定义mtd_partition数组,将实际电路板中的flash分区信息记录其中

在模块加载时分配nand_chip内存,根据目标板NAND控制器的特殊情况初始化nand_chip中的hwcontrol(),calculate_eccread_byte()等,若不赋值会使用nand_base.c中的默认函数,若使用软件ECC,不需要赋值calculate_ecc()correct_date()成员。

mtd_info为参数调用nand_scan()函数探测NAND FLASH的存在。Nand_scan()函数会读取NAND芯片ID,并根据mtd->privnand_chip中的成员初始化mtd_info.

如果要分区,则以mtd_infomtd_parition为参数调用add_mtd_partition(),添加分区信息

Ps.NAND芯片级驱动中,若在nand_chip中没有赋值,将使用nand_base.c中默认的参数,比如/* Define default oob placement schemes for large and small page devices */

static struct nand_ecclayout nand_oob_8 = {

         .eccbytes = 3,

         .eccpos = {0, 1, 2},

         .oobfree = {

                   {.offset = 3,

                    .length = 2},

                   {.offset = 6,

                    .length = 2}}

};

 

Parse_mtd_partitions()用于解析MTD分区信息,常见的MTD分区解析是命令行解析,即解析在Linux启动命令行中通过mtdparts=传入的MTD分区信息

通过查看/proc/mtd文件可以获知系统中包含的MTD分区

Linux2.6内核中,s3c2410NAND被注册为一个平台设备,当NAND驱动模块调用platform_driver_register($s3c2410_nand_driver)注册平台驱动时,其对应的platform_driver结构体的s3c24xx_nand_probe()成员函数被调用,在该函数中将调用前述的s3c2410_nand_init_chip()初始化nand_chip,通过nand_scan()扫描到NAND Flash存储器后,调用s3c2410_nand_add_partition()添加MTD分区和设备信息。

同样地,当nand驱动模块卸载调用platform_driver_unregister($s3c2410_nand_driver)。

阅读(218) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~