mmc: error -110 whilst initialising SD card
硬件:RK3562
原理图
解决方案
先直接说解决方案,请检查设备树中是否有设置SDMMC为sdr104模式。
&sdmmc0 {
no-sdio;
no-mmc;
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
disable-wp;
sd-uhs-sdr104;
vmmc-supply = <&vcc_3v3>;
vqmmc-supply = <&vccio_sd>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
status = "okay";
};
vccio_sd: LDO_REG5 {
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-name = "vccio_sd";
regulator-state-mem {
regulator-off-in-suspend;
};
};
如有,请检查SDMMC通信引脚电源域供电是否配置为1.8V-3.3V。SDMMC其vqmmc供电应是1.8V-3.3V。上述vccio_sd是LDO引出的regulator,其给SDMMC0通信引脚供电,设备树中需保证SDMMC0信令电压支持1.8V-3.3V电压。所以设备树中vccio_sd最小电压1.8V,最大电压3.3V。例如下图为固定电压调节器3.3V供电,不支持sdr104模式,所以mmc控制器切换后无法通信。
- 解决方案1
如若硬件暂时无法更改,使用的regulator使固定电压的不支持1.8V。可以尝试注释 上述代码中的sd-uhs-sdr104;,使其运行High Speed模式。如下图所示,High Speed模式使用的3.3V,速度会有一定的损失,但可以保证TF卡正常工作,测试了下对于市面上大多的sd卡速度损失不会太大,因为都跑不满。
这个图可以看到各模式使用的电压及频率
这个图可以对比各模式速度差异
- 解决方案2
在mmc控制器中添加no-1-8-v属性。此方法未尝试。
RK3562的mmc控制器:
&sdhci {
bus-width = <8>;
no-sdio;
no-sd;
non-removable;
max-frequency = <200000000>;
mmc-hs400-1_8v;
no-1-8-v;
mmc-hs400-enhanced-strobe;
full-pwr-cycle-in-suspend;
status = "okay";
};
-
解决方案3
修改设备树中的regulator,设置最小值1.8V,最大值3.3V。参考上面的vccio_sd修改。注意,修改regulator需要注意其是否影响其他引脚供电。所以修改前请先确认哪些电源域使用到该regulator。 -
解决方案4
修改硬件,使SDMMC通信引脚电源域支持1.8v-3.3v。
问题分析概述
表现为识别不了sd卡,并且报错
mmc0: error -110 whilst initialising SD card
使用的sdmmc0(在系统里叫mmc1,设备树定义),先查找一下基地址,好多抓取些日志分析
cd kernel/arch/arm64/boot/dts/rockchip
grep -nr sdmmc0 *3562*
==>rk3562.dtsi:2829: sdmmc0: mmc@ff880000 {
==>rk3562-linux.dtsi:10: mmc1 = &sdmmc0;
可以看到基地址为ff880000,其系统里的别名为mmc1。按这两个名称检索内核日志。
插上TK卡,打开开发板串口终端
dmesg | grep "mmc1\|ff880000"
先贴一份“正常”的日志
[ 4.125830] dwmmc_rockchip ff880000.mmc: No normal pinctrl state
[ 4.125834] dwmmc_rockchip ff880000.mmc: No idle pinctrl state
[ 4.125998] dwmmc_rockchip ff880000.mmc: IDMAC supports 32-bit address mode.
[ 4.126016] dwmmc_rockchip ff880000.mmc: Using internal DMA controller.
[ 4.126023] dwmmc_rockchip ff880000.mmc: Version ID is 270a
[ 4.126059] dwmmc_rockchip ff880000.mmc: DW MMC controller at irq 84,32 bit host data width,256 deep fifo
[ 4.139105] mmc_host mmc1: Bus speed (slot 0) = 400000Hz (slot req 400000Hz, actual 400000HZ div = 0)
[ 4.213397] mmc_host mmc1: Bus speed (slot 0) = 50000000Hz (slot req 50000000Hz, actual 50000000HZ div = 0)
[ 4.213779] mmc1: new high speed SDHC card at address aaaa
[ 4.214238] mmcblk1: mmc1:aaaa SK32G 29.7 GiB
为什么说是“正常”的呢?因为这里可以看到这是high speed SDHC card。我们实际插入的是支持超高速SDR104模式的TF卡。
- 错误日志
dmesg | grep "mmc1\|ff880000"
[ 4.134141] dwmmc_rockchip ff880000.mmc: No normal pinctrl state
[ 4.134160] dwmmc_rockchip ff880000.mmc: No idle pinctrl state
[ 4.134312] dwmmc_rockchip ff880000.mmc: IDMAC supports 32-bit address mode.
[ 4.134325] dwmmc_rockchip ff880000.mmc: Using internal DMA controller.
[ 4.134333] dwmmc_rockchip ff880000.mmc: Version ID is 270a
[ 4.134359] dwmmc_rockchip ff880000.mmc: DW MMC controller at irq 84,32 bit host data width,256 deep fifo
[ 4.146805] mmc_host mmc1: Bus speed (slot 0) = 400000Hz (slot req 400000Hz, actual 400000HZ div = 0)
[ 4.245282] mmc1: error -110 whilst initialising SD card
[ 4.745314] dwmmc_rockchip ff880000.mmc: Busy; trying anyway
[ 5.245354] mmc_host mmc1: Timeout sending command (cmd 0x202000 arg 0x0 status 0x80202000)
[ 5.260065] mmc_host mmc1: Bus speed (slot 0) = 300000Hz (slot req 300000Hz, actual 300000HZ div = 0)
[ 5.783810] dwmmc_rockchip ff880000.mmc: Busy; trying anyway
[ 6.283841] mmc_host mmc1: Timeout sending command (cmd 0x202000 arg 0x0 status 0x80202000)
[ 6.298060] mmc_host mmc1: Bus speed (slot 0) = 200000Hz (slot req 200000Hz, actual 200000HZ div = 0)
[ 6.824140] dwmmc_rockchip ff880000.mmc: Busy; trying anyway
[ 7.324172] mmc_host mmc1: Timeout sending command (cmd 0x202000 arg 0x0 status 0x80202000)
[ 7.337194] mmc_host mmc1: Bus speed (slot 0) = 100000Hz (slot req 100000Hz, actual 100000HZ div = 0)
[ 7.873286] dwmmc_rockchip ff880000.mmc: Busy; trying anyway
[ 8.373317] mmc_host mmc1: Timeout sending command (cmd 0x202000 arg 0x0 status 0x80202000)
- 代码分析
打开opengrok检索错误日志,-110替换成%d。这种检索可适当缩减检索信息。定位到代码在kernel/drivers/mmc/core/sd.c
/*
* Starting point for SD card init.
*/
int mmc_attach_sd(struct mmc_host *host)
{
int err;
u32 ocr, rocr;
WARN_ON(!host->claimed);
// 省略无用代码
/*
* Detect and init the card.
*/
err = mmc_sd_init_card(host, rocr, NULL);
if (err)
goto err;
mmc_claim_host(host);
return 0;
// 省略无用代码
err:
mmc_detach_bus(host);
pr_err("%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);
return err;
}
- 定位报错函数
添加打印信息,定位报错函数,最终看到大概是电压切换的问题。
需要添加很多日志打印,定位到具体函数,复盘问题实在不想再做一遍了。