本文介绍如何三招搞定Linux SD
卡驱动调试。
一、SD卡介绍
SD Card(Secure Digital Memory Card)
:即安全数码卡,是一种基于半导体快闪存储器的新一代高速存储设备。
SD
卡架构如下:
下面简单整理下SD
卡的外部引脚、内部寄存器、速度等级和容量等级。
1、外部引脚
SD
卡支持三种传输模式:SPI
模式、1bit SD
模式和4bit SD
模式。
在实际项目中,自己主要调试后面两种模式,SD
卡共有9个引脚,汇总如下:
引脚名称 | 引脚描述 | 备注 |
---|---|---|
CLK | 时钟信号 | |
CMD | 命令/回复引脚 | |
DATA0 ~ 3 | 数据线 | 1bit SD 模式:只使用DATA0 ,CD :卡检测。4bit SD 模式:CD/DATA3 :卡检测/数据3 |
VDD | 电源 | |
VSS1/2 | 地 |
2、内部寄存器
SD卡相关寄存器整理如下:
寄存器名称 | 寄存器描述 |
---|---|
OCR(Operating Conditions Register) | 运行条件寄存器 |
CID(Card IDentification Register) | 卡识号寄存器,每张卡都有唯一的识别号 |
CSD(Card Specific Data Register) | 描述数据寄存器 |
SCR(SD Card Configuration Register) | SD卡配置寄存器 |
RCA(Relative Card Address) | 卡地址寄存器 |
DSR(Driver Stage Register) | 驱动级寄存器 |
3、速度等级
根据数据传输速度,SD
卡有不同的速度等级表示方法。
协议规范 | 简介 |
---|---|
SD1.0 | 使用X 表示不同的速度等级,较少使用。 |
SD2.0 | 普通卡(Class2、Class4、Class6)和高速卡(Class10)。 |
SD3.0 | 使用UHS速度等级1和3。 |
SD4.0 | 使用UHS-II |
4、容量等级
SD
卡容量目前支持:SD
、SDHC
和SDXC
。
SD卡类型 | 协议规范 | 容量大小 | 支持文件格式 |
---|---|---|---|
SD | SD1.0 | ~2GB | FAT 12,16 |
SDHC(SD High Capacity) | SD2.0 | 2GB ~ 32GB | FAT 32 |
SDXC(SD eXtended Capacity) | SD3.0 | 32GB ~ 2TB | exFAT |
二、SD卡调试
1、原理图
预调驱动,先看原理图。
下图是RK3568
和microSD
卡槽之间的连接方式。
2、SDCard配置
RK3568 SD
卡配置文件:
1)arch/arm64/boot/dts/rockchip/rk3568.dtsi
sdmmc0: dwmmc@fe2b0000 {
compatible = "rockchip,rk3568-dw-mshc",
"rockchip,rk3288-dw-mshc";
reg = <0x0 0xfe2b0000 0x0 0x4000>;
interrupts = ;
max-frequency = <150000000>;
clocks = <&cru HCLK_SDMMC0>, <&cru CLK_SDMMC0>,
<&cru SCLK_SDMMC0_DRV>, <&cru SCLK_SDMMC0_SAMPLE>;
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>;
resets = <&cru SRST_SDMMC0>;
reset-names = "reset";
status = "disabled";
};
2)arch/arm64/boot/dts/rockchip/rk3568-firefly-core.dtsi
&sdmmc0 {
max-frequency = <150000000>;
supports-sd;
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
disable-wp;
sd-uhs-sdr104;
vmmc-supply = <&vcc3v3_sd>;
vqmmc-supply = <&vccio_sd>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
status = "okay";
};
其中:
clocks
:表示SD
卡控制器时钟、driver
和sample
时钟。
max-frequency
:SD
卡的最大运行频率,根据不同的模式进行调整。
supports-sd
:表示为SD
卡功能,必须添加。否则无法初始化SD
卡。
bus-width
:SD
卡使用4线模式。如果不配置,默认1线模式。
cap-mmc-highspeed/cap-sd-highspeed
:支持highspeed
的SD
卡。
vmmc-supply、vqmmc-supply
:SD
卡电源域。
SD3.0
速度模式:
sd-uhs-sdr12:时钟频率不超过24M,信号电压1.8V
sd-uhs-sdr25:时钟频率不超过50M,信号电压1.8V
sd-uhs-sdr50:时钟频率不超过100M,信号电压1.8V
sd-uhs-ddr50:时钟频率不超过50M,采用双沿采样,信号电压1.8V
sd-uhs-sdr104:时钟频率不超过208M,信号电压1.8V
pinctrl-0
:SD
卡pinmux
配置。
3、SDCard驱动
RK3568
驱动文件:drivers/mmc/host/dw_mmc-rockchip.c
,主要关注:
static const struct dw_mci_drv_data rk3288_drv_data = {
.caps = dw_mci_rk3288_dwmmc_caps,
.num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps),
.set_ios = dw_mci_rk3288_set_ios, ## 配置时钟、总线、电源、片选、时序等
.execute_tuning = dw_mci_rk3288_execute_tuning, ## 调节driver clk和sample clk phase
.parse_dt = dw_mci_rk3288_parse_dt,
.init = dw_mci_rockchip_init,
};
RK3568 SD
控制器使用Synopsys IP
,主要关注:dw_mci_rk3288_set_ios()
和dw_mci_rk3288_execute_tuning()
。
系统启动后,可通过如下命令查看SD
卡属性(驱动实现:drivers/mmc/core/debugfs.c
):
[root@xiaotianbsp:/]# cat /sys/kernel/debug/mmc1/ios
clock: 150000000 Hz
actual clock: 148500000 Hz
vdd: 21 (3.3 ~ 3.4 V)
bus mode: 2 (push-pull)
chip select: 0 (don't care)
power mode: 2 (on)
bus width: 2 (4 bits)
timing spec: 6 (sd uhs SDR104)
signal voltage: 1 (1.80 V)
driver type: 0 (driver type B)
三、SDCard测试
下面测试基于SanDisk Ultra 1 32G SD
卡完成。
1、SD卡检测
系统启动后,SD
卡启动日志如下:
[ 1.225398] dwmmc_rockchip fe2b0000.dwmmc: Successfully tuned phase to 266
[ 1.225420] mmc1: new ultra high speed SDR104 SDHC card at address aaaa
[ 1.226456] mmcblk1: mmc1:aaaa SD32G 29.7 GiB
[ 1.227643] mmcblk1: p1
如果SD
卡没有正常初始化,出现如下日志:
[ 182.501273] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 400000Hz, actual 375000HZ div = 0)
[ 182.672282] mmc1: error -123 whilst initialising SD card
[ 182.686489] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 300000Hz, actual 187500HZ div = 1)
[ 182.699318] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 375000Hz, actual 375000HZ div = 0)
[ 182.717513] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 200000Hz, actual 187500HZ div = 1)
原因:mmc_sd_init_card()
失败。出错信息定义(include/uapi/asm-generic/errno.h
):
#define ETIMEDOUT 110 /* Connection timed out */
...
#define ENOMEDIUM 123 /* No medium found */
2、SD卡寄存器
通过如下命令,可以查看SD
卡相关寄存器的值。
[root@xiaotianbsp:/]# cd /sys/class/mmc_host/mmc1/mmc1:aaaa
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# ls
block driver hwrev oemid scr type
cid dsr manfid power serial uevent
csd erase_size name preferred_erase_size ssr
date fwrev ocr rca subsystem
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat cid
03534453443332478554c496d501636f
## 其它寄存器查看方式类似
SD
卡其它参数的查看方法如下:
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat erase_size
512
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat fwrev
0x5
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat hwrev
0x8
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat manfid
0x000003
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat name
SD32G
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat oemid
0x5344
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat serial
0x54c496d5
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat type
SD
3、挂载/卸载
SD
卡分区挂载命令:
[root@xiaotianbsp:/]# mount -t vfat /dev/mmcblk1p1 /tmp/
[ 244.746983] FAT-fs (mmcblk1p1): utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!
[ 244.749331] FAT-fs (mmcblk1p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[root@xiaotianbsp:/]# mount
...
/dev/mmcblk1p1 on /tmp type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=936,iocharset=utf8,shortname=mixed,errors=remount-ro)
SD
卡分区卸载命令:
umount /dev/mmcblk1p1
4、创建分区
使用fdisk
命令,可在SD
卡上重新创建分区。
[root@xiaotianbsp:/]# fdisk /dev/mmcblk1
...
Command (m for help): p ## 1、查看现有分区
Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors
3880 cylinders, 255 heads, 63 sectors/track
Units: cylinders of 16065 * 512 = 8225280 bytes
Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type
/dev/mmcblk1p1 0,0,17 1023,254,63 16 62333951 62333936 29.7G c Win95 FAT32 (LBA)
Command (m for help): d ## 2、删除分区
Selected partition 1
Command (m for help): p
Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors
3880 cylinders, 255 heads, 63 sectors/track
Units: cylinders of 16065 * 512 = 8225280 bytes
Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type
Command (m for help): n ## 3、创建新分区,共创建了2个分区
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-3880, default 1): Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-3880, default 3880): 1940
Command (m for help): p
Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors
3880 cylinders, 255 heads, 63 sectors/track
Units: cylinders of 16065 * 512 = 8225280 bytes
Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type
/dev/mmcblk1p1 0,1,1 1023,254,63 63 31166099 31166037 14.8G 83 Linux
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (1941-3880, default 1941): Using default value 1941
Last cylinder or +size or +sizeM or +sizeK (1941-3880, default 3880): Using default value 3880
Command (m for help): p
Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors
3880 cylinders, 255 heads, 63 sectors/track
Units: cylinders of 16065 * 512 = 8225280 bytes
Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type
/dev/mmcblk1p1 0,1,1 1023,254,63 63 31166099 31166037 14.8G 83 Linux
/dev/mmcblk1p2 1023,254,63 1023,254,63 31166100 62332199 31166100 14.8G 83 Linux
Command (m for help): w ## 4、保存新分区
5、读写测试
测试SD
卡写命令:
[root@RK356X:/]# time dd oflag=direct,nonblock if=/dev/zero of=/dev/mmcblk1p1 bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 3.4844 s, 30.1 MB/s
real 0m 3.49s
user 0m 0.00s
sys 0m 0.16s
测试SD
卡读命令:
[root@RK356X:/]# time dd iflag=direct,nonblock if=/dev/mmcblk1p1 of=/dev/null bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 1.65236 s, 63.5 MB/s
real 0m 1.65s
user 0m 0.00s
sys 0m 0.03s
上面命令中配置的iflag
和oflag
属性,可以规避文件系统cache
,直接读写,不使用buffer cache
。
注:转载请标注作者和出处。