Versions Compared


  • This line was added.
  • This line was removed.
  • Formatting was changed.

This page is intended to complement  UG1186 "LibMetal and OpenAMP User Guide"  for Zynq-7000 and Zynq UltraScale+ MPSoC.

Table of Contents

Table of Contents
excludeTable of Contents

Getting Started with the Pre-Built Images

Here are the basic steps to boot Linux and run an openamp application using pre-built images.

e.g for ZCU102:
The echo-test application sends packets from Linux running on quad-core Cortex-A53 to a single cortex-R5 running FreeRTOS which sends them back.
  • Extract the files BOOT.BIN, image.ub and openamp.dtb files from a pre-built PetaLinux BSP to an SD card.

    Code Block
    host shell$ petalinux-create -star xvf xilinx-zcu102-v2020.12-final.bsp --strip-components=4 --wildcards */BOOT.BIN */image.ub */openamp.dtb
    host shell$ cp BOOT.BIN image.ub openamp.dtb <your sd card>

Note: Alternatively, if you already created a PetaLinux project with a provided BSP for your board, pre-built images can also be found under the <your project>/pre-built/linux/images/ directory.
  • Go to the u-boot prompt and boot Linux from the SD card.

    Code Block
    Hit any key to stop autoboot:  0 
    u-boot> fatload mmc 0 0x3000000 Image
    u-boot> fatload mmc 0 0x2000000 openamp.dtb
    u-boot> fatload mmc 0 0x2A00000  rootfs.cpio.gz.u-boot
    u-boot> bootm 0x3000000 0x2A00000 0x2000000

Note: As an alternative to all steps above to boot from an SD card, you can boot the board via JTAG. For this you need to have connected a JTAG cable, installed JTAG drivers and created a PetaLinux project using a provided BSP. You would then go into the <your project>/pre-built/linux/images directory and replace file system.dtb by openamp.dtb, then enter: "petalinux-boot --jtag --prebuilt 3"
  • At Linux login prompt enter 'root' for user and 'root' for password and run echo-test demo

    Code Block
    plnx_aarch64 login: root
    root@plnx_aarch64:~# echo image_echo_test > /sys/class/remoteproc/remoteproc0/firmware 
    root@plnx_aarch64:~# echo start > /sys/class/remoteproc/remoteproc0/state   
    [  177.375451] remoteproc remoteproc0: powering up ff9a0100.zynqmp_r5_rproc
    [  177.384705] remoteproc remoteproc0: Booting fw image image_echo_test, size 644144
    [  177.396832] remoteproc remoteproc0: registered virtio0 (type 7)
    [  177.399108] virtio_rpmsg_bus virtio0: rpmsg host is online
    [  177.412370] zynqmp_r5_remoteproc ff9a0100.zynqmp_r5_rproc: RPU boot from TCM.
    [  17Starting application...
    Try to init remoteproc resource
    Init remoteproc resource succeeded
    Waiting for events...
    7.422089] remoteproc remoteproc0: remote processor ff9a0100.zynqmp_r5_rproc is now up
    [  177.442121] virtio_rpmsg_bus virtio0: creating channel rpmsg-openamp-demo-channel addr 0x1
    root@plnx_aarch64:~# echo_test
     Echo test start 
     Open rpmsg dev! 

Docs and source code


  • The following document describes libmetal APIs:
    View file

URLs to source code

Xilinx Openamp and Libmetal related code

The following locations provide access to the code:

Additional examples

ZynqMP Linux Master running on APU with RPMsg in kernel space and one RPU slave.

When running with RPU in split mode and only one RPU is an OpenAMP slave, the second RPU can still run another non-openamp application.


  • RPU 0:
    • use default application in petalinux BSP: build with petalinux-build -c openamp-fw-echo-testd
  • RPU 1:
    • in petalinux project, modify <plnx proj root>/components/yocto/layers/meta-xilinx-tools/recipes-openamp/examples/ :  XSCTH_PROC_zynqmp ?= "psu_cortexr5_0" to "psu_cortexr5_1"

Device Tree:

  • append the following to <plnx proj root>/ project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
  • note the snippet within for rpu1 instead of rpu0
  • The memory sections in the below sample described in the reserved-memory node that are then shown in the memory-region property of the remoteproc node are needed for either sections where the ELF binary is loaded into or that the binary uses at runtime for OpenAMP-related IPC communication. 
    • In this case rpu0vdev0buffer@3ed48000  range of 0x3ed48000 - 0x3ee48000  is not described in the linker script but is used at runtime for shared buffers. As such this range should be described in the reserved-memory node so that it is not unduly mapped in by the kernel. Similarly for rpu0vdev0vring0@3ed40000 and rpu0vdev0vring1@3ed44000
    • As the default linker script for OpenAMP applications running on R5 use the DDR address range of 0x3ed00000  to 0x3ed40000 is used as a section to load the R5 ELF binary, this also needs to be described in the reserved-memory node so that the ELF can run there and not overwrite memory that would ordinarily be mapped into the kernel.
    • In addition to the nodes described in reserved-memory the R5 has TCM nodes with their own memory ranges that are coupled with each of the R5 cores. As such, the memory ranges for each are described as they might be used for ELF loading with the corresponding R5 remoteproc node that these TCM nodes are respectively coupled with.
Code Block
/ {
	reserved-memory {
		#address-cells = <2>;
		#size-cells = <2>;
		rpu0vdev0vring0: rpu0vdev0vring0@3ed40000 {
			reg = <0x0 0x3ed40000 0x0 0x4000>;
		rpu0vdev0vring1: rpu0vdev0vring1@3ed44000 {
			reg = <0x0 0x3ed44000 0x0 0x4000>;
		rpu0vdev0buffer: rpu0vdev0buffer@3ed48000 {
			reg = <0x0 0x3ed48000 0x0 0x100000>;
		rproc_0_reserved: rproc@3ed00000 {
			reg = <0x0 0x3ed00000 0x0 0x40000>;
	zynqmp-rpu {
		compatible = "xlnx,zynqmp-r5-remoteproc-1.0";
		#address-cells = <2>;
		#size-cells = <2>;
		core_conf = "split";
		reg = <0x0 0xFF9A0000 0x0 0x10000>;
		r5_0: r5@0 {
			#address-cells = <2>;
			#size-cells = <2>;
			memory-region = <&rproc_0_reserved>, <&rpu0vdev0buffer>, <&rpu0vdev0vring0>, <&rpu0vdev0vring1>;
			pnode-id = <0x7>;
			mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>;
			mbox-names = "tx", "rx";
			tcm_0_a: tcm_0@0 {
				reg = <0x0 0xFFE00000 0x0 0x10000>;
				pnode-id = <0xf>;
			tcm_0_b: tcm_0@1 {
				reg = <0x0 0xFFE20000 0x0 0x10000>;
				pnode-id = <0x10>;
		/* if instead for RPU1 use the following: 
    	r5_1: r5@1 {
        	#address-cells = <2>;
        	#size-cells = <2>;
        	memory-region = <&rproc_0_fw_reserved>,
        	pnode-id = <0x8>;
        	mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>;
        	mbox-names = "tx", "rx";
        	tcm_a: tcm@0 {
            	reg = <0x0 0xFFE90000 0x0 0x10000>;
            	pnode-id = <0x11>;
        	tcm_b: tcm@1 {
            	reg = <0x0 0xFFEb0000 0x0 0x10000>;
            	pnode-id = <0x12>;

	zynqmp_ipi1 {
		compatible = "xlnx,zynqmp-ipi-mailbox";
		interrupt-parent = <&gic>;
		interrupts = <0 29 4>;
		xlnx,ipi-id = <7>;
		#address-cells = <1>;
		#size-cells = <1>;

		/* APU<->RPU0 IPI mailbox controller */
		ipi_mailbox_rpu0: mailbox@ff990600 {
			reg = <0xff990600 0x20>,
			      <0xff990620 0x20>,
			      <0xff9900c0 0x20>,
			      <0xff9900e0 0x20>;
			reg-names = "local_request_region",
			#mbox-cells = <1>;
			xlnx,ipi-id = <1>;


  1. Create R5-0 standalone BSP
    • NOTE: make sure that R5 BSP has XilPM and GIC software components built. XilPM is used to interface with the ZU+ PMUFW to bring up RPU. The GIC is needed as IPIs are the mechanism by which to communicate with the XilPM framework.
  2. Build libmetal for R5 standalone
    1. below is sample toolchain file

      Code Block
      set (CMAKE_SYSTEM_PROCESSOR "arm"           CACHE STRING "")
      set (MACHINE        "zynqmp_r5" CACHE STRING "")
      set (CROSS_PREFIX           "armr5-none-eabi-" CACHE STRING "")
      set (CMAKE_C_FLAGS          "-mfloat-abi=hard -mcpu=cortex-r5 -mfpu=vfpv3-d16  -Wall -Werror -Wextra \
         -flto -Os -I<path to bsp>/bsp/psu_cortexr5_0/include" CACHE STRING "")
      <path to bsp>/bsp/psu_cortexr5_0/lib
      set (PLATFORM_LIB_DEPS      "  -lxil -lxilstandalone  -lc -lm  -lxilpm " CACHE STRING "")
      SET(CMAKE_AR  "gcc-ar" CACHE STRING "")
      include (cross-generic-gcc)

    2. script to build libmetal

      Code Block
      git clone
      cd libmetal
      mkdir build_r5
      cd build_r5
      cmake .. -DCMAKE_TOOLCHAIN_FILE=<toolchain_file>  \
      -DCMAKE_LIBRARY_PATH=<path to bsp>/bsp/psu_cortexr5_0/lib 
      make DESTDIR=. install VERBOSE=1

  3. build openamp for r5 standalone

    1. toolchain file for openamp

      Code Block
          set (MACHINE                zynqmp_r5 )
          set (CROSS_PREFIX           "armr5-none-eabi-" CACHE STRING "")
          set (CMAKE_C_FLAGS          "-mfloat-abi=hard -mcpu=cortex-r5 -Os -flto -mfpu=vfpv3-d16 -DUNDEFINE_FILE_OPS \
          -I<path to libmetal repo>/libmetal/build_r5/usr/local/include \
          -I<bsp path>/bsp/psu_cortexr5_0/include" CACHE STRING "")
          set (CMAKE_ASM_FLAGS        " -mcpu=cortex-r5  " CACHE STRING "")
          set (PLATFORM_LIB_DEPS      "  -lxil -lxilstandalone  -lxilpm -lxilmem -lc -lm" CACHE STRING "")
          SET(CMAKE_AR  "gcc-ar" CACHE STRING "")
          SET(CMAKE_C_ARCHIVE_FINISH   true)
      <path to libmetal repo>/libmetal/build_r5/usr/local/include/
      <path to libmetal repo>/libmetal/build_r5/usr/local/lib/
         set (WITH_LOAD_FW ON)
         set (CMAKE_FIND_ROOT_PATH <path to libmetal repo>/libmetal/build/usr/local/lib <bsp path>/bsp/psu_cortexr5_0/lib )
          include (cross_generic_gcc)
          string (TOLOWER "FreeRTOS"                PROJECT_SYSTEM)
          string (TOUPPER "FreeRTOS"                PROJECT_SYSTEM_UPPER)
      # vim: expandtab:ts=2:sw=2:smartindent

    2. srcipt using toolchain file for openamp

      Code Block
      git clone
      cd open-amp
      mkdir build
      cd build
      cmake .. \
       -DCMAKE_TOOLCHAIN_FILE=toolchain \
       -DCMAKE_INCLUDE_PATH="<path to libmetal repo>/libmetal/build_r5/lib/include/;<path to bsp>/bsp/psu_cortexr5_0/include/" \
       -DCMAKE_LIBRARY_PATH="<path to libmetal repo>/libmetal/build_r5/usr/local/lib/<path to bsp>/bsp/psu_cortexr5_0/lib/" -DWITH_APPS=on -DWITH_LOAD_FW=ON
      make DESTDIR=$(pwd) install VERBOSE=1

      Note: how to set remoteproc elf-load slave
      1. If RPU1 is slave, add thef ollowing after -DWITH_LOAD_FW=ON, add -DLOAD_FW_TARGET=NODE_RPU_1
      2. If APU is slave, add thef ollowing after -DWITH_LOAD_FW=ON, add -DLOAD_FW_TARGET=NODE_APU_1
  4. boot up to uboot on target zcu102
    1. in xsdb: 
      1. WARNING: do not reset remoteproc slave processor. as this introduces issue when using PM library for lifecycle management
      2. confgure r5 to be in split mode if using single r5 as remoteproc slave
      3. reset tcm
      4. load remoteproc slave application into base address (default 0x3ed00000)
      5. load binary for r5 remoteproc master (in this case r5 0)
      6. start r5 0

        Code Block
        ta 6
        # set r5 to split
        mwr 0xFF9A0000 0x08
        # reset tcm
        ta 7
        rst -processor
        mwr 0xFFE00000 0 10000
        after 1000
        mwr 0xFFE20000 0 10000
        after 1000
        # load apu
        dow -data <a53 app> 0x3ed00000
        # load rpu
        ta 6
        dow load_fw.out
        # start rpu