目录
0.说明
1.设备树初始化
2.申请mmc主机控制器
3.配置mmc的时钟配置
4.4.启动tasklet(下半部延时任务处理),基于状态机处理硬件中断(上半部紧急的事务)
5.启动硬件atmci_interrupt中断,处理mmc控制器的状态
6.配置DMA
7.设置一个超时的软定时器
8.初始化mmc插槽
9.初始化debugfs文件系统
10.提供给上层的访问数据接口
11.启动信息
12. eMMC获取CSD
基于A5D36平台eMMC驱动分析,设备和驱动匹配之后调用atmci_probe
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)
struct atmel_mci *host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); //申请atmel host主机控制器
//3.配置mmc的时钟配置
host->mck = devm_clk_get(&pdev->dev, "mci_clk"); //mci_clk在哪里定义的???
host->bus_hz = clk_get_rate(host->mck); //host->bus_hz数值是多少???
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
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
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;
}
setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
atmci_timeout_timer //任务超时将执行以下动作
host->state = STATE_END_REQUEST; //停止请求,交给 atmci_tasklet_func 处理
tasklet_schedule(&host->tasklet); //启动调度
//8.初始化mmc插槽
atmci_init_slot
struct mmc_host *mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev) //初始化一个mmc主控制器
dev_set_name(&host->class_dev, "mmc%d", host->index); //mmc0
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
mmc_rescan
for (i = 0; i < ARRAY_SIZE(freqs); i++) //static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
mmc_rescan_try_freq(host, max(freqs[i], host->f_min)
sdio_reset
mmc_io_rw_direct_host
mmc_wait_for_cmd
mmc_wait_for_req
__mmc_start_req
mmc_start_request
host->ops->request(host, mrq) //.request = atmci_request, //见下分析
mmc_wait_for_req_done
mmc_go_idle
//组织eMMC格式数据
struct mmc_command cmd = {0};
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
//mmc发送cmd
mmc_wait_for_cmd(host, &cmd, 0) //具体流程同上
struct mmc_request mrq = {NULL};
cmd->retries = retries;
mrq.cmd = cmd;
cmd->data = NULL;
mmc_wait_for_req(host, &mrq)
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
mmc_send_if_cond
struct mmc_command cmd = {0};
cmd.opcode = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
mmc_wait_for_cmd(host, &cmd, 0);
mmc_attach_sdio //未使用
mmc_attach_sd //未使用
mmc_attach_mmc //mmc主控制器连接mmc
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN) //设置mmc的总线模式
host->ios.bus_mode = mode;
mmc_set_ios(host);
//调试信息输出
pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " "width %u timing %u\n",
mmc_hostname(host), ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, ios->bus_width, ios->timing);
//设置io总线
host->ops->set_ios(host, ios) //.set_ios = atmci_set_ios
atmci_set_ios //见下分析
mmc_send_op_cond(host, 0, &ocr) //设置card的工作电压寄存器OCR,并且通过busy位(bit31)来判断card的上电复位过程是否完成,如果没有完成的话需要重复发送。
struct mmc_command cmd = {0};
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
mmc_wait_for_cmd(host, &cmd, 0)
mmc_attach_bus(host, &mmc_ops)
host->bus_ops = ops;
//以下为总线结构体定义
static const struct mmc_bus_ops mmc_ops = {
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
.runtime_suspend = mmc_runtime_suspend,
.runtime_resume = mmc_runtime_resume,
.power_restore = mmc_power_restore,
.alive = mmc_alive,
.shutdown = mmc_shutdown,
};
mmc_select_voltage(host, ocr) //屏蔽掉不支持的任何电压并选择最低电压
mmc_power_cycle(host, ocr)
mmc_power_off(host) //断电
host->ios.clock = 0;
host->ios.vdd = 0;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_power_up(host, ocr) //上电
//第1步骤
host->ios.vdd = fls(ocr) - 1;
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
//第2步骤
host->ios.clock = host->f_init;
host->ios.power_mode = MMC_POWER_ON;
mmc_set_ios(host);
mmc_init_card(host, rocr, NULL)
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN) //设置总线模式,开路
mmc_go_idle(host);
mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
struct mmc_command cmd = {0};
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
mmc_wait_for_cmd(host, &cmd, 0)
mmc_all_send_cid(host, cid) //获取cid
struct mmc_command cmd = {0};
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
mmc_set_relative_addr(card) //
struct mmc_command cmd = {0};
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES)
mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL)
host->ios.bus_mode = mode;
mmc_set_ios(host);
mmc_send_csd(card, card->raw_csd)
mmc_send_cxd_native(card->host, card->rca << 16,csd, MMC_SEND_CSD)
struct mmc_command cmd = {0};
cmd.opcode = opcode;
cmd.arg = arg;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
mmc_decode_csd(card) //解析csd
csd->max_dtr = tran_exp[e] * tran_mant[m]; //时钟,25M
mmc_decode_cid(card) //解析cid
mmc_set_dsr(host)
struct mmc_command cmd = {0};
cmd.opcode = MMC_SET_DSR;
cmd.arg = (host->dsr << 16) | 0xffff;
cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
mmc_select_card(card)
_mmc_select_card(card->host, card)
struct mmc_command cmd = {0};
cmd.opcode = MMC_SELECT_CARD;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
mmc_get_ext_csd(card, &ext_csd) //验证时,这里出错了
mmc_send_ext_csd(card, ext_csd)
mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,ext_csd, 512)
mmc_set_data_timeout(&data, card)
mmc_wait_for_req(host, &mrq)
mmc_read_ext_csd(card, ext_csd)
struct mmc_ext_csd //将ext_csd的内容解析到card结构体中(struct mmc_ext_csd),内部很复杂!!!!!!
mmc_card_blockaddr(card)
mmc_init_erase(card)
mmc_set_erase_size(card)
mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,EXT_CSD_ERASE_GROUP_DEF, 1,card->ext_csd.generic_cmd6_time)
__mmc_switch(card, set, index, value, timeout_ms, true, true,false)
struct mmc_command cmd = {0};
cmd.opcode = MMC_SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |(index << 16) |(value << 8) |set;
cmd.flags = MMC_CMD_AC;
mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
mmc_select_timing(card) //选择时序(很关键的步骤!!!!!!!!!!)
mmc_set_bus_speed(card)
mmc_select_hs(card)
__mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,card->ext_csd.generic_cmd6_time,true, true, true)
mmc_set_timing(card->host, MMC_TIMING_MMC_HS)
host->ios.timing = timing;
mmc_set_ios(host);
mmc_card_hs(card)
mmc_card_hs200(card)
mmc_set_clock(card->host, max_dtr)
__mmc_set_clock(host, hz)
host->ios.clock = hz
mmc_set_ios(host)
mmc_select_bus_width(card) //测试总线(未执行)
for (; idx < ARRAY_SIZE(bus_widths); idx++)
mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,EXT_CSD_BUS_WIDTH,ext_csd_bits[idx],card->ext_csd.generic_cmd6_time)
mmc_set_bus_width(host, bus_width) //设置bus总线位数
host->ios.bus_width = width;
mmc_set_ios(host);
mmc_bus_test(card, bus_width)
mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width);
mmc_select_powerclass(card)
__mmc_select_powerclass(card, ext_csd_bits)
mmc->ops = &atmci_ops; //绑定mmc的操作接口函数,见下
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); //向上取整, #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
mmc->f_max = host->bus_hz / 2;
if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) //最新的内核有更新,要注意同步!!!!!!!!!!!!!!!!!!!!!!!!!
mmc->caps |= MMC_CAP_4_BIT_DATA;
//检测mmc卡是否存在
set_bit(ATMCI_CARD_PRESENT, &slot->flags); //假设卡存在,然后进行验证
if (gpio_is_valid(slot->detect_pin)) {
...
//检测mmc卡是否写保护
if (gpio_is_valid(slot->wp_pin)) {
...
//mmc增加电源调节
mmc_regulator_get_supply(mmc);
//配置定时器和中断,用于探测卡的状态
if (gpio_is_valid(slot->detect_pin))
setup_timer(&slot->detect_timer, atmci_detect_change,(unsigned long)slot);
atmci_detect_change
if (present != present_old) //卡当前状态与之前状态比较
dev_dbg(&slot->mmc->class_dev, "card %s\n", present ? "inserted" : "removed");
if (!present)
clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
else
set_bit(ATMCI_CARD_PRESENT, &slot->flags);
if (mrq == host->mrq)
switch (host->state)
case STATE_IDLE:
case STATE_SENDING_CMD:
case STATE_DATA_XFER:
case STATE_WAITING_NOTBUSY:
case STATE_SENDING_STOP:
case STATE_END_REQUEST:
else
list_del(&slot->queue_node);
mmc_request_done(slot->mmc, mrq);
ret = request_irq(gpio_to_irq(slot->detect_pin), atmci_detect_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "mmc-detect", slot);
atmci_detect_interrupt
mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20)); //探测到mmc管脚的变化(即热插拔),启动定时器
atmci_init_debugfs
node = debugfs_create_file("regs", S_IRUSR, root, host,&atmci_regs_fops);
node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
node = debugfs_create_x32("pending_events", S_IRUSR, root,(u32 *)&host->pending_events);
node = debugfs_create_x32("completed_events", S_IRUSR, root,(u32 *)&host->completed_events);
//以下是数据请求发送流程
static const struct mmc_host_ops atmci_ops = {
.request = atmci_request, //见下分析
.set_ios = atmci_set_ios,
.get_ro = atmci_get_ro,
.get_cd = atmci_get_cd,
.enable_sdio_irq = atmci_enable_sdio_irq,
};
atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
atmci_queue_request(struct atmel_mci *host, struct atmel_mci_slot *slot, struct mmc_request *mrq)
if (host->state == STATE_IDLE) //如果 atmci_tasklet_func 任务机制中的状态机为空闲 STATE_IDLE 就直接启动发送
host->state = STATE_SENDING_CMD
atmci_start_request(host, slot);
host->prepare_data(host, data) //host->prepare_data = &atmci_prepare_data_dma;
atmci_prepare_data
host->sg = data->sg; //以下是DMA数据准备
host->sg_len = data->sg_len;
host->data = data;
host->data_chan = NULL;
desc->callback = atmci_dma_complete; //DMA数据完成回调函数
atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
tasklet_schedule(&host->tasklet); //任务调度
host->submit_data(host, data) //host->submit_data = &atmci_submit_data_dma;
mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); //启动软定时器
else //否则添加到 slot->queue_node 队列中
list_add_tail(&slot->queue_node, &host->queue);
//配置io总线
static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
//总线位宽初始化
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
slot->sdc_reg |= ATMCI_SDCBUS_1BIT;
break;
case MMC_BUS_WIDTH_4:
slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
break;
case MMC_BUS_WIDTH_8:
slot->sdc_reg |= ATMCI_SDCBUS_8BIT;
break;
}
//时钟初始化
if (ios->clock) {
unsigned int clock_min = ~0U;
u32 clkdiv;
...
//电源初始化
switch (ios->power_mode) {
case MMC_POWER_OFF:
if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
break;
case MMC_POWER_UP:
set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
break;
...
//获取mmc读写标识
static int atmci_get_ro(struct mmc_host *mmc)
read_only = gpio_get_value(slot->wp_pin);
dev_dbg(&mmc->class_dev, "card is %s\n", read_only ? "read-only" : "read-write");
//获取卡是否存在
static int atmci_get_cd(struct mmc_host *mmc)
present = !(gpio_get_value(slot->detect_pin) ^ slot->detect_is_active_high);
dev_dbg(&mmc->class_dev, "card is %spresent\n", present ? "" : "not ");
//中断使能和禁止
static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
if (enable)
atmci_writel(host, ATMCI_IER, slot->sdio_irq);
else
atmci_writel(host, ATMCI_IDR, slot->sdio_irq);
Mar 16 17:56:08 kernel: atmci_probe: run here0
Mar 16 17:56:08 kernel: atmci_of_init(): pdata->slot[0].bus_width = 8
Mar 16 17:56:08 kernel: atmci_probe(): host->bus_hz=132000000
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: version: 0x505
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: using dma0chan5 for DMA transfers
Mar 16 17:56:08 kernel: atmci_init_slot(): slot->sdc_reg=0x00000000, mmc->ios.bus_width=8
bus_width=8, detect_pin=-2, detect_is_active_high=false, wp_pin=-2
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: No vmmc regulator found
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: No vqmmc regulator found
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 0Hz busmode 2 powermode 1 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 0Hz bm PP pm UP vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: Atmel MCI controller at 0xf0000000 irq 25, 1 slots
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here1
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here2
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here3
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here5
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here6
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 1 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
OK
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_decode_csd(): run here csd->max_dtr=25000000, tran_exp[e]=1000000, tran_mant[m]=25
Mar 16 17:56:08 kernel: mmc_init_card(): run here13
Mar 16 17:56:08 kernel: mmc0: BKOPS_EN bit is not set
Mar 16 17:56:08 kernel: mmc_init_card(): run here15
Mar 16 17:56:08 kernel: mmc_select_timing: run here 4 err=0
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 25000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 25000000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_init_card(): card->host->ios.timing=0
Mar 16 17:56:08 kernel: mmc_init_card(): run here20
Mar 16 17:56:08 kernel: mmc_select_bus_width: host->caps=0x0000006d
Mar 16 17:56:08 kernel: mmc_select_bus_width(): idx=0, bus_width=3
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 25000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 3 timing 0
(CRON) STARTUP (1.4.12)
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 25000000Hz bm PP pm ON vdd 21 width 8 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=3, slot->sdc_reg=0x000000c0
(CRON) INFO (Syslog will be used instead of sendmail.)
Mar 16 17:56:08 kernel: mmc_init_card(): run here21
(CRON) INFO (RANDOM_DELAY will be scaled with factor 12% if used.)
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here7
Mar 16 17:56:08 kernel: mmc0: new MMC card at address 0001
Mar 16 17:56:08 kernel: mmcblk0: mmc0:0001 IS032G 29.1 GiB
(root) BAD FILE MODE (/etc/crontab)
Mar 16 17:56:08 kernel: mmcblk0boot0: mmc0:0001 IS032G partition 1 4.00 MiB
Mar 16 17:56:08 kernel: mmcblk0boot1: mmc0:0001 IS032G partition 2 4.00 MiB
Mar 16 17:56:08 kernel: mmcblk0: unknown partition table
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here8
4.eMMC调试输出CSD获取
Mar 17 08:35:21 kernel: mmc_decode_csd(): run here structure=3, mmca_vsn=4, mmca_vsn=4, max_dtr=25000000, cmdclass=000000f5, read_blkbits=9, read_partial=0, write_misalign=0, read_misalign=0, write_blkbits=9, write_partial=0, erase_size=1024