linux eMMC驱动分析
创始人
2025-05-29 13:05:29
0

目录

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


0.说明

基于A5D36平台eMMC驱动分析,设备和驱动匹配之后调用atmci_probe

1.设备树初始化

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)

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_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

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_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

6.配置DMA

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;}

7.设置一个超时的软定时器

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插槽

//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管脚的变化(即热插拔),启动定时器

9.初始化debugfs文件系统

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);

10.提供给上层的访问数据接口

//以下是数据请求发送流程
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);

11.启动信息

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

12. eMMC获取CSD

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

相关内容

热门资讯

确定了!i茅台App将上线14... 12月30日下午,有媒体报道,自2026年1月开始,贵州茅台(600519)将在旗下官方数字销售平台...
光刻机概念股短线拉升,张江高科... 新京报贝壳财经讯 12月31日,光刻机概念股短线拉升,张江高科盘中涨超9%,新莱应材盘中涨超5%,凯...
创刊不到四年,这份报纸明起休刊... 来源丨新渝报公众号 原标题丨致《新渝报》读者:别纸页,赴山海亲爱的读者,朋友们:当您点开这最后的推...
潮宏基荣获《证券日报》2025... 近日,潮宏基凭借在时尚珠宝领域的持续创新力、稳健的市场表现以及行业引领作用,在《证券日报》社主办的2...
用千问“魔改”老厂,这些企业家... “AI的尽头是算力,但AI的价值尽头是应用。”在2025年的科技人文秀演讲中,著名财经作家吴晓波如此...
年终盘点|低空经济加速跑,开启... 中国商报(记者 雷珂馨 文/图)2025年,低空经济作为战略性新兴产业,展现出强劲的发展势头和巨大的...
昆明市联社又1人被带走,是云南... 云南农信系统2025年第8人被查。据清风云南消息,昆明市农村信用合作社联合社原党委委员、副主任张继明...
协作机器人企业越疆拟回A上市:... “协作机器人第一股”要回A上市。12月30日,据证监会公开发行辅导公示系统显示,“协作机器人第一股”...
44岁育有3娃,高盛出身,“投... 在全球投资圈,不少富二代们都开始接班了。随着一代大佬们谢幕,越来越多二代上位,资本帝国的权力交接悄然...
下一个湘菜?不!江西菜正进化成... 作者 |餐饮老板内参七饭漂亮饭、大排档、山野风,江西菜正进化成“超级物种”当我们以为江西小炒会成为下...