How to build Arm Trusted Firmware (ATF) for ultra96 V2 Based on Avnet BSP 2018.3
Updated: May 5

Build Steps
PetaLinux Tools Build Guide for Ultra96-V2 Avnet out of box BSP 2018.3
Build Platform Management Unit firmware PMUFW) for Ultra96 V2
Arm-trusted-firmware source code location
"your project folder"/ultra96v2_oob_2018_3/build/tmp/work/aarch64-xilinx-linux/arm-trusted-firmware
Setup PetaLinux Environment
Set the Petalinux source path to the version of Petalinux you're using. In this case we are using 2018.3 and it is installed in the folder "/opt/pkg/petalinux/2018.3/" Yours may be different if you installed it in another folder. If you have not setup Petalinux 2018.3, you can follow the steps in the following blog post:
source /opt/pkg/petalinux/2018.3/settings.sh
Change folders to your project folder where you build the BSP source code.
Example:
cd /plxprjs/Ultra96_V2
Change "/plxprjs/Ultra96_V2" to the folder you build the BSP.
Clean up build temp files by running following command:
petalinux-build -c arm-trusted-firmware -x distclean
When the cleaning process finishes, you should see following debug messages:
[INFO] building arm-trusted-firmware [INFO] sourcing bitbake INFO: bitbake virtual/arm-trusted-firmware -c cleansstate Loading cache: 100% |##################################################################################################################################################| Time: 0:00:00 Loaded 3468 entries from dependency cache. Parsing recipes: 100% |################################################################################################################################################| Time: 0:00:05 Parsing of 2577 .bb files complete (2542 cached, 35 parsed). 3469 targets, 133 skipped, 0 masked, 0 errors. NOTE: Resolving any missing task queue dependencies Initialising tasks: 100% |#############################################################################################################################################| Time: 0:00:00 NOTE: Executing RunQueue Tasks NOTE: Tasks Summary: Attempted 2 tasks of which 0 didn't need to be rerun and all succeeded. [INFO] successfully built arm-trusted-firmware |
# In order to fetch source ode, please run following command:
petalinux-build -c arm-trusted-firmware -x fetch
This command downloads the bare git repository file into the build folder and extracts the bare repository into the build folder as well:
You should see following debug messages:
petalinux-build -c arm-trusted-firmware -x fetch [INFO] building arm-trusted-firmware [INFO] sourcing bitbake INFO: bitbake virtual/arm-trusted-firmware -c fetch Loading cache: 100% |##################################################################################################################################################| Time: 0:00:03 Loaded 3468 entries from dependency cache. Parsing recipes: 100% |################################################################################################################################################| Time: 0:00:11 Parsing of 2577 .bb files complete (2542 cached, 35 parsed). 3469 targets, 133 skipped, 0 masked, 0 errors. NOTE: Resolving any missing task queue dependencies Initialising tasks: 100% |#############################################################################################################################################| Time: 0:00:00 NOTE: Executing RunQueue Tasks NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded. INFO: Copying Images from deploy to images [INFO] successfully built arm-trusted-firmware |
In order to unpack source ode, please run following command:
petalinux-build -c arm-trusted-firmware -x unpack
This command extracts the bare git repo into the build work directory:
You will see following debug messages:
[INFO] building arm-trusted-firmware [INFO] sourcing bitbake INFO: bitbake virtual/arm-trusted-firmware -c unpack Loading cache: 100% |##################################################################################################################################################| Time: 0:00:02 Loaded 3468 entries from dependency cache. Parsing recipes: 100% |################################################################################################################################################| Time: 0:00:11 Parsing of 2577 .bb files complete (2542 cached, 35 parsed). 3469 targets, 133 skipped, 0 masked, 0 errors. NOTE: Resolving any missing task queue dependencies Initialising tasks: 100% |#############################################################################################################################################| Time: 0:00:00 NOTE: Executing RunQueue Tasks NOTE: Tasks Summary: Attempted 2 tasks of which 1 didn't need to be rerun and all succeeded. INFO: Copying Images from deploy to images [INFO] successfully built arm-trusted-firmware |
Change the ATF
Now that the arm trusted firmware has been unpacked we can make changes to the files. The file we need to find is find is called bl31.c
As an example mine is located:
plxprjs/Ultra96/build/tmp/work/aarch64-xilinx-linux/arm-trusted-firmware/1.5-xilinx-v2018.3+gitAUTOINC+08560c36ea-r0/git/bl31/
To find the correct path for your ATF, issue this command in your project folder
find -name bl31_main.c
Once located, you can open it in your favorite compiler or text editor to add come text or functionality depending on your requirements.
Edit the bl31_main(void) by adding the two bold faced lines and save the file.
void bl31_main(void)
{
NOTICE("BL31: %s\n", version_string);
NOTICE("BL31: %s\n", build_message);
ERROR("This is Your Name modified ATF. Exiting.\r\n");
while (1) ; // infinite loop
In order to rebuild source code, please run following command:
petalinux-build -c arm-trusted-firmware -x build
You will see following debug messages:
petalinux-build -c arm-trusted-firmware -x build [INFO] building arm-trusted-firmware [INFO] sourcing bitbake INFO: bitbake virtual/arm-trusted-firmware -c build Loading cache: 100% |##################################################################################################################################################| Time: 0:00:00 Loaded 3468 entries from dependency cache. Parsing recipes: 100% |################################################################################################################################################| Time: 0:00:02 Parsing of 2577 .bb files complete (2542 cached, 35 parsed). 3469 targets, 133 skipped, 0 masked, 0 errors. NOTE: Resolving any missing task queue dependencies Initialising tasks: 100% |#############################################################################################################################################| Time: 0:00:00 Checking sstate mirror object availability: 100% |#####################################################################################################################| Time: 0:00:00 NOTE: Executing SetScene Tasks NOTE: Executing RunQueue Tasks NOTE: Tasks Summary: Attempted 575 tasks of which 560 didn't need to be rerun and all succeeded. INFO: Copying Images from deploy to images [INFO] successfully built arm-trusted-firmware |
This process will generate new files bl31.bin and bl31.elf in folder /images/linux which we will utilize later in this experiment when we boot off JTAG.
You can verify that the files were updated by viewing the time date stamp. If you're using a git repository to manage your project files you can issue a git status and see that they were updated as well.
How to load and debug over JTAG
To load over JTAG we need set the Ultra96 V2 SW3 switches to 00, which tells the board to boot from JTAG.
#1 Connect the USB cable to the Ultra96
#2 Connect the USB cable to your host machine and make sure that it is connected (If you're using a VMware session this is under VMware removable devices and must be connected using USB 3.0


#3 Change the switches on SW3 for jtag as shown below

#4 Open up a terminal and set the file path to Petalinux 2018.3
source /opt/pkg/petalinux/2018.3/settings.sh
Where /opt/pkg/petalinux/2018.3 is the correct path to your install of petalinux. This could be different depending on what folder you installed it in your host system.
#5 Start the XSCT server
/opt/pkg/petalinux/2018.3/tools/xsct/SDK/2018.3/bin/xsct
If the source path is set correctly and the folder is pointing to the correct build of petalinux you will see following debug message
****** Xilinx Software Commandline Tool (XSCT) v2018.3 **** SW Build 2390844 on Thu Nov 15 19:17:20 MST 2018 ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. xsct% |
#6 Run connect command to start hardware server connection
connect
xsct% connect attempting to launch hw_server
****** Xilinx hw_server v2018.3 **** Build date : Nov 15 2018-19:35:59 ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. INFO: hw_server application started INFO: Use Ctrl-C to exit hw_server application INFO: To connect to this hw_server instance use url: TCP:127.0.0.1:3121 tcfchan#0 xsct% |
#7 Power on the Ultra96 V2

#8 Open another terminal for your Minicom, set the petalinux source path using the path from step #4, and start minicom on that terminal window by typing in the command:
minicom
#9 Open another separate terminal window, set the petalinux source path using the same path you used in step #4. We will use this terminal to issue the JTAG boot command and watch for the results in the other two terminal windows.
At this point you should have three terminal windows opened. XSCT, Minicom, and a normal terminal that has the project folder open waiting for the next command.
NOTE: You must have an SD card in the card reader that has a current valid build on it before the next step or you will get an error "no mmc device at slot 0" and the kernal will fail to load properly.
#10 Start the JTAG boot with this command
petalinux-boot --jtag --u-boot --hw_server-url TCP:127.0.0.1:3121 -v
You will see following debug message from host in your terminal window
petalinux-boot --jtag --u-boot --hw_server-url TCP:127.0.0.1:3121 -v XSDB Script: INFO: Launching XSDB for file download and boot. INFO: This may take a few minutes, depending on the size of your image. connect -url TCP:127.0.0.1:3121 targets -set -nocase -filter {name =~ "*PSU*"} mask_write 0xFFCA0038 0x1C0 0x1C0 targets -set -nocase -filter {name =~ "*MicroBlaze PMU*"} puts stderr "INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/pmufw.elf to the target." dow "/home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/pmufw.elf" after 2000 con targets -set -nocase -filter {name =~ "*APU*"} mwr 0xffff0000 0x14000000 mask_write 0xFD1A0104 0x501 0x0 targets -set -nocase -filter {name =~ "*A53*#0"} source /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/project-spec/hw-description/psu_init.tcl puts stderr "INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/zynqmp_fsbl.elf to the target." dow "/home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/zynqmp_fsbl.elf" after 2000 con after 4000; stop; catch {stop}; psu_ps_pl_isolation_removal; psu_ps_pl_reset_config targets -set -nocase -filter {name =~ "*A53*#0"} puts stderr "INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/u-boot.elf to the target." dow "/home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/u-boot.elf" after 2000 targets -set -nocase -filter {name =~ "*A53*#0"} puts stderr "INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/bl31.elf to the target." dow "/home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/bl31.elf" after 2000 con exit rlwrap: warning: your $TERM is 'xterm-256color' but rlwrap couldn't find it in the terminfo database. Expect some problems.: Inappropriate ioctl for device INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/pmufw.elf to the target. Downloading Program -- /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/pmufw.elf section, .vectors.reset: 0xffdc0000 - 0xffdc0007 section, .vectors.sw_exception: 0xffdc0008 - 0xffdc000f section, .vectors.interrupt: 0xffdc0010 - 0xffdc0017 section, .vectors.hw_exception: 0xffdc0020 - 0xffdc0027 section, .text: 0xffdc0050 - 0xffdd0527 section, .rodata: 0xffdd0528 - 0xffdd266f section, .data: 0xffdd2670 - 0xffdd66e7 section, .sdata2: 0xffdd66e8 - 0xffdd66e7 section, .sdata: 0xffdd66e8 - 0xffdd66e7 section, .sbss: 0xffdd66e8 - 0xffdd66e7 section, .bss: 0xffdd6700 - 0xffdda78f section, .srdata: 0xffdda790 - 0xffddb09f section, .stack: 0xffddb0a0 - 0xffddc09f section, .xpbr_serv_ext_tbl: 0xffddf6e0 - 0xffddfadf 100% 0MB 0.2MB/s 00:00 Setting PC to Program Start Address 0xffdcfa7c Successfully downloaded /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/pmufw.elf INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/zynqmp_fsbl.elf to the target. Downloading Program -- /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/zynqmp_fsbl.elf section, .text: 0xfffc0000 - 0xfffce13b section, .init: 0xfffce140 - 0xfffce173 section, .fini: 0xfffce180 - 0xfffce1b3 section, .note.gnu.build-id: 0xfffce1b4 - 0xfffce1d7 section, .rodata: 0xfffce200 - 0xfffce63f section, .sys_cfg_data: 0xfffce640 - 0xfffcee07 section, .mmu_tbl0: 0xfffcf000 - 0xfffcf00f section, .mmu_tbl1: 0xfffd0000 - 0xfffd1fff section, .mmu_tbl2: 0xfffd2000 - 0xfffd5fff section, .data: 0xfffd6000 - 0xfffd71a7 section, .sbss: 0xfffd71a8 - 0xfffd71bf section, .bss: 0xfffd71c0 - 0xfffd91bf section, .heap: 0xfffd91c0 - 0xfffd95bf section, .stack: 0xfffd95c0 - 0xfffdb5bf section, .dup_data: 0xfffdb5c0 - 0xfffdc767 section, .handoff_params: 0xfffe9e00 - 0xfffe9e87 section, .bitstream_buffer: 0xffff0040 - 0xfffffc3f 100% 0MB 0.1MB/s 00:00 Setting PC to Program Start Address 0xfffc0000 Successfully downloaded /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/zynqmp_fsbl.elf INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/u-boot.elf to the target. Downloading Program -- /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/u-boot.elf section, .data: 0x08000000 - 0x0808a567 100% 0MB 0.2MB/s 00:03 Setting PC to Program Start Address 0x08000000 Successfully downloaded /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/u-boot.elf INFO: Downloading ELF file: /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/bl31.elf to the target. Downloading Program -- /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/bl31.elf section, .text: 0xfffea000 - 0xffff1fff section, .rodata: 0xffff2000 - 0xffff2fff section, .data: 0xffff3000 - 0xffff6a1f section, stacks: 0xffff6a40 - 0xffff7b3f section, .bss: 0xffff7b40 - 0xffff88d3 section, xlat_table: 0xffff9000 - 0xffffdfff section, coherent_ram: 0xffffe000 - 0xffffefff 100% 0MB 0.2MB/s 00:00 Setting PC to Program Start Address 0xfffea000 Successfully downloaded /home/jimmy/petalinux/2018.3/ultra96v2_oob_2018_3/images/linux/bl31.elf |
You will see following debug message from the XSCT hyperterminal
Xilinx Zynq MP First Stage Boot Loader changed by Jimmy Release 2018.3 Apr 11 2022 - 23:12:08 PMUFW: v1.1
U-Boot 2018.01 (Apr 12 2022 - 01:35:13 +0000)
Model: Avnet Ultra96 Rev1 Board: Xilinx ZynqMP I2C: ready DRAM: 2 GiB EL Level: EL2 Chip ID: zu3eg Watchdog: Started By Jimmy MMC: mmc@ff160000: 0 (SD), mmc@ff170000: 1 *** Warning - bad CRC, using default environment In: serial@ff010000 Out: serial@ff010000 Err: serial@ff010000 Model: Avnet Ultra96 Rev1 Board: Xilinx ZynqMP Bootmode: JTAG_MODE Net: Net Initialization Skipped No ethernet found. U-BOOT for ultra96v2-oob-2018-3 Hit any key to stop autoboot: 0 Device: mmc@ff160000 Manufacturer ID: 95 OEM: 5355 Name: Tran Speed: 50000000 Rd Block Len: 512 SD version 3.0 High Capacity: Yes Capacity: 29.8 GiB Bus Width: 4-bit Erase Group Size: 512 Bytes reading image.ub 9520292 bytes read in 747 ms (12.2 MiB/s) ## Loading kernel from FIT Image at 10000000 ... Using 'conf-system-top.dtb' configuration |