Unless otherwise stated, everything on this page is based on Vivado 2017.2 and a ZCU102 Revision 1.0 board with ES2 silicon (EK-U1-ZCU102-ES2-G).
The process for booting Linux on Zynq UltraScale+ has a few more steps than on Zynq-7000, some of which aren't (currently) documented well by Xilinx.
These instructions have been compiled from several different pages on the Xilinx Wiki, along with a bit of experimentation.
Before building anything, the Vivado tools need to be sourced, and the correct cross-compiler set:
Building the FSBL
The FSBL can be built in Xilinx SDK (by creating an Application Project targeting
psu_cortexa53_0 and selecting the 'Zynq MP FSBL' example project), or using HSI with the following TCL script.
I have experienced problems with the FSBL not updating correctly in SDK after changing Zynq parameters in Vivado then re-exporting the hardware design, leading to the board not booting. This could be fixed by deleting all SDK projects and starting from scratch (possibly caused by a bug in SDK).
Building the PMU firmware
PMU firmware can be built in Xilinx SDK (by creating an Application Project targeting
psu_pmu_0), or using HSI with the following TCL script.
Building ARM Trusted Firmware (ATF)
The Xilinx instructions for building ATF seem to work fine - clone the sources from https://github.com/xilinx/arm-trusted-firmware, checkout the appropriate tag (e.g.
xilinx-v2017.2), and build with the following to create
Building U-Boot is similar to the Zynq-7000, but the output no longer needs to be manually renamed to
Building the Linux Kernel
The Linux kernel build is fairly standard, with the only differences from the Zynq-7000 being the architecture (arm64 instead of arm) and not needing to build a uImage file for U-Boot as (Image will suffice).
Building the device tree
The device tree can be created from the Xilinx Linux kernel sources (either within or out of the main source tree), or using SDK/HSI.
As of the v2017.2 tag of the Xilinx Linux kernel, the latest ZCU102 device tree is "zynqmp-zcu102-revB". This can be built using the standard
make dtbs command within the kernel source folder, but its often easier to move the dts sources elsewhere if they need to be customised.
The following Makefile (run with just
make) can be used to build the device tree when files are not within the kernel source tree, but still use kernel headers and includes (replace
KDIR with the path to the Xilinx Linux repository).
Alternatively, device trees can be created using SDK or HSI from the Xilinx tools. The following HSI TCL script (or Xilinx SDK instructions) should theoretically create device tree sources based on the specified hardware design, however this has had problems for me (most obviously SATA did not work). Replace the
device-tree-xlnx repository path as appropriate.
Creating the boot image (BOOT.bin)
The SD card boot image should contain the FSBL, PMU firmware, ATF, and U-Boot.
This can be created using the 'Create Boot Image' option in Xilinx SDK, or by using the
bootgen tool. When using SDK, ensure the appropriate Exception Level and TrustZone options are used for ATF and U-Boot, and that bootloader and pmu partition types are used for the first two items.
To generate 'BOOT.bin' using
Loading the bitstream, device tree and kernel from U-Boot
The bitstream, device tree and kernel (and root filesystem) can be loaded from SD card, external storage (USB or SATA), flash, or a remote server via TFTP. This is similar to Zynq-7000, but with the addition of SATA support on Zynq UltraScale+ (accessed using U-Boot
The main difference between the Zynq UltraScale+ and Zynq-7000 is the ability to use the
booti command instead of
bootm. This allows the use of a standard kernel
Image file, instead of a packaged
uImage generated by
Also note that U-Boot by default seems to save its environment to a
uboot.env file on the SD card rather than to flash (which was the default on ZC706 boards).
Another thing to note is the
fpga info 0 command does not correctly display the size of the FPGA bitstream (instead showing '1 byte'). When using
fpga load, the size of the .bit file in bytes can be used instead.