作者:Aningsk ,本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。
基于ATMEL-sama5d3芯片与Linux-3.6.9内核。
SD卡系列简介
这些都是网上找出来的,权当作为开场白了。
MMC卡全称Multi Media Card,由西门子公司和SanDisk公司1997年推出的多媒体记忆卡标准。MMC卡尺寸为32mm x24mm x 1.4mm,它将存贮单元和控制器一同做到了卡上,智能的控制器使得MMC保证兼容性和灵活性。MMC卡具有MMC和SPI两种工作模式,MMC模式是默认工作模式,具有MMC的全部特性。而SPI模式则是MMC协议的一个子集,主要用于低速系统。
SD卡全称Secure Digital Memory Card,由松下、东芝和SanDisk公司于1999年8月共同开发的新一代记忆卡标准,已完全兼容MMC标准。SD卡比MMC卡多了一个进行数据著作权保护的暗号认证功能,读写速度比MMC卡快4倍。尺寸为32mm x 24mm x2.1mm,长宽和MMC卡一样,只是比MMC卡厚了0.7mm,以容纳更大容量的存贮单元。SD卡与MMC卡保持向上兼容,也就是说,MMC卡可以被新的设有SD卡插槽的设备存取,但是SD卡却不可以被设有MMC插槽的设备存取。
SDIO全称Secure Digital Input and Output Card,SDIO是在SD标准上定义了一种外设接口,它使用SD的I/O接口来连接外围设备,并通过SD上的I/O数据接口与这些外围设备传输数据。现在已经有很多手持设备支持SDIO功能,而且许多SDIO外设也被开发出来,目前常见的SDIO外设有:WIFI Card、GPS Card、 Bluetooth Card等等。
eMMC全称Embedded Multi MediaCard,是MMC协会所制定的内嵌式存储器标准规格,主要应用于智能手机和移动嵌入式产品等。eMMC是一种嵌入式非易失性存储系统,由闪存和闪存控制器两部分组成,它的一个明显优势是在封装中集成了一个闪存控制器,它采用JEDEC标准BGA封装,并采用统一闪存接口管理闪存。eMMC结构由一个嵌入式存储解决方案组成,带有MMC接口、快闪存储设备及主控制器,所有这些由一个小型BGA封装。由于采用标准封装,eMMC也很容易升级,并不用改变硬件结构。
MMC/SD通信协议
卡的状态与模式:
工作条件检测:
发送CMD0(reset);
发送CMD8,用于取得SD卡支持的工作电压。
在版本2.0中,发送ACMD41,必须先发送CMD8,有应答则是高容量SD卡。
ACMD41是给卡的控制器一个识别卡是否能在给定电压下工作的机制。
卡根据CMD8的参数检测控制器的电压,如果电压不可以,卡处于Idle状态;如果电压可以,发送回执(check voltage, check pattern),控制器分析回传的CMD8参数校验是否可以在给定的电压下工作。
在ACMD41之后,控制器与卡之间的工作电压将确定。
初始化:
开始于收到ACMD41。
响应CMD8的卡为SDHC卡,ACMD41的HCS部分为1;不响应CMD8的则是普通SD卡;
作为ACMD41的回应,SDHC卡会带有CCS=1。
控制器发送CMD2,处于Ready状态的卡,发送自己的CID作为响应,然后卡进入Identification状态。
控制器发送CMD3,SD卡会发送一个相对地址(RCA)作为响应。卡进入等待状态。
数据传输模式:
CMD7:选择某个卡进入Transfer状态。
CMD9:获取卡的CSD(card specific data),包括块长度、卡的容量等。
CMD12:停止命令。
CMD17:块读命令。
CMD18:多块读命令。
ACMD51:发送scr(SD Configuration Register)
CMD24:块写命令。
CMD25:多块写命令。
CMD32:擦除的起始地址。
CMD33:擦除的截止地址。
CMD38:擦除命令。
仅仅看SPEC上的通信协议可能略有枯燥,结合代码就比较好理解了。关于SD卡的初始化过程参见:http://www.cnblogs.com/fengeryi/p/3469782.html
这个博客详细描述了SD卡的初始化(mmc_sd_init_card())。MMC卡的初始化是mmc_init_card(),大致过程相似,比SD卡的函数长不少,但实际的代码干的事情貌似比SD的那些简单一些。这里我们用到的是MMC卡,它的初始化后面会涉及到的。
关于eMMC的原理图部分:
现在的内核使用设备树文件,来描述ARM平台上的相关硬件设备资源。对于设备树(Device Tree)这个东西资料还不是很多,网上有宋宝华写的有关设备树的文章,挺值得参考的。
按我自己的理解,设备树文件就是用一种类似于C语言的东西来描述具体平台相关的硬件资源。这些文件使用特定的编译器编译为.dtb文件,在uboot加载内核的时候,将dtb文件提供给内核,内核便获知了具体的硬件设置;而不再是以前那样,各种各样的硬件信息统统编译进内核。
所使用的硬件资源,来自于设备树文件sama5d3.dtsi(arch/arm/boot/dts/sama5d3.dtsi)
与MMC设置有关的寄存器地址:0xf0000000;长度0x600。中断号21,触发模式:4(上升沿触发)。中断优先级为0 。拥有的DMA资源是dma0,寄存器的配置为0x10002200 。
关于设备树文件含义的一些说明,在源码目录中的Document/devicetree/bindings/下有TXT类型的描述文档。
MMC驱动的层次结构
CARD层 具体的块设备驱动
CORE层 为card层提供操作接口,为host层注册提供机制
HOST层 MMC/SD/SDIO的控制器驱动层
我觉得之所以将整个的驱动分为三层,是为了驱动能够更好的移植到其他的硬件平台上去。CARD层是通用的MMC块设备驱动,这些代码只要是Linux都可以用的;而HOST层里的代码则是与具体平台有关的,进去看文件与函数的名字就可以猜到——我们这里HOST层中的函数常常是"atmci"开头,意思是ATMEL的媒体控制接口,这是因为我们的平台是ATMEL的ARM芯片;而CORE层,则是提供了MMC/SD的核心机制,并且为CARD层屏蔽了HOST层中具体硬件的差异。基于这些有但不完全的原因,MMC/SD的驱动自然而然的分出了三层,也就是drivers/mmc下的三个文件夹。
Linux内核中的面向对象的思想与实现
在个人学习Linux驱动的过程中,感觉如果只是按照一个一个函数的调用,不断的来回跳,即便是能看懂单个函数的意思,对于整个体系依然是云里雾里,不知内核写了神马东西。若是按照面向对象的思想去理解这些代码,我发现内核的东西就比较容易懂了。
内核虽然是用面向过程的C语言写出来的,但处处体现着面向对象的思想,甚至可以称为一种编程哲学(PS.那些把内核写出来的牛人们,实在太牛了)。Linux不仅仅把设备全部抽象为文件,这种宏观的抽象对象的方法在内核代码里也是比比皆是。个人感觉看代码是在自己脑子里把程序要处理的东西,都抽象为一件件具体的物品,对理解内核代码的来龙去脉,很有帮助。
Linux内核中用面向过程的C语言实现了面向对象的程序架构。一种面向对象的语言,拥有三方面的特性:封装、继承、多态。Linux内核用C语言的基本特性实现了这三种面向对