目录
1.芯片简介
1.1 模块与接口
1.2 SD/eMMC初始化流程
1.3 SD/eMMC数据传输流程
1.3.1 传输模式
2.调试问题
2.1 uboot
2.1.1 连续读4个以上block超时
2.1.2 SD卡未识别
2.2 kernel
2.2.1驱动初始化依赖时钟配置
2.2.3 SD卡fdisk分区失败
3. 内核MMC
4.调试命令
4.1 uboot
4.2 kernel
4.2.1 mmc_test
4.2.2 文件系统读写
4.2.3 sysfs
AHB Slave接口用于寄存器访问。
AXI/AHB Master接口用于数据传输。
SD/eMMC接口对接SD卡(支持4bit)和eMMC芯片(支持4/8 bit)。
UHS-II接口对接PHY。
SD卡初始化流程如下:
从SD卡初始化流程可知,不管什么卡(卡分为4类:SD2.0高容量卡(SDHC,最大32G),SD2.0标准容量卡(SDSC,最大2G),SD1.x卡和MMC卡),首先执行卡上电,上电后发送CMD0,对卡进行软复位,之后发送CMD8命令,用于区分SD卡2.0,只有2.0及以后的卡才支持CMD8命令,MMC卡和V1.x的卡,是不支持该命令的。
在发送CMD8的时候,通过其带的参数可以设置VHS位,以告诉SD卡,主机的供电情况,让SD卡知道主机的供电范围。
这里使用参数0X1AA,即告诉SD卡,主机供电为2.7~3.6V之间,如果SD卡支持CMD8,且支持该电压范围,则会通过CMD8的响应R7将参数部分原本返回给主机,如果不支持CMD8,或者不支持这个电压范围,则不响应。
在发送CMD8后,发送ACMD41(注意:发送ACMD41之前,要先发送CMD55),来进一步确认卡的操作电压范围,并通过HCS位来告诉SD卡,主机是不是支持高容量卡(SDHC)。
对于支持CMD8的卡,主机设置ACMD41的参数HCS=1,告诉SD卡,主机支持SDHC卡。
对2.0的卡,OCR的CCS位用于表示SDHC还是SDSC;对1.x的卡,则忽略该位;
对MMC卡,则不支持ACMD41,MMC卡只需要发送:CMD0和CMD1即可完成初始化。
SD卡在收到CMD2后,将返回R2长响应(136位),其中包含128位有效数据(CID寄存器内容),存放在SDIO_RESP1~4等4个寄存器里面。通过读取这四个寄存器,就可以获得SD卡的CID信息。
CMD3用于设置卡相对地址(RCA,必须为非0),对于SD卡(非MMC卡),在收到CMD3后,将返回一个新的RCA给主机,方便主机寻址。RCA的存在允许一个SDIO接口挂多个SD卡,通过RCA来区分主机要操作的是哪个卡。对于MMC卡,则不是由SD卡自动返回RCA,而是主机主动设置MMC卡的RCA,即通过CMD3带参数(高16位用于RCA设置),实现RCA设置。同样MMC卡也支持一个SDIO接口挂多个MMC卡,不同于SD卡的是所有的RCA都是由主机主动设置的,而SD卡的RCA则是SD卡发给主机的。
在获得卡RCA之后,便可以发送CMD9(带RCA参数),获得SD卡的CSD寄存器内容,从CSD寄存器可以得到SD卡的容量和扇区大小等十分重要的信息。
至此,SD卡初始化基本就结束了,最后通过CMD7命令,选中要操作的SD卡,即可开始对SD卡的读写操作了。
分为LEGACY/SDMA/ADMA 3种传输模式,基本流程类似,LEGACY模式为轮询方式,需要CPU访问控制器的buffer寄存器直接存取数据。DMA方式则不需要,使用控制器自带的DMA控制器,CPU只需要准备好DMA使用的DDR基址或者DMA描述符,然后等待控制器自己完成数据搬移即可。
1.3.2 读数据
单个block读取流程。
多个block读取流程:
1.3.3 写数据
单个block写入流程。
多个block写入流程。
【问题现象】
Uboot命令行执行mmc read一次读4个以上block,提示超时失败。
(1) 连续读流程:CMD16 -> CMD18 -> CMD12;
(2) Host发送CMD18开始读取多个block,前4个block能读到,第5个block读失败,中断状态寄存器未改变为期望的状态。从DDR中的内容看,前4个block的内容是正确的,说明问题出在读第5个block的时候;
(3) 类似的流程,Host连续写4个以上block没有问题;
(4) 使用Legacy或者DMA方式,现象一样。
【问题原因】
设计人员仿真DMA方式传输5个block是可以的,怀疑是FPGA版本在buffer满的时候接口时钟没有关闭,这个跟实际芯片版本实现不一样,实际芯片版本当内部buffer满的时候,控制器会停掉供给card的时钟,这样就可以停止接收数据,当buffer内有一个block剩余空间的时候,重新打开时钟,这样就可以保证接收到正确的一个block。
由于新出FPGA版本的问题,暂未确认上述怀疑及验证解决问题的版本。当前通过软件规避。当一次访问多个block时,按照4个block一组切片访问。当前ATF代码就是这样实现的。等正式版本出来,可以去掉该规避措施。
【问题现象】
(1) SD卡与eMMC同时在位,分别连到控制器1和控制器0。Uboot执行命令行mmc info未扫描到SD卡;
(2) 去掉mmc0的dts配置,仅保留mmc1的配置,还是没检测到。
=> mmc info
blk_find_device: if_type=6, devnum=0: [email protected], 6, 1
MMC Device 0 not found
no mmc device at slot 0
Command failed, result=1
=>
【问题原因】
Dts配置SD卡的别名,从mmc1改为sd0。
tsm_tx511_fpga.dtx
aliases {
mmc0 = &sdhci0;
sd0 = &sdhci1; /*mmc1 = &sdhci1;*/
};
Uboot命令行一次只能访问一个设备,通过mmc dev id#来切换设备。
=> mmc dev 0
blk_find_device: if_type=6, devnum=0: [email protected], 6, 0
clock is disabled (0Hz)
clock is enabled (400000Hz)
clock is enabled (20000000Hz)
clock is enabled (20000000Hz)
blk_find_device: if_type=6, devnum=0: [email protected], 6, 0
switch to partitions #0, OK
mmc0(part 0) is current device
=> mmc info
mmc num 2, curr_device 0
blk_find_device: if_type=6, devnum=0: [email protected], 6, 0
Device: mmc@f0d70000
Manufacturer ID: 11
OEM: 100
Name: 032G7
Bus Speed: 20000000
Mode: MMC High Speed (52MHz)
Rd Block Len: 512
MMC version 5.0
High Capacity: Yes
Capacity: 29.1 GiB
Bus Width: 4-bit
Erase Group Size: 512 KiB
HC WP Group Size: 4 MiB
User Capacity: 29.1 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
Boot area 0 is not write protected
Boot area 1 is not write protected
=>
=> mmc dev 1
blk_find_device: if_type=6, devnum=1: [email protected], 6, 0
blk_find_device: if_type=6, devnum=1: [email protected], 6, 1
clock is disabled (0Hz)
clock is enabled (400000Hz)
clock is enabled (20000000Hz)
blk_find_device: if_type=6, devnum=1: [email protected], 6, 0
blk_find_device: if_type=6, devnum=1: [email protected], 6, 1
switch to partitions #0, OK
mmc1 is current device
=> mmc info
mmc num 2, curr_device 1
blk_find_device: if_type=6, devnum=1: [email protected], 6, 0
blk_find_device: if_type=6, devnum=1: [email protected], 6, 1
Device: mmc@f0d71000
Manufacturer ID: 3
OEM: 5344
Name: SB16G
Bus Speed: 20000000
Mode: SD High Speed (50MHz)
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 14.8 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
=>
【问题现象】
probe失败,打印时钟解析错误。
root@(none):/lib# insmod sdhci-of-dwcmshc.ko
sdhci_of_dwcmshc: loading out-of-tree module taints kernel.
[dwcmshc_probe] enter
host ffffffc020652580
pltfm_host->clk fffffffffffffffe
sdhci-dwcmshc f0d70000.sdhci: failed to get core clk: -2
sdhci-dwcmshc: probe of f0d70000.sdhci failed with error -2
root@(none):/lib#
【问题原因】
驱动模块初始化依赖时钟配置,需要在dts中显式配置,FPGA版本中配上桩。
sdhci0: sdhci@f0d70000 {
compatible = "snps,dwcmshc-sdhci";
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 60 4>;
reg = <0x0 0xf0d70000 0x0 0x1000>;
clocks = <&misc_clk>, <&misc_clk>;
clock-names = "core", "bus";
};
2.2.2 mmc_test破坏eMMC中内容
【问题现象】
执行mmc_test测试项之后重启,BL2被破坏。
root@(none):/# mount -t debugfs none /sys/kernel/debug
root@(none)::/# echo -n mmc0:0001 > /sys/bus/mmc/drivers/mmcblk/unbind
root@(none)::/# echo -n mmc0:0001 > /sys/bus/mmc/drivers/mmc_test/bind
root@(none)::/# cd /sys/kernel/debug/mmc0/mmc0:0001
root@(none):/sys/kernel/debug/mmc0/mmc0:0001# echo 2 > test
mmc0: Starting tests of card mmc0:0001...
mmc0: Test case 2. Basic read (no data verification)...
mmc0: Result: OK
mmc0: Tests completed.
root@(none):/sys/kernel/debug/mmc0/mmc0:0001#
重启后启动失败:
NOTICE: Booting Trusted Firmware
NOTICE: BL1: v2.4(debug):e8b6f69-dirty
NOTICE: BL1: Built : 09:25:34, Dec 28 2021
INFO: BL1: CODE 0xf0d40000 RAM 0xf122e000 - 0xf123a000
INFO: emmc_8 boot.
INFO: BL1: Loading BL2
WARNING: Firmware Image Package header check failed.
WARNING: Failed to obtain reference to image id=1 (-2)
ERROR: Failed to load BL2 firmware.
【问题原因】
测试项会破坏内容,prepare函数会将缓存设置为00 01 02 03这样的内容,测试时写入,cleanup中会将缓存清零后写入。后将mmc_test测试地址偏移了2MB,以免破坏卡中内容。
【问题现象】
(1) Probe提示SD设备为ro,执行fdisk分区时无法写入分区表。
(2) 对比操作eMMC,没有该问题,内核起来后重新mount eMMC,分区内容还在。
root@(none):/lib# insmod sdhci-of-dwcmshc.ko
mmc1: sdhci: Version: 0x00000005 | Present: 0x03f70000
mmc1: sdhci: Caps: 0x2768ffa0 | Caps_1: 0x08008077
mmc1: Unknown controller version (5). You may experience problems.
mmc1: sdhci: Auto-CMD23 available
mmc1: SDHCI controller on f0d71000.sdhci [f0d71000.sdhci] using ADMA
mmc1: new high speed SDHC card at address aaaa
mmcblk1: mmc1:aaaa SB16G 14.8 GiB (ro)
root@(none):/lib#
# fdisk /dev/mmcblk1
'/dev/mmcblk1' is opened for read only
Device contains neither a valid DOS partition table, nor Sun, SGI, OSF or GPT disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that the previous content
won't be recoverable.
Command (m for help): w
fdisk: write error: Bad file descriptor
#
【问题原因】
SD卡初始化过程会判断PSTATE寄存器的写保护状态,该寄存器WR_PROTECT_SW_LVL默认为0,软件认为卡写保护,因此Probe和写操作失败。
mmc_test之所以可以正常读写,是因为将SD卡驱动从mmcblk切换到了mmc_test,测试过程中忽略了写保护状态。
eMMC可以正常分区和读写,是因为eMMC跟SD卡走了不一样的软件流程,不判断写保护状态。
与设计人员确认,硬件上不支持写保护,因此需要在配置中去使能写保护检测。
sdhci1: sdhci@f0d71000 {
compatible = "snps,dwcmshc-sdhci";
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 62 4>;
reg = <0x0 0xf0d71000 0x0 0x1000>;
clocks = <&misc_clk>, <&misc_clk>;
clock-names = "core", "bus";
bus-width = <4>;
disable-wp;
};
Linux MMC 子系统主要分成三个部分:
(1)MMC 核心层:完成不同协议和规范的实现,为 host 层和设备驱动层提供接口函数。MMC 核心层由三个部分组成:MMC,SD 和 SDIO,分别为三类设备驱动提供接口函数;
(2)Host 驱动层:针对不同主机端的 SDHC、MMC 控制器的驱动;
(3)Client 驱动层:针对不同客户端的设备驱动程序。如 SD 卡、T-flash 卡、SDIO 接口的 GPS 和 wi-fi 等设备驱动。
系统框架:
Linux MMC framework的工作流程如下:
(1) mmc读操作
mmc read addr blk# cnt
(2) mmc写操作
mmc write addr blk# cnt
(3) mmc擦除操作
mmc erase blk# cnt
(4) 重新搜索mmc设备
mmc rescan
(5) 列出mmc的分区
mmc part - lists available partition on current mmc device
(6) 查看当前的设备号,或者设置设备号及分区
存在多个mmc设备时,可使用该命令切换设备
mmc dev [dev] [part] - show or set current mmc device [partition]
(7) 显示boot分区号
mmc bootpart [dev] [part] - show or set boot partition
(8) 列出当前的mmc设备
mmc list - lists available devices
(9) 打印当前mmc设备的信息
mmc info
(10) dump当前mmc控制器的寄存器信息
mmcdump
(1) 挂载debugfs;
(2) 切换设备驱动到mmc_test;
(3) 在debugfs下执行测试项。
# mount -t debugfs none /sys/kernel/debug
for eMMC
# echo -n mmc0:0001 > /sys/bus/mmc/drivers/mmcblk/unbind
# echo -n mmc0:0001 > /sys/bus/mmc/drivers/mmc_test/bind
# cd /sys/kernel/debug/mmc0/mmc0:0001
for SD
# echo -n mmc1:aaaa > /sys/bus/mmc/drivers/mmcblk/unbind
# echo -n mmc1:aaaa > /sys/bus/mmc/drivers/mmc_test/bind
# cd /sys/kernel/debug/mmc1/mmc1\:aaaa/
debugfs下
cat testlist打印所有测试项
echo test_item > test执行测试项
(1) 执行fdisk对设备分区;
(2) 执行mkfs创建文件系统;
(3) 执行mount挂载文件系统;
(4) 读写挂载的分区。
root@(none):~# fdisk /dev/mmcblk1
Device contains neither a valid DOS partition table, nor Sun, SGI, OSF or GPT disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that the previous content
won't be recoverable.
The number of cylinders for this disk is set to 486192.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Command (m for help): n
Partition type
p primary partition (1-4)
e extended
p
Partition number (1-4): 1
First sector (16-31116287, default 16):
Using default value 16
Last sector or +size{,K,M,G,T} (16-31116287, default 31116287): +131072
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table
mmcblk1: p1
root@(none):~# fdisk /dev/mmcblk1
The number of cylinders for this disk is set to 486192.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Command (m for help): p
Disk /dev/mmcblk1: 15 GB, 15931539456 bytes, 31116288 sectors
486192 cylinders, 4 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes
Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type
/dev/mmcblk1p1 0,1,1 1023,3,16 16 131088 131073 64.0M 83 Linux
Command (m for help): q
root@(none):~# mdev -s
root@(none):~# ls -lt /dev/mmc*
brw-rw---- 1 root 0 179, 25 Apr 15 08:05 /dev/mmcblk1p1
brw-rw---- 1 root 0 179, 24 Apr 15 08:04 /dev/mmcblk1
brw-rw---- 1 root 0 179, 0 Apr 15 08:02 /dev/mmcblk0
brw-rw---- 1 root 0 179, 8 Apr 15 08:02 /dev/mmcblk0boot0
brw-rw---- 1 root 0 179, 16 Apr 15 08:02 /dev/mmcblk0boot1
crw-rw---- 1 root 0 247, 0 Apr 15 08:02 /dev/mmcblk0rpmb
root@(none):~# mkfs.ext2 /dev/mmcblk1p1
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
16384 inrandom: mkfs.ext2: uninitialized urandom read (16 bytes read)
odes, 65536 blocks
3276 blocks random: mkfs.ext2: uninitialized urandom read (16 bytes read)
(5%) reserved for the super user
First data block=1
Maximum filesystem blocks=262144
8 block groups
8192 blocks per group, 8192 fragments per group
2048 inodes per group
Superblock backups stored on blocks:
8193, 24577, 40961, 57345
root@(none):~# mkdir -p /mnt/sd1
root@(none):~# mount /dev/mmcblk1p1 /mnt/sd1/
EXT4-fs (mmcblk1p1): mounting ext2 file system using the ext4 subsystem
EXT4-fs (mmcblk1p1): mounted filesystem without journal. Opts: (null)
root@(none):~# cd /mnt/sd1
root@(none):/mnt/sd1# ls
lost+found
root@(none):/mnt/sd1# cp /lib/sdhci-of-dwcmshc.ko ./22.ko
root@(none):/mnt/sd1# ls -lt
total 28
-rwxr-xr-x 1 root 0 15080 Apr 15 08:06 22.ko
drwxr-xr-x 2 root 0 12288 Apr 15 08:05 lost+found
root@(none):/mnt/sd1#
cat /sys/dwc_mshc/dwcmshcdbg
交替dump两个控制器的寄存器内容。