【米尔 NXP i.MX93 开发板评测】 U-Boot编译与实践
本帖最后由 小麦克 于 2024-8-4 04:47 编辑# U-Boot编译与实践
从这期开始,我们从底层uboot开始,构建嵌入式Linux系统,系统的学习一下嵌入式Linux开发的整个流程。
## 环境准备
从ARM官网下载最新的交叉编译器:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
这里需要选择 `AArch64 GNU/Linux target (aarch64-none-linux-gnu)`
[交叉编译器下载地址](https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz)
在Ubuntu中安装必要的工具
```bash
sudo apt install flex bison libssl-dev gcc-aarch64-linux-gnu u-boot-tools libncurses5-dev libncursesw5-dev uuid-dev gnutls-dev
```
为了后续操作方便,写个简单的脚本`linux_imx93.sh`将`CROSS_COMPILE`变量导入到当前的环境中
```
#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-
export PATH=$PATH:/opt/tools/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu/bin
```
每次打开终端开始编译时执行一下`source linux_imx93.sh `
## IMX93启动镜像
### 镜像组成
i.MX93上电时会首先运行内部的BOOT ROM,BOOT ROM根据拨码盘或者eFUSE确定从哪个设备启动。启动的设备必须在特定的位置存储下面的镜像。
从上面的框图可以看出,启动镜像必须按照上面的要求封装起来。由于使用uboot启动linux,所以只需要把uboot的镜像按照要求封装即可。BOOT ROM负责加载uboot,uboot启动好就可以加载内核和文件系统。
好在NXP提供了`imx-mkimage` https://github.com/nxp-imx/imx-mkimage.git ,有了这个工具,可以通过一条命令将所有文件打包成`imx-boot`镜像
在 《IMX_LINUX_USERS_GUIDE.pdf》提到了打包`imx-boot`需要的物料。
从文档中得知需要如下部分:
```bash
SPL:second program loader,二级程序加载器,为 uboot 的一部分,编译 uboot 的时候会一并编译出;
U-Boot:编译 uboot 的时候一并编译出;
ATF:Arm Trusted Firmware,由 Arm 提供的项目,支持 Arm 架构上的安全启动和运行时需求;
OP-TEE:Open Portable Trusted Execution Environment,开源的可信执行环境(TEE)框架;
Sentinel Firmware:应该就是指 EdgeLock Secure Enclave (ELE) firmware;
DDR PHY Firmware:ddr 固件
```
### UBOOT编译
首先尝试使用NXP官方uboot来尝试一下,然后再用myir官方提供的uboot。
#### 官方uboot编译实践体验
> 需要提前配置好交叉编译器
```bash
git clone https://github.com/nxp-imx/uboot-imx -b lf_v2023.04
cd uboot
make distclean
make imx93_11x11_evk_defconfig
# 可选,可以删掉typec相关的支持
make menuconfig
make -j$(nproc --all)
# 编译成功,生成如下两个文件
ls -alh u-boot.bin
ls -alh ./spl/u-boot-spl.bin
```
##### ATF 编译
```bash
# 下载源码
git clone https://github.com/nxp-imx/imx-atf
cd imx-atf
git checkout lf-6.6.3-1.0.0
# 执行 make help 查看编译帮助
make help
# 从 make help 中可以知道,执行 make clean 是清除编译;
# 一般的编译命令为 make
# 所以构建 imx93 的 ATF 命令如下(配置交叉编译器的前提下)
make PLAT=imx93 bl31
# 生成的文件如下:
ls -alh build/imx93/release/bl31.bin
```
##### ELE 固件下载
```bash
# 在以下文件中,可知下载命令,和最新的分支
# https://www.nxp.com/docs/en/release-note/IMX_LINUX_RELEASE_NOTES.pdf
wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-ele-imx-0.1.1.bin
# 导出固件,firmware-ele-imx-0.1.1.bin 头部是一段 shell 脚本,赋予执行权限
chmod u+x firmware-ele-imx-0.1.1.bin
# 执行 bin 文件,同意许可后会导出固件
./firmware-ele-imx-0.1.1.bin
# 导出的文件为: mx93a1-ahab-container.img
ls -alh firmware-ele-imx-0.1.1/mx93a1-ahab-container.img
```
##### DDR 固件下载
```bash
# 在以下文件中,可知下载命令,和最新的分支
# https://www.nxp.com/docs/en/release-note/IMX_LINUX_RELEASE_NOTES.pdf
wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.23.bin
# 导出固件,firmware-imx-8.23.bin 头部是一段 shell 脚本,赋予执行权限
chmod u+x firmware-imx-8.23.bin
# 执行 bin 文件,同意许可后会导出固件
./firmware-imx-8.23.bin
# 导出的文件为: lpddr4*
ls -alh firmware-imx-8.23/firmware/ddr/synopsys/lpddr4*
```
##### imx-mkimage 工具下载
```bash
# 在以下文件中,可知 imx-mkimage 仓库
# https://www.nxp.com/docs/en/release-note/IMX_LINUX_RELEASE_NOTES.pdf
git clone https://github.com/nxp-imx/imx-mkimage.git
cd imx-mkimage
git checkout lf-6.6.3-1.0.0
```
##### 打包
将上面的生成的固件通过 `imx-mkimage` 打包成一个文件 `flash.bin`
```bash
# 拷贝 3.1 编译的 u-boot.bin 和 spl/u-boot-spl.bin 到 imx-mkimage/iMX93/ 目录
cp uboot-imx/u-boot.bin uboot-imx/spl/u-boot-spl.bin imx-mkimage/iMX93/
# 拷贝 3.2 编译的 bl31.bin 文件到 imx-mkimage/iMX93/ 目录
cp imx-atf/build/imx93/release/bl31.bin imx-mkimage/iMX93/
# 拷贝 3.3 下载的 Sentinel firmware container mx93a1-ahab-container.img 到 imx-mkimage/iMX93/ 目录
cp firmware-ele-imx-0.1.1/mx93a1-ahab-container.img imx-mkimage/iMX93/
# 拷贝 3.4 下载的 ddr 固件 lpddr4* 到 imx-mkimage/iMX93/ 目录
# 参考博客:https://xterra2.avnet.com/poc/nxp/buildroot-for-i.mx93
cp firmware-imx-8.23/firmware/ddr/synopsys/lpddr4* imx-mkimage/iMX93/
# 进入 imx-mkimage 构建 flash.bin
cd imx-mkimage
make SOC=iMX9 REV=A1 flash_singleboot
# 生成的 flash.bin 文件在 iMX93/flash.bin 路径
ls -alh iMX93/flash.bin
```
#### myir uboot
参考《MYD-LMX9X_Linux软件开发指南.pdf》4.2节,编译成功会在`output/1g`文件夹下生成 `imx-boot-myd-lmx9x-sd.bin-flash_singleboot`
## 烧录到SD卡
编译出`flash.bin` 文件,下面将SD卡(此次是64GB)插入Ubuntu系统。
从SD卡32KB开始的位置写`flash.bin` ,从8MB开始的位置格式化成FAT32`boot` 分区。
> 文档《IMX_LINUX_USERS_GUIDE.pdf》中描述,iMX93从0x8000(32KB)开始的位置启动
### SD卡设备确认
> 警告:操作时必须先确认SD卡的设备名,防止操作失误导致数据丢失!
```bash
# 查找SD卡设备名
sudo fdisk -l
Disk /dev/sda: 500 GiB, 536870912000 bytes, 1048576000 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xd6bcc382
Device Boot Start End Sectors Size Id Type
/dev/sda1* 2048 1050623 1048576 512Mb W95 FAT32
/dev/sda2 1052670 1048573951 1047521282 499.5G5 Extended
/dev/sda5 1052672 1048573951 1047521280 499.5G 83 Linux
Disk /dev/sdb: 58.27 GiB, 62562238464 bytes, 122191872 sectors
Disk model: STORAGE DEVICE
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
```
通过以上信息,可以确认SD卡盘设备名为 `/dev/sdb`
### 前半部分处理
将SD卡前面的8MB空间全部清零
```bash
dd if=/dev/zero of=/dev/sdb bs=1024 count=8096
sync
```
### 创建分区
使用fdisk工具创建`boot`分区。
新建分区`n`,类型 `p`,First sector`16384`,保存 `w`, 退出 `q`
> 注意,由于电脑配置差异,SD卡的盘符可能不一致,我这里是 `/dev/sdb`,操作不当可能会导致数据丢失。请谨慎操作
```bash
# Disk /dev/sdb: 58.27 GiB是我的SD卡
# 在 /dev/sdb 新建分区
sudo fdisk /dev/sdb
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-122191871, default 2048): 16384
Last sector, +/-sectors or +/-size{K,M,G,T,P} (16384-122191871, default 122191871):
Created a new partition 1 of type 'Linux' and of size 58.3 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```
操作完成检查确认是否出现 `/dev/sdb1`
```bash
sudo fdisk -l
Disk /dev/sdb: 58.27 GiB, 62562238464 bytes, 122191872 sectors
Disk model: STORAGE DEVICE
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
Device Boot Start End SectorsSize Id Type
/dev/sdb1 16384 122191871 122175488 58.3G 83 Linux
```
格式化成`FAT32`分区,分区名`boot`
```bash
sudo mkfs.vfat -F 32 -n "boot" /dev/sdb1
```
将之前编译好的`flash.bin`写入SD卡32KB开始的位置
```bash
dd if=flash.bin of=/dev/sdb bs=32K seek=1 conv=fsync
sync
```
这样SD卡就处理好了。后面`flash.bin`如果有更新,只要执行最后一步就行,之前的boot分区不需要动了。
将SD卡插入开发板,接上串口,开始DEBUG
启动日志
## 补充 DDR配置
从NXP官方提供的UBOOT源码编译的源码发现启动的时候识别到DDR为2GB,其实开发板只有1GB。
尝试在UBOOT中修改配置,发现无效。
uboot中比较重要和初始化相关的源文件
`common/board_f.c`
`board/freescale/imx93_evk/imx93_evk.c`
`arch/arm/mach-imx/imx9/native/soc.c`
`soc.c` 中通过读取DDR控制器的得到DDR的大小,所有上面的配置无效。
通过查阅代码,这个DDR控制器的寄存器是在 `SPL`阶段配置好的。
在 `board/freescale/imx93_evk/spl.c` `spl_dram_init`函数通过结构体`dram_timing` 拿到`DDR`的配置信息。
这个 `dram_timing` 是通过NXP的配置工具(https://www.nxp.com/design/design-center/development-boards-and-designs/i-mx-evaluation-and-development-boards/config-tools-for-i-mx-applications-processors:CONFIG-TOOLS-IMX) 生成的。配置1GB的内存,生成c配置文件覆盖`board/freescale/imx93_evk/lpddr4x_timing.c`
将修改后的uboot重新打包成`flash.bin`并烧入SD卡,重新启动开发板成功识别成1GB的内存
## 结论
我们从头构建了imx-boot,掌握了IMX镜像的原理;还学习了通过Config Tool配置内存的方法。
<p>帖子比较长,整理了pdf,有需要的可以下载。</p>
<div></div>
页:
[1]