【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

时间:2023-01-14 09:59:44

1)实验平台:正点原子MPSoC开发板
2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html

第十三章Linux内核移植

前面章节我们简单了解了一下Linux内核顶层Makefile和Linux内核的启动流程,本章我们就来学习一下如何将Xilinx官方提供的Linux内核移植到正点原子的MPSoc开发板上。需要说明的是当我们使用Petalinux工具的时候是不需要移植内核的,因为Petalinux工具可以根据硬件描述文件xsa使能相应配置。本章讲解内核移植(更准确的说是内核适配)是为了了解一般情况下(不使用Petalinux)的内核移植过程。通过本章的学习,我们将掌握如何将半导体厂商提供的Linux BSP包移植到我们自己的平台上。

13.1Linux内核获取
关于Linux的起源以及发展历史,网上相关的介绍太多了,这里不作过多介绍。Linux由Linux基金会管理与发布,Linux官网为https://www.kernel.org,所以你想获取最新的Linux版本就可以在这个网站上下载,网站界面如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.1.1 linux官网
从上图可以看出最新的稳定版Linux已经到了5.17.9,大家没必要追新,因为4.x版本的Linux和5.x版本没有本质上的区别,5.x更多的是加入了一些新的平台、新的外设驱动而已。
Xilinx会从https://www.kernel.org下载某个版本的Linux内核,然后将其移植到自己的芯片平台上,测试成功以后就会将其开放给Xilinx的芯片平台开发者。开发者下载Xilinx提供的Linux内核,然后将其移植到自己的产品上。后面的移植我们使用Xilinx提供的Linux源码,Xilinx提供的Linux内核源码发布在https://github.com/Xilinx/linux-xlnx,可以clone或下载,注意要与Petalinux版本一致,否则会出现一些问题,我们使用的是2019.2版本的Petalinux,所以选择的linux内核源码要带2019.2(Tags带2019.2)。不过我们不从上面的github网站下载,因为在6.3.5节配置Linux内核时,Petalinux工具就已经生成了linux内核源码,如下图所示,所以没有必要从github网站下载。
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.1.2 Xilinx linux内核源码
后面的linux内核移植和驱动开发都需要使用该源码,为了方便访问和备份(版本管理),
我们将Petalinux生成的linux内核源码拷贝到12.1.1节建立的git.d文件夹下,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.1.3拷贝linux内核源码到git.d目录
13.2Petalinux使用外部linux内核源码
上一节我们将Petalinux生成的内核源码移动到~/git.d/linux-xlnx目录(绝对路径/home/shang/git.d/linux-xlnx),以后我们在该内核源码上移植修改、添加驱动等,Petalinux工程都无法使用该内核源码了,如何让Petalinux能访问使用呢?
方法如下:

  1. 进入到Petalinux工程目录下,设置好Petalinux工作环境后,输入“petalinux-config”命令配置Petalinux工程。
    设置Linux Components Selection —>linux-kernel (linux-xlnx) —>为“ext-local-src”,如下图所示:
    【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.2.1配置linux-kernel
该配置项将linux来源配置为外部的本地源。设置好后按回车键返回。设置External linux-kernel local source settings —> External linux-kernel local source path (NEW)为“/home/shang/git.d/linux-xlnx”,也就是当前内核源码存放的目录,结果如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.2.2配置External linux-kernel local source path
保存配置并退出,现在该Petalinux工程就可以访问和使用/home/ shang /git.d/linux-xlnx中的内核源码了。
需要注意的一点是在Petalinux工程配置linux内核和编译时需要先清理/home/ shang /git.d/linux-xlnx中的内核(命令 make distclean),否则配置和编译会报错(12.2节外部uboot源码也要清理)。
13.3Linux内核编译初次编译
我们在13.1小节中将Petalinux生成的linux内核源码放到了git.d文件夹下。现在进入到该内核源码目录处,查看内核目录结构,命令如下:
cd ~/git.d/linux-xlnx/
ls
可以看到Linux源码根目录如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.3.1 Linux内核源码根目录
其中oe-logs和oe-workdir是Petalinux工具生成的链接目录,不是linux内核的源码目录。
现在我们讲解一下如何编译出对应的Linux镜像文件。新建名为“zynqmp.sh”的shell脚本,然后在这个shell脚本里面输入如下所示内容:
示例代码 zynqmp.sh文件内容
#!/bin/sh
make distclean
make xilinx_zynqmp_defconfig
unset PKG_CONFIG_PATH
make menuconfig
make -j8
第2行,执行“make distclean”,清理工程,所以zynqmp.sh每次都会清理一下工程。如果通过图形界面配置了Linux,但是还没保存新的配置文件,那么就要慎重使用zynqmp.sh编译脚本了,因为它会把你的配置信息都删除掉。
第3行,执行“make xxx_defconfig”,配置工程。该配置文件在/home/shang/git.d/linux-xlnx/arch/arm64/configs路径下。
第4行,执行“unset PKG_CONFIG_PATH”,取消环境变量PKG_CONFIG_PATH。打开图形配置界面需要先取消该环境变量,否则有问题。
第5行,执行“make menuconfig”,打开图形配置界面,对Linux进行配置,如果不想每次编译都打开图形配置界面的话可以将这一行删除掉。
第6行,执行“make”,编译Linux源码。如果读者ubuntu虚拟机使用的是多核处理器,可以在make命令后加参数“-jn”来加快编译,其中n表示处理器核数,笔者虚拟机是8核,所以这里参数为“-j8”。
可以看出,Linux的编译过程基本和uboot一样,都要先执行“make xxx_defconfig”来配置一下,然后再执行“make”进行编译。如果需要使用图形界面配置的话就执行“make menuconfig”。
使用chmod给予zynqmp.sh可执行权限,然后运行此shell脚本,命令如下:
chmod 777 zynqmp.sh
./zynqmp.sh
编译的时候会弹出Linux图形配置界面,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.3.2 Linux图形配置界面
Linux的图行界面配置和uboot是一样的,这里我们不需要做任何的配置,直接按两下ESC键退出,退出图形界面以后会自动开始编译Linux。等待编译完成,完成以后如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.3.3 Linux编译完成
编译完成以后就会在arch/arm64/boot这个目录下生成一个叫做Image的文件,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.3.4 Linux内核镜像文件
Image就是我们要用的Linux内核镜像文件。Image.gz文件是Image文件的压缩文件,可以用uboot的bootz命令启动,不过Xilinx不用该文件。
另外也会在arch/arm64/boot/dts/xilinx下生成很多.dtb文件,这些.dtb就是设备树文件,比如zynqmp-zcu102-rev1.0.dtb文件就是xilinx zcu102开发板对应的设备树文件。
13.4Linux内核源码工程目录分析
我们在13.1节获取的linux内核源码目录如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.4.1未编译的Linux内核源码目录
上图是petalinux生成的未编译的Linux源码目录文件,我们在分析Linux之前一定要先在Ubuntu中编译一下Linux,因为编译过程会生成一些文件,而生成的这些恰恰是分析Linux不可或缺的文件。编译后的Linux目录如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.4.2编译后的Linux目录
上图中重要的文件夹或文件的含义如下表所示:
表 13.4.1 Linux目录
类型 名字 描述 备注
文件夹 arch 架构相关目录。 Linux自带
block 块设备相关目录。
crypto 加密相关目录。
Documentation 文档相关目录。
drivers 驱动相关目录。
firmeare 固件相关目录。
fs 文件系统相关目录。
include 头文件相关目录。
init 初始化相关目录。
ipc 进程间通信相关目录。
kernel 内核相关目录。
lib 库相关目录。
mm 内存管理相关目录。
net 网络相关目录。
samples 例程相关目录。
scripts 脚本相关目录。
security 安全相关目录。
sound 音频处理相关目录。
tools 工具相关目录。
usr 与initramfs相关的目录,用于生成initramfs。
virt 提供虚拟机技术(KVM)。
文件 .config Linux最终使用的配置文件。 编译生成的文件。
.gitignore git工具相关文件。 Linux自带
.mailmap 邮件列表。
.missing-syscalls.d 。 编译生成的文件
.tmp_xx 这是一系列的文件,作用目前笔者还不是很清楚。 编译生成的文件
.version 好像和版本有关。
.vmlinux.cmd cmd文件,用于连接生成vmlinux。
COPYING 版权声明。 Linux自带
CREDITS Linux贡献者。
Kbuild Makefile会读取此文件。
Kconfig 图形化配置界面的配置文件。。
MAINTAINERS 维护者名单。
Makefile Linux顶层Makefile
Module.xx
modules.xx 一系列文件,和模块有关。 编译生成的文件
zynqmp.sh 正点原子提供的,Linux编译脚本。 正点原子提供
README Linux描述文件。 Linux自带
System.map 符号表。 编译生成的文件
vmlinux 编译出来的、未压缩的ELF格式Linux文件
vmlinux.o 编译出来的vmlinux.o文件。
上表中的很多文件夹和文件我们都不需要去关心,我们要关注的文件夹或文件如下:
1、arch目录
这个目录是和架构有关的目录,比如arm、arm64、avr32、x86等等架构。每种架构都对应一个目录,在这些目录中又有很多子目录,比如boot、common、configs等等,以arch/arm64为例,其子目录如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.4.3 arch/arm子目录
上图是arch/arm64的子目录,这些子目录用于控制系统引导、系统调用、动态调频、主频设置等。arch/arm64/configs目录是不同平台的默认配置文件:xxx_defconfig,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.4.4配置文件
可以看到,总共有3个defconfig文件,其中两个以xilinx开头的都是用于Xilinx厂商soc系列的配置文件。xilinx_zynqmp_defconfig属于Zynq UltraScale+ MPSoC系列平台的通用默认配置文件,xilinx_versal_defconfig应该属于Versal系列平台的通用默认配置文件。执行“make xilinx_zynqmp_defconfig”即可完成配置。
arch/arm64/boot/dts/xilinx/目录里面是对应开发平台的设备树文件,xilinx zcu102开发板对应的设备树文件如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.4.5正点原子DFZU2EG_4EV MPSoC开发板对应的设备树
其中zynqmp-zcu102-rev1.0.dts为zcu102开发板1.0版本的设备树文件,编译后的设备树镜像文件为zynqmp-zcu102-rev1.0.dtb。
arch/arm64/boot目录中有编译出来的Image镜像文件,而Image就是我们要用的linux镜像文件。
arch/arm/mach-xxx目录分别为相应平台的驱动和初始化文件,比如mach-zynq目录里面就是ZYNQ 系列CPU的驱动和初始化文件。
2、block目录
block是Linux下块设备目录,像SD卡、eMMC、NAND、硬盘等存储设备就属于块设备,block目录中存放着管理块设备的相关文件。
3、crypto目录
crypto目录里面存放着加密文件,比如常见的crc、crc32、md4、md5、hash等加密算法。
4、Documentation目录
此目录里面存放着Linux相关的文档,如果要想了解Linux某个功能模块或驱动架构的功能,就可以在Documentation目录中查找有没有对应的文档。
5、drivers目录
设备驱动程序目录,此目录根据驱动类型的不同,分门别类进行整理,比如drivers/i2c就是I2C相关驱动目录,drivers/gpio就是GPIO相关的驱动目录,这是我们学习的重点。
6、firmware目录
此目录用于存放固件。
7、fs目录
此目录存放文件系统相关代码,比如fs/ext2、fs/ext4、fs/f2fs等,分别是ext2、ext4和f2fs等文件系统。
8、include目录
头文件目录。与系统相关的头文件被放置在内核 include/linux子目录下。
9、init目录
此目录存放Linux内核启动的时候初始化代码。
10、ipc目录
IPC为进程间通信,ipc目录是进程间通信的具体实现代码。
11、kernel目录
Linux内核代码。与平台相关的部分代码放在arch//kernel目录下,其中代表各种处理器平台
12、lib目录
lib是库的意思,lib目录都是一些公用的库函数。
13、mm目录
此目录存放与平台无关的内存管理代码,与平台相关的内存管理代码放在arch/*/mm目录下。
14、net目录
此目录存放网络相关代码。
15、samples目录
此目录存放一些示例代码文件。
16、scripts目录
脚本目录,Linux编译的时候会用到很多脚本文件,这些脚本文件就保存在此目录中。
17、security目录
此目录存放安全相关的文件。
18、sound目录
此目录存放音频相关驱动文件,音频驱动文件并没有存放到drivers目录中,而是单独的目录。
19、tools目录
此目录存放一些编译的时候使用到的工具。
20、usr目录
此目录存放与initramfs有关的代码。
21、virt目录
此目录存放虚拟机相关文件。
22、.config文件
根uboot一样,.config保存着Linux最终的配置信息,编译Linux的时候会读取此文件中的配置信息。最终根据配置信息来选择编译Linux哪些模块,哪些功能。
23、Kbuild文件
有些Makefile会读取此文件。
24、Kconfig文件
图形化配置界面的配置文件。
25、Makefile文件
Linux顶层Makefile文件,建议好好阅读一下此文件。
26、README文件
此文件详细讲解了如何编译Linux源码,以及Linux源码的目录信息,建议仔细阅读一下此文件。
13.5移植准备工作
从本小节开始,我们对官方linux内核进行移植,使其能在正点原子MPSoC开发板上启动并正常工作。
进入到13.1节创建的linux内核源码目录~/git.d/linux-xlnx,输入如下命令清理linux内核源码:
make distclean
初次移植不知道该添加哪些文件的时候,最好的方法就是看看别的开发板是怎么添加的,我们以Xilinx的ZCU102开发板为例,看看内核源码中有哪些文件或文件夹与ZCU102开发板有关。
输入如下命令,根据文件名称或文件夹名称,查找与ZCU102开发板有关的文件或文件夹:
find . -name “zcu102
结果如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.5.1查找相关的文件或文件夹
然后搜索内容中带有zcu102字样的文件,命令如下:
grep -irn --exclude-dir=.git “zcu102”
结果如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.5.2带zcu102字样的文件
由于Documentation文件夹是说明文档,不编译进内核,剩下的就是arch/arm64/boot/dts/xilinx目录下的Makefile和设备树dts文件了。
下面开始移植。
13.6移植步骤
13.6.1添加开发板默认配置文件
编译内核之前需要先配置内核,配置内核用的文件为开发板的默认内核配置文件。开发板的默认内核配置文件在内核源码的arch//configs目录下,ARCH对应开发板使用的芯片架构,对于我们使用的MPSoC开发板而言,ARCH为arm64。在添加之前先看下arch/arm64/configs目录下arm64架构不同平台的默认配置文件,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.1默认配置文件
可以看到,总共有3个defconfig文件,其中两个以xilinx开头的都是用于Xilinx厂商soc系列的配置文件。前面说过,xilinx_zynqmp_defconfig是用于Zynq UltraScale+ MPSoc系列平台的通用默认配置文件,为了保持一致,我们依旧使用xilinx_zynqmp_defconfig作为开发板的默认配置文件。不过呢,我们还是可以修改xilinx_zynqmp_defconfig的。要想修改配置文件,首先得知道配置项的含义,如果直接打开xilinx_zynqmp_defconfig文件来修改的话,移除配置项到还可以,添加的话,就无从谈起了,所以我们得在图形配置界面修改配置项。此处我们就不修改了,保持默认的配置即可。
可以使用如下命令来配置正点原子MPSoC开发板对应的linux内核:
make xilinx_zynqmp_defconfig
13.6.2添加开发板对应的设备树文件
Linux支持设备树,每个开发板都有对应的设备树文件。Xilinx的Zynq UltraScale+ MPSoc系列芯片的所有设备树文件都存放在arch/arm64/boot/dts/xilinx目录下,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.2 Zynq UltraScale+ MPSoc系列芯片的所有设备树文件
其中zynqmp.dtsi、zynqmp-clk.dtsi和zynqmp-clk-ccf.dtsi设备树文件是Zynq UltraScale+ MPSoc系列芯片通用的基础设备树文件,我们在12.4.4小节有介绍。Makefile用于设置哪些设备树文件将被编译,其内容如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.3默认编译的设备树
当编译linux内核源码时,这些设备树文件也会默认编译,如果不想编译其中的某些设备树文件,可以删除或注释相应行。
不同的开发板有不同的设备树文件,我们自己的开发板当然得用我们自己的设备树文件。设备树文件从哪来,可以参考其他开发板的设备树文件,然后与自己的开发板对比,手动编写,不过这样做工作量太大,没什么意义,除非迫不得已,否则不推荐这种方法。最简便直接的方法是用Petalinux工具生成的设备树文件。Petalinux工具会根据我们提供的开发板xsa文件自动生成相应的设备树文件,生成的设备树文件在Petalinux工程(第六章Petalinux设计流程实战章节建立的Petalinux工程)的components/plnx_workspace/device-tree/device-tree目录下,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.4 Petalinux生成的设备树文件
后缀为dtsi和dts的都是设备树文件,这些设备树文件都是Petalinux根据xsa自动生成的。关于这些设备树文件的含义在前面移植uboot的时候已经讲解过了。
要想在linux内核源码中添加开发板的设备树文件,可以将system-top.dts文件及其依赖文件添加到linux内核源码中。打开system-top.dts文件,其内容如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.5 system-top.dts文件的内容
可以看到总共include五个设备树文件,其中zynqmp.dtsi和zynqmp-clk-ccf.dtsi是通用文件,不用添加,剩下的pcw.dtsi、pl.dtsi和system-user.dtsi需要添加。
进入到第六章创建的Petalinux工程的components/plnx_workspace/device-tree/device-tree目录下,然后输入如下命令将设备树文件复制到linux内核源码相应目录:
cp pcw.dtsi pl.dtsi ~/git.d/linux-xlnx/arch/arm64/boot/dts/xilinx/
cp system-top.dts ~/git.d/linux-xlnx/arch/arm64/boot/dts/xilinx/
其中system-top.dts设备树文件是我们开发板的默认设备树文件。
然后切换到project-spec/meta-user/recipes-bsp/device-tree/files/目录下,将设备树文件system-user.dtsi复制到linux内核源码相应目录:
cp system-user.dtsi ~/git.d/linux-xlnx/arch/arm64/boot/dts/xilinx/
system-user.dtsi是用户设备树文件。为了方便管理,我们一般配置这个设备树文件添加外设。
复制结果如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.6向内核源码中添加设备树
添加完开发板的设备树文件后,还需要进行相应的修改才可以使用。
进入到linux内核源码的arch/arm64/boot/dts/xilinx/目录下,编辑system-user.dtsi文件,修改前共有119行,内容如下:

1 /include/ "system-conf.dtsi"
  2 #include <dt-bindings/gpio/gpio.h>
  3 #include <dt-bindings/input/input.h>
  4 
  5 / {
  6     model = "Alientek Zynq MpSoc Development Board";
  7 
  8     leds {
  9         compatible = "gpio-leds";
 10 
 11         gpio-led0 {
 12             label = "ps_led1";
 13             gpios = <&gpio 38 GPIO_ACTIVE_HIGH>;
 14             linux,default-trigger = "timer";
 15         };
 16 
 17         gpio-led1 {
 18             label = "ps_led2";
 19             gpios = <&gpio 39 GPIO_ACTIVE_HIGH>;
 20             default-state = "on";
 21         };
 22 
 23         gpio-led2 {
 24             label = "pl_led1";
 25             gpios = <&axi_gpio_0 0 0 GPIO_ACTIVE_HIGH>;
 26             linux,default-trigger = "timer";
 27         };
 28 
 29         gpio-led3 {
 30             label = "pl_led2";
 31             gpios = <&axi_gpio_0 1 0 GPIO_ACTIVE_HIGH>;
 32             default-state = "on";
 33         };
 34     };
 35 
 36     keys {
 37         compatible = "gpio-keys";
   …
   …
   …
 97 &sdhci1 {
 98 disable-wp;
 99 no-1-8-v;
100 };
101 
102 &i2c1 {
103     clock-frequency = <400000>;
104 
105     eeprom@50 {
106         compatible = "24c64";
107         reg = <0x50>;
108         pagesize = <32>;
109     };
110 };
111 
112 &dwc3_0 {
113     dr_mode = "host";
114     maximum-speed = "super-speed";
115 };
116 
117 &usb0 {
118     dr_mode = "host";
119 };
修改后的内容如下:
1 #include <dt-bindings/gpio/gpio.h>
  2 #include <dt-bindings/input/input.h>
  3 
  4 / {
  5     model = "Alientek Zynq MpSoc Development Board";
  6     compatible = "xlnx,zynqmp-atk", "xlnx,zynqmp";
  7 };
  8 
  9 &gem3 {
 10     phy-handle = <&ethernet_phy>;
 11     local-mac-address = [00 0a 35 00 1e 53];
 12 
 13     ethernet_phy: ethernet-phy@7 {
 14         reg = <0x7>;
 15     };
 16 };
 17 
 18 &gem0 {
 19     psu_ethernet_0_mdio: mdio {
 20         #address-cells = <1>;
 21         #size-cells = <0>;
 22         phy1:phy@4 {
 23             reg = <0x4>;   /* YT8521 phy address */
 24         };
 25         gmii_to_rgmii_0: gmii_to_rgmii_0@0 {
 26                         compatible = "xlnx,gmii-to-rgmii-1.0";
 27                         phy-handle = <&phy1>;
 28                         reg = <0>;
 29         };
 30     };
 31 };
 32 
 33 &sdhci0 {
 34 mmc-hs200-1_8v;
 35 bus-width = <0x8>;
 36 non-removable;
 37 };
38 
 39 &sdhci1 {
 40 disable-wp;
 41 no-1-8-v;
 42 };
 43 
 44 &dwc3_0 {
 45     dr_mode = "host";
 46     maximum-speed = "super-speed";
 47 };
 48 
 49 &usb0 {
 50     dr_mode = "host";
 51 };

删除了原文件第一行的“/include/“system-conf.dtsi””,在第6行添加了“compatible = “xlnx,zynqmp-atk”, “xlnx,zynqmp”;”。
删除第8行至第64行根节点下leds和keys两个节点,这两个节点在后面驱动章节中用到的时候再添加。
删除第102行至第110行iic节点。
gem3是ps端网口,gem0是pl端网口,sdhci0和sdhci1分别是emmc和sd卡接口,dwc3_0和usb0分别是usb3.0接口和usb2.0接口。上面这6个节点我们保留。
修改完设备树后,还需要在arch/arm64/boot/dts/xilinx目录中的Makefile文件中添加开发板的设备树文件。添加到Makefile中的设备树文件在编译内核的时候会自动编译。
打开arch/arm64/boot/dts/xilinx/Makefile文件,添加行“dtb-$(CONFIG_ARCH_ZYNQMP) += system-top.dtb”,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.7添加设备树文件
可以看到像zc1232、zc1254、zc1751、zcu100、zcu102、zcu104、zcu106、zcu113、zcu1275、zcu1285这些设备树我们没有用到,可以直接删除,删除后的Makefile内容如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.8修改后的Makefile
这样编译linux内核的时候就可以从system-top.dts编译成system-top.dtb文件了。到此为止,MPSoC开发板就已经添加到linux内核源码中了。
在linux内核源码目录中输入“git status”命令,可以看到移植过程中,我们修改了哪些文件,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.9移植过程中修改的文件
如果后面测试的时候只修改设备树文件的话可只重新编译设备树,在linux内核源码根目录下输入如下命令编译设备树:
make dtbs
命令“make dtbs”只编译设备树文件,也就是将.dts编译为.dtb,编译完成以后就可以使用新的设备树文件。
13.6.3Linux内核编译与测试
经过前两个小节,我们已经在Linux内核里面添加了正点原子MPSoC开发板的配置,接下接进行编译测试。在终端中输入如下命令配置编译linux内核源码:
make distclean
make xilinx_zynqmp_defconfig
make -j8
第1行,清理工程。
第2行,使用默认配置文件xilinx_zynqmp_defconfig来配置Linux内核。
第3行,编译Linux。参数“-j8”表示处理器使用8核来运行编译,读者可根据自己电脑配置自行设置此参数。
编译完成以后就会在目录arch/arm64/boot下生成Image镜像文件(Image.gz是Image镜像文件的压缩文件),在arch/arm64/boot/dts/xilinx目录下生成system-top.dtb文件,如图 13.6.10和图 13.6.11所示。
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.10生成Image镜像文件
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.11生成system-top.dtb文件
将/tftpboot目录下原有的Image镜像文件删除,重新复制编译生成的Image文件和system-top.dtb文件到/tftpboot目录下,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.12复制镜像和设备树文件
拷贝完成以后就可以测试了。将开发板启动模式调为JTAG模式,开发板连接下载器,电脑连接开发板的usb_uart接口,用网线连接PS端网口和电脑,最后连接开发板电源。
开发板硬件连接好后,打开虚拟机,按照图 12.3.4所示将jtag下载器连接到虚拟机内,进入到工程ALIENTEK-ZYNQ路径下,输入“sptl”命令设置环境变量,然后使用“petalinux-boot --jtag --fpga --u-boot”命令下载并启动uboot。同时观察串口终端软件上的打印信息,注意在倒计时结束前按回车键进入uboot模式,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.13进入uboot模式
进入uboot模式后输入如下命令设置网络环境变量:
setenv ipaddr 192.168.2.22
setenv ethaddr 00:0a:35:00:1e:53
setenv gatewayip 192.168.2.1
setenv netmask 255.255.255.0
setenv serverip 192.168.2.21
然后输入如下命令将Image和system-top.dtb下载到开发板并启动:
tftpboot 0x200000 Image
tftpboot 0x100000 system-top.dtb
booti 0x200000 - 0x100000
结果如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.6.14 uboot模式下启动linux内核
出现上图所示内容就表示Linux内核启动成功,说明我们已经在Xilinx提供的Linux内核源码中成功添加了正点原子MPSoC开发板。
13.7根文件系统缺失错误
在上一小节打印信息的最后,出现如下图所示的信息:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.7.1根文件系统缺失错误
在上图中最后会有下面这一行:
end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
也就是提示内核崩溃,因为根文件系统目录不存在,VFS(虚拟文件系统)不能挂载根文件系统。即使根文件系统目录存在,如果根文件系统目录里面是空的依旧会提示内核崩溃。这个就是根文件系统缺失导致的内核崩溃。但是内核是启动了的,只是根文件系统不存在而已。
13.8image.ub的来源
从前面章节中我们知道,编译linux内核后得到的是Image镜像文件和dtb设备树文件,而我们在前面uboot移植章节使用uboot启动linux的时候使用的是image.ub镜像文件,那么image.ub文件是怎么产生的呢,它和Image文件、设备树文件有什么关系?是否一定需要image.ub文件才能启动内核呢?
在12.6节uboot启动Linux测试中我们使用了image.ub文件,在13.6.3节Linux内核编译与测试中,我们使用Image和设备树文件启动linux,结果是都可以正常启动linux,说明启动linux内核并不一定需要image.ub文件,而且从中我们也可以得出一个信息,image.ub文件一定是包含Image文件和设备树文件信息的。接下来,我们来探索下image.ub的来源。
既然image.ub文件包含Image文件和设备树文件信息,那么image.ub文件一定是由某个工具打包制作而得到的,常用的镜像制作工具是mkimage。mkimage工具位于u-boot-xlnx/tools目录下,初次使用前,要把mkimage文件复制到系统可执行命令文件夹内(也就是/usr/bin/),如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.8.1复制mkimage文件
我们先用mkimage来分析image.ub文件(命令mkimage -l images/linux/image.ub),结果如图 13.8.2所示。从显示的内容来看,image.ub确实是包括linux内核镜像和设备树的,另外从“FIT description”的信息来看,image.ub文件是U-Boot fitImage。现在我们根据“FIT description”的信息来搜索哪个文件包含该内容,搜索结果如图 13.8.3所示。
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.8.2 分析image.ub文件
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.8.3 搜索结果
可见包含该内容的文件不少。大致的看了一下以上文件,以“.its”结尾的文件是由run.do_assemble_fitimage_initramfs*文件生成的。我们打开build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/linux-xlnx-5.4+git999/fit-image.its文件,内容如下:

/dts-v1/;

/ {
        description = "U-Boot fitImage for PetaLinux/5.4+git999/zynqmp-generic";
        #address-cells = <1>;

        images {
                kernel@1 {
                        description = "Linux kernel";
                        data = /incbin/("linux.bin");
                        type = "kernel";
                        arch = "arm64";
                        os = "linux";
                        compression = "gzip";
                        load = <0x80000>;
                        entry = <0x80000>;
                        hash@1 {
                                algo = "sha256";
                        };
                };
                fdt@system-top.dtb {
                        description = "Flattened Device Tree blob";
                        data = /incbin/("/home/cx/workspace/petalinux/ALIENTEK-ZYNQ/build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/recipe-sysroot/boot/devicetree/system-top.dtb");
                        type = "flat_dt";
                        arch = "arm64";
                        compression = "none";
                        
                        hash@1 {
                                algo = "sha256";
                        };
                };
    };

        configurations {
                default = "conf@system-top.dtb";
                conf@system-top.dtb {
            description = "1 Linux kernel, FDT blob";
            kernel = "kernel@1";
            fdt = "fdt@system-top.dtb";
            
            
                        hash@1 {
                                algo = "sha256";
                        };
                };
    };
};

可以看出该文件的内容与我们使用“mkimage -l images/linux/image.ub”命令得到的信息基本一致。另外,从该文件内容可以看到镜像的kernel来源于linux.bin,而设备树来源于工程目录下的build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/recipe-sysroot/boot/devicetree/system-top.dtb。从build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/temp/run.do_assemble_fitimage.22866是由vmlinux生成的。其实我们也可以用Image来代替linux.bin,下面我们使用Image和zynqmp-atk.dtb生成image.ub。
将build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/linux-xlnx-5.4+git999/fit-image.its文件复制到linux内核源码根目录下,也就是“~/git.d/linux-xlnx/”目录下,然后修改相应的内容,修改后的fit-image.its文件内容如下:

/dts-v1/;

/ {
        description = "U-Boot fitImage for Alientek ZYNQ MPSoc";
        #address-cells = <1>;

        images {
                kernel-1 {
                        description = "Linux kernel";
                        data = /incbin/("arch/arm64/boot/Image");
                        type = "kernel";
                        arch = "arm64";
                        os = "linux";
                        compression = "none";
                        load = <0x80000>;
                        entry = <0x80000>;
                        hash-1 {
                                algo = "sha256";
                        };
                };
                fdt-1 {
                        description = "Flattened Device Tree blob";
                        data = /incbin/("arch/arm64/boot/dts/xilinx/system-top.dtb");
                        type = "flat_dt";
                        arch = "arm64";
                        compression = "none";
                        
                        hash-1 {
                                algo = "sha256";
                        };
                };
        };

        configurations {
                default = "config-1";
                
                config-1 {
                    description = "1 Linux kernel, FDT blob";
                    kernel = "kernel-1";
                    fdt = "fdt-1";
                };
        };
};

保存文件内容后,在终端中输入命令“mkimage -f fit-image.its image.ub”,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.8.4 生成image.ub文件
在内核源码根目录下可以找到生成的image.ub文件,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.8.5 生成的image.ub文件
如何验证该文件确实可行呢。如果是通过SD卡启动开发板可以将生成的image.ub文件复制到SD卡中,如果是通过网络启动开发板,可以将其复制到/tftboot目录下,启动开发板测试。经测试,是可以启动内核的,如何启动可以参考错误!未找到引用源。节,启动结果如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.8.6 验证结果
至此,我们终于知道了image.ub是怎么来的,怎么生成的了。另外image.ub既然是U-Boot fitImage,那U-Boot fitImage又是什么呢?限于篇幅就不再介绍了,可自行上网搜索,笔者找到一篇不错的介绍,推荐下,链接如下:
http://www.wowotech.net/u-boot/fit_image_overview.html
从该链接可知U-Boot fitImage主要来源于Unify Kernel的思想,其思想如下:
“在编译linux kernel的时候,不必特意的指定具体的架构和SOC,只需要告诉kernel本次编译需要支持哪些板级的platform即可,最终将会生成一个Kernel image,以及多个和具体的板子(哪个架构、哪个SOC、哪个版型)有关的FDT image(dtb文件)。
bootloader在启动的时候,根据硬件环境,加载不同的dtb文件,即可使linux kernel运行在不同的硬件平台上,从而达到unify kernel的目标。”
关于fit更多的介绍和使用方法请参考本章的扩展阅读部分。
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

13.9CPU调频策略
1、设置MPSoC开发板的CPU调频策略
我们知道:主频越高,功耗也越高。为了节省CPU的功耗和减少发热,我们有必要根据当前CPU的负载状态,动态地提供刚好足够的主频给CPU。调频或称变频技术应运而生。变频技术作为电源管理技术以节能为目的加入linux内核。我们可以通过配置内核来选择不同的调频策略。
我们来看一下如何通过图形化界面配置Linux内核的CPU调频策略,输入“make menuconfig”打开Linux内核的图形化配置界面,如下图所示:
【正点原子FPGA连载】第十三章Linux内核移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

图 13.9.1 Linux内核图形化配置界面
进入如下路径:
CPU Power Management
-> CPU Frequency scaling
-> Default CPUFreq governor
打开默认调频策略选择界面,如下图所示:

图 13.9.2默认调频策略选择
可以看到Linux内核一共有6种调频策略,
①Performance,最高性能,直接用最高频率,不考虑耗电。
②Powersave,省电模式,通常以最低频率运行,系统性能会受影响,一般不会用这个。
③Userspace,可以在用户空间手动调节频率,可以看到这是默认的配置。
④Ondemand,定时检查负载,然后根据负载来调节频率。负载低的时候降低CPU频率以省电,负载高的时候提高CPU频率,增加性能。
⑤conservative:保守模式,类似于ondemand,但调整相对较缓。
⑥schedutil:4.7版本内核新增加的一种调度策略,可以直接使用调度程序提供的信息做出调整cpu频率的决策;也可以调用cpufreq驱动程序更改频率以立即调整CPU的性能,无需生成进程上下文或其他工作项。
我们可以根据实际需求选择合适的调频策略。
关于Linux内核的移植就讲解到这里,简单总结一下移植步骤:
①在Linux内核中查找可以参考的板子,一般都是半导体厂商自己做的开发板。
②编译出参考板子对应的Image和.dtb文件。
③使用参考板子的Image文件和.dtb文件在我们所使用的板子上启动Linux内核,看能否启动。
④如果能启动的话就万事大吉,如果不能启动就需要调试Linux内核和修改设置树。不过一般都会参考半导体官方的开发板设计自己的硬件,所以大部分情况下都会启动起来。启动Linux内核用到的外设不多,一般就DRAM(Uboot都初始化好的)和串口。
⑤修改相应的驱动,像USB、eMMC、SD卡等驱动官方的Linux内核都是已经提供好了,基本不会出问题。重点是网络驱动,因为Linux驱动开发一般都要通过网络调试代码,所以一定要确保网络驱动工作正常。如果是处理器内部MAC+外部PHY这种网络方案的话,一般网络驱动都很好处理,因为在Linux内核中是有外部PHY通用驱动的。只要设置好复位引脚、PHY地址信息基本上都可以驱动起来。
⑥Linux内核启动以后需要根文件系统,如果没有根文件系统的话肯定会崩溃,所以确定Linux内核移植成功以后就要开始根文件系统的构建。