文章目录
- [1 说明及源码获取](#1 说明及源码获取)
-
- [1.1 源码获取](#1.1 源码获取)
- [1.2 安装依赖包](#1.2 安装依赖包)
- [1.3 Linux内核源码打补丁](#1.3 Linux内核源码打补丁)
- [1.4 生成默认配置文件](#1.4 生成默认配置文件)
- [1.5 修改编译配置](#1.5 修改编译配置)
- [2 注意事项](#2 注意事项)
- [3 Linux内核移植](#3 Linux内核移植)
-
- [3.1 创建默认配置设备树](#3.1 创建默认配置设备树)
- [3.2 修改设备树Makefile配置项](#3.2 修改设备树Makefile配置项)
- [3.3 网络驱动修改](#3.3 网络驱动修改)
-
- [3.3.1 驱动源文件替换](#3.3.1 驱动源文件替换)
- [3.3.2 Makefile文件修改](#3.3.2 Makefile文件修改)
- [3.3.3 Kconfig文件修改](#3.3.3 Kconfig文件修改)
- [3.3.4 使能YT8511网络驱动](#3.3.4 使能YT8511网络驱动)
- [3.4 更新stm32mp157d-da.dtsi文件](#3.4 更新stm32mp157d-da.dtsi文件)
-
- [3.4.1 删除](#3.4.1 删除)
- [3.4.2 添加](#3.4.2 添加)
- [3.4.3 修改](#3.4.3 修改)
- [3.4.4 stm32mp157d-da.dtsi文件最终内容](#3.4.4 stm32mp157d-da.dtsi文件最终内容)
- [3.5 关闭内核模块验证](#3.5 关闭内核模块验证)
- [3.6 关闭内核log信息时间戳](#3.6 关闭内核log信息时间戳)
- [4 备份.config文件](#4 备份.config文件)
- [5 编译及烧录](#5 编译及烧录)
-
- [5.1 编译](#5.1 编译)
- [5.2 网络加载](#5.2 网络加载)
-
- [5.2.1 准备加载文件](#5.2.1 准备加载文件)
- [5.2.2 Linux内核运行](#5.2.2 Linux内核运行)
- [5.2.3 uboot设置linux内核网络加载](#5.2.3 uboot设置linux内核网络加载)
- [5.3 EMMC加载](#5.3 EMMC加载)
-
-
- [5.3.1.1 bootfs.ext4文件制作](#5.3.1.1 bootfs.ext4文件制作)
- [5.3.1.2 Linux内核烧录](#5.3.1.2 Linux内核烧录)
-
- [5.3.1.2.1 文件准备](#5.3.1.2.1 文件准备)
- [5.3.1.2.2 使用USB烧写bootfs.ext4](#5.3.1.2.2 使用USB烧写bootfs.ext4)
- [5.3.1.3 Linux内核运行](#5.3.1.3 Linux内核运行)
- [5.3.1.4 uboot设置Linux内核从EMMC启动](#5.3.1.4 uboot设置Linux内核从EMMC启动)
-
- [6 Linux内核移植结果验证](#6 Linux内核移植结果验证)
- [7 根文件系统缺失](#7 根文件系统缺失)
1 说明及源码获取
1.1 源码获取
使用正点原子提供的en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-06-24.tar.xz。
使用如下命令解压文件:
bash
tar -xvf en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-06-24.tar.xz
目录下包含了如下文件夹:
| 文件夹 | 描述 |
|---|---|
| linux-stm32mp-5.4.31-r0 | linux源码,版本号为5.4.31 |
| optee-os-stm32mp-3.9.0.r1-r0 | optee系统源码,版本为3.9.0 |
| tf-a-stm32mp-2.2.r1-r0 | tf-a源码,版本号为2.2 |
| tf-a-stm32mp-ssp-2.2.r1-r0 | tf-a源码,ssp全称为secure secert provisioning,安全相关的内容 |
| u-boot-stm32mp-2020.01-r0 | uboot源码,版本号为2020.01 |
linux内核使用linux-stm32mp-5.4.31-r0文件夹内容。
1.2 安装依赖包
bash
sudo apt update
sudo apt install lzop
sudo apt install libssl-dev
sudo apt install u-boot-tools
STM32MP1编译出来的Linux内核镜像文件为uImage,这是uboot所使用的内核镜像格式,通过在zImage镜像的前面添加0X40个字节的头部来得到uImage,这个需要mkimage工具来完成此工作。使用sudo apt install u-boot-tools命令在Ubuntu下安装mkimage工具。
1.3 Linux内核源码打补丁
将linux-stm32mp-5.4.31-r0文件夹内容重新拷贝到一个新的文件夹中,例如/home/alientek/linux/da-mp1/da/kernel在新的文件夹中使用如下命令打补丁:
bash
# 在 /home/alientek/linux/da-mp1/da/kernel 文件夹下打开一个终端,执行如下命令:
tar -vxf linux-5.4.31.tar.xz
cd linux-5.4.31/
for p in `ls -1 ../*.patch`; do patch -p1 < $p; done # 打补丁
1.4 生成默认配置文件
编译linux内核的时候也需要使用make xxx_defconfig来对其进行默认配置,ST官方原厂Linux内核需要先生成默认配置文件,并且对其进行打补丁,命令如下:
bash
cd linux-5.4.31/
make ARCH=arm multi_v7_defconfig "fragment*.config" # 生成默认配置文件
# 如下两条命令将 fragment config补丁文件打入 .config 文件中
for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done
yes '' | make ARCH=arm oldconfig # 命令中的 '' 为两个 '
经过上述命令生成了默认的.config文件。建议在自行调整了kernel的配置参数后,将新的配置文件.config拷贝一份到./arch/arm/configs/xxx_defconfig,避免执行make distclean将新配置文件.config删除。使用以下命令备份.config文件:
bash
cd linux-5.4.31/
cp .config ./arch/arm/configs/stm32mp1_da_defconfig
1.5 修改编译配置
主要修改Makefile文件:
- 添加
ARCH变量; - 添加
CROSS_COMPILE变量。
在linux-5.4.31/Makefile中修改,在文件的第361行添加如下代码:
makefile
ARCH = arm
CROSS_COMPILE = arm-none-linux-gnueabihf-
添加前内容:

添加后内容:

2 注意事项
内核移植涉及修改内容较多,为避免最后结果不符合预期,建议可以在有效修改后分步骤编译运行,查看结果,可以提高最后结果的正确性。
3 Linux内核移植
3.1 创建默认配置设备树
bash
cd linux-5.4.31/
cd arch/arm/boot/dts/
cp stm32mp15xx-edx.dtsi stm32mp157d-da.dtsi
cp stm32mp157d-ed1.dts stm32mp157d-da.dts
打开stm32mp157d-da.dts文件,修改如下内容:
- 修改
#include "stm32mp15xx-edx.dtsi"头文件引用为#include "stm32mp157d-da.dtsi" - 修改
/节点下的compatible属性值为"st,stm32mp157d-da", "st,stm32mp157"。
打开stm32mp157d-da.dtsi文件,修改如下内容:
- 添加
#include "stm32mp157-m4-srm.dtsi"头文件引用; - 添加
#include "stm32mp157-m4-srm-pinctrl.dtsi头文件引用;
3.2 修改设备树Makefile配置项
修改arch/arm/boot/dts/Makefile,修改内容如下:
- 在
dtb-$(CONFIG_ARCH_STM32)配置项中添加stm32mp157d-da.dtb。
修改后内容如下:
makefile
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-da.dtb
3.3 网络驱动修改
3.3.1 驱动源文件替换
正点原子V1.3及以后版本的核心板开始将网络PHY芯片更换为了国产裕太电子的YT8511所以需要修改一下驱动。
使用提供的资源目录/yt8511/motorcomm.c拷贝到linux-5.4.31/drivers/net/phy/文件夹中,使用提供的资源目录/yt8511/motorcomm_phy.h拷贝到linux-5.4.31/include/linux/文件夹中。
3.3.2 Makefile文件修改
打开linux-5.4.31/drivers/net/phy/Makefile文件,修改内容如下:
- 添加
obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o到文件中;
修改后文件内容如下:

3.3.3 Kconfig文件修改
打开linux-5.4.31/drivers/net/phy/Kconfig文件,修改内容如下:
- 添加下面内容到文件中;
tex
config MOTORCOMM_PHY
tristate "Motorcomm PHYs"
---help---
Supports the YT8010, YT8510, YT8511, YT8512 PHYs.
修改后文件内容如下:

3.3.4 使能YT8511网络驱动
bash
cd linux-5.4.31/
make menuconfig
按照下图修改:

修改完成之后退出保存。并执行如下命令保存最新配置到arch/arm/configs/stm32mp1_da_defconfig文件:
bash
cd linux-5.4.31/
cp .config ./arch/arm/configs/stm32mp1_da_defconfig
3.4 更新stm32mp157d-da.dtsi文件
3.4.1 删除
打开stm32mp157d-da.dtsi文件,删除如下内容:
- 删除
/节点下的sd_switch节点、vin节点和led节点; - 删除
dac节点; - 删除
adc节点; - 删除
i2c4节点; - 删除
m4_rproc节点; - 删除
pwr_regulators节点; - 删除
timers6节点; - 删除
usbotg_hs节点; - 删除
usbphyc_port0节点; - 删除
usbphyc_port1节点。
3.4.2 添加
打开stm32mp157d-da.dtsi文件,添加如下内容:
- 在
/下添加vddcore节点和v3v3节点; - 添加
ethernet0节点。
3.4.3 修改
打开stm32mp157d-da.dtsi文件,修改如下内容:
- 修改
sdmmc1节点; - 修改
sdmmc2节点。
3.4.4 stm32mp157d-da.dtsi文件最终内容
d
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* Copyright (C) STMicroelectronics 2017 - All Rights Reserved
* Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
*/
#include "stm32mp157-m4-srm.dtsi"
#include "stm32mp157-m4-srm-pinctrl.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/mfd/st,stpmic1.h>
/ {
memory@c0000000 {
device_type = "memory";
reg = <0xC0000000 0x40000000>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
mcuram2: mcuram2@10000000 {
compatible = "shared-dma-pool";
reg = <0x10000000 0x40000>;
no-map;
};
vdev0vring0: vdev0vring0@10040000 {
compatible = "shared-dma-pool";
reg = <0x10040000 0x1000>;
no-map;
};
vdev0vring1: vdev0vring1@10041000 {
compatible = "shared-dma-pool";
reg = <0x10041000 0x1000>;
no-map;
};
vdev0buffer: vdev0buffer@10042000 {
compatible = "shared-dma-pool";
reg = <0x10042000 0x4000>;
no-map;
};
mcuram: mcuram@30000000 {
compatible = "shared-dma-pool";
reg = <0x30000000 0x40000>;
no-map;
};
retram: retram@38000000 {
compatible = "shared-dma-pool";
reg = <0x38000000 0x10000>;
no-map;
};
};
vddcore: buck1 {
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;
};
};
&cpu0{
cpu-supply = <&vddcore>;
};
&crc1 {
status = "okay";
};
&dma1 {
sram = <&dma_pool>;
};
&dma2 {
sram = <&dma_pool>;
};
&dts {
status = "okay";
};
ð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>;
};
};
};
&hash1 {
status = "okay";
};
&ipcc {
status = "okay";
};
&iwdg2 {
timeout-sec = <32>;
status = "okay";
};
&rng1 {
status = "okay";
};
&rtc {
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>;
broken-cd;
st,neg-edge;
bus-width = <4>;
vmmc-supply = <&v3v3>;
status = "okay";
};
&sdmmc2 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc2_b4_pins_a>;
pinctrl-1 = <&sdmmc2_b4_od_pins_a>;
pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>;
non-removable;
st,neg-edge;
bus-width = <8>;
vmmc-supply = <&v3v3>;
keep-power-in-suspend;
status = "okay";
};
&sram {
dma_pool: dma_pool@0 {
reg = <0x50000 0x10000>;
pool;
};
};
&uart4 {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <&uart4_pins_a>;
pinctrl-1 = <&uart4_sleep_pins_a>;
pinctrl-2 = <&uart4_idle_pins_a>;
pinctrl-3 = <&uart4_pins_a>;
/delete-property/dmas;
/delete-property/dma-names;
status = "okay";
};
3.5 关闭内核模块验证
Linux驱动的时候都是编译驱动模块,然后在系统里面加载,加载的时候系统会验证模块,有时候会验证出错。比如板子运行的系统和编译驱动模块所用的系统不一致的时候。为了方便开发,我们可以关闭内核模块验证。
bash
cd linux-5.4.31/
make menuconfig
按照下图修改:

修改完成之后退出保存。并执行如下命令保存最新配置到arch/arm/configs/stm32mp1_da_defconfig文件:
bash
cd linux-5.4.31/
cp .config ./arch/arm/configs/stm32mp1_da_defconfig
3.6 关闭内核log信息时间戳
bash
cd linux-5.4.31/
make menuconfig
按照下图修改:

修改完成之后退出保存。并执行如下命令保存最新配置到arch/arm/configs/stm32mp1_da_defconfig文件:
bash
cd linux-5.4.31/
cp .config ./arch/arm/configs/stm32mp1_da_defconfig
4 备份.config文件
针对有效修改Linux内核配置项后使用以下命令备份:
bash
cd linux-5.4.31/
cp .config ./arch/arm/configs/stm32mp1_da_defconfig
这样做的目的就是为了防止在make distclen时将配置文件删除,也可以使用如下命令加载配置:
bash
cd linux-5.4.31/
make stm32mp1_da_defconfig
5 编译及烧录
5.1 编译
使用如下命令编译:
bash
cd linux-5.4.31/
make uImage dtbs LOADADDR=0XC2000040 -j8
# 可单独编译设备树 或者 内核镜像
make dtbs -j8 # 单独编译设备树
make uImage LOADADDR=0XC2000040 -j8 # 单独编译内核镜像
编译成功后会在linux-5.4.31/arch/arm/boot/目录下生成uImage内核镜像文件,在linux-5.4.31/arch/arm/boot/dts目录下生成stm32mp157d-da.dtb文件。
Linux内核加载有两种方式:
- 网络加载;
- EMMC加载。
5.2 网络加载
5.2.1 准备加载文件
将编译生成的uImage和stm32mp157d-da.dtb文件拷贝到tftp服务端设置的文件夹中,笔者的tftp服务根目录为/home/alientek/linux/tftpboot/,可以使用如下命令拷贝文件:
bash
cd linux-5.4.31/
cp ./arch/arm/boot/uImage ./arch/arm/boot/dts/stm32mp157d-da.dtb /home/alientek/linux/tftpboot/
5.2.2 Linux内核运行
打开MobaXterm软件,设置好与开发板连接的串口,波特率选择115200。
设置开发板拨码开关为010,也就是从EMMC启动,然后复位开发板!
在串口中观察启动过程。
5.2.3 uboot设置linux内核网络加载
在系统启动的uboot阶段,进入uboot命令行,可以通过如下命令进行Linux内核网络加载(每次都需要进入uboot执行命令):
bash
tftp c2000000 uImage
tftp c4000000 stm32mp157d-da.dtb
bootm c2000000 - c4000000
也可以将上述命令设置到bootcmd环境变量中,只设置一次就可以:
bash
setenv bootcmd 'tftp c2000000 uImage;tftp c4000000 stm32mp157d-da.dtb;bootm c2000000 - c4000000'
saveenv
boot
5.3 EMMC加载
5.3.1.1 bootfs.ext4文件制作
bash
# 第一步:在家目录中选择合适位置,创建 bootfs 文件夹,并进入
mkdir bootfs
cd bootfs
# 第二步:将生成的 uImage 和 stm32mp157d-da.dtb 文件拷贝到 bootfs 文件夹目录中
# 第三步:新建 ext4 格式磁盘
# of为名称,bs为块大小,count为块数量,所以 bootfs.ext4 文件大小为10MB,如果空间不够则调整 count
dd if=/dev/zero of=bootfs.ext4 bs=1M count=10
# -L bootfs 为卷名,使用 mkfs.ext4 将 bootfs.ext4 文件格式化为 ext4 格式,且指定卷名为 bootfs
mkfs.ext4 -L bootfs bootfs.ext4
# 第四步:将系统镜像拷贝到 ext4 磁盘中
sudo mkdir /mnt/bootfs
sudo mount bootfs.ext4 /mnt/bootfs/
sudo cp uImage stm32mp157d-da.dtb /mnt/bootfs/
# 第五步:卸载 /mnt/bootfs
sudo umount /mnt/bootfs
将生成的bootfs.ext4文件拷贝到win系统中,便于后续烧录。
5.3.1.2 Linux内核烧录
5.3.1.2.1 文件准备
将制作好的的bootfs.ext4、tf-a-stm32mp157d-da-trusted.stm32和tf-a-stm32mp157d-da-serialboot.stm32、u-boot.stm32文件(其中u-boot.stm32、tf-a-stm32mp157d-da-trusted.stm32和tf-a-stm32mp157d-da-serialboot.stm32使用已经编译好的),统一放入文件夹中,例如:da-images文件夹。在da-images文件夹中添加da.tsv文件;文件内容如下所示:
tex
#Opt Id Name Type Device Offset Binary
- 0x01 fsbl1-boot Binary none 0x0 tf-a-stm32mp157d-da-serialboot.stm32
- 0x03 ssbl-boot Binary none 0x0 u-boot.stm32
P 0x04 fsbl1 Binary mmc1 boot1 tf-a-stm32mp157d-da-trusted.stm32
P 0x05 fsbl2 Binary mmc1 boot2 tf-a-stm32mp157d-da-trusted.stm32
P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32
P 0x21 boot System mmc1 0x00280000 bootfs.ext4
文件内容格式要严格遵循下图:

tsv语法要求只能用TAB键,不能用空格!以#开头为注释。
最终da-images文件夹中的内容如下:

使用STM32CubeProgrammer采用USB的方式烧写至开发板中,也就是USB_OTG口来烧写系统。
5.3.1.2.2 使用USB烧写bootfs.ext4
通过USBType-C线将开发板的USB_OTG和USB_TTL连接到电脑上。

设置开发板拨码开关,设置为000,也就是从USB启动,然后复位开发板。
打开STM32CubeProgrammer,选择USB连接方式,Port选择USB1。

USB设置好以后点击右上角的"Connect"来连接开发板,连接成功以后左下角的log区域就会输出一些信息,右侧中间的数据区域也会显示开发板默认的分区情况,右下角会显示目标板信息,如图所示:

STM32CubeProgrammer要使用FlashLayout文件来烧写系统,也就是da-images文件夹下的da.tsv。点击界面上的"Open File",打开da.tsv,如下图所示:

烧写完成后会有如下提示:

5.3.1.3 Linux内核运行
打开MobaXterm软件,设置好与开发板连接的串口,波特率选择115200。
设置开发板拨码开关为010,也就是从EMMC启动,然后复位开发板!
在串口中观察启动过程。
5.3.1.4 uboot设置Linux内核从EMMC启动
bash
setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157d-da.dtb;bootm c2000000 - c4000000'
saveenv
boot
6 Linux内核移植结果验证
下面图片有内核的时间信息。

7 根文件系统缺失

tex
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,19) ]---
内核崩溃,崩溃原因是VFS(虚拟文件系统)不能挂载根文件系统。在Linux内核启动后是正常的,因为还没有设置根文件系统。