第2章:学习正点原子开发板-stm32mp157-uboot移植
1. uboot移植需要
首先,我们需要下载官方的原厂包(即BSP包),
u-boot-stm32mp-2020.01-r0
进入到u-boot-stm32mp-2020.01-r0里面,里面包含了许多.patch,Makefile.sdk和uboot源码压缩包,和tf-a一样,patch包的作用是给当前的uboot打补丁。
2. uboot移植的操作
接下来是解压u-boot-stm32mp-2020.01-r0.tar.gz文件
tar -vxf u-boot-stm32mp-2020.01-r0.tar.gz
解压完成以后,进入解压文件,然后打补丁
cd u-boot-stm32mp-2020.01/ //进入 uboot 源码目录
for p inls -1 ../*.patch
;do patch -p1 < $p;done //打补丁
这里需要注意一些符号。在以上操作完成之后,若感觉操作路径太长,则可以拷贝到短一点的路径中,便于操作。拷贝指令为
cp 源路径 目标路径 -rf
在顶层Makefile中设置ARCH和CROSS_COMPILE,如下图所示:
因为我们是参考ST官方的 STM32MP1 EVK 开发板,所以我们可以试着试用官方的设备树文件,看看哪些会报错,需要修改,这点很重要,可以节约我们大部分时间。
make stm32mp15_trusted_defconfig make DEVICE_TREE=stm32mp157d-ev1 all -j8
uboot 编译成功,生成了 u-boot.bin 和 u-boot.stm32,u-boot.bin 包含了设备树(dtb),也就是将 uboot 镜像和设备树打包在了一起。其中 u-boot.stm32 是在 u-boot.bin前面添加了 256 字节头部信息的可执行文件,是要烧写到开发板里面的。
注意:我们在向板子下载程序时,试用的也是uboot,为了排除我们自己移植的系统无法正常使用DDR,所有在烧写系统时,我们需要正电原子提供移植好的uboot,我们移植的系统改名为my-u-boot.stm32;
注意修改tsv文件,修改内容如下:
从图中可以看出,将系统烧写到的地址为0x00080000,一切准备就绪,烧写程序到EMMC中,拨动开关,启动,看结果:
一看fail,全是stpmic1_read的错误,接下来我们将围绕这些问题进行移植。
创建默认配置文件,我们使用官方的defconfig文件,将文件stm32mp15_trusted_defconfig复制一下,
cd configs //进入 uboot 的 configs 目录
cp stm32mp15_trusted_defconfig stm32mp15_atk_trusted_defconfig //拷贝
对应的设备树也复制一些,我们将在复制的文件中进行操作。
cd arch/arm/dts/ //进入 uboot 设备树目录 cp stm32mp157d-ed1.dts
stm32mp157d-atk.dts //复制.dts cp stm32mp15xx-edx.dtsi
stm32mp157d-atk.dtsi //复制.dtsi cp stm32mp157a-ed1-u-boot.dtsi
stm32mp157d-atk-u-boot.dtsi //复制.dtsi
打开 stm32mp157d-atk.dts 文件,要修改一下其中的一个头文件引用,stm32mp157d-atk.dts默认头文件引用如下:
14行 #include “stm32mp15xx-edx.dtsi”
修改为我们刚才复制的文件stm32mp15d-atk.dtsi
结果如图所示:
修改电源管理设置
打开 创建的 stm32mp157d-atk-u-boot.dtsi 这个文件,将文件中的21~22行,26~31行和51~53行都删除,删除之后如图所示:
接着修改 stm32mp157d-atk.dtsi 文件,将文件中 90~104 行的 adc 节点、114~125 行的 dac 节点以及 143~298 行的i2c4 节点全部删除掉,删除以后如图 ,主要是删除电池管理的那部分:
继续修改stm32mp157d-atk.dtsi 文件,将 led 和 sd_switch 这两个节点都删除掉,然后在文件的根节点中添加电源管理配置,将
下面的代码添加58行处:代码如下:
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;
};
在其中分别添加了vddcore、v3v3、v1v8_audio、vdd 和 vdd_usb节点,和tf-a配置的差不多。
接下来修改TF卡和EMMC配置,在 stm32mp157d-atk.dtsi 文件继续修改,找到sdmmc1和sdmmc2这两个节点,修改其中的内容为如图所示内容:
现在开始编译uboot,我们先测试前面的内容是否移植成功,则注释掉USB_OTG的电源配置,
在编译uboot之前,添加我们修改的设备树文件,打开 arch/arm/dts/Makefile文件,找到“dtb-$(CONFIG_STM32MP15x)”配置项,然后在此配置项中加入“stm32mp157d-atk.dtb”添加完成如图所示:
开始编译,操作指令如下:
make distclean
make stm32mp15_atk_trusted_defconfig
make DEVICE_TREE=stm32mp157d-atk all
在编译成功之后会出现以下信息,对应的文件也会生成。
我们将编译成功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>;
};
};
};
开发板的网络PHY芯片被更换为国产裕太电子的YT8511芯片,所以我们需要找到该芯片的驱动源代码,路径在
1、程序源码→8、模块驱动源码→1、YT8511 驱动源码→uboot 下修改方法→phy.c此文件中内容兼容RTL8211和YT8511。用修改后的phy.c文件替换掉uboot下的/drivers/net/phy/phy.c 文件即可设备树无需做任何修改,直接编译即可。注意,正点原子 V1.2 版本核心板上使用的 RTL8211,其 PHY 地址为 0X01。V1.3 以后的
核心板使用 YT8511,其 PHY 地址为 0X00,因此在设备树里面需要修改 PHY 地址为 0X00。但是这样修改以后会导致 YT8511 和RTL8211 的设备树不兼容,需要多编写一份设备树,导致出厂设备树过多。因此为了一个设备树兼容 YT8511 和 RTL8211,正点原子团队修改了 phy.c 文件中的 phy_connect 函数,直接给定 YT8511 的地址为 0X00,也就是不受设备树控制,如下图所示:
编译测试,测试结果如下:
但其中还是会出现“No ethernet found.”错误,这是因为 uboot 启动的
时候获取不到 MAC 地址,我们只需要设置一些地址相关的环境变量即可,配置命令如下,这里面参考自己的环境进行修改:
setenv ipaddr 192.168.1.250 //开发板 IP 地址 setenv ethaddr
00:04:9f:04:d2:35 //开发板网卡 MAC 地址 setenv gatewayip 192.168.1.1
//开发板默认网关 setenv netmask 255.255.255.0 //开发板子网掩码 setenv serverip
192.168.1.249 //服务器地址,也就是 Ubuntu 地址 saveenv
这是网络可以正常运行了,接下来修改USB_OTG设备树
添加 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 子节点
正点原子 STM32MP157 开发板上的 USB OTG 接口类型为 Type-C,使用 STUSB1600 芯片来实现此接口功能,STUSB1600 有一个 I2C 接口,此 I2C 接口用来配置芯片,因此我们还需要在设备树中添加 STUSB1600 相关的 I2C 节点内容。将如下内容添加到 stm32mp157d-atk.dtsi 的最后面
&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 文件添加 USB 接口相关节点内容,内容如下:
&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";
};
上述代码中有三个节点 usbh_ehci、usbotg_hs 和 usbphyc,其中 usbotg_hs 默认就有,我们在前面将其屏蔽掉了
在 stm32mp157d-atk-u-boot.dtsi 文件中添加 usbotg_hs 节点,最后,我们需要在 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";
};
至此,uboot 下的 USB OTG 就已经修改完成,重新编译 uboot 并烧写,然后使用 ums 命令
测试,看看能不能将 EMMC 模拟成 U 盘,挂载到电脑上,命令如下:
做到这里,保存修改的文件,编译和拷贝。把 STM32MP157D-ATK 开发板的 USB_OTG 接口连接到电脑里,重启开发板,接着运行以下命令:
ums 0 mmc 1
则此时电脑上会出现一个盘,不要格式化,只能在linux中挂载。
使能boot和bootd命令
ST 官方 uboot 默认并没有使能 boot 和 bootd 这两个命令,这两个命令的实现源文件为cmd/bootm.c,我们来看bootm.c文件,其中有一个宏定义,用来使能boot和bootd命令。如图所示:
那么就需要定义宏CONFIG_CMD_BOOT,打开 include/configs/stm32mp1.h,然后在后面添加如下宏定义:
重新编译uboot,使用?boot和?bootd看是否有信息,有则表示驱动成功。
LCD驱动修改
uboot 也是支持 LCD 显示的,但是要进行相应的设置,主要是设置屏幕背光、屏幕时序参数这些,这些直接在设备树里面修改即可。打开 stm32mp157d-atk.dts 文件,在里面添加 LCD 相关节点信息,首先在根节点“/”下添加 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 参数 */
};
};
};
第 1~6 行,panel_backlight 为 LCD 的背光控制节点,主要指定 LCD 背光 IO 所使用的引脚,正点原子的 STM32MP157 开发板 LCD 背光引脚为 PD13。
第 8~38 行,panel_rgb 为 RGB LCD 节点,指定了 LTDC 接口所使用的 IO、屏幕时序参数等。第 11~12 行指定 LTDC 接口的 IO,ltdc_pins_b 和 ltdc_pins_sleep_b 定义在 stm32mp15-pinctrl.dtsi 文件中。第 22~35 行的 display-timings 是非常重要的 LCD 时序参数,不同的屏幕其时序参数不同,这里演示的是正点原子 7 寸 1024600 分辨率的。正点原子有 4 款 RGB 接口屏幕,分别为 4.3 寸 480272 和 800480 分辨率、7 寸 800480 和 1024*600 分辨率,这款屏幕时序参数如表
屏幕型号 参数 值 值 单位
ATK4342
水平显示区域 480 tCLK
HSPW(thp) 1 tCLK
HBP(thb) 40 tCLK
HFP(thf) 5 tCLK
垂直显示区域 272 th
VSPW(tvp) 1 th
VBP(tvb) 8 th
VFP(tvf) 8 th
像素时钟 9 MHz
ATK4384
水平显示区域 800 tCLK
HSPW(thp) 48 tCLK
HBP(thb) 88 tCLK
HFP(thf) 40 tCLK
垂直显示区域 480 th
VSPW(tvp) 3 th
VBP(tvb) 32 th
VFP(tvf) 13 th
像素时钟 31 MHz
ATK7084
水平显示区域 800 tCLK
HSPW(thp) 1 tCLK
HBP(thb) 46 tCLK
HFP(thf) 210 tCLK
垂直显示区域 480 th
VSPW(tvp) 1 th
VBP(tvb) 23 th
VFP(tvf) 22 th
像素时钟 33.3 MHz
ATK7016
水平显示区域 1024 tCLK
HSPW(thp) 20 tCLK
HBP(thb) 140 tCLK
HFP(thf) 160 tCLK
垂直显示区域 600 th
VSPW(tvp) 3 th
VBP(tvb) 20 th
VFP(tvf) 12 th
像素时钟 51.2 MHz
如图所示:
最后还需要在 stm32mp157d-atk.dts 文件里面向 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>;
};
};
从 从 EMMC 启动 Linux
从EMMC启动也就是将编译出来的Linux镜像文件uImage和.dtb设备树文件保存在EMMC中,uboot 从 EMMC 中读取这两个文件并启动,这个是我们产品最终的启动方式。首先 EMMC里面要先存放 Linux 镜像文件 uImage 和.dtb 设备树,但是我们前面新建的 FlashLayout 文件并没有烧写 uImage 和.dtb,所以我们需要修改一下 FlashLayout 文件,加入 uImage 和.dtb 烧写命令。由于我们还没有移植 Linux 系统,所以 uImage 和.dtb 就先使用正点原子出厂系统提供的,路径为:开发板光盘→8、系统镜像→2、出厂系统镜像→1、STM32CubeProg 烧录固件包→atk-image-bootfs.ext4 。atk-image-bootfs.ext4 是 ext4 格式的打包文件,因为 STM32CubeProgrammer软件要求将 uImage 和.dtb 打包在一起,格式为 ext4。atk-image-bootfs.ext4 里面的文件如图
将文件烧写到板子中,tsv的配置如下
在烧写程序之后,开启板子,然后在uboot中参看uImage等是否烧写入文件。
最后我们配置开机自启命令。命令如下:
setenv bootcmd ‘ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2
c4000000 stm32mp157d- atk.dtb;bootm c2000000 - c4000000’ saveenv boot
注意:此时还没有根文件系统,所以内核启动之后会报错。
从网络启动 Linux 系统
命令如下:
setenv bootcmd ‘tftp c2000000 uImage;tftp c4000000
stm32mp157d-atk.dtb;bootm c2000000 - (有空格) c4000000’ saveenv
boot
启动结果如下:
LCD测试
在烧写程序时,开发板的lcd会显示一下内容:
bmp 命令显示测试
使用uboot下的bmp命令在LCD上显示一张bmp图片,如图所示:
bmp info < imageAddr >
bmp info 命令用于显示 BMP 图片信息,imageAddr 就是 BMP 图片在 RAM 中的起始地址。
bmp display
命令用于显示 bmp 图片,imageAddr 是要显示的 BMP 图片在 RAM 中的起始地址,[x,y]用于指定 BMP 图片左上角在屏幕上的显示坐标。
tftp c0000000 test.bmp //下载 bmp 图片
bmp info c0000000 //显示图片信息
显示图片
bmp display c0000000 0 0 //显示 bmp 图片
以上就是uboot的整个移植过程,可能其中内容存在很多不足,有什么不妥地方请联系。