linux eMMC驱动分析

目录

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

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

9.初始化debugfs文件系统

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

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

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

你可能感兴趣的:(eMMC,A5D3,linux,eMMC驱动)