基于Linux-3.10.0-229内核的Baytrail eMMC驱动分析之一概述
一、硬件环境
- Intel Baytrail处理器,自带eMMC-4.5控制器
- CentOS-7.1-1503-X86_64.iso
- linux-3.10.0-229.el7.x86_64
- eMMC存储芯片——KLMxGxGEND-B031(支持eMMC-5.0协议标准)
二、软件环境
1、MMC子系统框架

2、子系统代码结构
2、子系统代码结构
Linux MMC子系统主要分成三个部分:
- Card:存放闪存卡(块设备)的相关驱动,如MMC/SD卡设备驱动,SDIOUART;
- Host:针对不同主机端的SDHC、MMC控制器的驱动,这部分需要由驱动工程师来完成;
- Core:整个MMC的核心层,这部分完成不同协议和规范的实现,为host层和设备驱动层提供接口函数。
(1)、区块层(Card)
主要是按照 LINUX 块设备驱动程序的框架实现一个卡的块设备驱动,这block.c当中我们可以看到写一个块 设备驱动程序时需要的block_device_operations结构体变量的定义,其中有open/release/request函数的实现,而queue.c则是对内核提供的请求队列的封装,我们暂时不用深入理解它,只需要知道一个块设备需要一个请求队列就可以了。
(2)、核心层(Core)
核心层封装了MMC/SD卡的命令,例如存储卡的识别,设置,读写。例如不管什么卡都应该有一些识别,设置,和读写的命令,这些流程都是必须要有的,只是具体对于不同的卡会有一些各自特有的操作。Core.c文件是由sd.c、 mmc.c两个文件支撑的,core.c把MMC卡、SD卡的共性抽象出来,它们的差别由sd.c和sd_ops.c、mmc.c和mmc_ops.c 来完成。
(3)、主机控制器层(Host)
主机控制器则是依赖于不同的平台的,例如Baytrail处理器的eMMC卡控制器和三星的s3c24xx系列的卡控制器必定是不一样的,所以要针对不同的控制器来实现。以s3cmci.c为例,它首先要进行一些设置,例如中断函数注册,全能控制器等等。然后它会向core层注册一个主机(host),用结构mmc_host_ops描述,这样核心层就可以拿着这个host来操作s3c24xx的卡控制器了,而具体是s3c24xx的卡控制器还是Baytrail的卡控制器,core层是不用知道的。
3、结构体描述
主要包括如下:
- struct mmc_host 用来描述卡控制器、
- struct mmc_card 用来描述卡
- struct mmc_driver 用来描述 mmc 卡驱动
- struct mmc_host_ops 用来描述卡控制器操作集,用于从主机控制器层向core层注册操作函数,从而将core层与具体的主机控制器隔离。也就是说core要操作主机控制器,就用这个ops当中给的函数指针操作,不能直接调用具体主控制器的函数。
struct mmc_host {
const struct mmc_host_ops *ops; // SD卡主控制器的操作函数,即该控制器所具备的驱动能力
const struct mmc_bus_ops *bus_ops; // SD总线驱动的操作函数,即SD总线所具备的驱动能力
struct mmc_ios ios; // 配置时钟、总线、电源、片选、时序等
struct mmc_card *card; // 连接到此主控制器的SD卡设备
... ...
};
struct mmc_card *card; // 连接到此主控制器的SD卡设备
... ...
};
struct mmc_host_ops {
void (*request)(struct mmc_host *host, struct mmc_request *req); // 核心函数,完成主控制器与SD卡设备之间的数据通信
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); // 配置时钟、总线、电源、片选、时序等
int (*get_ro)(struct mmc_host *host); //获取gpio管脚,判断是否是写保护
void (*enable_sdio_irq)(struct mmc_host *host, int enable); //卡插入与拔出中断
};
struct mmc_bus_ops {
void (*remove)(struct mmc_host *); // 拔出SD卡的回调函数
void (*detect)(struct mmc_host *); // 探测SD卡是否还在SD总线上的回调函数
void (*suspend)(struct mmc_host *);
void (*resume)(struct mmc_host *);
};
struct mmc_card {
struct mmc_host *host; /* the host this device belongs to */
struct device dev; /* the device */
unsigned int rca; /* relative card address of device */
unsigned int type; /* card type */
unsigned int state; /* (our) card state */
unsigned int quirks; /* card quirks */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
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_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 */
... ...
};
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); // 配置时钟、总线、电源、片选、时序等
int (*get_ro)(struct mmc_host *host); //获取gpio管脚,判断是否是写保护
void (*enable_sdio_irq)(struct mmc_host *host, int enable); //卡插入与拔出中断
};
struct mmc_bus_ops {
void (*remove)(struct mmc_host *); // 拔出SD卡的回调函数
void (*detect)(struct mmc_host *); // 探测SD卡是否还在SD总线上的回调函数
void (*suspend)(struct mmc_host *);
void (*resume)(struct mmc_host *);
};
struct mmc_card {
struct mmc_host *host; /* the host this device belongs to */
struct device dev; /* the device */
unsigned int rca; /* relative card address of device */
unsigned int type; /* card type */
unsigned int state; /* (our) card state */
unsigned int quirks; /* card quirks */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
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_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 */
... ...
};