Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: fix spelling, code link

This document describes the base set of hardware required for OpenAMP to operate successfully as presented in Xilinx Vitis OpenAMP and libmetal template examples.

Table of Contents

Table of Contents
excludeTable of Contents

Introduction

This document describes the base set of hardware required for OpenAMP to operate successfully as presented in Xilinx Vitis OpenAMP and libmetal template examples. It covers configurations for the RPU memory, shared memory for both the APU and RPU, generic interrupt controllers (GIC) and the inter-processor interconnect (IPI) interrupts. There are several examples of using Vitis, PetaLinux and OpenAMP, however this is not a tutorial for these tools. The reader is encouraged to refer to Xilinx user guides listed in the Related Links.

OpenAMP on Xilinx SoCs

Xilinx SoC products combine a set of heterogeneous hardware designs into one powerful and flexible platform that includes Arm Cortex-Ax, Cortex-R5 and Xilinx MicroBlaze processors. The OpenAMP project enables a distributed software architecture across this asymmetric multiprocessing platform (AMP).

There are two components of the OpenAMP framework:

  1. Life Cycle Management (LCM) : enables a master processor to load, start and stop a firmware on a remote processor.

  2. Inter-Processor Communication (IPC): interrupts, shared memory and message passing between the master and the remote processor.

Both the LCM and the IPC in the demos are using the remoteproc and the rpmsg drivers in the Linux kernel.  Xilinx SoCs based systems should provide access to a specific set of hardware resources in order to use the OpenAMP framework. Depending on the OpenAMP or libmetal demo this includes:

  1. Processing cores; need at least two:

    1. application processing unit (APU)

    2. real-time processing unit (RPU) for Versal and ZynqMP

  2. Memory for the processing system (PS): APU (master), RPU (remote) and shared memory:

    1. DDR

    2. Tightly-coupled memory (TCM)

    3. On-chip memory (OCM)

  3. Interrupts:

    1. APU GIC interrupts

    2. RPU GIC interrupts

    3. IPI interrupts

The next section tries to generalize each hardware component as it is used in the OpenAMP, followed by specific example of configuring some demos with the default values and another section showing how to change the defaults.

Zynq UltraScale+ MPSoC and Versal

LCM: Memory for RPU Firmware

Most demos use the DDR or the Tightly Coupled Memory (TCM) for RPU firmware text and data depending on the linker script (e.g.: linker_remote.ld) while the stack, heap and the interrupt vector table are in the TCM. The RPU is configured to enable the TCM interfaces from reset with base address 0 for TCMA. The Linux remoteproc driver on the APU will preload the TCMA with the boot code while the RPU is halted. When the halt is removed the RPU starts fetching instructions from the reset vector address in the normal way. The RPU's firmware .vectors section is loaded into TCMA at address 0 (see linker script). It starts with a set of branch instructions called _vector_table and a few code blocks labeled _boot, init and a function Init_MPU(). When the remoteproc driver requests RPU start t he the execution begins at address 0 in TCMA with a jump to _boot which calls Init_MPU(). All this is fetched from and executed in the TCMA. At the end the _boot jumps to _startup which could be in the DDR. The _startup prepares the "C runtime" and calls main().

Firmware load memory

ZynqMP / Versal

RPU

0x3ED0_0000,  see linker script

APU kernel DT

0x3ED0_0000,  see rproc_0_reserved in the Linux Device Tree 

APU app

not used

IPC: Shared Memory

The OpenAMP demos have a .resource_table ELF section as in this example linker_remote.ld. It has list of system resources required by the Linux remoteproc, e.g.: virtIO device data used by rpmsg, see rsc_table.h and rsc_table.c.

The default location for shared meory memory is the DDR.

SHM_BASE_ADDR

ZynqMP / Versal

RPU

E.g. 0x3ED8_0000,  see metal_dev_table,  SHARED_MEM_PA, SHARED_MEM_SIZE, SHARED_BUF_OFFSET

APU kernel DT

E.g. 0x3ED8_0000, see reserved-memory nodes in the Linux Device Tree 

APU app: libmetal_amp_demo

UIO nodes names for zynqMP:

Code Block
languagenone
SHM_DEV_NAME "3ed80000.shm"
IPI_DEV_NAME="ff340000.ipi"         (if Versal=)  "ff360000.ipi"
TTC_DEV_NAME="ff110000.timer"       (if Versal=)  "ff0e0000.ttc0"

APU app: openamp demos

Code Block
/sys/bus/rpmsg/devices/virtio0.rpmsg-openamp-demo-channel.-1.0

IPC: Interrupts

Info

Recommended Reading

  •  UG1085                  Chapter 13: Interrupts

  •  Versal-ACAP-TRM  Chapter 52: Inter-Processor Interrupts

The OpenAMP and Libmetal demos use the IPI interrupts to enable one processor (source agent) to interrupt another processor (destination agent). The communications process uses the IPI interrupt register structure, the system interrupt structure, and the IPI message buffers. On the RPU’s firmware side these are represented by the struct metal_device ipi_device and IPI_CHN_BITMASK in platform_info.c.

GIC

IRQ System Interrupts: see IPI_IRQ_VECT_ID

Versal

63      See "IRQ System Interrupts" in Versal-ACAP-TRM for IPI1 "IPI 1 interrupt";

ZynqMP

65      or XPAR_XIPIPSU_0_INT_ID  See "system interrupts"  in UG1085 for RPU0 IPI_Ch1  

The demos need two IPI channels (and IPI masks) one for the APU and one for the RPU. These are selected from the set of seven reprogrammable IPIs. Other system users might be requesting IPI channels. Both the firmware and the Linux device tree should be checked to detect and avoid conflicts.


ZynqMP

IPI Channel

Base Addr

IPI_MASK  / IPI_CHN_BITMASK

See UG1087 Register Reference

References

Send to Ch_7

Send to Ch_1

RPU_0

Ch_1

0xFF31_0000

0x0100_0000 (set bit 24)


ipi_device, IPI_BASE_ADDR, IPI_CHN_BITMASK in platform_info.h

APU

Ch_7

0xFF34_0000


0x100 (set bit 8)


"xlnx,ipi-id" property, zynqmp_ipi1 node in ZynqMP .dtsi :

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

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

In Versal the channel names and numbers are different, see Versal-ACAP-TRM


Versal

IPI Channel

Base Addr

IPI_MASK / IPI_CHN_BITMASK

Versal ACAP Register Reference

References

Send to ipi3

Send to ipi1

RPU_0

ipi1

0xFF34_0000

0x20  (set bit 5)

ipi_device, IPI_BASE_ADDR, IPI_CHN_BITMASK in platform_info.h

APU

ipi3

0xFF36_0000


0x8 (set bit 3)

"xlnx,ipi-id" property, zynqmp_ipi1 node in Versal .dtsi. The mapping of ipi-id to channel is not obvious and it’s not the same as in ZynqMP.

Code Block
zynqmp_ipi1 {
    compatible = "xlnx,zynqmp-ipi-mailbox";
    interrupt-parent = <&gic>;
    interrupts = <0 33 4>;
    xlnx,ipi-id = <5>;
    #address-cells = <1>;
    #size-cells = <1>;
    ranges;

    /* APU<->RPU0 IPI mailbox controller */
    ipi_mailbox_rpu0: mailbox@ff990600 {
        reg = <0xff3f0ac0 0x20>,
              <0xff3f0ae0 0x20>,
              <0xff3f0740 0x20>,
              <0xff3f0760 0x20>;
        reg-names = "local_request_region",
                "local_response_region",
                "remote_request_region",
                "remote_response_region";
        #mbox-cells = <1>;
        xlnx,ipi-id = <3>;
    };
};

Build and Run Demos

Build RPU firmware

Step 1. Launch Vitis IDE and select a workspace directory with enough free space and fast access. Local disk is prefered as some NFS can be slow.

Step 2. Create a new application project using "File > New Application Project".  This will start a wizard that will guide you through the process.

  • Create a new platform from hardware description XSA file. Select from the included XSA’s or use browse and import your own XSA.

  • Specify the application project name. E.g.: lm_amp and select psu_cortexr5_0 as the target processor from the list.

  • Select template for your project, e.g. "Libmetal AMP Application" and click "Finish":

Processor for the RPU firmware project

Domain: FreeRTOS or generic

Libmetal AMP Demo, OpenAMP echo-test,..

Configuration of some hardware blocks used in this demo must match between the RPU’s firmware and APU’s Linux kernel, device tree and the user application. Please, see the "Hardware specification" tab to examine the address maps for APU and RPU processors:

  1. Memory: DDR and Tightly-coupled memory (TCM)

  2. Interrupts: PS-to-PS interrupts and Inter-processor interrupts (IPI)

  3. Timers: Triple Timer Counters (TTC)

Hardware specification: Memory Maps

IPI:  psu_ipi_1 example

Linker Script: lscript.ld

Firmware memory map: Select lscript.ld file in the source Explorer. The summary view shows the memory regions for this application:

  1. The processor is configured to enable the TCM interfaces from reset with base address 0x0 for TCMA and 0x20000 for TCMB. This demo does not use TCMB.

  2. The stack, heap and the interrupt vector table are in psu_r5_atcm_MEM_0, TCMA.

  3. The text, read-only, initialized, uninitialized data sections, etc. are in psu_r5_ddr_0_MEM_0 starting at 0x3ED00000 with LENGTH=0x80000.

  4. OpenAMP demos have .resource_table ELF section. It has list of system resources required by the Linux remoteproc, e.g.: virtIO device data.

  5. The Linux remoteproc driver on the APU will preload the TCMA with the boot code while halting the RPU via nCPUHALTm pin. When the nCPUHALTm pin is deasserted, the processor starts fetching instructions from the reset vector address in the normal way. The FreeRTOS _vector_table is loaded into TCMA at address 0x0 followed by _boot and Init_MPU().

  6. The execution starts at address 0x0 in TCMA via a jump to _boot which calls Init_MPU(). All this is fetched from and executed in the TCMA. At the end the _boot jumps to _startup in the DDR. The _startup prepares the "C runtime" and calls main(). Starting from _startup the RPU fetches its instructions from the DDR while its stack and heap are in the TCMA.

Step 3. Build the application project: click lm_amp or lm_amp_system in the source Explorer and select "Project > Build Project". The build produces an ARM CortexR5 binary in the Debug (or Release) directory called lm_amp.elf. In this example this binary will be loaded to execute on the RPU (r5_0) via Xilinx remoteproc Linux driver.

Build PetaLinux

Create a PetaLinux project using the BSP where we took the XSA file for the RPU firmware:

  1. Code Block
        source <path_to_petalinux_settings>
        petalinux-create -t project -s <path_to_petalinux_project_bsp>
  2. Depending on the selected demo you have to enable the following kernel config options (see: project-spec/meta-user/recipes-kernel/linux/linux-xlnx_%.bbappend and the kernel config file (e.g.: defconfig) it includes):

    Code Block
    CONFIG_UIO_PDRV_GENIRQ=m
    CONFIG_RPMSG_CHAR=m
    CONFIG_RPMSG_VIRTIO=m
    CONFIG_RPMSG=m
    CONFIG_VIRTIO=m
    CONFIG_REMOTEPROC=y
    CONFIG_ZYNQMP_R5_REMOTEPROC=m
    CONFIG_SPARSEMEM_VMEMMAP=y
  3. Copy one of the following device tree overlay files into <plnx-proj>/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi depending on the demo selected for the RPU firmware:

Expand
titleLibmetal AMP demo: system-user.dtsi for ZynqMP
Code Block
/ {
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        rproc_0_reserved: rproc@3ed000000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x40000>;
        };
    };

    zynqmp-rpu {
        compatible = "xlnx,zynqmp-r5-remoteproc-1.0";
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        core_conf = "lockstep";
        reg = <0x0 0xFF9A0000 0x0 0x10000>;
        r5_0: r5@0 {
            #address-cells = <2>;
            #size-cells = <2>;
            ranges;
            memory-region = <&rproc_0_reserved>;
            pnode-id = <0x7>;
            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>;
            };
        };
    };
        /* Shared memory */
    shm0: shm@0 {
            compatible = "shm";
            reg = <0x0 0x3ed80000 0x0 0x1000000>;
    };
        /* IPI device */
    ipi0: ipi@0 {
            compatible = "ipi_uio";
            reg = <0x0 0xff340000 0x0 0x1000>;
            interrupt-parent = <&gic>;
            interrupts = <0 29 4>;
    };
};

&ttc0 {
        /* compatible = "ttc"; timer@ff110000 */
        status = "okay";
};
&ttc1 {
        /* compatible = "ttc"; timer@ff120000 */
        status = "okay";
};
Expand
titleLibmetal AMP demo: system-user.dtsi for Versal
Code Block
/ {
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        rproc_0_reserved: rproc@3ed000000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x2000000>;
        };
    };

    zynqmp-rpu {
        compatible = "xlnx,zynqmp-r5-remoteproc-1.0";
        #address-cells = <0x2>;
        #size-cells = <0x2>;
        ranges;
        core_conf = "lockstep";
        reg = <0x0 0xff9a0000 0x0 0x10000>;

        r5_0: r5@0 {
            #address-cells = <0x2>;
            #size-cells = <0x2>;
            ranges;
            memory-region = <&rproc_0_reserved>;
            pnode-id = <0x18110005>;
            tcm_0@0 {
                reg = <0x0 0xffe00000 0x0 0x10000>;
                pnode-id = <0x1831800b>;
            };

            tcm_0@1 {
                reg = <0x0 0xffe20000 0x0 0x10000>;
                pnode-id = <0x1831800c>;
            };
        };
    };

    /* Shared memory */
    shm0: shm@0 {
            compatible = "shm_uio";
            reg = <0x0 0x3ed80000 0x0 0x1000000>;
    };

    /* IPI device */
    ipi_amp: ipi@ff360000 {
        compatible = "ipi_uio";
        reg = <0x0 0xff360000 0x0 0x1000>;
        interrupt-parent = <&gic>;
        interrupts = <0 33 4>;
    };

    ttc0 {
        compatible = "ttc-uio";
        reg = <0x0 0xFF0E0000 0x0 0x1000>;
    };
};
Expand
titleOpenAMP demos: system-user.dtsi for ZynqMP
Code Block
/ {
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        rpu0vdev0vring0: rpu0vdev0vring0@3ed40000 {
            no-map;
            reg = <0x0 0x3ed40000 0x0 0x4000>;
        };
        rpu0vdev0vring1: rpu0vdev0vring1@3ed44000 {
            no-map;
            reg = <0x0 0x3ed44000 0x0 0x4000>;
        };
        rpu0vdev0buffer: rpu0vdev0buffer@3ed48000 {
            no-map;
            reg = <0x0 0x3ed48000 0x0 0x100000>;
        };
        rproc_0_reserved: rproc@3ed00000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x40000>;
        };
    };

    zynqmp-rpu {
        compatible = "xlnx,zynqmp-r5-remoteproc-1.0";
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        core_conf = "lockstep";
        reg = <0x0 0xFF9A0000 0x0 0x10000>;
        r5_0: r5@0 {
            #address-cells = <2>;
            #size-cells = <2>;
            ranges;
            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>;
            };
        };
    };

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

        /* APU<->RPU0 IPI mailbox controller */
        ipi_mailbox_rpu0: mailbox@ff90000 {
            reg = <0xff990600 0x20>,
                  <0xff990620 0x20>,
                  <0xff9900c0 0x20>,
                  <0xff9900e0 0x20>;
            reg-names = "local_request_region",
                    "local_response_region",
                    "remote_request_region",
                    "remote_response_region";
            #mbox-cells = <1>;
            xlnx,ipi-id = <1>;
        };
    };
};
Expand
titleOpenAMP demos: system-user.dtsi for Versal
Code Block
 / {
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        rpu0vdev0vring0: rpu0vdev0vring0@3ed40000 {
            no-map;
            reg = <0x0 0x3ed40000 0x0 0x4000>;
        };
        rpu0vdev0vring1: rpu0vdev0vring1@3ed44000 {
            no-map;
            reg = <0x0 0x3ed44000 0x0 0x4000>;
        };
        rpu0vdev0buffer: rpu0vdev0buffer@3ed48000 {
            no-map;
            reg = <0x0 0x3ed48000 0x0 0x100000>;
        };
        rproc_0_reserved: rproc@3ed00000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x40000>;
        };
    };

    zynqmp-rpu {
        compatible = "xlnx,zynqmp-r5-remoteproc-1.0";
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        core_conf = "lockstep";
        reg = <0x0 0xFF9A0000 0x0 0x10000>;
        r5_0: r5@0 {
            #address-cells = <2>;
            #size-cells = <2>;
            ranges;
            memory-region = <&rproc_0_reserved>, <&rpu0vdev0buffer>, <&rpu0vdev0vring0>, <&rpu0vdev0vring1>;
            pnode-id = <0x18110005>;
            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 = <0x1831800b>;
            };
            tcm_0_b: tcm_0@1 {
                reg = <0x0 0xFFE20000 0x0 0x10000>;
                pnode-id = <0x1831800c>;
            };
        };
    };

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

        /* APU<->RPU0 IPI mailbox controller */
        ipi_mailbox_rpu0: mailbox@ff990600 {
            reg = <0xff3f0ac0 0x20>,
                  <0xff3f0ae0 0x20>,
                  <0xff3f0740 0x20>,
                  <0xff3f0760 0x20>;
            reg-names = "local_request_region",
                    "local_response_region",
                    "remote_request_region",
                    "remote_response_region";
            #mbox-cells = <1>;
            xlnx,ipi-id = <3>;
        };
    };
};

The following descriptions refer to the "ZyncMP Libmetal AMP Demo" device tree overlay (.dtsi).

  • The <reg> property of the rproc_0_reserved node has the same memory region as the one selected in the lscript.ld in the Vitis application. This allows Xilinx Linux remoteproc driver to take our lm_amp CortexR5 binary (from /lib/firmware), parse its ELF headers and set up the segments in the DDR where the RPU can read and execute the text and access the shared data.

  • The <reg> property of shm0 node is included for Linux UIO to let user space demo to talk to our firmware application lm_amp on the RPU.

  • Cross-reference for Shared memory: the Linux device tree (system-user.dtsi), RPU linker script (lscript.ld), metal_dev_table from freertos/zynqmp_r5/zynqmp_amp_demo/sys_init.c

firmware ELF: text, data, etc. sections

shared memory

RPU

lscript.ld: ORIGIN = 0x3ED00000, LENGTH = 0x00080000

/* 0x80000 is excessive. Can be 0x40000 as in the DT */

SHM_BASE_ADDR 0x3ED80000

.size = 0x1000000    /* sys_init.c  metal_dev_table  */

APU kernel DT

rproc_0_reserved: reg = <0x0 0x3ed00000 0x0 0x40000>;

shm0:  reg = <0x0 0x3ed80000 0x0 0x1000000>;

APU app

/* not referenced via UIO */

SHM_DEV_NAME "3ed80000.shm"      /* common.h */

  • Cross-reference for the IPI. The ipi0 node for Linux UIO uses IPI Channel 7 with base address 0xFF34_0000, while the RPU uses its default IPI Channel-1 with BASE_ADDRESS 0xFF31_0000.

IPI Channel

Base Addr

IPI_MASK

References

Send IPI to Ch_7

Send IPI to Ch_1

RPU_0

Ch_1

0xFF31_0000

0x100_0000 (set bit 24)

IPI_MASK   0x1000000      in  common.h

APU

Ch_7

0xFF34_0000

0x100  (set bit 8)

-DCONFIG_IPI_MASK=0x100  in  CMakeLists.txt

  • The RPU code uses metal_dev_table from sys_init.c, common.h, CMakeLists.txt

RPU

IPI_BASE_ADDR=0xFF310000;             /* metal_dev_table, CMakeLists.txt */

APU kernel DT

reg = <0x0 0xff340000 0x0 0x1000>;        /*   ipi0  node */

APU app

IPI_DEV_NAME="ff340000.ipi"         /* common.h, CMakeLists.txt   */

  • Cross-reference for the TTCs, mapped via UIO for the Linux demo app

RPU

TTC0_BASE_ADDR=0xFF0E0000;      /* metal_dev_table, CMakeLists.txt */

APU kernel DT

&ttc0                             /* enable TTC0 via the reference to ttc0 node */

APU app

TTC_DEV_NAME="ff110000.timer"       /* common.h, CMakeLists.txt   */

Build the PetaLinux project and package the BOOT.bin for Versal

Code Block
      petalinux-build
      petalinux-package --boot --plm --psmfw --u-boot --dtb

For other architectures please see UG1144 PetaLinux Tools.

Changing the Defaults

LCM: TCM for RPU Firmware

Some OpenAMP demos are configured to have their text segment in the DDR memory. This allows larger firmware to run on RPU, but it might be slower compared to running from the TCM. According to Cortex-R5 Technical Reference Manual: “A ATCM typically holds interrupt or exception code that must be accessed at high speed, without any potential delay resulting from a cache miss.  A BTCM typically holds a block of data for intensive processing, such as audio or video processing.” Another reason to run from the TCM is power usage, i.e. if the APU decides  to suspend the DDR can be powered down or put into retention mode to save power.

The linker script controls the location of the ELF sections of the RPU firmware. For example, to run with .vectors, .text and .note.gnu.build-id  in psu_r5_atcm_MEM_0, and  with everything else in psu_r5_btcm_MEM_0, use the following linker script:

Expand
titleLinker script for TCM
Code Block
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x4000;

_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;

/* Define Memories in the system */

MEMORY
{
   psu_r5_atcm_MEM_0 : ORIGIN = 0x0, LENGTH = 0x10000
   psu_r5_btcm_MEM_0 : ORIGIN = 0x20000, LENGTH = 0x10000
   psu_r5_ddr_0_MEM_0 : ORIGIN = 0x3ed00000, LENGTH = 0x80000
}

/* Specify the default entry point to the program */

ENTRY(_boot)

/* Define the sections, and where they are mapped in memory */

SECTIONS
{
.vectors : {
   KEEP (*(.vectors))
   *(.boot)
} > psu_r5_atcm_MEM_0

.text : {
   *(.text)
   *(.text.*)
   *(.gnu.linkonce.t.*)
   *(.plt)
   *(.gnu_warning)
   *(.gcc_execpt_table)
   *(.glue_7)
   *(.glue_7t)
   *(.vfp11_veneer)
   *(.ARM.extab)
   *(.gnu.linkonce.armextab.*)
   *(.note.gnu.build-id)
} > psu_r5_atcm_MEM_0

.note.gnu.build-id : {
   KEEP (*(.note.gnu.build-id))
} > psu_r5_atcm_MEM_0

.init : {
   KEEP (*(.init))
} > psu_r5_btcm_MEM_0

.fini : {
   KEEP (*(.fini))
} > psu_r5_btcm_MEM_0

.interp : {
   KEEP (*(.interp))
} > psu_r5_btcm_MEM_0

.note-ABI-tag : {
   KEEP (*(.note-ABI-tag))
} > psu_r5_btcm_MEM_0

.rodata : {
   __rodata_start = .;
   *(.rodata)
   *(.rodata.*)
   *(.gnu.linkonce.r.*)
   __rodata_end = .;
} > psu_r5_btcm_MEM_0

.rodata1 : {
   __rodata1_start = .;
   *(.rodata1)
   *(.rodata1.*)
   __rodata1_end = .;
} > psu_r5_btcm_MEM_0

.sdata2 : {
   __sdata2_start = .;
   *(.sdata2)
   *(.sdata2.*)
   *(.gnu.linkonce.s2.*)
   __sdata2_end = .;
} > psu_r5_btcm_MEM_0

.sbss2 : {
   __sbss2_start = .;
   *(.sbss2)
   *(.sbss2.*)
   *(.gnu.linkonce.sb2.*)
   __sbss2_end = .;
} > psu_r5_btcm_MEM_0

.data : {
   __data_start = .;
   *(.data)
   *(.data.*)
   *(.gnu.linkonce.d.*)
   *(.jcr)
   *(.got)
   *(.got.plt)
   __data_end = .;
} > psu_r5_btcm_MEM_0

.data1 : {
   __data1_start = .;
   *(.data1)
   *(.data1.*)
   __data1_end = .;
} > psu_r5_btcm_MEM_0

.got : {
   *(.got)
} > psu_r5_btcm_MEM_0

.ctors : {
   __CTOR_LIST__ = .;
   ___CTORS_LIST___ = .;
   KEEP (*crtbegin.o(.ctors))
   KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
   KEEP (*(SORT(.ctors.*)))
   KEEP (*(.ctors))
   __CTOR_END__ = .;
   ___CTORS_END___ = .;
} > psu_r5_btcm_MEM_0

.dtors : {
   __DTOR_LIST__ = .;
   ___DTORS_LIST___ = .;
   KEEP (*crtbegin.o(.dtors))
   KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
   KEEP (*(SORT(.dtors.*)))
   KEEP (*(.dtors))
   __DTOR_END__ = .;
   ___DTORS_END___ = .;
} > psu_r5_btcm_MEM_0

.fixup : {
   __fixup_start = .;
   *(.fixup)
   __fixup_end = .;
} > psu_r5_btcm_MEM_0

.eh_frame : {
   *(.eh_frame)
} > psu_r5_btcm_MEM_0

.eh_framehdr : {
   __eh_framehdr_start = .;
   *(.eh_framehdr)
   __eh_framehdr_end = .;
} > psu_r5_btcm_MEM_0

.gcc_except_table : {
   *(.gcc_except_table)
} > psu_r5_btcm_MEM_0

.mmu_tbl (ALIGN(16384)) : {
   __mmu_tbl_start = .;
   *(.mmu_tbl)
   __mmu_tbl_end = .;
} > psu_r5_btcm_MEM_0

.ARM.exidx : {
   __exidx_start = .;
   *(.ARM.exidx*)
   *(.gnu.linkonce.armexidix.*.*)
   __exidx_end = .;
} > psu_r5_btcm_MEM_0

.preinit_array : {
   __preinit_array_start = .;
   KEEP (*(SORT(.preinit_array.*)))
   KEEP (*(.preinit_array))
   __preinit_array_end = .;
} > psu_r5_btcm_MEM_0

.init_array : {
   __init_array_start = .;
   KEEP (*(SORT(.init_array.*)))
   KEEP (*(.init_array))
   __init_array_end = .;
} > psu_r5_btcm_MEM_0

.fini_array : {
   __fini_array_start = .;
   KEEP (*(SORT(.fini_array.*)))
   KEEP (*(.fini_array))
   __fini_array_end = .;
} > psu_r5_btcm_MEM_0

.ARM.attributes : {
   __ARM.attributes_start = .;
   *(.ARM.attributes)
   __ARM.attributes_end = .;
} > psu_r5_btcm_MEM_0

.sdata : {
   __sdata_start = .;
   *(.sdata)
   *(.sdata.*)
   *(.gnu.linkonce.s.*)
   __sdata_end = .;
} > psu_r5_btcm_MEM_0

.sbss (NOLOAD) : {
   __sbss_start = .;
   *(.sbss)
   *(.sbss.*)
   *(.gnu.linkonce.sb.*)
   __sbss_end = .;
} > psu_r5_btcm_MEM_0

.tdata : {
   __tdata_start = .;
   *(.tdata)
   *(.tdata.*)
   *(.gnu.linkonce.td.*)
   __tdata_end = .;
} > psu_r5_btcm_MEM_0

.tbss : {
   __tbss_start = .;
   *(.tbss)
   *(.tbss.*)
   *(.gnu.linkonce.tb.*)
   __tbss_end = .;
} > psu_r5_btcm_MEM_0

.bss (NOLOAD) : {
   . = ALIGN(4);
   __bss_start__ = .;
   *(.bss)
   *(.bss.*)
   *(.gnu.linkonce.b.*)
   *(COMMON)
   . = ALIGN(4);
   __bss_end__ = .;
} > psu_r5_btcm_MEM_0

_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );

_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );

/* Generate Stack and Heap definitions */

.heap (NOLOAD) : {
   . = ALIGN(16);
   _heap = .;
   HeapBase = .;
   _heap_start = .;
   . += _HEAP_SIZE;
   _heap_end = .;
   HeapLimit = .;
} > psu_r5_btcm_MEM_0

.stack (NOLOAD) : {
   . = ALIGN(16);
   _stack_end = .;
   . += _STACK_SIZE;
   _stack = .;
   __stack = _stack;
   . = ALIGN(16);
   _irq_stack_end = .;
   . += _IRQ_STACK_SIZE;
   __irq_stack = .;
   _supervisor_stack_end = .;
   . += _SUPERVISOR_STACK_SIZE;
   . = ALIGN(16);
   __supervisor_stack = .;
   _abort_stack_end = .;
   . += _ABORT_STACK_SIZE;
   . = ALIGN(16);
   __abort_stack = .;
   _fiq_stack_end = .;
   . += _FIQ_STACK_SIZE;
   . = ALIGN(16);
   __fiq_stack = .;
   _undef_stack_end = .;
   . += _UNDEF_STACK_SIZE;
   . = ALIGN(16);
   __undef_stack = .;
} > psu_r5_btcm_MEM_0

_end = .;
}

IPC: Shared Memory

Shared memory parameter changes need to be coordinated between the RPU firmware code and the APU's Linux device tree as shown in this table:


Default

Change to

RPU      SHARED_MEM_PA

0x3ED40000

0x3EF40000

RPU      SHARED_MEM_SIZE

0x100000

no change

RPU      SHARED_BUF_OFFSET

0x8000

no change

Linux DT:   rpu0vdev0vring0

reg = <0x0 0x3ed40000 0x0 0x4000>;

reg = <0x0 0x3ef40000 0x0 0x4000>;

Linux DT:   rpu0vdev0vring1

reg = <0x0 0x3ed44000 0x0 0x4000>;

reg = <0x0 0x3ef44000 0x0 0x4000>;

Linux DT:   rpu0vdev0buffer

reg = <0x0 0x3ed48000 0x0 0x100000>;

reg = <0x0 0x3ef40000 0x0 0x100000>;

IPC: IPI Channels

Selecting a different IPI channel also requires coordinating changes in the RPU firmware and the APU's Linux device tree:

Versal

Default IPI1

Change to IPI2

RPU     IPI_BASE_ADDR

0xFF340000

0xFF350000

RPU  IPI_CHN_BITMASK

0x00000020

0x00000040

RPU    IPI_IRQ_VECT_ID

63

64

Linux DT:    xlnx,ipi-id

3

4

Please, see the IPI Interrupt Channel Architecture:

Additional Information

Timers for the Libmetal AMP Demo

The timers are used in the "libmetal AMP demo" and are not needed for any of the OpenAMP demos. ZynqMP and Versal have four Triple Timer Counters (TTC[0-3]). The code in the demo uses TTC0 by default. However any of the four TTCs can be used.

Triple Timer Counter

ZynqMP

Versal

TTC0_BASE_ADDR

0xFF11_0000

0xFF0E_0000

TTC_DEV_NAME

ff110000.timer

ff0e0000.ttc0

For example, what code changes are needed to use a different TTC  in zynqmp_amp_demo? Find  the base address of TTC1 in ug1085 zu+ TRM (it's 0xFF12_0000). Unfortunately,  some some values for TTC0 are hard coded and not easy to changerequire source code changes.

Zynq-7000

Zynq-7000 has two Arm Cortex-A9 MPCore CPUs. Our demos use one core A9_0 to run Linux master and A9_1 to run a baremetal or FreeRTOS remote firmware.

Shared Memory

There are both on-chip memory (OCM) and external memory interfaces (DDR). The demos use the DDR as a default shared memory location.

Zynq

SHARED_MEM_PA

0x3e800000

SHARED_MEM_SIZE

0x80000

SHARED_BUF_OFFSET

0x80000

Interrupts

Generic Interrupt Controller (PL390)

Zynq

 SCUGIC_PERIPH_BASE

0x3e800000

SGI_TO_NOTIFY

15

SGI_NOTIFICATION

14