05-emmc的识别模式

、协议流程
1、整体框图
在这里插入图片描述
2、框图描述
从上图可以看出:
(1)设备上电或者设备接收到参数为0的CMD0命令,便会进入idle状态
(2)当设备进入idle状态后,通过CMD1(SEND_OP_COND)命令来判断设备是否处于忙状态,而且可以获取到OCR寄存器的值,即可以获取到emmc支持的电压范围,和控制进行比较,判断是否有匹配的电压
在这里插入图片描述
CMD1需要重复发送直到返回不忙状态,设备进入ready状态
(3)进入ready状态后,发送广播命令CMD2(ALL_SEND_CID),该命令请求所有设备发送其唯一设备标识(CID)号,所有
未识别的(即处于Ready状态的)设备同时开始串行地发送其CID号,成功后设备进入Identification状态
在这里插入图片描述
(4)主机发送CMD3(SET_RELATIVE_ADDR),给改设备一个相对设备地址(RCA),该地址用于数据传输模式,设备一旦接收到RCA,设备就变为Stand-by状态。设备将其输出驱动器从开漏切换到推拉模式。
RCA寄存器模式是0x0001

二、裸驱配置流程
1、SRS11.SRFA ( Software Reset For All) 复位整个芯片,循环等待该bit为0,为0代表复位成功
2、SRS10.BP=1 SRS10.BVS=101(1.8V)
3、SRS13 使能或者SRS14关闭各种中断
4、phy初始化
5、SRS10.EDTW=0 SRS10.DTW=0 配置位宽为1bit
6、SRS11.SDCFSL=(200M/400KHz)配置clk为400Hz
7、开始发送CMD0,延时2ms
8、发送CMD1,根据应答判断OCR的bit31是否busy,1代表空闲,0代表忙,如果忙,再次发送,连续尝试3次
9、发送CMD2,根据应答获取到CID
10、发送CMD3,分配一个rca值,根据应答获取到rca

三、linux的流程

drivers/mmc/host/sdhci-xxxx.c
sdhci_add_host
	__sdhci_add_host
		host->complete_wq = alloc_workqueue("sdhci", flags, 0); 
		timer_setup(&host->timer, sdhci_timeout_timer, 0);
		timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
		sdhci_init(host, 0);
			sdhci_do_reset(host, SDHCI_RESET_ALL);
			sdhci_set_default_irqs(host);
		ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,IRQF_SHARED,>mmc_hostname(mmc), host);
		ret = mmc_add_host(mmc);
			err = device_add(&host->class_dev);
			mmc_start_host(host);
				mmc_gpiod_request_cd_irq(host)
				_mmc_detect_change(host, 0, false);
					host->detect_change = 1;
					mmc_schedule_delayed_work(&host->detect, delay); // 触发mmc_rescan
driver/mmc/core/core.c
subsys_initcall(mmc_init);
	__init mmc_init(void) 
		ret = mmc_register_bus();
			bus_register(&mmc_bus_type);
		ret = mmc_register_host_class();
			class_register(&mmc_host_class);
		ret = sdio_register_bus(); 
			bus_register(&sdio_bus_type); 
			
drivers/mmc/core/host.c
drivers/mmc/host/mmci.c
module_amba_driver(mmci_driver);
#define module_amba_driver(__amba_drv) \
	module_driver(__amba_drv, amba_driver_register, amba_driver_unregister) 

static struct amba_driver mmci_driver = {
	...
	.probe	= mmci_probe,
	...
}

static struct mmc_host_ops mmci_ops = {
	.request	= mmci_request,
	.pre_req	= mmci_pre_request,
	.post_req	= mmci_post_request,
	.set_ios	= mmci_set_ios,
	.get_ro		= mmc_gpio_get_ro,
	.get_cd		= mmci_get_cd,
	.start_signal_voltage_switch = mmci_sig_volt_switch,
};


mmci_probe
	mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
	ret = mmci_of_parse(np, mmc);  
		alias_id = of_alias_get_id(dev->of_node, "mmc");
		dev_set_name(&host->class_dev, "mmc%d", host->index); 
		INIT_DELAYED_WORK(&host->detect, mmc_rescan);
		INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work);
		timer_setup(&host->retune_timer, mmc_retune_timer, 0);
	host->mmc_ops = &mmci_ops;
	mmc->ops = &mmci_ops;
	host->clk = devm_clk_get(&dev->dev, NULL);
	ret = clk_prepare_enable(host->clk);
	host->mclk = clk_get_rate(host->clk)
	host->base = devm_ioremap_resource(&dev->dev, &dev->res);
	host->rst = devm_reset_control_get_optional_exclusive(&dev->dev, NULL);
	ret = mmc_regulator_get_supply(mmc);
	ret = devm_request_threaded_irq(&dev->dev, dev->irq[0], mmci_irq,mmci_irq_thread, IRQF_SHARED,DRIVER_NAME " (cmd)", host);
	mmci_dma_setup(host);
	mmc_add_host(mmc); 
mmc_rescan // 在sdhci_add_host中被触发
	if (!mmc_card_is_removable(host) && host->rescan_entered) return
	if (mmc_card_is_removable(host) && host->ops->get_cd &&  host->ops->get_cd(host) == 0) {
		mmc_power_off(host);
		mmc_release_host(host); 
	}
	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
		unsigned int freq = freqs[i];
		if (freq > host->f_max) {
			if (i + 1 < ARRAY_SIZE(freqs))
				continue;
			freq = host->f_max;
		}
		if (!mmc_rescan_try_freq(host, max(freq, host->f_min)))
			break;
		if (freqs[i] <= host->f_min)
			break;
	}
	mmc_release_host(host);
	if (!(host->caps2 & MMC_CAP2_NO_SD)) 
		mmc_send_if_cond(host, host->ocr_avail);
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
	host->f_init = freq;
	mmc_power_up(host, host->ocr_avail);
		mmc_pwrseq_pre_power_on(host); 
		mmc_delay(host->ios.power_delay_ms);
		mmc_pwrseq_post_power_on(host);
		host->ios.power_mode = MMC_POWER_ON;
			mmc_set_ios(host);
		mmc_delay(host->ios.power_delay_ms); // This delay must be at least 74 clock sizes, or 1 ms,
	mmc_hw_reset_for_init(host);
		mmc_pwrseq_reset(host);
	if (!(host->caps2 & MMC_CAP2_NO_SDIO))
		sdio_reset(host);

	mmc_go_idle(host);
		cmd.opcode = MMC_GO_IDLE_STATE;
		cmd.arg = 0
		err = mmc_wait_for_cmd(host, &cmd, 0)

	if (!(host->caps2 & MMC_CAP2_NO_SD))
		mmc_send_if_cond(host, host->ocr_avail);
			cmd.opcode = SD_SEND_IF_COND; 
			cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
			err = mmc_wait_for_cmd(host, &cmd, 0);
			result_pattern = cmd.resp[0] & 0xFF;

	/* Order's important: probe SDIO, then SD, then MMC */
	if (!(host->caps2 & MMC_CAP2_NO_SDIO))
		if (!mmc_attach_sdio(host))
			return 0;

	if (!(host->caps2 & MMC_CAP2_NO_SD))
		if (!mmc_attach_sd(host))
			return 0;

	if (!(host->caps2 & MMC_CAP2_NO_MMC))
		if (!mmc_attach_mmc(host)) // 见下
			return 0;
	mmc_power_off(host);
	return -EIO;
}
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,
	.alive = mmc_alive,
	.shutdown = mmc_shutdown,
	.hw_reset = _mmc_hw_reset,
};

mmc_attach_mmc
	mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); 
		host->ios.bus_mode = mode;
		mmc_set_ios(host);
	err = mmc_send_op_cond(host, 0, &ocr);
		cmd.opcode = MMC_SEND_OP_COND;
		cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; 
		for (i = 100; i; i--) {
			err = mmc_wait_for_cmd(host, &cmd, 0); 
			if (cmd.resp[0] & MMC_CARD_BUSY)
				break; 
			mmc_delay(10); // ms
			cmd.arg = cmd.resp[0] | BIT(30);
		}
		*rocr = cmd.resp[0];
	mmc_attach_bus(host, &mmc_ops);
		host->bus_ops = ops;
	rocr = mmc_select_voltage(host, ocr);
	err = mmc_init_card(host, rocr, NULL); 
		mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); 
		mmc_go_idle(host);
		err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
		err = mmc_send_cid(host, cid);
		card = mmc_alloc_card(host, &mmc_type);
		card->ocr = ocr;
		card->type = MMC_TYPE_MMC;
		card->rca = 1; 
		memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); 
		err = mmc_set_relative_addr(card);
			cmd.opcode = MMC_SET_RELATIVE_ADDR;
			cmd.arg = card->rca << 16; 
			mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES)
		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
		err = mmc_send_csd(card, card->raw_csd);
			mmc_send_cxd_native(card->host, card->rca << 16,>csd,MMC_SEND_CSD);
		err = mmc_decode_csd(card);
		err = mmc_decode_cid(card); 
		
		err = mmc_select_card(card);
			_mmc_select_card(card->host, card);
				cmd.opcode = MMC_SELECT_CARD;
				cmd.arg = card->rca << 16; 
				mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
		err = mmc_read_ext_csd(card);
		
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_ERASE_GROUP_DEF, 1,
						card->ext_csd.generic_cmd6_time); 
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,	
						card->ext_csd.part_config, 
						card->ext_csd.part_time);

		err = mmc_select_timing(card);
			if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
				err = mmc_select_hs400es(card);
					err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)
					err = mmc_select_bus_width(card); 
					err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
									EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
									card->ext_csd.generic_cmd6_time, 0,
									false, true); 
					mmc_set_timing(host, MMC_TIMING_MMC_HS);
					err = mmc_switch_status(card, true);
					mmc_set_clock(host, card->ext_csd.hs_max_dtr);
					val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
					err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
									EXT_CSD_BUS_WIDTH,
									val,
									card->ext_csd.generic_cmd6_time);
					mmc_select_driver_type(card);
					val = EXT_CSD_TIMING_HS400 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
					err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 
									EXT_CSD_HS_TIMING, val,
									card->ext_csd.generic_cmd6_time, 0, 
									false, true);
					mmc_set_timing(host, MMC_TIMING_MMC_HS400);
					err = mmc_switch_status(card, true);
			else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
				err = mmc_select_hs200(card);
					mmc_select_driver_type(card);
					err = mmc_select_bus_width(card);
					val = EXT_CSD_TIMING_HS200 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
					err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
									EXT_CSD_HS_TIMING, val,
									card->ext_csd.generic_cmd6_time, 0,
									false, true);
					mmc_set_timing(host, MMC_TIMING_MMC_HS200);
					err = mmc_switch_status(card, false);
			else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
				err = mmc_select_hs(card);
					err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
									EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
									card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS,
									true, true); 
						
		
			if (mmc_card_hs200(card)) {  // card->host->ios.timing == MMC_TIMING_MMC_HS200;
				err = mmc_hs200_tuning(card);
					err = host->ops->execute_tuning(host, opcode);
				err = mmc_select_hs400(card);
			} else if (!mmc_card_hs400es(card)) {  // card->host->ios.enhanced_strobe;
				err = mmc_select_bus_width(card); 
				if (err > 0 && mmc_card_hs(card)) { // card->host->ios.timing == MMC_TIMING_SD_HS || card->host->ios.timing == MMC_TIMING_MMC_HS;
					err = mmc_select_hs_ddr(card);
						bus_width = host->ios.bus_width;
						ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
						err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 
									EXT_CSD_BUS_WIDTH,
									ext_csd_bits,
									card->ext_csd.generic_cmd6_time,
									MMC_TIMING_MMC_DDR52,
									true, true);
						err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
	
			}
			if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) { 
				err = mmc_cmdq_enable(card);
					mmc_cmdq_switch(card, true);
			}
			
		
	mmc_release_host(host);
	err = mmc_add_card(host->card);
	mmc_claim_host(host);
	
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值