作者:Fisher Yang,文章来源:FPGA FAE技术分享选集
前言
在上一篇中,我们完成了KPL3858 的开箱体验,并介绍了通过 OSPI + SD 卡多阶段启动进入 Linux 系统的完整流程。本篇聚焦 UFS(Universal Flash Storage) —— KPL3858 板载的高速存储介质,详细介绍 UFS 的硬件接口特性、在 Versal Gen2 上的优势,以及如何将 Linux 镜像烧录到 UFS 并从 UFS 启动。
值得一提的是,UFS 是在 Versal Gen2(第二代)上首次引入的存储接口,第一代 Versal 并不支持 UFS,这也是 Versal Gen2 在存储子系统上的重要升级之一。
注意开普勒KPL3858评估板分带UFS版本和不带UFS版本。
UFS 简介
什么是 UFS
UFS(Universal Flash Storage)是由 JEDEC 标准化的高性能闪存存储接口,最初面向智能手机等移动设备设计,现已广泛应用于汽车电子、工业嵌入式等对存储性能有较高要求的场景。
UFS 采用串行差分信号传输,基于 M-PHY + UniPro 协议栈,支持全双工通信,与 eMMC 的并行总线架构有本质区别。

UFS 硬件接口特性

UFS 的核心架构由三层组成:
1. UFS Transport Protocol(UTP)层:处理命令、数据和响应
2. UniPro 互联层:负责数据包路由和流控
3. M-PHY 物理层:提供高速串行差分信号传输

UFS 各协议栈标准速度
UFS 相对 eMMC 的优势
1. 性能大幅领先:UFS 3.1 顺序读取理论带宽可达 2.9 GB/s,随机读写 IOPS 远超 eMMC,对于需要频繁读写大量小文件的 Linux 系统来说体验差异明显。
2. 全双工通信:UFS 可以同时进行读和写操作,eMMC 同一时刻只能读或写,在多任务并发场景下 UFS 优势显著。
3. 命令队列(Command Queue):UFS 支持最多 32 条命令并发排队,控制器可以对命令重排序以优化访问效率,eMMC 的命令队列能力有限。
4. 更低功耗:UFS 支持 Auto-Hibernate 机制,空闲时自动进入低功耗状态,功耗优于 eMMC。
5. 更小的 PCB 占用:串行接口引脚数少,布线更简单,有利于高密度板卡设计。
Versal Gen2 上的 UFS 支持
Versal Gen2 的 PS(Processing System)内置了标准的 UFS Host Controller,符合 UFS 架构规范(UFSHCI),支持:
1. UFS 2.0:最高 HS-G3(High-Speed Gear 3),对称 2RX-2TX 双通道
2. UFS 3.0:最高 HS-G4(High-Speed Gear 4);在 KPL3858 上启用高速模式后默认工作在 HS-G4 Rate B 档位
3. 最多 32 个任务请求队列,8 个任务管理请求,最多 16 条 PRD 预取
4. Scatter/Gather DMA,支持大块数据传输(UPIU 包从 32 字节到 64KB)
5. Auto-Hibernate 自动低功耗进出,支持手动 Hibernate 进出
6. 支持 UFS Card Detection,支持 40-bit RMMI 数据接口
KPL3858 上的 UFS 控制器时钟配置:
1. UFS 控制器参考时钟:300MHz
2. PHY 参考时钟(外部):26MHz
3. 通道数:2 Tx + 2 Rx lanes
AMD 官方为 Versal Gen2 提供了完整的 Linux UFS 驱动(驱动名 ufshcd-versal2,基于内核标准 ufshcd 框架),已集成在 EDF Linux 镜像中,开箱即用。所需内核配置项:
CONFIG_SCSI_UFSHCD=y
CONFIG_SCSI_UFS_BSG=y
CONFIG_SCSI_UFSHCD_PLATFORM=y
CONFIG_SCSI_UFS_AMD_VERSAL2=y
开普勒 KPL3858 板载 Micron MT064GBCAVAL(64GB UFS 3.1),通过 PS 的 UFS 控制器直连,无需额外的 PHY 芯片。
UFS 烧录前的准备
UFS 逻辑单元(LU)初始化
UFS 设备出厂时,所有逻辑单元(Logical Unit,LU)默认处于禁用状态,必须先完成 LU 配置,才能像普通块设备一样访问 UFS 存储空间。
这是 UFS 与 SD 卡、eMMC 最大的使用差异之一——UFS 需要先分区初始化,才能烧录镜像。
KPL3858 上的 UFS 推荐配置为三个 LU:
1. LU0(Boot LU A):20GB,存放 Linux 根文件系统镜像,设置为 Boot LUN(bBootLunID=0x1)
2. LU1:1GB,辅助分区
3. LU2:4GB,辅助分区
UFS 启动必须满足的配置前提(UFS boot Prerequisites):

LU 初始化可以通过以下两种方式完成:
1. Vitis 裸机应用(ufspsxc_setluncfg_example.c):通过 JTAG 运行裸机程序完成 LU 配置,修改 LunEnable 和 SIZE_MB 数组字段
2. Linux 下的 ufs-utils 工具:在 Linux 系统中通过命令行读取、编辑、写回配置描述符
官方 Image Recovery Web 方式界面烧录的问题
AMD 官方Wiki上介绍了通过 Image Recovery Web 界面烧录 UFS 的方法:将 OSPI 烧录为 revB 固件后,板卡启动进入 Image Recovery Shell,通过浏览器访问 板卡IP地址:8080 的 Web 界面上传 .wic.ufs.xz 镜像文件进行烧录。
然而,在开普勒 KPL3858 上实测,通过 Image Recovery Web 上传 .wic.ufs.xz 文件烧写 UFS 时会触发 kernel panic,导致烧录失败。这是开普勒 KPL3858 无系统控制器 SOM、与官方板配置存在差异导致的兼容性问题。不过没关系,有很多方法可以烧录UFS。
下面介绍两种在开普勒 KPL3858 上可以成功烧录 UFS 的方法,感谢 AMD AE Longley 提供的帮助。
UFS 烧录方法
方法一:通过 Image Recovery Shell + ufs-utils 初始化后烧录
此方法分两个阶段:先烧录 revB 固件进入 Image Recovery Shell,用内置的 ufs-utils 完成 UFS LU 初始化;再通过预装 revA 镜像的 SD 卡启动进入 Linux 系统,用 bmaptool 将镜像烧录到 UFS。
步骤一:OSPI 烧录 revB 固件
Image Recovery Shell 功能依赖 revB 的 OSPI 固件,官方revA 固件不支持进入 Linux-based Image Recovery Shell。
参考开普勒KPL3858(一)开箱及烧录启动文章中的 OSPI 烧录方法,将 OSPI 烧录为 revB 的 boot.bin。
步骤二:上电进入 Image Recovery Shell
1. 确认 SW1 处于 OSPI 启动模式(SW1[1:4] = 开,开,开,关)
2. 连接串口(PS-UART1,波特率 115200)
3. 上电,等待系统启动进入 Image Recovery Shell
启动成功后串口会显示:
##################################################################################################
# #
#Launching to Image Recovery shell, Use 192.168.110.69:8080 to launch the Image Recovery web app.#
# #
##################################################################################################
sh-5.2#
步骤三:初始化 UFS 逻辑单元
在 Image Recovery Shell 中,使用 ufs-utils 完成 LU 初始化,分三步:
3.1 读取当前配置描述符
sh-5.2# ufs-utils desc -t 1 -D ufsconfig -p /dev/bsg/ufs-bsg0
该命令将 UFS 配置描述符以二进制格式保存到 ufsconfig 文件,同时在终端打印描述符内容。可以看到当前各 LU 的 bLUEnable、bBootLunID、dNumAllocUnits 等字段值。
3.2 用 hexedit 修改配置
使用 hexedit 编辑 ufsconfig 二进制文件,配置 3 个 LU(LU0=20GB Boot LU、LU1=1GB、LU2=4GB):
sh-5.2# hexedit ufsconfig
修改后的关键字段(以实际 hexedit 输出为参考):
00000000 E6 01 00 01 00 01 7F 00 00 00 00 01 ...
00000018 00 00 00 00 14 00 00 0C 00 00 00 00 ... ← LU0: dNumAllocUnits=0x1400(20GB)
00000030 01 00 00 00 00 00 01 00 00 0C 00 00 ... ← LU1: dNumAllocUnits=0x100(1GB)
00000048 00 00 01 00 00 00 00 00 04 00 00 0C ... ← LU2: dNumAllocUnits=0x400(4GB)

dNumAllocUnits 计算方法: dNumAllocUnits LU0 = 目标容量/(dSegmentSize × bAllocationUnitSize x 512byte) 其中 dSegmentSize=1024,bAllocationUnitSize=8 例如 20GB:20Gbyte/8 x 1024 x 512byte = 20Gbyte/4Mbyte = 0x1400
3.3 写回配置描述符
sh-5.2# ufs-utils desc -t 1 -w ufsconfig -p /dev/bsg/ufs-bsg0
写回成功后串口输出:
Config Descriptor was written to device
重要: 写回后需要重启板卡,新配置的逻辑单元才会生效。UFS LU 初始化只需做一次,后续步骤切换固件重启后即可看到新 LU 出现在 /dev 下。
步骤四:SD 卡启动进入 Linux 并烧录 UFS 镜像
UFS LU 初始化完成后,通过 SD 卡(预装 revA EDF Linux 镜像)启动进入 Linux 系统,再将 UFS 镜像烧录到 UFS。
4.1 SD 卡启动进入 Linux
将预装 revA EDF Linux 镜像的 SD 卡插入 J51 槽位,确认 SW1 处于 OSPI 启动模式(SW1[1:4] = 开,开,开,关),上电后系统通过 OSPI 加载 revA 固件,再从 SD 卡引导进入 Linux。
4.2 准备 UFS 镜像文件
进入 Linux 系统后,将 UFS 镜像文件传输到板卡本地,可通过以下方式:
1. SCP/SSH:通过以太网从主机传输(推荐,速度快)
# 在主机上执行
scp edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.xz \
edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.bmap \
amd-edf@<板卡IP>:/home/amd-edf/
2. 或将文件拷贝到 SD 卡,在 Linux 中挂载后访问
注意: UFS 专用镜像格式为 .wic.ufs.xz,与 SD 卡使用的 .wic.xz 不同,请从 AMD 官方 EDF 发布页面下载正确的 UFS 镜像。 下载地址:https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/3250586438/Downloa...
4.3 确认 UFS 设备节点
fdisk -l
UFS LU0 通常映射为 /dev/sda:
Disk /dev/sda: 20 GiB, 21474836480 bytes, 5242880 sectors
Disk model: MT064GBCAV1U31AA
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 524288 bytes
4.4 烧录 UFS 镜像
bmaptool copy --bmap edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.bmap \
edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.xz /dev/sda
或使用 bmap-writer:
xzcat edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.xz | \
bmap-writer - edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.bmap

烧录完成后,UFS 镜像写入成功。
方法二:从 JTAG/SD 卡启动 Linux 后烧录
此方法先通过standalone的例子完成 UFS LU 初始化,JTAG 或 SD 卡启动 Linux 系统,在 Linux 环境中完成镜像烧录。
步骤一:UFS LU 初始化
Vitis 裸机应用(ufspsxc_setluncfg_example.c):通过 JTAG 运行裸机程序完成 LU 配置,修改 LunEnable 和 SIZE_MB 数组字段。
步骤二:启动进入Linux
通过 JTAG 启动 Linux,或将 SD 卡烧录 EDF Linux 镜像后从 SD 卡启动。
步骤三:确认 UFS 设备节点
fdisk -l
UFS 第一个分区通常映射为 /dev/sda:
Disk /dev/sda: 20 GiB, 21474836480 bytes, 5242880 sectors
Disk model: MT064GBCAV1U31AA
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 524288 bytes
步骤三:传输镜像文件
将 UFS 镜像文件传输到板卡本地,可通过以下方式:
1. SCP/SSH:通过以太网从主机传输(推荐,速度快)
2. SD 卡:将镜像文件拷贝到 SD 卡,在 Linux 中挂载后访问
# 通过 SCP 从主机传输(在主机上执行)
scp edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.xz \
edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.bmap \
amd-edf@<板卡IP>:/home/amd-edf/
步骤四:烧录 UFS 镜像
bmaptool copy --bmap edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.bmap \
edf-linux-disk-image-amd-cortexa78-mali-common.rootfs-*.wic.ufs.xz /dev/sda
从 UFS 启动
UFS 烧录完成后,重新对KPL3858板卡上电启动,并确认启动模式。
步骤一:确认启动模式
确认 SW1 处于 OSPI 启动模式(SW1[1:4] = 开,开,开,关),这是 KPL3858 的默认多阶段启动模式:OSPI 加载 boot.bin → U-Boot 引导 → 从 UFS 加载 Linux 根文件系统。
步骤二:上电启动
上电后,串口(PS-UART1,115200)可以看到 PLM 启动日志,U-Boot 识别 UFS 设备并引导进入 Linux:
ufs-versal2-pltfm ufs@f10b0000:[RX,TX]:gear=[4,4],lane[2,2],pwr[FAST MODE, FAST MODE],rate=2
scanning bus for devices...
Device 0: (0:0) Vendor: MICRON Prod.: MT064GBCAV1U31AA Rev: 0302
Type: Hard Disk
Capacity: 20480.0 MB = 20.0 GB (5242880 x 4096)
Device 1: (0:1) Vendor: MICRON Prod.: MT064GBCAV1U31AA Rev: 0302
Type: Hard Disk
Capacity: 16384.0 MB = 16.0 GB (4194304 x 4096)
Bootmode: OSPI_MODE

UFS 启动后 Linux 系统
进入 Linux 后,可通过以下命令确认 UFS 设备正常工作:
# 查看块设备及分区
lsblk
# 查看 UFS 性能(hdparm 顺序读测试)
hdparm -tT /dev/sda
性能数据(HS-G4 Rate B,默认模式):
versal2-vek385:/home/basecamp# hdparm -tT /dev/sda
/dev/sda:
Timing cached reads: 10704 MB in 2.00 seconds = 5359.80 MB/sec
Timing buffered disk reads: 1024 MB in 0.63 seconds = 1617.36 MB/sec
顺序读取速度达到 ~1617 MB/s,相比 SD 卡(通常 20~90 MB/s)有数量级的提升,充分体现了 UFS 作为嵌入式 Linux 主存储的性能优势。
总结
UFS 是 Versal Gen2 新增的高性能存储接口,相比 eMMC 在带宽、延迟、并发性能上均有显著提升,非常适合作为嵌入式 Linux 系统的主存储介质。
通过本文介绍的两种方法均可成功完成 UFS 初始化和镜像烧录。需要注意的是,官方 Image Recovery Web 界面的上传烧录方式在开普勒 KPL3858 上存在 kernel panic 问题,建议使用本文介绍的 Shell 命令行方式烧录。
下一篇预告: 开普勒 KPL3858 LPDDR5X 介绍及性能测试 —— 详解板载 LPDDR5X 的介绍与带宽测试,敬请期待。
本文操作基于开普勒 KPL3858 评估板,软件镜像来源于 AMD 官方 EDF 发布版本。
如果您对Versal Gen2及KPL3858开发板感兴趣,欢迎联系您身边的科通FAE及Sales,也欢迎邮件联系: