STM32MP157系统移植(TF-A,U-Boot,Linux)
作者:zzssdd2
E-mail:zzssdd2@foxmail.com
〇 环境搭建
主机系统:Ubuntu 20.04.3 LTS
MPU型号:STM32MP157DAA1
参考官方板:STM32MP157D-EV1(STM32MP157D-ED1)
STM32MP1 Developer Package SDK : STM32MP15-Ecosystem-v2.1.0 release
STM32MP1 Developer Package SOURCES : STM32MP15-Ecosystem-v2.1.0 release
-
资源下载
在官网地址STM32MP1 OpenSTLinux Developer Package下载开发包资源。
-
SDK安装
将下载的开发包资源
en.SDK-x86_64-stm32mp1-openstlinux-5-4-dunfell-mp1-20-11-12.tar_v2.1.0.xz
和en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-11-12.tar_v2.1.0.xz
拷贝到Ubuntu下。-
解压SDK
$ tar xvfJ en.SDK-x86_64-stm32mp1-openstlinux-5-4-dunfell-mp1-20-11-12.tar_v2.1.0.xz
-
赋予SDK安装脚本可执行权限
$ chmod +x stm32mp1-openstlinux-5.4-dunfell-mp1-20-11-12/sdk/st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-openstlinux-5.4-dunfell-mp1-20-11-12.sh
-
执行安装命令
$ ./stm32mp1-openstlinux-5.4-dunfell-mp1-20-11-12/sdk/st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-openstlinux-5.4-dunfell-mp1-20-11-12.sh -d <安装目录绝对路径>/SDK
过程如下:
$ ./stm32mp1-openstlinux-5.4-dunfell-mp1-20-11-12/sdk/st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-openstlinux-5.4-dunfell-mp1-20-11-12.sh -d <安装目录绝对路径>/SDK ST OpenSTLinux - Weston - (A Yocto Project Based Distro) SDK installer version 3.1-openstlinux-5.4-dunfell-mp1-20-11-12 ======================================================================================================================= You are about to install the SDK to "<安装目录绝对路径>/SDK". Proceed [Y/n]? Y Extracting SDK....................................................................................................................................................................................................................done Setting it up...done SDK has been successfully set up and is ready to be used. Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g. $ . <安装目录绝对路径>/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
-
SDK环境设置
$ source <安装目录绝对路径>/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
-
确认SDK环境变量
$ echo $ARCH arm $ echo $CROSS_COMPILE arm-ostl-linux-gnueabi- # 在bash下运行该命令,实测zsh执行报错 $ $CC --version arm-ostl-linux-gnueabi-gcc (GCC) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ echo $OECORE_SDK_VERSION 3.1-openstlinux-5.4-dunfell-mp1-20-11-12
-
-
解压源码
$ tar xvfJ en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-11-12.tar_v2.1.0.xz
-
SD卡分区
因为是使用SD卡作为启动设备来验证,所以需要事先对SD卡进行分区(我的SD卡设备在Ubuntu下是sdb)。
格式化当前分区:
sudo sgdisk -Z -go /dev/sdb
创建新分区:
$ sudo sgdisk --resize-table=128 -a 1 \ -n 1:34:545 -c 1:fsbl1 \ -n 2:546:1057 -c 2:fsbl2 \ -n 3:1058:5153 -c 3:ssbl \ -n 4:5154:136225 -c 4:bootfs \ -n 5:136226: -c 5:rootfs \ -A 4:set:2 \ -p /dev/sdb -g
查看当前SD卡分区情况:
$ sudo sgdisk -p /dev/sdb Disk /dev/sdb: 61157376 sectors, 29.2 GiB Model: Multi-Card Sector size (logical/physical): 512/512 bytes Disk identifier (GUID): CE89FBB7-8211-45AE-8F5A-C6601A2EC29E Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is 61157342 Partitions will be aligned on 2-sector boundaries Total free space is 0 sectors (0 bytes) Number Start (sector) End (sector) Size Code Name 1 34 545 256.0 KiB 8300 fsbl1 2 546 1057 256.0 KiB 8300 fsbl2 3 1058 5153 2.0 MiB 8300 ssbl 4 5154 136225 64.0 MiB 8300 bootfs 5 136226 61157342 29.1 GiB 8300 rootfs
关于sgdisk工具更多信息使用命令
sgdisk --help
查看
一 TF-A移植
tf-a-stm32mp-2.2.r2-r0
目录下的README.HOW_TO.txt
文件描述了源码解压、打补丁、编译等操作
1.0 组织源码
# 解压
$ tar xvfz tf-a-stm32mp-2.2.r2-r0.tar.gz
# 进入解压后的源码目录
$ cd tf-a-stm32mp-2.2.r2
# git管理
$ test -d .git || git init . && git add . && git commit -m "tf-a source code" && git gc
# 创建开发分支
$ git checkout -b develop
# 打补丁
$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
1.1 添加自己的开发板
根据所参考的官方开发板创建自己开发板的设备树文件
$ cp ./fdts/stm32mp157d-ed1.dts ./fdts/stm32mp157d-custom.dts
$ cp ./fdts/stm32mp15xx-edx.dtsi ./fdts/stm32mp157d-custom.dtsi
1.2 修改stm32mp157d-custom.dts
文件
#include "stm32mp15xx-edx.dtsi"
改为:
#include "stm32mp157d-custom.dtsi"
model = "STMicroelectronics STM32MP157D eval daughter";
compatible = "st,stm32mp157d-ed1", "st,stm32mp157";
改为:
model = "STMicroelectronics STM32MP157D custom board";
compatible = "st,stm32mp157d-custom", "st,stm32mp157";
/* 我手上板子使用的是USART1,官方板子是UART4 */
aliases {
serial0 = &uart4;
};
改为:
aliases {
serial0 = &usart1;
};
1.3 修改stm32mp157d-custom.dtsi
文件
1.3.1 修改输出串口
&uart4 {
pinctrl-names = "default";
pinctrl-0 = <&uart4_pins_a>;
status = "okay";
};
改为:
&usart1 {
pinctrl-names = "default";
pinctrl-0 = <&usart1_pins_a>;
status = "okay";
};
1.3.2 修改外部晶振
官方板子使用的是第一种方案的有源晶振,我手上板子使用的是第三种方案的无源晶振。所以需要将以下内容删除或注释掉:
&clk_hse {
st,digbypass;
};
1.3.3 修改SD卡接口
上面是官方板子和我板子的SD卡电路图。可以看到有的功能我的板子是没有的,所以需要将设备树中sdmmc1
节点做一些删减:
&sdmmc1 {
pinctrl-names = "default";
pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
disable-wp;
st,sig-dir;
st,neg-edge;
st,use-ckin;
bus-width = <4>;
vmmc-supply = <&vdd_sd>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-ddr50;
sd-uhs-sdr104;
status = "okay";
};
修改后:
&sdmmc1 {
pinctrl-names = "default";
pinctrl-0 = <&sdmmc1_b4_pins_a>;
disable-wp;
st,neg-edge;
bus-width = <4>;
vmmc-supply = <&vdd_sd>;
status = "okay";
};
注:我手上板子的PMIC和官方板子一致,所以无需修改(虽然市面上一些教学开发板采用分立电源方案,但是落实到产品设计个人认为使用官方推荐方案更好。电源这种重要部件的钱能不省就不要省,毕竟有些坑能不踩就不要去踩)
1.4 修改stm32mp15-pinctrl.dtsi
文件
在文件stm32mp15-pinctrl.dtsi
中的pinctrl_z
节点下添加usart1_pins_a
节点:
&pinctrl_z {
......
usart1_pins_a: usart1-0 {
pins1 {
pinmux = <STM32_PINMUX('Z', 7, AF7)>; /* USART1_TX */
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = <STM32_PINMUX('Z', 6, AF7)>; /* USART1_RX */
bias-pull-up;
};
};
};
注意:一定要添加在pinctrl_z
节点下面,因为USART1使用的是端口Z的引脚
1.5 编译TF-A
创建编译脚本编译tf-a源码,脚本内容如下:
#!/bin/bash
# SDK环境设置
source <安装目录绝对路径>/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
# 编译前清除上一次编译
make -f $PWD/../Makefile.sdk clean
# 编译命令
make -f $PWD/../Makefile.sdk TFA_DEVICETREE=stm32mp157d-custom TF_A_CONFIG="trusted serialboot" ELF_DEBUG_ENABLE='1' all
赋予脚本可执行权限:
$ chmod +x build.sh
执行编译脚本./build.sh
等待编译完成后在tf-a源码上层目录build/trusted
下生成镜像tf-a-stm32mp157d-custom-trusted.stm32
1.6 烧写验证
将前面完成分区的SD卡连接到Ubuntu,然后进入镜像存放目录后执行如下命令进行烧写:
# 烧写fsbl1
$ sudo dd if=tf-a-stm32mp157d-custom-trusted.stm32 of=/dev/sdb1 bs=1M conv=fdatasync
# 烧写fsbl2
$ sudo dd if=tf-a-stm32mp157d-custom-trusted.stm32 of=/dev/sdb2 bs=1M conv=fdatasync
启动模式调整为SD卡启动:
BOOT Mode | BOOT2 | BOOT1 | BOOT0 |
---|---|---|---|
Cortex_M4 | 1 | 0 | 0 |
SD_Card | 1 | 0 | 1 |
NOR | 0 | 0 | 1 |
EMMC | 0 | 1 | 0 |
并行NAND | 0 | 1 | 1 |
串行NAND | 1 | 1 | 1 |
USB/UART | 1 | 1 | 0 |
USB/UART | 0 | 0 | 0 |
启动后输出如下:
NOTICE: CPU: STM32MP157DAA Rev.Z
NOTICE: Model: STMicroelectronics STM32MP157D custom board
INFO: Reset reason (0x15):
INFO: Power-on Reset (rst_por)
INFO: PMIC version = 0x21
INFO: Using SDMMC
INFO: Instance 1
INFO: Boot used partition fsbl1
NOTICE: BL2: v2.2-r2.0(debug):d8a87d6-dirty
NOTICE: BL2: Built : 15:45:09, Feb 8 2022
INFO: Using crypto library 'stm32_crypto_lib'
INFO: BL2: Doing platform setup
INFO: RAM: DDR3-DDR3L 32bits 533000Khz
INFO: Memory size = 0x40000000 (1024 MB)
INFO: BL2 runs SP_MIN setup
INFO: BL2: Loading image id 4
INFO: Loading image id=4 at address 0x2ffeb000
INFO: Image id=4 loaded: 0x2ffeb000 - 0x2ffff000
INFO: BL2: Loading image id 5
INFO: Loading image id=5 at address 0xc0100000
WARNING: Failed to determine the size of the image id=5 (-12)
ERROR: BL2: Failed to load image (-12)
由于此时还没有u-boot,所以会报无法加载镜像的错误。
二 U-BOOT移植
u-boot-stm32mp-2020.01.r2-r0
目录下的README.HOW_TO.txt
文件描述了源码解压、打补丁、编译等操作
2.0 组织源码
# 解压
$ tar xfvz u-boot-stm32mp-2020.01.r2-r0.tar.gz
# 进入解压后的源码目录
$ cd u-boot-stm32mp-2020.01.r2
# git管理
$ test -d .git || git init . && git add . && git commit -m "U-Boot source code" && git gc
# 创建开发分支
$ git checkout -b develop
# 打补丁
$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
2.1 添加自己的开发板
$ cp arch/arm/dts/stm32mp157d-ed1.dts arch/arm/dts/stm32mp157d-custom.dts
$ cp arch/arm/dts/stm32mp15xx-edx.dtsi arch/arm/dts/stm32mp157d-custom.dtsi
# stm32mp157d-ed1-u-boot.dtsi文件直接引用的stm32mp157a-ed1-u-boot.dtsi文件
$ cp arch/arm/dts/stm32mp157a-ed1-u-boot.dtsi arch/arm/dts/stm32mp157d-custom-u-boot.dtsi
2.2 修改文件适配平台
2.2.1 修改stm32mp157d-custom.dts
文件
#include "stm32mp15xx-edx.dtsi"
改为
#include "stm32mp157d-custom.dtsi"
model = "STMicroelectronics STM32MP157D eval daughter";
compatible = "st,stm32mp157d-ed1", "st,stm32mp157";
改为
model = "STMicroelectronics STM32MP157D custom board";
compatible = "st,stm32mp157d-custom", "st,stm32mp157";
/* 我手上板子使用的是USART1,官方板子是UART4 */
aliases {
serial0 = &uart4;
};
改为:
aliases {
serial0 = &usart1;
};
2.2.2 修改stm32mp157d-custom.dtsi
文件
2.2.2.1 修改输出串口
&uart4 {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <&uart4_pins_a>;
pinctrl-1 = <&uart4_sleep_pins_a>;
pinctrl-2 = <&uart4_idle_pins_a>;
/delete-property/dmas;
/delete-property/dma-names;
status = "okay";
};
改为:
&usart1 {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <&usart1_pins_a>;
pinctrl-1 = <&usart1_sleep_pins_a>;
pinctrl-2 = <&usart1_idle_pins_a>;
/delete-property/dmas;
/delete-property/dma-names;
status = "okay";
};
2.2.2.2 修改SD卡接口
前面移植TF-A是有说到SD卡接口与官方板子的差异,修改如下:
&sdmmc1 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_dir_pins_a>;
pinctrl-2 = <&sdmmc1_b4_sleep_pins_a &sdmmc1_dir_sleep_pins_a>;
cd-gpios = <&gpiog 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
disable-wp;
st,sig-dir;
st,neg-edge;
st,use-ckin;
bus-width = <4>;
vmmc-supply = <&vdd_sd>;
vqmmc-supply = <&sd_switch>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-ddr50;
sd-uhs-sdr104;
status = "okay";
};
改为:
&sdmmc1 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc1_b4_pins_a>;
pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
/* SD卡的CD引脚连接的是PE8 */
cd-gpios = <&gpioe 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
disable-wp;
st,neg-edge;
bus-width = <4>;
vmmc-supply = <&vdd_sd>;
status = "okay";
};
2.2.2.3 添加以太网接口(KSZ9031)
在文件末添加以下内容(参考stm32mp15xx-evx.dtsi
和Documentation/devicetree/bindings/net/ethernet-phy.yaml
文件):
ðernet0 {
status = "okay";
pinctrl-0 = <ðernet0_rgmii_pins_a>;
pinctrl-1 = <ðernet0_rgmii_sleep_pins_a>;
pinctrl-names = "default", "sleep";
phy-mode = "rgmii-id";
max-speed = <1000>;
phy-handle = <&phy0>;
nvmem-cells = <ðernet_mac_address>;
nvmem-cell-names = "mac-address";
mdio0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
phy0: ethernet-phy@0 {
/* PHY_ID_KSZ9031 0x00221620 */
compatible = "ethernet-phy-id0022.1620";
reset-gpios = <&gpiog 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
reset-assert-us = <1000>;
reset-deassert-us = <2000>;
reg = <0>;
};
};
};
2.2.2.4 添加USB外设接口
修改如下(参考stm32mp15xx-evx.dtsi
文件):
添加usb_phy_tuning
节点到根节点
usb_phy_tuning: usb-phy-tuning {
st,hs-dc-level = <2>;
st,fs-rftime-tuning;
st,hs-rftime-reduction;
st,hs-current-trim = <15>;
st,hs-impedance-trim = <1>;
st,squelch-level = <3>;
st,hs-rx-offset = <2>;
st,no-lsfs-sc;
};
接下来修改如下所示内容
&usbotg_hs {
vbus-supply = <&vbus_otg>;
};
&usbphyc_port0 {
phy-supply = <&vdd_usb>;
};
&usbphyc_port1 {
phy-supply = <&vdd_usb>;
};
修改后:
&usbh_ehci {
phys = <&usbphyc_port0>;
status = "okay";
};
&usbotg_hs {
pinctrl-0 = <&usbotg_hs_pins_a>;
pinctrl-names = "default";
phys = <&usbphyc_port1 0>;
phy-names = "usb2-phy";
status = "okay";
};
&usbphyc {
status = "okay";
};
&usbphyc_port0 {
phy-supply = <&vdd_usb>;
st,phy-tuning = <&usb_phy_tuning>;
};
&usbphyc_port1 {
phy-supply = <&vdd_usb>;
st,phy-tuning = <&usb_phy_tuning>;
};
2.2.2.5 修改LED接口
st官方板ev1设计了两个led作为heartbeat
和error
指示灯,分别连接在PD9
和PA13
:
若自己板子有设计指示灯可以改为自己的LED接口,若没有则可以注释或删除这些节点,我这块板子LED接口如图:
修改stm32mp157d-custom.dtsi
文件:
led {
compatible = "gpio-leds";
led-blue {
label = "heartbeat";
/* 改为自己开发板的led引脚 */
gpios = <&gpiod 1 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
default-state = "off";
};
};
修改stm32mp157d-custom-u-boot.dtsi
文件:
led {
led-red {
label = "error";
/* 改为自己开发板的led引脚 */
gpios = <&gpiod 15 GPIO_ACTIVE_LOW>;
default-state = "off";
status = "okay";
};
};
2.2.3 修改stm32mp157d-custom-u-boot.dtsi
文件
2.2.3.1 HSE和输出串口
/* 删除或注释下面内容 */
&clk_hse {
st,digbypass;
};
/* uart4节点下添加usart1 */
&usart1 {
u-boot,dm-pre-reloc;
};
&usart1_pins_a {
u-boot,dm-pre-reloc;
pins1 {
u-boot,dm-pre-reloc;
};
pins2 {
u-boot,dm-pre-reloc;
/* pull-up on rx to avoid floating level */
bias-pull-up;
};
};
2.2.3.2 去除无关引脚
官方ev1开发板使用了两个按键用于进入fastboot
和stm32prog
模式,这两个按键分别连接在PA13
和PA14
端口上面。
我手上的板子没有这个设计,所以需要做如下修改:
/* 删除或注释掉下面内容 */
st,fastboot-gpios = <&gpioa 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
st,stm32prog-gpios = <&gpioa 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
这里的修改也和前面的添加USB外设接口有关系,若修改USB接口后不改这里则启动U-Boot会进入fastboot(提示Enter fastboot!)
2.2.4 修改stm32mp15-pinctrl.dtsi
文件
在pinctrl_z
节点下添加usart1
引脚相关节点如下:
&pinctrl_z {
......
usart1_pins_a: usart1-0 {
pins1 {
pinmux = <STM32_PINMUX('Z', 7, AF7)>; /* USART1_TX */
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = <STM32_PINMUX('Z', 6, AF7)>; /* USART1_RX */
bias-disable;
};
};
usart1_idle_pins_a: usart1-idle-0 {
pins1 {
pinmux = <STM32_PINMUX('Z', 7, ANALOG)>; /* USART1_TX */
};
pins2 {
pinmux = <STM32_PINMUX('Z', 6, AF7)>; /* USART1_RX */
bias-disable;
};
};
usart1_sleep_pins_a: usart1-sleep-0 {
pins {
pinmux = <STM32_PINMUX('Z', 7, ANALOG)>, /* USART1_TX */
<STM32_PINMUX('Z', 6, ANALOG)>; /* USART1_RX */
};
};
};
2.2.5 添加RGB-LCD接口
U-Boot中添加LCD接口后使用STM32CubeProgrammer软件烧写系统时会在LCD上显示烧写过程。
我板子上有一块5寸rgb接口显示屏,添加rgb-lcd接口需要对stm32mp157d-custom.dts
文件做如下修改:
1、在根节点添加以下内容:
panel_backlight: panel-backlight {
compatible = "gpio-backlight";
gpios = <&gpiod 13 GPIO_ACTIVE_HIGH>;
default-on;
status = "okay";
};
panel_rgb: panel-rgb {
compatible = "simple-panel";
pinctrl-names = "default", "sleep";
pinctrl-0 = <<dc_pins_b>;
backlight = <&panel_backlight>;
status = "okay";
port {
rgb_in: endpoint {
remote-endpoint = <<dc_ep0_out>;
};
};
display-timings {
native-mode = <&timing0>; /* 时序信息 */
timing0: 800x480 { /* 5 寸 800*480 分辨率 */
clock-frequency = <30000000>; /* LCD 像素时钟,单位 Hz */
hactive = <800>; /* LCD X 轴像素个数 */
vactive = <480>; /* LCD Y 轴像素个数 */
hfront-porch = <40>; /* LCD hfp 参数 */
hback-porch = <88>; /* LCD hbp 参数 */
hsync-len = <0>; /* LCD hspw 参数 */
vback-porch = <32>; /* LCD vbp 参数 */
vfront-porch = <13>; /* LCD vfp 参数 */
vsync-len = <3>; /* LCD vspw 参数 */
};
};
};
2、在根节点外追加ltdc节点内容如下:
<dc {
status = "okay";
pinctrl-names = "default";
port {
#address-cells = <1>;
#size-cells = <0>;
ltdc_ep0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&rgb_in>;
};
};
};
2.2.6 修改arch/arm/dts/Makefile
文件
CONFIG_STM32MP15x
下添加自己平台的设备树stm32mp157d-custom.dtb
:
dtb-$(CONFIG_STM32MP15x) += \
stm32mp157a-avenger96.dtb \
stm32mp157a-dk1.dtb \
stm32mp157a-ed1.dtb \
stm32mp157a-ev1.dtb \
stm32mp157c-dk2.dtb \
stm32mp157c-ed1.dtb \
stm32mp157c-ev1.dtb \
stm32mp157d-dk1.dtb \
stm32mp157d-ed1.dtb \
stm32mp157d-ev1.dtb \
stm32mp157f-dk2.dtb \
stm32mp157f-ed1.dtb \
stm32mp157f-ev1.dtb \
stm32mp15xx-dhcom-pdk2.dtb \
stm32mp157d-custom.dtb
2.3 修改stm32mp15_trusted_defconfig
文件
1、为了能够在U-boot终端设置MAC地址等参数,需要在文件末追加以下内容:
CONFIG_ENV_OVERWRITE=y
否则无法更改环境变量,以设置以太网MAC为例报错信息如下:
STM32MP> setenv ethaddr 2c:de:34:8c:5b:e5
## Error: Can't overwrite "ethaddr"
## Error inserting "ethaddr" variable, errno=1
2、使能boot
命令。官方uboot配置文件并没有开启boot命令,需要在文件添加以下内容来开启:
CONFIG_CMD_BOOTD=y
2.4 编译U-boot
创建编译脚本内容如下:
#!/bin/bash
# SDK环境设置
source <安装目录绝对路径>/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
# 编译前清除上一次编译
make -f $PWD/../Makefile.sdk clean
# 编译命令
make -f $PWD/../Makefile.sdk all UBOOT_CONFIGS=stm32mp15_trusted_defconfig,trusted,u-boot.stm32 DEVICE_TREE=stm32mp157d-custom
赋予脚本执行权限:
$ chmod +x build.sh
执行编译脚本./build.sh
等待编译完成后会在U-Boot源码上级目录build-trusted
下生成镜像u-boot-stm32mp157d-custom-trusted.stm32
。
注意:编译时可能会遇到如下报错:
Error: You must add new CONFIG options using Kconfig The following new ad-hoc CONFIG options were detected: CONFIG_UBIFS_SILENCE_MSG Please add these via Kconfig instead. Find a suitable Kconfig file and add a 'config' or 'menuconfig' option.
这是
Makefile
执行到scripts/check-config.sh
脚本时发生错误,有如下两种解决方法:方法1:屏蔽U-Boot根目录Makefile文件中如下内容,不执行该有序检查操作
quiet_cmd_cfgcheck = CFGCHK $2 cmd_cfgcheck = $(srctree)/scripts/check-config.sh $2 \ $(srctree)/scripts/config_whitelist.txt $(srctree)
方法2:把报错信息中的
CONFIG_UBIFS_SILENCE_MSG
插入到文件scripts/config_whitelist.txt
中,注意一定要按照字母排序放到对应位置,如下CONFIG_UBIBLOCK CONFIG_UBIFS_SILENCE_MSG CONFIG_UBIFS_VOLUME
2.5 烧写验证
将前面移植烧写过TF-A的SD卡连接到Ubuntu,然后进入镜像存放目录后执行如下命令进行烧写:
$ sudo dd if=u-boot-stm32mp157d-custom-trusted.stm32 of=/dev/sdb3 conv=fdatasync
插入SD卡并设置BOOT模式为SD卡启动(101)后可以看到在TF-A信息加载完成后会接着加载U-Boot输出信息:
NOTICE: CPU: STM32MP157DAA Rev.Z
NOTICE: Model: STMicroelectronics STM32MP157D custom board
INFO: Reset reason (0x15):
INFO: Power-on Reset (rst_por)
INFO: PMIC version = 0x21
INFO: Using SDMMC
INFO: Instance 1
INFO: Boot used partition fsbl1
NOTICE: BL2: v2.2-r2.0(debug):d8a87d6-dirty
NOTICE: BL2: Built : 15:45:09, Feb 8 2022
INFO: Using crypto library 'stm32_crypto_lib'
INFO: BL2: Doing platform setup
INFO: RAM: DDR3-DDR3L 32bits 533000Khz
INFO: Memory size = 0x40000000 (1024 MB)
INFO: BL2 runs SP_MIN setup
INFO: BL2: Loading image id 4
INFO: Loading image id=4 at address 0x2ffeb000
INFO: Image id=4 loaded: 0x2ffeb000 - 0x2ffff000
INFO: BL2: Loading image id 5
INFO: Loading image id=5 at address 0xc0100000
INFO: STM32 Image size : 899871
INFO: Image id=5 loaded: 0xc0100000 - 0xc01dbb1f
WARNING: Skip signature check (header option)
NOTICE: ROTPK is not deployed on platform. Skipping ROTPK verification.
NOTICE: BL2: Booting BL32
INFO: Entry point address = 0x2ffeb000
INFO: SPSR = 0x1d3
NOTICE: SP_MIN: v2.2-r2.0(debug):d8a87d6-dirty
NOTICE: SP_MIN: Built : 15:45:14, Feb 8 2022
INFO: ARM GICv2 driver initialized
INFO: Set calibration timer to 60 sec
INFO: stm32mp IWDG1 (12): Secure
INFO: ETZPC: CRYP1 (9) could be non secure
INFO: SP_MIN: Initializing runtime services
INFO: SP_MIN: Preparing exit to normal world
U-Boot 2020.01-stm32mp-r2 (Feb 09 2022 - 01:26:51 +0800)
CPU: STM32MP157DAA Rev.Z
Model: STMicroelectronics STM32MP157D custom board
Board: stm32mp1 in trusted mode (st,stm32mp157d-custom)
DRAM: 1 GiB
Clocks:
- MPU : 800 MHz
- MCU : 208.878 MHz
- AXI : 266.500 MHz
- PER : 24 MHz
- DDR : 533 MHz
WDT: Started with servicing (32s timeout)
NAND: 0 MiB
MMC: STM32 SD/MMC: 0, STM32 SD/MMC: 1
Loading Environment from MMC... OK
In: serial
Out: serial
Err: serial
invalid MAC address in OTP 00:00:00:00:00:00
Net:
Error: ethernet@5800a000 address not set.
No ethernet found.
Hit any key to stop autoboot: 0
STM32MP>
报错提示没有设置网卡MAC地址,在U-Boot模式下设置MAC后重启即可解决问题:
# 设置
STM32MP> setenv ethaddr D4:B2:C3:A1:C6:F5
# 保存
STM32MP> saveenv
Saving Environment to MMC... Writing to MMC(0)... OK
# 重启
STM32MP> reset
或者在include/configs/stm32mp1.h
文件中添加以太网MAC默认环境变量("ethaddr=D4:B2:C3:A1:C6:F5\0" \
)也可以解决该问题:
#define CONFIG_EXTRA_ENV_SETTINGS \
"bootdelay=1\0" \
"ethaddr=D4:B2:C3:A1:C6:F5\0" \
"kernel_addr_r=0xc2000000\0" \
"fdt_addr_r=0xc4000000\0" \
"scriptaddr=0xc4100000\0" \
"pxefile_addr_r=0xc4200000\0" \
"splashimage=0xc4300000\0" \
"ramdisk_addr_r=0xc4400000\0" \
"altbootcmd=run bootcmd\0" \
"env_check=" \
"env exists env_ver || env set env_ver ${ver};" \
"if env info -p -d -q; then env save; fi;" \
"if test \"$env_ver\" != \"$ver\"; then" \
" echo \"*** Warning: old environment ${env_ver}\";" \
" echo '* set default: env default -a; env save; reset';" \
" echo '* update current: env set env_ver ${ver}; env save';" \
"fi;\0" \
STM32MP_BOOTCMD \
STM32MP_ANDROID \
PARTS_DEFAULT \
BOOTENV \
"boot_net_usb_start=true\0"
三、LINUX移植
linux-stm32mp-5.4.56-r0
目录下的README.HOW_TO.txt
文件描述了源码解压、打补丁、编译等操作
3.1 组织源码
# 解压源码
$ $ tar xvfJ linux-5.4.56.tar.xz
# 进入源码目录
$ cd linux-5.4.56
# git管理
$ test -d .git || git init . && git add . && git commit -m "Linux source code" && git gc
# 创建开发分支
$ git checkout -b develop
# 打补丁
$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
# 绕过SHA1内核版本号生成
$ echo "" > .scmversion
# 创建编译输出目录
$ mkdir -p ../build
# 在编译输出目录下生成.config文件
$ make ARCH=arm O="$PWD/../build" multi_v7_defconfig fragment*.config
# 注入补丁文件完善.config配置文件-1
$ for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config $f; done
# 注入补丁文件完善.config配置文件-2
$ yes '' | make ARCH=arm oldconfig O="$PWD/../build"
# 复制配置文件
$ cp ../build/.config ./arch/arm/configs/stm32mp157d_custom_defconfig
注意:
make ARCH=arm O="$PWD/../build" multi_v7_defconfig fragment*.config
这条命令需要使用bash执行,使用zsh执行会报错如下:$ make ARCH=arm O="$PWD/../build" multi_v7_defconfig fragment*.config zsh: no matches found: fragment*.config
若使用zsh则需要补全文件执行,如下:
make ARCH=arm O="$PWD/../build" multi_v7_defconfig fragment-01-multiv7_cleanup.config fragment-02-multiv7_addons.config
3.2 添加自己的开发板
$ cp ./arch/arm/boot/dts/stm32mp157d-ed1.dts ./arch/arm/boot/dts/stm32mp157d-custom.dts
$ cp ./arch/arm/boot/dts/stm32mp15xx-edx.dtsi ./arch/arm/boot/dts/stm32mp157d-custom.dtsi
3.3 修改文件适配平台
3.3.1 修改stm32mp157d-custom.dts
文件
参考U-Boot移植2.2.1
3.3.2 修改stm32mp157d-custom.dtsi
文件
参考U-Boot移植2.2.2
需要注意ðernet0
节点中以下内容与uboot中有差别:
ðernet0 {
......
pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>;
......
};
3.3.3 修改stm32mp15-pinctrl.dtsi
文件
在pinctrl_z
节点下添加usart1相关节点。注意与uboot移植时添加这部分内容有不同之处:USART1_RX引脚需要配置上拉(bias-pull-up)选项,否则linux引导进入文件系统登录时无法输入。uboot移植时是在stm32mp157d-custom-u-boot.dtsi
文件中对&usart1_pins_a
节点的pins2
(USART1_RX引脚)设置了上拉选项。
&pinctrl_z {
......
usart1_pins_a: usart1-0 {
pins1 {
pinmux = <STM32_PINMUX('Z', 7, AF7)>; /* USART1_TX */
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = <STM32_PINMUX('Z', 6, AF7)>; /* USART1_RX */
bias-pull-up;
};
};
usart1_idle_pins_a: usart1-idle-0 {
pins1 {
pinmux = <STM32_PINMUX('Z', 7, ANALOG)>; /* USART1_TX */
};
pins2 {
pinmux = <STM32_PINMUX('Z', 6, AF7)>; /* USART1_RX */
bias-pull-up;
};
};
usart1_sleep_pins_a: usart1-sleep-0 {
pins {
pinmux = <STM32_PINMUX('Z', 7, ANALOG)>, /* USART1_TX */
<STM32_PINMUX('Z', 6, ANALOG)>; /* USART1_RX */
};
};
};
3.3.4 修改arch/arm/boot/dts/Makefile
文件
CONFIG_ARCH_STM32
下添加自己平台的设备树stm32mp157d-custom.dtb
:
dtb-$(CONFIG_ARCH_STM32) += \
stm32f429-disco.dtb \
stm32f469-disco.dtb \
stm32f746-disco.dtb \
stm32f769-disco.dtb \
stm32429i-eval.dtb \
stm32746g-eval.dtb \
stm32h743i-eval.dtb \
stm32h743i-disco.dtb \
stm32mp157a-avenger96.dtb \
stm32mp157a-dk1.dtb \
stm32mp157d-dk1.dtb \
stm32mp157c-dk2.dtb \
stm32mp157f-dk2.dtb \
stm32mp157c-dk2-a7-examples.dtb \
stm32mp157c-dk2-m4-examples.dtb \
stm32mp157f-dk2-a7-examples.dtb \
stm32mp157f-dk2-m4-examples.dtb \
stm32mp157a-ed1.dtb \
stm32mp157c-ed1.dtb \
stm32mp157d-ed1.dtb \
stm32mp157f-ed1.dtb \
stm32mp157a-ev1.dtb \
stm32mp157c-ev1.dtb \
stm32mp157d-ev1.dtb \
stm32mp157f-ev1.dtb \
stm32mp157c-ev1-a7-examples.dtb \
stm32mp157c-ev1-m4-examples.dtb \
stm32mp157f-ev1-a7-examples.dtb \
stm32mp157f-ev1-m4-examples.dtb \
stm32mp157d-custom.dtb
3.4 编译Linux
# 清除上次编译
$ make ARCH=arm O="$PWD/../build" distclean
# 生成编译配置选项文件
$ make ARCH=arm O="$PWD/../build" stm32mp157d_custom_defconfig
# Build kernel images (uImage and vmlinux) and device tree (dtbs)
$ make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 O="$PWD/../build"
# Build kernel module
$ make ARCH=arm modules O="$PWD/../build"
# Generate output build artifacts
$ make ARCH=arm INSTALL_MOD_PATH="$PWD/../build/install_artifact" modules_install O="$PWD/../build"
最后创建一个专门用于存放编译输出项目的目录,将编译完成的镜像和设备树拷贝该目录下:
$ mkdir -p $PWD/../build/install_artifact/boot/
$ cp $PWD/../build/arch/arm/boot/uImage $PWD/../build/install_artifact/boot/
$ cp $PWD/../build/arch/arm/boot/dts/stm32mp157d-custom.dtb $PWD/../build/install_artifact/boot/
3.5 测试验证
3.5.1 Ubuntu上搭建TFTP环境
# 安装tftp相关软件包
$ sudo apt-get install xinetd tftpd tftp
# 在/etc/xinetd.d/目录下创建名为tftp的文件
$ sudo touch /etc/xinetd.d/tftp
# 编辑文件
$ sudo vim /etc/xinetd.d/tftp
内容如下:
service tftp
{
protocol = udp
port = 69
socket_type = dgram
wait = yes
user = nobody
server = /usr/sbin/in.tftpd
server_args = /tftpboot
disable = no
}
创建tftpboot文件夹,注意路径及名称要和上面的server_args
一致:
$ sudo mkdir /tftpboot
$ sudo chmod -R 777 /tftpboot
$ sudo chown -R nobody /tftpboot
通过xinetd启动tftpd:
$ sudo /etc/init.d/xinetd stop
$ sudo /etc/init.d/xinetd start
至此,tftp服务器已启动并运行
3.5.2 启动验证
首先将内核镜像uImage和设备树stm32mp157d-custom.dtb复制到tftpboot目录下。
开发板进入U-Boot模式,执行以下命令:
# 设置bootcmd使用tftp加载内核&设备树
setenv bootcmd 'tftp c2000000 uImage;tftp c4000000 stm32mp157d-custom.dtb;bootm c2000000 - c4000000'
# 设置ipaddr
setenv ipaddr 192.168.10.128
# 设置serverip
setenv serverip 192.168.10.64
# 设置gatewayip
setenv gatewayip 192.168.10.1
#设置netmask
setenv netmask 255.255.255.0
# 保存环境变量
saveenv
# 重启
reset
由于没有文件系统挂载,启动内核最后会提示Kernel panic
错误。
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
3.5.3 Ubuntu上搭建NFS环境
# 安装nfs相关软件包
sudo apt-get install nfs-kernel-server
# 创建nfs共享目录
sudo mkdir /nfsroot
# 修改目录访问权限
sudo chmod 777 /nfsroot
# 修改如下文件
sudo vim /etc/default/nfs-kernel-server
为避免开发板与虚拟机nfs服务版本不同导致挂载失败(Ubuntu的nfs默认为协议V3和协议V4,开发板uboot使用的是V2协议,从而导致uboot不能在nfs服务器中找到文件),做如下修改让Ubuntu中的nfs服务兼容V2协议。
/etc/default/nfs-kernel-server
文件内容修改后如下所示:
# Number of servers to start up
RPCNFSDCOUNT="-V 2 8"
# Runtime priority of server (see nice(1))
RPCNFSDPRIORITY=0
# Options for rpc.mountd.
# If you have a port-based firewall, you might want to set up
# a fixed port here using the --port option. For more information,
# see rpc.mountd(8) or http://wiki.debian.org/SecuringNFS
# To disable NFSv4 on the server, specify '--no-nfs-version 4' here
RPCMOUNTDOPTS="-V 2 --manage-gids"
# Do you want to start the svcgssd daemon? It is only required for Kerberos
# exports. Valid alternatives are "yes" and "no"; the default is "no".
NEED_SVCGSSD=""
# Options for rpc.svcgssd.
RPCSVCGSSDOPTS="--nfs-version 2,3,4 --debug --syslog"
接下来修改/etc/exports
文件:sudo vim /etc/exports
修改后内容如下:
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/nfsroot *(rw,sync,no_root_squash)
/nfsroot
:nfs共享目录(与前面创建的目录一致)
*
:允许所有的网络段访问
rw
:访问者具有可读写权限
sync
:同步缓存
no_root_squash
:访问者具有 root 权限。
最后重启nfs服务:sudo /etc/init.d/nfs-kernel-server restart
3.5 Linux挂载nfs文件系统
重启开发板在uboot模式下执行如下命令:
# 设置bootargs
setenv bootargs 'console=ttySTM0,115200 \
root=/dev/nfs \
nfsroot=192.168.10.64:/nfsroot/rootfs,proto=tcp rw \
ip=192.168.10.128:192.168.10.64:192.168.10.1:255.255.255.0::eth0:off'
# 保存环境变量
saveenv
# 重启
reset
setenv bootargs 'console=开发板串口号,波特率
root=挂载方式
nfsroot=nfs服务器ip地址:nfs文件系统路径,proto=传输协议 读写权限
ip=开发板ip地址:nfs服务器ip地址:网关:子网掩码::开发板网口:off'
四 打包镜像
4.1 bootfs镜像
这部分由Linux镜像文件uImage
和设备树文件stm32mp157d-custom.dtb
构成。在Ubuntu下创建一个bootfs
文件夹,将uImage和stm32mp157d-custom.dtb拷贝到该目录下,然后执行如下命令:
# 进入目录
cd bootfs
# 创建磁盘,of磁盘名称,bs磁盘块大小,count磁盘块数量
dd if=/dev/zero of=bootfs.ext4 bs=1M count=64
# 将磁盘格式化为ext4格式
mkfs.ext4 -L bootfs bootfs.ext4
# 创建目录用来挂载上一步制作的bootfs.ext4
sudo mkdir /mnt/bootfs
# 将bootfs.ext4挂载到/mnt/bootfs目录下
sudo mount bootfs.ext4 /mnt/bootfs/
# 将文件拷贝到/mnt/bootfs目录下
sudo cp uImage stm32mp157d-custom.dtb /mnt/bootfs/
# 拷贝完成后取消挂载
sudo umount /mnt/bootfs
完成上述操作后bootfs.ext4
文件就打包完成了。
4.2 rootfs镜像
这部分由根文件系统构成,打包方法和前面打包bootfs.ext4操作一样。
# 进入目录
cd rootfs
# 创建磁盘,of磁盘名称,bs磁盘块大小,count磁盘块数量
dd if=/dev/zero of=rootfs.ext4 bs=1M count=512
# 将磁盘格式化为ext4格式
mkfs.ext4 -L rootfs rootfs.ext4
# 创建目录用来挂载上一步制作的rootfs.ext4
sudo mkdir /mnt/rootfs
# 将rootfs.ext4挂载到/mnt/rootfs目录下
sudo mount rootfs.ext4 /mnt/rootfs/
# 进入根文件系统存放目录
cd /nfsroot/rootfs/
# 将文件拷贝到/mnt/rootfs目录下
sudo cp * /mnt/rootfs/ -drf
# 拷贝完成后取消挂载
sudo umount /mnt/rootfs
完成上述操作后rootfs.ext4
文件就打包完成了。
4.3 烧写验证
Windows下创建一个image文件夹,然后将tf-a,u-boot,bootfs,rootfs烧写文件拷贝到里面,然后在该文件夹下创建一个tsv文件(STM32CubeProgrammer的烧录脚本)。
FlashLayout_emmc_stm32mp157d-custom-trusted.tsv
文件内容如下:
#Opt Id Name Type Device Offset Binary
- 0x01 fsbl1-boot Binary none 0x0 tf-a-stm32mp157d-custom-serialboot.stm32
- 0x03 ssbl-boot Binary none 0x0 u-boot-stm32mp157d-custom-trusted.stm32
P 0x04 fsbl1 Binary mmc1 boot1 tf-a-stm32mp157d-custom-trusted.stm32
P 0x05 fsbl2 Binary mmc1 boot2 tf-a-stm32mp157d-custom-trusted.stm32
PD 0x06 ssbl Binary mmc1 0x00080000 u-boot-stm32mp157d-custom-trusted.stm32
P 0x21 boot System mmc1 0x00280000 bootfs.ext4
P 0x22 rootfs FileSystem mmc1 0x04280000 rootfs.ext4
关于tsv文件各选项含义详见STM32CubeProgrammer flashlayout - stm32mpu (stmicroelectronics.cn)
1、开发板拨码为USB启动(000),使用USB线将开发板USB-OTG接口与Windows连接,然后开发板上电。
2、打开STM32CubeProgrammer软件,查看USB configuration
是否有USB信息,没有就点击刷新按钮,确定接口为USB
后点击Connect
按钮,如图所示:
3、点击Open file
选择所使用的tsv文件,注意Binaries path
里面的路径为存放烧写文件的路径(Browse
按钮选择文件路径),然后点击Download
等待烧写完成。
4、烧写完成后开发板拨码为EMMC启动(010),然后进入uboot后依次进行如下操作:
# 设置bootcmd环境变量
setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157d-custom.dtb;bootm c2000000 - c4000000'
# 设置bootargs环境变量
setenv bootargs 'console=ttySTM0,115200 root=/dev/mmcblk1p3 rootwait rw'
# 保存
saveenv
# 重启
reset
至此就实现了从emmc启动系统。