Rockchip · AI & Linux Hub

存储与网络

Rockchip SDMMC、SDIO 与 eMMC:DTS、模式切换和兼容性排查完整指南

完整保留 V1.4.0 的存储接口配置、动态调频、52 项 mmc_test 测试、供电波形分析与 JTAG/漏电排查。

· ArmSoM Editorial · Rockchip source documentation · 23 分钟阅读

本文为 ArmSoM 适配的平台参考,不代表全部板卡均支持。来源为 Rockchip_Developer_Guide_SDMMC_SDIO_eMMC_CN.pdf(22 页)和对应英文 PDF(25 页),均为 V1.4.0、RK-KF-YF-121。中文遵循中文原稿,英文遵循英文原稿,俄文和德文完整译自英文,局部差异明确注明。中文使用中文原图,其他三语使用英文 PDF 原图;英文 PDF 的示波器图仍含中文标注,原图未伪装成英文图。请核对具体 ArmSoM 板卡、SoC、SDK/BSP、内核、DTS、IO 电压、存储器及 WiFi 模组接线。未做硬件验证,日志、频率和波形均为原文示例,不是 ArmSoM 实测。

安全提示:本文保留修改设备状态、解绑驱动、写入/擦除测试、格式化和 fsck 修复等原文操作。它们可能破坏数据;只能在备份完毕、明确识别的专用测试卡上评估,勿在系统盘或生产设备上直接执行。整理期间未执行任何这些操作。

芯片名称 内核版本
全系列(原文范围,不是 ArmSoM 全系列支持声明) 4.4, 4.19, 5.10, 6.1

ArmSoM Docs · Rockchip Linux · EDITORIAL-NOTES

1. DTS 配置

1.1 SDMMC 的 DTS 配置说明

(1) max-frequency = <150000000>;

此配置设置 SD 卡的运行频率,虽然设置为 150MHz,但是还要根据 SD 卡的不同模式进行调整。这部分不需要用戶关心,实际运行频率和模块的关系软件会关联。最大不超过 150MHz。

(2) supports-sd;

此配置标识此插槽为 SD 卡功能,为必须添加项。否则无法初始化 SD 卡。注意4.19内核之后不再使用此配置,改为 no-sdio 与 no-mmc 的组合来表明此卡槽不支持SDIO和MMC,专用为SD功能;

(3) bus-width = <4>;

此配置标识需要使用 SD 卡的线宽。SD 卡最大支持 4 线模式,如果不配置就模式使用 1 线模式。另外,这个位只支持的数值为 1,4,配置其他数值会认为是非法数值,强制按照 1 线模式进行使用。

(4) cap-mmc-highspeed; cap-sd-highspeed;

此配置为标识此卡槽支持 highspeed 的 SD 卡。 如果不配置,表示不支持 highspeed 的 SD 卡。

(5) 配置使用 SD3.0

首先确保芯片支持 SD3.0 模式,并且需要配置 vqmmc 这一路的 SDMMC 控制器的 IO 电源,并添加如下一些 SD3.0 的速度模式

模式 频率上限(原值) 说明
sd-uhs-sdr12 24M  
sd-uhs-sdr25 50M  
sd-uhs-sdr50 100M  
sd-uhs-ddr50 50M 双沿采样
sd-uhs-sdr104 208M  

(6) 配置 SD 卡设备的 3V3 电源

如果硬件上使用的电源控制引脚是芯片上 SDMMC 控制器默认的电源控制脚:sdmmc_pwren,那么只需要在 pinctrl 上配置为 sdmmc_pwren 的功能脚,并在 sdmmc 节点内引入到 default 的 pinctrl 内即可,例如以 RK312X 为例:

sdmmc_pwren: sdmmc-pwren {
    rockchip,pins = <1 RK_PB6 1 &pcfg_pull_default>;
};
pinctrl-0 = <&sdmmc_pwr &sdmmc_clk &sdmmc_cmd &sdmmc_bus4>;

如果硬件是使用其他 GPIO 作为 SD 卡设备的 3V3 电源控制引脚,则需要将其定义成 regulator 来使用,并在 sdmmc 的节点内将其引用到 vmmc-supply 内,例如:

sdmmc_pwr: sdmmc-pwr {
    rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
};
vcc_sd: sdmmc-regulator {
    compatible = "regulator-fixed";
    gpio = <&gpio7 11 GPIO_ACTIVE_LOW>;
    pinctrl-names = "default";
    pinctrl-0 = <&sdmmc_pwr>;
    regulator-name = "vcc_sd";
    regulator-min-microvolt = <3300000>;
    regulator-max-microvolt = <3300000>;
    startup-delay-us = <100000>;
    vin-supply = <&vcc_io>;
};
&sdmmc {
    vmmc-supply = <&vcc_sd>;
};

(7) 配置 SD 卡热拔插检测脚

如果检测脚是直接连接到芯片的 SDMMC 控制器的 sdmmc_cd 脚,则请直接将该脚位配置为功能脚,并在 sdmmc 节点的 default 的 pinctrl 内进行引用即可。

如果检测脚是使用其他 GPIO,则需要在 sdmmc 节点内使用 cd-gpios 来进配置,例如

cd-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>;

如果使用 GPIO 的检测脚,但是又要求反向检测方式(即 SD 卡插入时检测脚为高电平),则需要追加

cd-inverted;

1.2 SDIO 的 DTS 配置说明

(1) max-frequency = <150000000>;

此项同 SD 卡的配置,最大运行频率不超过 150Mhz; 如果接入的是SDIO2.0设备,则自动向下兼容为最大 50MHz,如果接入的是SDIO3.0设备则最大支持 150MHz;

(2) supports-SDIO;

此配置标识此插槽为 SDIO 功能,为必须添加项。否则无法初始化 SDIO 外设。注意4.19内核之后不再使用此配置,改为 no-sd 与 no-mmc 的组合来表明此卡槽不支持SDMMC和MMC,专用为SDIO功能;

(3) bus-width = <4>;

此配置同 SD 卡功能。

(4) cap-sd-highspeed;

此配置同 SD 卡功能,作为 SDIO 外设,也有区分是否为 highspeed 的 SDIO 外设。

(5) cap-sdio-irq;

此配置标识该 SDIO 外设(通常是 Wifi)是否支持 sdio 中断,如果你的外设是 OOB 中断,

请不要加入此项。支持哪种类型的中断请联系 Wifi 原厂确定。

(6) keep-power-in-suspend;

此配置表示是否支持睡眠不断电,请默认加入该选项。Wifi 一般都有深度唤醒的要求。

中英差异:英文 PDF 第 7 页写成 sleep power-off,与此处中文“睡眠不断电”相反;需结合实际 BSP 核对。

(7) mmc-pwrseq = <&sdio_pwrseq>;

此项是 SDIO 外设(一般是 Wifi)的电源控制。为必须项,否则 Wifi 无法上电工作。请参考下面的例子,晶振时钟和复位-使能的 GPIO 的选择按照实际板级硬件要求进行配置。

sdio_pwrseq:sdio-pwrseq {
        compatible ="mmc-pwrseq-simple";
        clocks = <&rk808 1>;
        clock-names ="ext_clock";
        pinctrl-names ="default";
        pinctrl-0 =<&wifi_enable_h>;
        /*
        * On the module itself this isone of these (depending
        * on the actual cardpopulated):
        * - SDIO_RESET_L_WL_REG_ON
        * - PDN (power down when low)
        */
        reset-gpios = <&gpio0 10GPIO_ACTIVE_LOW>; /* GPIO0_B2 */
};

(8) non-removable;

此项表示该插槽为不可移动设备且此项为 SDIO 设备必须添加项。

(9) num-slots = <4>;

此项同 SD 卡的配置。

(10) sd-uhs-sdr104;

此项配置决定该 SDIO 设备是否支持 SDIO3.0 模式。前提是需要 Wifi 的 IO 电压为 1.8v。

1.3 eMMC 的 DTS 配置

(1) max-frequency = <150000000>;

此项同 SD 卡的配置,最大运行频率不超过 150Mhz; 若运行在eMMC Highspeed模式则自动向下兼容到50MHz,若运行在eMMC HS200模式最大支持到150MHz。

(2) supports-emmc;

此配置标识此插槽为 emmc 功能,为必须添加项。否则无法初始化 emmc 外设。注意4.19内核之后不再使用此配置,改为 no-sd 与 no-sdio 的组合来表明此卡槽不支持SDMMC和SDIO,专用为eMMC功能;

(3) bus-width = <4>;

此配置同 SD 卡功能。

(4) mmc-ddr-1_8v;

此配置表示支持 50MDDR 模式;

(5) mmc-hs200-1_8v;

此配置表示支持 HS200 模式;

(6) mmc-hs400-1_8v; mmc-hs400-enhanced-strobe

此两项配置表示支持 HS400 模式以及 HS400ES 模式,具体芯片支持情况请查阅芯片规格书。

(7) non-removable;

此项表示该插槽为不可移动设备。 此项为必须添加项。

2. 频率和模式切换

(1) 模式切换可以使用上述DTS配置中相关项来实现。

(2) 如果希望在不修改固件的情况下,则可以使用动态切换方式。

原文说明:内核 6.1 默认包含下列提交,其他平台需要移植。

commit 0c11160a3c03bcf41fd1217d5e44e68ff078c54b
Author: Shawn Lin <shawn.lin@rock-chips.com>
Date: Tue Nov 5 18:05:50 2024 +0800
    mmc: debugfs: Allow more host caps to be moodified
    Change-Id: I2d5df7bc95eaa4a380b5107364aff8df3a759788
commit 478cdcd25cba8be5cfcf56b503b0e070f5aef245
Author: Vincent Whitchurch <vincent.whitchurch@axis.com>
Date: Fri Sep 29 09:45:09 2023 +0200
    UPSTREAM: mmc: debugfs: Allow host caps to be modified
    Change-Id: I6ea2fc093234785e05d05128556c60ef42da02a4
commit a5a3ea5e45d09cff84c04b515b5b71d4dd76524e
Author: Vincent Whitchurch <vincent.whitchurch@axis.com>
Date: Fri Sep 29 09:45:08 2023 +0200
    UPSTREAM: mmc: core: Always reselect card type
    Change-Id: Ie80514ade3b267901818f477d74d91cf7c13e103

2.1 SD/SDIO动态切换

(1) DTS按照所支持的最大速率模式配置 。从log识别所需修改的MMC设备ID和地址,以某张tf卡为例

[ 5.739929] mmc_host mmc1: Bus speed (slot 0) = 400000Hz (slot req 400000Hz, actual 400000HZ div = 0)
[ 5.941037] mmc_host mmc1: Bus speed (slot 0) = 198000000Hz (slot req 200000000Hz, actual 198000000HZ div = 0)
[ 5.941682] dwmmc_rockchip 2a310000.mmc: Successfully tuned phase to 90
[ 5.941705] mmc1: new ultra high speed SDR104 SDHC card at address aaaa
[ 5.943229] mmcblk1: mmc1:aaaa SC32G 29.7 GiB

我们可以得到三个信息

MMC设备ID为1, 即mmc1

tf卡的地址为aaaa,路径组合即为mmc1:aaaa

目前运行模式是sdr104模式,频率198MHz

(2) 因为此设备是mmc1,所以执行 cd /sys/kernel/debug/mmc1 进入对应目录。如果是mmc0则进入mmc0目录,以此类推。

(3) 如果希望在当前模式下,仅仅切换频率为100MHz,则使用 echo 100000000 > clock 命令,以此类推。

root@rk3576-buildroot:/sys/kernel/debug/mmc1# echo 100000000 > clock
[ 86.451685] mmc_host mmc1: Bus speed (slot 0) = 100000000Hz (slot req 100000000Hz, actual 100000000HZ div = 0)

(4) 切换成High speed模式,默认50MHz

#在sys/kernel/debug/mmc1目录依次执行下面命令:
echo $(($(cat caps) | (1 << 7))) > caps
echo on > /sys/bus/mmc/devices/mmc1\:aaaa/power/control
echo auto > /sys/bus/mmc/devices/mmc1\:aaaa/power/control
echo $(($(cat caps) & ~(1 << 19))) > caps
echo on > /sys/bus/mmc/devices/mmc1\:aaaa/power/control
#可以看到切换了
[ 78.304578] mmc_host mmc1: Bus speed (slot 0) = 400000Hz (slot req 400000Hz, actual 400000HZ div = 0)
[ 78.501126] mmc_host mmc1: Bus speed (slot 0) = 50000000Hz (slot req 50000000Hz, actual 50000000HZ div = 0)
#执行下面命令,确认切换成功了
grep timing ios
timing spec: 2 (sd high-speed) #High speed模式了

(5) 切换成Default speed模式,默认25MHz

#在sys/kernel/debug/mmc1目录依次执行下面命令:
echo $(($(cat caps) | (1 << 7))) > caps
echo on > /sys/bus/mmc/devices/mmc1\:aaaa/power/control
echo auto > /sys/bus/mmc/devices/mmc1\:aaaa/power/control
echo $(($(cat caps) & ~(1 << 2))) > caps
echo on > /sys/bus/mmc/devices/mmc1\:aaaa/power/control
#可以看到切换了
[ 287.590885] mmc_host mmc1: Bus speed (slot 0) = 400000Hz (slot req 400000Hz, actual 400000HZ div = 0)
[ 287.784531] mmc_host mmc1: Bus speed (slot 0) = 25000000Hz (slot req 25000000Hz, actual 25000000HZ div = 0)
#执行下面命令,确认切换成功了
grep timing ios
timing spec: 0 (legacy) #Defalt speed模式了

2.2 eMMC动态切换

(1) DTS按照所支持的最大速率模式配置。从log识别所需修改的MMC设备ID和地址,以RK3588eMMC为例

[ 2.260445] mmc0: Command Queue Engine enabled
[ 2.260458] mmc0: new HS400 Enhanced strobe MMC card at address 0001
[ 2.260740] mmcblk0: mmc0:0001 BJTD4R 29.1 GiB

我们可以得到三个信息

MMC设备ID为0, 即mmc0

eMMC设备的地址为0001,路径组合即为mmc0:0001

目前运行模式是HS400模式,平台eMMC默认频率198MHz

(2) 因为此设备是mmc0,所以执行 cd /sys/kernel/debug/mmc0 进入对应目录。如果是mmc1则进入mmc1目录,以此类推。

(3) 如果希望在当前模式下,仅仅切换频率,则使用 echo 100000000 > clock 命令,以此类推。

#先确认默认频率和模式
root@rk3588-buildroot:/sys/kernel/debug/mmc0# grep clock ios
clock: 200000000 Hz actual clock: 198000000 Hz #默认198MHz
root@rk3588-buildroot:/sys/kernel/debug/mmc0# grep timing ios
timing spec: 10 (mmc HS400 enhanced strobe) #HS400es模式
#开始切换频率
root@rk3588-buildroot:/sys/kernel/debug/mmc0# echo 100000000 > clock
root@rk3588-buildroot:/sys/kernel/debug/mmc0# grep clock ios
clock: 100000000 Hz actual clock: 100000000 Hz #切换成100MHz了
root@rk3588-buildroot:/sys/kernel/debug/mmc0# grep timing ios
timing spec: 10 (mmc HS400 enhanced strobe) #仍然HS400es模式

(4) 切换成HS200模式,默认198MHz

#在sys/kernel/debug/mmc0目录依次执行下面命令:
echo $(($(cat caps) | (1 << 7))) > caps
echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control
echo auto > /sys/bus/mmc/devices/mmc0\:0001/power/control
echo $(($(cat caps2) & ~(1 << 15))) > caps2
echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control
#执行下面命令,确认切换成功了
grep timing ios
timing spec: 9 (mmc HS200) #HS200模式了

(5) 切换成High speed模式,默认50MHz

#在sys/kernel/debug/mmc0目录依次执行下面命令:
echo $(($(cat caps) | (1 << 7))) > caps
echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control
echo auto > /sys/bus/mmc/devices/mmc0\:0001/power/control
echo $(($(cat caps) & ~(1 << 1))) > caps
echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control
#执行下面命令,确认切换成功了
grep timing ios
timing spec: 1 (mmc high-speed) #High speed模式了

2.3 其他说明

除了频率和模式切换,目前还支持线宽切换(多线宽向下切换可能带来模式的自动降级)、CMD23支持开关、CQE和DCMD开关,以mmc0:0001设备为例:

#在sys/kernel/debug/mmc0目录依次执行下面命令:
echo $(($(cat caps) | (1 << 7))) > caps
echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control
echo auto > /sys/bus/mmc/devices/mmc0\:0001/power/control
#下面的切换配置按需选择
echo $(($(cat caps) & ~(1 << 6))) > caps #去除8bit支持
echo $(($(cat caps) | (1 << 6))) > caps #添加8bit支持
echo $(($(cat caps) & ~(1 << 0))) > caps #去除4bit支持
echo $(($(cat caps) | (1 << 0))) > caps #添加4bit支持
echo $(($(cat caps) & ~(1 << 30))) > caps #去除cmd23支持
echo $(($(cat caps) | (1 << 30))) > caps #添加cmd23支持
echo $(($(cat caps) & ~(1 << 30))) > caps #去除cmd23支持
echo $(($(cat caps) | (1 << 30))) > caps #添加cmd23支持
echo $(($(cat caps2) & ~(1 << 23))) > caps2 #去除cqe支持
echo $(($(cat caps2) | (1 << 23))) > caps2 #添加cqe支持
echo $(($(cat caps2) & ~(1 << 24))) > caps2 #去除cqe dcmd支持
echo $(($(cat caps2) | (1 << 24))) > caps2 #添加cqe dcmd支持
#再执行这句
echo on > /sys/bus/mmc/devices/mmc0\:0001/power/control
#确认ios信息,查看输出结果
cat ios

以上这些caps和caps2支持的bit信息可查询内核include/linux/mmc/host.h文件。目前支持的caps和caps2为:

caps caps2
MMC_CAP_AGGRESSIVE_PM MMC_CAP2_HS400_1_8V
MMC_CAP_SD_HIGHSPEED MMC_CAP2_HS400_1_2V
MMC_CAP_MMC_HIGHSPEED MMC_CAP2_HS400_ES
MMC_CAP_UHS MMC_CAP2_HS200_1_8V_SDR
MMC_CAP_DDR MMC_CAP2_HS200_1_2V_SDR
MMC_CAP_4_BIT_DATA MMC_CAP2_CQE
MMC_CAP_8_BIT_DATA MMC_CAP2_CQE_DCMD
MMC_CAP_CMD23  

如果项目这些还有额外需要支持的配置,可以模仿前述 commit0c11160a3c03bcf41fd1217d5e44e68ff078c54b 提交自行追加。

3. mmc_test兼容性测试

推荐依赖SD卡的产品导入SD卡专项兼容性测试中。

3.1 内核配置确认

确认启用 CONFIG_MMC_TEST=y:

Device Drivers --->
   <*> MMC/SD/SDIO card support --->
   [*] MMC host test driver

若配置为模块,请在开机后执行 insmod mmc_test.ko。

3.2 使用方法

(1) 列出全部 mmc 设备。

ls /sys/bus/mmc/devices/

(2) 确定测试设备,例如从日志确认 SD 卡的路径组合。

mmc1:aaaa

(3) 将 SD 卡从 mmcblk 驱动解绑。

echo 'mmc1:aaaa' > /sys/bus/mmc/drivers/mmcblk/unbind

(4) 将 SD 卡绑定到 mmc_test。

echo 'mmc1:aaaa' > /sys/bus/mmc/drivers/mmc_test/bind

(5) 此时应看到以下日志。

mmc_test mmc1:aaaa: Card claimed for testing.

(6) 查看可用测试项目。

cat /sys/kernel/debug/mmc1/mmc1:aaaa/testlist

(7) 按需要选择测试编号 N;含义见下方完整测试表。

echo N > /sys/kernel/debug/mmc1/mmc1:aaaa/test

3.3 输出结果

输出 含义
mmc1: Result: OK 测试完成
mmc1: Result: FAILED 测试失败
mmc1: Result: UNSUPPORTED (by host) 控制器配置不支持
mmc1: Result: UNSUPPORTED (by card) 卡不支持

3.4 测试说明

原始英文测试名称保持不变,便于与 testlist 输出逐项对照。

N 原始测试名称 说明
0 Run all tests 运行所有的测试
1 Basic write (no data verification) 写测试,不校验数据
2 Basic read (no data verification) 读测试,不校验数据
3 Basic write (with data verification) 写测试,校验数据
4 Basic read (with data verification) 读测试,校验数据
5 Multi-block write 多块写
6 Multi-block read 多块读
7 Power of two block writes 偶次方块写入
8 Power of two block reads 偶次发块读出
9 Weird sized block writes 各种奇怪的块数写入
10 Weird sized block reads 各种奇怪的块数读出
11 Badly aligned write 不对⻬地址单块写入
12 Badly aligned read 不对⻬地址单块读出
13 Badly aligned multi-block write 不对⻬地址多块写入
14 Badly aligned multi-block read 不对⻬地址多块读出
15 Proper xfer_size at write (start failure) 故意创造一个错误的传输类型,比如用单 块传输命令来执行一个多块写入
16 Proper xfer_size at read (start failure) 故意创造一个错误的传输类型,比如用单 块传输命令来执行一个多块读出
17 Proper xfer_size at write (midway failure) 与15相同,只是在多块传输中插入写错误
18 Proper xfer_size at read (midway failure) 与16相同,只是在多块传输中插入读错误
19 Highmem write 用High memory page来执行单块写数据
20 Highmem read 用High memory page来执行单块读数据
21 Multi-block highmem write 用High memory page来执行多块写数据
22 Multi-block highmem read 用High memory page来执行多块读数据
23 Best-case read performance 执行512K顺序读,地址连续,不启用sg 方式
24 Best-case write performance 执行512K顺序写,地址连续,不启用sg 方式

原始英文测试名称保持不变,便于与 testlist 输出逐项对照。

N 原始测试名称 说明
25 Best-case read performance into scattered pages 执行512K顺序读,启用sg方式
26 Best-case write performance from scattered pages 执行512K顺序读,启用sg方式(保留中文原文;英文第16页为写,名称也为write。)
27 Single read performance by transfer size 单块读性能
28 Single write performance by transfer size 单块写性能
29 Single trim performance by transfer size 单块擦除性能
30 Consecutive read performance by transfer size 持续读性能
31 Consecutive write performance by transfer size 持续写性能
32 Consecutive trim performance by transfer size 持续擦除性能
33 Random read performance by transfer size 随机读性能
34 Random write performance by transfer size 随机写性能
35 Large sequential read into scattered pages 用sg方式的大量连续读测试
36 Large sequential write from scattered pages 用sg方式的大量连续写测试
37 Write performance with blocking req 4k to 4MB 测试4K到4MB下不同传输⻓度的阻塞写 性能
38 Write performance with non-blocking req 4k to 4MB 测试4K到4MB下不同传输⻓度的非阻塞 写性能
39 Read performance with blocking req 4k to 4MB 测试4K到4MB下不同传输⻓度的阻塞读 性能
40 Read performance with non-blocking req 4k to 4MB 测试4K到4MB下不同传输⻓度的非阻塞 读性能
41 Write performance blocking req 1 to 512 sg elems 测试1到512个sg下的阻塞写性能
42 Write performance non-blocking req 1 to 512 sg elems 测试1到512个sg下的非阻塞写性能
43 Read performance blocking req 1 to 512 sg elems 测试1到512个sg下的阻塞读性能

原始英文测试名称保持不变,便于与 testlist 输出逐项对照。

N 原始测试名称 说明
44 Read performance non-blocking req 1 to 512 sg elems 测试1到512个sg下的非阻塞写性能(保留中文原文;英文第17页为读,名称也为read。)
45 Reset test 重置测试项
46 Commands during read - no Set Block Count (CMD23) 读过程中发送各种命令(非CMD23方式)
47 Commands during write - no Set Block Count (CMD23) 写过程中发送各种命令(非CMD23方式)
48 Commands during read - use Set Block Count (CMD23) 读过程中发送各种命令(CMD23方式)
49 Commands during write - use Set Block Count (CMD23) 写过程中发送各种命令(CMD23方式)
50 Commands during non-blocking read - use Set Block Count (CMD23) 非阻塞读过程中发送各种命令(CMD23方 式)
51 Commands during non-blocking write - use Set Block Count (CMD23) 非阻塞写过程中发送各种命令(CMD23方 式)

4. 常⻅问题排查

4.1 硬件问题分析

(1) SD 卡

SD 卡布线与检测脚原图

SD 卡布线与检测脚原图 — 原图来源: CN PDF p.15.

从左到右依次是:

DET —- 检测脚

DATA1 —- 数据线

DATA0

GND

CLK —- 时钟

VCC_SD —- SD 卡供电电源

VCCIO_SD —- 数据线的 IO 供电电源

CMD —- 命令线

DATA3

DATA2

除了 DET/CLK/GND 外,其它的 DATA0-3/VCC_SD/VCCIO_SD/CMD 必须都为 3.3v 左右,最小不能低于3v;DET 脚插入为低,拔出为高; DATA0-3/CMD 的电压都是 VCCIO_SD 供给的,所以 DATA0-3/CMD必须跟 VCCIO_SD 保持一致,而 VCC_SD 和 VCCIO_SD 要保持一致(NOTE: SD 3.0,要求 VCCIO_SD 为1.8v);

如果 VCC_SD/VCCIO_SD 的电源是⻓供电,那么请保证 VCC_SD 和 VCCIO_SD 在卡拔插时不会有塌陷;

(2) SDIO

SDIO 数据及命令线电路原图

SDIO 数据及命令线电路原图 — 原图来源: CN PDF p.16.

WiFi IO 电源和控制电路原图

WiFi IO 电源和控制电路原图 — 原图来源: CN PDF p.16.

WiFi 晶振及供电电路原图

WiFi 晶振及供电电路原图 — 原图来源: CN PDF p.17.

首先看下硬件:主要的部分都在绿色方框内

WIFI_D0~3:数据线,平时为高,电压取决于 VCCIO_WL 的电压;

WIFI_CMD:命令线,平时为高,电压取决于 VCCIO_WL 的电压;

WIFI_CLK:时钟,平时为低,电压取决于 VCCIO_WL 的电压;

VBAT_WL:WIFI 模组供电电源,一直都为高,供电需打印 3.3v;

VCCIO_WL:给 DATA/CMD/CLK 的 IO 供电电源,可以为 3.3 或者 1.8v,但 SDIO3.0

必须为 1.8v;

WIFI_REG_ON: 正常工作时为 3.3v,WiFi 关闭时为 0v;

两个晶振:32K 和 26M/37.4M,正常工作时都会有波形输出;

(3) eMMC

eMMC 电路与电源原图

eMMC 电路与电源原图 — 原图来源: CN PDF p.17.

eMMC 有效电压的组合:

eMMC 有效电压组合原表

eMMC 有效电压组合原表 — 原图来源: CN PDF p.17.

VCC / VCCQ 1.1 V–1.3 V 1.70 V–1.95 V 2.7 V–3.6 V
2.7 V–3.6 V 有效 有效 有效 (1)
1.7 V–1.95 V 有效 有效 无效

注 1:HS200 或 HS400 设备均不支持 VCCQ(I/O)的 3.3 V 范围。

VCC_FLASH 对应 VCC;

VCC_IO 对应 VCCQ;

确保 eMMC_CMD/DATA0~7/VCC_IO 电压都一致(1.8 或 3.3v);

确保 VCC_FLAHS/VCC_IO 的电压在开机和运行时或者休眠唤醒时必须保持稳定、不能有塌陷或者纹波过大的情况;

有条件的话,测下 clk 和 cmd 以及 data 的波形质量,确保波形正常;

4.2 波形分析

下图是 SD 卡识别模式时的波形时序图(sdio、emmc 一样)

简单说一下识别 SD 卡的方式:主控发出 48clk 并携带 48bit 的数据发给 SD 卡,而 SD 卡要回应给主控48clk 加 48bit 的数据;如下图:

命令与响应时序原图

命令与响应时序原图 — 原图来源: CN PDF p.18.

主控命令和卡端响应示波器原图

主控命令和卡端响应示波器原图 — 原图来源: CN PDF p.18.

绿色:SDMMC_CLK

⻩色:SDMMC_CMD: SDMMC_CMD 空闲时一直处于高电平;

主控发出的波形:当最开始的两个电平有一高一低时,是主控发出去的命令;

SD 卡响应的波形: 当最开始的两个电平有连续的两个低电平是表示卡端有响应;

其次主控和响应一般包含 48 个 bit 的数据,所以 48 个 clk 为一个完整的包。要确认的就是:主控发出去命令包后,SD 卡端是否有响应。

4.3 LOG 分析

(1) 正确识别 SD 卡的 LOG

[ 293.194013] mmc1: new high speed SDXC card at address 59b4
[ 293.198185] mmcblk1: mmc1:59b4 00000 59.6 GiB
[ 293.204351] mmcblk1: p1

如果在内核看到这样的打印,说明 SD 卡已经被正确识别,并且已经有一个可用的分区 p1。

如果在用戶界面看不到 SD 卡设备或者设备不可使用,请排查用戶态磁盘守护进程,如 vold。

另外可手动验证分区是否可以使用

mount -t vfat /dev/block/mmcblk1p1 /mnt

或者

mount -t vfat /dev/block/mmcblk1 /mnt

然后到 mnt 目录下看下是否有 SD 卡里面的文件

(2) 开机不读卡,运行时拔插 OK:大概率时电源问题

例如:拔掉所有电源,发现查着 HDMI 发现有漏电到 VCC_SD 卡里面;或者使用外接电源进行测试。

(3) 挂载失败:

如果已经看到(1)中的 LOG,但是看到如下挂载失败的 LOG

[ 2229.405694] FAT-fs (mmcblk1p1): bogus number of reserved sectors
[ 2229.405751] FAT-fs (mmcblk1p1): Can't find a valid FAT filesystem

请格式化 SD 卡为 FAT32 文件系统;

或者 NTFS: make menuconfig 选择 NTFS 文件系统的支持即可;

(4) 概率性不识别:

mmc1: new high speed SD card at address b368
mmcblk1: mmc1:b368 SMI 486 MiB
[mmc1] Data transmission error !!!! MINTSTS: [0x00002000]
dwmmc_rockchip ff0c0000.rksdmmc: data FIFO error (status=00002000)
mmcblk1: error -110 sending status command, retrying
need_retune:0,brq->retune_retry_done:0.

降频和增加卡检测延时增强电源稳定性,如果降频 OK 的话,请检查硬件 layout;

&sdmmc {
    card-detect-delay = <1200>;
}

(5) TF 卡已经 mount,但不能访问 TF 卡目录,看起来是卡文件系统问题,但卡在 Windows 下可以访问。

请尝试使用 fsck 对 TF 卡做修复。

(6) 硬件问题,io 电压异常

Workqueue: kmmcd mmc_rescan
[<c0013e24>] (unwind_backtrace+0x0/0xe0) from [<c001172c>] (show_stack+0x10/0x14)
[<c001172c>] (show_stack+0x10/0x14) from [<c04fa444>] (dw_mci_set_ios+0x9c/0x21c)
[<c04fa444>] (dw_mci_set_ios+0x9c/0x21c) from [<c04e7748>] (mmc_set_chip_select+0x18/0x1c)
[<c04e7748>] (mmc_set_chip_select+0x18/0x1c) from [<c04ebd5c>] (mmc_go_idle+0x94/0xc4)
[<c04ebd5c>] (mmc_go_idle+0x94/0xc4) from [<c0748d80>] (mmc_rescan_try_freq+0x54/0xd0)
[<c0748d80>] (mmc_rescan_try_freq+0x54/0xd0) from [<c04e85d0>] (mmc_rescan+0x2c4/0x390)
[<c04e85d0>] (mmc_rescan+0x2c4/0x390) from [<c004d738>] (process_one_work+0x29c/0x458)
[<c004d738>] (process_one_work+0x29c/0x458) from [<c004da88>] (worker_thread+0x194/0x2d4)
[<c004da88>] (worker_thread+0x194/0x2d4) from [<c0052fb4>] (kthread+0xa0/0xac)
[<c0052fb4>] (kthread+0xa0/0xac) from [<c000da98>] (ret_from_fork+0x14/0x3c)
1409..dw_mci_set_ios: wait for unbusy timeout....... STATUS = 0x306 [mmc1]

请检查 CMD 线与 DATA 的电压是否在空载状态下为高电平。并且检测 IO 电压是否过低,以及 IO 电压与电源域的配置是否一致。如果是 SDIO 接口,建议排查 VCCIO_WL 电压,VBAT_WL 和 WIFI_REG_ON以及晶振是否正常。另可以尝试排查走线太⻓导致波形质量很差,降频进行测试。

4.4 其他问题

(1) u-boot下SD卡1线模式工作正常,4线模式工作报错

大部分SOC的SD卡都会和JTAG复用,在没有插卡时,SOC会自动切换IO到JTAG功能。

EVB参考板会按SOC要求设计SD DET低电平为有插卡,个别客戶会修改原理图,设计SD DET高电平为有插卡,这时SOC会误判,把IO切换到JTAG功能。

解决办法: 查找对应芯片GRF寄存器定义,配置force_jtag为Disable,关闭JTAG IO自动切换功能。

RV1126参考代码:

diff --git a/arch/arm/mach-rockchip/rv1126/rv1126.c b/arch/arm/mach-rockchip/rv1126/rv1126.c
index 311310d3f2..29b694df9c 100644
--- a/arch/arm/mach-rockchip/rv1126/rv1126.c
+++ b/arch/arm/mach-rockchip/rv1126/rv1126.c
@@ -544,6 +544,9 @@ void board_debug_uart_init(void)
 #ifndef CONFIG_TPL_BUILD
 int arch_cpu_init(void)
 {
+ struct rv1126_grf * const grf = (void *)GRF_BASE;
+
+ writel(0x00100000, &grf->iofunc_con3);
        /*
         * CONFIG_DM_RAMDISK: for ramboot that without SPL.
*/

(2) SD卡漏电导致卡工作异常

当SD模块的IO电源不可控时,若插入卡后,卡的3V3供电还未提供前,此时会从IO上产生漏电倒灌到SD卡,使得SD卡的3V3供电有半电平,易使得个别卡概率性异常,表现为平台兼容性差。因此为了解决漏电问题,驱动会在插入卡时,先将SD卡IO设置为下拉,释放掉漏电后再对SD卡的3V3电源进行上电。当SD卡上电完成之后再恢复SD卡的IO为SD功能脚并设置上拉,从而避免漏电可能导致的一系列异常。对SD卡兼容性要求较高的客戶,请确认SDK内核的drivers/mmc/host/dw_mmc.c文件包含了提交“mmc:dw_mmc: Add normal and idle pinctrl control”,并参考下面的例子,修改自己的DTS节点,新增pinctrl的idle模式,需要根据实际板子的使用情况,配置所需的clk、cmd和data线:

--- a/arch/arm/boot/dts/rv1126-evb-v10.dtsi
+++ b/arch/arm/boot/dts/rv1126-evb-v10.dtsi
    wireless_wlan: wireless-wlan {
@@ -104,9 +99,14 @@ sdmmc_pwren: sdmmc-pwren {
            rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
        };
+ sdmmc0_idle_pins: sdmmc-idle-pins {
+ rockchip,pins =
+ <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>,
+ <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>,
+ <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
+ <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>,
+ <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>,
+ <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
    };
@@ -140,21 +140,18 @@ &sdio {
 };
 &sdmmc {
    max-frequency = <200000000>;
    no-sdio;
    no-mmc;
    bus-width = <4>;
    cap-mmc-highspeed;
    cap-sd-highspeed;
    disable-wp;
- pinctrl-names = "default";
+ pinctrl-names = "normal", "idle";
    pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
+ pinctrl-1 = <&sdmmc0_idle_gpios &sdmmc0_det>;
    vmmc-supply = <&vcc3v3_sd>;
    vqmmc-supply = <&vccio_sd>;
    status = "okay";
 };

浏览此主题 → · 入门路线 →