From 3a4fa283ec08558d3c2cd283a2d828f745e0c188 Mon Sep 17 00:00:00 2001 From: Ben Levinsky Date: Thu, 1 Oct 2020 14:48:10 -0700 Subject: [PATCH] Add support for MicroBlaze in programmable logic (PL) to OpenAMP. Add an example of a baremetal echo server running on a MicroBlaze in PL on a ZynqMP board and using RPMSG (with NO_IPI) to reply to a Linux user space app running in the PS APU. Signed-off-by: Ben Levinsky Signed-off-by: Sergei Korneichuk Signed-off-by: Ed Mooring --- README.md | 1 + apps/examples/CMakeLists.txt | 4 + .../machine/microblaze_generic/CMakeLists.txt | 4 + apps/machine/microblaze_generic/README.md | 154 +++++++++++++ .../microblaze_generic/platform_info.c | 209 +++++++++++++++++ .../microblaze_generic/platform_info.h | 97 ++++++++ apps/machine/microblaze_generic/rsc_table.c | 59 +++++ apps/machine/microblaze_generic/rsc_table.h | 43 ++++ .../microblaze_generic/zynqmp_mb_a53_rproc.c | 118 ++++++++++ .../machine/microblaze_generic/CMakeLists.txt | 19 ++ .../machine/microblaze_generic/helper.c | 39 ++++ .../microblaze_generic/linker_remote.ld | 218 ++++++++++++++++++ apps/tests/CMakeLists.txt | 4 + 13 files changed, 969 insertions(+) create mode 100644 apps/machine/microblaze_generic/CMakeLists.txt create mode 100644 apps/machine/microblaze_generic/README.md create mode 100644 apps/machine/microblaze_generic/platform_info.c create mode 100644 apps/machine/microblaze_generic/platform_info.h create mode 100644 apps/machine/microblaze_generic/rsc_table.c create mode 100644 apps/machine/microblaze_generic/rsc_table.h create mode 100644 apps/machine/microblaze_generic/zynqmp_mb_a53_rproc.c create mode 100644 apps/system/generic/machine/microblaze_generic/CMakeLists.txt create mode 100644 apps/system/generic/machine/microblaze_generic/helper.c create mode 100644 apps/system/generic/machine/microblaze_generic/linker_remote.ld diff --git a/README.md b/README.md index 90b5851..7a812d9 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,7 @@ For now, it supports: * Linux host OpenAMP between Linux userspace processes * Linux userspace OpenAMP RPMsg master * Linux userspace OpenAMP RPMsg slave +* Linux userspace OpenAMP RPMsg and MicroBlaze bare metal remote ## Known Limitations: 1. In case of OpenAMP on Linux userspace for inter processors communication, diff --git a/apps/examples/CMakeLists.txt b/apps/examples/CMakeLists.txt index 319f01e..0b89a17 100644 --- a/apps/examples/CMakeLists.txt +++ b/apps/examples/CMakeLists.txt @@ -1,6 +1,9 @@ option (WITH_LOAD_FW "Include loading firmware example" OFF) +if (MACHINE MATCHES ".*microblaze.*") +add_subdirectory (echo) +else () add_subdirectory (echo) add_subdirectory (rpmsg_sample_echo) add_subdirectory (matrix_multiply) @@ -10,3 +13,4 @@ endif (WITH_LOAD_FW) if (WITH_PROXY_APPS) add_subdirectory (rpc_demo) endif (WITH_PROXY_APPS) +endif (MACHINE MATCHES ".*microblaze.*") diff --git a/apps/machine/microblaze_generic/CMakeLists.txt b/apps/machine/microblaze_generic/CMakeLists.txt new file mode 100644 index 0000000..5be3100 --- /dev/null +++ b/apps/machine/microblaze_generic/CMakeLists.txt @@ -0,0 +1,4 @@ +collect (APP_COMMON_SOURCES platform_info.c) +collect (APP_COMMON_SOURCES rsc_table.c) +collect (APP_COMMON_SOURCES zynqmp_mb_a53_rproc.c) +collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/apps/machine/microblaze_generic/README.md b/apps/machine/microblaze_generic/README.md new file mode 100644 index 0000000..c384e6e --- /dev/null +++ b/apps/machine/microblaze_generic/README.md @@ -0,0 +1,154 @@ +# OpenAMP MicroBlaze example + +The microblaze_generic directories in OpenAMP repository provide an +implementation of rpmsg for Xilinx MicroBlaze design +example. The design instantiates Xilinx MicroBlaze soft processor in +ZynqMP's programmable logic (PL) and uses the processing system (PS) +DDR memory for its text and data. The HP0_DDR_LOW is mapped from 0 to +0x7FFFFFFF. The Local Memory Bus (LMB) is not connected and the LMB +memory is not present. The MicroBlaze Vector Base Address is set to +0x70000000 and its reset_mode (01) will force it to enter sleep mode +without performing any bus access. The design is available in the Xilinx +Shell Archive (XSA) format at https://xilinx-wiki.atlassian.net + +## How to build OpenAMP echo server for the MicroBlaze design example. +For simplicity the example is not using Inter-Processor Interrupt (IPI) +hardware at this time and the MicroBlaze OpenAMP echo server is built +with RPMSG_NO_IPI flag. + +* build the libmetal library on your host as follows: + * Create your own cmake toolchain file to compile libmetal for your generic + (baremetal) platform. Here is an example toolchain file: + + ``` + set (BSP "/path/to/your_MicroBlaze_design_BSP/dir" CACHE STRING "") + set (CMAKE_SYSTEM_PROCESSOR "microblaze" CACHE STRING "") + set (MACHINE "microblaze_generic" CACHE STRING "") + set (CROSS_PREFIX "microblaze-xilinx-elf-" CACHE STRING "") + set (CMAKE_C_FLAGS "-g -mlittle-endian -mxl-soft-mul -Wall -Werror \ + "-Wextra -flto -Os -I${BSP}/include" CACHE STRING "") + link_directories( ${BSP}/lib ) + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") + SET(CMAKE_AR "gcc-ar" CACHE STRING "") + SET(CMAKE_C_ARCHIVE_CREATE " qcs ") + SET(CMAKE_C_ARCHIVE_FINISH true) + include (cross-generic-gcc) + ``` + + * Compile the libmetal library: + + ``` + $ mkdir -p build-libmetal + $ cd build-libmetal + $ BSP="/path/to/your_MicroBlaze_design_BSP/dir" + $ cmake -DCMAKE_TOOLCHAIN_FILE= \ + -DCMAKE_LIBRARY_PATH=$BSP/lib + $ make VERBOSE=1 DESTDIR= install + ``` + +* build the OpenAMP library on your host as follows: + * Create your own cmake toolchain file to compile openamp for your generic + (baremetal) platform. Here is an example toolchain file: + ``` + set (BSP "/path/to/your_MicroBlaze_design_BSP/dir" CACHE STRING "") + set (CMAKE_SYSTEM_PROCESSOR "microblaze" CACHE STRING "") + set (MACHINE "microblaze_generic" CACHE STRING "") + set (CROSS_PREFIX "microblaze-xilinx-elf-" CACHE STRING "") + set (CMAKE_C_FLAGS "-g -mlittle-endian -Wall -Wextra -flto -Os \ + -DUNDEFINE_FILE_OPS -DRPMSG_NO_IPI -I${LIBMETAL}/include \ + -I${BSP}/include" CACHE STRING "") + + set (PLATFORM_LIB_DEPS "-lxil -lc -lm -lmetal " CACHE STRING "") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") + SET(CMAKE_AR "gcc-ar" CACHE STRING "") + SET(CMAKE_C_ARCHIVE_CREATE " qcs ") + SET(CMAKE_C_ARCHIVE_FINISH true) + link_directories(${LIBMETAL}/include/ ${LIBMETAL}/lib/) + set (CMAKE_FIND_ROOT_PATH ${LIBMETAL}/lib ${BSP}/lib ) + include (cross-generic-gcc) + ``` + + * We use cmake `find_path` and `find_library` to check if libmetal headers + and library are in the includes and library search paths. However, + for non-linux system, it doesn't work with `CMAKE_INCLUDE_PATH` and + `CMAKE_LIBRARY_PATH` variables, and thus, we need to specify those paths + in the toolchain file with `CMAKE_C_FLAGS` and `CMAKE_FIND_ROOT_PATH`. + +* Compile the OpenAMP library: + + ``` + $ mkdir -p build-openamp + $ cd build-openamp + $ BSP="/path/to/your_MicroBlaze_design_BSP/dir" + + $ cmake -DCMAKE_TOOLCHAIN_FILE= \ + -DCMAKE_INCLUDE_PATH="$LIBMETAL/include;$BSP/include" \ + -DCMAKE_LIBRARY_PATH="$LIBMETAL/lib/;BSP/lib" -DWITH_APPS=on + $ make VERBOSE=1 DESTDIR=$(pwd) install + ``` + +The OpenAMP library will be built in `build/usr/local/lib` directory, +headers will be built in `build/usr/local/include` directory, and the +application executable will be built in `build/usr/local/bin` directory. + +## How to build OpenAMP Linux Userspace echo Client for ZynqMP MPSoC + +To test the MicroBlaze echo server we use an rpmsg-echo-ping client from +Linux running on the Application Processing Unit (APU) in PS. To run both +the echo server on the MicroBlaze in PL from PS DDR and a Linux echo +client on APU in PS the kernel device tree needs reserved-memory nodes +for the MicroBlaze text and data including vrings. A Yocto overlay +device tree example: openamp-linux-u-MicroBlaze.dtsi + +Build the OpenAMP Linux userspace library and application via Yocto. +The open-amp and libmetal recipes are in this Yocto layer: + https://github.com/OpenAMP/meta-openamp + +* Add the `meta-openamp` layer to your layers in your Yocto build project's + `bblayers.conf` file. +* Add `libmetal` and `open-amp` to your packages list. E.g. add `libmetal` + and `open-amp` to the `IMAGE_INSTALL_append` in the `local.conf` file. +* You can also add OpenAMP demos Linux applications packages to your Yocto + packages list. OpenAMP demo examples recipes are also in `meta-openamp`: + https://github.com/OpenAMP/meta-openamp/tree/master/recipes-openamp/openamp-examples + +## Sample Microblaze DTSI + + + / { + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + rproc_0_reserved: rproc@3ed000000 { + no-map; + reg = <0x0 0x3ed00000 0x0 0x1000000>; + }; + microblaze_text_data: microblaze:@70000000 { + no-map; + reg = <0x0 0x70000000 0x0 0x80000>; + }; + }; + + amba { + vring: vring@0 { + compatible = "vring_uio"; + reg = <0x0 0x3ed40000 0x0 0x40000>; + }; + shm0: shm@0 { + compatible = "shm_uio"; + reg = <0x0 0x3ed20000 0x0 0x0100000>; + }; + shm1: shm@1 { + compatible = "shm_uio"; + reg = <0x0 0x3ee40000 0x0 0x0100000>; + }; + ipi0: ipi@0 { + compatible = "ipi_uio"; + reg = <0x0 0xff340000 0x0 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 29 4>; + }; + }; + }; + diff --git a/apps/machine/microblaze_generic/platform_info.c b/apps/machine/microblaze_generic/platform_info.c new file mode 100644 index 0000000..7d9ce0e --- /dev/null +++ b/apps/machine/microblaze_generic/platform_info.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2020 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/************************************************************************** + * FILE NAME + * + * platform_info.c + * + * DESCRIPTION + * + * This file define platform specific data and implements APIs to set + * platform specific information for OpenAMP. + * + **************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "platform_info.h" +#include "rsc_table.h" + +#define SHARED_MEM_PA 0x3ED40000UL +#define SHARED_MEM_SIZE 0x100000UL +#define SHARED_BUF_OFFSET 0x8000UL + +/* + * IPI information used by remoteproc operations. + */ +static struct remoteproc_priv rproc_priv = { +}; + +static struct remoteproc rproc_inst; + +/* External functions */ +extern int init_system(void); +extern void cleanup_system(void); + +/* + * processor operations from MicroBlaze to a53. It defines + * notification operation and remote processor management operations. + */ +extern struct remoteproc_ops zynqmp_mb_a53_proc_ops; + +/* RPMsg virtio shared buffer pool */ +static struct rpmsg_virtio_shm_pool shpool; + +static struct remoteproc *platform_create_proc(int proc_index, int rsc_index) +{ + void *rsc_table; + int rsc_size; + int ret; + metal_phys_addr_t pa; + + (void)proc_index; + rsc_table = get_resource_table(rsc_index, &rsc_size); + + /* Initialize remoteproc instance */ + if (!remoteproc_init(&rproc_inst, &zynqmp_mb_a53_proc_ops, &rproc_priv)) + return NULL; + + /* mmap resource table */ + pa = (metal_phys_addr_t)rsc_table; + (void *)remoteproc_mmap(&rproc_inst, &pa, + NULL, rsc_size, + NORM_NSHARED_NCACHE | PRIV_RW_USER_RW, + &rproc_inst.rsc_io); + /* mmap shared memory */ + pa = SHARED_MEM_PA; + (void *)remoteproc_mmap(&rproc_inst, &pa, + NULL, SHARED_MEM_SIZE, + NORM_NSHARED_NCACHE | PRIV_RW_USER_RW, + NULL); + + /* parse resource table to remoteproc */ + ret = remoteproc_set_rsc_table(&rproc_inst, rsc_table, rsc_size); + if (ret) { + xil_printf("Failed to initialize remoteproc\r\n"); + remoteproc_remove(&rproc_inst); + return NULL; + } + /* dbg("%d:%s rsc_table= %p\r\n", __LINE__, __func__, rsc_table); */ + xil_printf("Initialize remoteproc successfully.\r\n"); + + return &rproc_inst; +} + +int platform_init(int argc, char *argv[], void **platform) +{ + unsigned long proc_id = 0; + unsigned long rsc_id = 0; + struct remoteproc *rproc; + + if (!platform) { + xil_printf("Failed to initialize platform," + "NULL pointer to store platform data.\r\n"); + return -EINVAL; + } + /* Initialize HW system components */ + init_system(); + + if (argc >= 2) { + proc_id = strtoul(argv[1], NULL, 0); + } + + if (argc >= 3) { + rsc_id = strtoul(argv[2], NULL, 0); + } + + rproc = platform_create_proc(proc_id, rsc_id); + if (!rproc) { + xil_printf("Failed to create remoteproc device.\r\n"); + return -EINVAL; + } + *platform = rproc; + return 0; +} + +struct rpmsg_device * +platform_create_rpmsg_vdev(void *platform, unsigned int vdev_index, + unsigned int role, + void (*rst_cb)(struct virtio_device *vdev), + rpmsg_ns_bind_cb ns_bind_cb) +{ + struct remoteproc *rproc = platform; + struct rpmsg_virtio_device *rpmsg_vdev; + struct virtio_device *vdev; + void *shbuf; + struct metal_io_region *shbuf_io; + int ret; + + rpmsg_vdev = metal_allocate_memory(sizeof(*rpmsg_vdev)); + if (!rpmsg_vdev) + return NULL; + shbuf_io = remoteproc_get_io_with_pa(rproc, SHARED_MEM_PA); + if (!shbuf_io) + goto err1; + shbuf = metal_io_phys_to_virt(shbuf_io, + SHARED_MEM_PA + SHARED_BUF_OFFSET); + + xil_printf("creating remoteproc virtio\r\n"); + /* TODO: can we have a wrapper for the following two functions? */ + vdev = remoteproc_create_virtio(rproc, vdev_index, role, rst_cb); + if (!vdev) { + xil_printf("failed remoteproc_create_virtio\r\n"); + goto err1; + } + + xil_printf("initializing rpmsg shared buffer pool\r\n"); + /* + * Only RPMsg virtio master needs to initialize the shared buffers + * pool + */ + rpmsg_virtio_init_shm_pool(&shpool, shbuf, + (SHARED_MEM_SIZE - SHARED_BUF_OFFSET)); + + xil_printf("initializing rpmsg vdev\r\n"); + /* RPMsg virtio slave can set shared buffers pool argument to NULL */ + ret = rpmsg_init_vdev(rpmsg_vdev, vdev, ns_bind_cb, + shbuf_io, + &shpool); + if (ret) { + xil_printf("failed rpmsg_init_vdev\r\n"); + goto err2; + } + xil_printf("initializing rpmsg vdev\r\n"); + return rpmsg_virtio_get_rpmsg_device(rpmsg_vdev); +err2: + remoteproc_remove_virtio(rproc, vdev); +err1: + metal_free_memory(rpmsg_vdev); + return NULL; +} + +int platform_poll(void *priv) +{ + struct remoteproc *rproc = priv; + + while (1) { + char *done_polling = (char *)POLL_SHM_LOCATION; + + if (*done_polling) { + remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY); + break; + } + + } + return 0; +} + +void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev) +{ + if (rpdev-> + (void)rpdev; +} + +void platform_cleanup(void *platform) +{ + struct remoteproc *rproc = platform; + + if (rproc) + remoteproc_remove(rproc); + cleanup_system(); +} diff --git a/apps/machine/microblaze_generic/platform_info.h b/apps/machine/microblaze_generic/platform_info.h new file mode 100644 index 0000000..ba11702 --- /dev/null +++ b/apps/machine/microblaze_generic/platform_info.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef PLATFORM_INFO_H_ +#define PLATFORM_INFO_H_ + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* MicroBlaze memory attributes. Depends on MB memory the design */ +#define DEVICE_SHARED 0x00000001U /* device, shareable */ +#define DEVICE_NONSHARED 0x00000010U /* device, non shareable */ +#define NORM_NSHARED_NCACHE 0x00000008U /* Non cacheable non shareable */ +#define NORM_SHARED_NCACHE 0x0000000CU /* Non cacheable shareable */ +#define PRIV_RW_USER_RW (0x00000003U << 8U) /* Full Access */ + +#define POLL_SHM_LOCATION 0x3EE40000 +#define POLL_STOP 0x1U + +struct remoteproc_priv { + const char *ipi_name; /**< IPI device name */ + const char *ipi_bus_name; /**< IPI bus name */ + struct metal_device *ipi_dev; /**< pointer to IPI device */ + struct metal_io_region *ipi_io; /**< pointer to IPI i/o region */ + unsigned int ipi_chn_mask; /**< IPI channel mask */ + atomic_int ipi_nokick; +}; + +/** + * platform_init - initialize the platform + * + * Initialize the platform. + * + * @argc: number of arguments + * @argv: array of the input arguments + * @platform: pointer to store the platform data pointer + * + * return 0 for success or negative value for failure + */ +int platform_init(int argc, char *argv[], void **platform); + +/** + * platform_create_rpmsg_vdev - create rpmsg vdev + * + * Create rpmsg virtio device, and return the rpmsg virtio + * device pointer. + * + * @platform: pointer to the private data + * @vdev_index: index of the virtio device, there can more than one vdev + * on the platform. + * @role: virtio master or virtio slave of the vdev + * @rst_cb: virtio device reset callback + * @ns_bind_cb: rpmsg name service bind callback + * + * return pointer to the rpmsg virtio device + */ +struct rpmsg_device * +platform_create_rpmsg_vdev(void *platform, unsigned int vdev_index, + unsigned int role, + void (*rst_cb)(struct virtio_device *vdev), + rpmsg_ns_bind_cb ns_bind_cb); + +/** + * platform_poll - platform poll function + * + * @platform: pointer to the platform + * + * return negative value for errors, otherwise 0. + */ +int platform_poll(void *platform); + +/** + * platform_release_rpmsg_vdev - release rpmsg virtio device + * + * @rpdev: pointer to the rpmsg device + */ +void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev); + +/** + * platform_cleanup - clean up the platform resource + * + * @platform: pointer to the platform + */ +void platform_cleanup(void *platform); + +#if defined __cplusplus +} +#endif + +#endif /* PLATFORM_INFO_H_ */ diff --git a/apps/machine/microblaze_generic/rsc_table.c b/apps/machine/microblaze_generic/rsc_table.c new file mode 100644 index 0000000..a938ea6 --- /dev/null +++ b/apps/machine/microblaze_generic/rsc_table.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* This file populates resource table for BM remote + * for use by the Linux Master + */ + +#include +#include "rsc_table.h" + +/* Place resource table in special ELF section */ +#define __section_t(S) __attribute__((__section__(#S))) +#define __resource __section_t(.resource_table) + +#define RPMSG_IPU_C0_FEATURES 1 + +#define NUM_VRINGS 0x02 +#define VRING_ALIGN 0x1000 +#define RING_TX 0x3ed40000 +#define RING_RX 0x3ed44000 +#define VRING_SIZE 256 + +#define NUM_TABLE_ENTRIES 1 + +struct remote_resource_table __resource resources = { + /* Version */ + 1, + + /* NUmber of table entries */ + NUM_TABLE_ENTRIES, + /* reserved fields */ + {0, 0,}, + + /* Offsets of rsc entries */ + { + offsetof(struct remote_resource_table, rpmsg_vdev), + }, + + /* Virtio device entry */ + { + RSC_VDEV, VIRTIO_ID_RPMSG, 0, RPMSG_IPU_C0_FEATURES, 0, 0, 0, + NUM_VRINGS, {0, 0}, + }, + + /* Vring rsc entry - part of vdev rsc entry */ + {RING_TX, VRING_ALIGN, VRING_SIZE, 1, 0}, + {RING_RX, VRING_ALIGN, VRING_SIZE, 2, 0}, +}; + +void *get_resource_table(int rsc_id, int *len) +{ + (void)rsc_id; + *len = sizeof(resources); + return &resources; +} + diff --git a/apps/machine/microblaze_generic/rsc_table.h b/apps/machine/microblaze_generic/rsc_table.h new file mode 100644 index 0000000..c018588 --- /dev/null +++ b/apps/machine/microblaze_generic/rsc_table.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Resource table declarations. Resource table is placed in a separate + * section of a bare-metal binary or firmware. It's used to describe + * shared memory (virtIO devices) resources the remoteproc master should + * initialize and / or use to communicate with the firmware. + */ +#ifndef RSC_TABLE_H_ +#define RSC_TABLE_H_ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#define NO_RESOURCE_ENTRIES 8 + +/* Resource table for the given remote */ +struct __packed remote_resource_table { + unsigned int version; + unsigned int num; + unsigned int reserved[2]; + unsigned int offset[NO_RESOURCE_ENTRIES]; + /* rpmsg vdev entry */ + struct fw_rsc_vdev rpmsg_vdev; + struct fw_rsc_vdev_vring rpmsg_vring0; + struct fw_rsc_vdev_vring rpmsg_vring1; +}; + +void *get_resource_table(int rsc_id, int *len); + +#if defined __cplusplus +} +#endif + +#endif /* RSC_TABLE_H_ */ diff --git a/apps/machine/microblaze_generic/zynqmp_mb_a53_rproc.c b/apps/machine/microblaze_generic/zynqmp_mb_a53_rproc.c new file mode 100644 index 0000000..bccb7c4 --- /dev/null +++ b/apps/machine/microblaze_generic/zynqmp_mb_a53_rproc.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2020 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/************************************************************************** + * FILE NAME + * + * zynqmp_mb_a53_rproc.c + * + * DESCRIPTION + * + * OpenAMP remoteproc implementation for Xilinx MicroBlaze design + * example. The design instanciates Xilinx MicroBlaze soft proccesor + * in ZynqMP's programmable logic and uses processing system (PS) + * DDR memory for its text and data. The APU in PS runs Linux with + * reserved-memory nodes in its device tree toaccommodat the + * MicroBlaze text, data. + * + **************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "platform_info.h" + +static struct remoteproc * +zynqmp_mb_a53_proc_init(struct remoteproc *rproc, struct remoteproc_ops *ops, + void *arg) +{ + struct remoteproc_priv *prproc = arg; + + if (!rproc || !prproc || !ops) + return NULL; + rproc->priv = prproc; + rproc->ops = ops; + return rproc; +} + +static inline void zynqmp_mb_a53_proc_remove(struct remoteproc *rproc) +{ + (void)rproc; +} + +static void * +zynqmp_mb_a53_proc_mmap(struct remoteproc *rproc, metal_phys_addr_t *pa, + metal_phys_addr_t *da, size_t size, + unsigned int attribute, struct metal_io_region **io) +{ + struct remoteproc_mem *mem; + metal_phys_addr_t lpa, lda; + struct metal_io_region *tmpio; + + lpa = *pa; + lda = *da; + + if (lpa == METAL_BAD_PHYS && lda == METAL_BAD_PHYS) + return NULL; + if (lpa == METAL_BAD_PHYS) + lpa = lda; + if (lda == METAL_BAD_PHYS) + lda = lpa; + + mem = metal_allocate_memory(sizeof(*mem)); + if (!mem) + return NULL; + tmpio = metal_allocate_memory(sizeof(*tmpio)); + if (!tmpio) { + metal_free_memory(mem); + return NULL; + } + remoteproc_init_mem(mem, NULL, lpa, lda, size, tmpio); + /* va is the same as pa in this platform */ + metal_io_init(tmpio, (void *)lpa, &mem->pa, size, + sizeof(metal_phys_addr_t) << 3, attribute, NULL); + remoteproc_add_mem(rproc, mem); + *pa = lpa; + *da = lda; + if (io) { + *io = tmpio; + } else { + metal_free_memory(tmpio); + metal_free_memory(mem); + return NULL; + } + + return metal_io_phys_to_virt(tmpio, mem->pa); +} + +static int zynqmp_mb_a53_proc_notify(struct remoteproc *rproc, uint32_t id) +{ + (void)rproc; + (void)id; + if (!rproc) + return -1; + + char *notify = (char *)POLL_SHM_LOCATION; + *notify = POLL_STOP; + return 0; +} + +/* + * processor operations from mb to a53. It defines + * notification operation and remote processor management operations. + */ +struct remoteproc_ops zynqmp_mb_a53_proc_ops = { + .init = zynqmp_mb_a53_proc_init, + .remove = zynqmp_mb_a53_proc_remove, + .mmap = zynqmp_mb_a53_proc_mmap, + .notify = zynqmp_mb_a53_proc_notify, + .start = NULL, + .stop = NULL, + .shutdown = NULL, +}; diff --git a/apps/system/generic/machine/microblaze_generic/CMakeLists.txt b/apps/system/generic/machine/microblaze_generic/CMakeLists.txt new file mode 100644 index 0000000..79da366 --- /dev/null +++ b/apps/system/generic/machine/microblaze_generic/CMakeLists.txt @@ -0,0 +1,19 @@ +include(CheckSymbolExists) + +collect (APP_COMMON_SOURCES helper.c) + +set (_linker_script "${CMAKE_CURRENT_SOURCE_DIR}/linker_remote.ld") +set_property (GLOBAL PROPERTY APP_LINKER_OPT "-T\"${_linker_script}\"") + +find_path(XIL_INCLUDE_DIR NAMES xparameters.h PATHS ${CMAKE_FIND_ROOT_PATH}) +collect (PROJECT_INC_DIRS "${XIL_INCLUDE_DIR}") + +find_library(LIBXIL_LIB NAMES xil PATHS ${CMAKE_FIND_ROOT_PATH}) +get_filename_component(LIBXIL_LIB_DIR ${LIBXIL_LIB} DIRECTORY) +collect(PROJECT_LIB_DIRS ${LIBXIL_LIB_DIR}) + + +collect(PROJECT_LIB_DEPS xil) +collect(PROJECT_LIB_DEPS c) +collect(PROJECT_LIB_DEPS m) + diff --git a/apps/system/generic/machine/microblaze_generic/helper.c b/apps/system/generic/machine/microblaze_generic/helper.c new file mode 100644 index 0000000..710d7e0 --- /dev/null +++ b/apps/system/generic/machine/microblaze_generic/helper.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Xilinx, Inc. All rights reserved. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "xparameters.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include +#include "platform_info.h" + +static void system_metal_logger(enum metal_log_level level, + const char *format, ...) +{ + (void)level; + (void)format; +} + +/* Main hw machinery initialization entry point, called from main()*/ +/* return 0 on success */ +int init_system(void) +{ + int ret; + struct metal_init_params metal_param = { + .log_handler = system_metal_logger, + .log_level = METAL_LOG_INFO, + }; + + /* Low level abstraction layer for openamp initialization */ + ret = metal_init(&metal_param); + return ret; +} + +void cleanup_system(void) +{ + metal_finish(); +} diff --git a/apps/system/generic/machine/microblaze_generic/linker_remote.ld b/apps/system/generic/machine/microblaze_generic/linker_remote.ld new file mode 100644 index 0000000..39dad2a --- /dev/null +++ b/apps/system/generic/machine/microblaze_generic/linker_remote.ld @@ -0,0 +1,218 @@ +/*******************************************************************/ +/* */ +/* This file is automatically generated by linker script generator.*/ +/* */ +/* Version: 2020.1.0 */ +/* */ +/* Copyright (c) 2010-2020 Xilinx, Inc. All rights reserved. */ +/* */ +/* Description : MicroBlaze Linker Script */ +/* */ +/*******************************************************************/ + +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x400; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x1800; + +/* Define Memories in the system */ + +MEMORY +{ + psu_ddr_0_HP0_AXI_BASENAME_MEM_0 : ORIGIN = 0x70000050, LENGTH = 0x7FEFFFB0 + rsc_table_psu_ddr_S_AXI_BASEADDR : ORIGIN = 0x3ED00000, LENGTH = 0x00040000 +} + +/* Specify the default entry point to the program */ + +ENTRY(_start) + +/* Define the sections, and where they are mapped in memory */ + +SECTIONS +{ +.vectors.reset 0x70000000 : { + KEEP (*(.vectors.reset)) +} + +.vectors.sw_exception 0x70000008 : { + KEEP (*(.vectors.sw_exception)) +} + +.vectors.interrupt 0x70000010 : { + KEEP (*(.vectors.interrupt)) +} + +.vectors.hw_exception 0x70000020 : { + KEEP (*(.vectors.hw_exception)) +} + +.text : { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.init : { + KEEP (*(.init)) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.fini : { + KEEP (*(.fini)) +} > psu_ddr_0_HP0_AXI_BASENAME_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_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + PROVIDE(__DTOR_END__ = .); + PROVIDE(___DTORS_END___ = .); +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.sdata2 : { + . = ALIGN(8); + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + . = ALIGN(8); + __sdata2_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.data : { + . = ALIGN(4); + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + __data_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.got : { + *(.got) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.got1 : { + *(.got1) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.got2 : { + *(.got2) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.eh_frame : { + *(.eh_frame) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.jcr : { + *(.jcr) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.gcc_except_table : { + *(.gcc_except_table) +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.sdata : { + . = ALIGN(8); + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.sbss (NOLOAD) : { + . = ALIGN(4); + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + . = ALIGN(8); + __sbss_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.bss (NOLOAD) : { + . = ALIGN(4); + __bss_start = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_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(8); + _heap = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +.stack (NOLOAD) : { + _stack_end = .; + . += _STACK_SIZE; + . = ALIGN(8); + _stack = .; + __stack = _stack; +} > psu_ddr_0_HP0_AXI_BASENAME_MEM_0 + +/* Linux must have reserved-memory node for this resource_table */ +.resource_table 0x3ed20000 : { + . = ALIGN(4); + *(.resource_table) +} > rsc_table_psu_ddr_S_AXI_BASEADDR + +_end = .; +} diff --git a/apps/tests/CMakeLists.txt b/apps/tests/CMakeLists.txt index eac5840..0475b49 100644 --- a/apps/tests/CMakeLists.txt +++ b/apps/tests/CMakeLists.txt @@ -1,2 +1,6 @@ +# tests presently do not support microblaze +if (MACHINE MATCHES ".*microblaze.*") + return() +endif (MACHINE MATCHES ".*microblaze.*") add_subdirectory (msg)