mirror of
https://github.com/OpenAMP/open-amp.git
synced 2026-02-06 11:13:09 +08:00
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 <ben.levinsky@xilinx.com> Signed-off-by: Sergei Korneichuk <sergei.korneichuk@xilinx.com> Signed-off-by: Ed Mooring <ed.mooring@xilinx.com>
This commit is contained in:
committed by
Arnaud Pouliquen
parent
0b696708c0
commit
3a4fa283ec
@@ -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,
|
||||
|
||||
@@ -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.*")
|
||||
|
||||
4
apps/machine/microblaze_generic/CMakeLists.txt
Normal file
4
apps/machine/microblaze_generic/CMakeLists.txt
Normal file
@@ -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}")
|
||||
154
apps/machine/microblaze_generic/README.md
Normal file
154
apps/machine/microblaze_generic/README.md
Normal file
@@ -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 "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
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 <libmetal_source> -DCMAKE_TOOLCHAIN_FILE=<toolchain_file> \
|
||||
-DCMAKE_LIBRARY_PATH=$BSP/lib
|
||||
$ make VERBOSE=1 DESTDIR=<libmetal_install> 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 "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
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 <openamp_source> -DCMAKE_TOOLCHAIN_FILE=<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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
209
apps/machine/microblaze_generic/platform_info.c
Normal file
209
apps/machine/microblaze_generic/platform_info.c
Normal file
@@ -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 <metal/atomic.h>
|
||||
#include <metal/assert.h>
|
||||
#include <metal/device.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <openamp/rpmsg_virtio.h>
|
||||
#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();
|
||||
}
|
||||
97
apps/machine/microblaze_generic/platform_info.h
Normal file
97
apps/machine/microblaze_generic/platform_info.h
Normal file
@@ -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 <openamp/remoteproc.h>
|
||||
#include <openamp/virtio.h>
|
||||
#include <openamp/rpmsg.h>
|
||||
|
||||
#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_ */
|
||||
59
apps/machine/microblaze_generic/rsc_table.c
Normal file
59
apps/machine/microblaze_generic/rsc_table.c
Normal file
@@ -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 <openamp/open_amp.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
43
apps/machine/microblaze_generic/rsc_table.h
Normal file
43
apps/machine/microblaze_generic/rsc_table.h
Normal file
@@ -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 <stddef.h>
|
||||
#include <openamp/open_amp.h>
|
||||
|
||||
#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_ */
|
||||
118
apps/machine/microblaze_generic/zynqmp_mb_a53_rproc.c
Normal file
118
apps/machine/microblaze_generic/zynqmp_mb_a53_rproc.c
Normal file
@@ -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 <metal/atomic.h>
|
||||
#include <metal/assert.h>
|
||||
#include <metal/device.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <openamp/rpmsg_virtio.h>
|
||||
#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,
|
||||
};
|
||||
@@ -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)
|
||||
|
||||
39
apps/system/generic/machine/microblaze_generic/helper.c
Normal file
39
apps/system/generic/machine/microblaze_generic/helper.c
Normal file
@@ -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 <metal/sys.h>
|
||||
#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();
|
||||
}
|
||||
218
apps/system/generic/machine/microblaze_generic/linker_remote.ld
Normal file
218
apps/system/generic/machine/microblaze_generic/linker_remote.ld
Normal file
@@ -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 = .;
|
||||
}
|
||||
@@ -1,2 +1,6 @@
|
||||
# tests presently do not support microblaze
|
||||
if (MACHINE MATCHES ".*microblaze.*")
|
||||
return()
|
||||
endif (MACHINE MATCHES ".*microblaze.*")
|
||||
|
||||
add_subdirectory (msg)
|
||||
|
||||
Reference in New Issue
Block a user