《基于S3C2440的嵌入式Linux开发实例》课件第4章_第1页
《基于S3C2440的嵌入式Linux开发实例》课件第4章_第2页
《基于S3C2440的嵌入式Linux开发实例》课件第4章_第3页
《基于S3C2440的嵌入式Linux开发实例》课件第4章_第4页
《基于S3C2440的嵌入式Linux开发实例》课件第4章_第5页
已阅读5页,还剩144页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

4.1SD/MMC概述4.2S3C2440SD/MMC接口寄存器介绍4.3LinuxSD/MMC驱动程序分析4.1.1SD卡总线协议及工作原理

作为一种新型的存储设备,SD卡具有以下特点:内置加密技术,适应基于SDMI协议的著作版权保护功能;高速数据传送;高存储容量;体积小,便于携带,具有很强的抗冲击能力。

SD卡的电气参数如下:

(1)物理特性。4.1SD/MMC概述(2)电源要求。

(3)数据传输速度:2 Mb/s。

(4)使用环境。

SD卡基于9针接口,最大可工作在25 MHz。SD卡的结构如图4-1所示。SD卡内部的结构分为外接口驱动、SD卡接口驱动、电源检测、存储器内核接口及内存储器内核5部分。图4-1SD卡结构示意图4.1.2SD卡引脚及接口电路

1. SD卡引脚说明

SD卡引脚如表4-1所示。表4-1SD卡引脚说明

2.S3C2410的SD卡接口电路

图4-2为SD卡接口原理图,SD卡的数据和命令线用上拉电阻。

S3C2410的SD卡兼容SD存储卡(1.0版)/MMC(2.11版);兼容SDIO卡(1.0版);16字(64字节)的FIFO寄存器,用于接收/发送数据;40位的命令寄存器;136位的应答寄存器;8位的预分频逻辑电路(Freq=SystemClock/(P+1));支持普通和DMA传送模式(字节、半字、字传输);1位或4位线宽模式,区块/串流(block/stream)的传输模式。图4-2SD卡接口原理图

1. SDI控制寄存器

SDI控制寄存器各位定义如表4-2和表4-3所示。4.2S3C2440SD/MMC接口寄存器介绍表4-2SDI控制寄存器表4-3SDI控制寄存器位定义

2.SDI预设分频寄存器

SDI预设分频寄存器各位定义如表4-4和表4-5所示。

3.SDI命令参数寄存器

SDI命令参数寄存器各位定义如表4-6和表4-7所示。表4-4SDI预设分频寄存器表4-5SDI预设分频寄存器位定义表4-6SDI命令参数寄存器表4-7SDI命令参数寄存器位定义4.SDI命令控制寄存器

SDI命令控制寄存器各位定义如表4-8和4-9所示。表4-8SDI命令控制寄存器表4-9SDI命令控制寄存器位定义5. SDI命令状态寄存器

SDI命令状态寄存器各位定义如表4-10和表4-11所示。

6. SDI应答寄存器

SDI应答寄存器各位定义如表4-12和表4-13所示。表4-10SDI命令状态寄存器表4-11SDI命令状态寄存器位定义表4-12SDI应答寄存器表4-13SDI应答寄存器位定义7.SDI应答寄存器1(SDIRSP1)

SDI应答寄存器各位定义如表4-14和表4-15所示。

8.SDI应答寄存器2(SDIRSP2)

SDI应答寄存器2各位定义如表4-16和表4-17所示。表4-14SDI应答寄存器1表4-15SDI应答寄存器1位定义表4-16SDI应答寄存器2表4-17SDI响应寄存器2位定义9.SDI响应寄存器3(SDIRSP3)

SDI应答寄存器3各位定义如表4-18和表4-19所示。

10.数据/测忙定时寄存器(SDIDTimer)

数据/测忙定时寄存器各位定义如表4-20和表4-21所示。表4-18SDI应答寄存器3表4-19SDI应答寄存器3位定义表4-20数据/测忙定时寄存器表4-21数据/测忙定时寄存器位定义11.SDI块大小寄存器(SDIBSize)

SDI块大小寄存器各位定义如表4-22和表4-23所示。

12.数据控制寄存器(SDIDatCon)

数据控制寄存器各位定义如表4-24和表4-25所示。表4-22SDI块大小寄存器表4-23SDI块大小寄存器位定义表4-24数据控制寄存器位定义表4-25数据控制寄存器4.3.1寄存器地址和功能定义

S3C2440SDI控制器相关寄存器地址及初始值定义如下:

#defineS3C2410_SDICON (0x00)

#defineS3C2410_SDIPRE (0x04)

#defineS3C2410_SDICMDARG (0x08)

#defineS3C2410_SDICMDCON (0x0C)

#defineS3C2410_SDICMDSTAT (0x10)

#defineS3C2410_SDIRSP0 (0x14)4.3LinuxSD/MMC驱动程序分析#defineS3C2410_SDIRSP1 (0x18)

#defineS3C2410_SDIRSP2 (0x1C)

#defineS3C2410_SDIRSP3 (0x20)

#defineS3C2410_SDITIMER (0x24)

#defineS3C2410_SDIBSIZE (0x28)

#defineS3C2410_SDIDCON (0x2C)

#defineS3C2410_SDIDCNT (0x30)

#defineS3C2410_SDIDSTA (0x34)

#defineS3C2410_SDIFSTA (0x38)#ifdefCONFIG_CPU_S3C2440

#defineS3C2410_SDIDATA (0x40)

#defineS3C2410_SDIIMSK (0x3c)

#else

#defineS3C2410_SDIDATA (0x3C)

#defineS3C2410_SDIIMSK (0x40)

#endif#defineS3C2410_SDICON_MMCRESET (1<<8)

#defineS3C2410_SDICON_CLOCKTYPE (1<<5)

#defineS3C2410_SDICON_BYTEORDER (1<<4)

#defineS3C2410_SDICON_SDIOIRQ (1<<3)

#defineS3C2410_SDICON_RWAITEN (1<<2)

#defineS3C2410_SDICON_CLKEN (1<<0)#defineS3C2410_SDICMDCON_ABORT (1<<12)

#defineS3C2410_SDICMDCON_WITHDATA (1<<11)

#defineS3C2410_SDICMDCON_LONGRSP (1<<10)

#defineS3C2410_SDICMDCON_WAITRSP (1<<9)

#defineS3C2410_SDICMDCON_CMDSTART (1<<8)

#defineS3C2410_SDICMDCON_SENDERHOST (1<<6)

#defineS3C2410_SDICMDCON_INDEX (0xff)#defineS3C2410_SDICMDSTAT_CRCFAIL (1<<12)

#defineS3C2410_SDICMDSTAT_CMDSENT (1<<11)

#defineS3C2410_SDICMDSTAT_CMDTIMEOUT(1<<10)

#defineS3C2410_SDICMDSTAT_RSPFIN (1<<9)

#defineS3C2410_SDICMDSTAT_XFERING (1<<8)

#defineS3C2410_SDICMDSTAT_INDEX (0xff)#defineS3C2410_SDIDCON_BURST4 (1<<24)//FOR2440

#defineS3C2410_SDIDCON_DATASIZE (3<<22)//FOR2440

#defineS3C2410_SDIDCON_IRQPERIOD (1<<21)

#defineS3C2410_SDIDCON_TXAFTERRESP (1<<20)

#defineS3C2410_SDIDCON_RXAFTERCMD (1<<19)

#defineS3C2410_SDIDCON_BUSYAFTERCMD(1<<18)

#defineS3C2410_SDIDCON_BLOCKMODE (1<<17)#defineS3C2410_SDIDCON_WIDEBUS (1<<16)

#defineS3C2410_SDIDCON_DMAEN (1<<15)

//#defineS3C2410_SDIDCON_STOP (1<<14)

#defineS3C2410_SDIDCON_DTST (1<<14)

#defineS3C2410_SDIDCON_DATMODE (3<<12)

#defineS3C2410_SDIDCON_BLKNUM (0x7ff)/*constantsforS3C2410_SDIDCON_DATMODE*/

#defineS3C2410_SDIDCON_XFER_READY (0<<12)

#defineS3C2410_SDIDCON_XFER_CHKSTART (1<<12)

#defineS3C2410_SDIDCON_XFER_RXSTART (2<<12)

#defineS3C2410_SDIDCON_XFER_TXSTART (3<<12)#defineS3C2410_SDIDCON_DAT_BYTE(0<<22)//FOR2440

#defineS3C2410_SDIDCON_DAT_HW (1<<22)//FOR2440

#defineS3C2410_SDIDCON_DAT_WD(2<<22)//FOR2440

#defineS3C2410_SDIDCON_BLKNUM_MASK (0xFFF)

#defineS3C2410_SDIDCNT_BLKNUM_SHIFT

(12)#defineS3C2410_SDIDSTA_RDYWAITREQ (1<<10)

#defineS3C2410_SDIDSTA_SDIOIRQDETECT (1<<9)

#defineS3C2410_SDIDSTA_FIFOFAIL (1<<8) /*reservedon2440*/

#defineS3C2410_SDIDSTA_CRCFAIL

(1<<7)

#defineS3C2410_SDIDSTA_RXCRCFAIL

(1<<6)

#defineS3C2410_SDIDSTA_DATATIMEOUT (1<<5)#defineS3C2410_SDIDSTA_XFERFINISH (1<<4)

#defineS3C2410_SDIDSTA_BUSYFINISH (1<<3)

#defineS3C2410_SDIDSTA_SBITERR (1<<2) /*reservedon2410a/2440*/

#defineS3C2410_SDIDSTA_TXDATAON (1<<1)

#defineS3C2410_SDIDSTA_RXDATAON (1<<0)#defineS3C2410_SDICON_FIFORESET (1<<16)//fors3c2440

#defineS3C2410_SDIFSTA_TFDET (1<<13)

#defineS3C2410_SDIFSTA_RFDET (1<<12)

#defineS3C2410_SDIFSTA_TXHALF (1<<11)

#defineS3C2410_SDIFSTA_TXEMPTY(1<<10)

#defineS3C2410_SDIFSTA_RFLAST (1<<9)

#defineS3C2410_SDIFSTA_RFFULL (1<<8)

#defineS3C2410_SDIFSTA_RFHALF (1<<7)

#defineS3C2410_SDIFSTA_COUNTMASK (0x7f)#defineS3C2410_SDIIMSK_RESPONSECRC(1<<17)

#defineS3C2410_SDIIMSK_CMDSENT (1<<16)

#defineS3C2410_SDIIMSK_CMDTIMEOUT (1<<15)

#defineS3C2410_SDIIMSK_RESPONSEND (1<<14)

#defineS3C2410_SDIIMSK_READWAIT (1<<13)

#defineS3C2410_SDIIMSK_SDIOIRQ (1<<12)

#defineS3C2410_SDIIMSK_FIFOFAIL

(1<<11)

#defineS3C2410_SDIIMSK_CRCSTATUS (1<<10)#defineS3C2410_SDIIMSK_DATACRC (1<<9)

#defineS3C2410_SDIIMSK_DATATIMEOUT (1<<8)

#defineS3C2410_SDIIMSK_DATAFINISH (1<<7)

#defineS3C2410_SDIIMSK_BUSYFINISH (1<<6)

#defineS3C2410_SDIIMSK_SBITERR (1<<5) /*reserved2440/2410a*/#defineS3C2410_SDIIMSK_TXFIFOHALF (1<<4)

#defineS3C2410_SDIIMSK_TXFIFOEMPTY (1<<3)

#defineS3C2410_SDIIMSK_RXFIFOLAST (1<<2)

#defineS3C2410_SDIIMSK_RXFIFOFULL (1<<1)

#defineS3C2410_SDIIMSK_RXFIFOHALF (1<<0)4.3.2数据结构和变量描述

1.结构体mmc_blk_data

SD/MMC设备由控制器及插卡组成,对应设备结构为mmc_host结构和mmc_card结构体。每个卡的插槽都对应一个块的数据结构体mmc_blk_data,其结构体代码描述如下:

structmmc_blk_data

{

spinlock_t lock;

structgendisk *disk; /*通用硬盘结构*/

structmmc_queuequeue; /*MMC请求队列结构*/

unsignedint usage;

unsignedint block_bits; /*卡每一块大小所占的bit位*/

};2.结构体mmc_card

结构体mmc_card描述了插卡的特性,它带有一个插卡,代码描述如下:

structmmc_card

{

structlist_head node; /*在主设备链表中的节点*/

structmmc_host *host;/*卡所属的控制器*/

structdevice dev; /*通用设备结构*/unsignedchar sd;

unsignedint rca; /*设备相对本地系统的地址*/

unsignedint state; /*卡的状态*/

u8 bus_width; /*总线宽度*/

#defineMMC_STATE_PRESENT (1<<0)

/*卡出现在sys文件系统中*/

#defineMMC_STATE_DEAD(1<<1)

/*卡不在工作状态*/

#defineMMC_STATE_BAD (1<<2) /*不认识的设备*/

u32 raw_cid[4]; /*raw-card

cid*/

u32 raw_csd[4]; /*rawcardCSD*/

structmmc_cid cid;

/*卡身份鉴别,值来自卡的CID寄存器*/

structmmc_csd csd;

/*卡特定信息,值来自卡的CSD寄存器*/

};3.结构体mmc_host

结构体mmc_host描述了一个MMC卡控制器的特性及操作等,代码描述如下:

structmmc_host

{

structdevice*dev; /*通用设备结构*/

structmmc_host_ops*ops;/*控制器操作函数集结构*/

void*priv;unsignedintf_min;

unsignedintf_max;

u32

ocr_avail; /*卡可用的ocr寄存器*/

charhost_name[8]; /*控制器名字*/

/*私有数据*/

structmmc_iosios; /*当前io总线设置*/

u32ocr; /*当前OCR设置*/structlist_head cards; /*接在主控制器的卡*/

wait_queue_head_twq; /*等待队列*/

spinlock_tlock; /*卡忙的锁*/

structmmc_card*card_busy;

/*theMMCcardclaiminghost*/

structmmc_card*card_selected; /*选择MMC卡*/

structwork_struct detect;

};4.结构体s3c2410sdi_host

结构体s3c2410sdi_host描述了s3c2440控制器的相关特性,代码描述如下:

structs3c2410sdi_host

{

structmmc_host*mmc;/*通用mmc_host结构体指针*/

s3c24xx_mmc_pdata_t*pdata;

structresource *mem; /*设备内存资源*/structclk*clk;/*设备时钟*/

void__iomem *base; /*设备d端口I/O基地址*/

intirq; /*中断号*/

intirq_cd;

intdma;structscatterlist*cur_sg;

unsignedintnum_sg;

void*mapped_sg;

unsignedintoffset;

unsignedintremain;

intsize; /*传输的大小*/

structmmc_request*mrq;

unsignedcharbus_width; /*总线宽度*/

spinlock_tcomplete_lock;

structcompletioncomplete_request;

structcompletioncomplete_dma;

enums3c2410sdi_waitfor complete_what;

};5. s3c2410sdi_ops变量

s3c2410sdi_ops变量定义了mmchost相关操作,代码描述如下:

staticstructmmc_host_opss3c2410sdi_ops=

{

.request=s3c2410sdi_request,

.set_ios=s3c2410sdi_set_ios,

};6.结构体mmc_ios

结构体mmc_ios描述了控制器对卡的I/O状态,代码描述如下:

structmmc_ios

{

unsignedint clock; /*时钟频率*/

unsignedshort vdd; /*SD工作电压值*/

unsignedchar bus_mode; /*命令输出模式*/

unsignedchar chip_select;/*芯片选择*/

unsignedchar power_mode;/*电源模式*/

unsignedchar bus_width; /*数据总线宽度*/

}7.结构体变量s3c2410sdi_driver

结构体变量s3c2410sdi_driver描述了sd/mmc初始化和移除的操作,代码描述如下:

staticstructdevice_drivers3c2410sdi_driver=

{

.name=“s3c2440-sdi”,

.bus=&platform_bus_type,

.probe=s3c2410sdi_probe,

.remove=s3c2410sdi_remove,

};4.3.3主要函数描述

驱动程序结构如图4-3所示。图4-3驱动程序结构图

1.模块初始化函数s3c2410sdi_init()

模块初始化函数s3c2410sdi_init()代码描述如下:

staticint_inits3c2410sdi_init(void)

{

returndriver_register(&s3c2410sdi_driver);

}2. SD/MMC驱动卸载函数s3c2410sdi_exit()

SD/MMC驱动卸载函数s3c2410sdi_exit()代码描述如下:

staticvoid__exits3c2410sdi_exit(void)

{

driver_unregister(&s3c2410sdi_driver);

}

3. SD/MMC探测函数s3c2410sdi_probe()

s3c2410sdi_probe()函数主要完成SD控制器驱动结构分配、GPIO中的的配置、IO地址空间分配、中断的分配、时钟的设置等。其主要流程如图4-4所示。图4-4SD/MMC探测函数流程图代码描述如下:

staticints3c2410sdi_probe(structdevice*dev)

{

structplatform_device*pdev=to_platform_device(dev);

structmmc_host*mmc;

s3c24xx_mmc_pdata_t*pdata;

structs3c2410sdi_host*host;

intret;/*分配mmchost*/

mmc=mmc_alloc_host(sizeof(structs3c2410sdi_host),dev);

if(!mmc)

{

ret=-ENOMEM;

gotoprobe_out;

}

/*获得mmc私有数据*/

host=mmc_priv(mmc);spin_lock_init(&host->complete_lock);

host->complete_what=COMPLETION_NONE;

host->mmc=mmc;

host->dma=S3C2410SDI_DMA;

/*得到平台数据*/

pdata=dev->platform_data;

if(!pdata)

{

dev->platform_data=&s3c2410_mmc_defplat;

pdata=&s3c2410_mmc_defplat;

}

host->pdata=pdata;

/*得到SD/MMC检测卡gpio中断号*/

host->irq_cd=s3c2410_gpio_getirq(pdata->gpio_detect);/*配置SD/MMCGPIO管脚*/

s3c2410_gpio_cfgpin(pdata->gpio_detect,S3C2410_GPG8_EINT16);

/*分配内存空间*/

host->mem=platform_get_resource(pdev,IORESOURCE_MEM,0);

if(!host->mem)

{

gotoprobe_free_host;

}/*IO地址空间分配*/

host->mem=request_mem_region(host->mem->start,

RESSIZE(host->mem),pdev->name);

if(!host->mem)

{

printk(KERN_INFOPFX“failedtorequestiomemory

region.\n”);

ret=-ENOENT;

gotoprobe_free_host;

}/*io地址映射*/

host->base=ioremap(host->mem->start,RESSIZE(host->mem));

if(host->base==0)

{

printk(KERN_INFOPFX“failedtoioremap()iomemoryregion.\n”);

ret=-EINVAL;

gotoprobe_free_mem_region;

}/*得到中断号*/

host->irq=platform_get_irq(pdev,0);

if(host->irq==0)

{

printk(KERN_INFOPFX“failedtogetinterruptresouce.\n”);

ret=-EINVAL;

gotoprobe_iounmap;

}/*系统申请中断*/

if(request_irq(host->irq,s3c2410sdi_irq,0,DRIVER_NAME,host))

{

printk(KERN_INFOPFX“failedtorequestsdiinterrupt.\n”);

ret=-ENOENT;

gotoprobe_iounmap;

}/*设置中断类型*/

set_irq_type(host->irq_cd,IRQT_BOTHEDGE);

/*申请卡插入拔出检测中断*/

if(request_irq(host->irq_cd,s3c2410sdi_irq_cd,0,DRIVER_NAME,host))

{

printk(KERN_WARNINGPFX“failedtorequestcarddetectinterrupt.\n”);

ret=-ENOENT;

gotoprobe_free_irq;}

/*DMA申请*/

if(s3c2410_dma_request(S3C2410SDI_DMA,&s3c2410sdi_dma_client,NULL))

{

printk(KERN_WARNINGPFX“unabletogetDMAchannel.\n”);

ret=-EBUSY;

gotoprobe_free_irq_cd;

}/*得到SD/MMC时钟*/

host->clk=clk_get(dev,“sdi”);

if(IS_ERR(host->clk))

{

printk(KERN_INFOPFX“failedtofindclocksource.\n”);

ret=PTR_ERR(host->clk);

host->clk=NULL;

gotoprobe_free_host;}

if((ret=clk_use(host->clk)))

{

printk(KERN_INFOPFX“failedtouseclocksource.\n”);

gotoclk_free;

}if((ret=clk_enable(host->clk)))

{

printk(KERN_INFOPFX“failedtoenableclocksource.\n”);

gotoclk_unuse;

}

s3c2410_sdi_test(mmc);mmc->ops=&s3c2410sdi_ops;

mmc->ocr_avail=MMC_VDD_32_33;

mmc->f_min=clk_get_rate(host->clk)/512;

mmc->f_max =clk_get_rate(host->clk)/2;

mmc->caps=MMC_CAP_4_BIT_DATA;

//HACK:ThereseemstobeahardwarebuginTomTomGO.

if(mmc->f_max>3000000)mmc->f_max=3000000;mmc->max_sectors=64;

mmc->max_seg_size=mmc->max_sectors<<9;

if((ret=mmc_add_host(mmc)))

{

printk(KERN_INFOPFX“failedtoaddmmchost.\n”);

gotoclk_disable;

}dev_set_drvdata(dev,mmc);

return0;

clk_disable:

clk_disable(host->clk);

clk_unuse:

clk_unuse(host->clk);

clk_free:

clk_put(host->clk);probe_free_irq_cd:

free_irq(host->irq_cd,host);

probe_free_irq:

free_irq(host->irq,host);

probe_iounmap:

iounmap(host->base);

probe_free_mem_region:

release_mem_region(host->mem->start,RESSIZE(host->mem));

probe_free_host:

mmc_free_host(mmc);

probe_out:

returnret;

}4. SD/MMC驱动移除函数s3c2410sdi_remove()

SD/MMC驱动移除函数s3c2410sdi_remove()代码描述如下:

staticints3c2410sdi_remove(structdevice*dev)

{

structmmc_host*mmc=dev_get_drvdata(dev);

structs3c2410sdi_host*host=mmc_priv(mmc);mmc_remove_host(mmc);

clk_disable(host->clk);

clk_unuse(host->clk);

clk_put(host->clk);

free_irq(host->irq_cd,host);

free_irq(host->irq,host);

iounmap(host->base);

release_mem_region(host->mem->start,RESSIZE(host->mem));

mmc_free_host(mmc);

return0;

}

5. SD/MMC中断处理函数s3c2410sdi_irq()

s3c2410sdi_irq()函数主要根据SD卡相关寄存器,完成SD控制器中的的处理,如判断数据的收发,校验等。其主要流程如图4-5所示。图4-5SD/MMC中断处理函数流程图代码描述如下:

staticirqreturn_ts3c2410sdi_irq(intirq,void*dev_id,structpt_regs*regs)

{

structs3c2410sdi_host*host;

u32sdi_csta,sdi_dsta,sdi_dcnt;

u32sdi_cclear,sdi_dclear;

unsignedlongiflags;

host=(structs3c2410sdi_host*)dev_id;

if(!host)returnIRQ_HANDLED;/*读取SD命令状态卡的的寄存器*/

sdi_csta=readl(host->base+S3C2410_SDICMDSTAT);

sdi_dsta=readl(host->base+S3C2410_SDIDSTA);

sdi_dcnt=readl(host->base+S3C2410_SDIDCNT);

spin_lock_irqsave(&host->complete_lock,iflags);

/*判断中断是否处理完成*/

if(host->complete_what==COMPLETION_NONE)

{

gotoclear_imask;

}if(!host->mrq)

{

gotoclear_imask;

}

sdi_cclear=0;

sdi_dclear=0;

/*判断命令超时状态*/

if(sdi_csta&S3C2410_SDICMDSTAT_CMDTIMEOUT)

{

host->mrq->cmd->error=MMC_ERR_TIMEOUT;

gototransfer_closed;

}/*判断否处于发送状态*/

if(sdi_csta&S3C2410_SDICMDSTAT_CMDSENT)

{

if(host->complete_what==COMPLETION_CMDSENT)

{

host->mrq->cmd->error=MMC_ERR_NONE;

gototransfer_closed;

}

sdi_cclear|=S3C2410_SDICMDSTAT_CMDSENT;

}/*判断CRC校验是否成功*/

if(sdi_csta&S3C2410_SDICMDSTAT_CRCFAIL)

{

if(host->mrq->cmd->flags&MMC_RSP_LONG)

{

DBG(PFX"s3c2410fixup:ignoreCRCfailwithlongrsp\n");

}

else

{

DBG(PFX“COMMANDCRCFAILED%x\n”,sdi_csta);

if(host->mrq->cmd->flags&MMC_RSP_CRC)

{

host->mrq->cmd->error=MMC_ERR_BADCRC;

gototransfer_closed;

}

}

sdi_cclear|=S3C2410_SDICMDSTAT_CRCFAIL;

}/*判断是否有响应*/

if(sdi_csta&S3C2410_SDICMDSTAT_RSPFIN)

{

if(host->complete_what==COMPLETION_RSPFIN)

{

host->mrq->cmd->error=MMC_ERR_NONE;

gototransfer_closed;

}if(host->complete_what==COMPLETION_XFERFINISH_RSPFIN)

{

host->mrq->cmd->error=MMC_ERR_NONE;

host->complete_what=COMPLETION_XFERFINISH;

}

sdi_cclear|=S3C2410_SDICMDSTAT_RSPFIN;

}

/*判断FIFO响应是否成功*./if(sdi_dsta&S3C2410_SDIDSTA_FIFOFAIL)

{

host->mrq->cmd->error=MMC_ERR_NONE;

host->mrq->data->error=MMC_ERR_FIFO;

gototransfer_closed;

}/*判断发送校验是否成功*/

if(sdi_dsta&S3C2410_SDIDSTA_RXCRCFAIL)

{

host->mrq->cmd->error=MMC_ERR_NONE;

host->mrq->data->error=MMC_ERR_BADCRC;

gototransfer_closed;

}

/*判断CRC校验是否成功*if(sdi_dsta&S3C2410_SDIDSTA_CRCFAIL)

{

host->mrq->cmd->error=MMC_ERR_NONE;

host->mrq->data->error=MMC_ERR_BADCRC;

gototransfer_closed;

}/*判断数据是否超时*/

if(sdi_dsta&S3C2410_SDIDSTA_DATATIMEOUT)

{

host->mrq->cmd->error=MMC_ERR_NONE;

host->mrq->data->error=MMC_ERR_TIMEOUT;

gototransfer_closed;

}if(sdi_dsta&S3C2410_SDIDSTA_XFERFINISH)

{

if(host->complete_what==COMPLETION_XFERFINISH)

{

host->mrq->cmd->error=MMC_ERR_NONE;

host->mrq->data->error=MMC_ERR_NONE;

gototransfer_closed;

}if(host->complete_what==COMPLETION_XFERFINISH_RSPFIN)

{

host->mrq->data->error=MMC_ERR_NONE;

host->complete_what=COMPLETION_RSPFIN;

}

sdi_dclear|=S3C2410_SDIDSTA_XFERFINISH;

}writel(sdi_cclear,host->base+S3C2410_SDICMDSTAT);

writel(sdi_dclear,host->base+S3C2410_SDIDSTA);

spin_unlock_irqrestore(&host->complete_lock,iflags);

 DBG(PFX"IRQstillwaiting.\n");

returnIRQ_HANDLED;

transfer_closed:writel(sdi_cclear,host->base+S3C2410_SDICMDSTAT);

writel(sdi_dclear,host->base+S3C2410_SDIDSTA);

host->complete_what=COMPLETION_NONE;

complete(&host->complete_request);

writel(0,host->base+S3C2410_SDIIMSK);

spin_unlock_irqrestore(&host->complete_lock,iflags);

DBG(PFX"IRQtransferclosed.\n");

returnIRQ_HANDLED;clear_imask:

writel(0,host->base+S3C2410_SDIIMSK);

spin_unlock_irqrestore(&host->complete_lock,iflags);

DBG(PFX“IRQclearimask.\n”);

returnIRQ_HANDLED;

}6. s3c2410sdi_dma_done_callback()函数

s3c2410sdi_dma_done_callback()函数用于处理SD/MMC的dma操作,代码描述如下:

voids3c2410sdi_dma_done_callback(s3c2410_dma_chan_t*dma_ch,void*buf_id,

intsize,s3c2410_dma_buffresult_tresult)

{

unsignedlongiflags;

u32sdi_csta,sdi_dsta,sdi_dcnt;

structs3c2410sdi_host*host=(structs3c2410sdi_host*)buf_id;//读取SD/MMC卡寄存器值

sdi_csta=readl(host->base+S3C2410_SDICMDSTAT);

sdi_dsta=readl(host->base+S3C2410_SDIDSTA);

sdi_dcnt=readl(host->base+S3C2410_SDIDCNT);

spin_lock_irqsave(&host->complete_lock,iflags);

if(!host->mrq)gotoout;

if(!host->mrq->data)gotoout;sdi_csta=readl(host->base+S3C2410_SDICMDSTAT);

sdi_dsta=readl(host->base+S3C2410_SDIDSTA);

sdi_dcnt=readl(host->base+S3C2410_SDIDCNT);

if(result!=S3C2410_RES_OK)

{

printk(“result!=S3C2410_RES_OK\n”);

gotofail_request;

}if(host->mrq->data->flags&MMC_DATA_READ)

{

if(sdi_dcnt>0)

{

printk(“MMC_DATA_READ:sdi_dcnt>0\n”);

gotofail_request;

}

}out:

complete(&host->complete_dma);

spin_unlock_irqrestore(&host->complete_lock,iflags);

return;

fail_request:

host->mrq->data->error=MMC_ERR_FAILED;

host->complete_what=COMPLETION_NONE;

complete(&host->complete_request);

writel(0,host->base+S3C2410_SDIIMSK);

gotoout;

}7. s3c2410sdi_request()函数

s3c2410sdi_reques()函数,主要处理SD卡的请求,包括命令、数据等,代码描述如下:

staticvoids3c2410sdi_request(structmmc_host*mmc,structmmc_request*mrq)

{

structs3c2410sdi_host*host=mmc_priv(mmc);

structdevice*dev=mmc_dev(host->mmc);

structplatform_device*pdev=to_platform_device(dev);

u32sdi_carg,sdi_ccon,sdi_timer;

u32sdi_bsize,sdi_dcon,sdi_imsk;

intdma_len=0;

u32sdifsta;sdi_ccon=mrq->cmd->opcode&S3C2410_SDICMDCON_INDEX;

sdi_ccon|=S3C2410_SDICMDCON_SENDERHOST;

sdi_ccon|=S3C2410_SDICMDCON_CMDSTART;

sdi_carg=mrq->cmd->arg;

sdi_timer=0x007FFFFF;sdi_bsize=0;

sdi_dcon=0;

sdi_imsk=0;

/*使能传输错误中断*/

sdi_imsk|=S3C2410_SDIIMSK_RESPONSEND;

sdi_imsk|=S3C2410_SDIIMSK_CRCSTATUS;

host->complete_what=COMPLETION_CMDSENT;if(mrq->cmd->flags&MMC_RSP_MASK)

{

host->complete_what=COMPLETION_RSPFIN;

sdi_ccon|=S3C2410_SDICMDCON_WAITRSP;

sdi_imsk|=S3C2410_SDIIMSK_CMDTIMEOUT;

}

else

{

sdi_imsk|=S3C2410_SDIIMSK_CMDSENT;

}if(mrq->cmd->flags&MMC_RSP_LONG)

{

sdi_ccon|=S3C2410_SDICMDCON_LONGRSP;

}

if(mrq->cmd->flags&MMC_RSP_CRC)

{

sdi_imsk|=S3C2410_SDIIMSK_RESPONSECRC;

}if(mrq->data)

{

sdifsta=readl(host->base+S3C2410_SDIFSTA);

sdifsta|=S3C2410_SDICON_FIFORESET;

writel(sdifsta,host->base+S3C2410_SDIFSTA);

host->complete_what=COMPLETION_XFERFINISH_RSPFIN;

sdi_bsize=(1<<mrq->data->blksz_bits);sdi_dcon=(mrq->data->blocks&S3C2410_SDIDCON_BLKNUM_MASK);

sdi_dcon|=S3C2410_SDIDCON_DMAEN;

sdi_dcon|=S3C2410_SDIDCON_DTST;

sdi_imsk|=S3C2410_SDIIMSK_FIFOFAIL;

sdi_imsk|=S3C2410_SDIIMSK_DATACRC;

sdi_imsk|=S3C2410_SDIIMSK_DATATIMEOUT;

sdi_imsk|=S3C2410_SDIIMSK_DATAFINISH;

sdi_imsk|=0xFFFFFFE0;if(host->bus_width==MMC_BUS_WIDTH_4)

{

DBG(PFX“MMC_BUS_WIDTH_4\n”);

sdi_dcon|=S3C2410_SDIDCON_WIDEBUS;

}

if(!(mrq->data->flags&MMC_DATA_STREAM))

{

sdi_dcon|=S3C2410_SDIDCON_BLOCKMODE;

DBG(PFX“MMC_DATA_BLOCK\n”);

}

if(mrq->data->flags&MMC_DATA_WRITE)

{

DBG(PFX“MMC_DATA_WRITE\n”);

sdi_dcon|=S3C2410_SDIDCON_TXAFTERRESP;

sdi_dcon|=S3C2410_SDIDCON_XFER_TXSTART;

sdi_dcon|=S3C2410_SDIDCON_DAT_WD;

sdi_dcon|=S3C2410_SDIDCON_BURST4;

}

if(mrq->data->flags&MMC_DATA_READ)

{

DBG(PFX“MMC_DATA_READ\n”);

sdi_dcon|=S3C2410_SDIDCON_RXAFTERCMD;

sdi_dcon|=S3C2410_SDIDCON_XFER_RXSTART;

sdi_dcon|=S3C2410_SDIDCON_DAT_WD;

//sdi_dcon|=S3C2410_SDIDCON_BURST4;

}

s3c2410sdi_dma_setup(host,mrq->data->flags&MMC_DATA_WRITE?

S3C2410_DMASRC_MEM:S3C2410_DMASRC_HW);dma_len=dma_map_sg(&pdev->dev,mrq->data->sg,mrq->data->sg_len,mrq->data->flags

&MMC_DATA_READ?DMA_FROM_DEVICE:DMA_TO_DEVICE);

DBG(PFX"dma_len:0x%08x\n",dma_len);

/*开始DMA*/

s3c2410_dma_enqueue(host->dma,(void*)host,

sg_dma_address(&mrq->data->sg[0]),

(mrq->data->blocks<<mrq->data->blksz_bits));

}host->mrq=mrq;

init_completion(&host->complete_request);

init_completion(&host->complete_dma);

/*清除命令状态寄存器*/

writel(0xFFFFFFFF,host->base+S3C2410_SDICMDSTAT);

writel(0xFFFFFFFF,host->base+S3C2410_SDIDSTA);/*设置SDI控制器*/

writel(sdi_bsize,host->base+S3C2410_SDIBSIZE);

writel(sdi_timer,host->base+S3C2410_SDITIMER);

writel(sdi_imsk,host->base+S3C2410_SDIIMSK);

/*设置SDI命令参数和数据寄存器*/

writel(sdi_carg,host->base+S3C2410_SDICMDARG);

writel(sdi_dcon,host->base+S3C2410_SDIDCON);

//Thisinitiatestransfer

writel(sdi_ccon,host->base+S3C2410_SDICMDCON);/*等待传输完成*/

wait_for_completion(&host->complete_request);

DBG("[CMD]requestcomplete.\n");

if(mrq->data)

{

wait_for_completion(&host->complete_dma);

}

/*清除SD/MMC控制器和寄存器*/

writel(0,host->base+S3C2410_SDICMDARG);

writel(0,host->base+S3C2410_SDIDCON);

writel(0,host->base+S3C2410_SDICMDCON);

writel(0,host->base+S3C2410_SDIIMSK);/*读取响应*/

mrq->cmd->resp[0]=readl(host->base+S3C2410_SDIRSP0);

mrq->cmd->resp[1]=readl(host->base+S3C2410_SDIRSP1);

mrq->cmd->resp[2]=readl(host->base+S3C2410_SDIRSP2);

mrq->cmd->resp[3]=readl(host->base+S3C2410_SDIRSP3);

host->mrq=NULL;

if(!mrq->data)gotorequest_done;dma_unmap_sg(&pdev->dev,mrq->data->sg,dma_len,\

mrq->data

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论