Flash Open Source Solution 开发指南
:::info 文档信息
文档标识:RK-KF-YF-314 · 发布版本:V3.0.0 · 发布日期:2022-03-06 · 页数:31 · 语言:中文
原始文档:Rockchip_Developer_Guide_Linux_Flash_Open_Source_Solution_CN.pdf
:::
章节大纲
- Flash Open Source Solution 开发指南(P1)
- 开源方案须知(P6)
- 开源方案特性(P6)
- Nand Flash 颗粒选型须知(P6)
- 芯片对应分区扩展支持(P6)
- 存储软件驱动配置(P7)
- SPL & U-Boot 基础配置(P7)
- Kernel 基础配置(P8)
- SLC Nand(P8)
- SPI Nor\Nand(P8)
- Linux 4.19 及旧版本(P8)
- Linux 5.10 版本(P9)
- 分区配置(P9)
- MTD 分区基础(P9)
- GPT 分区扩展(P10)
- Vendor Storage(P10)
- OTA(P10)
- 镜像来源(P11)
- Shell 命令升级 MTD 分区(P11)
- Shell 命令升级 UBIFS 镜像分区(P13)
- 函数接口升级 MTD 分区(P13)
- 文件系统(P14)
- UBIFS 文件系统(P14)
- 简介(P14)
- 配置(P14)
- 镜像制作及挂载(P14)
- 预制作镜像(P14)
- 空分区镜像制作(P17)
- UBIFS 分区命令挂载(P17)
- UBIFS 分区自动挂载(P18)
- UBI 镜像分区损耗(P18)
- UBI Block 支持 SquashFS(P19)
- 镜像空间大小优化(P20)
- UBIFS OTA(P20)
- U-Boot 下支持 UBIFS(P21)
- JFFS2 文件系统支持(P22)
- 简介(P22)
- 配置(P22)
- 镜像制作(P22)
- UBIFS 文件系统(P14)
- PC 工具烧录(P22)
- PC 工具烧录 —— GPT 分区扩展(P23)
- 烧录器烧录(P23)
- SPI Nand 镜像烧录 —— GPT 分区扩展(P23)
- SPI Nand 制作烧录镜像(P23)
- SPI Nand 烧录器烧录(P25)
- SLC Nand 镜像烧录 —— GPT 分区扩展(P26)
- SLC Nand 制作烧录镜像(P26)
- SLC Nand 烧录器烧录(P27)
- SPI Nor 镜像烧录 —— GPT 分区扩展(P28)
- SPI Nor 制作烧录镜像(P28)
- SPI Nor 烧录器烧录(P29)
- SPI Nand 镜像烧录 —— GPT 分区扩展(P23)
- 常见问题(P30)
- Nand Flash 信息(P30)
- IDB Layout(P30)
- 附录参考(P30)
- 开源方案须知(P6)
在线预览
若预览无法显示,请直接下载 PDF 后用本地阅读器打开。
1. 开源方案须知
1.1 开源方案特性
确认以下开源实现方案特性:
| 简称 | 主要支持的 颗粒类型 | 注册设备类型 | 主要支持 文件系统 | 支持的烧录方式 |
|---|---|---|---|---|
| SLC Nand 开源方案 (并口 Nand) | SLC Nand | mtd 设备、 ubiblock | SquashFS、 UBIFS | USB 升级、SD 卡升 级、烧录器升级 |
| SPI Nand 开源方案 | SPI Nand | mtd 设备、 ubiblock | SquashFS、 UBIFS | USB 升级、SD 卡升 级、烧录器升级 |
| SPI Nor 开源方案 | SPI Nor | mtd 设备、mtd block 设备 | SquashFS、 JFFS2 | USB 升级、SD 卡升 级、烧录器升级 |
主要确认:
选用的颗粒类型文件系统是否符合需求
1.2 Nand Flash 颗粒选型须知
由于 UBIFS 依赖 Nand 设备的具体规格来进行制作,所以制作出来的固件无法兼容不同 page size 和block size 的颗粒。
Nand 物料选型规格要一致该文档中 SLC Nand 指并口 nand
1.3 芯片对应分区扩展支持
如 “分区配置” 章节中所述,RK SDK 为 MTD 分区做了一些特殊扩展,请根据芯片确认扩展支持情况:
| 芯片 | GPT 分区扩展 |
|---|---|
| RK3308 | Y |
| RV1126 & RV1109 | Y |
| RK3568 & RK3566 | Y |
| RK3588 & RK3588s | Y |
2. 存储软件驱动配置
2.1 SPL & U-Boot 基础配置
框架简介:
| 简称 | 主要支持的颗粒类型 | 主控驱动 | flash 框架 |
|---|---|---|---|
| SLC Nand 开源方案 | SLC Nand | drivers/mtd/nand/raw | drivers/mtd/nand/raw |
| SPI Nand 开源方案 | SPI Nand | drivers/spi/rockchip sfc.c _ | drivers/mtd/nand/spi |
| SPI Nor 开源方案 | SPI Nor | drivers/spi/rockchip sfc.c _ | drivers/mtd/spi |
defconfig 配置:
增加
// MTD 驱动支持
CONFIG_MTD=y
CONFIG_CMD_MTD_BLK=y
CONFIG_SPL_MTD_SUPPORT=y
CONFIG_MTD_BLK=y
CONFIG_MTD_DEVICE=y
// spi nand 驱动支持
CONFIG_NAND=y
CONFIG_MTD_SPI_NAND=y
CONFIG_ROCKCHIP_SFC=y
CONFIG_SPL_SPI_FLASH_SUPPORT=y
CONFIG_SPL_SPI_SUPPORT=y
// nand 驱动支持
CONFIG_NAND=y
CONFIG_CMD_NAND=y
CONFIG_NAND_ROCKCHIP=y
CONFIG_SPL_NAND_SUPPORT=y
CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
CONFIG_SYS_NAND_U_BOOT_OFFS=0x8000
CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND=0x10000
// rkfw 打包格式指定u-boot trust地址(fit 格式则无需)
CONFIG_RKFW_TRUST_SECTOR=0X3000 #存储设备里面的烧写地址,以sector为单位的,1
sector=512 Bytes,即paramter.txt 里trust的起始地址
CONFIG_RKFW_U_BOOT_SECTOR=0X2000 #存储设备里面的烧写地址,以sector为单位的,1
sector=512 Bytes,即paramter.txt 里u-boot的起始地址
删除
CONFIG_RKFLASH=y
CONFIG_RKNANDC_NAND=y
CONFIG_RKSFC_NAND=y
2.2 Kernel 基础配置
2.2.1 SLC Nand
框架简介:
| 简称 | 主要支持的颗粒类型 | 主控驱动 | flash 框架 |
|---|---|---|---|
| SLC Nand 开源方案 | SLC Nand | drivers/mtd/nand/raw | drivers/mtd/nand/raw |
defconfig 配置:
CONFIG_RK_NANDC_NAND=n /* 不兼容 */
CONFIG_MTD_NAND_ROCKCHIP_V6=y /* NandC v6 可根据 TRM NANDC->NANDC_NANDC_VER 寄存器
确认,0x00000801 */
# CONFIG_MTD_NAND_ROCKCHIP_V9=y /* NandC v9 可根据 TRM NANDC->NANDC_NANDC_VER 寄存
器确认,0x56393030 */
CONFIG_MTD_CMDLINE_PARTS=y
2.2.2 SPI Nor\Nand
2.2.2.1 Linux 4.19 及旧版本
框架简介:
| 简称 | 主要支持的颗粒类型 | 主控驱动 | flash 框架 |
|---|---|---|---|
| SPI Nand 开源方案 | SPI Nand | drivers/rkflash | drivers/rkflash |
| SPI Nor 开源方案 | SPI Nor | drivers/rkflash | drivers/rkflash |
defconfig 配置:
CONFIG_RK_FLASH=y
CONFIG_RK_SFC_NAND=y /* SPI Nand flash */
CONFIG_RK_SFC_NAND_MTD=y /* SPI Nand flash 及其分区注册为 mtd 设备,不选中则注册为普通
block 设备(rkflash0pn) */
CONFIG_RK_SFC_NOR=y /* SPI Nor flash */
CONFIG_RK_SFC_NOR_MTD=y /* SPI Nor flash 及其分区注册为 mtd 设备,不选中则注册为普通
block 设备(rkflash0pn) */
CONFIG_MTD_CMDLINE_PARTS=y
dts 配置:
&sfc {
status = "okay";
flash@0 {
compatible = "spi-nand"; # compatible = "jedec,spi-nor"; for spinor
reg = <0>;
spi-max-frequency = <75000000>;
spi-rx-bus-width = <4>;
spi-tx-bus-width = <1>;
};
};
2.2.2.2 Linux 5.10 版本
框架简介
| 简称 | 主要支持的颗粒类 型 | 主控驱动 | flash 框架 |
|---|---|---|---|
| SPI Nand 开源方 案 | SPI Nand | drivers/spi/spi-rockchip- sfc.c | drivers/mtd/nand/spi |
| SPI Nor 开源方案 | SPI Nor | drivers/spi/spi-rockchip- sfc.c | drivers/mtd/spi-nor |
defconfig 配置:
CONFIG_SPI_ROCKCHIP_SFC=y
dts 配置:
&sfc {
status = "okay";
flash@0 {
compatible = "spi-nand"; # compatible = "jedec,spi-nor"; for spinor
reg = <0>;
spi-max-frequency = <75000000>;
spi-rx-bus-width = <4>;
spi-tx-bus-width = <1>;
};
};
2.3 分区配置
2.3.1 MTD 分区基础
flash 开源方案注册存储设备为 MTD 设备,仅支持解析规范的 mtd partition 分区表信息。
Nand 分区规划须知:SLC Nand 及 SPI Nand 开源方案每个分区应预留出 2~3 个 flash block size 的冗余空间,以便遇到坏块时,有冗余空间可替换,尤其注意 u-boot 分区是否做到了空间预留;分区起始地址应做 flash block size 对齐;SLC Nand 及 SPI Nand 开源方案预留最后 4 个 flash block 给全局坏块表,所以最后一个用户分区不应包括该区域
2.3.2 GPT 分区扩展
RK 部分 SDK 方案支持在 u-boot 中解析 GPT 并生成 MTD mtdparts 所需的信息,最终通过 cmdline 传递给内核,可以通过查阅 “芯片对应分区扩展支持” 章节确认对应芯片平台。
分区表要使用GPT表,即parameter.txt 文件中,配置如下字段
TYPE: GPT
2.4 Vendor Storage
u-boot defconfig 配置:
CONFIG_MTD_BLK = y 时默认开启。
u-boot 相关代码:
arch/arm/mach-rockchip/vendor.c
kernel defconfig 配置:
CONFIG_ROCKCHIP_MTD_VENDOR_STORAGE=y
代码:
drivers/soc/rockchip/mtd_vendor_storage.c
分区配置:
添加分区 “vnvm”。
分区规划建议:
vnvm 跟在 IDB 分区后,size 建议为 4 flash block
3. OTA
3.1 镜像来源
OTA 仅支持预制作镜像,镜像制作参考“烧录器烧录” “制作镜像” 相关章节。
3.2 Shell 命令升级 MTD 分区
首先要确定,如果 MTD 分区内的镜像使用 UBIFS 文件系统,要参考 “Shell 命令升级 UBIFS 镜像分区”章节,所以该 MTD 分区主要针对 IDB、u-boot、kernel 等只读没有文件系统的固件分区。
u-boot SLC Nand
nand info:
nand info
nand erase:
nand erase off size
off:block size 对齐,单位为 byte,仅支持十六进制,不计入 oob size,例如 block 128KB data size + 8KB oob size 计算值为 128KB size:block size 对齐,单位为 byte,仅支持十六进制,不计入 oob size,例如 block 128KB data size + 8KB oob size 计算值为 128KB
nand write:
nand write.raw[.noverify] - addr off|partition [count]
addr:memory 地址,仅支持十六进制off|partition:page size 对齐,单位为 byte,仅支持十六进制,不计入 oob size,例如 block 128KB data size + 8KB oob size 计算值为 128KB count:单位为 page,仅支持十六进制,计入 oob size,例如 page 为 0x800 Byte data size + 0x80 Byte oob size 则 count 计算公式为 file_size / 0x880默认带写回读 verify
nand read:
nand read.raw - addr off|partition [count]
addr:memory 地址,仅支持十六进制off|partition:page size 对齐,单位为 byte,仅支持十六进制,不计入 oob size,例如 block 128KB data size + 8KB oob size 计算值为 128KB count:单位为 page,仅支持十六进制,计入 oob size,例如 page 为 0x800 Byte data size + 0x80 Byte oob size 则 count 计算公式为 file_size / 0x880
针对一个分区的升级,建议操作顺序:
tftp 0x4000000 rootfs.img
nand erase 0x600000 0x200000 /* 升级分区时先擦除整个分区 */
nand write.raw 0x4000000 0x600000 0x1000
kernel SLC Nand
flash_erase:
flash_erase /* 例如: flash_erase /dev/mtd1 0 0 */
nanddump:
nanddump -o -n -p --bb=skipbad /dev/mtd3
--bb=skipbad:跳过坏块-o:读出 oob 数据-n:读数据不带 ecc
nandwrite:
nandwrite -o -n -p /dev/mtd3 /rockchip_test/rockchip_test.sh
-o:输入文件带 oob 数据-n:写数据不带 ecc
针对一个分区的升级,建议操作顺序:
flash_erase /dev/mtd4 0 0 /* 升级分区时先擦除整个分区 */
nandwrite -o -n -p /dev/mtd3 /userdata/boot.img
sync
nanddump -o -n -p --bb=skipbad /userdata/boot_read.img
md5sum /userdata/boot_read.img ... /* 建议添加校验 */
u-boot SPI Nand
SPI Nand 无法支持 nand cmd 命令,可选用 cmd/mtd.c 接口,依旧能跳过坏块。
mtd erase:
mtd erase <name> <off> <size>
name:spi-nand0 for SPI Nand mtd devices off:page size 对齐,单位为 byte,仅支持十六进制size 对齐,单位为 byte,仅支持十六进制
mtd write:
mtd write <name> <addr> <off> <size>
name:spi-nand0 for SPI Nand mtd devices addr:memory 地址,仅支持十六进制off:page size 对齐,单位为 byte,仅支持十六进制size 对齐,单位为 byte,仅支持十六进制
mtd read:
mtd read <name> <addr> <off> <size>
name:spi-nand0 for SPI Nand mtd devices addr:memory 地址,仅支持十六进制off:page size 对齐,单位为 byte,仅支持十六进制size 对齐,单位为 byte,仅支持十六进制
针对一个分区的升级,建议操作顺序:
tftp 0x4000000 rootfs.img
mtd erase spi-nand0 0x600000 0x200000 /* 升级分区时先擦除整个
分区 */
mtd write spi-nand0 0x4000000 0x600000 0x200000
kernel SPI Nand
flash_erase:
flash_erase /* 例如: flash_erase /dev/mtd1 0 0 */
nanddump:
nanddump --bb=skipbad /dev/mtd3
--bb=skipbad:跳过坏块
nandwrite:
nandwrite -p /dev/mtd3 /rockchip_test/rockchip_test.sh
针对一个分区的升级,建议操作顺序:
flash_erase /dev/mtd4 0 0 /* 升级分区时先擦除整个分区 */
nandwrite -p /dev/mtd3 /userdata/boot.img
sync
nanddump -p --bb=skipbad /userdata/boot_read.img
md5sum /userdata/boot_read.img ... /* 建议添加校验 */
3.3 Shell 命令升级 UBIFS 镜像分区
参考 "UBIFS 文件系统" -> "UBIFS OTA" 章节。
3.4 函数接口升级 MTD 分区
首先要确定,如果 MTD 分区内的镜像使用 UBIFS 文件系统,要参考 “Shell 命令升级 UBIFS 镜像分区”章节,所以该 MTD 分区主要针对 IDB、u-boot、kernel 等只读没有文件系统的固件分区。
u-boot
建议参考 drivers/mtd/nand/nand_util.c,使用有坏块识别的读写擦除接口。
对于数据量较少的一次完整写行为(建议每次上电写数据量少于 2KB),可以考虑使用 RK SDK中 mtd 转 block 设备相应的接口,源码 drivers/mtd/mtd_blk.c,该 block 抽象接口有以下特点:无论单次写请求的数据量多大,都会擦除数据对应的 flash block,所以对于零碎且频繁的写行为如果调用该接口将会影响 flash 的寿命。
kernel
建议参考 ./miscutils/nandwrite.c ./miscutils/flash_eraseall.c,使用有坏块识别的读写擦除接口。
user
原则上依旧是参考 ./miscutils/nandwrite.c ./miscutils/flash_eraseall.c,结合 mtd 设备阶段支持的系列 ioctrl命令,完成有坏块识别的读写擦除应用代码。
mtd device 支持的 ioctrl 选项在 include/uapi/mtd/mtd-abi.h 中。
4. 文件系统
4.1 UBIFS 文件系统
4.1.1 简介
UBIFS 是 Unsorted Block Image File System 的简称,常应用于 raw nand 上的文件系统支持,作为 jffs2 的后继文件系统之一。UBIFS 通过 UBIFS 子系统处理与 MTD 设备之间动作。
4.1.2 配置
内核支持:
CONFIG_MTD_UBI=y
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UBIFS_FS_LZO=y /* 建议选用 lzo 压缩 */
4.1.3 镜像制作及挂载
4.1.3.1 预制作镜像
命令详细说明
Usage: mkfs.ubifs [OPTIONS] target
Make a UBIFS file system image from an existing directory tree
Examples:
Build file system from directory /opt/img, writting the result in the ubifs.img
file
mkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img
The same, but writting directly to an UBIFS volume
mkfs.ubifs -r /opt/img/dev/ubi0_0
Creating an empty UBIFS filesystem on an UBIFS volume
mkfs.ubifs/dev/ubi0_0
Options:
-r, -d, --root=DIR build file system from directory DIR, 待制作的文件系统目
录
-m, --min-io-size=SIZE minimum I/O unit size,最小输入输出大小, NAND FLASH 的最小
读写单元,一般为 page size,有4096或 2048
-e, --leb-size=SIZE logical erase block size 逻辑可擦出块大小,为 block size-
2x (page size),如 block_size 256KB page_size 2KB 应设置 -e 258048,如 block_size
128KB page_size 2KB 应设置 -e 126976
-c, --max-leb-cnt=COUNT maximum logical erase block count 最大逻辑可擦出块数目,
autoresize 时文件系统的的上限
-o, --output=FILE output to FILE 输出文件名
-j, --jrn-size=SIZE journal size
-R, --reserved=SIZE how much space should be reserved for the super-user
-x, --compr=TYPE compression type - "lzo", "favor_lzo", "zlib" or
"none" (default: "lzo")
-X, --favor-percent may only be used with favor LZO compression and
defines how many percent better zlib should compress to make mkfs.ubifs use zlib
instead of LZO (default 20%)
-f, --fanout=NUM fanout NUM (default: 8)
-F, --space-fixup file-system free space has to be fixed up on first
mount(requires kernel version 3.0 or greater),如果是通过 u-boot 烧写需要使能此功能。
-k, --keyhash=TYPE key hash type - "r5" or "test" (default: "r5")
-p, --orph-lebs=COUNT count of erase blocks for orphans (default: 1)
-D, --devtable=FILE use device table FILE
-U, --SquashFS-uids SquashFS owners making all files owned by root
-l, --log-lebs=COUNT count of erase blocks for the log (used only for
debugging)
-v, --verbose verbose operation
-V, --version display version information
-g, --debug=LEVEL display debug information (0 - none, 1 - statistics, 2
- files, 3 - more details)
-h, --help display this help text
流程
- 制作 UBIFS 镜像(通常只需配置以下参数)
mkfs.ubifs -F -d rootfs_dir -e real_value -c real_value -m real_value -v -o
rootfs.ubifs
- 制作为 flash 烧写格式
ubinize -o ubi.img -m 2048 -p 128KiB ubinize.cfg
-p:block size。-m:NAND FLASH 的最小读写单元,一般为 page size -o:输出的 ubi.img 文件
其中,ubinize.cfg 配置:
[ubifs-volumn]
mode=ubi
image=rootfs.ubifs
vol_id=0
vol_type=dynamic
vol_alignment=1
vol_name=ubifs
vol_flags=autoresize
mode=ubi:是强制参数,当前不能输入别的值,保留为以后扩展功能image=out/rootfs.ubifs:此文件为源文件vol_id=0:表示卷的 ID,UBI 镜像可能包含多个卷,这个用来区别不同的卷vol_type=dynamic:表示当前卷类型是可读写的,只读为 static vol_name=ubifs:卷的名称vol_flags=autosize:表示卷的大小是可扩展的
实例
page size 2KB,page per block 64,即 block size 128KB,分区 size 64MB:
mkfs.ubifs -F -d /path-to-
it/buildroot/output/rockchip_rv1126_rv1109_spi_nand/target -e 0x1f000 -c 0x200 -m
0x800 -v -o rootfs.ubifs
ubinize -o ubi.img -m 2048 -p 128KiB ubinize.cfg
page size 2KB,page per block 128,即 block size 256KB,分区 size 64MB:
mkfs.ubifs -F -d /path-to-
it/buildroot/output/rockchip_rv1126_rv1109_spi_nand/target -e 0x3f000 -c 0x100 -m
0x800 -v -o rootfs.ubifs
ubinize -o ubi.img -m 2048 -p 256KiB ubinize.cfg
page size 4KB,page per block 64,即 block size 256KB,分区 size 64MB:
mkfs.ubifs -F -d /path-to-
it/buildroot/output/rockchip_rv1126_rv1109_spi_nand/target -e 0x3e000 -c 0x100 -m
0x1000 -v -o rootfs.ubifs
ubinize -o ubi.img -m 0x1000 -p 256KiB ubinize.cfg
多卷镜像实例
以 page size 2KB,page per block 64,即 block size 128KB,分区大小 8MB oem 和分区大小 8MB userdata复合的多卷分区为例:
mkfs.ubifs -F -d oem -e 0x1f000 -c 0x40 -m 0x800 -v -o oem.ubifs
mkfs.ubifs -F -d userdata -e 0x1f000 -c 0x40 -m 0x800 -v -o userdata.ubifs
ubinize -o oem_userdata.img -p 0x20000 -m 2048 -s 2048 -v
ubinize_oem_userdata.cfg
设置 ubinize_oem_userdata.cfg 如下:
[oem-volume]
mode=ubi
image=oem.ubifs
vol_id=0
vol_size=8MiB
vol_type=dynamic
vol_name=oem
[userdata-volume]
mode=ubi
image=userdata.ubifs
vol_id=1
vol_size=8MiB
vol_type=dynamic
vol_name=userdata
vol_flags=autoresize
挂载分区:
ubiattach /dev/ubi_ctrl -m 4 -d 4 -b 5
mount -t ubifs /dev/ubi4_0 /oem
mount -t ubifs /dev/ubi4_1 /uesrdata
注意:
多卷中的独立分区无法单独简单升级,即 flash 读写接口直接升级多卷中特定卷,所以多卷内的分区 OTA 需求和频率应该相近
4.1.3.2 空分区镜像制作
ubiformat -y /dev/mtd4
ubiattach /dev/ubi_ctrl -m 4 -d 4
ubimkvol /dev/ubi4 -N userdata -m /* -N 指定卷名,-m 将分区设备 autorisize 可动态调整
到最大 */
4.1.3.3 UBIFS 分区命令挂载
将 MTD 设备连接到 UBI 设备:
ubiattach /dev/ubi_ctrl -m 4 -d 4
-m:指定 mtd 分区序号
-d:绑定后的 ubi 设备编号,建议与 mtd 分区序号一致
-b, --max-beb-per1024:每1024个eraseblock预期的最大坏块数,注意:
- 不带参数,默认为 20 2. 分区镜像预制作:分区冗余 flash block < --max-beb-per1024 实际值 < --max-beb-per1024 设定值,即实际值可能比设定值小3. 命令制作空分区为 UBI 镜像:--max-beb-per1024 实际值等于设定值4. SDK 默认值可设定为 10(可能旧版本 SDK 该值未设定)5. 如需优化空间,请灵活设定该值:4 + 分区所占 block 数 * 1%,例如:flash block size 128KB,oem 空间大小 16MB,占 128 flash block,可以考虑填值 5
mount -t ubifs /dev/ubi4_0 /oem
4.1.3.4 UBIFS 分区自动挂载
ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs
4.1.3.5 UBI 镜像分区损耗
UBI 镜像挂载文件系统后有效空间小于分区大小,主要存在 UBIFS 冗余信息和坏块替换所需的预留块的损耗。
精确计算
UBI overhead = (B + 4) * SP + 0 * (P - B - 4) /* 该空间用户无法获取 */
P - MTD 设备上物理除块的总数SP - 物理擦除块大小,通常为128KB或 256KB
SL - 逻辑擦除块,即 mkfs 时 -e 参数值,通常为 block_size - 2 * page_size
B - 为坏块替换预留的 f1ash blocks,与 ubiattach- b参数相关
O - 与以字节为单位存储EC和VID文件头有关的开销, i.e. 0 = SP - SL
通用案例1
flash block size 128KB, page size 2KB,128 MB size, ubiattach -b 预留默认 20;
SP = block size = 128KB
SL = 128kb - 2 * 2KB = 124KB
B = --max-beb-per1024 * n_1024 = 20 * 1 = 20
O = 128KB -124KB = 4KB
UBI overhead = (20 + 4) * 128KB + 4KB * (P - 20 - 4) = 2976KB + 4KB * P
以对应分区为 32MB 为例,即 P = 256,那么最终损耗为 UBI overhead = 2976KB + 4KB * 256 = 4000KB
通用案例2
flash block size 128KB, page size 2KB,256 MB size, ubiattach -b 预留默认 20;
SP = block size = 128KB
SL = 128kb - 2 * 2KB = 124KB
B = --max-beb-per1024 * n_1024 = 20 * 2 = 40
O = 128KB -124KB = 4KB
UBI overhead = (40 + 4) * 128KB + 4KB * (P - 40 - 4) = 5456KB + 4KB * P
以对应分区为 32MB 为例,即 P = 256,那么最终损耗为 UBI overhead = 5456KB + 4KB * 256 = 6456KB
详细参考:Flash space overhead 章节http://www.linux-mtd.infradead.org/doc/ubi.html#L_overhead
4.1.4 UBI Block 支持 SquashFS
内核配置
+CONFIG_MTD_UBI_BLOCK=y
dts 指定 rootfs
dts 中bootargs参数指定了cmdline中相关ubi的参数。
- ubi.mtd=4 : 选择 MTD 设备(从0开始)
- ubi.block=0,rootfs : "rootfs" 是 vol_name (参考 ubinize.cfg), block=0 指定了
ubi block的序号
- root=/dev/ubiblock0_0 : 指定 rootfs 分区名;由 ubi block 驱动根据 ubi.block 参数生
成的块设备
- rootfstype=squashfs : 指定文件系统类型
实例参考:
ubi.mtd=3 ubi.block=0,rootfs root=/dev/ubiblock0_0 rootfstype=squashfs
注意:
- 如果 mtd 分区由 u-boot 解析 GPT 获取,则与 parameter.txt 中的分区一一对应,从 mtd0 或者mtdblock0 开始计数;2. mtd 为 char 设备,mtdblock 为 block 设备
制作 SquashFS UBI volume
Buildroot 默认会打包 SquashFS image。如需要另行打包,可使用mksquashfs命令,例如:
sudo mksquashfs squashfs-root/ squashfs.img -noappend -always-use-fragments
使用ubinize工具将 SquashFS 镜像打包成ubi image。
首先生成ubinize.cfg文件:
cat > ubinize.cfg << EOF
[ubifs]
mode=ubi
vol_id=0
vol_type=static
vol_name=rootfs
vol_alignment=1
vol_flags=autoresize
image=/data/rk/projs/rv1126/sdk/buildroot/output/rockchip_rv1126_robot/images/roo
tfs.squashfs
EOF
其中:
vol_type 为 static 指定为只读image 指定 SquashFS image 的路径
然后使用ubinize打包image:
ubinize -o rootfs.ubi -p 0x20000 -m 2048 -s 2048 -v ubinize.cfg
-p:指定flash的物理擦除块大小
-m:指定flash的最小输入输出单元,当为nor flash时,此值应指定为1,当为nand flash时此值应指定为页面大小
-s:指定子页大小,当为nor flash时,此值应指定为1,当为nand flash时需指定此值为nand flash的子页大小
参数
输出 rootfs.ubi 文件即升级所用文件。
注意:
Nand 产品使用开源方案应将 SquashFS 挂载在 UBI block 上而非 mtdblock,因为 mtdblock 没有加入坏块探测,所以无法跳过坏块.
手动挂载 UBI block 参考
ubiattach /dev/ubi_ctrl -m 4 -d 4 /* 先挂载 UBI 设备 */
ubiblock -c /dev/ubi4_0 /* UBI 设备上扩展 UBI block 支持 */
mount -t squashfs /dev/ubiblock4_0 /oem
4.1.5 镜像空间大小优化
通过以上描述可知,主要通过以下三点来优化镜像可用空间:
- 选择合适的 --max-beb-per1024 参数,参考 “命令制作空分区 UBI 镜像及镜像挂载” 章节的 “-b 参数详述” 第 5 点2. 使用 UBI 多卷技术来共享部分 UBIFS 冗余开销,参考 “镜像制作” 中多卷制作说明3. 使用 UBI block 支持下的 SquashFS,参考 “UBI Block 支持 SquashFS” 章节
UBIFS 最小分区:
Minimum block num = 4(固定预留) + B + 17 /* B - 为坏块替换预留的 f1ash blocks,与
ubiattach - b 参数相关,UBIFS_MIN_LEB_CNT 等于 17 */
可通过 ubiattach 时打印 log 来判断,例如:
ubi4: available PEBs: 7, total reserved PEBs: 24, PEBs reserved for bad PEB
handling: 20 /* B = 20 */
如果分区 available PEBs + total reserved PEBs < Minimum block num,则挂载时会报错:
mount: mounting /dev/ubi4_0 on userdata failed: Invalid argument
4.1.6 UBIFS OTA
升级使用 UBIFS 的分区应使用 ubiupdatevol 工具,参考,命令:
ubiupdatevol /dev/ubi1_0 rootfs.ubifs
注意:
rootfs.ubifs 为 mkfs.ubifs 命令所制作的镜像,非 ubinize 制作的最终烧录镜像
4.1.7 U-Boot 下支持 UBIFS
u-boot 下 UBIFS 仅支持文件读操作,不支持文件写或删除操作。
SLC Nand 补丁参考
参考 RK3308 支持,补丁如下:
CONFIG_CMD_UBI=y
diff --git a/include/configs/rk3308_common.h b/include/configs/rk3308_common.h
index 1c2b9e4461..bc861acde8 100644
--- a/include/configs/rk3308_common.h
+++ b/include/configs/rk3308_common.h
@@ -57,6 +57,9 @@
#define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_ROCKUSB_G_DNL_PID 0x330d
+#define MTDIDS_DEFAULT "nand0=rk-nand"
+#define MTDPARTS_DEFAULT "mtdparts=rk-
nand:0x100000@0x400000(uboot),0x100000@0x500000(trust),0x600000@0x600000(boot),0x
3000000@0xc00000(rootfs),0x1200000@0x4000000(oem),0x9f60000@0x6000000(userdata)"
+
#ifdef CONFIG_ARM64
#define ENV_MEM_LAYOUT_SETTINGS \
"scriptaddr=0x00500000\0" \
SPI Nand 补丁参考
参考 RK3568 支持,补丁如下:
diff --git a/include/configs/rk3568_common.h b/include/configs/rk3568_common.h
index cce44b52a8..eb93455c62 100644
--- a/include/configs/rk3568_common.h
+++ b/include/configs/rk3568_common.h
@@ -92,6 +92,9 @@
"run distro_bootcmd;"
#endif
+#define MTDIDS_DEFAULT "spi-nand0=spi-nand0"
+#define MTDPARTS_DEFAULT "mtdparts=spi-
nand0:0x100000@0x400000(vnvm),0x440000@0x500000(uboot),0x1600000@0xa00000(boot),0
x4400000@0x2000000(rootfs),0x1b60000@0x6400000(userdata)"
+
/* rockchip ohci host driver */
#define CONFIG_USB_OHCI_NEW
#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 1
(END)
menuconfig 开启宏配置
#define CONFIG_CMD_UBI = y
挂载命令
以 rootfs 分区为例,详细参考 doc/README.ubi。
mtdpart
ubi part rootfs
ubifsmount ubi0:rootfs
ubifsls
4.2 JFFS2 文件系统支持
4.2.1 简介
JFFS2 的全名为 Journalling Flash FileSystem Version 2(闪存日志型文件系统第 2 版),其功能就是管理在 MTD 设备上实现的日志型文件系统。与其他的存储设备存储方案相比,JFFS2 并不准备提供让传统文件系统也可以使用此类设备的转换层。它只会直接在 MTD 设备上实现日志结构的文件系统。JFFS2 会在安装的时候,扫描 MTD 设备的日志内容,并在 RAM 中重新建立文件系统结构本身。
4.2.2 配置
内核配置:
CONFIG_JFFS2_FS=y
4.2.3 镜像制作
参考以下是实例:
mkfs.jffs2 -r data/-o data.jffs2 -e 0x10000 --pad=0x400000 -s 0x1000 -n
Options:
--pad [=SIZE] Pad output to SIZE bytes with 0xFF. If SIZE is
not specified, the output is padded to the end of
the final erase block
-r, -d, --root=DIR Build file system from directory DIR (default: cwd)
-s, --pagesize=SIZE Use page size (max data node size) SIZE.
Set according to target system's memory management
page size (default: 4KiB)
-e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)
-n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock
说明:
--pad:定为与分区大小一致-e:erase size 设置为 64KB,内核版本 5.10 后可以设置为 4KB -s:默认设置为 4KB
5. PC 工具烧录
5.1 PC 工具烧录 —— GPT 分区扩展
工具版本要求:
AndroidTools 工具版本必须在 V2.7.8 或者之上。upgrade_tools 应在 V1.5.6 或者之上
特殊逻辑处理:
Nand 设备 PC 工具烧录会自动拷贝多份 IDB 固件在 block 1~ block 7,对应如下:
page size 2KB flash 前1MB 为 gpt 分区和 IDB 空间
page size 4KB flash 前2MB 为 gpt 分区和 IDB 空间
Nor 设备 PC 工具烧录会做 IDB 固件双备份,对应如下:
64KB 处存放第一份
第一份后紧接着存放第二份 IDB,size 对齐为 64KB
开发过程中,如果 gpt 分区做了调整,升级固件请转到 maskrom mode 下升级,否则可能导致UBIFS 挂载异常
烧写工具支持 UBIFS 镜像烧写,识别到固件为 UBIFS,分区,再烧写该分区
6. 烧录器烧录
6.1 SPI Nand 镜像烧录 —— GPT 分区扩展
6.1.1 SPI Nand 制作烧录镜像
输入文件:SDK 输出的用于 PC 工具烧录的镜像
[/IMAGES] tree
.
├── parameter.txt
├── MiniLoaderAll.bin
├── uboot.img
├── boot.img
├── rootfs.img
├── oem.img
└── update.img // 用以制作烧录镜像
制作镜像
工具 programmer_image_tool 在 SDK rkbin/ 目录下,命令说明如下:
./tools/programmer_image_tool --help
NAME
programmer_image_tool - creating image for programming on flash
SYNOPSIS
programmer_image_tool [-iotbpsvh]
DESCRIPTION
This tool aims to convert firmware into image for programming
From now on,it can support slc nand(rk)|spi nand|nor|emmc.
OPTIONS:
-i input firmware
-o output directory
-t storage type,range in[SLC|SPINAND|SPINOR|EMMC]
-b block size,unit KB
-p page size,unit KB
-s oob size,unit B
-2 2k data in one page
-l using page linked l
例如: rv1126 block size 128KB page size 2KB flash:
./tools/programmer_image_tool -i update.img -b 128 -p 2 -t spinand -o out
input firmware is 'update.img'
block size is '128'
page size is '2'
flash type is 'spinand'
output directory is 'out'
writing idblock...
start to write partitions...gpt=1
preparing gpt saving at out/gpt.img
writing gpt...OK
preparing trust saving at out/trust.img
writing trust...OK
preparing uboot saving at out/uboot.img
writing uboot...OK
preparing boot saving at out/boot.img
writing boot...OK
preparing rootfs saving at out/rootfs.img
writing rootfs...OK
preparing recovery saving at out/recovery.img
writing recovery...OK
preparing oem saving at out/oem.img
writing oem...OK
preparing userdata:grow saving at out/userdata:grow.img
writing userdata:grow...OK
preparing misc saving at out/misc.img
writing misc...OK
creating programming image ok.
说明:
4KB page size programmer_image_tool 添加 -2 参数
输出文件:用于烧录器烧的镜像
out
├── boot.img
├── gpt.img
├── idblock.img // 自行根据需求制作 idblock_mutli_copies.img 的多备份镜像
├── misc.img
├── oem.img
├── recovery.img
├── rootfs.img
├── trust.img
├── uboot.img
└── userdata.img
注释:
IDB 多备份命令参考,通常双备份即可:
cat out/idblock.img > out/idblock_mutli_copies.img // 1 copy
cat out/idblock.img >> out/idblock_mutli_copies.img // 2 copies
6.1.2 SPI Nand 烧录器烧录
烧录地址
假定 block size 为 128KB 的 flash,PC 烧录工具及相应烧录器镜像烧录信息对比如下:
| 烧录器镜像源文 件:SDK 默认输出 镜像 | PC 烧录 工具扇区 地址 | 烧录器镜像 | 烧录 器块 起始 地址 | 结束 地址 | 固 件 大 小 | 备 注 |
|---|---|---|---|---|---|---|
| paramter.txt | 0 | gpt.img | 0x0 | 0x1 | 0x1 | Note 1 |
| MiniLoaderAll.bin | 0 | idblock mutli copies.img _ _ | 0x1 | 0x7 | 0x6 | Note 2 |
| uboot.img | 0x2000 | uboot.img | 0x20 | 0x47 | 0x20 | Note 3 |
| boot.img | 0x4800 | boot.img | 0x48 | 0xa0 | 0x50 | |
| ... | ... | ... | ... | |||
| xxx.img | 0x3E000 | xxx.img | 0x3e0 | 0x3fb | 0x18 | Note 4 |
表格注释:
-
gpt.img 固定烧录在 block 0,backup gpt 由软件在 u-boot 下自动修复生成;
-
idblock_mutli_copies.img 固定烧录在 block1,要求结束地址为 block 7,镜像要求小于分区大小(预留一个块做坏块替换);
-
除 gpt.img 和 idblocks.img 由特定的烧录地址要求,其他固件按照 parameter.txt 中的地址烧录,sector 单位为 512B/s,所以烧录器块地址 = sectors * 512B / block_size,简化换算:
128KB block size:sectors / 0x100;256KB block size:sectors / 0x200。
除了 gpt.img,其余固件均应比分区小 1~2 个 block size,以便冗余块替换分区内可能存在的坏块;
- 尾部预留 4 flash block size 给坏块表空间,所以用户分区不应达到该区间,可以考虑定义 reverved分区以避免用户使用或将来误用。
注意事项
- 由于 RK spinand 主控 FSPI(旧称SFC)没有集成 ECC 模块,所以需要依赖颗粒自身的 ECC 功能,因此烧录器烧录时所用镜像不带 oob 数据,oob 空间由烧录器自行填充全 FF,并在烧录器工具界面中使能 spinand device 端的 ECC 功能;2. 非空片烧录,烧录器应先擦除所有 flash 好块再烧录镜像;3. 烧录器要开启烧录校验功能。
6.2 SLC Nand 镜像烧录 —— GPT 分区扩展
6.2.1 SLC Nand 制作烧录镜像
输入文件:SDK 输出的用于 PC 工具烧录的镜像
[/IMAGES] tree
.
├── parameter.txt
├── MiniLoaderAll.bin
├── uboot.img
├── boot.img
├── rootfs.img
├── oem.img
└── update.img // 用以制作烧录镜像
制作镜像
例如: rv1126 block size 128KB page size 2KB oob size 128 flash:
./tools/programmer_image_tool -i update.img -b 128 -p 2 -s 128 -t slc -o out
input firmware is 'update.img'
block size is '128'
page size is '2'
oob size is '128'
flash type is 'slc'
2k data page on.
output directory is 'out'
writing idblock...
start to write partitions...gpt=1
preparing gpt saving at out/gpt.img
writing gpt...OK
preparing trust saving at out/trust.img
writing trust...OK
preparing uboot saving at out/uboot.img
writing uboot...OK
preparing boot saving at out/boot.img
writing boot...OK
preparing rootfs saving at out/rootfs.img
writing rootfs...OK
preparing recovery saving at out/recovery.img
writing recovery...OK
preparing oem saving at out/oem.img
writing oem...OK
preparing userdata:grow saving at out/userdata:grow.img
writing userdata:grow...OK
preparing misc saving at out/misc.img
writing misc...OK
creating programming image ok.
说明:
RK3326/PX30/RK3568 programmer_image_tool 添加 -l 参数来修改链表链接方式RV1126/RK3326/PX30/RK3308 使用 4KB page size 颗粒时 programmer_image_tool 添加 -2 参数
输出文件:用于烧录器烧的镜像
out
├── boot.img
├── gpt.img
├── idblock.img // 自行根据需求制作 idblock_mutli_copies.img 的多备份镜像
├── misc.img
├── oem.img
├── recovery.img
├── rootfs.img
├── trust.img
├── uboot.img
└── userdata.img
注释:
IDB 多备份命令参考,通常备份即可:
cat out/idblock.img > out/idblock_mutli_copies.img // 1 copy
cat out/idblock.img >> out/idblock_mutli_copies.img // 2 copies
6.2.2 SLC Nand 烧录器烧录
烧录地址
假定 block size 为 128KB 的 flash,PC 烧录工具及相应烧录器镜像烧录信息对比如下:
| 烧录器镜像源文 件:SDK 默认输出 镜像 | PC 烧录 工具扇区 地址 | 烧录器镜像 | 烧录 器块 起始 地址 | 结束 地址 | 固 件 大 小 | 备 注 |
|---|---|---|---|---|---|---|
| paramter.txt | 0 | gpt.img | 0x0 | 0x1 | 0x1 | Note 1 |
| MiniLoaderAll.bin | 0 | idblock mutli copies.img _ _ | 0x1 | 0x7 | 0x6 | Note 2 |
| uboot.img | 0x2000 | uboot.img | 0x20 | 0x47 | 0x20 | Note 3 |
| boot.img | 0x4800 | boot.img | 0x48 | 0xa0 | 0x50 | |
| ... | ... | ... | ... | |||
| xxx.img | 0x3E000 | xxx.img | 0x3e0 | 0x3fb | 0x18 | Note 4 |
表格注释:
-
gpt.img 固定烧录在 block 0;
-
idblock_mutli_copies.img 固定烧录在 block1,要求结束地址为 block 7,镜像要求小于 7 个 blocks(预留一个块做坏块替换);
-
除 gpt.img 和 idblocks.img 由特定的烧录地址要求,其他固件按照 parameter.txt 中的地址烧录,sector 单位为 512B/s,所以烧录器块地址 = sectors * 512B / block_size,简化换算:
128KB block size:sectors / 0x100;
256KB block size:sectors / 0x200。
除了 gpt.img,其余固件均应比分区小 1~2 个 block size,以便冗余块替换分区内可能存在的坏块;
- 尾部预留 4 flash block size 给坏块表空间,所以用户分区不应达到该区间,可以考虑定义 reverved分区以避免用户使用或将来误用。
注意事项
- 所有镜像带 oob 数据;2. 非空片烧录,烧录器应先擦除所有 flash 好块再烧录镜像;3. 烧录器要开启烧录校验功能。
6.3 SPI Nor 镜像烧录 —— GPT 分区扩展
6.3.1 SPI Nor 制作烧录镜像
输入文件:SDK 输出的用于 PC 工具烧录的镜像
[/IMAGES] tree
.
├── parameter.txt
├── MiniLoaderAll.bin
├── uboot.img
├── boot.img
├── rootfs.img
├── oem.img
└── update.img // 用以制作烧录镜像
制作镜像
例如:
./tools/programmer_image_tool -i update.img -t SPINOR -o ./out
input firmware is 'update.img'
flash type is 'SPINOR'
output directory is './out'
writing idblock...
start to write partitions...gpt=1
preparing gpt at 0x00000000
writing gpt...OK
preparing trust at 0x00002800
writing trust...OK
preparing uboot at 0x00002000
writing uboot...OK
preparing boot at 0x00009800
writing boot...OK
preparing rootfs at 0x0000c800
writing rootfs...OK
preparing recovery at 0x00003800
writing recovery...OK
preparing misc at 0x00003000
writing misc...OK
creating programming image ok.
输出文件:用于烧录器烧的镜像
tree
.
└── out_image.img
6.3.2 SPI Nor 烧录器烧录
programmer_image_tool 输出的镜像烧录到 SPI Nor 0 地址。
7. 常见问题
7.1 Nand Flash 信息
在制作 UBIFS 镜像、IDB 镜像(Pre loader)时需要通过存储颗粒手册来确认 Nand flash 相关信息,并根据选择镜像制作参数,主要包括以下:
page size,SLC Nand 通常为 2KB 或 4KB page size;page per block,SLC Nand 通常为 64 或 128;block size = page_size * page_per_block,SLC Nand 通常为 128KB,256KB;oob size,SLC Nand 通常为 64B,128B 或 256B。
在以下操作时,默认通常为 2KB page size,128KB block size 配置,如用其他颗粒,应做相应调整:
制作烧录器镜像制作使用 UBIFS 文件系统的镜像;
可以通过通过查看颗粒手册来确认 flash 信息。
7.2 IDB Layout
IDB 为 ddr.bin 和 spl.bin 的打包固件,掩膜代码后的第一级固件,其布局如下:
PC 工具升级存放在 flash block 1~7,多备份填充;烧录器烧录建议:参考 ”烧录器烧录章节“ 中的 ”烧录地址“ 说明。
8. 附录参考
[1] UBI FAQ: http://www.linux-mtd.infradead.org/faq/ubi.html
[2] UBIFS FAQ: http://www.linux-mtd.infradead.org/faq/ubifs.html#L_lebsz_mismatch
[3] MTD FAQ: http://www.linux-mtd.infradead.org/faq/general.html