目录
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_initof_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_funccase STATE_IDLE: //状态空闲case STATE_SENDING_CMD: //发送命令中atmci_test_and_clear_pending(host, EVENT_CMD_RDY) //条件成立,执行下面的流程atmci_set_completed(host, EVENT_CMD_RDY); //设置完成命令 EVENT_CMD_RDYatmci_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;elsestate = 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;elsestate = STATE_END_REQUEST;case STATE_SENDING_STOP: //发送停止atmci_test_and_clear_pending(host, EVENT_CMD_RDY)if (mrq->stop->error)state = STATE_END_REQUESTelsestate = 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_ERRORtasklet_schedule(&host->tasklet); //任务调度ATMCI_TXBUFE //数据发送为空atmci_pdc_completeatmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETEtasklet_schedule(&host->tasklet); //任务调度ATMCI_ENDTX //数据结束发送 ATMCI_RXBUFF //数据接收缓冲满atmci_pdc_completesg_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_COMPLETEtasklet_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_COMPLETEATMCI_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_COMPLETEATMCI_CMDRDYatmci_set_pending(host, EVENT_CMD_RDY); //设置 EVENT_CMD_RDYtasklet_schedule(&host->tasklet); //任务调度ATMCI_SDIOIRQA | ATMCI_SDIOIRQBatmci_sdio_interruptmmc_signal_sdio_irq
atmci_configure_dmaif (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_slotstruct 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); //mmc0INIT_DELAYED_WORK(&host->detect, mmc_rescan);mmc_rescanfor (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_resetmmc_io_rw_direct_hostmmc_wait_for_cmdmmc_wait_for_req__mmc_start_reqmmc_start_requesthost->ops->request(host, mrq) //.request = atmci_request, //见下分析mmc_wait_for_req_donemmc_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发送cmdmmc_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_condstruct 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主控制器连接mmcmmc_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_iosatmci_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) //获取cidstruct 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) //解析csdcsd->max_dtr = tran_exp[e] * tran_mant[m]; //时钟,25Mmmc_decode_cid(card) //解析cidmmc_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 = hzmmc_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_changeif (present != present_old) //卡当前状态与之前状态比较dev_dbg(&slot->mmc->class_dev, "card %s\n", present ? "inserted" : "removed");if (!present)clear_bit(ATMCI_CARD_PRESENT, &slot->flags);elseset_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:elselist_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_interruptmod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20)); //探测到mmc管脚的变化(即热插拔),启动定时器
atmci_init_debugfsnode = 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_CMDatmci_start_request(host, slot);host->prepare_data(host, data) //host->prepare_data = &atmci_prepare_data_dma;atmci_prepare_datahost->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_COMPLETEtasklet_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);elseatmci_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