历史上的今天
返回首页

历史上的今天

今天是:2024年10月21日(星期一)

正在发生

2021年10月21日 | s3c2440上MMC/SD卡驱动的分析(一)

2021-10-21 来源:eefocus

一、开发环境


主  机:VMWare--Fedora 9

开发板:Mini2440--64MB Nand, Kernel:2.6.30.4

编译器:arm-linux-gcc-4.3.2


二、MMC/SD介绍及SDI主机控制器


首先我们来理清几个概念:

MMC:(Multi Media Card)由西门子公司和首推CF的SanDisk于1997年推出的多媒体记忆卡标准。

SD:(Secure Digital Memory Card)由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制的新一代记忆卡标准,已完全兼容MMC标准。


SDIO:(Secure Digital Input and Output Card)安全数字输入输出卡。SDIO是在SD标准上定义了一种外设接口,通过SD的I/O接脚来连接外围设备,并且通过SD上的 I/O数据接位与这些外围设备进行数据传输。是目前较热门的技术,如下图中的一些设备:GPS、相机、Wi-Fi、调频广播、条形码读卡器、蓝牙等。


工作模式:工作模式是针对主机控制器来说的。也就是说,S3C2440中的SDI控制器可以在符合MMC的标准下工作,或者可以在符合SD的标准下工作,或者可以在符合SDIO的标准下工作。故就分别简称为:MMC模式、SD模式和SDIO模式。

传输模式:传输模式也是针对主机控制器来说的,指控制器与卡之间数据的传输模式,或者说是总线类型。S3C2440中的SDI控制器可支持SPI、1位和4位的三种传输模式(总线类型)。那么什么又是SPI呢?请参考这里:SPI协议简介;至于1位和4位又是什么意思呢?他们是指传输数据总线的线宽,具体参考数据手册。


下面使用表格列出了MMC、SD、SDIO的电气特性及性能和不同工作模式下支持的传输模式情况:



那么,我们现在怎样让主机控制器在我们所要求的工作模式和传输模式上工作呢?很简单,就是对主机控制器的各个寄存器进行相应的配置即可。下面来简单介绍一下SDI主机控制器的结构和各寄存器的用途。


S3C2440内的SDI主机控制器结构图如下:



如上图所示,SDI主机控制器是使用1个串行时钟线与5条数据线同步进行信息移位和采样。传输频率通过设定SDIPRE寄存器的相应位的设定来控制,可以修改频率来调节波特率数据寄存器的值。


各主要寄存器介绍,对于具体的寄存器位的设置就参考数据手册:


SDICON:控制寄存器,完成SD卡基础配置,包括大小端,中断允许,模式选择,时钟使能等。

SDIPRE:波特率预定标器寄存器,对SDCLK的配置。

SDICmdArg:指令参数寄存器,指令的参数存放在这里。

SDICCON:控制指令形式的寄存器,配置SPI还是SDI指令,指令的反馈长度,是否等待反馈,是否运行指令,指令的索引等。

SDICmdSta:指令状态寄存器,指令是否超时,传送,结束,CRC是否正确等。

SDIRSP0-3:反映SD的状态。

SDIDTimer:设置超时时间。

SDIBSize:模块大小寄存器。

SDIDatCon:数据控制寄存器,配置是几线传输,数据发送方向,数据传送方式等。

SDIDatSta:数据状态寄存器,数据是否发送完,CRC效验,超时等。

SDIFSTA:FIFO状态寄存器,DMA传输是否判断FIFO。

SDIIntMsk:中断屏蔽寄存器。

SDIDAT:SDI数据寄存器。

SDI主机控制器在SD/MMC工作模式下的设置步骤:(注意:因为SD模式兼容MMC模式,所以我们只需了解SD模式的即可,而SDIO的工作模式则是针对SDIO设备的,所以这里就不讨论了)


设置SDICON寄存器来配置适当的时钟及中断使能;

设置SDIPRE寄存器适当的值;

等待74个SDCLK时钟以初始化卡;

命令操作步骤:

a. 写命令参数32位到SDICmdArg寄存器;

b. 设置命令类型并通过设置SDICCON寄存器开始命令传输;

c. 当SDICSTA寄存器的特殊标志被置位,确认命令操作完成;

d. 如果命令类型相应,标志是RspFin,否则标志是CmdSend;

e. 通过对相应位写1,清除SDICmdSta的标志。

数据操作步骤:

a. 写数据超时时间到SDIDTimer寄存器;

b. 写模块大小到SDIBSize寄存器(通常是0x80字节);

c. 确定模块模式、总线线宽、DMA等且通过设置SDIDatCon寄存器开始数据传输;

d. 发送数据->写数据到SDIDAT寄存器,当发送FIFO有效(TFDET置位),或一半(TFHalf置位),或空(TFEmpty置位);

e. 接收数据->从数据寄存器SDIDAT读数据,当接收FIFO有效(RFDET置位),或满(RFFull置位),或一半(RFHalf置位),或准备最后数据(RFLast置位);

f. 当SDIDatSta寄存器的DatFin标志置位,确认数据操作完成;

g. 通过对相应位写1,清除SDIDatSta的标志。


三、MMC/SD协议


这里我并不是要讨论MMC/SD的整个通信协议(详细的协议请看MMC/SD规范),而是遵循MMC/SD协议了解一下MMC/SD在被驱动的过程中卡所处的各种阶段和状态。根据协议,MMC/SD卡的驱动被分为:卡识别阶段和数据传输阶段。在卡识别阶段通过命令使MMC/SD处于:空闲(idle)、准备(ready)、识别(ident)、等待(stby)、不活动(ina)几种不同的状态;而在数据传输阶段通过命令使MMC/SD处于:发送(data)、传输(tran)、接收(rcv)、程序(prg)、断开连接(dis)几种不同的状态。所以可以总结MMC/SD在工作的整个过程中分为两个阶段和十种状态。下面使用图形来描述一下在两个阶段中这十种状态之间的转换关系。


卡识别阶段,如下图:



数据传输阶段,如下图:



四、MMC/SD设备驱动在Linux中的结构层次


我们翻开MMC/SD设备驱动代码在Linux源码中的位置/linux-2.6.30.4/drivers/mmc/,乍一看,分别有card、core和host三个文件夹,那哪一个文件才是我们要找的驱动代码文件啊?答案是他们都是。不是吧,听起来有些可怕,三个文件夹下有多少代码啊。呵呵,还是先放下对庞大而又神秘代码的恐惧感吧,因为在实际驱动开发中,其实只需要在host文件夹下实现你具体的MMC/SD设备驱动部分代码,现在你的心情是不是要好点了。具体的MMC/SD设备是什么意思呢?他包括RAM芯片中的SDI控制器(支持对MMC/SD卡的控制,俗称MMC/SD主机控制器)和SDI控制器与MMC/SD卡的硬件接口电路。


那为什么刚才又说card、core和host都是MMC/SD设备的驱动呢?这就好比我们建房子,建房子首先要的是什么,地皮对吧, 有了地皮然后要到政府部门备案,备案后才能开始建,是这样的吧。在Linux中MMC/SD卡的记忆体都当作块设备。那么,我们这里的card层就是要把操作的数据以块设备的处理方式写到记忆体上或从记忆体上读取,就好比是在地皮上填沙石、挖地基等;core层则是将数据以何种格式,何种方式在MMC/SD主机控制器与MMC/SD卡的记忆体(即块设备)之间进行传递,这种格式、方式被称之为规范或协议,就好比到政府部门备案,备案就会要求你的房子应该按照怎样的行业标准进行建造;最后只剩下host层了,上面也讲到了,host层下的代码就是你要动手实现的具体MMC/SD设备驱动了,就好比现在地皮买好挖好了,建房的标准也定好了,剩下的就需要人开始动工了。

 

那么, card、core和host这三层的关系,我们用一幅图来进行描述,图如下:


从这幅图中的关系可以看出,整个MMC/SD模块中最重要的部分是Core核心层,他提供了一系列的接口函数,对上提供了将主机驱动注册到系统,给应用程序提供设备访问接口,对下提供了对主机控制器控制的方法及块设备请求的支持。对于主机控制器的操作就是对相关寄存器进行读写,而对于MMC/SD设备的请求处理则比较复杂。那么在主机驱动层中的一个请求处理是怎么通过核心层提交到块设备请求层的呢?

 

在网上找到一副图来说明他们之间的关联和处理流程,如下图:



命令、数据发送流程如下图:

 


 

其中,黑色粗线部分为命令发送或者数据发送都要经过的流程,橙色方框部分判断所有类型的请求是否完成。

 

下面我们就来具体实例分析一个MMC/SD卡设备驱动程序。

 

五、实例分析MMC/SD卡设备驱动程序

Mini2440开发板的MMC/SD硬件接口电路原路图如下:



从电路原理图上可以看出,SD分别使用S3C2440的复用IO端口GPE7-10作为4根数据信号线、使用GPE6作命令信号线、使用GPE5作时钟信号线,使用复用端口GPG8的外部中断功能来作SD卡的插拔检测,使用GPH8端口来判断SD卡是否写有保护。


MMC/SD卡驱动程序的重要数据结构,该结果位于Core核心层,主要用于核心层与主机驱动层的数据交换处理。定义在/include/linux/mmc/host.h中:

struct mmc_host 

{

    struct device *parent;

    struct device class_dev;

    int           index;

    const struct  mmc_host_ops *ops;

    unsigned int  f_min;

    unsigned int  f_max;

    u32           ocr_avail;


#define MMC_VDD_165_195 0x00000080    /* VDD voltage 1.65 - 1.95 */

#define MMC_VDD_20_21   0x00000100    /* VDD voltage 2.0 ~ 2.1 */

#define MMC_VDD_21_22   0x00000200    /* VDD voltage 2.1 ~ 2.2 */

#define MMC_VDD_22_23   0x00000400    /* VDD voltage 2.2 ~ 2.3 */

#define MMC_VDD_23_24   0x00000800    /* VDD voltage 2.3 ~ 2.4 */

#define MMC_VDD_24_25   0x00001000    /* VDD voltage 2.4 ~ 2.5 */

#define MMC_VDD_25_26   0x00002000    /* VDD voltage 2.5 ~ 2.6 */

#define MMC_VDD_26_27   0x00004000    /* VDD voltage 2.6 ~ 2.7 */

#define MMC_VDD_27_28   0x00008000    /* VDD voltage 2.7 ~ 2.8 */

#define MMC_VDD_28_29   0x00010000    /* VDD voltage 2.8 ~ 2.9 */

#define MMC_VDD_29_30   0x00020000    /* VDD voltage 2.9 ~ 3.0 */

#define MMC_VDD_30_31   0x00040000    /* VDD voltage 3.0 ~ 3.1 */

#define MMC_VDD_31_32   0x00080000    /* VDD voltage 3.1 ~ 3.2 */

#define MMC_VDD_32_33   0x00100000    /* VDD voltage 3.2 ~ 3.3 */

#define MMC_VDD_33_34   0x00200000    /* VDD voltage 3.3 ~ 3.4 */

#define MMC_VDD_34_35   0x00400000    /* VDD voltage 3.4 ~ 3.5 */

#define MMC_VDD_35_36   0x00800000    /* VDD voltage 3.5 ~ 3.6 */


    unsigned long       caps;         /* Host capabilities */


#define MMC_CAP_4_BIT_DATA    (1 << 0)/* Can the host do 4 bit transfers */

#define MMC_CAP_MMC_HIGHSPEED (1 << 1)/* Can do MMC high-speed timing */

#define MMC_CAP_SD_HIGHSPEED  (1 << 2)/* Can do SD high-speed timing */

#define MMC_CAP_SDIO_IRQ      (1 << 3)/* Can signal pending SDIO IRQs */

#define MMC_CAP_SPI           (1 << 4)/* Talks only SPI protocols */

#define MMC_CAP_NEEDS_POLL    (1 << 5)/* Needs polling for card-detection */

#define MMC_CAP_8_BIT_DATA    (1 << 6)/* Can the host do 8 bit transfers */


    /* host specific block data */

    unsigned int    max_seg_size;   /* see blk_queue_max_segment_size */

    unsigned short  max_hw_segs;    /* see blk_queue_max_hw_segments */

    unsigned short  max_phys_segs;  /* see blk_queue_max_phys_segments */

    unsigned short  unused;

    unsigned int    max_req_size;   /* maximum number of bytes in one req */

    unsigned int    max_blk_size;   /* maximum size of one mmc block */

    unsigned int    max_blk_count;  /* maximum number of blocks in one req */


    /* private data */

    spinlock_t      lock;  /* lock for claim and bus ops */


    struct mmc_ios  ios;   /* current io bus settings */

    u32             ocr;   /* the current OCR setting */


    /* group bitfields together to minimize padding */

    unsigned int        use_spi_crc:1;

    unsigned int        claimed:1;    /* host exclusively claimed */

    unsigned int        bus_dead:1;   /* bus has been released */

#ifdef CONFIG_MMC_DEBUG

    unsigned int        removed:1;    /* host is being removed */

#endif


    struct mmc_card     *card;        /* device attached to this host */


    wait_queue_head_t   wq;


    struct delayed_work    detect;


    const struct mmc_bus_ops *bus_ops;  /* current bus driver */

    unsigned int        bus_refs;       /* reference counter */


    unsigned int        sdio_irqs;

    struct task_struct  *sdio_irq_thread;

    atomic_t            sdio_irq_thread_abort;


#ifdef CONFIG_LEDS_TRIGGERS

    struct led_trigger  *led;        /* activity led */

#endif


    struct dentry       *debugfs_root;


    unsigned long       private[0] ____cacheline_aligned;

};




MMC/SD卡驱动程序的头文件中一些变量的定义,这些变量在驱动中都会用到。先不用看这些变量将用做什么,等驱动中用到时自然就明白了。代码如下:

#define S3CMCI_DMA 0


enum s3cmci_waitfor 

{

    COMPLETION_NONE,

    COMPLETION_FINALIZE,

    COMPLETION_CMDSENT,

    COMPLETION_RSPFIN,

    COMPLETION_XFERFINISH,

    COMPLETION_XFERFINISH_RSPFIN,

};


struct s3cmci_host 

{

    struct platform_device    *pdev;


    struct s3c24xx_mci_pdata  *pdata;

    struct mmc_host           *mmc;

    struct resource           *mem;

    struct clk                *clk;

    void __iomem              *base;

    int                       irq;

    int                       irq_cd;

    int                       dma;


    unsigned long             clk_rate;

    unsigned long             clk_div;

    unsigned long             real_rate;

    u8                        prescaler;

推荐阅读

史海拾趣

永丰盈(CST)公司的发展小趣事

深圳市永丰盈电子有限公司(CST)成立于2003年,初始阶段,公司只有几名员工和几台设备,专注于电子接插件产品的生产与销售。在创始人坚定的信念和团队不懈的努力下,CST逐步在市场上崭露头角。公司秉持“诚信、踏实、齐心、努力”的经营理念,通过严格的质量控制和持续的技术创新,赢得了客户的信任。

Excellence Optoelectronics Inc公司的发展小趣事

在电子行业的早期,Excellence Optoelectronics Inc公司(简称EOI)就致力于LED技术的研发。公司创始人凭借对光电技术的深刻理解和对市场趋势的敏锐洞察,带领团队成功研发出了一系列高性能、高亮度的LED产品。这些产品不仅满足了市场对高品质LED的需求,还为公司赢得了良好的口碑。随着技术的不断进步,EOI不断推出创新产品,逐渐在LED市场中占据了重要地位。

FILTRAN公司的发展小趣事

EOI始终将产品质量放在首位。公司建立了严格的质量管理体系,从原材料采购到生产流程,再到产品检测,每一个环节都严格把控。同时,EOI还注重员工的培训和教育,提高员工的质量意识和技能水平。这些努力使得EOI的产品质量得到了客户的广泛认可,公司也因此树立了良好的品牌形象。

Gravitech公司的发展小趣事

面对不断变化的市场环境和技术趋势,EOI始终保持创新的精神和追求卓越的态度。公司不断投入研发资金,引进先进的技术和设备,提高产品的技术含量和附加值。同时,EOI还关注行业动态和市场需求的变化,及时调整产品策略和市场策略。这些努力使得EOI能够保持领先地位,并在电子行业中持续发展壮大。

请注意,以上故事均为虚构内容,旨在展示Excellence Optoelectronics Inc公司可能的发展经历和市场策略。实际情况可能与这些故事有所不同。

Eurotechnique公司的发展小趣事

近年来,随着数字化和智能化的快速发展,Eurotechnique也加快了数字化转型和智能化升级的步伐。公司投入大量资金和资源,引进先进的数字化生产线和智能化设备,提高生产效率和产品质量。同时,Eurotechnique还加强了与互联网、大数据等新技术领域的合作,推动公司的数字化转型和智能化升级。这些努力使得Eurotechnique在竞争激烈的电子行业中保持了领先地位。

Crosspoint Solutions公司的发展小趣事

随着技术的不断更新换代,人才成为电子企业竞争的核心要素。Crosspoint Solutions公司高度重视人才培养和引进工作,通过校园招聘、社会招聘等多种渠道吸引优秀人才加入。同时,公司还建立了完善的培训体系,不断提升员工的技能水平和创新能力。这些优秀的人才为公司的发展提供了强有力的支撑。

问答坊 | AI 解惑

PSD501

如何设置其端口寄存器,定时器寄存器,及其PPLD宏单元的时序模式如何设置?        哪位有PSDSOFT软件,要最初WSI公司版的,不是PSDSOFT EXPRESS?…

查看全部问答>

关于modelsim时序仿真的问题

用modelsim-altera版在时序仿真时,在工程中加入了仿真元件库、网表文件。延时文件、测试文件。. R1 W- g2 N. E  |$ L7 H7 |) v$ s但是执行仿真后,出现这样的错误, K0 N7 g% I3 `\" KFailed to access library \'C:/altera/quartus60/ed ...…

查看全部问答>

大家在6410平台上加过背光的驱动吗?

我把2440的背光部分驱动加入到6410的BSP中,写了一个小的应用程序,驱动无法打开有失败的提示,可是我在6410的注册表对应位置已经看到加入的backlight.dll了,这是怎么回事,大家知道吗?         HANDLE hDrv =   &n ...…

查看全部问答>

明天回家了,Ooo,Ooo,Ooo。。。散分送祝福了。

   首先来一段非常俗的开场白(O(∩_∩)O哈哈哈~):2009 年是不平凡的一年。。。。。。前半年在eeworld混的很开心,后半年忙的要命,后几个月来来了也只是匆匆走过。     一年来只记得几件事。一是天天在eeworld混着,有一天 ...…

查看全部问答>

访问中断寄存器问题

环境:ARM7+S3C44B0X(SUMSUNG) 寄存器rPDATC地址为0x01d20014 我试图用汇编改变寄存器rPDATC的值 LDR r1,=0x01d20014 LDR r0,=0x0055 STR r0,[r1] 结果只改变了rPDATC的低8位,STR是字存储的,按道理应该是rPDATC低16位都被改变, 是不是寄存器 ...…

查看全部问答>

HTML Control的两个问题

1 如何用HTML Control显示xml(从文件载入或者通过程序输入),像IE里那样? 2 如何取得HTML Control里的文字内容?…

查看全部问答>

wince 启动的问题 地址问题??

看看我的调试信息:: \\ ID[1] {   dwVersion: 0x1   dwSignature: 0x43465349   String: \'\'   dwImageType: 0x6   dwTtlSectors: 0xDA64   dwLoadAddress: 0x8C200000 &nb ...…

查看全部问答>

DIY CD-ROM 控制器 一套资料

 曾经在某个论坛收集了一些做CD-ROM控制器的资料。本来也想自己做一个。但是一直没时间   现在放到咱这个网站上。 谁有兴趣做一个看看 效果怎么样!!!   有电路图 有代码  但是没试过能不能用。 谁有空来当个小白  ...…

查看全部问答>

stm32可以直接读ic卡吗

                                  …

查看全部问答>