8.1. aarch64 (AArch64)

8.1.1. Qemu A53

This BSP supports two variants, qemu_a53_ilp32 and qemu_a53_lp64. The basic hardware initialization is performed by the BSP. These BSPs support the GICv3 interrupt controller.

8.1.1.1. Boot via ELF

The executable image is booted by Qemu in ELF format.

8.1.1.2. Clock Driver

The clock driver uses the ARM Generic Timer.

8.1.1.3. Console Driver

The console driver supports the default Qemu emulated ARM PL011 PrimeCell UART.

8.1.1.4. Running Executables

Executables generated by these BSPs can be run using the following command:

qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio \
 -machine virt,gic-version=3 -cpu cortex-a53 -m 4096 -kernel example.exe

8.1.2. Qemu A72

This BSP supports two variants, qemu_a72_ilp32 and qemu_a72_lp64. The basic hardware initialization is performed by the BSP. These BSPs support the GICv3 interrupt controller.

8.1.2.1. Boot via ELF

The executable image is booted by Qemu in ELF format.

8.1.2.2. Clock Driver

The clock driver uses the ARM Generic Timer.

8.1.2.3. Console Driver

The console driver supports the default Qemu emulated ARM PL011 PrimeCell UART.

8.1.2.4. Running Executables

Executables generated by these BSPs can be run using the following command:

qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio

-machine virt,gic-version=3 -cpu cortex-a72 -m 4096 -kernel example.exe

8.1.3. Qemu Xilinx Versal

This BSP supports three variants: versal-qemu, versal-aiedge and versal-vck190. The basic hardware initialization is performed by the BSP. These BSPs support the GICv3 interrupt controller present in the Xilinx Versal Adaptive Compute Acceleration Platform (ACAP) systems. The BSPs currently only work when started in the secure mode.

8.1.3.1. Boot via ELF

The executable image is booted by Qemu in ELF format.

8.1.3.2. Clock Driver

The clock driver uses the ARM Generic Timer.

8.1.3.3. Console Driver

The console driver supports the default Qemu emulated ARM PL011 PrimeCell UART. There are some differences between the PL011 and the UART used by actual Versal ACAP hardware systems.

8.1.3.4. Running Executables

Executables generated by these BSPs can be run using the following command:

qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio

-machine xlnx-versal-virt -m 4096 -kernel example.exe

8.1.4. Xilinx ZynqMP

This BSP family supports the following variants:

  • zynqmp_qemu_ilp32

  • zynqmp_qemu

  • zynqmp_apu_ilp32

  • zynqmp_apu

  • zynqmp_cfc400x

Platform-specific hardware initialization is performed by ARM Trusted Firmware (ATF). Other basic hardware initialization is performed by the BSP. These BSPs support the GICv2 interrupt controller present in all ZynqMP systems. The zynqmp_apu BSP has been tested on zu2cg, zu3eg, and zu9cg chip variants and should also work on any other ZynqMP chip variant since the Processing Subsystem (PS) does not vary among chip variants other than the number of CPU cores available.

This BSP family has been tested on the following hardware:

  • Avnet UltraZed-EG SOM

  • Innoflight CFC-400X

  • Trenz TE0802

  • Xilinx ZCU102

8.1.4.1. Boot on QEMU

The executable image is booted by Qemu in ELF format.

8.1.4.2. Boot on ZynqMP Hardware

On ZynqMP hardware, RTEMS can be started at EL1, EL2, or EL3 by u-boot or directly as part of BOOT.bin. Regardless of the exception level at boot, RTEMS will drop to EL1 for execution. For quick turnaround during testing, it is recommended to use the u-boot BOOT.bin that comes with the PetaLinux prebuilts for the board in question.

Some systems such as the CFC-400X may require a bitstream to be loaded into the FPGA portion of the chip to operate as expected. This bitstream must be loaded before RTEMS begins operation since accesses to programmable logic (PL) memory space can cause the CPU to hang if the FPGA is not initialized. This can be performed as part of BOOT.bin or by a bootloader such as u-boot. Loading bitstreams from RTEMS has not been tested on the ZynqMP platform and requires additional libraries from Xilinx.

8.1.4.3. Hardware Boot Image Generation

RTEMS expects some hardware initialization to be performed by ATF and expects the services it provides to be present, so this must be included when generating a direct-boot RTEMS BOOT.bin.

When booting via u-boot, RTEMS must be packaged into a u-boot image or booted as a raw binary since u-boot does not currently support ELF64 which is required for AArch64 ELF binaries.

8.1.4.4. Example: Booting a RTEMS image on the ZCU102 ZynqMP board

This example will walk through the steps needed for booting RTEMS from a SD card on the ZCU102 ZynqMP board. The reference for setting up a SD card and obtaining pre-built boot images is here.

8.1.4.4.1. Hardware Setup

Set the dip switch SW6 according to the table below. This will allow the board to boot from the SD card. Connect a Micro-USB cable to the USB UART interface J83. This is a quad USB UART interface which will show up on the development host computer as four different serial or tty devices. Use the first channel for the console UART. It should be set to 115k baud.

Dip Switch JW6

ON

OFF

OFF

OFF

8.1.4.4.2. Prepare a SD card with a bootable partition

The goal is to have a bootable SD card with a partition that is formatted with the FAT file system. The file system will contain the boot artifacts including BOOT.bin and the u-boot image. The RTEMS image will be placed on this volume. To create the bootable SD card, follow the directions here.

Once you have the card formatted correctly, you need to place the files from this archive on the FAT partition. The following file was used for this example: xilinx-vck190-v2021.2-final.bsp

In order to download these files, you need to have a Xilinx account login. As an alternative, you can download a bootable image for Ubuntu 20.04 and write it to an SD card using a utility such as Balena Etcher or dd. The Ubuntu image is available here. Download the image for the Zynq Ultrascale+ MPSoC Development boards, uncompress it and write it to the SD card. This image creates multiple partitions, but we only need to use the FAT partition with the boot artifacts on it.

8.1.4.4.3. Verify that the board can boot from the SD card

It is worth booting the board from the SD card before trying to boot RTEMS. Insert the card and power on the board. You should see the messages on the first console indicating the various boot loader stages and eventually the Linux kernel. The goal is to interrupt u-boot when given the chance to access the u-boot command prompt.

8.1.4.4.4. Build RTEMS with examples

Build the RTEMS zynqmp_apu BSP. Use the ticker.exe sample which can be found in the directory:

build/aarch64/zynqmp_apu/testsuites/samples

8.1.4.4.5. Prepare the RTEMS image

Prepare your RTEMS image to boot from u-boot with the following commands:

$ aarch64-rtems@rtems-ver-major@-objcopy -Obinary ticker.exe ticker.bin
$ gzip -9 ticker.bin
$ mkimage -A arm64 -O rtems -T kernel -a 0x10000 -e 0x10000 -n RTEMS -d ticker.bin.gz rtems.img

Note: If the start address has been changed in the BSP configuration, you have to adapt the -a and -e parameters accordingly. To find out the start address of an application, aarch64-rtems6-nm ticker.exe | grep _start can be used. That will show the address of the _start symbol which is the value that has to be used for the two parameters.

8.1.4.4.6. Boot the RTEMS image

Copy the prepared RTEMS image to the SD card and insert the SD crd in the ZCU102 board. Power on the board. When you see the prompt on the console to interupt u-boot, hit a key to bring up the u-boot command prompt. On the u-boot command prompt you can boot your RTEMS image:

Zynq-MP> fatload mmc 0:1 0x1000 rtems.img
Zynq-MP> bootm 0x1000

This is the entire boot sequence:

Pre-FSBL boot Started
Xilinx Zynq MP First Stage Boot Loader
Release 2020.2   Nov 18 2020  -  11:46:01
NOTICE:  ATF running on XCZU9EG/silicon v1/RTL5.1 at 0xfffea000
NOTICE:  BL31: v2.2(release):xilinx_rebase_v2.2_2020.1-10-ge6eea88b1
NOTICE:  BL31: Built : 12:28:45, Nov 17 2020

U-Boot 2020.01 (Jun 15 2021 - 14:24:32 +0000)

Model: ZynqMP ZCU102 Rev1.0
Board: Xilinx ZynqMP
DRAM:  4 GiB
PMUFW:  v1.1
EL Level:       EL2
Chip ID:        zu9eg
NAND:  0 MiB
MMC:   mmc@ff170000: 0
In:    serial@ff000000
Out:   serial@ff000000
Err:   serial@ff000000
Bootmode: SD_MODE1
Reset reason:   SOFT
Net:
ZYNQ GEM: ff0e0000, mdio bus ff0e0000, phyaddr 12, interface rgmii-id

Warning: ethernet@ff0e0000 (eth0) using random MAC address - 82:32:1d:80:d9:c9
eth0: ethernet@ff0e0000
Hit any key to stop autoboot:  0

ZynqMP> fatload mmc 0:1 0x1000 rtems.img
46669 bytes read in 27 ms (1.6 MiB/s)
ZynqMP> bootm 0x1000
## Booting kernel from Legacy Image at 00001000 ...
   Image Name:   RTEMS
   Image Type:   AArch64 RTEMS Kernel Image (gzip compressed)
   Data Size:    46605 Bytes = 45.5 KiB
   Load Address: 10000000
   Entry Point:  10000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image
## Transferring control to RTEMS (at address 10000000) ...

*** BEGIN OF TEST CLOCK TICK ***
*** TEST VERSION: @rtems-version@.f381e9bab29278e4434b1a93e70d17a7562dc64c
*** TEST STATE: EXPECTED_PASS
*** TEST BUILD: RTEMS_POSIX_API RTEMS_SMP
*** TEST TOOLS: 10.3.1 20210409 (RTEMS 6, RSB ad54d1dd3cf8249d9d39deb1dd28b2f294df062d, Newlib eb03ac1)
TA1  - rtems_clock_get_tod - 09:00:00   12/31/1988
TA2  - rtems_clock_get_tod - 09:00:00   12/31/1988
TA3  - rtems_clock_get_tod - 09:00:00   12/31/1988
TA1  - rtems_clock_get_tod - 09:00:05   12/31/1988
TA2  - rtems_clock_get_tod - 09:00:10   12/31/1988
TA1  - rtems_clock_get_tod - 09:00:10   12/31/1988
TA1  - rtems_clock_get_tod - 09:00:15   12/31/1988
TA3  - rtems_clock_get_tod - 09:00:15   12/31/1988
TA2  - rtems_clock_get_tod - 09:00:20   12/31/1988
TA1  - rtems_clock_get_tod - 09:00:20   12/31/1988
TA1  - rtems_clock_get_tod - 09:00:25   12/31/1988
TA2  - rtems_clock_get_tod - 09:00:30   12/31/1988
TA1  - rtems_clock_get_tod - 09:00:30   12/31/1988
TA3  - rtems_clock_get_tod - 09:00:30   12/31/1988

*** END OF TEST CLOCK TICK ***

[ RTEMS shutdown ]

8.1.4.4.7. Follow up

This is just one possible way to boot the RTEMS image. For a development environment you may wish to configure u-boot to boot the RTEMS image from a TFTP server. For a production environment, you may wish to download, configure, and build u-boot, or develop a BOOT.BIN image with the RTEMS application.

8.1.4.5. Clock Driver

The clock driver uses the ARM Generic Timer.

8.1.4.6. Console Driver

The console driver supports the default Qemu emulated ARM PL011 PrimeCell UART as well as the physical ARM PL011 PrimeCell UART in the ZynqMP hardware.

8.1.4.7. SDHCI Driver

The ZynqMP bsp has an SDHCI driver which allows writing to and reading from SD cards. These can be tested in qemu using the “-sd” option. For example:

qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio \
 -machine xlnx-zcu102 -m 4096 -kernel media01.exe -sd example.img

The SD card image should have an MSDOS partition table with a single partition containing a FAT file system.

8.1.4.8. Network Configuration

When used with LibBSD, these BSP variants support networking via the four Cadence GEM instances present on all ZynqMP hardware variants. All interfaces are enabled by default, but only interfaces with operational MII busses will be recognized and usable in RTEMS. Most ZynqMP dev boards use RGMII with CGEM3.

When used with lwIP from the rtems-lwip integration repository, these BSP variants support networking via CGEM0 and one of the other CGEM* instances simultaneously. This is a limitation of the Xilinx driver, specifically in code referring directly to XPAR_XEMACPS_0_BASEADDR. Attempting to use more than two interfaces simultaneously may cause unexpected behavior. Attempting to use a set of two interfaces that does not include CGEM0 may cause unexpected behavior.

The interfaces will not come up by default under lwIP and must be configured manually. There are examples of this in the start_networking() implementation in netstart.c as used by the network tests.

8.1.4.9. Running Executables on QEMU

Executables generated by these BSPs can be run using the following command:

qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio \
 -machine xlnx-zcu102 -m 4096 -kernel example.exe

8.1.5. Raspberry Pi 4B

The ‘raspberrypi4b’ BSP currently supports only the LP64 ABI. ILP32 is not supported. Raspberry pi 4B all variants and Raspberry Pi 400 are supported. The default bootloader which is used by the Raspbian OS or other OS can be used to boot RTEMS. SMP is currently not supported.

Raspberry Pi 4B has 2 types of interrupt controller, GIC-400 (GICv2) and ARM legacy generic controller. Both are supported.

The documentation says that enable_gic=1 is the default but that seems to be true only if device tree is present otherwise it reverts to the legacy interrupt controller. So set enable_gic=1 in the config.txt file to make sure gic is enable.

8.1.5.1. Build Configuration Options

The following options can be used in the BSP section of the waf configuration INI file. The waf defaults can be used to inspect the values.

CONSOLE_USE_INTERRUPTS

Use interrupt driven mode for console devices (enabled by default).

GPU_CORE_CLOCK_RATE

The GPU processor core frequency in Hz (default is 500000000), The value of this option should be the same as the value of option core_freq in config.txt. See the Raspberry Pi documentation for details.

BSP_SPI_USE_INTERRUPTS

Use interrupt mode in the SPI driver (enabled by default).

BSP_CLOCK_USE_SYSTEMTIMER

Use the System Timer in the clock driver (disable by default).

BSP_CONSOLE_PORT

Default UART port for the console device (default is UART0). The optional ports are UART0, UART2, UART3, UART4, UART5.

BSP_PL011_CLOCK_FREQ

PL011 UART clock frequency in Hz (default is 48000000). The value of this option should be the same as the value of option init_uart_clock in config.txt. See the Raspberry Pi documentation for details.

8.1.5.2. Clock Driver

Raspberry pi 4B has two timers.

The System Timer and The ARM Generic Timer.

The clock from the ARM timer is derived from the system clock. This clock can change dynamically e.g. if the system goes into reduced power or in low power mode. Thus the clock speed adapts to the overall system performance capabilities. For accurate timing it is recommended to use the system timers.

The clock driver uses the ARM Generic Timer by default. Set BSP_CLOCK_USE_SYSTEMTIMER = True in the Build Configuration Options to enable the System Timer.

8.1.5.3. Console Driver

Raspberry pi 4B has 2 types of UARTs, ARM PL011 and Mini-uart. The PL011 is a capable, broadly 16550-compatible UART, while the mini UART has a reduced feature set. The console driver supports the default Qemu emulated ARM PL011 PrimeCell UART as well as the physical ARM PL011 PrimeCell UART in the raspberrypi hardware. Mini-uart is not supported.

Set BSP_CONSOLE_PORT in the Build Configuration Options to set the default UART port for the console device.

Initialize gpio of UART and install UART to the dev directory by raspberrypi_uart_init() function.

#include <assert.h>
#include <bsp/console.h>

void uart_init(void)
{
  int rv;

  /* The optional devices are UART0, UART2, UART3, UART4, UART5. */
  rv =  raspberrypi_uart_init(UART0);
  assert(rv == 0);
}

8.1.5.4. GPIO Driver

The GPIO of Raspberry pi 4B can be controlled by the following functions: raspberrypi_gpio_set_function() raspberrypi_gpio_set_pin() raspberrypi_gpio_clear_pin() raspberrypi_gpio_set_pull()

8.1.5.5. SPI Driver

The BCM2711 device has five SPI interfaces of this type: SPI0, SPI3, SPI4, SPI5 & SPI6. It has two additional mini SPI interfaces (SPI1 and SPI2). The SPI driver supports SPI0, SPI3, SPI4, SPI5 & SPI6. The mini SPI is not supported.

SPI drivers are registered by the raspberrypi_spi_init() function. The driver has no DMA support, but has interrupt support.

#include <assert.h>
#include <bsp/raspberrypi-spi.h>

void spi_init(void)
{
  int rv;

  /*
   * The optional devices are raspberrypi_SPI0, raspberrypi_SPI3,
   * raspberrypi_SPI4, raspberrypi_SPI5, raspberrypi_SPI6.
   */
  rv =  raspberrypi_spi_init(raspberrypi_SPI0);
  assert(rv == 0);
}

8.1.5.6. Watchdog Driver

void raspberrypi_watchdog_example()
{
  raspberrypi_watchdog_init();
  raspberrypi_watchdog_start(15000);

  raspberrypi_watchdog_reload();
  /* ... */
  raspberrypi_watchdog_reload();

  raspberrypi_watchdog_stop();
}

8.1.5.7. Preparing to boot

Raspberry Pi uses a different mechanism to boot when compared with any ARM SoC. First the GPU initializes, loads the bootloader (Raspberry pi firmware) and then looks for the kernel img. This whole process is done by the GPU (VideoCore IV) till the kernel is loaded. More information can be found on the Raspberry pi documentation page. By default the arm64 mode looks for the kernel8.img. Any other kernel can be loaded by adding kernel=<img_name> to the config.txt file.

The Firmware files are required in order to boot RTEMS. The latest firmware can be downloaded from the Raspberry Pi Firmware Repository. USB boot is supported. All the files (Firmwares and kernel) must be place in the FAT32 partition only. Add arm_64bit=1 in the config.txt file in order to boot the BSP in 64bit kernel mode (it is default).

8.1.5.7.1. UART Setup

Connect your serial device to the GPIO15 and GPIO14. Add the following to the config.txt file in order to use the PL011 UART0 and thus disabling the default Mini-uart.

A Minimal version of config.txt: .. code-block:: none

# If you use mini-uart, please comment it out. dtoverlay=disable-bt

# If you use mini-uart, enable it. # enable_uart=1

# The documentation says that enable_gic=1 is the default but that seems to be # true only if device tree is present otherwise it reverts to the legacy # interrupt controller. enable_gic = 1

8.1.5.7.2. Generating kernel image

The following steps show how to run hello.exe on the BSP. Other executables can be processed in a similar way.

To create the kernel image:

$ aarch64-rtems@rtems-ver-major@-objcopy -Obinary hello.exe kernel8.img

Copy the kernel image to the SD card.

8.1.5.8. JTAG Setup

The Raspberry Pi 4 doesn’t have dedicated JTAG pins. Instead, you must configure the GPIO pins (GPIO22-GPIO27) to activate the JTAG functionality. The RPi 4 documentation refers to this as Alt4 functions of those pins. Alt5 does exist too, which goes from GPIO4, 5, 6, 12 and 13. you can check this out from pinout.xyz or eLinux

One more thing to note on JTAG with Raspberry pi 4B is that, by default, All the GPIO pins are pulled down, according to the BCM2711 documentation. This wasn’t the case in the earlier models. So in order to let the data flow freely, we will have to disable them.

# Disable pull downs
gpio=22-27=np

# Enable jtag pins (i.e. GPIO22-GPIO27)
enable_jtag_gpio=1