高手进阶 Linux系统下MTD/CFI驱动介绍
某些Intel的FLASH芯片(如StrataFlash系列)支持多分区,也就是各个分区可以同时进行操作。应该说这是不错的特性,但是也会带来些问题。记得当初移植Linux-2.4.21,挂JFFS2文件系统的时候,经常会报一些"Magic bitmask not found"之类的错误,跟进去发现FLASH读出来的都是些0x80之类的数据,查看资料发现该款FLASH有分区的特性,而Linux的FLASH驱动只用一个状态变量表示整个FLASH的状态,这就会造成某个分区的实际状态和系统记录的不符,从而导致读FLASH的时候该点实际上不处在读状态。当时的解决办法是,每次读的时候,不管记录的状态是什么,先进入读状态再说,当然这会带来性能的下降,具体损失多少个时钟周期就不算了。
话说进入Linux-2.6.x的时代(具体是2.6.13),除了Lock/Unlock(Linux在擦/写的时候不先Unlock,解决办法就是初始化的时候先全部Unlock)这个老问题外,竟然多分区的错误没有出现,惊讶之下决定好好研究下Linux的MTD/FLASH驱动。
说驱动之前,先明确几个编程要点:
1:读写,要按照总线位宽读写,注意不是FLASH芯片位宽(例如背靠背)。
2:寻址,程序要访问的地址和FLASH芯片地址引脚得到的值是不一样的,例如16位的FLASH芯片,对于CPU,0x00和0x01表示2个不同的字节,但是到了FLASH引脚得到的都是0,也就是都指向FLASH的第一个WORD。可以认为地址总线的bit0悬空,或者认为转换总线, bit0上实际输出的是bit1。这个解释了要点1。
3:芯片手册提到偏移量都是基于WORD的,而WORD的位宽取决于芯片的位宽,因此在下命令的时候,实际偏移=手册偏移*buswidth/8。
4:芯片手册提到的变量长度(典型如CFI信息)例如2,指的是,变量是个16bit数,但是读的时候,要读2个WORD,然后把每个WORD的低8位拼成1个16bit数。读WORD再拼凑确实挺麻烦,尤其是读取大结构的时候,不过参照cfi_util.c的cfi_read_pri函数的做法就简单了。
5:背靠背,也就是比方说2块16位的芯片一起接在32位的总线上。带来的就是寻址的问题,很显然,首先要按32位读写;其次就是下命令的地址,实际偏移=手册偏移*interleave*device_type/8,device_type=buswidth/interleave,而buswidth这个时候是32(总线位宽)。另外就是背靠背的时候,命令和返回的状态码是“双份的”,例如2块16位背靠背,读命令是0x00ff00ff。
如果不是想写像Linux那么灵活的代码(考虑各种接法/位宽/CFI获取信息等),那事情就简单很多,只要考虑要点1以及擦除块的大小就好了,当然如果是背靠背接法,擦除块的实际大小要乘个interleave。
进入Linux代码
关于CHIP/MAP/MTD之间绕来绕去的关系现在还糊涂着呢,因此下面只是简单的跟一下脉络和各个编程要点。
1:构造map_info结构,指定基址/位宽/大小等信息以及"cfi_probe"限定,然后调用do_map_probe()。
2:do_map_probe()根据名字"cfi_probe"找到芯片驱动"cfi_probe.c"直接调用cfi_probe()。
3:cfi_probe()直接调用mtd_do_chip_probe(),传入cfi_probe_chip()函数指针。
4:mtd_do_chip_probe()分2步,先调用genprobe_ident_chips()探测芯片信息,后调用check_cmd_set()获取和初始化芯片命令集(多分区初始化就在里面)。
5:genprobe_ident_chips()函数如果不考虑多芯片串连的情况,那只需看前面的genprobe_new_chip()调用,完成后cfi.chipshift=cfi.cfiq->DevSize,2^chipshift=FLASH大小。
6:genprobe_new_chip()枚举各种不同的芯片位宽和背靠背数量,结合配置设定依次调用步骤3的cfi_probe_chip(),注意cfi->device_type=bankwidth/nr_chips,bankwidth是总线位宽,device_type是芯片位宽。这里我们只需要注意有限复杂情况即可,所谓有限复杂指的是编译时确定的复杂连接。这样,cfi_probe_chip()只有第1次调用才成功,如果考虑32位宽的FLASH插在16bit总线上的情况,那第2次调用成功。
7:cfi_probe_chip(),由于步骤6的原因,函数就在cfi_chip_setup()直接返回,后面的代码就不用考虑了。
8:cfi_chip_setup()读取CFI信息,可以留意下Linux是怎么实现要点4的。
9:回到步骤4的check_cmd_set()阶段,进入cfi_cmdset_0001()函数,先调用read_pri_intelext()读取Intel的扩展信息,然后调用cfi_intelext_setup()初始化自身结构。
10:read_pri_intelext()函数,可以留意下怎么读取变长结构的技巧,也就是"need_more"的用法。这里说明下一些变量的含义,例如对于StrataFlash 128Mb Bottom类型的的FLASH芯片,块结构是4*32KB+127*128KB=16MB,一共16个分区,每个分区1MB。nb_parts=2。
第1部分
NumIdentPartitions=1 // 有1个重复的分区
NumBlockTypes=2 // 分区内有2种不同的Block类型
第1类型
NumIdentBlocks=3 // 有4个Block(3+1)
BlockSize=0x80 // 32KB(0x80*256)
第2类型
NumIdentBlocks=6 // 有7个Block(6+1)
BlockSize=0x200 // 128KB(0x200*256)
第2部分
NumIdentPartitions=15// 有15个重复的分区
NumBlockTypes=1 // 分区内有1种Block类型
第1类型
NumIdentBlocks=7 // 有8个Block(7+1)
BlockSize=0x200 // 128KB(0x200*256)
11:cfi_intelext_setup()函数首先根据CFI建立mtd_erase_region_info信息,然后调用cfi_intelext_partition_fixup()来支持分区。
12:cfi_intelext_partition_fixup()用来建立虚拟Chip,每个分区对应1个Chip,不过并没有完全根据CFI扩展信息来建立,而是假定每个分区的大小都一致。cfi->chipshift调整为partshift,各个虚拟chip->start调整为各分区的基址。将来访问FLASH的入口函数cfi_varsize_frob()就根据ofs得到chipnum(chipnum=ofs>>cfi->chipshift),这也是为什么要假定分区一致的原因。
分享到:
相关推荐
"Linux系统下MTD/CFI驱动介绍" 在Linux系统下,MTD/CFI驱动是Flash存储器的驱动程序。MTD是Memory Technology Device的缩写,是Linux系统下的Flash存储器驱动接口。CFI是Common Flash Interface的缩写,是一个工业...
在Linux操作系统中,存储设备的管理分为不同的层次,其中一种是Memory Technology Device(MTD),主要用来处理非易失性存储器,如闪存。在Linux内核中,MTD层提供了一个抽象接口来访问这些特殊的存储介质。当我们...
2. `drivers/mtd/`目录下的驱动源码:这里包含了各种具体的MTD设备驱动,如NAND、SPI等。 3. `drivers/mtd/maps/`目录:包含了一些映射驱动,用于将MTD设备映射到块设备。 4. `drivers/mtd/nand/`目录:NAND Flash的...
MTD驱动程序是Linux内核的一部分,它提供了一个抽象层,使得操作系统可以方便地与各种不同类型的闪存设备交互。MTD驱动程序分为字符设备(MTD_CHAR)和块设备(MTD_BLOCK)两种。字符设备提供原始的字节级访问,而块...
总结来说,这个压缩包包含的Linux MTD驱动源码是针对S3C2410和AT91RM9200处理器的,目的是为了在Linux操作系统下有效地管理和操作非易失性存储设备。通过这些驱动,开发人员可以构建可靠的嵌入式系统,确保数据的...
Linux MTD,全称为Memory Technology Device,是Linux内核中用于处理非易失性存储设备如闪存(Flash Memory)的子系统。MTD的设计目的是为了抽象出底层硬件的复杂性,提供一个统一的接口供上层软件,如文件系统,...
### Linux下建立MTD分区详解 #### 一、引言 在嵌入式系统开发过程中,对于非易失性存储器(例如Flash)的操作是非常重要的环节。Linux内核提供了多种方式来管理和操作这类存储器,其中之一就是通过MTD(Memory ...
`Linux MTD 源代码分析.pdf`可能包含对MTD子系统源代码的深入解析,涵盖了MTD结构体定义、驱动注册过程、I/O操作的实现、错误处理机制以及如何处理坏块等方面。通过分析源代码,开发者可以更好地理解MTD的工作原理,...
Linux MTD,全称为Memory Technology Device,是Linux内核中用于处理非易失性存储设备(如闪存)的一个子系统。它为这些设备提供了一个抽象层,使得上层的文件系统和其他驱动程序可以更容易地与不同的硬件进行交互。...
下面将详细介绍MTD系统、Linux MTD设备、Modbus以及如何利用这些资源进行学习和移植。 MTD系统: MTD设计的初衷是为了抽象化各种类型的非易失性存储器,包括NOR Flash、NAND Flash等,提供了一个通用的接口供操作...
Linux下的Memory Technology Device (MTD) 是一个专为非易失性存储器(如闪存)设计的驱动层。MTD框架提供了一个抽象层,使得Linux内核可以更方便地管理和操作各种类型的闪存设备,如EEPROM、NOR Flash和NAND Flash...
4. **分区管理**:`drivers/mtd/partitions`目录下的代码处理了MTD设备的分区定义和管理。 5. **错误处理**:MTD代码中包含了各种错误检查和处理机制,确保在硬件故障或其他问题时能够正确报告和恢复。 6. **内存...
**MTD / HDT 3008C / 3016C**是Meteodata / Hydrodata系列3000C下的数据采集站,用于远程测量、记录和传输气象学、水文学、工业及环境监测等领域的数据。这些数据采集站能够实现自动化数据收集和处理,对于科研机构...
1. **Flash硬件驱动**:遵循CFI(Common Flash Interface)接口标准的NOR Flash驱动位于`/drivers/mtd/chips`目录下,而NAND Flash的驱动则位于`/drivers/mtd/nand`目录下。 2. **MTD原始设备**:在`/drivers/mtd/...
1. MTD驱动架构:介绍MTD驱动在Linux内核中的位置和作用,以及其与块设备驱动和文件系统的交互方式。 2. 设备操作:详细讲解如何进行读、写、擦除操作,以及如何处理NAND闪存的特性。 3. 驱动注册:描述如何在内核中...
MTD层是Linux内核硬件抽象层的一部分,它提供了与硬件特性相对应的低级别驱动程序接口,以便上层软件如文件系统能够更好地操作这些设备。 在Linux MTD系统中,每个非易失性存储设备都被看作一个独立的设备,并由一...
MTD(Memory Technology Device)技术设备驱动框架是Linux内核中的一个重要组成部分,专门用于管理非易失性存储器,如闪存(Flash Memory)。在深入分析MTD技术设备驱动框架之前,我们首先需要理解MTD的基本概念。 ...
10. **Nand Flash驱动**:Nand Flash驱动在`Linux-2.6.32.2/drivers/mtd/nand`,用于管理Nand闪存设备。 11. **UDA1341音频驱动**:音频驱动位于`Linux-2.6.32.2/sound/soc/s3c24xx`,针对UDA1341音频编解码器。 ...
"嵌入式Linux系统下NOR Flash的配置和使用" 嵌入式Linux系统下NOR Flash的配置和使用是指在嵌入式系统中使用NOR Flash存储器的配置和使用方法。NOR Flash作为一种非易失性存储器,具有擦写方便、可靠性高的优点,在...
只读文件系统不能写的文件不能保存(掉电丢失),此代码是通过linux应用层直接掉用mtd子系统提供API对flash的分区进行读写、擦除,实现文件的保存。