SD卡软件识别流程

概述

本文章是结合SD的协议手册,来描述SD卡的初始化流程,文章有点臭,建议仔细阅读,定有收获。

初始化框图

下图引用spec中的初始化流程
在这里插入图片描述
在这里插入图片描述

linux kernel代码流程


```c
sd卡命令流程:
cmd0(idle) ---> cmd8(if_cmd) --> cmd55(app_cmd) -->cmd41(acmd41, r3 return ocr) 第一次传入ocr为0,到此结束。
第二次从mmc_sd_init_card()走上面的流程, 然后支持1.8(uhs) --> cmd11(voltage switch) --> cmd2(mmc_sd_get_cid MMC_ALL_SEND_CID get cid) --> cmd3(get rca ralative card address aaaa) --> cmd9(get csd) --> cmd7(MMC_SELECT_CARD _mmc_select_card() select card)--> cmd5 + acmd51(get scr) --> cmd6(mode 0 query card timing capability)


mmc_rescan() --> mmc_rescan_try_freq() (get_cd()成功才会调用,400k --> 100k 4个频率尝试)

mmc_rescan_try_freq() --> mmc_go_idle()(MMC_GO_IDLE_STATE cmd0) --> mmc_send_if_cond()(SD_SEND_IF_COND sd接口测试命令 arg 1aa SD 2.0之后的卡会成功 cmd8)--> mmc_attach_sd() --> mmc_send_app_op_cond(host, 0, &ocr)(发送app cmd, 先发cmd55,再发acmd41, 通过mmc_wait_for_app_cmd()组合

mmc_wait_for_app_cmd()
--> mmc_app_cmd() (MMC_APP_CMD cmd55)
--> mrq.cmd = cmd; cmd.opcode = SD_APP_OP_COND;(acmd41)
--> cmd->data = NULL;
--> mmc_wait_for_req(host, &mrq);

第一次调用mmc_send_app_op_cond()第二个参数ocr为0 (probe), retry 10次,因为ocr为0,retry失效, 直接break*rocr = cmd.resp[0]; 读出来的ocr返回mmc_attach_sd(), 一般是0x00ff8000bit30(ccs), bit24(s18a)无效。

mmc_attach_sd() --> mmc_send_app_op_cond(host, 0, &ocr) --> mmc_select_voltage(host, ocr)(跟host支持的ocr适配之后, ocr变成0x200000, bit21 电压 vdd21 3.3-3.4V)

--> mmc_sd_init_card(host, rocr, NULL)(init card 重新从cmd 0开始)
--> mmc_sd_get_cid(host, ocr, cid, &rocr) //u32 cid[4]; 获取cid, 在该函数中, 先走cmd0 ,cmd8 ,(cmd55 + acmd41)循环直到,ocr r3 respond bit31 为1, 表示card上电初始化成功。
--> mmc_go_idle(host);
--> mmc_send_if_cond(host, ocr); //ocr 为0x200000 bit21 vdd21, 然后cmd8, arg为0x1aa
--> ocr |= SD_OCR_CCS; ocr |= SD_OCR_S18R(cmd 8有响应,则host发送ocr设置bit30, host timing为uhs, 则ocr设置bit24)
--> mmc_send_app_op_cond(host, ocr, rocr); //ocr为0x41200000 (cmd55 + acmd41)循环
--> (*rocr & 0x41000000) == 0x41000000) mmc_set_uhs_voltage(host, pocr);// cmd11, 切换1.8v电压
--> cmd.opcode = SD_SWITCH_VOLTAGE; //cmd11
--> !host->ops->card_busy(host) //dat线非低电平则返回-again, retry。 The card should drive cmd and dat[0:3] low immediately
--> mmc_host_set_uhs_voltage(host) //切换电压, 先关闭时钟, 切换1.8v, 然后等待10ms, 再恢复时钟
--> host->ios.clock = 0; mmc_set_ios(host); mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);host->ios.clock = clock;
--> mmc_send_cid(host, cid); //cmd2 MMC_ALL_SEND_CID

--> card = mmc_alloc_card(host, &sd_type);
--> mmc_send_relative_addr(host, &card->rca); //cmd3, SD_SEND_RELATIVE_ADDR, 获取卡的rca地址, 如aaaa
--> mmc_sd_get_csd(host, card); //cmd9 MMC_SEND_CSD


--> mmc_select_card(); //cmd7 MMC_SELECT_CARD, arg 是card rca地址

--> mmc_sd_setup_card()
--> mmc_app_send_scr() //cmd55 + amcd51 Fetch SCR from card.
--> cmd.opcode = SD_APP_SEND_SCR;data.blksz = 8;data.flags = MMC_DATA_READ;

--> mmc_read_ssr() // cmd55 + acmd13 SD_APP_SD_STATUS

--> mmc_read_switch(card); //cmd6 Fetch switch information from card. 读取支持的sdr速率 timing之类的信息
--> mmc_sd_switch(card, 0, 0, 0, status); //mode 0, 读

Switch Function Status 68/214 512bit 的switch response, 64字节,
card->sw_caps.sd3_bus_mode = status[13]; 每个group 16bits, 2字节, group1 是外卡的 speed mode,
card->sw_caps.sd3_drv_type = status[9]; group3是driver


--> mmc_sd_init_uhs_card()
--> mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); //cmd55 + acmd6 SD_APP_SET_BUS_WIDTH cmd.arg = SD_BUS_WIDTH_4;
--> mmc_set_bus_width(card, MMC_BUS_WIDTH_4) //set host ios

--> sd_update_bus_speed_mode()//根据host的情况caps和card的情况card->sw_caps.sd3_bus_mode 确定bus speed, 也就是最终使用的速率
--> card->sd_bus_speed = UHS_SDR104_BUS_SPEED; UHS_SDR104_BUS_SPEED: 3

--> sd_set_bus_speed_mode() //设置卡速率, timing = MMC_TIMING_UHS_SDR104; MMC_TIMING_UHS_SDR104 6 0-6 host timing
--> card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
--> mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status); //mode 1, 切换卡的速率, starting CMD6 arg 80fffff3 flags 000000b5
--> mmc_set_timing(card->host, timing);
--> mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); //208M
--> if (hz > host->f_max)
--> host->ios.clock = hz;
--> mmc_set_ios(host);

--> mmc_execute_tuning(card)
--> cmd19

--> mmc_add_card(host->card); //在attach card中
--> dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca)
--> pr_info("%s: new %s%s%s%s%s%s card at address %04x\n") //卡识别的打印

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linux顿悟吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值