host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; if (data->flags & MMC_DATA_READ) {
host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); } else {
host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; }
host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); }
host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; wmb();
DDADR(host->dma) = host->sg_dma; DCSR(host->dma) = DCSR_RUN; }
for()循环里的内容是整个SD卡主控制器设备驱动的实质,通过DMA的方式实现主控制器与SD卡之间数据的读写操作。
3) pxamci_start_cmd 实现主控制器与SD卡之间指令的传输
static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) {
host->cmd = cmd;
if (cmd->flags & MMC_RSP_BUSY) cmdat |= CMDAT_BUSY;
#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) switch (RSP_TYPE(mmc_resp_type(cmd))) { case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ cmdat |= CMDAT_RESP_SHORT; break;
case RSP_TYPE(MMC_RSP_R3): cmdat |= CMDAT_RESP_R3; break;
case RSP_TYPE(MMC_RSP_R2): cmdat |= CMDAT_RESP_R2;
break; default: break; }
writel(cmd->opcode, host->base + MMC_CMD); writel(cmd->arg >> 16, host->base + MMC_ARGH); writel(cmd->arg & 0xffff, host->base + MMC_ARGL); writel(cmdat, host->base + MMC_CMDAT); pxamci_start_clock(host);
pxamci_enable_irq(host, END_CMD_RES); }
-> response类型
根据SD卡的协议,当SD卡收到从控制器发来的cmd指令后,SD卡会发出response相应,而response的类型分为R1,R1b,R2,R3,R6,R7,这些类型分别对应不同的指令,各自的数据包结构也不同(具体内容参考SD卡协议)。这里,通过RSP_TYPE对指令cmd的opcode的解析得到相对应的reponse类型,再通过swich赋给寄存器MMC_CMDAT对应的[1:0]位。
-> 将指令和参数写入寄存器
4行writel()是整个SD卡主控制器设备驱动的实质,通过对主控制器芯片寄存器MMC_CMD,MMC_ARGH,MMC_ARGL,MMC_CMDAT的设置,实现主控制器发送指令到SD卡的功能。 4) 调用(*request) 以上通过pxamci_request()实现了主控制器的通信功能,之后只须通过host->ops->request(host, mrq);回调函数即可。
协议层里,每条指令都会通过mmc_wait_for_req(host, &mrq)调用到host->ops->request(host, mrq)来发送指令和数据。 /* core/core.c */
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) {
DECLARE_COMPLETION_ONSTACK(complete); mrq->done_data = &complete; mrq->done = mmc_wait_done; mmc_start_request(host, mrq); wait_for_completion(&complete); }
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { ... ...
host->ops->request(host, mrq); }
2.2.4 申请中断
pxamci_probe(struct platform_device *pdev)中有两个中断,一个为SD主控制器芯片内电路固有的内部中断,另一个为探测引脚的探测到外部有SD卡插拔引起的中断。 1) 由主控芯片内部电路引起的中断
request_irq(host->irq, pxamci_irq, 0, \回顾一下,host->irq就是刚才从platform_device里得到的中断号, irq = platform_get_irq(pdev, 0); host->irq = irq;
接下来,pxamci_irq便是为该中断host->irq申请的中断函数, static irqreturn_t pxamci_irq(int irq, void *devid) {
struct pxamci_host *host = devid; // 得到主控制器的数据 unsigned int ireg; int handled = 0;
ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); // 读取中断寄存器的值 if (ireg) {
unsigned stat = readl(host->base + MMC_STAT); // 读取状态寄存器的值 if (ireg & END_CMD_RES)
handled |= pxamci_cmd_done(host, stat); if (ireg & DATA_TRAN_DONE)
handled |= pxamci_data_done(host, stat); if (ireg & SDIO_INT) {
mmc_signal_sdio_irq(host->mmc); } }
return IRQ_RETVAL(handled); }
当调用(*request),即host->ops->request(host, mrq),即上文中的pxamci_request()后,控制器与SD卡之间开始进行一次指令或数据传输,通信完毕后,主控芯片将产生一个内部
中断,以告知此次指令或数据传输完毕。这个中断的具体值将保存在一个名为MMC_I_REG的中断寄存器中以供读取,中断寄存器MMC_I_REG中相关描述如下,
如果中断寄存器MMC_I_REG中的第0位有值,则意味着数据传输完成,执行pxamci_cmd_done(host, stat);
如果中断寄存器MMC_I_REG中的第2位有值,则意味着指令传输完成,执行pxamci_data_done(host, stat);
其中stat是从状态寄存器MMC_STAT中读取的值,在代码里主要起到处理错误状态的作用。
-> pxamci_cmd_done 收到结束指令的内部中断信号,主控制器从SD卡那里得到response,结束这次指令传输
这里需要注意,寄存器MMC_RES里已经存放了来自SD卡发送过来的response,以供读取。
static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) {
struct mmc_command *cmd = host->cmd;
cmd->resp[i] = readl(host->base + MMC_RES) & 0xffff; if (stat & STAT_TIME_OUT_RESPONSE) { cmd->error = -ETIMEDOUT;
} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; }
pxamci_disable_irq(host, END_CMD_RES); if (host->data && !cmd->error) {
pxamci_enable_irq(host, DATA_TRAN_DONE); } else {
pxamci_finish_request(host, host->mrq); // 结束一次传输,清空主控制器中的指令和数据 }
return 1; }
-> pxamci_data_done 收到结束数据的内部中断信号,得到传输数据的大小,结束这次数据传输
static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) {
struct mmc_data *data = host->data; DCSR(host->dma) = 0;
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, host->dma_dir); if (stat & STAT_READ_TIME_OUT) data->error = -ETIMEDOUT;
else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) data->error = -EILSEQ; if (!data->error)
data->bytes_xfered = data->blocks * data->blksz; // 数据传输量=块的数量*每个块的大小(一般为512字节) else
data->bytes_xfered = 0;
pxamci_disable_irq(host, DATA_TRAN_DONE); host->data = NULL;
pxamci_finish_request(host, host->mrq); ... ... }
static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) {
host->mrq = NULL; host->cmd = NULL; host->data = NULL;
mmc_request_done(host->mmc, mrq); set_mmc_cken(host, 0); unset_dvfm_constraint(); }
/* drivers/mmc/core/core.c */
void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) {