本次开发平台 :
开发平台:Ubuntu16.04
XSDK+Vivado(2018.3 Linux版本)
内核: linux-xlnx-xilinx-v2018.3
u-boot: u-boot-xlnx2018.3
devicetree: device-tree-xlnx
移植平台:ZYNQ z7035

OpenAMP

开放式非对称多处理( OpenAMP )是一个框架,它提供了为非对称多处理(AMP)系统开发软件应用所需的软件组件。该框架提供了以下主要功能。

  • 提供生命周期管理和处理器间通信功能,用于管理远程计算资源及其相关软件上下文。
  • 提供一个独立的库,可用于RTOS和裸机软件环境。
  • upstream 的Linux remoteprocrpmsgVirtIO 组件兼容。

开发换环境搭建

我们首先安装Vivado 与xSDK,安装在/tools文件夹中,安装完成后,在~.bashrc中添加:

source /tools/Xilinx/Vivado/2018.3/.settings64-Vivado.sh
source /tools/Xilinx/SDK/2018.3/.settings64-SDK_Core_Tools.sh
source /tools/Xilinx/DocNav/.settings64-DocNav.sh

这样,为我们提供编译u-boot与内核的编译环境。

编译U-boot

Xilinx提供了定制化的针对ZYNQ的通用linux内核,我们可以很方便的从Git上下载到。由于本次使用的开发平台Ubuntu16.04 与Vivado xSDK为2018.3 ,为了保持版本稳定性,我们的u-boot、内核、DeviceTree都使用2018.3的Release版本。

我们从u-boot-xlnx2018.3下载u-boot(注意版本),下载完成后解压。

我们先export编译环境:

export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm

然后进行一次distclean(第一次编译无需此步骤)

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean

随后,尽心编译:

make zynq_adrv9361_defconfig

export DEVICE_TREE="zynq-adrv9361"

make  -j8

随后编译完成。

因为编译内核时候会自动编译设备树,而在uboot tools目录中会有设备树的编译器,所以需要进行一次export

cd tools
export PATH=`pwd`:$PATH

然后拷贝u-boot文件为u-boot.elf,至此u-boot编译完成

编译Kernel

zynq linux 内核我们从linux-xlnx-xilinx-v2018.3下载(注意版本),下载完成后解压。

解压完成后进入内核目录:
如果切换过终端窗口,我们需要重新export一次arm linux交叉编译环境:

export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm

然后,配置Linux内核:

make ARCH=<architecture> <kernel config>

(可选)可以配置其他内核选项:

make ARCH=<architecture> (menu|x|n)config

构建Linux内核(需要为交叉编译设置环境):

make ARCH=<architecture> UIMAGE_LOADADDR=<kernel load address> <make targets>

这将在linux-xlnx / arch / / boot /以及linux-xlnx / vmlinux中创建用于引导的Linux映像。

在此我们构建适用于Zynq AP SoC的Linux:
内核是基于linux-xlnx / arch / arm / configs / xilinx_zynq_defconfig配置的。

make ARCH=arm xilinx_zynq_defconfig
make ARCH=arm menuconfig

因为我们要启用OpenAMP编译,我们参考ug1114的petalinu22018.3的Quick Try中对linux内核的配置来配置内核:
Enable loadable module support:
[*] Enable loadable module support —>

Enable loadable module support
Enable user space firmware loading support:
Device Drivers —>
Generic Driver Options —>
<*> Userspace firmware loading support
Enable user space firmware loading support
Enable the remoteproc driver support: Note that the commands differ, based on which Zynq device you are using:
Device Drivers —>
Remoteproc drivers —>
for R5:
ZynqMP_r5 remoteproc support
for Zynq A9
Support ZYNQ remoteproc
Enable the remoteproc driver support
make menuconfig 编译后,我们产生内核映像:

make ARCH=arm UIMAGE_LOADADDR=0x8000 uImage

在此过程中,将创建linux-xlnx / arch / arm / boot / Image和linux-xlnx / arch / arm / boot / zImage。该Image文件是未压缩的内核映像和的zImage文件是压缩的内核映像启动时,将解压缩本身。
如果在构建环境中可以使用mkimage实用程序,那么将通过使用U-Boot头包装zImage来创建linux-xlnx / arch / arm / boot / uImage。

编译设备树

此部分涵盖了使用Xilinx工具生成devicetree源(DTS)文件以及使用标准开源工具构建/编译这些源文件的过程。特别是,将涉及使用Xilinx设备树生成器(DTG)从Xilinx硬件项目生成DTS文件,而将涉及设备树编译器(DTC)将DTS文件编译为设备树二进制文件(DTB)。尽管DTB的主要用途是将其提供给Linux内核,以便可以将Linux正确初始化为特定的硬件,但是DTB也可以与QEMU一起使用,以仿真Linux和独立系统的硬件。

什么是devicetree?

设备树或简称为DT是描述硬件的数据结构。它描述了可由Linux等操作系统读取的硬件,因此不需要对计算机的详细信息进行硬编码。
Linux基本上将DT用于平台识别,运行时配置(如bootargs)和设备节点填充。

Devicetree基础

设备树中的每个驱动程序或模块均由该节点定义,并且其所有属性都在该节点下定义。基于驱动程序,它可以具有子节点或父节点。

例如,通过SPI总线连接的设备将以SPI总线控制器作为其父节点,而该设备将成为spi节点的子节点之一。根节点是所有节点的父节点。

在根节点下通常包括
1)CPU节点信息
2)内存信息
3)选择的配置数据可以包括内核参数字符串和initrd映像的位置
4)别名
5)定义总线信息的节点

设备树属性

兼容:顶级兼容属性通常为电路板然后为SoC定义一个兼容字符串。
值始终以最具体的优先为准,最后指定的最不具体为准。
#address-cells:该属性指示在reg属性中形成基地址部分需要多少个单元(即32位值)。
#size-cells:reg属性的大小部分。
interrupt-controller:是一个布尔型属性,指示当前节点是一个中断控制器。
#interrupt-cells:指示由所选中断控制器管理的中断的interrupts属性中的单元数。
interrupt-parent:是一个虚拟对象,它指向当前节点的中断控制器。通常,主中断控制器有一个顶级的中断父级定义。

设备树生成器(DTG)

DTG旨在帮助用户构建其特定于硬件的DTS文件。为自定义硬件构建DTS始终是一个手动过程,但是DTG可以帮助用户快速入门。这是因为可以从硬件交接文件(XSA)中的信息中提取DTS中捕获的许多信息。DTG会根据提供的XSA文件为各种DTS文件填充尽可能多的信息,然后要求用户填写空白或根据需要进行调整。

Task Output Products

DTG生成带有.dts和.dtsi文件扩展名的DTS文件。将有一个带有include语句的顶级 .dts文件,以引用单独的DTS包含(DTSI)文件。使用DTSI文件可以在不同文件之间组织信息。例如,如下文更详细描述的,一个DTSI可以用来描述固定硬件(ie fixed in silicon),而另一个DTSI可以用来描述动态硬件(即可编程逻辑中的IP)。

通常,对于SOC,会有一个静态的dts / dtsi文件,但是当涉及FPGA时,可能会有许多复杂的设计,而外围逻辑(PL)IP可能会有所不同,或者可能具有不同的配置。
对于这些复杂的FPGA设计,我们需要一个设备树生成器(DTG),在其中它可以为这些设计自动生成dts / dtsi。

生成后,输出目录中将提供不同的文件,例如pl.dtsi,pcw.dtsi,system-top.dts,zynqmp.dtsi,zynqmp-clk-ccf.dtsi。这些文件如下所述。

pl.dtsi:这是一个文件,所有存储器映射的外围逻辑(PL)IP节点都将可用。
pcw.dtsi:这是PS外设需要动态属性的文件。
system-top.dts:这是一个文件,其中包含内存信息,早期控制台和引导参数。
zynqmp.dtsi:此文件包含所有PS外围设备信息以及cpu信息。
zynqmp-clk-ccf.dtsi:此文件包含外围IP的所有时钟信息。

除了这些文件以外,它还将基于board在相同的输出目录dt /下生成一个board.dtsi文件。例如,如果板卡是zcu111-reva,则它将生成dt / zcu111-reva.dtsi。

zcu111-reva.dtsi:它包含所有板子特定的属性,例如i2c可能已连接到某个从站等。
实际文件输出将根据设备架构(例如ZynqUS +与Zynq-7000与MicroBlaze)而有所不同。

第1步:获取DTG源

DTG是一个开源实用程序,其源代码发布在Xilinx GitHub网站上。它使用解释语言(Tcl),因此无需编译源代码。


git clone https://github.com/Xilinx/device-tree-xlnx
cd device-tree-xln
git checkout -b xilinx-v2018.3
第2步:生成DTS文件(使用Xilinx SDK生成DTS文件(GUI流:工具版本2014.2-2019.1))

从硬件项目生成HDF文件(如果尚不可用)
1、在Vivado中打开硬件项目。
2、生成模块设计

IP Integrator: Generate Block Design
Vivado Menu: File > Export > Export Hardware

在<project_name> .sdk HDF文件中生成
从SDK生成设备树源(.dts / .dtsi)文件

1、从Vivado打开SDK或通过命令行打开SDK(xsdk -hwspec <文件名> .hdf -workspace

Vivado Menu: File > Launch SDK

2、在这里插入图片描述
3、在SDK中添加BSP存储库(对于SDK 2018.3,然后从检出的git区域中选择“ device-tree-xlnx”):

SDK Menu: Xilinx Tools > Repositories > New... (<bsp repo>) > OK

4、创建设备树板支持包(BSP):

SDK Menu: File > New > Board Support Package > Board Support Package OS: device-tree > Finish

5、将出现一个BSP设置窗口。也可以通过打开设备树BSP的system.mss文件并单击“修改此BSP的设置”来访问此窗口。填写适当的值:

  • 'bootargs’参数指定在引导时(内核命令行)传递给内核的参数。***
  • “控制台设备”参数指定将使用哪个串行输出设备。从下拉列表中选择一个值。

*.dts / .dtsi文件现在位于<SDK工作空间> / device_tree_bsp_0 /文件夹中。
**例如console = , root = / dev / ram rw ip = ::::: eth0:dhcp earlyprintk
*** 的一些示例值是使用Zynq时的ttyPS0,使用时是ttyUL0 UART Lite软ip或使用UART16550软ip时为ttyS0。

然后我们可以XSDK devicetreebsp source 文件夹中找到设备树文件。
我们为了获取remoteproc的支持,需要在source文件夹中添加openamp.dtsi文件,其中填写:

/ {
	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;
			rproc_0_reserved: rproc@3e000000 {
				no-map;
				reg = <0x3e000000 0x01000000>;
			};
	};
	amba {
		elf_ddr_0: ddr@0 {
			compatible = "mmio-sram";
			reg = <0x3e000000 0x400000>;
		};
	};
	remoteproc0: remoteproc@0 {
		compatible = "xlnx,zynq_remoteproc";
		firmware = "firmware";
		vring0 = <15>;
		vring1 = <14>;
		srams = <&elf_ddr_0>;
	};
};

我们需要注意其中第linux 保留内存的起始地址与大小,保持和cpu1的应用起始地址相同。

然后再system-top.dts文件夹底部包含该文件:
在这里插入图片描述

编译

编译设备树之前我们需要拥有设备树编译器,首先我们编译设备树编译器:

步骤1:获取Devicetree编译器源

获取源码:

https://git.kernel.org/pub/scm/utils/dtc/dtc.git
cd dtc

产生的输出文件

  • dtc(dtc二进制可执行文件)

建立DTC
所有命令都必须在DTC源目录中执行。有一个适用于所有体系结构的dtc二进制文件。无需构建单独的DTC二进制文件来支持MicroBlaze和ARM。

要构建dtc,请执行以下操作:

make

构建过程完成后,将在当前目录中创建dtc二进制文件。必须使工具可以访问dtc二进制文件的路径(例如,U-Boot构建过程)。要使dtc在其他步骤中可用,建议将tools目录添加到$ PATH变量中。

export PATH=$PATH:/<path-to-dtc>/dtc

exp:
export PATH=pwd:$PATH

之后我们就可以利用设备树编译器编译我们生成的设备树文件了。

步骤2:预处理Devicetree源

如上一节所述,DTG会生成多个devicetree文件,并使用“ #include”指令将它们链接在一起。在将该设备树源提供给编译器(DTC)之前,必须对顶级DTS进行预处理,以将所有源合并到一个DTS中。这可以使用标准的GNU C编译器来完成。例如:

gcc -I my_dts -E -nostdinc -undef -D__DTS__ -x assembler-with-cpp -o system.dts system-top.dts

步骤3:从DTS编译Devicetree Blob(.dtb)文件

称为设备树编译器(DTC)的实用程序用于将DTS文件编译为DTB文件。DTC是Linux源目录的一部分。linux-xlnx / scripts / dtc /包含DTC的源代码,需要进行编译才能使用。编译DTC的一种方法是构建Linux树。也可以通过操作系统的程序包管理器来获取DTC。

一旦DTC可用,就可以调用该工具以生成DTB,其中“ system.dts”是预处理产生的聚合设备树源。


cd /<path-to-dtc>
dtc -I dts -O dtb -o system.dtb system.dts

DTC也可以用于将DTB转换回DTS:


dtc -I dtb -O dts -o system.dts system.dtb

杂项
以下各节假定您具有可用的Linux源。

替代:仅适用于ARM
在Linux源目录中,使目标“ dtbs”将把linux-xlnx / arch / arm / boot / dts /中的所有DTS文件编译为DTB文件。

make ARCH=arm dtbs

Devicetree二进制比较
Linux源代码还包括用于DTB比较的脚本。我们可以使用dtx_diff二进制文件检查两个devicetree blob(DTB文件)之间的差异,如下所示。

cd linux-xlnx/scripts/dtc
make ARCH=arm <devicetree name>.dtb
dtx_diff system1.dtb system2.dtb

至此,除了文件系统我们已经把支持amp zynq的u-boot 、内核,设备树已经编译完成。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐