本文简单分析下Fuchsia的MMC框架,主要是基于mmc协议的初始化流程进行说明。至于mmc框架中的SD以及SDIO协议流程本文不涉及。另外,Fuchsia块设备层以及文件系统层的分析,本文也不涉及。
下表为目前rcar-M3单板系统的“设备树”(为描述方便,省略了部分设备树节点)。
root$ dm dump [root] <root> pid=2524 [null] pid=2524 /boot/driver/builtin.so [zero] pid=2524 /boot/driver/builtin.so [misc] <misc> pid=2607 [console] pid=2607 /boot/driver/console.so …… [sys] <sys> pid=2439 /boot/driver/platform-bus.so [platform] pid=2439 /boot/driver/platform-bus.so [rcar-m3] pid=2439 /boot/driver/rcar-m3.so [16:01:1] pid=2439 /boot/driver/platform-bus.so <16:01:1> pid=2958 /boot/driver/platform-bus.proxy.so [sh_mobile_sdhi] pid=2958 /boot/driver/sh-mobile-sdhi.so [sdmmc] pid=2958 /boot/driver/sdmmc.so [sdmmc-mmc] pid=2958 /boot/driver/sdmmc.so [block] pid=2958 /boot/driver/block.core.so [part-000] pid=2958 /boot/driver/mbr.so [block] pid=2958 /boot/driver/block.core.so [fvm] pid=2958 /boot/driver/fvm.so [blobfs-p-1] pid=2958 /boot/driver/fvm.so [block] pid=2958 /boot/driver/block.core.so [minfs-p-2] pid=2958 /boot/driver/fvm.so [block] pid=2958 /boot/driver/block.core.so [part-001] …… [16:01:2] pid=2439 /boot/driver/platform-bus.so <16:01:2> pid=3131 /boot/driver/platform-bus.proxy.so [ravb-ethernet] pid=3131 /boot/driver/ethernetAVB-IF.so [ethernet] pid=3131 /boot/driver/ethernet.so [cpu-trace] pid=2439 /boot/driver/platform-bus.so [test] <test> pid=2471 …… |
我们可以看到,这实际上是一颗“倒置”的“树”,设备硬件相关的信息在上面的“树干”,而层层抽象的驱动则是挂在设备下的“树枝”和“树叶”。以mmc块设备为例,其board级驱动([rcar-m3] pid=2439 /boot/driver/rcar-m3.so)设备挂在系统的永久设备sys的platform总线设备下面。而board设备下面则是挂载的emmc驱动(sh-mobile-sdhi.so)设备。Emmc驱动设备下面层层的挂载了系统的软件抽象层设备,包括mmc抽象层设备、block块抽象层设备、分区设备以及文件系统抽象层设备。更详细的驱动框架DDK相关细节,请参考我的“DDK驱动框架分析”文档。
从上面的这颗“倒置树”可以看出mmc框架抽象层是挂载在emmc驱动([sh_mobile_sdhi] )下面的,也就是emmc驱动初始化完成并发布设备后,才能触发mmc框架层驱动的初始化。如下图所示,mmc框架层的初始化入口为SdmmcRootDevice::Bind。其在Init函数中会新启动一个线程(SdmmcRootDevice::WorkerThread)来执行mmc协议层的probe流程。
在SdmmcRootDevice::WorkerThread流程中,首先调用emmc host驱动的reset接口,执行卡的reset初始化操作。接下来不管卡处于什么状态,都先发送CMD0命令,让其进入idle态,以保证后面的初始化流程正常进行下去。接下来会依次进行SDIO、SD以及MMC子协议的probe操作,前面的probe成功,后面的就不会再执行。这里我们选择MMC子协议的probe流程进行展开分析。
- 发送CMD1命令获取卡OCR寄存器值
- 设置OCR寄存器的bit30位,使能sector模式(不使能位byte模式)
- 发送CMD2命令获取CID寄存器值
- 解析CID值,获取mmc序列号、版本信息等
- 发送CMD3命令,为卡分配mmc总线上的相对地址,写入RCA寄存器。初始化时,RCA寄存器值为0,这里如果mmc总线上只有一个设备,该地址将会是0001。
- 发送CMD9命令,获取CSD寄存器值
- 解析CSD寄存器值,获取卡容量、扇区大小等信息
- 发送CMD7命令选中该卡(arg参数带上卡地址0001)
- 发送CMD8命令读取ext CSD寄存器值;该寄存器为512字节大小,储存了丰富的信息,包括支持的总线位宽、高速模式、CMDQ、超时值等等;详情请参考emmc协议手册
- 解析ext CSD寄存器值,获取卡的相关特性支持情况
- 如果支持高速模式(HS、HSDDR、HS200),进行下面的初始化操作
- 高速模式首先需要将总线接口电平设置为1.8V(低速模式为3.3V)
- 然后通过CMD6和CMD13命令选择并设置emmc支持的最大总线位宽(HS200支持4-bit和8-bit两种总线位宽,但HS400只支持8-bit位宽)
- 更进一步,如果支持高速模式中的HS200模式,进行下面的初始化操作
- 通过CMD6和CMD13命令设置HS200模式
- 切换host时钟频率为200MHz
- 执行mmc总线tuning过程(发送CMD21命令,根据host寄存器值确定需要进行的tuning次数,rcar-M3需要进行16次,然后根据结果则有选择最佳采样点)
- 再进一步,如果支持HS400模式,则进行下面的初始化操作
- 通过CMD6和CMD13命令,将模式切换回普通高速模式
- 时钟频率设置为52MHz(普通高速模式)
- 通过CMD6和CMD13命令设置总线位宽为8bit DDR(Dual Data Rate)
- 通过CMD6和CMD13命令切换模式为HS400
- 最后一步是将时钟频率设置为200MHz,完成HS400模式的切换
请结合下图及具体代码,来理解fuchsia的MMC协议框架初始化流程。
来源:oschina
链接:https://my.oschina.net/u/4290163/blog/3275070