Linux内核SD卡

本文介绍如何三招搞定Linux SD卡驱动调试。

一、SD卡介绍

SD Card(Secure Digital Memory Card):即安全数码卡,是一种基于半导体快闪存储器的新一代高速存储设备。

SD卡架构如下:

image.png

下面简单整理下SD卡的外部引脚、内部寄存器、速度等级和容量等级。

1、外部引脚

SD卡支持三种传输模式:SPI模式、1bit SD模式和4bit SD模式。

在实际项目中,自己主要调试后面两种模式,SD卡共有9个引脚,汇总如下:

引脚名称 引脚描述 备注
CLK 时钟信号
CMD 命令/回复引脚
DATA0 ~ 3 数据线 1bit SD模式:只使用DATA0CD:卡检测。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卡容量目前支持:SDSDHCSDXC

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、原理图

预调驱动,先看原理图。

下图是RK3568microSD卡槽之间的连接方式。

image.png

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卡控制器时钟、driversample时钟。

max-frequencySD卡的最大运行频率,根据不同的模式进行调整。

supports-sd:表示为SD卡功能,必须添加。否则无法初始化SD卡。

bus-widthSD卡使用4线模式。如果不配置,默认1线模式。

cap-mmc-highspeed/cap-sd-highspeed:支持highspeedSD卡。

vmmc-supply、vqmmc-supplySD卡电源域。

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-0SDpinmux配置。

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

上面命令中配置的iflagoflag属性,可以规避文件系统cache,直接读写,不使用buffer cache

注:转载请标注作者和出处。

你可能感兴趣的:(Linux内核SD卡)