今天学习了NandFlash的驱动,硬件操作非常简单,就是这个linux下的驱动比较复杂,主要还是MTD层的问题,用了一下午时间整理出来一份详细的分析,只是分析函数结构和调用关系,具体代码实现就不看了,里面有N个结构体,搞得我头大。我用linux2.6.25内核,2440板子,先从启动信息入手。内核启动信息,NAND部分:S3C24XXNANDDriver,(c)2004SimtecElectronicss3c2440-nands3c2440-nand:Tacls=2,20nsTwrph0=330ns,Twrph1=220nsNANDdevice:ManufacturerID:0xec,ChipID:0x76(SamsungNAND64MiB3,3V8-bit)ScanningdeviceforbadblocksCreating3MTDpartitionsonNAND64MiB3,3V8-bit:0x00000000-0x00040000:boot0x0004c000-0x0024c000:kernel0x0024c000-0x03ffc000:yaffs2第一行,在driver/mtd/nand/s3c2410.c中第910行,s3c2410_nand_init函数:printk(S3C24XXNANDDriver,(c)2004SimtecElectronics\n);行二行,同一文件,第212行,s3c2410_nand_inithw函数:dev_info(info-device,Tacls=%d,%dnsTwrph0=%d%dns,Twrph1=%d%dns\n,tacls,to_ns(tacls,clkrate),twrph0,to_ns(twrph0,clkrate),twrph1,to_ns(twrph1,clkrate));第三行,在driver/mtd/nand/nand_base.c中第2346行,printk(KERN_INFONANDdevice:ManufacturerID:0x%02x,ChipID:0x%02x(%s%s)\n,*maf_id,dev_id,nand_manuf_ids[maf_idx].name,type-name);第四行,在driver/mtd/nand/nand_bbt.c中第380行,creat_bbt函数:Printk(KERNINFOScanningdeviceforbadblocks\n);第五行,在driver/mtd/mtdpart.c中第340行,add_mtd_partitions函数:printk(KERN_NOTICECreating%dMTDpartitionson\%s\:\n,nbparts,master-name);下面三行,是flash分区表,也在mtdpart.c同一函数中,第430行:printk(KERN_NOTICE0x%08x-0x%08x:\%s\\n,slave-offset,slave-offset+slave-mtd.size,slave-mtd.name);MTD体系结构:在linux中提供了MTD(MemoryTechnologyDevice,内存技术设备)系统来建立Flash针对linux的统一、抽象的接口引入MTD后,linux系统中的Flash设备驱动及接口可分为4层:设备节点MTD设备层MTD原始设备层硬件驱动层硬件驱动层:Flash硬件驱动层负责底层硬件设备实际的读、写、擦除,LinuxMTD设备的NAND型Flash驱动位于driver/mtd/nand子目录下s3c2410对应的nandFlash驱动为s3c2410.cMTD原始设备层:MTD原始设备层由两部分构成,一部分是MTD原始设备的通用代码,另一部分是各个特定Flash的数据,比如分区主要构成的文件有:drivers/mtd/mtdcore.c支持mtd字符设备driver/mtd/mtdpart.c支持mtd块设备MTD设备层:基于MTD原始设备,Linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90),构成MTD设备层简单的说就是:使用一个mtd层来作为具体的硬件设备驱动和上层文件系统的桥梁。mtd给出了系统中所有mtd设备(nand,nor,diskonchip)的统一组织方式。mtd层用一个数组structmtd_info*mtd_table[MAX_MTD_DEVICES]保存系统中所有的设备,mtd设备利用structmtd_info这个结构来描述,该结构中描述了存储设备的基本信息和具体操作所需要的内核函数,mtd系统的那个机制主要就是围绕这个结构来实现的。结构体在include/linux/mtd/mtd.h中定义:structmtd_info{u_chartype;//MTD设备类型u_int32_tflags;//MTD设备属性标志u_int32_tsize;//标示了这个mtd设备的大小u_int32_terasesize;//MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小u_int32_toobblock;//oob区在页内的位置,对于512字节一页的nand来说是512u_int32_toobsize;//oob区的大小,对于512字节一页的nand来说是16u_int32_tecctype;//ecc校验类型u_int32_teccsize;//ecc的大小char*name;//设备的名字intindex;//设备在MTD列表中的位置structnand_oobinfooobinfo;//oob区的信息,包括是否使用ecc,ecc的大小//以下是关于mtd的一些读写函数,将在nand_base中的nand_scan中重载int(*erase)int(*read)int(*write)int(*read_ecc)int(*write_ecc)int(*read_oob)int(*read_oob)void*priv;//设备私有数据指针,对于NandFlash来说指nand芯片的结构下面看nand_chip结构,在include/linux/mtd/nand.h中定义:structnand_chip{void__iomem*IO_ADDR_R;//这是nandflash的读写寄存器void__iomem*IO_ADDR_W;//以下都是nandflash的操作函数,这些函数将根据相应的配置进行重载u_char(*read_byte)(structmtd_info*mtd);void(*write_byte)(structmtd_info*mtd,u_charbyte);u16(*read_word)(structmtd_info*mtd);void(*write_word)(structmtd_info*mtd,u16word);void(*write_buf)(structmtd_info*mtd,constu_char*buf,intlen);void(*read_buf)(structmtd_info*mtd,u_char*buf,intlen);int(*verify_buf)(structmtd_info*mtd,constu_char*buf,intlen);void(*select_chip)(structmtd_info*mtd,intchip);int(*block_bad)(structmtd_info*mtd,loff_tofs,intgetchip);int(*block_markbad)(structmtd_info*mtd,loff_tofs);void(*hwcontrol)(structmtd_info*mtd,intcmd);int(*dev_ready)(structmtd_info*mtd);void(*cmdfunc)(structmtd_info*mtd,unsignedcommand,intcolumn,intpage_addr);int(*waitfunc)(structmtd_info*mtd,structnand_chip*this,intstate);int(*calculate_ecc)(structmtd_info*mtd,constu_char*dat,u_char*ecc_code);int(*correct_data)(structmtd_info*mtd,u_char*dat,u_char*read_ecc,u_char*calc_ecc);void(*enable_hwecc)(structmtd_info*mtd,intmode);void(*erase_cmd)(structmtd_info*mtd,intpage);int(*scan_bbt)(structmtd_info*mtd);inteccmode;//ecc的校验模式(软件,硬件)intchip_delay;//芯片时序延迟参数intpage_shift;//页偏移,对于512B/页的,一般是9u_char*data_buf;//数据缓存区跟NAND操作相关的函数:1、nand_base.c:定义了NAND驱动中对NAND芯片最基本的操作函数和操作流程,如擦除、读写page、读写oob等。当然这些函数都只是进行一些常规的操作,若你的系统在对NAND操作时有一些特殊的动作,则需要在你自己的驱动代码中进行定义。2、nand_bbt.c:定义了NAND驱动中与坏块管理有关的函数和结构体。3、nand_ids.c:定义了两个全局类型的结构体:structnand_flash_devnand_flash_ids[]和structnand_manufacturersnand_manuf_ids[]。其中前者定义了一些NAND芯片的类型,后者定义了NAND芯片的几个厂商。NAND芯片的ID至少包含两项内容:厂商ID和厂商为自己的NAND芯片定义的芯片ID。当NAND加载时会找这两个结构体,读出ID,如果找不到,就会加载失败。4、nand_ecc.c:定义了NAND驱动中与softewareECC有关的函数和结构体,若你的系统支持hardwareECC,且不需要softwareECC,则该文件也不需理会。我们需要关心的是/nand/s3c2410,这个文件实现的是s3c2410/2440nandflash控制器最基本的硬件操作,读写擦除操作由上层函数完成。s3c2410.c分析:首先看一下要用到的结构体的注册:structs3c2410_nand_mtd{structmtd_infomtd;//mtd_info的结构体structnand_chipchip;//nand_chip的结构体structs3c2410_nand_set*set;structs3c2410_nand_info*info;intscan_res;};enums3c_cpu_type{//用来枚举CPU类型TYPE_S3C2410,TYPE_S3C2412,TYPE_S3C2440,};structs3c2410_nand_info{/*mtdinfo*/structnand_hw_controlcontroller;structs3c2410_nand_mtd*mtds;structs3c2410_platform_nand*platform;/*deviceinfo*/structdevice*device;structresource*area;structclk*clk;void__iomem*regs;void__iomem*sel_reg;intsel_bit;intmtd_count;unsignedlongsave_nfconf;enums3c_cpu_typecpu_type;};设备的注册:staticint__inits3c2410_na