Linux MMC介绍
1. 介绍
Linux中,将包括MMC、SD、SDIO统称为MMC子系统
MMC子系统从功能上可分为三个层次
- card层: Card驱动, 或称client驱动
- core层: MMC的核心层, 完成不同协议和规范的实现, 为host层和设备驱动层提供接口函数
- host层: Host驱动, 针对不同主机端的SDHC、MMC控制器的驱动
2. 数据结构
MMC中包含的主要数据结构如下
- mmc_host 表示一个mmc host控制器
- mmc_card 表示一个mmc设备
- mmc_ios IO总线相关设置
- mmc_driver 表示一个card drive
- mmc_bus_ops 总线操作函数集, 有mmc、sd、sdio三种
- mmc_host_ops Host Controller操作函数集
- mmc_command 表示一个mmc命令
- mmc_data 表示一个mmc数据
- mmc_request 表示一个mmc请求
- sdio_func 表示一个SDIO功能设备
mmc_host主要字段如下
struct mmc_host {
int index;
const struct mmc_host_ops *ops;
u32 ocr_avail;
u32 ocr_avail_sdio; /* SDIO-specific OCR */
u32 ocr_avail_sd; /* SD-specific OCR */
u32 ocr_avail_mmc; /* MMC-specific OCR */
u32 caps; /* Host能力标志*/
u32 caps2; /* Host更多能力标志*/
struct mmc_ios ios; /* current io bus settings */
int rescan_disable; /* disable card detection */
int rescan_entered; /* used with nonremovable devices */
struct mmc_card *card; /* device attached to this host */
struct delayed_work detect;
int detect_change; /* card检测标志 */
struct mmc_slot slot;
const struct mmc_bus_ops *bus_ops; /* current bus driver */
struct mmc_supply supply;
unsigned int slotno; /* used for sdio acpi binding */
int dsr_req; /* DSR value is valid */
u32 dsr; /* optional driver stage (DSR) value */
unsigned long private[];
};
mmc_card主要字段如下
struct mmc_card {
struct mmc_host *host; /* the host this device belongs to */
struct device dev; /* the device */
u32 ocr; /* the current OCR setting */
unsigned int rca; /* relative card address of device */
unsigned int type; /* Card类型: MMC、SD、SDIO、COMBO */
unsigned int state; /* (our) card state */
unsigned int quirks; /* card quirks */
struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */
struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */
struct sd_scr scr; /* extra SD information */
struct sd_ssr ssr; /* yet more SD information */
struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
unsigned int sdio_funcs; /* number of SDIO functions */
struct sdio_cccr cccr; /* common card info */
struct sdio_cis cis; /* common tuple info */
struct sdio_func *sdio_func[]; /* SDIO functions (devices) */
unsigned int sd_bus_speed; /* Bus Speed Mode set for the card */
unsigned int mmc_avail_type; /* supported device type by both host and card */
unsigned int drive_strength; /* for UHS-I, HS200 or HS400 */
};
mmc_ios字段如下
struct mmc_ios {
unsigned int clock; /* 时钟频率 */
unsigned short vdd;
unsigned char bus_mode; /* 命令输出模式: 开漏模式、上拉模式 */
unsigned char chip_select; /* SPI片选: DONTCARE、HIGH、LOW */
unsigned char power_mode; /* 电源供应状态: UNDEFINED、OFF、UP、ON */
unsigned char bus_width; /* 数据总线宽度: 1、4、8 */
unsigned char timing; /* 总线速度模式: DS、HS、SDR12、SDR25... */
unsigned char signal_voltage; /* 信号电压值: 3.3V、1.8V、1.2V */
unsigned char drv_type; /* 驱动类型: A, B, C, D */
bool enhanced_strobe; /* hs400es选择 */
};
mmc_driver字段如下
struct mmc_driver {
struct device_driver drv;
int (*probe)(struct mmc_card *);
void (*remove)(struct mmc_card *);
void (*shutdown)(struct mmc_card *);
};
mmc_bus_ops字段如下
struct mmc_bus_ops {
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
int (*pre_suspend)(struct mmc_host *);
int (*suspend)(struct mmc_host *);
int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *);
int (*runtime_resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *);
int (*reset)(struct mmc_host *);
};
mmc_host_ops字段如下
struct mmc_host_ops {
void (*post_req)(struct mmc_host *, struct mmc_request *, int err);
void (*pre_req)(struct mmc_host *, struct mmc_request *, bool is_first_req);
void (*request)(struct mmc_host *host, struct mmc_request *req);
void (*set_ios)(struct mmc_host *, struct mmc_ios *);
int (*get_ro)(struct mmc_host *);
int (*get_cd)(struct mmc_host *);
void (*enable_sdio_irq)(struct mmc_host *, int enable);
void (*init_card)(struct mmc_host *, struct mmc_card *card);
int (*start_signal_voltage_switch)(struct mmc_host *, struct mmc_ios *);
int (*card_busy)(struct mmc_host *);
int (*execute_tuning)(struct mmc_host *, u32 opcode);
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
void (*hs400_enhanced_strobe)(struct mmc_host *, struct mmc_ios *);
int (*select_drive_strength)(struct mmc_card *card,
unsigned int max_dtr, int host_drv, int card_drv, int *drv_type);
void (*hw_reset)(struct mmc_host *);
void (*card_event)(struct mmc_host *);
int (*multi_io_quirk)(struct mmc_card *, unsigned int direction, int blk_size);
};
3. MMC接口
3.1 Host API
Host相关接口, 供Host Controller使用
/* 设备树解析 */
int mmc_of_parse(struct mmc_host *); /* 分配/释放host结构体 */
struct mmc_host *mmc_alloc_host(int extra, struct device *);
void mmc_free_host(struct mmc_host *); /* 添加/移除host设备 */
int mmc_add_host(struct mmc_host *);
void mmc_remove_host(struct mmc_host *);
mmc_alloc_host主要流程如下
mmc_alloc_host
kzalloc(sizeof(struct mmc_host) + extra)
/* 分配mmc_host结构体 */
mmc_host::rescan_disable =
/* 禁用扫描*/
ida_pre_get
ida_get_new
/* ida相关 */
dev_set_name
/* 设置设备名称 */
device_initialize(mmc_host::class_dev)
/* 初始化设备结构体 */
mmc_gpio_alloc
/* 分配mmc_gpio结构体 */
init_waitqueue_head(mmc_host::wq)
/* 初始化等待队列 */
INIT_DELAYED_WORK(mmc_host::detect, mmc_rescan);
/* 初始化工作队列 */
mmc_add_host主要流程如下
mmc_add_host
device_add(mmc_host::class_dev)
/* 添加设备 */
mmc_start_host
/* 启用该Host */
mmc_claim_host
/* 占用Host控制器 */
mmc_power_up
/* 给Host供电 */
mmc_host::mmc_ios::power_mode = MMC_POWER_UP
/* 设置power状态为正在上电 */
mmc_set_initial_state
/* 设置初始化状态 */
mmc_host::mmc_ios::bus_width = MMC_BUS_WIDTH_1
/* 设置总线宽带为1bit */
mmc_host::mmc_ios::timing = MMC_TIMING_LEGACY
/* 设置总线速度模式为DS模式 */
mmc_set_ios
/* 将IO总线设置写入Host驱动, 调用mmc_host::mmc_host_ops::set_ios */
__mmc_set_signal_voltage
/* 设置信号电压, 依次尝试3.3V、1.8V、1.2V */
mmc_host::mmc_ios::clock = mmc_host::f_init;
/* 设置时钟频率 */
mmc_host::mmc_ios::power_mode = MMC_POWER_ON
/* 设置power状态为正常供电 */
mmc_set_ios
/* 将io相关设置写入Host驱动 */
mmc_release_host
/* 释放Host控制器 */
mmc_gpiod_request_cd_irq
/* 释放Host控制器 */
_mmc_detect_change
/* Card扫描 */
mmc_host::detect_change =
/* 设置Card检测标志 */
mmc_schedule_delayed_work(mmc_host::detect);
/* 调度工作队列, 调度函数为mmc_rescan */
3.2 Card API
/* 注册/注销MMC Card驱动 */
int mmc_register_driver(struct mmc_driver *);
void mmc_unregister_driver(struct mmc_driver *); /* 注册/注销SDIO Card驱动 */
int sdio_register_driver(struct sdio_driver *);
void sdio_unregister_driver(struct sdio_driver *);
3.3 General API
/* Card检测 */
void mmc_detect_change(struct mmc_host *host, unsigned long delay);
3.4 Command API
cmd0 - mmc_go_idle
cmd1 - mmc_send_op_cond
cmd2 - mmc_all_send_cid
4. MMC启动
MMC在启动时会进行相应的初始化
mmc_init
mmc_register_bus
bus_register /* 注册了mmc总线 */
mmc_register_host_class
class_register /* 注册'mmc_host'设备类 */
sdio_register_bus
bus_register /* 注册了sdio总线 */ mmc_blk_init
register_blkdev /* 注册mmc块设备 */
mmc_register_driver
driver_register /* 注册mmc card驱动 */
5. MMC扫描
MMC设备的发现通过mmc_rescan函数来实现,通过_mmc_detect_change/mmc_detect_change来触发
mmc_rescan主要流程如下
mmc_rescan
mmc_host::mmc_host_ops::card_event
mmc_host::mmc_bus_ops::detect
mmc_host::mmc_host_ops::get_cd
mmc_rescan_try_freq
/* 使用不同时钟频率进行初始化 */
mmc_power_up
/* 设备供电 */
mmc_hw_reset_for_init
/* 针对部分eMMC(VCCQ一直为高) */
mmc_host::mmc_host_ops::hw_reset
sdio_reset
/* 仅针对SDIO设备 */
mmc_go_idle
/* 发送CMD0命令 */
mmc_send_if_cond
/* 仅针对SD设备 */
mmc_attach_sdio
/* SDIO设备初始化 */
mmc_attach_sd
/* SD设备初始化 */
mmc_attach_mmc
/* MMC设备初始化 */
mmc_power_off
/* 当上述设备都不是则停止供电 */
其中SDIO、SD、MMC的初始化流程各不相同
mmc_attach_sdio主要流程如下
/* SDIO Card初始化 */
mmc_attach_sdio
mmc_send_io_op_cond
/* 发送SD_IO_SEND_OP_COND, 获取??? */
mmc_attach_bus(mmc_sdio_ops)
/* 将SDIO总线操作集分配给Host */
host->ocr_avail = host->ocr_avail_sdio;
/* 设置SDIO的OCR */
mmc_select_voltage
/* 选择合适的电压值 */
mmc_sdio_init_card
/* 识别和初始化SDIO Card */
......
pm_runtime_set_active
/* 设置Card运行时PM状态为活跃, 仅针对支持MMC_CAP_POWER_OFF_CARD特性的Host */
pm_runtime_enable
/* 使能Card运行时PM, 仅针对支持MMC_CAP_POWER_OFF_CARD特性的Host */
...... /* sdio functions related */
mmc_add_card(mmc_host::mmc_card)
/* 注册SDIO Card */
sdio_add_func(mmc_host::mmc_card::sdio_func)
/* 注册SDIO function */
mmc_attach_sd主要流程如下
/* SD Card初始化 */
mmc_attach_sd
mmc_send_app_op_cond
/* 发送SD_APP_OP_COND, 获取??? */
mmc_attach_bus(mmc_sd_ops)
/* 将SD总线操作集分配给Host */
host->ocr_avail = host->ocr_avail_sd;
/* 设置SD的OCR */
mmc_host_is_spi
->
mmc_go_idle
/* 发送CMD0 */
mmc_spi_read_ocr
/* 发送MMC_SPI_READ_OCR, 读取??? */
mmc_select_voltage
/* 选择合适的电压值 */
mmc_sd_init_card
/* 识别和初始化SD Card */
......
mmc_add_card(mmc_host::mmc_card)
/* 注册SD Card */
mmc_attach_mmc主要流程如下
/* MMC Card初始化 */
mmc_attach_mmc
mmc_send_op_cond
/* 发送MMC_SEND_OP_COND, 获取??? */
mmc_attach_bus(mmc_ops)
/* 将MMC总线操作集分配给Host */
host->ocr_avail = host->ocr_avail_mmc;
/* 设置MMC的OCR */
mmc_host_is_spi
->
mmc_spi_read_ocr
/* 发送MMC_SPI_READ_OCR, 读取??? */
mmc_select_voltage
/* 选择合适的电压值 */
mmc_init_card
/* 识别和初始化MMC Card */
......
mmc_add_card(mmc_host::mmc_card)
/* 注册MMC Card */
6. Host驱动
Host驱动的编写主要步骤如下:
. 通过mmc_alloc_host分配一个mmc_host结构体
. 定义实现mmc_host_ops数据结构, 并赋值给上面的mmc_host::mmc_host_ops成员变量
. 给mmc_host成员变量赋值, 如ocr_avail、caps等成员变量
. 调用mmc_add_host注册该Host
7. Card驱动
对于Memory Card,内核实现了块设备驱动; 对于SDIO设备(比如WiFi), 则需要厂商实现(比如BCM的bcmdhd)
参考:
<ooonebook mmc>
<WF111 Datasheet>
<BCM4330 Datasheet>
<MMC/SD卡驱动实例开发讲解>
<SDIO Simplified Specification>
Linux MMC介绍的更多相关文章
- Linux MMC framework2:基本组件之core
1.前言 本文主要core组件的主要流程,在介绍的过程中,将详细说明和core相关的流程,涉及到其它组件的详细流程再在相关文章中说明. 2.主要数据结构和API TODO 3. 主要流程 3.1 mm ...
- Linux mmc framework2:基本组件之queue
1.前言 本文主要介绍card下queue组件的主要流程,在介绍的过程中,将详细说明和queue相关的流程,涉及到其它组件的详细流程再在相关文章中说明. 2.主要数据结构和API 2.1 struct ...
- Linux mmc framework2:基本组件之block
1.前言 本文主要block组件的主要流程,在介绍的过程中,将详细说明和block相关的流程,涉及到其它组件的详细流程再在相关文章中说明. 2.主要数据结构和API 2.1 struct mmc_ca ...
- Linux MMC framework2:基本组件之host
声明:本文很多内容和思路参考了http://www.wowotech.net/comm/mmc_host_driver.html,对原作者表示感谢! 1.前言 本文是Linux MMC framewo ...
- Linux mmc framework1:软件架构
[部分内容来自] http://www.wowotech.net/comm/mmc_framework_arch.html 1. 前言 由eMMC基础技术1:MMC简介中MMC.SD.SDIO的介绍可 ...
- [MMC]Linux MMC/SD/SDIO驱动分析
转自:http://www.cnblogs.com/cslunatic/p/3678045.html 一.SD/MMC/SDIO概念区分 SD(SecureDigital)与 MMC(Multimed ...
- linux驱动基础系列--Linux mmc sd sdio驱动分析
前言 主要是想对Linux mmc子系统(包含mmc sd sdio)驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.块设备驱动.设备模型等也不进行详细说明原 ...
- Linux MMC 驱动子系统简述(源码剖析)
1. Linux MMC 驱动子系统 块设备是Linux系统中的基础外设之一,而 MMC/SD 存储设备是一种典型的块设备.Linux内核设计了 MMC子系统,用于管理 MMC/SD 设备. MMC ...
- 01 Linux入门介绍
一.Linux 初步介绍 Linux的优点 免费的,开源的 支持多线程,多用户 安全性好 对内存和文件管理优越 系统稳定 消耗资源少 Linux的缺点 操作相对困难 一些专业软件以及游戏支持度不足 L ...
随机推荐
- 虚拟现实-VR-UE4-编译源代码后,无法运行
情况是这个样,在一开始我编译后,是可以运行,但是当我重新做系统后,再次运行时,每次都是到加载的18%的时候提示了如下错误 具体解决方法还没有找到,正在努力找中.........,会后续更新 同时希望有 ...
- Python全栈 MongoDB 数据库(概念、安装、创建数据)
什么是关系型数据库? 是建立在关系数据库模型基础上的数据库,借助于集合代数等概念和方法来处理数据库中的数据, 同时也是一个被组织成一组拥有正式描述性的表格( ...
- Java 集合学习--ArrayList
一.ArrayList 定义 ArrayList 是一个用数组实现的集合,支持随机访问,元素有序且可以重复. ①.实现 List 接口 List接口继承Collection接口,是List类的顶层接口 ...
- python安装Django
现在有很多建站系统,很多都是基于php的,比如WordPress. 而Django 是老牌基于Python的CMS框架了,一直听说很强大,甚至曾经很红的Ruby On Rails都参考了它的很多概念, ...
- HDU 1698 Just a Hook(线段树区间覆盖)
线段树基本操作练习,防手生 #include <cstdio> #include <cstring> #include <cstdlib> #define lson ...
- MFC MDI 工程禁用win7任务栏(taskbar)多视图缩略图(preview)功能
花费了好几天,google上的把搜索关键字都想烂了终于搜出了答案 app的init函数中在创建mainframe之前调用 EnableTaskbarInteraction(FALSE);
- java文件的I/O
[原创] java文件的I/O操作,简单来说就是向文件中写入数据以及从文件中读出数据,这是我们平日做的最多的操作,这里给出两种文件I/O操作,当然还有许多的操作方法,各种流的使用,可谓是高深莫测:不管 ...
- sessionStorage的用法总结
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁.因此sessionStorage不是一种持久化的本地 ...
- LeetCode--Factorial Trailing Zeroes(注意)
Given an integer n, return the number of trailing zeroes in n!. 问题描述:给出一个正整数n,计算n!结构后面有几个0.要求:在多项式时间 ...
- 国内各运营商(ISP)IP段表
国内各运营商(ISP)IP段表 来源:http://bbs.hh010.com/forum.php?mod=viewthread&tid=490529&orderby=dateline ...