一、前言
在上一次教程中,我们了解了STM32MP157的启动流程与安全启动机制。我们还将FSBL的相关代码移植成功了。大家还记得FSBL的下一个步骤是什么吗?没错,就是SSBL,而且常见的我们将SSBL作为存放U-Boot的地方。所以本次教程,我们需要移植一份适用于我们开发板的U-Boot。当然,本次教程依然使用的是正点原子的STM32MP157开发板,这里还是强烈建议大家的开发板和我一样的,如果你准备好了,就让我们开始吧!
二、谁适合本次教程
因为STM32MP157的程序下载需要U-Boot的辅助,也就是说,我们想要移植并下载一个U-Boot前提是先有一个U-Boot,这就非常抽象了,又像是回到了TF-A那样的“死锁”状态。当然,这里我们下载Uboot时,可以直接使用正点原子已经移植好的Uboot来将我们自己移植的Uboot下载进去。所以,在移植之前请确保你对STM32MP157的程序下载有一定的了解。关于STM32MP157的程序下载在之前TF-A移植教程中已经讲过了,而且正点原子的手册中也有非常详细的讲解,本次教程就不过多讲解了:
STM32MP157 TF-A移植:[Linux]从零开始的STM32MP157启动流程讲解与TF-A的移植-CSDN博客
三、资料的准备
这里我们使用到的资料同样是正点原子的官方资料,在最开始的环境搭建教程中已经讲解了如何下载正点原子的官方资料,如果你还不知道如何下载请前往STM32MP157的开发环境搭建教程:
STM32MP157开发环境搭建:[Linux]从零开始的STM32MP157交叉编译环境配置_stm32mp157 linux 开发 单片机开发-CSDN博客
准备好的资料如下图:
如果你已经准备好了相关资料就让我们开始吧!
四、Uboot的作用以及不同厂家的Uboot
首先我们需要明确一点,Uboot并不是有一个系统,它是一个非常庞大的裸机程序,主要用于基本外设的初始化和拉起操作系统。我们的操作系统在被编译以后,并不是单纯的二进制文件,而是一个以img为后缀的系统文件。显然这个文件不像二进制文件那样可以直接被烧录运行,这时我们就需要一段代码来拉起这个img格式的系统文件。这个拉起系统的程序就是我们常说的Bootloader引导程序。Bootloader有非常多的种类,比如U-Boot、vivi、RedBoot。在嵌入式领域或者一些智能通讯设备领域最常用的还是Uboot。所以,为了能在我们的开发板上运行Linux内核,我们就必须用一个Bootloader程序来引导它,这里正点原子的开发板选择的是Uboot。总结一下,简单来说,Uboot主要就是一个用于引导系统的Bootloader程序。
当我们准备移植Uboot时,我们可能会面临三种Uboot分别是:Uboot官方开源出来的Uboot,这个Uboot往往是最纯正的;还有就是芯片厂家开放的Uboot,芯片厂家会从Uboot的官方下载一份Uboot并且对其进行修改使其适配自己的芯片;最后就是开发板厂家的Uboot,就拿正点原子来举例,正点原子使用ST公司的STM32MP157芯片生产了开发板,正点原子会从ST那里下载芯片对用的Uboot,并且对其进行修改从而适配自己的开发板。这里我们要进行的移植其实就是让原本芯片厂商的Uboot对我们的开发板进行适配。不同厂家的Uboot的关系可以看下面这张图:
当然,大家可能会有疑问,明明正点原子已经帮我们移植好了Uboot,为什么我们还要再移植一次呢?其实答案也很简单,正点原子移植Uboot的当然只适配正点原子的开发板。如果我们自己设计了一块开发板,这个板子的外设或者供电和正点原子的开发板不一样,就会导致这个Uboot在我们的开发板上不适用。我们移植Uboot的目的就是学习这个移植的过程,在以后我们自己设计了开发板以后也能将Uboot移植上去。
五、正点原子官方Uboot的编译与烧录
这里我们先来编译一下正点原子官方的Uboot,让大家体验一下Uboot编译与烧录的过程,这样也有助于大家对Uboot移植的整个步骤有一定的了解。这次的教程同样同步于正点原子的“【正点原子】STM32MP1嵌入式Linux驱动开发指南V2.1.pdf”文档,它被放在了正点原子资料目录下的“09、文档教程(非常重要)”目录下:
下面我们来编译正点原子的Uboot吧,正点原子的Uboot被放在了正点原子资料目录下的“01、程序源码\01、正点原子Linux出厂系统源码”目录下:
1.正点原子官方uboot的编译
这里我们新建一个文件夹来存放uboot:
创建的路径无所谓,大家自己决定即可。我们再在这个已经创建好文件夹中再创建一个文件夹用于存放正点原子的Uboot源码,我这里文件夹就叫“atk-uboot”:
然后,大家可以使用FTP服务将正点原子的Uboot源码上传到目录中,这里FTP传输文件在环境搭建的教程中已经讲得很详细了,大家自行操作即可,这里就不进行多的演示了。
我们将文件上传到指定目录后如图:
这里我们先使用下面的命令将正点原子的uboot进行解压:
tar -vxf u-boot-stm32mp-2020.01-gdb2b13ef-v1.6.tar.bz2
这里压缩文件的文件名可能会变化,大家根据自己当时的文件名解压就好。
解压过程可能比较久,毕竟uboot是一个非常庞大的程序并且也兼容了非常多的芯片。解压完成以后就得到了下面的文件:
现在我们先不着急编译正点原子的uboot源码,我们先安装编译所需的环境,不然编译会产生错误,我们使用下面的命令来安装对应的环境:
sudo apt-get install libncurses5-dev bison flex
安装好环境以后,我们在正点原子的uboot源码目录执行下面的命令来清除一下已经编译的内容:
make distclean
这里建议大家在编译之前都清除一下避免错误。
我们再使用下面的命令对编译进行一些初始化:
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- stm32mp157d_atk_defconfig
下面我来逐一解释一下这些选项的含义,首先是ARCH=arm,它指定我们交叉编译的架构为arm。然后是CROSS_COMPILE=arm-none-linux-gnueabihf-,它指定了我们要使用的交叉编译器,这里表示要使用名为“arm-none-linux-gnueabihf-”的交叉编译器,也就是我们在STM32MP157开发环境搭建中安装的交叉编译器。最后stm32mp157d_atk_defconfig表示使用预定义的配置文件。 编译之前会使用stm32mp157d_atk_defconfig生成 .config文件。后面的make命令会根据对应的.config文件进行编译。这里生成的.config文件是对我们开发板的基础配置。
当我们执行完上面的命令以后,就得到了以下输出,在输出中已经提示我们.config已经被成功写入了:
当我们成功生成.config文件以后,就可以开始准备编译了,我们使用下面的命令对正点原子的uboot进行编译:
make V=1 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- DEVICE_TREE=stm32mp157d-atk all
这里多了一个V=1的选项,这个选项表示在uboot编译时输出详细的编译过程。这里还多了一个
DEVICE_TREE=stm32mp157d-atk选项,表示要使用的设备树文件,这里我们指定要使用的设备树文件为我们自己的开发板的设备树。
最后面的all表示编译所有,所以这个all不能少。我们同样可以加上-j的参数来修改编译时使用的线程数量,编译完成以后,就得到了下面的输出:
这里正点原子官方的uboot编译一般是不会有错误的,如果你出现的错误,可以看看是不是遗漏了上面的某些步骤。编译之后生成的文件就被放在了uboot的源码目录下:
我们这里重点关注u-boot.bin文件和u-boot.stm32文件。这里的u-boot.bin就是uboot源码被编译以后生成的二进制文件,而u-boot.stm32则是在u-boot.bin的基础上加上头部信息的文件。是的uboot也和TF-A一样需要在编译后的二进制文件前面加上一段头部信息。
2.正点原子官方uboot的烧录
下面,我们就可以来烧录这个我们已经编译好的正点原子的uboot。这里我直接在自己电脑的桌面上新建了一个“stm32mp157_uboot”文件夹用于存放uboot相关的文件和下载时会用到的文件以及STM32CubeProgrammer的配置文件:
还记得我们在上一次教程中创建的“stm32mp157_tf-a”文件夹吗?是的,这个文件夹我们主要是用来下载TF-A的,我们可以直接借鉴这个文件夹中的内容,我们可以将stm32mp157_tf-a文件夹中的文件全部复制到stm32mp157_uboot中:
复制完成以后,我们需要进行一些小小的修改,首先就是将原本的u-boot.stm32删掉,换成我们自己编译出来的u-boot.stm32文件,大家注意文件的时间,确保自己替换成功了:
然后我们需要将原本的STM32CubeProgrammer配置文件的名字改以下,以前的配置文件名为“tf-a.tsv”我们将其改为“uboot.tsv”,修改完以后如下图所示:
然后我们需要对“uboot-tsv”的内容就行一些修改,我们在tsv文件的最下面插入下面这样一行:
P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32
注意,这里的开头就是P,不是PD或者别的,如果从正点原子原本的文件中复制,这里可能是PD,这会导致烧录不成功。配置文件修改完以后如图所示:
这里我们启动STM32CubeProgrammer对我们编写好的uboot进行下载,连接和下载的具体步骤在TF-A的教程中已经讲得很清楚了,这里就不多说了。下载完以后会收到如下提示,如果前面一直按照我的步骤下载的话应该是不会有错误的:
下载完成以后如图:
然后我们可以将拨码拨到串口启动,然后使用串口终端工具看看输出:
我们可以看到下面这里我们的uboot已经成功启动,并且输出了uboot的编译时间。我们也可以通过这里的编译时间判断我们的烧录是否成功。
至此,我们正点原子的uboot编译与烧录就已经完成了。
六、ST官方uboot的移植与烧录
在上面,我们已经成功的编译了正点原子的uboot源码,并且已经成功的在正点原子的开发板上运行了起来。当然,使用正点原子的开发板的目的就是为了让我们学习并且理解uboot的移植过程。那么现在就来教大家如何在ST官方uboot的基础上为我们的开发板移植一份uboot。这里大家可能会有疑问,为什么我们一定要从ST官方的uboot的基础上进行移植,而不是直接移植uboot官方开放出来的uboot。这是因为虽然uboot官方开放的uboot对ST的芯片有适配,但是适配程度肯定没有ST那么好。而且让我们在原本的uboot上进行移植这几乎是不可完成的。所以让uboot官方代码适配自己的芯片这个事一般是芯片厂商来做,我们只需要在芯片厂商已经移植的uboot的基础上为我们的开发板移植一份uboot。
1.编译ST官方的uboot:
这里我们首先需要编译ST官方的uboot代码,只有将uboot官方代码编译过了以后我们才能开始移植。ST官方的代码被放在了正点原子资料目录下的“01、程序源码\05、ST官方原版Linux源码”目录下:
我们同样使用FTP服务将其传输到Linux中,这里我创建了一个名为st_uboot的文件夹:
我们再使用下面的命令将这个源码包解压:
tar -xvf en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-06-24.tar.xz
解压以后得到如下文件夹:
这里我们进入“stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24”文件夹中的“sources/arm-ostl-linux-gnueabi”文件夹下可以看到以下文件夹。这些文件夹里面就是里面就是uboot、optee、tf-a、kernel 源码:
下面有一张这些文件夹对应源码的对照表:
这里很明显,我们要用到的文件夹是“u-boot-stm32mp-2020.01-r0”。
我们可以在一开始创建的“UBOOT”文件夹中新建一个my_uboot的文件夹,将u-boot-stm32mp-2020.01-r0下的所有文件都拷贝进去,使用下面的命令:
cp u-boot-stm32mp-2020.01-r0/* /home/chulingxiao/linux/UBOOT/my_uboot/
我们将文件复制到my_uboot后如图所示:
这里和我们TF-A的源码一样,以.patch结尾的文件都是补丁文件,我们需要使用这些补丁文件为uboot打补丁。我们使用下面的命令将uboot的源码解压:
tar -xvf u-boot-stm32mp-2020.01-r0.tar.gz
解压以后,我们进入uboot的源码目录就能看到以下文件和文件夹了:
我们在源码目录下,使用下面的命令对源码进行打补丁:
for p in `ls -1 ../*.patch`;do patch -p1 < $p;done
同样的,看到一堆输出过去以后,补丁就打成功了:
下面我们需要修改以下makefile文件,还记得一开始我们编译正点原子提供的uboot的时候吗?当时我们编译输入了命令非常长,为了编译方便一些,我们直接修改makefile,将我们编译时的一些选项直接写入makefile中,这样我们也就省去了很长的命令。
uboot的makefile就放在了uboot的源码目录下,我们直接使用下面的命令打开修改即可:
nano Makefile
我们这里在使用nano编辑时,可以直接按下“ctrl+w”搜索“CROSS_COMPILE”找到如下位置:
我们直接在它的下方加入如下两行:
ARCH=arm
CROSS_COMPILE=arm-none-linux-gnueabihf-
插入以后如图所示:
修改完makefile以后,我们使用下面的命令来生成编译所需的.config文件:
make stm32mp15_trusted_defconfig
然后我们再使用下面的命令进行编译,用编译命令时还是需要指定设备树,并且也要加上all,表示编译所有,最后可以加上-j的参数来选择编译时使用的线程:
make DEVICE_TREE=stm32mp157d-ev1 all -j12
这里大家可能会有疑问,为什么我们要使用stm32mp157d-ev1开发板的设备树文件,我们不是要编译正点原子开发板的uboot吗。因为正点原子的STM32MP157开发板参照了stm32mp157d-ev1开发板,所以,我们这里编译一份与正点原子开发板非常类似的开发板uboot。我们可以将这个编译出来的uboot烧录到正点原子的开发板中,当然,烧录进去肯定是不能运行的,我们要根据具体的问题对代码进行修改,这就是移植的过程,通过不断的烧录,测试,从而移植一个能运行的uboot。
编译完成以后,就会看到下面的日志输出了:
我们可以看到uboot的源码目录下也生成了编译后的二进制文件:
至此,ST官方uboot的编译就已经完成了。
2.烧录ST官方的uboot
当我们编译完ST官方的uboot以后,就可以准备烧录了。但是在烧录期间我们会遇到一个问题,因为STM32MP157的程序下载方式,是先将uboot加载到DDR中,然后通过uboot将程序下载到EMMC中,但是我们现在uboot都没有移植成功,那就更不可能可以成功的将uboot下载到EMMC中了。怎么办呢?我们可以使用正点原子已经移植好的uboot将我们现在编译的uboot烧录进去。我们先将我们编译好的uboot改名为my_u-boot.stm32,然后将其复制到我们下载uboot的文件夹中:
然后我们需要修改一下tsv文件,这里我们将tsv文件的最后一行替换为如下:
P 0x06 ssbl Binary mmc1 0x00080000 my_u-boot.stm32
修改完以后如图所示:
这里表示,我们烧录代码时使用的uboot名为“u-boot.stm32”,实际烧入的uboot名为“my_u-boot.stm32”。然后我们使用STM32CubeProgrammer加载文件:
我们将其烧入,如果你上面是跟着我操作的,一般是不会有错误的:
烧录以后,我们将拨码拨到从EMMC启动以后,我们使用串口终端工具查看输出,发现,我们的开发板正在反复重启,并且蜂鸣器也在响。当然实际的代码中没有让蜂鸣器鸣响的代码,只是因为uboot不能运行开发板反复重启拉到的蜂鸣器的电平。总的来说我们将EV1开发板的uboot直接放在正点原子的开发板中是无法运行的:
下面,我们就来进行代码移植,使得适配正点原子的开发板。
3.移植ST官方的uboot到正点原子开发板
因为我们要将uboot移植到正点原子的开发板上,那么我们需要为正点原子的开发板添加一些必要的文件。首先就是配置文件,还记得一开始我们编译uboot使用的生成配置文件的make stm32mp15_trusted_defconfig命令吗?这个命令调用相关的文件为我们生成了编译所需的.config文件。我们现在也要为正点原子的开发板创建一个这样的文件,用来生成正点原子开发板独有的.config配置文件。因为正点原子的开发板参考了EV1的开发板,所以这个配置文件我们可以直接复制,我们首先进入uboot源码目录下的configs目录:
cd configs/
然后使用下面的命令复制开发板的配置文件并将其改名为“stm32mp15_atk_trusted_defconfig ”,这个文件就是我们开发板独有的配置文件了:
cp stm32mp15_trusted_defconfig stm32mp15_atk_trusted_defconfig
然后我们再在uboot源码目录下使用下面的命令去到设备树相关的目录:
cd 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
复制以后得到的这些设备树文件,就是正点原子开发板的专属设备树文件了,我们修改也是在我们复制出来的文件的基础上进行修改。
在修改文件之前,我这里为大家推荐一种更为简单的文件修改方式——samba,我们可以将linux虚拟机中的文件直接映射为windows中的一个磁盘,这样我们就可以直接在windows上修改Linux中的文件了,查看起来也会更简单。当然,如果你觉得这个方法不好,也可以不采纳,直接在Ubuntu中使用vscode修改的效果也是一样的。下面是samba的安装教程:
samba服务安装:[Linux]在Ubuntu中安装samba并且正确配置(详细)_ubuntu samba-CSDN博客
如图所示,我已经将我的samba配置好了:
这里再次强调一下,如果你是小白,直接使用ubuntu里面的vscode配置即可,如果你有一定的基础并且觉得我的这个方法还不错,那么,你可以采用我的方法。
下面,我们就可以直接打开uboot的源码文件夹,不管你是使用samba映射或者是直接在ubuntu中直接使用vscode,都需要使用vscode打开uboot的文件夹,打开以后如图:
下面我们打开uboot源码目录下的“arch/arm/dts/”目录下的stm32mp157d-atk.dts文件:
我们需要将第14行,也就是【#include "stm32mp15xx-edx.dtsi"】一行改为如下内容:
#include "stm32mp157d-atk.dtsi"
修改完以后如图所示:
随后我们需要修改一下电源管理设置,我们打开同位于这个目录下的“stm32mp157d-atk-u-boot.dtsi”文件:
我们将位于51-53行的如下代码直接删除:
&pmic {
u-boot,dm-pre-reloc;
};
随后我们再将23-31行的如下代码直接删除:
red {
label = "error";
gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
default-state = "off";
status = "okay";
};
随后再将21-22行的如下代码直接删除:
st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
这里文件比较长,我就不放删除以后的截图了,大家按照我的步骤进行操作即可。
下面我们要修改stm32mp157d-atk.dtsi文件,同样位于这个目录下。我们找到“&i2c4”节点,我们将“&i2c4”节点整个删掉,也就是文件中的143行到298行:
注意,这里一定是将i2c4节点整个删掉。
删掉以后上下文就是这样的:
然后我们再找到“&dac”节点,也就是114-125行,将其全部删除:
删除以后上下文如下:
然后我们再找到“&adc”节点,也就是90-104行,将其全部删除:
删除以后,上下文如下:
然后,我们继续修改stm32mp157d-atk.dtsi这个文件,找到“led”和“sd_switch”节点:
将这两个节点全部删掉:
删掉以后,上下文如图:
我们需要在stm32mp157d-atk.dtsi文件的\下添加自己的电源管理信息,我们直接来到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;
};
添加完成以后如图所示,注意这里的括号不要弄错位了:
上述代码定义了5个电源节点,分别为:vddcore、v3v3、v1v8_audio、vdd和vdd_usb, 至此,电源管理相关配置已经设置好了。
下面我们来修改TF卡和EMMC相关的配置,我们继续修改stm32mp157d-atk.dtsi文件,找到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";
};
修改完成以后,如图所示:
就在这个文件中,我们找到“usbotg_hs”节点,直接将其注释掉:
这个节点配置了OTG的电源,因为ST官方的开发板电源是使用电源管理芯片配置的,而正点原子的开发板中并没有使用电源管理芯片给OTG供电,所以,为了避免报错,我们直接注释掉即可。
下面我们来编译一下uboot,在编译uboot之前要先让编译器知道我们要编译哪个设备树 文件,打开 arch/arm/dts/Makefile文件,找到“dtb-$(CONFIG_STM32MP15x)”配置项,然后在此配置项中 加入“stm32mp157d-atk.dtb”,添加完以后如图所示:
大家还记得我们一开始的编译经历了哪些步骤吗?我们首先清除了以前编译的内容,然后生成了.config的配置文件,最后才是编译,这样的步骤我们每次编译都需要输入三条命令,太麻烦了,我们可以直接在uboot的源码目录下创建一个shell脚本来编译,我们可以在uboot的源码目录下使用下面的命令来创建一个shell脚本:
touch build
注意,这个脚本一定要创建在uboot的源码目录下。然后我们再使用下面的命令给这个脚本可执行权限:
chmod +x build
然后我们打开这个脚本输入下面的内容,这些内容就是我们要使用的命令了:
#!/bin/bash
make distclean
make stm32mp15_atk_trusted_defconfig
make DEVICE_TREE=stm32mp157d-atk all -j12
然后我们直接在uboot的源码目录下输入下面的命令就可以调用这个编译脚本来编译了:
./build
注意,这里的“./”不能省略。大家别忘了在编译时,将修改过的文件都保存一下。一定要保存,这一步很重要。
如果你上面是严格的跟着我操作的,那么编译是不会有错误的,编译完成后,如图:
我们使用查看命令可以发现,这里已经编译出了我们所需的uboot.stm32文件:
这里我们同样将其改名为my_u-boot.stm32然后复制到uboot对应的下载目录中:
这里的tsv文件我们不用修改,下面打开STM32CubeProgrammer并且加载tsv文件:
我们将这些文件下载到开发板中,下载应该是不会出错的:
然后我们将拨码切换到EMMC启动,随后使用串口终端工具查看输出:
这里我们可以看到,我们的uboot已经成功的在我们的开发板上运行起来了,那,这就表示我们的uboot已经移植成功了吗?当然还没有,我们uboot的网络和OTG都不能正常工作,我们还需要修改网络和OTG相关的部分。
下面,我们首先来修改网络节点,打开stm32mp157d-atk.dtsi文件,将下面的网络节点添加到文件的最后面:
ð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>;
};
};
};
添加好以后,如图所示:
下面我们还需要为网络芯片添加驱动,正点原子的开发板使用了YT8511作为网络驱动芯片,它的驱动文件被放在了正点原子资料目录下的“1、程序源码\08、模块驱动源码\01、YT8511驱动源码\uboot下修改方法”文件夹下:
这个.c的文件就是网络芯片的驱动代码。
我们使用这个phy.c替换掉uboot源码目录下的“/drivers/net/phy/phy.c”,我这里为了方便就直接使用samba文件映射进行替换了:
这里我们使用vscode打开这个phy.c的文件找到phy_connect这个函数,大概在1095行的位置,我们需要将这个函数中的addr直接写0:
这样我们网络部分就差不多弄好了,下面来修改USBOTG。
首先我们来为USBOTG添加一个节点,我们可以直接将下面的代码添加到stm32mp157d-atk.dtsi文件的“\”节点下,注意这里一定要是“\”节点:
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;
};
添加完成以后如图所示:
正点原子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接口相关节点,我们直接将下方的代码复制到文件末尾即可:
&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”文件中添加osbotg_hs节点,将下面的代码直接添加到stm32mp157d-atk-u-boot.dtsi的最下方:
&usbotg_hs {
u-boot,force-b-session-valid;
hnp-srp-disable;
/* TEMP: force peripheral for USB OTG */
dr_mode = "peripheral";
};
添加以后,如图所示:
至此,我们usbotg的相关节点就已经完成了。
下面,我们还需要使能boot和bootd命令,在ST原本的uboot代码中,这两条命令并没有被使能。使能这两条命令也非常简单,只需要添加一条宏定义就行,我们打开uboot源码目录下的“include/configs/”目录下的stm32mp1.h文件:
将下面这一行代码添加到258行处:
#define CONFIG_CMD_BOOTD
添加完成以后如图所示:
这样一来我们的uboot和ubootd命令就使能了。
下面我们还需要一下LCD的驱动,使uboot能够支持LCD显示。我们再次回到“stm32mp157d-atk.dts”这个文件:
我们需要在这个文件下的“\”节点下添加panel_backlight和panel_rgb两个节点:
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 参数 */
};
};
};
添加完成以后如图:
正点原子不同的屏幕对应的panel-rgb下的display-timings 也不同,我代码中对应的是正点原子的1024x600的7寸屏幕,其他屏幕的display-timings 大家根据正点原子的文档自行修改即可。
就在当前文件,我们需要添加一个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>;
};
};
};
添加完成以后,如图所示:
当我们完成上面的步骤以后,我们的uboot就算是已经移植完成了。
我们再次使用我们的编译脚本进行编译:
4.uboot自下载测试
至此,我们的uboot已经和正点原子的uboot并没有什么区别了,我们再也不需要my_u-boot.stm32了。我们可以直接将uboot下载目录下的my_u-boot.stm32和u-boot.stm32都删掉,将我们已经编译好的u-boot.stm32拷贝到uboot的下载目录下:
我们再修改一下tsv文件,将最后一行替换为下面的内容:
P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32
替换完成以后,如下图:
然后再次打开STM32CubeProgrammer加载脚本:
我们可以看到,这里使用我们自己的uboot是可以正常下载程序的:
至此,我们就完成了uboot的移植与自下载测试。
七、结语
这篇教程未免有些太长了,我写起来也有些累,在下一次的教程中,我会教大家如何使用uboot中的基础命令,在使用基础命令的同时,也可以测试我们的移植是否成功。好了,最后,感谢大家的观看!