mmc subsystem系列(持续更新中):
[mmc subsystem] 概念与框架
[mmc subsystem] mmc core(第一章)——概述
[mmc subsystem] mmc core(第二章)——数据结构和宏定义说明
[mmc subsystem] mmc core(第三章)——bus模块说明
[mmc subsystem] mmc core(第四章)——host模块说明
[mmc subsystem] mmc core(第五章)——card相关模块(mmc type card)
[mmc subsystem] mmc core(第六章)——mmc core主模块
建议先参考《[mmc subsystem] 概念与框架》和《[mmc subsystem] mmc core(第一章)——概述》对整体有一个了解。
=========================================================================================================
零、说明(重要,需要先搞清楚概念有助于后面的理解)
1、mmc core——card相关模块为对应card实现相应的操作,包括初始化操作、以及对应的总线操作集合。负责和对应card协议层相关的东西。
主要包括三种类型的card,分别是mmc type card、sd type card和sdio type card。
这里先学习mmc type card。后续再学习sd type card。
对应代码:
drivers/mmc/core/mmc.c(提供接口),
drivers/mmc/core/mmc-ops.c(提供和mmc type card协议相关的操作),
drivers/mmc/core/mmc-ops.h
2、另外,这里继续强调一下mmc的概念
mmc core是指mmc subsystem的核心实现,这里的mmc是表示mmc总线、接口、设备相关的一种统称,可以理解为一种软件架构。
而mmc type card则是指mmc卡或者emmc。
总之,这里的mmc是两种概念概念,需要自己先消化一下。
3、mmc总线和mmc_bus
在本文里面这两个是不同的概念。
mmc_bus是指mmc core抽象出来的虚拟总线,和mmc设备对应的硬件总线无关,是一种软件概念。
而本文的mmc总线是一种物理概念,是实际的总线,是和host controller直接相关联的。
一、API总览
1、mmc type card匹配相关
- mmc_attach_mmc
提供给mmc core主模块使用,用于绑定card到host bus上(也就是card和host的绑定)。
通过mmc_host获取mmc type card信息,初始化mmc_card,并进行部分驱动,最后将其注册到mmc_bus上。
原型:int mmc_attach_mmc(struct mmc_host *host)
2、mmc type card协议相关操作
mmc_ops提供了部分和mmc type card协议相关操作,这些操作会在mmc.c中mmc的初始化过程中被使用到。
建议先简单了解一下mmc协议的内容。后续会进行总结。
mmc_go_idle
发送CMD0指令,GO_IDLE_STATE
使mmc card进入idle state。
虽然进入到了Idle State,但是上电复位过程并不一定完成了,这主要靠读取OCR的busy位来判断,而流程归结为下一步。mmc_send_op_cond
发送CMD1指令,SEND_OP_COND
这里会设置card的工作电压寄存器OCR,并且通过busy位(bit31)来判断card的上电复位过程是否完成,如果没有完成的话需要重复发送。
完成之后,mmc card进入ready state。mmc_all_send_cid
这里会发送CMD2指令,ALL_SEND_CID
广播指令,使card回复对应的CID寄存器的值。在这里就相应获得了CID寄存器的值了,存储在cid中。
完成之后,MMC card会进入Identification State。mmc_set_relative_addr
发送CMD3指令,SET_RELATIVE_ADDR
设置该mmc card的关联地址为card->rca,也就是0x0001
完成之后,该MMC card进入standby模式。mmc_send_csd
发送CMD9指令,MMC_SEND_CSD
要求mmc card发送csd寄存器,存储到card->raw_csd中,也就是原始的csd寄存器的值。
此时mmc card还是处于standby statemmc_select_card & mmc_deselect_cards
发送CMD7指令,SELECT/DESELECT CARD
选择或者断开指定的card
这时卡进入transfer state。后续可以通过各种指令进入到receive-data state或者sending-data state依次来进行数据的传输mmc_get_ext_csd
发送CMD8指令,SEND_EXT_CSD
这里要求处于transfer state的card发送ext_csd寄存器,这里获取之后存放在ext_csd寄存器中
这里会使card进入sending-data state,完成之后又退出到transfer state。mmc_switch
发送CMD6命令,MMC_SWITCH
用于设置ext_csd寄存器的某些bitmmc_send_status
发送CMD13命令,MMC_SEND_STATUS
要求card发送自己当前的状态寄存器mmc_send_cid
发送CMD10命令,MMC_SEND_CID
要求mmc card回复cid寄存器mmc_card_sleepawake
发送CMD5命令,MMC_SLEEP_AWAKE
使card进入或者退出sleep state,由参数决定。关于sleep state是指card的一种状态,具体参考emmc 5.1协议。
先结合协议理解上述几个mmc type card的操作函数有助于理解后续mmc card的初始化代码。具体参考第五节。
二、数据结构
1、mmc_ops & mmc_ops_unsafe
struct mmc_bus_ops表示mmc host在总线上的操作集合,由host的card 设备来决定,mmc type card、sd type card相应的操作集合是不一样的。
mmc_ops和mmc_ops_unsafe则表示mmc type card所属的host对于总线的操作集合。
static const struct mmc_bus_ops mmc_ops = {
.awake = mmc_awake,
.sleep = mmc_sleep,
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = NULL,
.resume = NULL,
.power_restore = mmc_power_restore,
.alive = mmc_alive,
.change_bus_speed = mmc_change_bus_speed,
};
static const struct mmc_bus_ops mmc_ops_unsafe = {
.awake = mmc_awake, // 使mmc总线上的mmc type card退出sleep state
.sleep = mmc_sleep, // 使mmc总线的mmc type card进入sleep state
.remove = mmc_remove, // 释放mmc type card
.detect = mmc_detect, // 检测mmc总线的mmc type card是否拔出
.suspend = mmc_suspend, // suspend掉mmc总线上的mmc type card,注意不仅仅会使card进入sleep state,还会对clock以及mmc cache进行操作
.resume = mmc_resume, // resume上mmc总线上的mmc type card
.power_restore = mmc_power_restore, // 恢复mmc总线上的mmc type card的电源状态
.alive = mmc_alive, // 检测mmc总线上的mmc type card状态是否正常
.change_bus_speed = mmc_change_bus_speed, // 修改mmc总线时钟频率
};
mmc_ops_unsafe和mmc_ops的区别在于是否实现suspend和resume方法。
对于card不可移除的host来说,需要使用mmc_ops_unsafe这个mmc_bus_ops来支持suspend和resume。
之所以在上述注释中不断说明mmc总线,是为了强调应该和mmc_bus虚拟总线区分开来,这里的mmc总线是物理概念、是和host controller直接相关联的。
2、mmc_type
struct device_type mmc_type中为mmc_card定义了很多属性,可以在sysfs中进行查看。
/sys/class/mmc_host/mmc0/mmc0:0001
或者/sys/bus/mmc/devices/mmc0:0001下可以查看到如下属性
block cid csd date driver enhanced_area_offset enhanced_area_size erase_size fwrev hwrev
manfid name oemid power preferred_erase_size prv raw_rpmb_size_mult rel_sectors
runtime_pm_timeout serial subsystem type uevent
mmc_type对应实现如下:
static struct device_type mmc_type = {
.groups = mmc_attr_groups,
};
static const struct attribute_group *mmc_attr_groups[] = {
&mmc_std_attr_group,
NULL,
};
static struct attribute_group mmc_std_attr_group = {
.attrs = mmc_std_attrs,
};
MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(cs