前言和先行知识
u-boot中有两个功能块对MMC(eMMC/SD)设备进行管理。
其中一个是fastboot、另一个是 MMC sub system(MMC子系统)。
fastboot
主要是实现烧写数据的功能,而MMC子系统则拥有完整的命令集对MMC(eMMC/SD)设备进行管理.
fastboot
也会调用MMC sub system
的命令来实现其功能。关于这一点,详见我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/146012950【搜索“Fastboot 的PC端可利用FB”】
本篇博文介绍MMC sub system
,而关于fastboot
的介绍,请见我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145985144
读懂本篇博文需要先对eMMC存储器有个详细的认识,详情见我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145967306
U-Boot 的 MMC (MultiMediaCard) 子系统(MMC sub system)是专门用于管理 MMC 设备(包括 eMMC 和 SD 卡)的子系统,它提供了对这些存储设备的初始化、读写和分区管理等功能。
1. MMC 子系统概述
MMC 子系统主要用于支持:
- SD/MMC/eMMC 存储设备的初始化和访问
- 分区管理
- FAT/ext 文件系统支持
- 设备挂载与引导功能
U-Boot 的 MMC 子系统主要由以下几个部分组成:
-
驱动层(
drivers/mmc/
)
负责具体的 MMC/SD 控制器驱动实现,例如 IMX6ULL 平台通常使用drivers/mmc/fsl_esdhc.c
。 -
核心层(
drivers/mmc/mmc.c
)
负责管理 MMC 设备的初始化、命令发送和数据传输。 -
命令层(
cmd/mmc.c
)
提供 U-Boot 命令行接口(CLI)来操作 MMC 设备。
2. MMC子系统的命令集
如何获取当前u-boot的MMC子系统的命令集
在u-boot下运行命令mmc
可以输出你当前使用的u-boot的MMC子系统的命令集。
比如我在博文 https://blog.csdn.net/wenhao_ir/article/details/145662136 中最终生成的u-boot运行后,我执行命令:
mmc
运行结果如下:
mmc - MMC sub system
Usage:
mmc info - display info of the current MMC device
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc erase blk# cnt
mmc rescan
mmc part - lists available partition on current mmc device
mmc dev [dev] [part] - show or set current mmc device [partition]
mmc list - lists available devices
mmc hwpartition [args...] - does hardware partitioning
arguments (sizes in 512-byte blocks):
[user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes
[gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition
[check|set|complete] - mode, complete set partitioning completed
WARNING: Partitioning is a write-once setting once it is set to complete.
Power cycling is required to initialize partitions after set to complete.
mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode
- Set the BOOT_BUS_WIDTH field of the specified device
mmc bootpart-resize <dev> <boot part size MB> <RPMB part size MB>
- Change sizes of boot and RPMB partitions of specified device
mmc partconf dev [boot_ack boot_partition partition_access]
- Show or change the bits of the PARTITION_CONFIG field of the specified device
mmc rst-function dev value
- Change the RST_n_FUNCTION field of the specified device
WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.
mmc setdsr <value> - set DSR register value
现根据上面的内容说明MMC子系统各条命令的使用。
基本操作命令
1. 查看当前 MMC 设备信息
mmc info
作用:
- 显示当前 MMC 设备的详细信息,包括厂商 ID、设备名称、容量、总块数、总线速度等。
示例输出:
Device: FSL_SDHC
Manufacturer ID: 3
OEM: 5344
Name: SL16G
Bus Speed: 50000000
Block Size: 512
Total Blocks: 30474240
实际输出如下:
2. 读数据
mmc read addr blk# cnt
作用:
- 从 MMC 设备的
blk#
块号开始读取cnt
个块的数据,并存入addr
指定的内存地址。
示例:
mmc read 0x82000000 0x100 0x10
- 读取
0x10
(16) 个块的数据,从0x100
块号开始,存入内存地址0x82000000
。
3. 写数据
mmc write addr blk# cnt
作用:
- 将
addr
指定的内存地址的数据写入到 MMC 设备,从blk#
开始写cnt
个块。
示例:
mmc write 0x82000000 0x100 0x10
- 从内存地址
0x82000000
取数据,写入到 MMC 设备的0x100
块,写入0x10
(16) 个块。
4. 擦除数据
mmc erase blk# cnt
作用:
- 擦除 MMC 设备上从
blk#
开始的cnt
个块。
示例:
mmc erase 0x100 0x10
- 擦除 MMC 设备的
0x100
块开始的0x10
(16) 个块。
5. 重新扫描 MMC 设备
mmc rescan
作用:
- 重新初始化 MMC 设备,检测是否有新插入的 SD 卡或 eMMC 设备。
设备和分区管理
6. 列出可用的 MMC 设备及其编号
mmc list
作用:
- 列出系统中所有可用的 MMC 设备。
示例输出:
FSL_SDHC: 0
- 表示系统检测到
FSL_SDHC
控制器管理的设备,编号为0
。
实际输出如下:
这个输出结果表明在当前u-boot下,eMMC存储器在SD/MMC 总线上的 SD/MMC 控制器的编号为1。
输出结果中FSL_SDHC
的全称为:Freescale Secure Digital Host Controller
,其中:
- FSL = Freescale(飞思卡尔,现已并入 NXP)
- SDHC = Secure Digital Host Controller(安全数字主机控制器)
在 NXP i.MX 处理器(如 i.MX6、i.MX7、i.MX8)中,FSL_SDHC
负责管理 SD/MMC 总线,通常有 2~4 个 SD/MMC 控制器(编号从 0
开始)。 SD/MMC 控制器可以管理 SD 卡、eMMC 存储设备。
例如,在 i.MX6ULL 处理器上:
- FSL_SDHC0 可能连接 SD 卡
- FSL_SDHC1 可能连接 eMMC
- FSL_SDHC2 可能是额外的 SD/MMC 控制器
7. 选择或查看当前 MMC 设备
mmc dev [dev] [part]
作用:
dev
指定新的设备编号,part
指定要使用的分区编号。这里的分区编号来源于eMMC存储器的EXT_CSD[179]的PARTITION_ACCESS
字段,详见 https://blog.csdn.net/wenhao_ir/article/details/145967306 【搜索“即哪个分区作为前活动分区”】
示例:
mmc dev 0
- 选择设备
0
作为当前操作的 MMC 设备。
mmc dev 0 1
- 选择设备
0
,并使用其第1
分区,对于eMMC存储器,实际上就是Boot partition 1
。
我的开发板上u-boot实际输出如下:
mmc dev 1
运行结果如下:
这个结果表明切换到了编号为1的MMC设备(mmc1),即当前活动的MMC设备为编号为1的mmc1设备,并且这个MMC设备的活动分区编号则是默认的0值,这里的0值在eMMC中代表的是User Area
,详情请参考我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/146088727 【搜索“被编号为0(即默认情况)”】
8. 列出 MMC 设备上的当前活动分区的逻辑分区信息
mmc part
说明:了解这个命令的作用前,你需要去复习下eMMC存储器启动的两个阶段——即“Boot读取阶段”和“正常数据操作阶段”,详情的介绍请参看博文https://blog.csdn.net/wenhao_ir/article/details/145967306 【搜索“eMMC启动过程的两个阶段”】。
作用:
- 显示当前 MMC 设备上的当前活动分区的逻辑分区信息。关于什么叫当前活动分区?请参考我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145967306 【搜索”即哪个分区作为前活动分区“】
- 注意:它并不是显示前 MMC 设备上的所有分区信息,它只是显示当前活动分区的逻辑分区信息,举个例子,eMMC进入“正常数据操作阶段”后,默认情况下当前活动分区都是
User Area
区,此时运行这个命令显示的是User Area
区下的逻辑分区信息,这里所谓逻辑分区就是指把User Area
分区再进行区域的划分。此时命令mmc part
是看不到Boot partition 1
分区和Boot partition 2
分区的,你此时查看的分区信息都是User Area
分区的逻辑分区信息。
示例输出:
Partition Map for MMC device 0 -- Partition Type: DOS
Part Start Sector Num Sectors UUID
1 8192 1048576 0x83
2 1056768 2097152 0x83
Part 1
从8192
扇区开始,大小1048576
扇区。Part 2
从1056768
扇区开始,大小2097152
扇区。
我的开发板实际运行结果如下:
分析:
首先用命令mmc dev 1 0
将编号为1的eMMC切换到User Area
区(命令中末尾的0代表User Area
区)。关于为什么0代表User Area
区,请参看我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/146088727
然后用命令mmc part
查看User Area
区的分区信息,即User Area
区的逻辑分区信息。
从结果中我们可以看到我所使用的eMMC存储器的User Area
区被划分为了三个逻辑分区,三个逻辑分区的编号分别为1、2、3。三个逻辑分区的大小可以使用Num Sectors
来计算,一个Num Sectors
代表512B,即512个字,所以三个分区的大小分别计算如下:
第1个逻辑分区:1024000512/1024/1024 = 500MB
第2个逻辑分区:2097152512/1024/1024 = 1024MB
第3个逻辑分区:20480*512/1024/1024 = 10MB
这就是为什么百问网的烧写工具要把根文件系统放在第2个逻辑分区的原因了,因为这个逻辑分区最大嘛。关于百问网的烧写工具的详细介绍见博文 https://blog.csdn.net/wenhao_ir/article/details/145653414
从上面可以看出:此时的编号1、2、3其实代表的是User Area
区的三个逻辑分区。
备注说明:Boot partition 1
和Boot partition 2
是没有划分逻辑分区的,所以如果你查看这两个逻辑分区,会出现bad MBR sector signature 0x0000
的提示,如下图所示:
注意:命令mmc dev 1 1
中的第1个1
表示编号为1的MMC设备,第2个1
表示Boot partition 1
分区,关于为什么第2个1
代表示Boot partition 1
分区,请参看我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/146088727
eMMC 专用管理命令
这些命令主要用于 eMMC 设备,因为 eMMC 具有比 SD 卡更多的高级功能,如硬件分区和引导配置。
9. 硬件分区管理
mmc hwpartition [args...]
作用:
- 对 eMMC 进行硬件分区,例如创建 用户区、增强型用户区和 GP(General Purpose)分区。
示例:
mmc hwpartition gp1 1024 enh set complete
- 创建一个
1024
个 512B 扇区的 GP1 分区,启用enh
(增强模式),然后set complete
(完成配置)。
⚠ 警告:
set complete
之后,分区配置 不可更改,需要 断电重启 使其生效!
10. 修改 eMMC 引导总线配置
mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode
作用:
- 设置 eMMC 的
BOOT_BUS_WIDTH
字段,以调整启动模式。
示例:
mmc bootbus 0 2 0 1
- 选择设备
0
boot_bus_width=2
(8-bit DDR)reset_boot_bus_width=0
boot_mode=1
(单数据率模式)
11. 调整 eMMC 启动分区大小
mmc bootpart-resize <dev> <boot part size MB> <RPMB part size MB>
作用:
- 修改 eMMC 设备的 引导分区 和 RPMB(Replay Protected Memory Block)分区 的大小。
示例:
mmc bootpart-resize 0 4 2
- 把 eMMC 设备
0
的引导分区设为4MB
,RPMB 分区设为2MB
。
12. 修改 eMMC 启动分区访问配置
mmc partconf dev [boot_ack boot_partition partition_access]
作用:
- 设置 eMMC 启动分区的访问模式。
示例:
mmc partconf 0 1 1 1
- 设备
0
:boot_ack=1
(启动确认)boot_partition=1
(使用boot1
分区作为启动分区)partition_access=1
(选择 eMMC进入“正常数据操作阶段”后,哪个分区作为活动分区,这里一般都是设置的是0,表示eMMC进入“正常数据操作阶段”后,使User Area
区作为当前活动分区。关于这一点详细的介绍请参看我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145967306 【搜索“控制当前访问的 eMMC 分区”】)
13. 修改 eMMC 复位功能
mmc rst-function dev value
作用:
- 设置 eMMC 设备
RST_n_FUNCTION
字段。
示例:
mmc rst-function 0 1
- 设置设备
0
的RST_n_FUNCTION
为1
(启用 eMMC 复位)。
RST_n_FUNCTION 取值及影响
值 | 说明 |
---|---|
0 | RST_n 引脚禁用(无效,外部复位信号不会影响 eMMC) |
1 | RST_n 引脚启用(eMMC 响应外部复位信号) |
2 | RST_n 引脚启用,并且是一次性写入的(OTP,One-Time Programmable) |
注意:如果RST_n_FUNCTION的值设为 2,那么RST_n_FUNCTION 的值就不能更改了(OTP-One-Time Programmable,永久设置),请谨慎使用!
14. 修改 DSR(Driver Stage Register)
mmc setdsr <value>
作用:
- 设置 MMC 设备的 DSR 值。在 MMC 设备中,DSR(Driver Stage Register,驱动级寄存器) 是一个 可选 的 16 位寄存器,用于微调 MMC 设备的驱动特性,以优化信号完整性和系统兼容性。它可以控制 MMC 设备的驱动强度,调整其 I/O 特性,以适应不同的 PCB 设计和电气环境。它可以允许主机和设备进行匹配,以减少信号反射、提高稳定性、减少 EMI(电磁干扰)。注意:不是所有 MMC 设备都支持 DSR 功能。
示例:
mmc setdsr 0x0404
- 设置 DSR 为
0x0404
。
3. 利用MMC子系统的fatload命令和ext4load命令引导加载内核
在 U-Boot 中,fatload mmc
和 ext4load mmc
命令用于从 MMC(SD 卡或 eMMC)加载文件到内存。它们的完整格式如下:
1. fatload mmc
用于从 FAT 文件系统的 MMC 设备加载文件到内存:
fatload mmc <dev[:part]> <addr> <filename> [bytes]
<dev>
:MMC 设备编号(通常是 0 或 1)<part>
:准备要加载的文件是存储在eMMC的当前活动分区(通常为User Area
区)的哪个逻辑分区中。<addr>
:文件加载到的内存地址(通常为 RAM 地址)<filename>
:要加载的文件路径[bytes]
(可选):要加载的字节数,默认加载整个文件
示例
fatload mmc 0:1 0x82000000 boot.img
表示从 mmc 0
的当前活动分区(通常为User Area
区)的第 1 逻辑分区加载 boot.img
到内存地址 0x82000000
。fat
代表这个逻辑分区的文件系统是FAT。
2. ext4load mmc
用于从 Ext4 文件系统的 MMC 设备加载文件到内存:
ext4load mmc <dev[:part]> <addr> <filename> [bytes]
<dev>
:MMC 设备编号<part>
:准备要加载的文件是存储在eMMC的当前活动分区(通常为User Area
区)的哪个逻辑分区中。<addr>
:文件加载到的内存地址<filename>
:要加载的文件路径[bytes]
(可选):要加载的字节数,默认加载整个文件
示例
ext4load mmc 0:2 0x82000000 /boot/uImage
表示从 mmc 0
的当前活动分区(通常为User Area
区)的第 2逻辑分区(Ext4 文件系统)加载 /boot/uImage
到内存地址 0x82000000
。ext4
代表这个逻辑分区的文件系统是ext4
。
两条命令中的part参数的编号来自于哪里
在命令fatload mmc
和 ext4load mmc
命令中part参数的意义为当前活动分区(通常为User Area
区)的逻辑分区的编号。也就是与命令mmc part
输出信息中part列编号的意义一样。所以对于命令fatload
和ext4load
中需要的part参数实际上我们可以从命令mmc part
的输出信息获取。
4. U-Boot 如何启用 MMC
U-Boot 需要正确配置 CONFIG_MMC
选项来启用 MMC 支持:
CONFIG_MMC=y
CONFIG_GENERIC_MMC=y
CONFIG_FSL_ESDHC=y /* i.MX6ULL 的 MMC 控制器 */
CONFIG_SYS_MMC_ENV_DEV=0 /* 指定存储环境变量的 MMC 设备号 */
如果 U-Boot 需要在 eMMC/SD 上存储环境变量,通常需要:
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_MMC_ENV_DEV=0
CONFIG_ENV_OFFSET=0x400000
5.实际使用例子
利用MMC子系统查看和修改eMMC设备的EXT_CSD[179]配置信息
第01步
运行下面的命令即可查看设备的EXT_CSD[179]信息:
先运行命令看下eMMC设备在u-boot中的编号:
mmc list
这个输出结果表明在当前u-boot下,eMMC存储器在SD/MMC 总线上的 SD/MMC 控制器的编号为1。
输出结果中FSL_SDHC
的全称为:Freescale Secure Digital Host Controller
,其中:
- FSL = Freescale(飞思卡尔,现已并入 NXP)
- SDHC = Secure Digital Host Controller(安全数字主机控制器)
在 NXP i.MX 处理器(如 i.MX6、i.MX7、i.MX8)中,FSL_SDHC
负责管理 SD/MMC 总线,通常有 2~4 个 SD/MMC 控制器(编号从 0
开始)。 SD/MMC 控制器可以管理 SD 卡、eMMC 存储设备。
例如,在 i.MX6ULL 处理器上:
- FSL_SDHC0 可能连接 SD 卡
- FSL_SDHC1 可能连接 eMMC
- FSL_SDHC2 可能是额外的 SD/MMC 控制器
第02步
选择当前的MMC设备,因为我的eMMC设备在u-boot中编号为1,所以命令如下:
mmc dev 1
运行结果如下:
这个结果表明切换到了编号为1的MMC设备(mmc1),即当前活动的MMC设备为编号为1的mmc1设备,并且这个MMC设备的活动分区编号则是默认的0值,这里的0值在eMMC中代表的是User Area
,详情请参考我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/146088727 【搜索“被编号为0(即默认情况)”】
第03步
运行下面的命令查看EXT_CSD[179]配置信息:
mmc partconf 1
命令中的参数1
代表设备编号为1。
这个结果表明eMMC 在 启动阶段(Boot Operation) 会发送 Boot Acknowledge(ACK) 信号,从从 Boot 分区 1 启动,当前访问的 eMMC 分区为0分区,即普通用户数据区。
第04步
接下来,说下怎么修改EXT_CSD[179的]配置信息。
本文上面介绍的第12个命令格式就可以实现修改EXT_CSD[179的]配置信息。。
mmc partconf dev [boot_ack boot_partition partition_access]
示例如下:
mmc partconf 1 1 1 0
具体意义如下:
- 第1个参数值为1的意义:选择 编号为1
的 eMMC 设备;
- 第2个参数值为1的意义:启用 Boot Acknowledge信号。
- 第3个参数值为1的意义:选择 eMMC Boot 分区 1(即 boot1) 作为启动分区。
- 第4个参数值为1的意义:
- boot_partition = 1
→ 选择 eMMC Boot 分区 1(即 boot1) 作为启动分区
- partition_access = 0
→ 设置eMMC进入“正常数据操作阶段”后,eMMC的活动分区为普通用户数据区(0值就是代表普通用户数据区),即从普通用户数据区进行数据的读写操作。关于这一点详细的介绍请参看我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/145967306 【搜索“控制当前访问的 eMMC 分区”】
利用MMC子系统和Fastboot烧写u-boot、内核、设备树
详情见我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/146012950