第13章 uboot移植
编译ST官方U-boot
ST官方uboot源码打补丁
获取ST官方uboot
u-boot-stm32mp-2020.01-r0 可以理解为是之前解压ST官方源码得到的uboot的SDK工具包(PS:里面有个README.HOW_TO.txt的帮助手册可以看下)
cd ~/linux/atk-mp1/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0
解压uboot源码包
tar -vxf u-boot-stm32mp-2020.01-r0.tar.gz
进入解压得到的 u-boot-stm32mp-2020.01 ,进行打补丁的操作
cd u-boot-stm32mp-2020.01
for p in `ls -1 ../*.patch`;do patch -p1 < $p;done
新建目录 my_uboot,将打好补丁的ST官方uboot源码拷贝到 my_uboot 目录(方便阅读)
mkdir ~/linux/atk-mp1/uboot/my_uboot
cp * ~/linux/atk-mp1/uboot/my_uboot/ -rf
编译ST官方uboot
进入到my_uboot目录下
cd ~/linux/atk-mp1/uboot/my_uboot
在Makefile中添加ARCH和CROSS_COMPILE变量值

编译uboot
make stm32mp15_trusted_defconfig
make DEVICE_TREE=stm32mp157d-ev1 all -j8
如果编译报错请看 编译13.1.2.1打完补丁的ST官方uboot报错
编译成功得到uboot可执行文件
(u-boot.bin:包含设备树和uboot镜像)(u-boot.stm32:u-boot.bin添加了256字节头部信息的可执行文件)

烧写
STM23CubeProgrammer 烧写原理:先向DDR烧写完整的uboot来启动板子再烧写完整的系统(uboot、内核、设备树、文件系统等等)
因此要确保uboot是完整的,但刚刚编译ST官方的uboot对于原子开发板来说是不完整的,所以我们要保留烧录工具里原有的uboot(烧给DDR),添加刚刚编译得到的ST的uboot(烧给EMMC)
重命名编译得到的u-boot.stm32为my-u-boot.stm32
将my-u-boot.stm32拷贝到 images 文件夹,修改烧录脚本为如下

烧写完成后,启动开发板,uboot会不断复位且蜂鸣器会响,uboot时间为刚刚编译uboot的时间

ST的uboot能运行但有错,因此需要移植
在uboot添加开发板
创建默认配置文件
拷贝uboot源码configs目录下的 stm32mp15_trusted_defconfig 并重命名为 stm32mp15_atk_trusted_defconfig
cd ~/linux/atk-mp1/uboot/my_uboot/configs
cp stm32mp15_trusted_defconfig stm32mp15_atk_trusted_defconfig
创建默认配置设备树
在 arch/arm/dts目录下复制ST官方设备树为自己的
cd ~/linux/atk-mp1/uboot/my_uboot/arch/arm/dts
cp stm32mp157d-ed1.dts stm32mp157d-atk.dts
cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi
cp stm32mp157a-ed1-u-boot.dtsi stm32mp157d-atk-u-boot.dtsi
修改 stm32mp157d-atk.dts 文件里的头文件引用,修改内容如下

修改电源管理设置
修改 stm32mp157d-atk-u-boot.dtsi 文件,屏蔽掉以下圈着的内容

修改 stm32mp157d-atk.dtsi 内容
删除掉adc节点(90~104行)、dac节点(114~125行)、i2c4节点(143~298行)
删除led节点和sd_switch节点信息
在/根节点下添加电源管理配置(vin节点前)
vddcore: regulator-vddcore {
compatible = "regulator-fixed";
regulator-name = "vddcore";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
regulator-boot-on;
};
v3v3: regulator-3p3v {
compatible = "regulator-fixed";
regulator-name = "v3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
v1v8_audio: regulator-v1v8-audio {
compatible = "regulator-fixed";
regulator-name = "v1v8_audio";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
vdd: regulator-vdd {
compatible = "regulator-fixed";
regulator-name = "vdd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
vdd_usb: regulator-vdd-usb {
compatible = "regulator-fixed";
regulator-name = "vdd_usb";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
修改TF卡和EMMC配置
修改sdmmc1和sdmmc2成内容如下
&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>;
st,neg-edge;
broken-cd;
bus-width = <4>;
vmmc-supply = <&v3v3>;
status = "okay";
};
&sdmmc2 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;
pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_a>;
pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_a>;
non-removable;
st,neg-edge;
bus-width = <8>;
vmmc-supply = <&v3v3>;
keep-power-in-suspend;
status = "okay";
};
编译uboot
这里只验证uboot能否运行,因此先屏蔽掉 stm32mp157d-atk.dtsi 文件中的 &usbotg_hs 节点。此节点是ST官方板的USB_OTG电源配置。

设置要编译的配置文件项,打开 arch/arm/dts/Makefile,添加如下

制作编译脚本,在uboot源码根目录下创建 stm32mp157d_alientek.sh 的脚本文件,内容如下
#!/bin/bash
make distclean
make stm32mp15_atk_trusted_defconfig
make CROSS_COMPILE=arm-none-linux-gnueabihf- DEVICE_TREE=stm32mp157d-atk all -j12
赋予脚本可执行权限后,执行脚本即可编译uboot
编译得到u-boot.stm32,重命名为my-u-boot.stm32,再烧录到板子,启动信息如下

网络、USB_OTG仍不正常,继续修改
网络设备树修改
打开 stm32mp157d-atk.dtsi 文件,在最后添加 ethernet0 节点,内容如下
ðernet0 {
status = "okay";
pinctrl-0 = <ðernet0_rgmii_pins_a>;
pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>;
pinctrl-names = "default", "sleep";
phy-mode = "rgmii-id";
max-speed = <1000>;
phy-handle = <&phy0>;
mdio0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
phy0: ethernet-phy@0 {
reg = <0>;
};
};
};
保存,重新编译uboot,将生成的u-boot.stm32重命名为my-u-boot.stm32再烧录,启动后信息如下

网络修改完成,继续修改
USB OTG设备树修改
添加 usb_phy_tuning 子节点
继续修改 stm32mp157d-atk.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;
};
添加STUSB1600 I2C 子节点
原子板子用的是 STUSB1600 芯片的 type-C接口,挂靠在I2C接口,因此添加 &i2c1 节点,内容如下:
&i2c1 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c1_pins_a>;
pinctrl-1 = <&i2c1_pins_sleep_a>;
i2c-scl-rising-time-ns = <100>;
i2c-scl-falling-time-ns = <7>;
status = "okay";
/delete-property/dmas;
/delete-property/dma-names;
stusb1600@28 {
compatible = "st,stusb1600";
reg = <0x28>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpiog>;
pinctrl-names = "default";
pinctrl-0 = <&stusb1600_pins_a>;
status = "okay";
vdd-supply = <&vin>;
connector {
compatible = "usb-c-connector";
label = "USB-C";
power-role = "dual";
power-opmode = "default";
port {
con_usbotg_hs_ep: endpoint {
remote-endpoint = <&usbotg_hs_ep>;
};
};
};
};
};
添加USB接口相关节点
继续在stm32mp157d-atk.dtsi添加,内容如下
&usbh_ehci {
phys = <&usbphyc_port0>;
status = "okay";
};
&usbotg_hs {
phys = <&usbphyc_port1 0>;
phy-names = "usb2-phy";
usb-role-switch;
status = "okay";
port {
usbotg_hs_ep: endpoint {
remote-endpoint = <&con_usbotg_hs_ep>;
};
};
};
&usbphyc {
status = "okay";
};
在stm32mp157d-atk-u-boot.dtsi 文件中添加usbotg_hs 节点
内容如下
&usbotg_hs {
u-boot,force-b-session-valid;
hnp-srp-disable;
/* TEMP: force peripheral for USB OTG */
dr_mode = "peripheral";
};
使能boot和bootd命令
ST官方uboot没有使能boot和bootd命令,指令源文件为cmd/bootm.c
打开 include/configs/stm32mp1.h,在后面添加如下定义

LCD驱动修改
打开 stm32mp157d-atk.dts 文件,在/根节点下添加panel_backlight 和panel_rgb 这两个节点,内容如下
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>;
pinctrl-1 = <<dc_pins_sleep_b>;
backlight = <&panel_backlight>;
status = "okay";
port {
panel_in_rgb: endpoint {
remote-endpoint = <<dc_ep0_out>;
};
};
display-timings {
native-mode = <&timing0>; /* 时序信息*/
timing0: timing0 { /* 7 寸1024*600 分辨率*/
clock-frequency = <51200000>; /* LCD 像素时钟,单位Hz */
hactive = <1024>; /* LCD X 轴像素个数*/
vactive = <600>; /* LCD Y 轴像素个数*/
hfront-porch = <160>; /* LCD hfp 参数*/
hback-porch = <140>; /* LCD hbp 参数*/
hsync-len = <20>; /* LCD hspw 参数*/
vback-porch = <20>; /* LCD vbp 参数*/
vfront-porch = <12>; /* LCD vfp 参数*/
vsync-len = <3>; /* LCD vspw 参数*/
};
};
};
追加 ltdc 节点,内容如下
<dc {
status = "okay";
pinctrl-names = "default";
port {
#address-cells = <1>;
#size-cells = <0>;
ltdc_ep0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&panel_in_rgb>;
};
};
};
自烧写测试
这里和前面的烧写不同,直接烧写编译好的u-boot.stm32,不需要重命名(改名)
将编译得到的u-boot.stm32替换掉 images 目录下的原文件,修改脚本成如下

从EMMC启动Linux
STM32CubeProgrammer的烧录要求 uImage 和 .dtb打包在一起成 ext4 格式的文件
这里添加烧录正点原子出厂的内核镜像,将网盘的内核镜像拷贝到 images 文件夹
网盘路径:开发板光盘A-基础资料\8、系统镜像\2、出厂系统镜像\1、STM32CubeProg烧录固件包\atk-image-bootfs.ext4
修改烧录脚本成如下

烧写完启动板子,执行 ext4ls mmc 1:2

设置bootcmd环境变量从EMMC读取系统文件并启动
setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157d-atk.dtb;bootm c2000000 - c4000000'
saveenv
boot
系统内核启动成功
从网络启动Linux系统
设置板子网络的相关信息
setenv ipaddr 192.168.1.250
setenv ethaddr 00:04:9f:04:d2:35
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.208
saveenv
ping 192.168.1.208
设置bootcmd环境变量
setenv bootcmd 'tftp c2000000 uImage;tftp c4000000 stm32mp157d-atk.dtb;bootm c2000000 - c4000000'
saveenv
boot
uboot下的LCD测试
bootcmd 和bootargs 环境变量
bootcmd 环境变量
bootcmd 所在位置 include/env_default.h