系统移植-STM32MP1_Linux内核移植

文章目录

  • [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 根文件系统缺失)

Linux内核移植教程资源

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文件:

  1. 添加ARCH变量;
  2. 添加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文件,修改如下内容:

  1. 修改#include "stm32mp15xx-edx.dtsi"头文件引用为#include "stm32mp157d-da.dtsi"
  2. 修改/节点下的compatible属性值为"st,stm32mp157d-da", "st,stm32mp157"

打开stm32mp157d-da.dtsi文件,修改如下内容:

  1. 添加#include "stm32mp157-m4-srm.dtsi"头文件引用;
  2. 添加#include "stm32mp157-m4-srm-pinctrl.dtsi头文件引用;

3.2 修改设备树Makefile配置项

修改arch/arm/boot/dts/Makefile,修改内容如下:

  1. 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文件,修改内容如下:

  1. 添加obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o到文件中;

修改后文件内容如下:

3.3.3 Kconfig文件修改

打开linux-5.4.31/drivers/net/phy/Kconfig文件,修改内容如下:

  1. 添加下面内容到文件中;
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文件,删除如下内容:

  1. 删除/节点下的sd_switch节点、vin节点和led节点;
  2. 删除dac节点;
  3. 删除adc节点;
  4. 删除i2c4节点;
  5. 删除m4_rproc节点;
  6. 删除pwr_regulators节点;
  7. 删除timers6节点;
  8. 删除usbotg_hs节点;
  9. 删除usbphyc_port0节点;
  10. 删除usbphyc_port1节点。

3.4.2 添加

打开stm32mp157d-da.dtsi文件,添加如下内容:

  1. /下添加vddcore节点和v3v3节点;
  2. 添加ethernet0节点。

3.4.3 修改

打开stm32mp157d-da.dtsi文件,修改如下内容:

  1. 修改sdmmc1节点;
  2. 修改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";
};

&ethernet0 {
	status = "okay";
	pinctrl-0 = <&ethernet0_rgmii_pins_a>;
	pinctrl-1 = <&ethernet0_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内核加载有两种方式:

  1. 网络加载;
  2. EMMC加载。

5.2 网络加载

5.2.1 准备加载文件

将编译生成的uImagestm32mp157d-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.ext4tf-a-stm32mp157d-da-trusted.stm32tf-a-stm32mp157d-da-serialboot.stm32u-boot.stm32文件(其中u-boot.stm32tf-a-stm32mp157d-da-trusted.stm32tf-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内核启动后是正常的,因为还没有设置根文件系统。

相关推荐
萧行之1 天前
Linux 下 Miniconda3 清华源极速安装教程(含报错解决、一键复制)
linux·运维·服务器
ZzzZZzzzZZZzzzz…1 天前
MySQL备份还原方法2----LVM
linux·运维·数据库·mysql·备份还原
x²+(y-√³x²)²=11 天前
Linux 或者 Ubuntu 离线使用 vllm启动大模型
linux·ubuntu·vllm
沉鱼.441 天前
第十五届题目
linux·运维·算法
凤年徐1 天前
Linux权限详解:从入门到掌握
linux·运维·服务器
zzzyyy5381 天前
进程优先级
linux·运维·服务器
小鸡食米1 天前
Linux-例行性工作+时间服务器
linux·服务器·网络
Bert.Cai1 天前
Linux head命令详解
linux·运维
Huy-C1 天前
云计算案例排错(云上4)
linux·运维·云计算
路溪非溪1 天前
Linux中Netlink简介和使用总结
linux·网络·arm开发·驱动开发