Linux Kernel and devicetrees

This section provides a concise guide on building the Linux kernel and devicetrees for different platforms on different hosts.

Jump to your platform and preferred method:

Building the Zynq Linux kernel and devicetrees from source

Using a script

We provide a script that does automates the build for Zynq using the Linaro toolchain.

The script takes up to 3 parameters, but if left blank, it uses defaults:

  1. <local_kernel_dir> - default is linux-adi if left blank ; use this, if you want to use an already cloned kernel repo

  2. <devicetree_file> - which device tree should be exported/copied from the build. Default is zynq-zc702-adv7511-ad9361-fmcomms2-3.dtb for Zynq

  3. <path_to_other_toolchain> - in case you have your own preferred toolchain (other than Linaro’s or Xilinx’s) you can use override it with this 3rd param

The script will:

  • Clone the ADI kernel tree

  • Download the Linaro GCC toolchain (if no other is specified)

  • Build the ADI kernel tree

  • Export/copy the Image file and device tree file out of the kernel build folder

Running the script in one line, with defaults:

wget https://raw.githubusercontent.com/analogdevicesinc/wiki-scripts/main/linux/build_zynq_kernel_image.sh && \
chmod +x build_zynq_kernel_image.sh && \
./build_zynq_kernel_image.sh

Building with Petalinux

Please see here: Building with Petalinux.

On the development host

Make sure you have u-boot-tools installed, to have the mkimage utility available. You can install it via your distro’s package manager.

Then

git clone https://github.com/analogdevicesinc/linux.git \
          --no-single-branch --depth=10 \
          -- linux

or do a git pull in a existing cloned repository.

The depth and no-single-branch options are included to speed up the cloning by fetching only near the head of each branch/release, you may remove them to fetch all history, but bear in mind it will go from around 800MB to around 3.4GB and growing.

Checkout the Release branch

Tip

Use the latest release, if not required otherwise!

Release names and Branches

2014_R2

2015_R2

2016_R1

2016_R2

2017_R1

2018_R1

2018_R2

2019_R1

2019_R2

2021_R1

git checkout origin/2021_R1 -b 2021_R1
# Branch 2021_R1 set up to track remote branch 2021_R1 from origin.
# Switched to a new branch '2021_R1'

Setup cross compile environment variables

There are a few toolchains that can be used. The Xilinx toolchain is recommended, but the Linaro toolchain can also be used.

Other toolchains/compilers for ARM may work as well, but the ones described here have been tested and found to work.

Using the Xilinx toolchain

Release names and Branches

Required Vivado/Vitis versions

2014_R2

Vivado 2014.2

2015_R2

Vivado 2015.2

2016_R1

Vivado 2015.4.2

2016_R2

Vivado 2016.2

2017_R1

Vivado 2016.4

2018_R1

Vivado 2017.4

2018_R2

Vivado 2018.2

2019_R1

Vivado 2018.3

2019_R2

Vivado 2019.1

2021_R1

Vivado 2021.1

source $PATH_TO_XILINX/Vitis/$VITIS_VERSION/settings64.sh
which which arm-linux-gnueabihf-gcc
# $PATH_TO_XILINX/Vitis/$VITIS_VERSION/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/arm-linux-gnueabihf-gcc

Important

Find the path to the Xilinx installation folder, and then use it to replace this string: $PATH_TO_XILINX that is written above. Same goes for the $VITIS_VERSION, where you choose the Vitis version.

export ARCH=arm
export CROSS_COMPILE="arm-linux-gnueabihf-"
Using the Linaro toolchain

Alternatively, the Linaro toolchain/compiler can be used to compile to kernel. Linaro compilers (that work with Zynq) can be downloaded from here. Always use the latest release just in case.

wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabi/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabi.tar.xz
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabi.tar.xz
export ARCH=arm
export CROSS_COMPILE=$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-

Configure the kernel

Inside the repository, generate the configuration file before building the kernel tree. The command shown below is generic and is not project specific. As long as the board is a ZYNQ FPGA, use the configuration below.

make zynq_xcomm_adv7511_defconfig
#
# configuration written to .config
#

Build the kernel

Build the kernel via ‘make’. This is the same for all Xilinx ZYNQ FPGAs.

make -j5 UIMAGE_LOADADDR=0x8000 uImage
# scripts/kconfig/conf --silentoldconfig Kconfig
#   CHK     include/config/kernel.release
#   CHK     include/generated/uapi/linux/version.h
#   UPD     include/config/kernel.release
#   CHK     include/generated/utsrelease.h
#
# [ -- snip --]
#
#   AS      arch/arm/boot/compressed/bswapsdi2.o
#   AS      arch/arm/boot/compressed/piggy.gzip.o
#   LD      arch/arm/boot/compressed/vmlinux
#   OBJCOPY arch/arm/boot/zImage
#   Kernel: arch/arm/boot/zImage is ready
#   UIMAGE  arch/arm/boot/uImage
# Image Name:   Linux-3.17.0-126697-g611e217-dir
# Created:      Fri Nov 28 10:20:40 2014
# Image Type:   ARM Linux Kernel Image (uncompressed)
# Data Size:    3195872 Bytes = 3120.97 kB = 3.05 MB
# Load Address: 00008000
# Entry Point:  00008000

Build the devicetree FCMOMMS2/3/4/5

Build the one that fits your FPGA carrier and FMC card

device tree

board

chip

zynq-adrv9361-z7035-bob

ADRV1CRR-BOB

zynq-adrv9361-z7035-bob-cmos

ADRV1CRR-BOB

zynq-adrv9361-z7035-packrf

ADRV-PACKRF

zynq-adrv9361-z7035-fmc

ADRV1CRR-FMC

ADV7511 (on-board) and the

zynq-adrv9361-z7035-fmc-rfcard-tdd

ADRV1CRR-FMC

ADV7511 (on-board), the
ADRV9361 and the

zynq-adrv9364-z7020-bob

ADRV1CRR-BOB

zynq-adrv9364-z7020-bob-cmos

ADRV1CRR-BOB

zynq-adrv9364-z7020-packrf

ADRV-PACKRF

zynq-coraz7s

Cora Z7


zynq-mini-itx-adv7511

Mini-ITX

ADV7511 (on-board)

zynq-mini-itx-adv7511-ad9361-fmcomms2-3

Mini-ITX

zynq-mini-itx-adv7511-ad9364-fmcomms4

Mini-ITX

ADV7511 (on-board) and the

zynq-zc702-adv7511

ZC702

ADV7511 (on-board)

zynq-zc702-adv7511-ad9361-fmcomms2-3

ZC702

ADV7511 (on-board) and the

zynq-zc702-adv7511-ad9361-fmcomms5

ZC702

ADV7511 (on-board) and the

zynq-zc702-adv7511-ad9364-fmcomms4

ZC702

ADV7511 (on-board) and the

zynq-zc706-adv7511

ZC706

ADV7511 (on-board)

zynq-zc706-adv7511-ad6676-fmc

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9265-fmc-125ebz

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9361-fmcomms2-3

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9361-fmcomms5

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9361-fmcomms5-ext-lo-adf5355

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9364-fmcomms4

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9434-fmc-500ebz

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9625-fmcadc2

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-ad9739a-fmc

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-adrv9371

ZC706

ADV7511 (on-board) and the
ADRV9371 board

zynq-zc706-adv7511-adrv9375

ZC706

ADV7511 (on-board) and the
ADRV9375 board

zynq-zc706-adv7511-fmcadc4

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-fmcdaq2

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-fmcdaq3

ZC706

ADV7511 (on-board) and the

zynq-zc706-adv7511-fmcjesdadc1

ZC706

ADV7511 (on-board) and the

zynq-zc706-imageon

ZC706

FMC-IMAGEON

zynq-zed-adv7511

Zed Board

ADV7511 (on-board)

zynq-zed-adv7511-ad9361-fmcomms2-3

Zed Board

ADV7511 (on-board) and the

zynq-zed-adv7511-ad9364-fmcomms4

ZedBoard

ADV7511 (on-board) and the

zynq-zed-adv7511-ad9467-fmc-250ebz

ZedBoard

ADV7511 (on-board) and the

zynq-zed-adv7511-cn0363

ZedBoard

ADV7511 (on-board) and the

zynq-zed-imageon

ZedBoard

FMC-IMAGEON

Building the device tree uses ‘make’ by turning the .dts file to a .dtb. The command is simply ‘make’ plus the device tree name with a .dtb file extension.

make zynq-zc702-adv7511-ad9361.dtb
#  DTC     arch/arm/boot/dts/zynq-zc702-adv7511-ad9361.dtb

Copy the generated files to your SD Card

The output files for building the kernel and device tree are uImage and <device_tree_name>.dtb. Refer to the code below to find their respective output directories. Take note that the device tree file needs to be renamed to devicetree.dtb. See SD Card flashing for more information in configuring the SD card.

cp arch/arm/boot/uImage /media/BOOT/uImage
cp arch/arm/boot/dts/zynq-zc702-adv7511-ad9361.dtb  /media/BOOT/devicetree.dtb

On the target platform (devicetrees)

To modify devicetrees on the target platform:

  1. Make sure the boot partition is mounted. On new images, this can be done by right-clicking the boot icon on the desktop and selecting the “Mount Volume” option. The partition will then be mounted at /media/analog/boot.

  2. Convert the compiled devicetree related to the target back into an editable format.

    cd /media/analog/boot/zynq-zc702-adv7511
    dtc -I dtb -O dts -o devicetree.dts devicetree.dtb
    
  3. Modify the devicetree.dts file as required.

  4. Recompile the devicetree file. Note that this will overwrite the original dtb file, copy or rename the original file if you want to keep it before running this step.

    cd /media/analog/boot/zynq-zc702-adv7511
    dtc -I dts -O dtb -o devicetree.dtb devicetree.dts
    

Building the ZynqMP / MPSoC Linux kernel and devicetrees from source

Using a script

We provide a script that does automates the build for Zynq using the Linaro toolchain.

Attention

This script differs from the one for Zynq.

The script takes up to 3 parameters, but if left blank, it uses defaults:

  1. <local_kernel_dir> - default is linux-adi if left blank ; use this, if you want to use an already cloned kernel repo

  2. <devicetree_file> - which device tree should be exported/copied from the build. Default is xilinx/zynqmp-zcu102-rev10-ad9361-fmcomms2-3.dtb for ZynqMP

  3. <path_to_other_toolchain> - in case you have your own preferred toolchain (other than Linaro’s or Xilinx’s) you can use override it with this 3rd param

The script will:

  • Clone the ADI kernel tree

  • Download the Linaro GCC toolchain (if no other is specified)

  • Build the ADI kernel tree

  • Export/copy the Image file and device tree file out of the kernel build folder

Running the script in one line, with defaults:

wget https://raw.githubusercontent.com/analogdevicesinc/wiki-scripts/main/linux/build_zynqmp_kernel_image.sh && \
chmod +x build_zynqmp_kernel_image.sh && \
./build_zynqmp_kernel_image.sh

Building with Petalinux

Please see here: Building with Petalinux.

On the development host

Make sure you have u-boot-tools installed, to have the mkimage utility available. You can install it via your distro’s package manager.

Then

git clone https://github.com/analogdevicesinc/linux.git \
          --no-single-branch --depth=10 \
          -- linux

or do a git pull in a existing cloned repository.

The depth and no-single-branch options are included to speed up the cloning by fetching only near the head of each branch/release, you may remove them to fetch all history, but bear in mind it will go from around 800MB to around 3.4GB and growing.

Checkout the main development

git checkout main
# Already on 'main'
# Your branch is up-to-date with 'origin/main'.

Add aarch64-linux-gnu-gcc to PATH

Using the Xilinx toolchain
source $PATH_TO_XILINX/Vitis/$VITIS_VERSION/settings64.sh
which aarch64-linux-gnu-gcc
# $PATH_TO_XILINX/Vitis/$VITIS_VERSION/gnu/aarch64/lin/aarch64-linux/bin/aarch64-linux-gnu-gcc

Important

Find the path to the Xilinx installation folder, and then use it to replace this string: $PATH_TO_XILINX that is written above. Same goes for the $VITIS_VERSION, where you choose the Vitis version.

export ARCH=arm64
export CROSS_COMPILE="aarch64-linux-gnu-"
Using the Linaro toolchain

Alternatively, the Linaro toolchain/compiler can be used to compile to kernel. Linaro compilers (that work with ZYNQMP) can be downloaded from here. Always use the latest release just in case.

wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
export ARCH=arm64
export CROSS_COMPILE=$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-

Configure the kernel

Inside the repository, generate the configuration file before building the kernel tree.

make adi_zynqmp_defconfig
#
# configuration written to .config
#

Build the kernel via ‘make’. This is the same for all Xlinx ZYNQMP MPSoC FPGAs.

make -j5 Image UIMAGE_LOADADDR=0x8000
#   CHK     include/config/kernel.release
#   CHK     include/generated/uapi/linux/version.h
#   HOSTCC  scripts/basic/fixdep
#   HOSTCC  scripts/basic/bin2c
#
# [ -- snip --]
#
#   CC      init/version.o
#   LD      init/built-in.o
#   KSYM    .tmp_kallsyms1.o
#   KSYM    .tmp_kallsyms2.o
#   LD      vmlinux
#   SORTEX  vmlinux
#   SYSMAP  System.map
#   OBJCOPY arch/arm64/boot/Image

Build the devicetree FCMOMMS2/3

Build the one that fits your FPGA carrier and FMC card

device tree

board

chip

zynqmp-zcu102-rev10-ad9361-fmcomms2-3.dts

ZCU102 Rev. 1.0

zynqmp-zcu102-rev10-ad9364-fmcomms4.dts

ZCU102 Rev. 1.0

zynqmp-zcu102-revB-ad9361-fmcomms2-3.dts

ZCU102 Rev.B

zynqmp-zcu102-revB-ad9364-fmcomms4.dts

ZCU102 Rev.B

The device tree zynqmp-zcu102-revA.dts can also be used for any ZCU102 FPGA that uses an SD card for boot up. Building the device tree uses ‘make’ by turning the .dts file to a .dtb. The command is simply ‘make’ plus the device tree name with a .dtb file extension.

make xilinx/zynqmp-zcu102-rev10-ad9361-fmcomms2-3.dtb
#  DTC     arch/arm64/boot/dts/xilinx/zynqmp-zcu102-rev10-ad9361-fmcomms2-3.dtb

Copy the generated files to your SD Card

The output files for building the kernel and device tree are uImage and <device_tree_name>.dtb. Refer to the code below to find their respective output directories. Take note that the device tree file needs to be renamed to devicetree.dtb. See SD Card flashing for more information in configuring the SD card.

cp arch/arm64/boot/Image /media/michael/BOOT/
cp arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revB-ad9361-fmcomms2-3.dtb /media/michael/BOOT/system.dtb

Common Issues

This sections goes through common issues related to the Linux Kernel on the ZynqMP.

DisplayPort - no picture?

The default configuration for most of the projects is to use the HDMI output, and that is what the configuration is set up for.

For DisplayPort projects, you may need to add a custom xorg.conf file.

printf 'Section "Device"
  Identifier "myfb"
  Driver "fbdev"
  Option "fbdev" "/dev/fb0"
EndSection' > /etc/X11/xorg.conf

After following that, the board should be rebooted.

You can find a list with tested monitors here. Resolution or image problems may appear if there is used a monitor that was not tested.