linux emmc子系统,Linux eMMC子系统之主机控制器驱动

1. 前言

本文是Linux MMC framework的第二篇,将从驱动工程师的角度,介绍MMC host controller driver有关的知识,学习并掌握如何在MMC framework的框架下,编写MMC控制器的驱动程序。同时,通过本篇文章,我们会进一步的理解MMC、SD、SDIO等有关的基础知识。

2. MMC host驱动介绍

linux emmc子系统,Linux eMMC子系统之主机控制器驱动_第1张图片

MMC的host driver,是用于驱动MMC host控制器的程序,位于“drivers/mmc/host”目录。从大的流程上看,编写一个这样的驱动非常简单,只需要三步:

1)调用mmc_alloc_host,分配一个struct mmc_host类型的变量,用于描述某一个具体的MMC host控制器。

2)根据MMC host控制器的硬件特性,填充struct mmc_host变量的各个字段,例如MMC类型、电压范围、操作函数集等等。

3)调用mmc_add_host接口,将正确填充的MMC host注册到MMC core中。

当然,看着简单,一牵涉到实现细节,还是很麻烦的,后面我们会慢慢分析。

注1:分析MMC host driver的时候,Linux kernel中有大把大把的例子(例如drivers/mmc/host/pxamci.c),大家可尽情参考、学习,不必谦虚(这是学习Linux的最佳方法)。

注2:由于MMC host driver牵涉到具体的硬件controller,分析的过程中需要一些具体的硬件辅助理解,本文将以“X Project”所使用Bubblegum-96平台为例,具体的硬件spec可参考[1]。

3. 主要数据结构

3.1 struct mmc_host

MMC core使用struct mmc_host结构抽象具体的MMC host controller,该结构的定义位于“include/linux/mmc/host.h”中,它既可以用来描述MMC控制器所具有的特性、能力(host driver关心的内容),也保存了host driver运行过程中的一些状态、参数(MMC core关心的内容)。需要host driver关心的部分的具体的介绍如下:

parent,一个struct device类型的指针,指向该MMC host的父设备,一般是注册该host的那个platform设备;

class_dev,一个struct device类型的变量,是该MMC host在设备模型中作为一个“设备”的体现。当然,人如其名,该设备从属于某一个class(mmc_host_class);

ops,一个struct mmc_host_ops类型的指针,保存了该MMC host有关的操作函数集,具体可参考3.2小节的介绍;

pwrseq,一个struct mmc_pwrseq类型的指针,保存了该MMC host电源管理有关的操作函数集,具体可参考3.2小节的介绍;

f_min、f_max、f_init,该MMC host支持的时钟频率范围,最小频率、最大频率以及初始频率;

ocr_avail,该MMC host可支持的操作电压范围(具体可参考include/linux/mmc/host.h中MMC_VDD_开头的定义);

注3:OCR(Operating CondiTIons Register)是MMC/SD/SDIO卡的一个32-bit的寄存器,其中有些bit指明了该卡的操作电压。MMC host在驱动这些卡的时候,需要和Host自身所支持的电压范围匹配之后,才能正常操作,这就是ocr_avail的存在意义。

ocr_avail_sdio、ocr_avail_sd、ocr_avail_mmc,如果MMC host针对SDIO、SD、MMC等不同类型的卡,所支持的电压范围不同的话,需要通过这几个字段特别指定。否则,不需要赋值(初始化为0);

pm_noTIfy,一个struct noTIfier_block类型的变量,用于支持power management有关的noTIfy实现;

max_current_330、max_current_300、max_current_180,当工作电压分别是3.3v、3v以及1.8v的时候,所支持的最大操作电流(如果MMC host没有特别的限制,可以不赋值);

caps、caps2,指示该MMC host所支持的功能特性,具体可参考3.4小节的介绍;

pm_caps,mmc_pm_flag_t类型的变量,指示该MMC host所支持的电源管理特性;

max_seg_size、max_segs、max_req_size、max_blk_size、max_blk_count、max_busy_timeout,和块设备(如MMC、SD、eMMC等)有关的参数,在古老的磁盘时代,这些参数比较重要。对基于MMC技术的块设备来说,硬件的性能大大提升,这些参数就没有太大的意义了。具体可参考5.2章节有关MMC数据传输的介绍;

lock,一个spin lock,是MMC host driver的私有变量,可用于保护host driver的临界资源;

ios,一个struct mmc_ios类型的变量,用于保存MMC bus的当前配置,具体可参考3.5小节的介绍;

supply,一个struct mmc_supply类型的变量,用于描述MMC系统中的供电信息,具体可参考3.6小节的介绍;

……

private,一个0长度的数组,可以在mmc_alloc_host时指定长度,由host controller driver自行支配。

3.2 struct mmc_host_ops

struct mmc_host_ops抽象并集合了MMC host controller所有的操作函数集,包括:

1)数据传输有关的函数

/*

* It is optional for the host to implement pre_req and post_req in

* order to support double buffering of requests (prepare one

* request while another request is active).

* pre_req() must always be followed by a post_req().

* To undo a call made to pre_req(), call post_req() with

* a nonzero err condition.

*/

void    (*post_req)(struct mmc_host *host, struct mmc_request *req,

int err);

void    (*pre_req)(struct mmc_host *host, struct mmc_request *req,

bool is_first_req);

void    (*request)(struct mmc_host *host, struct mmc_request *req);

pre_req和post_req是非必需的,host driver可以利用它们实现诸如双buffer之类的高级功能。

数据传输的主题是struct mmc_request类型的指针,具体可参考3.7小节的介绍。

2)总线参数的配置以及卡状态的获取函数

/*

* Avoid calling these three functions too often or in a "fast path",

* since underlaying controller might implement them in an expensive

* and/or slow way.

*

* Also note that these functions might sleep, so don't call them

* in the atomic contexts!

*

* Return values for the get_ro callback should be:

*   0 for a read/write card

*   1 for a read-only card

*   -ENOSYS when not supported (equal to NULL callback)

*   or a negative errno value when something bad happened

*

* Return values for the get_cd callback should be:

*   0 for a absent card

*   1 for a present c

你可能感兴趣的:(linux,emmc子系统)