目录
4.4.启动tasklet(下半部延时任务处理),基于状态机处理硬件中断(上半部紧急的事务)
5.启动硬件atmci_interrupt中断,处理mmc控制器的状态
0.说明
基于A5D36平台eMMC驱动分析,设备和驱动匹配之后调用atmci_probe
1.设备树初始化
atmci_of_init
of_property_read_u32(cnp, "reg", &slot_id)
of_get_named_gpio(cnp, "cd-gpios", 0)
of_property_read_u32(cnp, "bus-width",&pdata->slot[slot_id].bus_width //获取总线
of_property_read_bool(cnp, "cd-inverted")
of_property_read_bool(cnp, "non-removable")
of_get_named_gpio(cnp, "wp-gpios", 0)
2.申请mmc主机控制器
struct atmel_mci *host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); //申请atmel host主机控制器
3.配置mmc的时钟配置
//3.配置mmc的时钟配置
host->mck = devm_clk_get(&pdev->dev, "mci_clk"); //mci_clk在哪里定义的???
host->bus_hz = clk_get_rate(host->mck); //host->bus_hz数值是多少???
4.4.启动tasklet(下半部延时任务处理),基于状态机处理硬件中断(上半部紧急的事务)
tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
atmci_tasklet_func
case STATE_IDLE: //状态空闲
case STATE_SENDING_CMD: //发送命令中
atmci_test_and_clear_pending(host, EVENT_CMD_RDY) //条件成立,执行下面的流程
atmci_set_completed(host, EVENT_CMD_RDY); //设置完成命令 EVENT_CMD_RDY
atmci_command_complete(host, mrq->cmd) //从 atmci_interrupt -> ATMCI_CMDRDY 中获取到的数据处理,分几种情况
state = STATE_END_REQUEST; //命令错误,直接结束
state = STATE_DATA_XFER; //数据传输
state = STATE_WAITING_NOTBUSY; //写空闲
state = STATE_END_REQUEST; //结束请求
case STATE_DATA_XFER: //数据传输
atmci_test_and_clear_pending(host, EVENT_XFER_COMPLETE)
atmci_set_completed(host, EVENT_XFER_COMPLETE);
if (host->caps.need_notbusy_for_read_ops ||(host->data->flags & MMC_DATA_WRITE))
state = STATE_WAITING_NOTBUSY; //
else if (host->mrq->stop)
state = STATE_SENDING_STOP;
else
state = STATE_END_REQUEST;
case STATE_WAITING_NOTBUSY: //非忙等待
atmci_test_and_clear_pending(host, EVENT_NOTBUSY)
atmci_set_completed(host, EVENT_NOTBUSY);
if (host->mrq->stop)
state = STATE_SENDING_STOP;
else
state = STATE_END_REQUEST;
case STATE_SENDING_STOP: //发送停止
atmci_test_and_clear_pending(host, EVENT_CMD_RDY)
if (mrq->stop->error)
state = STATE_END_REQUEST
else
state = STATE_WAITING_NOTBUSY;
case STATE_END_REQUEST: //停止请求
state = STATE_IDLE
5.启动硬件atmci_interrupt中断,处理mmc控制器的状态
request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
atmci_interrupt
ATMCI_DATA_ERROR_FLAGS //数据错误标识
atmci_set_pending(host, EVENT_DATA_ERROR); //设置 EVENT_DATA_ERROR
tasklet_schedule(&host->tasklet); //任务调度
ATMCI_TXBUFE //数据发送为空
atmci_pdc_complete
atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
tasklet_schedule(&host->tasklet); //任务调度
ATMCI_ENDTX //数据结束发送
ATMCI_RXBUFF //数据接收缓冲满
atmci_pdc_complete
sg_copy_from_buffer(host->data->sg, host->data->sg_len, host->buffer, transfer_size); //数据拷贝到host->data->sg,非常重要!!!
atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
tasklet_schedule(&host->tasklet); //任务调度
ATMCI_ENDRX //数据结束接收
ATMCI_BLKE //数据块已结束
atmci_set_pending(host, EVENT_NOTBUSY);
tasklet_schedule(&host->tasklet);
ATMCI_NOTBUSY //数据不忙
atmci_set_pending(host, EVENT_NOTBUSY);
tasklet_schedule(&host->tasklet);
ATMCI_RXRDY //数据接收
atmci_read_data_pio //接收数据
struct scatterlist *sg = host->sg; //以下是从寄存器提取数据到缓存
void *buf = sg_virt(sg);
value = atmci_readl(host, ATMCI_RDR);
put_unaligned(value, (u32 *)(buf + offset));
atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
ATMCI_TXRDY //数据发送
atmci_write_data_pio //发送数据
struct scatterlist *sg = host->sg; //以下是从缓存提取数据到寄存器
void *buf = sg_virt(sg);
value = get_unaligned((u32 *)(buf + offset));
atmci_writel(host, ATMCI_TDR, value);
atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
ATMCI_CMDRDY
atmci_set_pending(host, EVENT_CMD_RDY); //设置 EVENT_CMD_RDY
tasklet_schedule(&host->tasklet); //任务调度
ATMCI_SDIOIRQA | ATMCI_SDIOIRQB
atmci_sdio_interrupt
mmc_signal_sdio_irq
6.配置DMA
atmci_configure_dma
if (ret == 0) {
host->prepare_data = &atmci_prepare_data_dma;
host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_dma;
} else if (host->caps.has_pdc) {
dev_info(&pdev->dev, "using PDC\n");
host->prepare_data = &atmci_prepare_data_pdc;
host->submit_data = &atmci_submit_data_pdc;
host->stop_transfer = &atmci_stop_transfer_pdc;
} else {
dev_info(&pdev->dev, "using PIO\n");
host->prepare_data = &atmci_prepare_data;
host->submit_data = &atmci_submit_data;
host->stop_transfer = &atmci_stop_transfer;
}

该文详细介绍了在A5D36平台上eMMC驱动的初始化过程,包括设备树配置、mmc主机控制器申请、时钟配置、Tasklet机制处理中断、硬件中断启动、DMA配置、超时处理、mmc插槽初始化以及debugfs文件系统设置。驱动通过设备树获取参数,然后申请和配置mmc控制器,利用Tasklet处理中断状态机,配置DMA进行数据传输,并设置了超时软定时器。最后,初始化mmc插槽并进行mmc卡操作,如检测卡的存在、读写保护等。
最低0.47元/天 解锁文章
2962

被折叠的 条评论
为什么被折叠?



