Sync inav to Gitea
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s

This commit is contained in:
2026-08-03 16:37:40 +08:00
commit dac37fd077
14095 changed files with 5603119 additions and 0 deletions
@@ -0,0 +1,66 @@
language: minimal # setting language to C will override cross-compiler and fail
compiler:
- gcc
sudo: required
dist: trusty
env:
global:
- ZEPHYR_TOOLCHAIN_VARIANT=zephyr
- ZEPHYR_SDK_INSTALL_DIR=/opt/zephyr-sdk
- ZEPHYR_BASE=$TRAVIS_BUILD_DIR/deps/zephyr
- ZEPHYR_SDK_VERSION=0.9.3
- ZEPHYR_SDK_DOWNLOAD_FOLDER=https://github.com/zephyrproject-rtos/meta-zephyr-sdk/releases/download/$ZEPHYR_SDK_VERSION
- ZEPHYR_SDK_SETUP_BINARY=zephyr-sdk-$ZEPHYR_SDK_VERSION-setup.run
- ZEPHYR_SDK_DOWNLOAD_URL=$ZEPHYR_SDK_DOWNLOAD_FOLDER/$ZEPHYR_SDK_SETUP_BINARY
matrix:
fast_finish: true
include:
- os: linux
env: TARGET="zephyr"
cache:
directories:
- $ZEPHYR_SDK_INSTALL_DIR
- /usr/local/bin
before_install:
- if [[ "$TARGET" == "zephyr" ]]; then
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test &&
sudo apt-get update -qq &&
sudo apt-get install libc6-dev-i386 make gperf gcc g++ python3-ply python3-yaml python3-pip device-tree-compiler ncurses-dev uglifyjs -qq &&
sudo pip3 install pyelftools;
fi
install: >
if [[ "$TARGET" == "zephyr" && "$(cat $ZEPHYR_SDK_INSTALL_DIR/sdk_version)" != "$ZEPHYR_SDK_VERSION" ]]; then
wget $ZEPHYR_SDK_DOWNLOAD_URL &&
chmod +x $ZEPHYR_SDK_SETUP_BINARY &&
rm -rf $ZEPHYR_SDK_INSTALL_DIR &&
./$ZEPHYR_SDK_SETUP_BINARY --quiet -- -y -d $ZEPHYR_SDK_INSTALL_DIR > /dev/null;
fi
before_script: >
if [[ "$TARGET" == "zephyr" ]]; then
cd .. &&
git clone --depth=1 git://github.com/OpenAMP/libmetal.git &&
git clone --depth=1 git://github.com/zephyrproject-rtos/zephyr.git &&
cd zephyr &&
source zephyr-env.sh;
fi
script:
- if [[ "$TARGET" == "zephyr" ]]; then
mkdir -p ../open-amp/build-zephyr &&
mkdir -p ../libmetal/build-zephyr &&
cd ../libmetal/build-zephyr &&
cmake .. -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 &&
make &&
cd ../../open-amp/build-zephyr &&
cmake .. -DWITH_ZEPHYR=ON -DWITH_PROXY=OFF -DBOARD=qemu_cortex_m3 -DLIBMETAL_INCLUDE_DIR=../../libmetal/build-zephyr/lib/include -DLIBMETAL_LIB=../../libmetal/build-zephyr/lib/libmetal.a &&
make VERBOSE=1;
fi
@@ -0,0 +1,38 @@
cmake_minimum_required (VERSION 2.6)
if (POLICY CMP0048)
cmake_policy(SET CMP0048 NEW)
endif()
# The version number
set (OPENAMP_VERSION_MAJOR 1)
set (OPENAMP_VERSION_MINOR 0)
list (APPEND CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/platforms")
include (syscheck)
project (open_amp C)
include (CheckIncludeFiles)
include (CheckCSourceCompiles)
include (collect)
include (options)
include (depends)
enable_testing ()
set (OPENAMP_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set (OPENAMP_BIN_ROOT "${CMAKE_CURRENT_BINARY_DIR}")
if (WITH_OBSOLETE)
add_subdirectory (obsolete)
endif (WITH_OBSOLETE)
add_subdirectory (lib)
if (WITH_APPS)
add_subdirectory (apps)
endif (WITH_APPS)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,69 @@
Software License Agreement (BSD 3-Clause License)
========================================
Copyright (c) 2014, Mentor Graphics Corporation. All rights reserved.
Copyright (c) 2015 - 2016 Xilinx, Inc. All rights reserved.
Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of <the copyright holder> nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
BSD 2-Clause License
-------------------------
Copyright (c) <year> <owner>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Notes
=========================================
Use the following tag instead of the full license text in the individual files:
SPDX-License-Identifier: BSD-3-Clause
SPDX-License-Identifier: BSD-2-Clause
This enables machine processing of license information based on the SPDX
License Identifiers that are here available: http://spdx.org/licenses/
@@ -0,0 +1,22 @@
# OpenAMP Maintainers
OpenAMP project is maintained by the OpenAMP open source community. Everyone
is encouraged to submit issues and changes to improve OpenAMP.
The intention of this file is to provide a set of names that developers can
consult when they have a question about OpenAMP and to provide a a set of
names to be CC'd when submitting a patch.
## Project Administration
Wendy Liang <wendy.liang@xilinx.com>
### All patches CC here
open-amp@googlegroups.com
## Machines
### Xilinx Platform - Zynq-7000
Wendy Liang <wendy.liang@xilinx.com>
### Xilinx Platform - Zynq UltraScale+ MPSoC
Wendy Liang <wendy.liang@xilinx.com>
@@ -0,0 +1,242 @@
# open-amp
This repository is the home for the Open Asymmetric Multi Processing (OpenAMP)
framework project. The OpenAMP framework provides software components that
enable development of software applications for Asymmetric Multiprocessing
(AMP) systems. The framework provides the following key capabilities.
1. Provides Life Cycle Management, and Inter Processor Communication
capabilities for management of remote compute resources and their associated
software contexts.
2. Provides a stand alone library usable with RTOS and Baremetal software
environments
3. Compatibility with upstream Linux remoteproc and rpmsg components
4. Following AMP configurations supported
a. Linux master/Generic(Baremetal) remote
b. Generic(Baremetal) master/Linux remote
5. Proxy infrastructure and supplied demos showcase ability of proxy on master
to handle printf, scanf, open, close, read, write calls from Bare metal
based remote contexts.
## OpenAMP Source Structure
```
|- lib/
| |- common/ # common helper functions
| |- virtio/ # virtio implementation
| |- rpmsg/ # rpmsg implementation
| |- remoteproc/ # remoteproc implementation
| | |- drivers # remoteproc drivers
| |- proxy/ # implement one processor access device on the
| | # other processor with file operations
|- apps/ # demonstration/testing applications
| |- machine/ # common files for machine can be shared by applications
| # It is up to each app to decide whether to use these files.
| |- system/ # common files for system can be shared by applications
| # It is up to each app to decide whether to use these files.
|- obsolete # It is used to build libs which may also required when
| # building the apps. It will be removed in future since
| # user can specify which libs to use when compiling the apps.
|- cmake # CMake files
```
OpenAMP library libopen_amp is composed of the following directories in `lib/`:
* `common/`
* `virtio/`
* `rpmsg/`
* `remoteproc/`
* `proxy/`
OpenAMP system/machine support has been moved to libmetal, the system/machine
layer in the `apps/` directory is for system application initialization, and
resource table definition.
### libmetal APIs used in OpenAMP
Here are the libmetal APIs used by OpenAMP, if you want to port OpenAMP for your
system, you will need to implement the following libmetal APIs in the libmetal's
`lib/system/<SYS>` directory:
* alloc, for memory allocation and memory free
* cache, for flushing cache and invalidating cache
* io, for memory mapping. OpenAMP required memory mapping in order to access
vrings and carved out memory.
* irq, for IRQ handler registration, IRQ disable/enable and global IRQ handling.
* mutex
* shmem (For RTOS, you can usually use the implementation from
`lib/system/generic/`)
* sleep, at the moment, OpenAMP only requires microseconds sleep as when OpenAMP
fails to get a buffer to send messages, it will call this function to sleep and
then try again.
* time, for timestamp
* init, for libmetal initialization.
* atomic
Please refer to `lib/system/generic` when you port libmetal for your system.
If you a different compiler to GNU gcc, please refer to `lib/compiler/gcc/` to
port libmetal for your compiler. At the moment, OpenAMP needs the atomic
operations defined in `lib/compiler/gcc/atomic.h`.
## OpenAMP Compilation
OpenAMP uses CMake for library and demonstration application compilation.
OpenAMP requires libmetal library. For now, you will need to download and
compile libmetal library separately before you compiling OpenAMP library.
In future, we will try to make libmetal as a submodule to OpenAMP to make this
flow easier.
### Example to compile OpenAMP for Zephyr
You can compile OpenAMP library for Zephyr.
As OpenAMP uses libmetal, please refer to libmetal README to build libmetal
for Zephyr before building OpenAMP library for Zephyr.
As Zephyr uses CMake, we build OpenAMP library as a target of Zephyr CMake
project. Here is how to build libmetal for Zephyr:
```
$ export ZEPHRY_GCC_VARIANT=zephyr
$ export ZEPHRY_SDK_INSTALL_DIR=<where Zephyr SDK is installed>
$ source <git_clone_zephyr_project_source_root>/zephyr-env.sh
$ cmake <OpenAMP_source_root> \
-DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 \
-DCMAKE_INCLUDE_PATH="<libmetal_zephyr_build_dir>/lib/include" \
-DCMAKE_LIBRARY_PATH="<libmetal_zephyr_build_dir>/lib" \
$ make VERBOSE=1 all
```
### Example to compile OpenAMP for communication between Linux processes:
* Install libsysfs devel and libhugetlbfs devel packages on your Linux host.
* build libmetal library on your host as follows:
```
$ mkdir -p build-libmetal
$ cd build-libmetal
$ cmake <libmetal_source>
$ make VERBOSE=1 DESTDIR=<libmetal_install> install
```
* build OpenAMP library on your host as follows:
$ mkdir -p build-openamp
$ cd build-openamp
$ cmake <openamp_source> -DCMAKE_INCLUDE_PATH=<libmetal_built_include_dir> \
-DCMAKE_LIBRARY_PATH=<libmetal_built_lib_dir> [-DWITH_APPS=ON]
$ make VERBOSE=1 DESTDIR=$(pwd) install
The OpenAMP library will be generated to `build/usr/local/lib` directory,
headers will be generated to `build/usr/local/include` directory, and the
applications executable will be generated to `build/usr/local/bin`
directory.
* cmake option `-DWITH_APPS=ON` is to build the demonstration applications.
* If you have used `-DWITH_APPS=ON` to build the demos, you can try them on
your Linux host as follows:
```
# Start echo test server to wait for message to echo
$ sudo LD_LIBRARY_PATH=<openamp_built>/usr/local/lib:<libmetal_built>/usr/local/lib \
build/usr/local/bin/rpmsg-echo-shared
# Run echo test to send message to echo test server
$ sudo LD_LIBRARY_PATH=<openamp_built>/usr/local/lib:<libmetal_built>/usr/local/lib \
build/usr/local/bin/rpmsg-echo-ping-shared 1
```
### Example to compile Zynq UltraScale+ MPSoC R5 generic(baremetal) remote:
* build libmetal library on your host as follows:
* Create your on cmake toolchain file to compile libmetal for your generic
(baremetal) platform. Here is the example of the toolchain file:
```
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "zynqmp_r5" CACHE STRING "")
set (CROSS_PREFIX "armr5-none-eabi-" CACHE STRING "")
set (CMAKE_C_FLAGS "-mfloat-abi=soft -mcpu=cortex-r5 -Wall -Werror -Wextra \
-flto -Os -I/ws/xsdk/r5_0_bsp/psu_cortexr5_0/include" 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)
include (cross-generic-gcc)
```
* Compile libmetal library:
```
$ mkdir -p build-libmetal
$ cd build-libmetal
$ cmake <libmetal_source> -DCMAKE_TOOLCHAIN_FILE=<toolchain_file>
$ make VERBOSE=1 DESTDIR=<libmetal_install> install
```
* build OpenAMP library on your host as follows:
* Create your on cmake toolchain file to compile openamp for your generic
(baremetal) platform. Here is the example of the toolchain file:
```
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "zynqmp_r5" CACHE STRING "")
set (CROSS_PREFIX "armr5-none-eabi-" CACHE STRING "")
set (CMAKE_C_FLAGS "-mfloat-abi=soft -mcpu=cortex-r5 -Os -flto \
-I/ws/libmetal-r5-generic/usr/local/include \
-I/ws/xsdk/r5_0_bsp/psu_cortexr5_0/include" CACHE STRING "")
set (CMAKE_ASM_FLAGS "-mfloat-abi=soft -mcpu=cortex-r5" CACHE STRING "")
set (PLATFORM_LIB_DEPS "-lxil -lc -lm" 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)
set (CMAKE_FIND_ROOT_PATH /ws/libmetal-r5-generic/usr/local/lib \
/ws/xsdk/r5_bsp/psu_cortexr5_0/lib )
include (cross_generic_gcc)
```
* We use cmake `find_path` and `find_library` to check if libmetal includes
and libmetal library is 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
$ cmake <openamp_source> -DCMAKE_TOOLCHAIN_FILE=<toolchain_file>
$ make VERBOSE=1 DESTDIR=$(pwd) install
```
The OpenAMP library will be generated to `build/usr/local/lib` directory,
headers will be generated to `build/usr/local/include` directory, and the
applications executable will be generated to `build/usr/local/bin`
directory.
### Example to compile OpenAMP Linux Userspace for Zynq UltraScale+ MPSoC
We can use yocto to build the OpenAMP Linux userspace library and application.
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
In order to user OpenAMP(RPMsg) in Linux userspace, you will need to have put the IPI device,
vring memory and shared buffer memory to your Linux kernel device tree. The device tree example
can be found here:
https://github.com/OpenAMP/open-amp/blob/master/apps/machine/zynqmp/openamp-linux-userspace.dtsi
## Supported System and Machines
For now, it supports:
* Zynq generic slave
* Zynq UltraScale+ MPSoC R5 generic slave
* Linux host OpenAMP between Linux userspace processes
* Linux userspace OpenAMP RPMsg master
* Linux userspace OpenAMP RPMsg slave
## Known Limitations:
1. In case of OpenAMP on Linux userspace for inter processors communication,
it only supports static vrings and shared buffers.
2. `sudo` is required to run the OpenAMP demos between Linux processes, as
it doesn't work on some systems if you are normal users.
For using the framework please refer to the wiki of the OpenAMP repo.
Subscribe to the open-amp mailing list at https://groups.google.com/group/open-amp.
@@ -0,0 +1,13 @@
collector_create (APP_COMMON_SOURCES "")
collector_create (APP_LIB_DIRS "")
collector_create (APP_INC_DIRS "")
collector_create (APP_LIB_DEPS "")
set (APPS_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set (APPS_SHARE_DIR "${CMAKE_CURRENT_BINARY_DIR}/share")
add_subdirectory (machine)
add_subdirectory (system)
add_subdirectory (tests)
add_subdirectory (examples)
@@ -0,0 +1,12 @@
option (WITH_LOAD_FW "Include loading firmware example" OFF)
add_subdirectory (echo)
add_subdirectory (rpmsg_sample_echo)
add_subdirectory (matrix_multiply)
if (WITH_LOAD_FW)
add_subdirectory (load_fw)
endif (WITH_LOAD_FW)
if (WITH_PROXY_APPS)
add_subdirectory (rpc_demo)
endif (WITH_PROXY_APPS)
@@ -0,0 +1,46 @@
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS} -fdata-sections -ffunction-sections")
set (_fw_dir "${APPS_SHARE_DIR}")
collector_list (_list PROJECT_INC_DIRS)
collector_list (_app_list APP_INC_DIRS)
include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
collector_list (_list PROJECT_LIB_DIRS)
collector_list (_app_list APP_LIB_DIRS)
link_directories (${_list} ${_app_list})
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
collector_list (_deps PROJECT_LIB_DEPS)
set (OPENAMP_LIB open_amp)
foreach (_app rpmsg-echo-ping rpmsg-echo)
collector_list (_sources APP_COMMON_SOURCES)
if (${_app} STREQUAL "rpmsg-echo-ping")
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-ping.c")
elseif (${_app} STREQUAL "rpmsg-echo")
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-echo.c")
endif (${_app} STREQUAL "rpmsg-echo-ping")
if (WITH_SHARED_LIB)
add_executable (${_app}-shared ${_sources})
target_link_libraries (${_app}-shared ${OPENAMP_LIB}-shared ${_deps})
install (TARGETS ${_app}-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (WITH_SHARED_LIB)
if (WITH_STATIC_LIB)
if (${PROJECT_SYSTEM} STREQUAL "linux")
add_executable (${_app}-static ${_sources})
target_link_libraries (${_app}-static ${OPENAMP_LIB}-static ${_deps})
install (TARGETS ${_app}-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
else (${PROJECT_SYSTEM})
add_executable (${_app}.out ${_sources})
set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections ${_linker_opt} -Wl,--start-group ${OPENAMP_LIB}-static ${_deps} -Wl,--end-group)
install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (${PROJECT_SYSTEM} STREQUAL "linux" )
endif (WITH_STATIC_LIB)
endforeach(_app)
@@ -0,0 +1,115 @@
/* This is a sample demonstration application that showcases usage of rpmsg
This application is meant to run on the remote CPU running baremetal code.
This application echoes back data that was sent to it by the master core. */
#include <stdio.h>
#include <openamp/open_amp.h>
#include <metal/alloc.h>
#include "platform_info.h"
#include "rpmsg-echo.h"
#define SHUTDOWN_MSG 0xEF56A55A
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
//#define LPRINTF(format, ...)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
static struct rpmsg_endpoint lept;
static int shutdown_req = 0;
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
(void)priv;
(void)src;
/* On reception of a shutdown we signal the application to terminate */
if ((*(unsigned int *)data) == SHUTDOWN_MSG) {
LPRINTF("shutdown message is received.\n");
shutdown_req = 1;
return RPMSG_SUCCESS;
}
/* Send data back to master */
if (rpmsg_send(ept, data, len) < 0) {
LPERROR("rpmsg_send failed\n");
}
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
LPRINTF("unexpected Remote endpoint destroy\n");
shutdown_req = 1;
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app(struct rpmsg_device *rdev, void *priv)
{
int ret;
/* Initialize RPMSG framework */
LPRINTF("Try to create rpmsg endpoint.\n");
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
0, RPMSG_ADDR_ANY, rpmsg_endpoint_cb,
rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create endpoint.\n");
return -1;
}
LPRINTF("Successfully created rpmsg endpoint.\n");
while(1) {
platform_poll(priv);
/* we got a shutdown request, exit */
if (shutdown_req) {
break;
}
}
rpmsg_destroy_ept(&lept);
return 0;
}
/*-----------------------------------------------------------------------------*
* Application entry point
*-----------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
LPRINTF("Starting application...\n");
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_SLAVE,
NULL, NULL);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,6 @@
#ifndef RPMSG_ECHO_H
#define RPMSG_ECHO_H
#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
#endif /* RPMSG_ECHO_H */
@@ -0,0 +1,202 @@
/* This is a sample demonstration application that showcases usage of rpmsg
This application is meant to run on the remote CPU running baremetal code.
This application echoes back data that was sent to it by the master core. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openamp/open_amp.h>
#include <metal/alloc.h>
#include "platform_info.h"
#include "rpmsg-echo.h"
#define APP_EPT_ADDR 0
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
struct _payload {
unsigned long num;
unsigned long size;
unsigned char data[];
};
static int err_cnt;
#define PAYLOAD_MIN_SIZE 1
/* Globals */
static struct rpmsg_endpoint lept;
static struct _payload *i_payload;
static int rnum = 0;
static int err_cnt = 0;
static int ept_deleted = 0;
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
int i;
struct _payload *r_payload = (struct _payload *)data;
(void)ept;
(void)src;
(void)priv;
LPRINTF(" received payload number %lu of size %lu \r\n",
r_payload->num, (unsigned long)len);
if (r_payload->size == 0) {
LPERROR(" Invalid size of package is received.\n");
err_cnt++;
return RPMSG_SUCCESS;
}
/* Validate data buffer integrity. */
for (i = 0; i < (int)r_payload->size; i++) {
if (r_payload->data[i] != 0xA5) {
LPRINTF("Data corruption at index %d\n", i);
err_cnt++;
break;
}
}
rnum = r_payload->num + 1;
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&lept);
LPRINTF("echo test: service is destroyed\n");
ept_deleted = 1;
}
static void rpmsg_name_service_bind_cb(struct rpmsg_device *rdev,
const char *name, uint32_t dest)
{
LPRINTF("new endpoint notification is received.\n");
if (strcmp(name, RPMSG_SERVICE_NAME))
LPERROR("Unexpected name service %s.\n", name);
else
(void)rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
APP_EPT_ADDR, dest,
rpmsg_endpoint_cb,
rpmsg_service_unbind);
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app (struct rpmsg_device *rdev, void *priv)
{
int ret;
int i;
int size, max_size, num_payloads;
int expect_rnum = 0;
LPRINTF(" 1 - Send data to remote core, retrieve the echo");
LPRINTF(" and validate its integrity ..\n");
max_size = rpmsg_virtio_get_buffer_size(rdev);
if (max_size < 0) {
LPERROR("No avaiable buffer size.\n");
return -1;
}
max_size -= sizeof(struct _payload);
num_payloads = max_size - PAYLOAD_MIN_SIZE + 1;
i_payload =
(struct _payload *)metal_allocate_memory(2 * sizeof(unsigned long) +
max_size);
if (!i_payload) {
LPERROR("memory allocation failed.\n");
return -1;
}
/* Create RPMsg endpoint */
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME, APP_EPT_ADDR,
RPMSG_ADDR_ANY,
rpmsg_endpoint_cb, rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create RPMsg endpoint.\n");
return ret;
}
while (!is_rpmsg_ept_ready(&lept))
platform_poll(priv);
LPRINTF("RPMSG endpoint is binded with remote.\n");
for (i = 0, size = PAYLOAD_MIN_SIZE; i < num_payloads; i++, size++) {
i_payload->num = i;
i_payload->size = size;
/* Mark the data buffer. */
memset(&(i_payload->data[0]), 0xA5, size);
LPRINTF("sending payload number %lu of size %lu\n",
i_payload->num,
(unsigned long)(2 * sizeof(unsigned long)) + size);
ret = rpmsg_send(&lept, i_payload,
(2 * sizeof(unsigned long)) + size);
if (ret < 0) {
LPERROR("Failed to send data...\n");
break;
}
LPRINTF("echo test: sent : %lu\n",
(unsigned long)(2 * sizeof(unsigned long)) + size);
expect_rnum++;
do {
platform_poll(priv);
} while ((rnum < expect_rnum) && !err_cnt && !ept_deleted);
}
LPRINTF("**********************************\n");
LPRINTF(" Test Results: Error count = %d \n", err_cnt);
LPRINTF("**********************************\n");
/* Destroy the RPMsg endpoint */
rpmsg_destroy_ept(&lept);
LPRINTF("Quitting application .. Echo test end\n");
metal_free_memory(i_payload);
return 0;
}
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_MASTER,
NULL,
rpmsg_name_service_bind_cb);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,32 @@
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS}")
set (_fw_dir "${APPS_SHARE_DIR}")
collector_list (_list PROJECT_INC_DIRS)
collector_list (_app_list APP_INC_DIRS)
include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
collector_list (_list PROJECT_LIB_DIRS)
collector_list (_app_list APP_LIB_DIRS)
link_directories (${_list} ${_app_list})
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
collector_list (_deps PROJECT_LIB_DEPS)
set (OPENAMP_LIB open_amp)
foreach (_app load_fw)
collector_list (_sources APP_COMMON_SOURCES)
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/${_app}.c")
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/mem_image_store.c")
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/zynqmp_r5_lcm_rproc_example.c")
if (WITH_STATIC_LIB)
add_executable (${_app}.out ${_sources})
set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections -T"${CMAKE_CURRENT_SOURCE_DIR}/lscript.ld" -Wl,--start-group ${OPENAMP_LIB}-static -lxilpm ${_deps} -Wl,--end-group)
install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (WITH_STATIC_LIB)
endforeach(_app)
@@ -0,0 +1,250 @@
/*
* Load firmware example
*
* Copyright(c) 2018 Xilinx Ltd.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <metal/io.h>
#include <metal/sys.h>
#include <openamp/remoteproc.h>
#include <openamp/remoteproc_loader.h>
#include <stdarg.h>
#include <stdio.h>
/* Xilinx headers */
#include <pm_api_sys.h>
#include <pm_defs.h>
#include <xil_printf.h>
#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__)
//#define LPRINTF(format, ...)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
extern struct remoteproc_ops r5_rproc_ops;
extern struct image_store_ops mem_image_store_ops;
struct mem_file {
const void *base;
};
static struct mem_file image = {
.base = (void *)0x3ED00000,
};
static XIpiPsu IpiInst;
static XStatus IpiConfigure(XIpiPsu *const IpiInstPtr)
{
XStatus Status;
XIpiPsu_Config *IpiCfgPtr;
/* Look Up the config data */
IpiCfgPtr = XIpiPsu_LookupConfig(XPAR_XIPIPSU_0_DEVICE_ID);
if (NULL == IpiCfgPtr) {
Status = XST_FAILURE;
LPERROR("%s ERROR in getting CfgPtr\n", __func__);
return Status;
}
/* Init with the Cfg Data */
Status = XIpiPsu_CfgInitialize(IpiInstPtr, IpiCfgPtr,
IpiCfgPtr->BaseAddress);
if (XST_SUCCESS != Status) {
LPERROR("%s ERROR #%d in configuring IPI\n", __func__, Status);
return Status;
}
return Status;
}
static void app_log_handler(enum metal_log_level level,
const char *format, ...)
{
char msg[1024];
va_list args;
static const char *level_strs[] = {
"metal: emergency: ",
"metal: alert: ",
"metal: critical: ",
"metal: error: ",
"metal: warning: ",
"metal: notice: ",
"metal: info: ",
"metal: debug: ",
};
va_start(args, format);
vsnprintf(msg, sizeof(msg), format, args);
va_end(args);
if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG)
level = METAL_LOG_EMERGENCY;
xil_printf("%s%s", level_strs[level], msg);
}
int load_exectuable_block(struct remoteproc *rproc,
struct image_store_ops *store_ops, void *store,
const char *img_path)
{
int ret;
(void)img_path;
if (rproc == NULL)
return -EINVAL;
/* Configure remoteproc to get ready to load executable */
remoteproc_config(rproc, NULL);
/* Load remoteproc executable */
LPRINTF("Start to load executable with remoteproc_load() \r\n");
ret = remoteproc_load(rproc, NULL, store, store_ops, NULL);
if (ret) {
LPRINTF("failed to load firmware\r\n");
return ret;
}
/* Start the processor */
ret = remoteproc_start(rproc);
if (ret) {
LPRINTF("failed to start processor\r\n");
return ret;
}
LPRINTF("successfully started the processor\r\n");
/* ... */
asm volatile("wfi");
LPRINTF("going to stop the processor\r\n");
remoteproc_stop(rproc);
/* application may want to do some cleanup before shutdown */
LPRINTF("going to shutdown the processor\r\n");
remoteproc_shutdown(rproc);
return 0;
}
int load_exectuable_noblock(struct remoteproc *rproc,
struct image_store_ops *store_ops, void *store,
const char *img_path)
{
int ret;
const void *img_data;
void *img_info = NULL;
metal_phys_addr_t pa;
struct metal_io_region *io;
size_t offset, noffset;
size_t len, nlen, nmlen;
unsigned char padding;
if (rproc == NULL)
return -EINVAL;
/* Configure remoteproc to get ready to load executable */
remoteproc_config(rproc, NULL);
/* Load remoteproc executable */
LPRINTF("Start to load executable with remoteproc_load() \r\n");
ret = store_ops->open(store, img_path, &img_data);
if (ret <= 0)
return -EINVAL;
offset = 0;
len = (size_t)ret;
do {
nlen = 0;
pa = METAL_BAD_PHYS;
io = NULL;
nmlen = 0;
LPRINTF("%s, loading 0x%lx,0x%lx\r\n",
__func__, offset, len);
ret = remoteproc_load_noblock(rproc, img_data, offset, len,
&img_info, &pa, &io, &noffset,
&nlen, &nmlen, &padding);
if (ret) {
LPERROR("failed to load executable, 0x%lx,0x%lx\r\n",
offset, len);
return ret;
}
if (nlen == 0)
break;
offset = noffset;
len = nlen;
ret = store_ops->load(store, noffset, nlen, &img_data, pa,
io, 1);
if (ret != (int)nlen) {
LPERROR("failed to load data to memory, 0x%lx,0x%lx\r\n",
noffset, nlen);
return ret;
}
if (nmlen > nlen && io != NULL) {
/* pad the rest of the memory with 0 */
size_t tmpoffset;
tmpoffset = metal_io_phys_to_offset(io, pa + nlen);
metal_io_block_set(io, tmpoffset, padding,
(nmlen - nlen));
}
} while(1);
/* Start the processor */
ret = remoteproc_start(rproc);
if (ret) {
LPRINTF("failed to start processor\r\n");
return ret;
}
LPRINTF("successfully started the processor\r\n");
/* ... */
asm volatile("wfi");
LPRINTF("going to stop the processor\r\n");
remoteproc_stop(rproc);
/* application may want to do some cleanup before shutdown */
LPRINTF("going to shutdown the processor\r\n");
remoteproc_shutdown(rproc);
return 0;
}
int main(void)
{
struct remoteproc rproc;
struct remoteproc *ret_rproc;
void *store = &image;
unsigned int cpu_id = NODE_RPU_1;
int ret;
struct metal_init_params metal_param = {
.log_handler = app_log_handler,
.log_level = METAL_LOG_DEBUG,
};
if (XST_SUCCESS != IpiConfigure(&IpiInst)) {
LPERROR("Failed to config IPI instance\r\n");
return -1;
}
if (XST_SUCCESS != XPm_InitXilpm(&IpiInst)) {
LPERROR("Failed to initialize PM\r\n");
return -1;
}
LPRINTF("Loading Exectuable Demo\n");
/* Initialize libmetal evironment */
metal_init(&metal_param);
/* Initialize remoteproc instance */
ret_rproc = remoteproc_init(&rproc, &r5_rproc_ops, &cpu_id);
if (!ret_rproc) {
LPRINTF("failed to initialize coprocessor\r\n");
return -1;
}
ret = load_exectuable_block(&rproc, &mem_image_store_ops, store, NULL);
if (ret < 0) {
LPERROR("load_exectuable_block failed\r\n");
/* Make sure the remote is shut down */
remoteproc_shutdown(&rproc);
return -1;
}
ret = load_exectuable_noblock(&rproc, &mem_image_store_ops, store,
NULL);
if (ret < 0) {
LPERROR("load_exectuable_noblock failed\r\n");
/* Make sure the remote is shut down */
remoteproc_shutdown(&rproc);
return -1;
}
remoteproc_remove(&rproc);
return ret;
}
@@ -0,0 +1,315 @@
/******************************************************************************
*
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
_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 */
/* TCM size is set to 2*0x20000 for R5 in lockstep mode */
MEMORY
{
psu_ocm_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000
psu_r5_tcm_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00010000
psu_r5_tcm_ram_1_S_AXI_BASEADDR : ORIGIN = 0x00020000, LENGTH = 0x00010000
}
/* Specify the default entry point to the program */
/* ENTRY(_boot) */
ENTRY(_vector_table)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.vectors : {
KEEP (*(.vectors))
*(.boot)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.text : {
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > psu_r5_tcm_ram_1_S_AXI_BASEADDR
.init : {
KEEP (*(.init))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.fini : {
KEEP (*(.fini))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.interp : {
KEEP (*(.interp))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.note-ABI-tag : {
KEEP (*(.note-ABI-tag))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.got : {
*(.got)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.eh_frame : {
*(.eh_frame)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.gcc_except_table : {
*(.gcc_except_table)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.bss (NOLOAD) : {
. = ALIGN(4);
__bss_start__ = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
_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_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
_end = .;
}
@@ -0,0 +1,93 @@
/*
* Memory based image store Operation
*
* Copyright(c) 2018 Xilinx Ltd.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <metal/io.h>
#include <metal/sys.h>
#include <openamp/remoteproc_loader.h>
#include <stdarg.h>
#include <stdio.h>
/* Xilinx headers */
#include <pm_api_sys.h>
#include <pm_defs.h>
#include <xil_printf.h>
#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__)
//#define LPRINTF(format, ...)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
struct mem_file {
const void *base;
};
int mem_image_open(void *store, const char *path, const void **image_data)
{
struct mem_file *image = store;
const void *fw_base = image->base;
(void)(path);
if (image_data == NULL) {
LPERROR("%s: input image_data is NULL\r\n", __func__);
return -EINVAL;
}
*image_data = fw_base;
/* return an abitrary length, as the whole firmware is in memory */
return 0x100;
}
void mem_image_close(void *store)
{
/* The image is in memory, does nothing */
(void)store;
}
int mem_image_load(void *store, size_t offset, size_t size,
const void **data, metal_phys_addr_t pa,
struct metal_io_region *io,
char is_blocking)
{
struct mem_file *image = store;
const void *fw_base = image->base;
(void)is_blocking;
LPRINTF("%s: offset=0x%x, size=0x%x\n\r",
__func__, offset, size);
if (pa == METAL_BAD_PHYS) {
if (data == NULL) {
LPERROR("%s: data is NULL while pa is ANY\r\n",
__func__);
return -EINVAL;
}
*data = (const void *)((const char *)fw_base + offset);
} else {
void *va;
if (io == NULL) {
LPERROR("%s, io is NULL while pa is not ANY\r\n",
__func__);
return -EINVAL;
}
va = metal_io_phys_to_virt(io, pa);
if (va == NULL) {
LPERROR("%s: no va is found\r\n", __func__);
return -EINVAL;
}
memcpy(va, (const void *)((const char *)fw_base + offset), size);
}
return (int)size;
}
struct image_store_ops mem_image_store_ops = {
.open = mem_image_open,
.close = mem_image_close,
.load = mem_image_load,
.features = SUPPORT_SEEK,
};
@@ -0,0 +1,313 @@
/*
* ZynqMP RPU life cycle management remoteproc example implementation
*
* Copyright(c) 2018 Xilinx Ltd.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <metal/alloc.h>
#include <metal/sys.h>
#include <metal/utilities.h>
#include <openamp/remoteproc.h>
#include <stdarg.h>
#include <stdio.h>
/* Xilinx headers */
#include <pm_api_sys.h>
#include <pm_defs.h>
#include <xil_mpu.h>
#include <xil_printf.h>
#include <xreg_cortexr5.h>
#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__)
//#define LPRINTF(format, ...)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
#define RPU_BASE_ADDR 0xFF9A0000
#define RPU_GLBL_CNTL_OFFSET 0
#define RPU0_CFG_BASE_OFFSET 0x100
#define RPU1_CFG_BASE_OFFSET 0x200
#define RPU_CFG_BASE_OFFSET(n) (RPU0_CFG_BASE_OFFSET << (n))
/* Boot memory bit. high for OCM, low for TCM */
#define VINITHI_BIT metal_bit(2)
/* CPU halt bit, high: processor is running. low: processor is halt */
#define nCPUHALT_BIT metal_bit(0)
/* RPU mode, high: split mode. low: lock step mode */
#define SLSPLIT_BIT metal_bit(3)
/* Clamp mode. high: split mode. low: lock step mode */
#define SLCLAMP_BIT metal_bit(4)
/* TCM mode. high: combine RPU TCMs. low: split TCM for RPU1 and RPU0 */
#define TCM_COMB_BIT metal_bit(6)
struct r5_rproc_priv {
struct remoteproc *rproc;
int cpu_id;
metal_phys_addr_t rpu_base;
struct metal_io_region rpu_io;
};
/**
* r5_rproc_boot_addr_config - configure the boot address of R5
* @pdata: platform data
*
* This function will set the boot address based on if the
* boot memory in the ELF file is TCM or OCM
*/
static uint32_t r5_rproc_boot_addr_config(struct r5_rproc_priv *priv,
metal_phys_addr_t bootaddr)
{
uint32_t rpu_resetaddr;
LPRINTF("%s: R5 ID: %d, boot_addr 0x%x\n",
__func__, priv->cpu_id, bootaddr);
if (bootaddr < 0x40000)
rpu_resetaddr = 0;
else
rpu_resetaddr = 1;
return rpu_resetaddr;
}
/**
* r5_rproc_mode_config - configure R5 operation mode
* @pdata: platform data
*
* configure R5 to split mode or lockstep mode
* based on the platform data.
*/
static void r5_rproc_mode_config(struct r5_rproc_priv *priv)
{
uint32_t tmp;
LPRINTF("%s: mode: %d\n", __func__, priv->cpu_id);
tmp = metal_io_read32(&priv->rpu_io, RPU_GLBL_CNTL_OFFSET);
if (priv->cpu_id == NODE_RPU) {
/* RPU lock step mode */
tmp &= ~SLSPLIT_BIT;
tmp |= TCM_COMB_BIT;
tmp |= SLCLAMP_BIT;
} else {
/* RPU split mode */
tmp |= SLSPLIT_BIT;
tmp &= ~TCM_COMB_BIT;
tmp &= ~SLCLAMP_BIT;
}
metal_io_write32(&priv->rpu_io, RPU_GLBL_CNTL_OFFSET, tmp);
}
struct remoteproc *r5_rproc_init(struct remoteproc *rproc,
struct remoteproc_ops *ops, void *arg)
{
struct r5_rproc_priv *priv;
unsigned int cpu_id = *((unsigned int *)arg);
if (cpu_id < NODE_RPU_0 || cpu_id > NODE_RPU_1) {
xil_printf("rproc init: invalide node id: %d\n\r", cpu_id);
return NULL;
}
xil_printf("rproc init: node id: %d\n\r", cpu_id);
priv = metal_allocate_memory(sizeof(*priv));
if (!priv)
return NULL;
memset(priv, 0, sizeof(*priv));
priv->rproc = rproc;
priv->cpu_id = cpu_id;
priv->rproc->ops = ops;
metal_list_init(&priv->rproc->mems);
priv->rproc->priv = priv;
priv->rpu_base = RPU_BASE_ADDR;
metal_io_init(&priv->rpu_io, (void *)RPU_BASE_ADDR, &priv->rpu_base,
0x1000, (metal_phys_addr_t)(-1),
DEVICE_NONSHARED | PRIV_RW_USER_RW, NULL);
r5_rproc_mode_config(priv);
rproc->state = RPROC_READY;
return priv->rproc;
}
void r5_rproc_remove(struct remoteproc *rproc)
{
if (rproc) {
struct r5_rproc_priv *priv;
priv = (struct r5_rproc_priv *)rproc->priv;
metal_free_memory(priv);
}
}
void *r5_rproc_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;
struct r5_rproc_priv *priv;
metal_phys_addr_t lpa, lda;
priv = rproc->priv;
if (!da || !pa)
return NULL;
LPRINTF("%s: pa=0x%x, da=0x%x, size=0x%x, atrribute=0x%x\n\r",
__func__, *pa, *da, size, attribute);
lda = *da;
lpa = *pa;
if (!attribute)
attribute = NORM_SHARED_NCACHE | PRIV_RW_USER_RW;
if (lda <= 0x40000) {
metal_phys_addr_t lda_end;
lda_end = lda + size;
if (priv->cpu_id == NODE_RPU_0 || priv->cpu_id == NODE_RPU) {
lpa = 0xFFE00000 + lda;
if (lda < 0x10000)
XPm_RequestNode(NODE_TCM_0_A,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (lda <= 0x20000 && lda_end >= 0x10000)
XPm_RequestNode(NODE_TCM_1_A,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (lda <= 0x30000 && lda_end >= 0x20000)
XPm_RequestNode(NODE_TCM_0_B,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (lda <= 0x40000 && lda_end >= 0x30000)
XPm_RequestNode(NODE_TCM_1_B,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
} else if (priv->cpu_id == NODE_RPU_1) {
lpa = 0xFFE90000 + lda;
if (lda < 0x10000)
XPm_RequestNode(NODE_TCM_1_A,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (lda <= 0x30000 && lda_end >= 0x20000)
XPm_RequestNode(NODE_TCM_1_B,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
} else {
LPERROR("mmap failed: invalid cpu node: %d\n",
priv->cpu_id);
return NULL;
}
}
if (lpa == METAL_BAD_PHYS)
lpa = lda;
if (lpa == METAL_BAD_PHYS)
return NULL;
mem = metal_allocate_memory(sizeof(*mem));
if (!mem)
return NULL;
mem->pa = lpa;
mem->da = lda;
*io = metal_allocate_memory(sizeof(struct metal_io_region));
if (!*io) {
metal_free_memory(mem);
return NULL;
}
metal_io_init(*io, (void *)mem->pa, &mem->pa, size,
sizeof(metal_phys_addr_t)<<3, attribute, NULL);
mem->io = *io;
metal_list_add_tail(&rproc->mems, &mem->node);
*pa = lpa;
*da = lda;
mem->size = size;
return metal_io_phys_to_virt(*io, mem->pa);
}
int r5_rproc_start(struct remoteproc *rproc)
{
struct r5_rproc_priv *priv;
int ret;
uint32_t resetaddr;
priv = rproc->priv;
resetaddr = r5_rproc_boot_addr_config(priv, rproc->bootaddr);
ret = XPm_RequestWakeUp(priv->cpu_id, true, resetaddr,
REQUEST_ACK_BLOCKING);
if (ret != XST_SUCCESS) {
LPRINTF("%s: Failed to start RPU 0x%x, ret=0x%x\n\r",
__func__, priv->cpu_id, ret);
return -1;
} else {
return 0;
}
}
int r5_rproc_stop(struct remoteproc *rproc)
{
/* It is lacking a stop operation in the libPM */
(void)rproc;
return 0;
}
int r5_rproc_shutdown(struct remoteproc *rproc)
{
struct r5_rproc_priv *priv;
int ret;
struct remoteproc_mem *mem;
struct metal_list *node;
priv = rproc->priv;
/* Delete all the registered remoteproc memories */
metal_list_for_each(&rproc->mems, node) {
struct metal_list *tmpnode;
metal_phys_addr_t pa, pa_end;
mem = metal_container_of(node, struct remoteproc_mem, node);
tmpnode = node;
/* Release TCM resource */
pa = mem->pa;
pa_end = metal_io_phys(mem->io, metal_io_region_size(mem->io));
if (priv->cpu_id == NODE_RPU_0 || priv->cpu_id == NODE_RPU) {
if (pa < 0xFFE10000)
XPm_RequestNode(NODE_TCM_0_A,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (pa <= 0xFFE20000 && pa_end >= 0xFFE10000)
XPm_RequestNode(NODE_TCM_1_A,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (pa <= 0xFFE30000 && pa_end >= 0xFFE20000)
XPm_RequestNode(NODE_TCM_0_B,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (pa <= 0xFFE40000 && pa_end >= 0xFFE30000)
XPm_RequestNode(NODE_TCM_1_B,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
} else if (priv->cpu_id == NODE_RPU_1) {
if (pa < 0xFFEA0000)
XPm_RequestNode(NODE_TCM_1_A,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
if (pa <= 0xFFC0000 && pa_end >= 0xFFEB0000)
XPm_RequestNode(NODE_TCM_1_B,
PM_CAP_ACCESS, 0,
REQUEST_ACK_BLOCKING);
}
node = tmpnode->prev;
metal_list_del(tmpnode);
metal_free_memory(mem->io);
metal_free_memory(mem);
}
ret = XPm_ForcePowerDown(priv->cpu_id, REQUEST_ACK_BLOCKING);
if (ret != XST_SUCCESS)
return -1;
else
return 0;
}
struct remoteproc_ops r5_rproc_ops = {
.init = r5_rproc_init,
.remove = r5_rproc_remove,
.start = r5_rproc_start,
.stop = r5_rproc_stop,
.shutdown = r5_rproc_shutdown,
.mmap = r5_rproc_mmap,
};
@@ -0,0 +1,41 @@
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS} -fdata-sections -ffunction-sections")
set (_fw_dir "${APPS_SHARE_DIR}")
collector_list (_list PROJECT_INC_DIRS)
collector_list (_app_list APP_INC_DIRS)
include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
collector_list (_list PROJECT_LIB_DIRS)
collector_list (_app_list APP_LIB_DIRS)
link_directories (${_list} ${_app_list})
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
collector_list (_deps PROJECT_LIB_DEPS)
set (OPENAMP_LIB open_amp)
foreach (_app matrix_multiply matrix_multiplyd)
collector_list (_sources APP_COMMON_SOURCES)
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/${_app}.c")
if (WITH_SHARED_LIB)
add_executable (${_app}-shared ${_sources})
target_link_libraries (${_app}-shared ${OPENAMP_LIB}-shared ${_deps})
install (TARGETS ${_app}-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (WITH_SHARED_LIB)
if (WITH_STATIC_LIB)
if (${PROJECT_SYSTEM} STREQUAL "linux")
add_executable (${_app}-static ${_sources})
target_link_libraries (${_app}-static ${OPENAMP_LIB}-static ${_deps})
install (TARGETS ${_app}-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
else (${PROJECT_SYSTEM})
add_executable (${_app}.out ${_sources})
set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections ${_linker_opt} -Wl,--start-group ${OPENAMP_LIB}-static ${_deps} -Wl,--end-group)
install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (${PROJECT_SYSTEM} STREQUAL "linux" )
endif (WITH_STATIC_LIB)
endforeach(_app)
@@ -0,0 +1,258 @@
/* This is a sample demonstration application that showcases usage of remoteproc
and rpmsg APIs on the remote core. This application is meant to run on the remote CPU
running baremetal code. This applicationr receives two matrices from the master,
multiplies them and returns the result to the master core. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <openamp/open_amp.h>
#include "matrix_multiply.h"
#include "platform_info.h"
#define MAX_SIZE 6
#define NUM_MATRIX 2
#define APP_EPT_ADDR 0
#define raw_printf(format, ...) printf(format, ##__VA_ARGS__)
#define LPRINTF(format, ...) raw_printf("CLIENT> " format, ##__VA_ARGS__)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
typedef struct _matrix {
unsigned int size;
unsigned int elements[MAX_SIZE][MAX_SIZE];
} matrix;
/* Globals */
static struct rpmsg_endpoint lept;
static struct _matrix i_matrix[2];
static struct _matrix e_matrix;
static unsigned int result_returned = 0;
static int err_cnt = 0;
static int ept_deleted = 0;
/**
* _gettimeofday() is called from time() which is used by srand() to generate
* random number. It is defined here in case this function is not defined in
* library.
*/
int __attribute__((weak)) _gettimeofday(struct timeval *tv, void *tz)
{
(void)tv;
(void)tz;
return 0;
}
static void matrix_print(struct _matrix *m)
{
unsigned int i, j;
/* Generate two random matrices */
LPRINTF("Printing matrix... \n");
for (i = 0; i < m->size; ++i) {
for (j = 0; j < m->size; ++j)
raw_printf(" %u ", m->elements[i][j]);
raw_printf("\n");
}
}
static void generate_matrices(int num_matrices,
unsigned int matrix_size, void *p_data)
{
unsigned int i, j, k;
struct _matrix *p_matrix = p_data;
unsigned long value;
for (i = 0; i < (unsigned int)num_matrices; i++) {
/* Initialize workload */
p_matrix[i].size = matrix_size;
LPRINTF("Input matrix %d \n", i);
for (j = 0; j < matrix_size; j++) {
raw_printf("\n");
for (k = 0; k < matrix_size; k++) {
value = (rand() & 0x7F);
value = value % 10;
p_matrix[i].elements[j][k] = value;
raw_printf(" %u ", p_matrix[i].elements[j][k]);
}
}
raw_printf("\n");
}
}
static void matrix_multiply(const matrix * m, const matrix * n, matrix * r)
{
unsigned int i, j, k;
memset(r, 0x0, sizeof(matrix));
r->size = m->size;
for (i = 0; i < m->size; ++i) {
for (j = 0; j < n->size; ++j) {
for (k = 0; k < r->size; ++k) {
r->elements[i][j] +=
m->elements[i][k] * n->elements[k][j];
}
}
}
}
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data,
size_t len, uint32_t src, void *priv)
{
struct _matrix *r_matrix = (struct _matrix *)data;
int i, j;
(void)ept;
(void)priv;
(void)src;
if (len != sizeof(struct _matrix)) {
LPERROR("Received matrix is of invalid len: %d:%lu\n",
(int)sizeof(struct _matrix), (unsigned long)len);
err_cnt++;
return RPMSG_SUCCESS;
}
for (i = 0; i < MAX_SIZE; i++) {
for (j = 0; j < MAX_SIZE; j++) {
if (r_matrix->elements[i][j] !=
e_matrix.elements[i][j]) {
err_cnt++;
break;
}
}
}
if (err_cnt) {
LPERROR("Result mismatched...\n");
LPERROR("Expected matrix:\n");
matrix_print(&e_matrix);
LPERROR("Actual matrix:\n");
matrix_print(r_matrix);
} else {
result_returned = 1;
}
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&lept);
LPRINTF("echo test: service is destroyed\n");
ept_deleted = 1;
}
static void rpmsg_name_service_bind_cb(struct rpmsg_device *rdev,
const char *name, uint32_t dest)
{
if (strcmp(name, RPMSG_SERVICE_NAME))
LPERROR("Unexpected name service %s.\n", name);
else
(void)rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
APP_EPT_ADDR, dest,
rpmsg_endpoint_cb,
rpmsg_service_unbind);
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app (struct rpmsg_device *rdev, void *priv)
{
int c;
int ret;
LPRINTF("Compute thread unblocked ..\n");
LPRINTF("It will generate two random matrices.\n");
LPRINTF("Send to the remote and get the computation result back.\n");
LPRINTF("It will then check if the result is expected.\n");
/* Create RPMsg endpoint */
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME, APP_EPT_ADDR,
RPMSG_ADDR_ANY,
rpmsg_endpoint_cb, rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create RPMsg endpoint.\n");
return ret;
}
while (!is_rpmsg_ept_ready(&lept))
platform_poll(priv);
LPRINTF("RPMSG endpoint is binded with remote.\n");
err_cnt = 0;
srand(time(NULL));
for (c = 0; c < 200; c++) {
generate_matrices(2, MAX_SIZE, i_matrix);
matrix_multiply(&i_matrix[0], &i_matrix[1],
&e_matrix);
result_returned = 0;
ret = rpmsg_send(&lept, i_matrix, sizeof(i_matrix));
if (ret < 0) {
LPRINTF("Error sending data...\n");
break;
}
LPRINTF("Matrix multiply: sent : %lu\n",
(unsigned long)sizeof(i_matrix));
do {
platform_poll(priv);
} while (!result_returned && !err_cnt && !ept_deleted);
if (err_cnt)
break;
}
LPRINTF("**********************************\n");
LPRINTF(" Test Results: Error count = %d \n", err_cnt);
LPRINTF("**********************************\n");
/* Detroy RPMsg endpoint */
rpmsg_destroy_ept(&lept);
LPRINTF("Quitting application .. Matrix multiplication end\n");
return 0;
}
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_MASTER,
NULL,
rpmsg_name_service_bind_cb);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,6 @@
#ifndef MATRIX_MULTIPLY_H
#define MATRIX_MULTIPLY_H
#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
#endif /* MATRIX_MULTIPLY_H */
@@ -0,0 +1,149 @@
/* This is a sample demonstration application that showcases usage of remoteproc
and rpmsg APIs on the remote core. This application is meant to run on the remote CPU
running baremetal code. This applicationr receives two matrices from the master,
multiplies them and returns the result to the master core. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openamp/open_amp.h>
#include "matrix_multiply.h"
#include "platform_info.h"
#define MAX_SIZE 6
#define NUM_MATRIX 2
#define SHUTDOWN_MSG 0xEF56A55A
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
//#define LPRINTF(format, ...)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
typedef struct _matrix {
unsigned int size;
unsigned int elements[MAX_SIZE][MAX_SIZE];
} matrix;
/* Local variables */
static struct rpmsg_endpoint lept;
static int shutdown_req = 0;
/*-----------------------------------------------------------------------------*
* Calculate the Matrix
*-----------------------------------------------------------------------------*/
static void Matrix_Multiply(const matrix *m, const matrix *n, matrix *r)
{
unsigned int i, j, k;
memset(r, 0x0, sizeof(matrix));
r->size = m->size;
for (i = 0; i < m->size; ++i) {
for (j = 0; j < n->size; ++j) {
for (k = 0; k < r->size; ++k) {
r->elements[i][j] +=
m->elements[i][k] * n->elements[k][j];
}
}
}
}
/*-----------------------------------------------------------------------------*
* RPMSG callbacks setup by remoteproc_resource_init()
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
matrix matrix_array[NUM_MATRIX];
matrix matrix_result;
(void)priv;
(void)src;
if ((*(unsigned int *)data) == SHUTDOWN_MSG) {
LPRINTF("shutdown message is received.\n");
shutdown_req = 1;
return RPMSG_SUCCESS;
}
memcpy(matrix_array, data, len);
/* Process received data and multiple matrices. */
Matrix_Multiply(&matrix_array[0], &matrix_array[1], &matrix_result);
/* Send the result of matrix multiplication back to master. */
if (rpmsg_send(ept, &matrix_result, sizeof(matrix)) < 0) {
LPERROR("rpmsg_send failed\n");
}
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
LPERROR("Endpoint is destroyed\n");
shutdown_req = 1;
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app(struct rpmsg_device *rdev, void *priv)
{
int ret;
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
0, RPMSG_ADDR_ANY, rpmsg_endpoint_cb,
rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create endpoint.\n");
return -1;
}
LPRINTF("Waiting for events...\n");
while(1) {
platform_poll(priv);
/* we got a shutdown request, exit */
if (shutdown_req) {
break;
}
}
rpmsg_destroy_ept(&lept);
return 0;
}
/*-----------------------------------------------------------------------------*
* Application entry point
*-----------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
LPRINTF("Starting application...\n");
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_SLAVE,
NULL, NULL);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,49 @@
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS}")
set (_fw_dir "${APPS_SHARE_DIR}")
collector_list (_list PROJECT_INC_DIRS)
collector_list (_app_list APP_INC_DIRS)
include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
collector_list (_list PROJECT_LIB_DIRS)
collector_list (_app_list APP_LIB_DIRS)
link_directories (${_list} ${_app_list})
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_LARGE_TEXT_OPT)
if (NOT _linker_opt)
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
endif (NOT _linker_opt)
collector_list (_deps PROJECT_LIB_DEPS)
set (OPENAMP_LIB open_amp)
if (${PROJECT_SYSTEM} STREQUAL "linux")
set (app_list rpc_demod)
else (${PROJECT_SYSTEM})
set (app_list rpc_demo)
endif (${PROJECT_SYSTEM} STREQUAL "linux")
foreach (_app ${app_list})
collector_list (_sources APP_COMMON_SOURCES)
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/${_app}.c")
if (WITH_SHARED_LIB)
add_executable (${_app}-shared ${_sources})
target_link_libraries (${_app}-shared ${OPENAMP_LIB}-shared ${_deps})
install (TARGETS ${_app}-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (WITH_SHARED_LIB)
if (WITH_STATIC_LIB)
if (${PROJECT_SYSTEM} STREQUAL "linux")
add_executable (${_app}-static ${_sources})
target_link_libraries (${_app}-static ${OPENAMP_LIB}-static ${_deps})
install (TARGETS ${_app}-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
else (${PROJECT_SYSTEM})
add_executable (${_app}.out ${_sources})
set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections ${_linker_opt} -Wl,--start-group ${OPENAMP_LIB}-static ${_deps} -Wl,--end-group)
install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (${PROJECT_SYSTEM} STREQUAL "linux" )
endif (WITH_STATIC_LIB)
endforeach(_app)
@@ -0,0 +1,169 @@
/* This is a sample demonstration application that showcases usage of proxy from the remote core.
This application is meant to run on the remote CPU running baremetal.
This applicationr can print to to master console and perform file I/O using proxy mechanism. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <openamp/open_amp.h>
#include <openamp/rpmsg_retarget.h>
#include "rsc_table.h"
#include "platform_info.h"
#include "rpmsg-rpc-demo.h"
#define REDEF_O_CREAT 0000100
#define REDEF_O_EXCL 0000200
#define REDEF_O_RDONLY 0000000
#define REDEF_O_WRONLY 0000001
#define REDEF_O_RDWR 0000002
#define REDEF_O_APPEND 0002000
#define REDEF_O_ACCMODE 0000003
#define LPRINTF(format, ...) xil_printf(format, ##__VA_ARGS__)
//#define LPRINTF(format, ...)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
static void rpmsg_rpc_shutdown(struct rpmsg_rpc_data *rpc)
{
(void)rpc;
LPRINTF("RPMSG RPC is shutting down.\n");
}
/*-----------------------------------------------------------------------------*
* Application specific
*-----------------------------------------------------------------------------*/
int app(struct rpmsg_device *rdev, void *priv)
{
struct rpmsg_rpc_data rpc;
struct rpmsg_rpc_syscall rpccall;
int fd, bytes_written, bytes_read;
char fname[] = "remote.file";
char wbuff[50];
char rbuff[1024];
char ubuff[50];
float fdata;
int idata;
int ret;
/* redirect I/Os */
LPRINTF("Initializating I/Os redirection...\n");
ret = rpmsg_rpc_init(&rpc, rdev, RPMSG_SERVICE_NAME,
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
priv, platform_poll, rpmsg_rpc_shutdown);
rpmsg_set_default_rpc(&rpc);
if (ret) {
LPRINTF("Failed to intialize rpmsg rpc\n");
return -1;
}
printf("\r\nRemote>Baremetal Remote Procedure Call (RPC) Demonstration\r\n");
printf("\r\nRemote>***************************************************\r\n");
printf("\r\nRemote>Rpmsg based retargetting to proxy initialized..\r\n");
/* Remote performing file IO on Master */
printf("\r\nRemote>FileIO demo ..\r\n");
printf("\r\nRemote>Creating a file on master and writing to it..\r\n");
fd = open(fname, REDEF_O_CREAT | REDEF_O_WRONLY | REDEF_O_APPEND,
S_IRUSR | S_IWUSR);
printf("\r\nRemote>Opened file '%s' with fd = %d\r\n", fname, fd);
sprintf(wbuff, "This is a test string being written to file..");
bytes_written = write(fd, wbuff, strlen(wbuff));
printf("\r\nRemote>Wrote to fd = %d, size = %d, content = %s\r\n", fd,
bytes_written, wbuff);
close(fd);
printf("\r\nRemote>Closed fd = %d\r\n", fd);
/* Remote performing file IO on Master */
printf("\r\nRemote>Reading a file on master and displaying its contents..\r\n");
fd = open(fname, REDEF_O_RDONLY, S_IRUSR | S_IWUSR);
printf("\r\nRemote>Opened file '%s' with fd = %d\r\n", fname, fd);
bytes_read = read(fd, rbuff, 1024);
*(char *)(&rbuff[0] + bytes_read + 1) = 0;
printf("\r\nRemote>Read from fd = %d, size = %d, printing contents below .. %s\r\n",
fd, bytes_read, rbuff);
close(fd);
printf("\r\nRemote>Closed fd = %d\r\n", fd);
while (1) {
/* Remote performing STDIO on Master */
printf("\r\nRemote>Remote firmware using scanf and printf ..\r\n");
printf("\r\nRemote>Scanning user input from master..\r\n");
printf("\r\nRemote>Enter name\r\n");
ret = scanf("%s", ubuff);
if (ret) {
printf("\r\nRemote>Enter age\r\n");
ret = scanf("%d", &idata);
if (ret) {
printf("\r\nRemote>Enter value for pi\r\n");
ret = scanf("%f", &fdata);
if (ret) {
printf("\r\nRemote>User name = '%s'\r\n", ubuff);
printf("\r\nRemote>User age = '%d'\r\n", idata);
printf("\r\nRemote>User entered value of pi = '%f'\r\n", fdata);
}
}
}
if (!ret) {
scanf("%s", ubuff);
printf("Remote> Invalid value. Starting again....");
} else {
printf("\r\nRemote>Repeat demo ? (enter yes or no) \r\n");
scanf("%s", ubuff);
if ((strcmp(ubuff, "no")) && (strcmp(ubuff, "yes"))) {
printf("\r\nRemote>Invalid option. Starting again....\r\n");
} else if ((!strcmp(ubuff, "no"))) {
printf("\r\nRemote>RPC retargetting quitting ...\r\n");
break;
}
}
}
printf("\r\nRemote> Firmware's rpmsg-rpc-channel going down! \r\n");
rpccall.id = TERM_SYSCALL_ID;
(void)rpmsg_rpc_send(&rpc, &rpccall, sizeof(rpccall), NULL, 0);
LPRINTF("Release remoteproc procedure call\n");
rpmsg_rpc_release(&rpc);
return 0;
}
/*-----------------------------------------------------------------------------*
* Application entry point
*-----------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
LPRINTF("Starting application...\n");
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_SLAVE,
NULL, NULL);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,371 @@
/* This is a sample demonstration application that showcases usage of proxy from the remote core.
This application is meant to run on the remote CPU running baremetal.
This applicationr can print to to master console and perform file I/O using proxy mechanism. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <openamp/open_amp.h>
#include <openamp/rpmsg_retarget.h>
#include "platform_info.h"
#include "rpmsg-rpc-demo.h"
#define RPC_BUFF_SIZE 496
#define REDEF_O_CREAT 100
#define REDEF_O_EXCL 200
#define REDEF_O_RDONLY 0
#define REDEF_O_WRONLY 1
#define REDEF_O_RDWR 2
#define REDEF_O_APPEND 2000
#define REDEF_O_ACCMODE 3
#define raw_printf(format, ...) printf(format, ##__VA_ARGS__)
#define LPRINTF(format, ...) raw_printf("Master> " format, ##__VA_ARGS__)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
static void *platform;
static struct rpmsg_device *rpdev;
static struct rpmsg_endpoint app_ept;
static int request_termination = 0;
static int ept_deleted = 0;
static int err_cnt = 0;
static void *copy_from_shbuf(void *dst, void *shbuf, int len)
{
void *retdst = dst;
while (len && ((uintptr_t)shbuf % sizeof(int))) {
*(uint8_t *)dst = *(uint8_t *)shbuf;
dst++;
shbuf++;
len--;
}
while (len >= (int)sizeof(int)) {
*(unsigned int *)dst = *(unsigned int *)shbuf;
dst += sizeof(int);
shbuf += sizeof(int);
len -= sizeof(int);
}
while (len > 0) {
*(uint8_t *)dst = *(uint8_t *)shbuf;
dst++;
shbuf++;
len--;
}
return retdst;
}
static int handle_open(struct rpmsg_rpc_syscall *syscall,
struct rpmsg_endpoint *ept)
{
char *buf;
struct rpmsg_rpc_syscall resp;
int fd, ret;
if (!syscall || !ept)
return -EINVAL;
buf = (char *)syscall;
buf += sizeof(*syscall);
/* Open remote fd */
fd = open(buf, syscall->args.int_field1, syscall->args.int_field2);
/* Construct rpc response */
resp.id = OPEN_SYSCALL_ID;
resp.args.int_field1 = fd;
resp.args.int_field2 = 0; /*not used */
resp.args.data_len = 0; /*not used */
/* Transmit rpc response */
ret = rpmsg_send(ept, (void *)&resp, sizeof(resp));
return ret > 0 ? 0 : ret;
}
static int handle_close(struct rpmsg_rpc_syscall *syscall,
struct rpmsg_endpoint *ept)
{
struct rpmsg_rpc_syscall resp;
int ret;
if (!syscall || !ept)
return -EINVAL;
/* Close remote fd */
ret = close(syscall->args.int_field1);
/* Construct rpc response */
resp.id = CLOSE_SYSCALL_ID;
resp.args.int_field1 = ret;
resp.args.int_field2 = 0; /*not used */
resp.args.data_len = 0; /*not used */
/* Transmit rpc response */
ret = rpmsg_send(ept, &resp, sizeof(resp));
return ret > 0 ? 0 : ret;
}
static int handle_read(struct rpmsg_rpc_syscall *syscall,
struct rpmsg_endpoint *ept)
{
struct rpmsg_rpc_syscall *resp;
unsigned char buf[RPC_BUFF_SIZE];
unsigned char *payload;
int bytes_read, payload_size;
int ret;
if (!syscall || !ept)
return -EINVAL;
payload = buf + sizeof(*resp);
if (syscall->args.int_field1 == 0) {
bytes_read = sizeof(buf) - sizeof(*resp);
/* Perform read from fd for large size since this is a
STD/I request */
bytes_read = read(syscall->args.int_field1, payload,
bytes_read);
} else {
/* Perform read from fd */
bytes_read = read(syscall->args.int_field1, payload,
syscall->args.int_field2);
}
/* Construct rpc response */
resp = (struct rpmsg_rpc_syscall *)buf;
resp->id = READ_SYSCALL_ID;
resp->args.int_field1 = bytes_read;
resp->args.int_field2 = 0; /* not used */
resp->args.data_len = bytes_read;
payload_size = sizeof(*resp) +
((bytes_read > 0) ? bytes_read : 0);
/* Transmit rpc response */
ret = rpmsg_send(ept, buf, payload_size);
return ret > 0 ? 0 : ret;
}
static int handle_write(struct rpmsg_rpc_syscall *syscall,
struct rpmsg_endpoint *ept)
{
struct rpmsg_rpc_syscall resp;
unsigned char *buf;
int bytes_written;
int ret;
if (!syscall || !ept)
return -EINVAL;
buf = (unsigned char *)syscall;
buf += sizeof(*syscall);
/* Write to remote fd */
bytes_written = write(syscall->args.int_field1, buf,
syscall->args.int_field2);
/* Construct rpc response */
resp.id = WRITE_SYSCALL_ID;
resp.args.int_field1 = bytes_written;
resp.args.int_field2 = 0; /*not used */
resp.args.data_len = 0; /*not used */
/* Transmit rpc response */
ret = rpmsg_send(ept, (void *)&resp, sizeof(resp));
return ret > 0 ? 0 : ret;
}
static int handle_rpc(struct rpmsg_rpc_syscall *syscall,
struct rpmsg_endpoint *ept)
{
int retval;
/* Handle RPC */
switch (syscall->id) {
case OPEN_SYSCALL_ID:
{
retval = handle_open(syscall, ept);
break;
}
case CLOSE_SYSCALL_ID:
{
retval = handle_close(syscall, ept);
break;
}
case READ_SYSCALL_ID:
{
retval = handle_read(syscall, ept);
break;
}
case WRITE_SYSCALL_ID:
{
retval = handle_write(syscall, ept);
break;
}
case TERM_SYSCALL_ID:
{
LPRINTF("Received termination request\n");
request_termination = 1;
retval = 0;
break;
}
default:
{
LPERROR
("Invalid RPC sys call ID: %d:%d!\n",
(int)syscall->id, (int)WRITE_SYSCALL_ID);
retval = -1;
break;
}
}
return retval;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&app_ept);
LPRINTF("Endpoint is destroyed\n");
ept_deleted = 1;
}
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
unsigned char buf[RPC_BUFF_SIZE];
struct rpmsg_rpc_syscall *syscall;
(void)priv;
(void)src;
if (len < (int)sizeof(*syscall)) {
LPERROR("Received data is less than the rpc structure: %d\n",
len);
err_cnt++;
return RPMSG_SUCCESS;
}
/* In case the shared memory is device memory
* E.g. For now, we only use UIO device memory in Linux.
*/
if (len > RPC_BUFF_SIZE)
len = RPC_BUFF_SIZE;
copy_from_shbuf(buf, data, len);
syscall = (struct rpmsg_rpc_syscall *)buf;
if (handle_rpc(syscall, ept)) {
LPRINTF("\nHandling remote procedure call errors:\n");
raw_printf("rpc id %d\n", syscall->id);
raw_printf("rpc int field1 %d\n",
syscall->args.int_field1);
raw_printf("\nrpc int field2 %d\n",
syscall->args.int_field2);
err_cnt++;
}
return RPMSG_SUCCESS;
}
void terminate_rpc_app()
{
LPRINTF("Destroying endpoint.\n");
if (!ept_deleted)
rpmsg_destroy_ept(&app_ept);
}
void exit_action_handler(int signum)
{
(void)signum;
terminate_rpc_app();
}
void kill_action_handler(int signum)
{
(void)signum;
LPRINTF("RPC service killed !!\n");
terminate_rpc_app();
if (rpdev)
platform_release_rpmsg_vdev(rpdev);
if (platform)
platform_cleanup(platform);
}
/* Application entry point */
int app(struct rpmsg_device *rdev, void *priv)
{
int ret = 0;
struct sigaction exit_action;
struct sigaction kill_action;
/* Initialize signalling infrastructure */
memset(&exit_action, 0, sizeof(struct sigaction));
memset(&kill_action, 0, sizeof(struct sigaction));
exit_action.sa_handler = exit_action_handler;
kill_action.sa_handler = kill_action_handler;
sigaction(SIGTERM, &exit_action, NULL);
sigaction(SIGINT, &exit_action, NULL);
sigaction(SIGKILL, &kill_action, NULL);
sigaction(SIGHUP, &kill_action, NULL);
/* Initialize RPMSG framework */
LPRINTF("Try to create rpmsg endpoint.\n");
ret = rpmsg_create_ept(&app_ept, rdev, RPMSG_SERVICE_NAME,
0, RPMSG_ADDR_ANY, rpmsg_endpoint_cb,
rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create endpoint.\n");
return -EINVAL;
}
LPRINTF("Successfully created rpmsg endpoint.\n");
while(1) {
platform_poll(priv);
if (err_cnt) {
LPERROR("Got error!\n");
ret = -EINVAL;
break;
}
/* we got a shutdown request, exit */
if (ept_deleted || request_termination) {
break;
}
}
LPRINTF("\nRPC service exiting !!\n");
terminate_rpc_app();
return ret;
}
int main(int argc, char *argv[])
{
int ret;
LPRINTF("Starting application...\n");
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_MASTER,
NULL, NULL);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,6 @@
#ifndef RPMSG_RPC_DEMO_H
#define RPMSG_RPC_DEMO_H
#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
#endif /* RPMSG_RPC_DEMO_H */
@@ -0,0 +1,42 @@
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS} -fdata-sections -ffunction-sections")
set (_fw_dir "${APPS_SHARE_DIR}")
collector_list (_list PROJECT_INC_DIRS)
collector_list (_app_list APP_INC_DIRS)
include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
collector_list (_list PROJECT_LIB_DIRS)
collector_list (_app_list APP_LIB_DIRS)
link_directories (${_list} ${_app_list})
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
collector_list (_deps PROJECT_LIB_DEPS)
set (OPENAMP_LIB open_amp)
foreach (_app rpmsg-sample-echo rpmsg-sample-ping)
collector_list (_sources APP_COMMON_SOURCES)
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/${_app}.c")
if (WITH_SHARED_LIB)
add_executable (${_app}-shared ${_sources})
target_link_libraries (${_app}-shared ${OPENAMP_LIB}-shared ${_deps})
install (TARGETS ${_app}-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (WITH_SHARED_LIB)
if (WITH_STATIC_LIB)
if (${PROJECT_SYSTEM} STREQUAL "linux")
add_executable (${_app}-static ${_sources})
target_link_libraries (${_app}-static ${OPENAMP_LIB}-static ${_deps})
install (TARGETS ${_app}-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
else (${PROJECT_SYSTEM})
add_executable (${_app}.out ${_sources})
set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections ${_linker_opt} -Wl,--start-group ${OPENAMP_LIB}-static ${_deps} -Wl,--end-group)
install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (${PROJECT_SYSTEM} STREQUAL "linux" )
endif (WITH_STATIC_LIB)
endforeach(_app)
@@ -0,0 +1,128 @@
/*
* This is a sample demonstration application that showcases usage of rpmsg
* This application is meant to run on the remote CPU running baremetal code.
* This application allows to check the compatibility with linux OS running on
* the master CPU. For this it echo MSG_LIMIT time message sent by the rpmsg
* sample client available in linux kernel distribution.
*/
#include <stdio.h>
#include <openamp/open_amp.h>
#include <metal/alloc.h>
#include "platform_info.h"
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
#define RPMSG_SERV_NAME "rpmsg-client-sample"
#define MSG_LIMIT 100
static struct rpmsg_endpoint lept;
static int shutdown_req = 0;
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
(void)priv;
(void)src;
static uint32_t count = 0;
char payload[RPMSG_BUFFER_SIZE];
/* Send data back MSG_LIMIT time to master */
memset(payload, 0, RPMSG_BUFFER_SIZE);
memcpy(payload, data, len);
if (++count <= MSG_LIMIT) {
LPRINTF("echo message number %u: %s\n",
(unsigned int)count, payload);
if (rpmsg_send(ept, (char *)data, len) < 0) {
LPERROR("rpmsg_send failed\n");
goto destroy_ept;
}
if (count == MSG_LIMIT) {
goto destroy_ept;
}
}
return RPMSG_SUCCESS;
destroy_ept:
shutdown_req = 1;
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
LPRINTF("unexpected Remote endpoint destroy\n");
shutdown_req = 1;
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app(struct rpmsg_device *rdev, void *priv)
{
int ret;
/* Initialize RPMSG framework */
LPRINTF("Try to create rpmsg endpoint.\n");
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERV_NAME, 0, RPMSG_ADDR_ANY,
rpmsg_endpoint_cb, rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create endpoint.\n");
return -1;
}
LPRINTF("Successfully created rpmsg endpoint.\n");
while (1) {
platform_poll(priv);
/* we got a shutdown request, exit */
if (shutdown_req) {
break;
}
}
rpmsg_destroy_ept(&lept);
return 0;
}
/*-----------------------------------------------------------------------------*
* Application entry point
*-----------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
LPRINTF("Starting application...\n");
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_SLAVE,
NULL, NULL);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,180 @@
/*
* This is a sample demonstration application that showcases usage of rpmsg
* This application is meant to run on the remote CPU running baremetal code.
* This application simulate linux sample rpmsg driver. For this it echo 100
* time message sent by the rpmsg sample client available in linux kernel
* distribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openamp/open_amp.h>
#include <metal/alloc.h>
#include "platform_info.h"
#define RPMSG_SERV_NAME "rpmsg-client-sample"
#define HELLO_MSG "hello world!"
#define BYE_MSG "goodbye!"
#define MSG_LIMIT 100
#define APP_EPT_ADDR 0
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
static int err_cnt;
/* Globals */
static struct rpmsg_endpoint lept;
static int rnum = 0;
static int err_cnt = 0;
static int ept_deleted = 0;
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
char payload[RPMSG_BUFFER_SIZE];
char seed[20];
(void)ept;
(void)src;
(void)priv;
memset(payload, 0, RPMSG_BUFFER_SIZE);
memcpy(payload, data, len);
LPRINTF("received message %d: %s of size %lu \r\n",
rnum + 1, payload, (unsigned long)len);
if (rnum == (MSG_LIMIT - 1))
sprintf (seed, "%s", BYE_MSG);
else
sprintf (seed, "%s", HELLO_MSG);
LPRINTF(" seed %s: \r\n", seed);
if (strncmp(payload, seed, len)) {
LPERROR(" Invalid message is received.\n");
err_cnt++;
return RPMSG_SUCCESS;
}
LPRINTF(" rnum %d: \r\n", rnum);
rnum++;
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&lept);
LPRINTF("echo test: service is destroyed\n");
ept_deleted = 1;
}
static void rpmsg_name_service_bind_cb(struct rpmsg_device *rdev,
const char *name, uint32_t dest)
{
LPRINTF("new endpoint notification is received.\n");
if (strcmp(name, RPMSG_SERV_NAME))
LPERROR("Unexpected name service %s.\n", name);
else
(void)rpmsg_create_ept(&lept, rdev, RPMSG_SERV_NAME,
APP_EPT_ADDR, dest,
rpmsg_endpoint_cb,
rpmsg_service_unbind);
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app(struct rpmsg_device *rdev, void *priv)
{
int ret;
int i;
LPRINTF(" 1 - Send data to remote core, retrieve the echo");
LPRINTF(" and validate its integrity ..\n");
/* Create RPMsg endpoint */
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERV_NAME, APP_EPT_ADDR,
RPMSG_ADDR_ANY,
rpmsg_endpoint_cb, rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create RPMsg endpoint.\n");
return ret;
}
while (!is_rpmsg_ept_ready(&lept))
platform_poll(priv);
LPRINTF("RPMSG endpoint is binded with remote.\n");
for (i = 1; i <= MSG_LIMIT; i++) {
if (i < MSG_LIMIT)
ret = rpmsg_send(&lept, HELLO_MSG, strlen(HELLO_MSG));
else
ret = rpmsg_send(&lept, BYE_MSG, strlen(BYE_MSG));
if (ret < 0) {
LPERROR("Failed to send data...\n");
break;
}
LPRINTF("rpmsg sample test: message %d sent\n", i);
do {
platform_poll(priv);
} while ((rnum < i) && !err_cnt);
}
LPRINTF("**********************************\n");
LPRINTF(" Test Results: Error count = %d\n", err_cnt);
LPRINTF("**********************************\n");
while (!ept_deleted)
platform_poll(priv);
LPRINTF("Quitting application .. rpmsg sample test end\n");
return 0;
}
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_MASTER,
NULL,
rpmsg_name_service_bind_cb);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,3 @@
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")
add_subdirectory (${PROJECT_MACHINE})
endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")
@@ -0,0 +1,6 @@
collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
collect (APP_COMMON_SOURCES platform_info.c)
collect (APP_COMMON_SOURCES rsc_table.c)
collect (APP_COMMON_SOURCES zynq_a9_rproc.c)
@@ -0,0 +1,261 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation. All rights reserved.
* Copyright (c) 2017 - 2018 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 <openamp/remoteproc.h>
#include <openamp/rpmsg_virtio.h>
#include <metal/atomic.h>
#include <metal/device.h>
#include <metal/io.h>
#include <metal/irq.h>
#include <metal/sys.h>
#include "platform_info.h"
#include "rsc_table.h"
#include <xparameters.h>
/* Another APU core ID. In this demo, the other APU core is 0. */
#define A9_CPU_ID 0UL
/* scugic device, used to raise soft irq */
#define SCUGIC_DEV_NAME "scugic_dev"
#define SCUGIC_BUS_NAME "generic"
/* scugic base address */
#define SCUGIC_PERIPH_BASE 0xF8F00000
#define SCUGIC_DIST_BASE (SCUGIC_PERIPH_BASE + 0x00001000)
#define _rproc_wait() asm volatile("wfi")
/* processor operations for hil_proc for A9. It defines
* notification operation and remote processor management. */
extern struct remoteproc_ops zynq_a9_proc_ops;
static metal_phys_addr_t scugic_phys_addr = SCUGIC_DIST_BASE;
struct metal_device scugic_device = {
.name = SCUGIC_DEV_NAME,
.bus = NULL,
.num_regions = 1,
.regions = {
{
.virt = (void *)SCUGIC_DIST_BASE,
.physmap = &scugic_phys_addr,
.size = 0x1000,
.page_shift = -1UL,
.page_mask = -1UL,
.mem_flags = DEVICE_MEMORY,
.ops = {NULL},
},
},
.node = {NULL},
.irq_num = 0,
.irq_info = NULL,
};
/* Remoteproc private data */
static struct remoteproc_priv rproc_priv = {
.gic_name = SCUGIC_DEV_NAME,
.gic_bus_name = SCUGIC_BUS_NAME,
.gic_dev = NULL,
.gic_io = NULL,
.irq_to_notify = SGI_TO_NOTIFY,
.irq_notification = SGI_NOTIFICATION,
/* toggle CPU ID, there is only two CPUs in PS */
.cpu_id = (~XPAR_CPU_ID) & ZYNQ_CPU_ID_MASK,
};
/* Remoteproc instance */
static struct remoteproc rproc_inst;
/* External functions */
extern int init_system(void);
extern void cleanup_system(void);
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);
/* Register IPI device */
(void)metal_register_generic_device(&scugic_device);
/* Initialize remoteproc instance */
if (!remoteproc_init(&rproc_inst, &zynq_a9_proc_ops, &rproc_priv))
return NULL;
/*
* Mmap shared memories
* Or shall we constraint that they will be set as carved out
* in the resource table?
*/
/* mmap resource table */
pa = (metal_phys_addr_t)rsc_table;
(void *)remoteproc_mmap(&rproc_inst, &pa,
NULL, rsc_size,
NORM_NONCACHE | STRONG_ORDERED,
&rproc_inst.rsc_io);
/* mmap shared memory */
pa = SHARED_MEM_PA;
(void *)remoteproc_mmap(&rproc_inst, &pa,
NULL, SHARED_MEM_SIZE,
NORM_NONCACHE | STRONG_ORDERED,
NULL);
/* parse resource table to remoteproc */
ret = remoteproc_set_rsc_table(&rproc_inst, rsc_table, rsc_size);
if (ret) {
xil_printf("Failed to intialize remoteproc\r\n");
remoteproc_remove(&rproc_inst);
return NULL;
}
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.\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.\n");
return -EINVAL;
}
*platform = rproc;
return 0;
}
/* RPMsg virtio shared buffer pool */
static struct rpmsg_virtio_shm_pool shpool;
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)
return NULL;
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 vdev\r\n");
if (role == VIRTIO_DEV_MASTER) {
/* Only RPMsg virtio master needs to initialize the
* shared buffers pool
*/
rpmsg_virtio_init_shm_pool(&shpool, shbuf,
(SHARED_MEM_SIZE -
SHARED_BUF_OFFSET));
/* RPMsg virtio slave can set shared buffers pool
* argument to NULL
*/
ret = rpmsg_init_vdev(rpmsg_vdev, vdev, ns_bind_cb,
shbuf_io, &shpool);
} else {
ret = rpmsg_init_vdev(rpmsg_vdev, vdev, ns_bind_cb,
shbuf_io, NULL);
}
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;
struct remoteproc_priv *prproc;
unsigned int flags;
prproc = rproc->priv;
while(1) {
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&prproc->nokick))) {
metal_irq_restore_enable(flags);
remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY);
break;
}
_rproc_wait();
metal_irq_restore_enable(flags);
}
return 0;
}
void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev)
{
(void)rpdev;
}
void platform_cleanup(void *platform)
{
struct remoteproc *rproc = platform;
if (rproc)
remoteproc_remove(rproc);
cleanup_system();
}
@@ -0,0 +1,107 @@
#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
/* SGIs */
#define SGI_TO_NOTIFY 15 /* SGI to notify the remote */
#define SGI_NOTIFICATION 14 /* SGI from the remote */
/* Memory attributes */
#define NORM_NONCACHE 0x11DE2 /* Normal Non-cacheable */
#define STRONG_ORDERED 0xC02 /* Strongly ordered */
#define DEVICE_MEMORY 0xC06 /* Device memory */
#define RESERVED 0x0 /* reserved memory */
/* Shared memory */
#define SHARED_MEM_PA 0x3e800000UL
#define SHARED_MEM_SIZE 0x80000UL
#define SHARED_BUF_OFFSET 0x80000UL
/* Zynq CPU ID mask */
#define ZYNQ_CPU_ID_MASK 0x1UL
/* Remoteproc private data struct */
struct remoteproc_priv {
const char *gic_name; /* SCUGIC device name */
const char *gic_bus_name; /* SCUGIC bus name */
struct metal_device *gic_dev; /* pointer to SCUGIC device */
struct metal_io_region *gic_io; /* pointer to SCUGIC i/o region */
unsigned int irq_to_notify; /* SCUGIC IRQ vector to notify the
* other end.
*/
unsigned int irq_notification; /* SCUGIC IRQ vector received from
* other end.
*/
unsigned int cpu_id; /* CPU ID */
atomic_int nokick; /* 0 for kick from other side */
};
/**
* platform_init - initialize the platform
*
* It will initialize the platform.
*
* @argc: number of arguments
* @argv: array of the input arguements
* @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
*
* It will create rpmsg virtio device, and returns 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_ */
@@ -0,0 +1,157 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* platform_info.c
*
* DESCRIPTION
*
* This file implements APIs to get platform specific
* information for OpenAMP.
*
**************************************************************************/
#include <string.h>
#include <openamp/hil.h>
#include <openamp/firmware.h>
/* Reference implementation that show cases platform_get_cpu_info and
platform_get_for_firmware API implementation for Bare metal environment */
extern struct hil_platform_ops zynq_a9_proc_ops;
/* IPC Device parameters */
#define SHM_ADDR (void *)0x08008000
#define SHM_SIZE 0x00200000
#define VRING0_IPI_VECT 6
#define VRING1_IPI_VECT 3
#define MASTER_CPU_ID 0
#define REMOTE_CPU_ID 1
/**
* This array provdes defnition of CPU nodes for master and remote
* context. It contains two nodes beacuse the same file is intended
* to use with both master and remote configurations. On zynq platform
* only one node defintion is required for master/remote as there
* are only two cores present in the platform.
*
* Only platform specific info is populated here. Rest of information
* is obtained during resource table parsing.The platform specific
* information includes;
*
* -CPU ID
* -Shared Memory
* -Interrupts
* -Channel info.
*
* Although the channel info is not platform specific information
* but it is conveneient to keep it in HIL so that user can easily
* provide it without modifying the generic part.
*
* It is good idea to define hil_proc structure with platform
* specific fields populated as this can be easily copied to hil_proc
* structure passed as parameter in platform_get_processor_info. The
* other option is to populate the required structures individually
* and copy them one by one to hil_proc structure in platform_get_processor_info
* function. The first option is adopted here.
*
*
* 1) First node in the array is intended for the remote contexts and it
* defines Master CPU ID, shared memory, interrupts info, number of channels
* and there names. This node defines only one channel
* "rpmsg-openamp-demo-channel".
*
* 2)Second node is required by the master and it defines remote CPU ID,
* shared memory and interrupts info. In general no channel info is required by the
* Master node, however in baremetal master and linux remote case the linux
* rpmsg bus driver behaves as master so the rpmsg driver on linux side still needs
* channel info. This information is not required by the masters for baremetal
* remotes.
*
*/
struct hil_proc proc_table []=
{
{
/* CPU ID of remote */
REMOTE_CPU_ID,
/* Shared memory info - Last field is not used currently */
{
SHM_ADDR, SHM_SIZE, 0x00
},
/* VirtIO device info */
{
0, 0, 0,
{
{
/* Provide vring interrupts info here. Other fields are obtained
* from the rsc table so leave them empty.
*/
NULL, NULL, 0, 0,
{
VRING0_IPI_VECT,0x1006,1
}
},
{
NULL, NULL, 0, 0,
{
VRING1_IPI_VECT,0x1006,1
}
}
}
},
/* Number of RPMSG channels */
1,
/* RPMSG channel info - Only channel name is expected currently */
{
{"rpmsg-openamp-demo-channel"}
},
/* HIL platform ops table. */
&zynq_a9_proc_ops,
/* Next three fields are for future use only */
0,
0,
NULL
}
};
/* Start and end addresses of firmware image for remotes. These are defined in the
* object files that are obtained by converting the remote ELF Image into object
* files. These symbols are not used for remotes.
*/
extern unsigned char _binary_firmware1_start;
extern unsigned char _binary_firmware1_end;
extern unsigned char _binary_firmware2_start;
extern unsigned char _binary_firmware2_end;
#define FIRMWARE1_START (void *)&_binary_firmware1_start
#define FIRMWARE1_END (void *)&_binary_firmware1_end
#define FIRMWARE2_START (void *)&_binary_firmware2_start
#define FIRMWARE2_END (void *)&_binary_firmware2_end
/* Init firmware table */
const struct firmware_info fw_table[] =
{
{"firmware1",
(unsigned int)FIRMWARE1_START,
(unsigned int)FIRMWARE1_END},
{"firmware2",
(unsigned int)FIRMWARE2_START,
(unsigned int)FIRMWARE2_END}
};
int fw_table_size = sizeof(fw_table)/sizeof(struct firmware_info);
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 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"
#include "platform_info.h"
/* Place resource table in special ELF section */
/* Redefine __section for section name with token */
#define __section_t(S) __attribute__((__section__(#S)))
#define __resource __section_t(.resource_table)
#define RPMSG_IPU_C0_FEATURES 1
/* VirtIO rpmsg device id */
#define VIRTIO_ID_RPMSG_ 7
/* Remote supports Name Service announcement */
#define VIRTIO_RPMSG_F_NS 0
/* Resource table entries */
#define NUM_VRINGS 0x02
#define VRING_ALIGN 0x1000
#define RING_TX 0x08000000
#define RING_RX 0x08004000
#define VRING_SIZE 256
#define NUM_TABLE_ENTRIES 2
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, rproc_mem),
offsetof(struct remote_resource_table, rpmsg_vdev),
},
{RSC_RPROC_MEM, SHARED_MEM_PA, SHARED_MEM_PA, SHARED_MEM_SIZE, 0},
/* 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;
}
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 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 */
#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 remote_resource_table {
unsigned int version;
unsigned int num;
unsigned int reserved[2];
unsigned int offset[NO_RESOURCE_ENTRIES];
/* rproc memory entry */
struct fw_rsc_rproc_mem rproc_mem;
/* rpmsg vdev entry */
struct fw_rsc_vdev rpmsg_vdev;
struct fw_rsc_vdev_vring rpmsg_vring0;
struct fw_rsc_vdev_vring rpmsg_vring1;
}__attribute__((packed, aligned(0x100000)));
void *get_resource_table (int rsc_id, int *len);
#if defined __cplusplus
}
#endif
#endif /* RSC_TABLE_H_ */
@@ -0,0 +1,168 @@
/*
* Copyright (c) 2018 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* zynq_a9_rproc.c
*
* DESCRIPTION
*
* This file define Xilinx Zynq A9 platform specific remoteproc
* implementation.
*
**************************************************************************/
#include <openamp/remoteproc.h>
#include <metal/atomic.h>
#include <metal/device.h>
#include <metal/irq.h>
#include <platform_info.h>
#include <xil_printf.h>
/* SCUGIC macros */
#define GIC_DIST_SOFTINT 0xF00
#define GIC_SFI_TRIG_CPU_MASK 0x00FF0000
#define GIC_SFI_TRIG_SATT_MASK 0x00008000
#define GIC_SFI_TRIG_INTID_MASK 0x0000000F
#define GIC_CPU_ID_BASE (1 << 4)
static int zynq_a9_proc_irq_handler(int vect_id, void *data)
{
struct remoteproc *rproc = data;
struct remoteproc_priv *prproc;
(void)vect_id;
if (!rproc)
return METAL_IRQ_NOT_HANDLED;
prproc = rproc->priv;
atomic_flag_clear(&prproc->nokick);
return METAL_IRQ_HANDLED;
}
static struct remoteproc *
zynq_a9_proc_init(struct remoteproc *rproc,
struct remoteproc_ops *ops, void *arg)
{
struct remoteproc_priv *prproc = arg;
struct metal_device *dev;
unsigned int irq_vect;
int ret;
if (!rproc || !prproc || !ops)
return NULL;
ret = metal_device_open(prproc->gic_bus_name, prproc->gic_name,
&dev);
if (ret) {
xil_printf("failed to open GIC device: %d.\r\n", ret);
return NULL;
}
rproc->priv = prproc;
prproc->gic_dev = dev;
prproc->gic_io = metal_device_io_region(dev, 0);
if (!prproc->gic_io)
goto err1;
rproc->ops = ops;
atomic_flag_test_and_set(&prproc->nokick);
/* Register interrupt handler and enable interrupt */
irq_vect = prproc->irq_notification;
metal_irq_register(irq_vect, zynq_a9_proc_irq_handler, NULL, rproc);
metal_irq_enable(irq_vect);
xil_printf("Successfully intialize remoteproc.\r\n");
return rproc;
err1:
metal_device_close(dev);
return NULL;
}
static void zynq_a9_proc_remove(struct remoteproc *rproc)
{
struct remoteproc_priv *prproc;
struct metal_device *dev;
if (!rproc)
return;
prproc = rproc->priv;
metal_irq_disable(prproc->irq_to_notify);
metal_irq_unregister(prproc->irq_to_notify, NULL, NULL, NULL);
dev = prproc->gic_dev;
if (dev)
metal_device_close(dev);
}
static void *
zynq_a9_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;
if (!attribute)
attribute = NORM_NONCACHE | STRONG_ORDERED;
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;
return metal_io_phys_to_virt(tmpio, mem->pa);
}
static int zynq_a9_proc_notify(struct remoteproc *rproc, uint32_t id)
{
struct remoteproc_priv *prproc;
unsigned long mask = 0;
(void)id;
if (!rproc)
return -1;
prproc = rproc->priv;
if (!prproc->gic_io)
return -1;
mask = ((1 << (GIC_CPU_ID_BASE + prproc->cpu_id)) |
(prproc->irq_to_notify))
& (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
/* Trigger IPI */
metal_io_write32(prproc->gic_io, GIC_DIST_SOFTINT, mask);
return 0;
}
/* processor operations from r5 to a53. It defines
* notification operation and remote processor managementi operations. */
struct remoteproc_ops zynq_a9_proc_ops = {
.init = zynq_a9_proc_init,
.remove = zynq_a9_proc_remove,
.mmap = zynq_a9_proc_mmap,
.notify = zynq_a9_proc_notify,
.start = NULL,
.stop = NULL,
.shutdown = NULL,
};
@@ -0,0 +1,4 @@
collect (APP_COMMON_SOURCES platform_info.c)
collect (APP_COMMON_SOURCES zynqmp_linux_r5_proc.c)
collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
@@ -0,0 +1,29 @@
/ {
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
rproc_0_reserved: rproc@3ed000000 {
no-map;
reg = <0x0 0x3ed00000 0x0 0x1000000>;
};
};
amba {
vring: vring@0 {
compatible = "vring_uio";
reg = <0x0 0x3ed40000 0x0 0x40000>;
};
shm0: shm@0 {
compatible = "shm_uio";
reg = <0x0 0x3ed80000 0x0 0x80000>;
};
ipi0: ipi@0 {
compatible = "ipi_uio";
reg = <0x0 0xff340000 0x0 0x1000>;
interrupt-parent = <&gic>;
interrupts = <0 29 4>;
};
};
};
@@ -0,0 +1,232 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2017 Xilinx, Inc.
*
* 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/alloc.h>
#include <metal/atomic.h>
#include <metal/io.h>
#include <metal/irq.h>
#include <metal/device.h>
#include <metal/utilities.h>
#include <openamp/remoteproc.h>
#include <openamp/rpmsg_virtio.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/un.h>
#include "platform_info.h"
#define RPU_CPU_ID 0 /* RPU remote CPU Index. We only talk to
* one CPU in the exmaple. We set the CPU
* index to 0. */
#define IPI_CHN_BITMASK 0x00000100 /* IPI channel bit mask for IPI
* from/to RPU0 */
#define DEV_BUS_NAME "platform" /* device bus name. "platform" bus
* is used in Linux kernel for generic
* devices */
/* libmetal devices names used in the examples.
* They are platform devices, you find them in Linux sysfs
* sys/bus/platform/devices */
#define IPI_DEV_NAME "ff340000.ipi" /* IPI device name */
#define SHM_DEV_NAME "3ed20000.shm" /* shared device name */
#define RSC_MEM_PA 0x3ED20000UL
#define RSC_MEM_SIZE 0x2000UL
#define VRING_MEM_PA 0x3ED40000UL
#define VRING_MEM_SIZE 0x8000UL
#define SHARED_BUF_PA 0x3ED48000UL
#define SHARED_BUF_SIZE 0x40000UL
struct remoteproc_priv rproc_priv = {
.ipi_name = IPI_DEV_NAME,
.ipi_bus_name = DEV_BUS_NAME,
.ipi_chn_mask = IPI_CHN_BITMASK,
.shm_name = SHM_DEV_NAME,
.shm_bus_name = DEV_BUS_NAME,
};
static struct remoteproc rproc_inst;
/* External functions */
extern int init_system(void);
extern void cleanup_system(void);
#define _rproc_wait() metal_cpu_yield()
/* processor operations from r5 to a53. It defines
* notification operation and remote processor managementi operations. */
extern struct remoteproc_ops zynqmp_linux_r5_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;
(void)rsc_index;
rsc_size = RSC_MEM_SIZE;
/* Initialize remoteproc instance */
if (!remoteproc_init(&rproc_inst, &zynqmp_linux_r5_proc_ops,
&rproc_priv))
return NULL;
printf("Successfully initialized remoteproc\n");
/* Mmap resource table */
pa = RSC_MEM_PA;
printf("Calling mmap resource table.\n");
rsc_table = remoteproc_mmap(&rproc_inst, &pa, NULL, rsc_size,
0, NULL);
if (!rsc_table) {
fprintf(stderr, "ERROR: Failed to mmap resource table.\n");
return NULL;
}
printf("Successfully mmap resource table.\n");
/* parse resource table to remoteproc */
ret = remoteproc_set_rsc_table(&rproc_inst, rsc_table, rsc_size);
if (ret) {
printf("Failed to intialize remoteproc\n");
remoteproc_remove(&rproc_inst);
return NULL;
}
printf("Successfully set resource table to remoteproc.\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) {
fprintf(stderr, "Failed to initialize platform, NULL pointer"
"to store platform data.\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) {
fprintf(stderr, "Failed to create remoteproc device.\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_BUF_PA);
if (!shbuf_io)
return NULL;
shbuf = metal_io_phys_to_virt(shbuf_io,
SHARED_BUF_PA);
printf("Creating virtio...\n");
/* TODO: can we have a wrapper for the following two functions? */
vdev = remoteproc_create_virtio(rproc, vdev_index, role, rst_cb);
if (!vdev) {
printf("failed remoteproc_create_virtio\n");
goto err1;
}
printf("Successfully created virtio device.\n");
/* Only RPMsg virtio master needs to initialize the shared buffers pool */
rpmsg_virtio_init_shm_pool(&shpool, shbuf, SHARED_BUF_SIZE);
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) {
printf("failed rpmsg_init_vdev\r\n");
goto err2;
}
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;
struct remoteproc_priv *prproc;
unsigned int flags;
prproc = rproc->priv;
while(1) {
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&prproc->ipi_nokick))) {
metal_irq_restore_enable(flags);
remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY);
break;
}
_rproc_wait();
metal_irq_restore_enable(flags);
}
return 0;
}
void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev)
{
(void)rpdev;
}
void platform_cleanup(void *platform)
{
struct remoteproc *rproc = platform;
if (rproc)
remoteproc_remove(rproc);
cleanup_system();
}
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2016 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 */
#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
struct remoteproc_priv {
const char *ipi_name; /**< IPI device name */
const char *ipi_bus_name; /**< IPI bus name */
const char *rsc_name; /**< rsc device name */
const char *rsc_bus_name; /**< rsc bus name */
const char *shm_name; /**< shared memory device name */
const char *shm_bus_name; /**< shared memory bus name */
struct metal_device *ipi_dev; /**< pointer to IPI device */
struct metal_io_region *ipi_io; /**< pointer to IPI i/o region */
struct metal_device *shm_dev; /**< pointer to shared memory device */
struct metal_io_region *shm_io; /**< pointer to shared memory i/o
region */
struct remoteproc_mem shm_mem; /**< shared memory */
unsigned int ipi_chn_mask; /**< IPI channel mask */
atomic_int ipi_nokick;
};
/**
* platform_init - initialize the platform
*
* It will initialize the platform.
*
* @argc: number of arguments
* @argv: array of the input arguements
* @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
*
* It will create rpmsg virtio device, and returns 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_ */
@@ -0,0 +1,207 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2017 Xilinx, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* platform_info.c
*
* DESCRIPTION
*
* This file define Xilinx ZynqMP R5 to A53 platform specific
* remoteproc implementation.
*
**************************************************************************/
#include <metal/alloc.h>
#include <metal/atomic.h>
#include <metal/io.h>
#include <metal/irq.h>
#include <metal/device.h>
#include <metal/utilities.h>
#include <openamp/remoteproc.h>
#include <openamp/rpmsg_virtio.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/un.h>
#include "platform_info.h"
/* IPI REGs OFFSET */
#define IPI_TRIG_OFFSET 0x00000000 /* IPI trigger register offset */
#define IPI_OBS_OFFSET 0x00000004 /* IPI observation register offset */
#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */
#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */
#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */
#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */
static int zynqmp_linux_r5_proc_irq_handler(int vect_id, void *data)
{
struct remoteproc *rproc = data;
struct remoteproc_priv *prproc;
unsigned int ipi_intr_status;
(void)vect_id;
if (!rproc)
return METAL_IRQ_NOT_HANDLED;
prproc = rproc->priv;
ipi_intr_status = (unsigned int)metal_io_read32(prproc->ipi_io,
IPI_ISR_OFFSET);
if (ipi_intr_status & prproc->ipi_chn_mask) {
atomic_flag_clear(&prproc->ipi_nokick);
metal_io_write32(prproc->ipi_io, IPI_ISR_OFFSET,
prproc->ipi_chn_mask);
return METAL_IRQ_HANDLED;
}
return METAL_IRQ_NOT_HANDLED;
}
static struct remoteproc *
zynqmp_linux_r5_proc_init(struct remoteproc *rproc,
struct remoteproc_ops *ops, void *arg)
{
struct remoteproc_priv *prproc = arg;
struct metal_device *dev;
unsigned int irq_vect;
metal_phys_addr_t mem_pa;
int ret;
if (!rproc || !prproc || !ops)
return NULL;
rproc->priv = prproc;
rproc->ops = ops;
prproc->ipi_dev = NULL;
prproc->shm_dev = NULL;
/* Get shared memory device */
ret = metal_device_open(prproc->shm_bus_name, prproc->shm_name,
&dev);
if (ret) {
fprintf(stderr, "ERROR: failed to open shm device: %d.\n", ret);
goto err1;
}
printf("Successfully open shm device.\n");
prproc->shm_dev = dev;
prproc->shm_io = metal_device_io_region(dev, 0);
if (!prproc->shm_io)
goto err2;
mem_pa = metal_io_phys(prproc->shm_io, 0);
remoteproc_init_mem(&prproc->shm_mem, "shm", mem_pa, mem_pa,
metal_io_region_size(prproc->shm_io),
prproc->shm_io);
remoteproc_add_mem(rproc, &prproc->shm_mem);
printf("Successfully added shared memory\n");
/* Get IPI device */
ret = metal_device_open(prproc->ipi_bus_name, prproc->ipi_name,
&dev);
if (ret) {
printf("failed to open ipi device: %d.\n", ret);
goto err2;
}
prproc->ipi_dev = dev;
prproc->ipi_io = metal_device_io_region(dev, 0);
if (!prproc->ipi_io)
goto err3;
printf("Successfully probed IPI device\n");
atomic_store(&prproc->ipi_nokick, 1);
/* Register interrupt handler and enable interrupt */
irq_vect = (uintptr_t)dev->irq_info;
metal_irq_register(irq_vect, zynqmp_linux_r5_proc_irq_handler,
dev, rproc);
metal_irq_enable(irq_vect);
metal_io_write32(prproc->ipi_io, IPI_IER_OFFSET,
prproc->ipi_chn_mask);
printf("Successfully initialized Linux r5 remoteproc.\n");
return rproc;
err3:
metal_device_close(prproc->ipi_dev);
err2:
metal_device_close(prproc->shm_dev);
err1:
return NULL;
}
static void zynqmp_linux_r5_proc_remove(struct remoteproc *rproc)
{
struct remoteproc_priv *prproc;
struct metal_device *dev;
if (!rproc)
return;
prproc = rproc->priv;
metal_io_write32(prproc->ipi_io, IPI_IDR_OFFSET, prproc->ipi_chn_mask);
dev = prproc->ipi_dev;
if (dev) {
metal_irq_disable((uintptr_t)dev->irq_info);
metal_irq_unregister((uintptr_t)dev->irq_info, NULL, NULL,
NULL);
metal_device_close(dev);
}
if (prproc->shm_dev)
metal_device_close(prproc->shm_dev);
}
static void *
zynqmp_linux_r5_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_priv *prproc;
metal_phys_addr_t lpa, lda;
struct metal_io_region *tmpio;
(void)attribute;
(void)size;
if (!rproc)
return NULL;
prproc = rproc->priv;
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;
tmpio = prproc->shm_io;
if (!tmpio)
return NULL;
*pa = lpa;
*da = lda;
if (io)
*io = tmpio;
return metal_io_phys_to_virt(tmpio, lpa);
}
static int zynqmp_linux_r5_proc_notify(struct remoteproc *rproc, uint32_t id)
{
struct remoteproc_priv *prproc;
(void)id;
if (!rproc)
return -1;
prproc = rproc->priv;
/* TODO: use IPI driver instead and pass ID */
metal_io_write32(prproc->ipi_io, IPI_TRIG_OFFSET,
prproc->ipi_chn_mask);
return 0;
}
/* processor operations from r5 to a53. It defines
* notification operation and remote processor managementi operations. */
struct remoteproc_ops zynqmp_linux_r5_proc_ops = {
.init = zynqmp_linux_r5_proc_init,
.remove = zynqmp_linux_r5_proc_remove,
.mmap = zynqmp_linux_r5_proc_mmap,
.notify = zynqmp_linux_r5_proc_notify,
.start = NULL,
.stop = NULL,
.shutdown = NULL,
};
@@ -0,0 +1,5 @@
collect (APP_COMMON_SOURCES platform_info.c)
collect (APP_COMMON_SOURCES rsc_table.c)
collect (APP_COMMON_SOURCES zynqmp_r5_a53_rproc.c)
collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
@@ -0,0 +1,254 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2017 Xilinx, Inc.
*
* 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 IPI_DEV_NAME "ipi_dev"
#define IPI_BUS_NAME "generic"
#define IPI_BASE_ADDR XPAR_XIPIPSU_0_BASE_ADDRESS /* IPI base address*/
#define IPI_CHN_BITMASK 0x01000000 /* IPI channel bit mask for IPI from/to
APU */
/* Cortex R5 memory attributes */
#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 SHARED_MEM_PA 0x3ED40000UL
#define SHARED_MEM_SIZE 0x100000UL
#define SHARED_BUF_OFFSET 0x8000UL
#define _rproc_wait() asm volatile("wfi")
/* IPI information used by remoteproc operations.
*/
static metal_phys_addr_t ipi_phys_addr = IPI_BASE_ADDR;
struct metal_device ipi_device = {
.name = "ipi_dev",
.bus = NULL,
.num_regions = 1,
.regions = {
{
.virt = (void*)IPI_BASE_ADDR,
.physmap = &ipi_phys_addr,
.size = 0x1000,
.page_shift = -1UL,
.page_mask = -1UL,
.mem_flags = DEVICE_NONSHARED | PRIV_RW_USER_RW,
.ops = {NULL},
}
},
.node = {NULL},
.irq_num = 1,
.irq_info = (void *)IPI_IRQ_VECT_ID,
};
static struct remoteproc_priv rproc_priv = {
.ipi_name = IPI_DEV_NAME,
.ipi_bus_name = IPI_BUS_NAME,
.ipi_chn_mask = IPI_CHN_BITMASK,
};
static struct remoteproc rproc_inst;
/* External functions */
extern int init_system(void);
extern void cleanup_system(void);
/* processor operations from r5 to a53. It defines
* notification operation and remote processor managementi operations. */
extern struct remoteproc_ops zynqmp_r5_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);
/* Register IPI device */
(void)metal_register_generic_device(&ipi_device);
/* Initialize remoteproc instance */
if (!remoteproc_init(&rproc_inst, &zynqmp_r5_a53_proc_ops, &rproc_priv))
return NULL;
/*
* Mmap shared memories
* Or shall we constraint that they will be set as carved out
* in the resource table?
*/
/* 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 intialize remoteproc\r\n");
remoteproc_remove(&rproc_inst);
return NULL;
}
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.\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.\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)
return NULL;
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;
struct remoteproc_priv *prproc;
unsigned int flags;
prproc = rproc->priv;
while(1) {
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&prproc->ipi_nokick))) {
metal_irq_restore_enable(flags);
remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY);
break;
}
_rproc_wait();
metal_irq_restore_enable(flags);
}
return 0;
}
void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev)
{
(void)rpdev;
}
void platform_cleanup(void *platform)
{
struct remoteproc *rproc = platform;
if (rproc)
remoteproc_remove(rproc);
cleanup_system();
}
@@ -0,0 +1,92 @@
#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
/* Cortex R5 memory attributes */
#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 */
/* Interrupt vectors */
#define IPI_IRQ_VECT_ID XPAR_XIPIPSU_0_INT_ID
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
*
* It will initialize the platform.
*
* @argc: number of arguments
* @argv: array of the input arguements
* @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
*
* It will create rpmsg virtio device, and returns 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_ */
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 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
/* VirtIO rpmsg device id */
#define VIRTIO_ID_RPMSG_ 7
/* Remote supports Name Service announcement */
#define VIRTIO_RPMSG_F_NS 0
#define NUM_VRINGS 0x02
#define VRING_ALIGN 0x1000
#define RING_TX 0x3ED40000
#define RING_RX 0x3ED44000
#define VRING_SIZE 256
#define NUM_TABLE_ENTRIES 3
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, rproc_mem),
offsetof(struct remote_resource_table, fw_chksum),
offsetof(struct remote_resource_table, rpmsg_vdev),
},
{RSC_RPROC_MEM, 0x3ed40000, 0x3ed40000, 0x100000, 0},
/* firmware checksum */
{RSC_FW_CHKSUM, "sha256", {0}},
/* 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;
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* Copyright (C) 2015 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 */
#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 remote_resource_table {
unsigned int version;
unsigned int num;
unsigned int reserved[2];
unsigned int offset[NO_RESOURCE_ENTRIES];
/* rproc memory entry */
struct fw_rsc_rproc_mem rproc_mem;
/* firmware checksum */
struct fw_rsc_fw_chksum fw_chksum;
/* rpmsg vdev entry */
struct fw_rsc_vdev rpmsg_vdev;
struct fw_rsc_vdev_vring rpmsg_vring0;
struct fw_rsc_vdev_vring rpmsg_vring1;
}__attribute__((packed, aligned(0x100)));
void *get_resource_table (int rsc_id, int *len);
#if defined __cplusplus
}
#endif
#endif /* RSC_TABLE_H_ */
@@ -0,0 +1,180 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2017 Xilinx, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* zynqmp_r5_a53_rproc.c
*
* DESCRIPTION
*
* This file define Xilinx ZynqMP R5 to A53 platform specific
* remoteproc implementation.
*
**************************************************************************/
#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"
/* IPI REGs OFFSET */
#define IPI_TRIG_OFFSET 0x00000000 /* IPI trigger register offset */
#define IPI_OBS_OFFSET 0x00000004 /* IPI observation register offset */
#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */
#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */
#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */
#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */
static int zynqmp_r5_a53_proc_irq_handler(int vect_id, void *data)
{
struct remoteproc *rproc = data;
struct remoteproc_priv *prproc;
unsigned int ipi_intr_status;
(void)vect_id;
if (!rproc)
return METAL_IRQ_NOT_HANDLED;
prproc = rproc->priv;
ipi_intr_status = (unsigned int)metal_io_read32(prproc->ipi_io,
IPI_ISR_OFFSET);
if (ipi_intr_status & prproc->ipi_chn_mask) {
atomic_flag_clear(&prproc->ipi_nokick);
metal_io_write32(prproc->ipi_io, IPI_ISR_OFFSET,
prproc->ipi_chn_mask);
return METAL_IRQ_HANDLED;
}
return METAL_IRQ_NOT_HANDLED;
}
static struct remoteproc *
zynqmp_r5_a53_proc_init(struct remoteproc *rproc,
struct remoteproc_ops *ops, void *arg)
{
struct remoteproc_priv *prproc = arg;
struct metal_device *ipi_dev;
unsigned int irq_vect;
int ret;
if (!rproc || !prproc || !ops)
return NULL;
ret = metal_device_open(prproc->ipi_bus_name, prproc->ipi_name,
&ipi_dev);
if (ret) {
xil_printf("failed to open ipi device: %d.\r\n", ret);
return NULL;
}
rproc->priv = prproc;
prproc->ipi_dev = ipi_dev;
prproc->ipi_io = metal_device_io_region(ipi_dev, 0);
if (!prproc->ipi_io)
goto err1;
atomic_store(&prproc->ipi_nokick, 1);
rproc->ops = ops;
/* Register interrupt handler and enable interrupt */
irq_vect = (uintptr_t)ipi_dev->irq_info;
metal_irq_register(irq_vect, zynqmp_r5_a53_proc_irq_handler,
ipi_dev, rproc);
metal_irq_enable(irq_vect);
metal_io_write32(prproc->ipi_io, IPI_IER_OFFSET,
prproc->ipi_chn_mask);
return rproc;
err1:
metal_device_close(ipi_dev);
return NULL;
}
static void zynqmp_r5_a53_proc_remove(struct remoteproc *rproc)
{
struct remoteproc_priv *prproc;
struct metal_device *dev;
if (!rproc)
return;
prproc = rproc->priv;
metal_io_write32(prproc->ipi_io, IPI_IDR_OFFSET, prproc->ipi_chn_mask);
dev = prproc->ipi_dev;
if (dev) {
metal_irq_disable((uintptr_t)dev->irq_info);
metal_irq_unregister((uintptr_t)dev->irq_info, NULL, NULL,
NULL);
metal_device_close(dev);
}
}
static void *
zynqmp_r5_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;
if (!attribute)
attribute = NORM_SHARED_NCACHE | PRIV_RW_USER_RW;
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;
return metal_io_phys_to_virt(tmpio, mem->pa);
}
static int zynqmp_r5_a53_proc_notify(struct remoteproc *rproc, uint32_t id)
{
struct remoteproc_priv *prproc;
(void)id;
if (!rproc)
return -1;
prproc = rproc->priv;
/* TODO: use IPI driver instead and pass ID */
metal_io_write32(prproc->ipi_io, IPI_TRIG_OFFSET,
prproc->ipi_chn_mask);
return 0;
}
/* processor operations from r5 to a53. It defines
* notification operation and remote processor managementi operations. */
struct remoteproc_ops zynqmp_r5_a53_proc_ops = {
.init = zynqmp_r5_a53_proc_init,
.remove = zynqmp_r5_a53_proc_remove,
.mmap = zynqmp_r5_a53_proc_mmap,
.notify = zynqmp_r5_a53_proc_notify,
.start = NULL,
.stop = NULL,
.shutdown = NULL,
};
@@ -0,0 +1,3 @@
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_SYSTEM}/CMakeLists.txt")
add_subdirectory (${PROJECT_SYSTEM})
endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_SYSTEM}/CMakeLists.txt")
@@ -0,0 +1 @@
add_subdirectory (machine)
@@ -0,0 +1,3 @@
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")
add_subdirectory (${PROJECT_MACHINE})
endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")
@@ -0,0 +1,13 @@
collect (APP_COMMON_SOURCES helper.c)
set (_linker_script "${CMAKE_CURRENT_SOURCE_DIR}/linker_remote.ld")
set_property (GLOBAL PROPERTY APP_LINKER_OPT "-Wl,-build-id=none -specs=${CMAKE_CURRENT_SOURCE_DIR}/Xilinx.spec -T\"${_linker_script}\"")
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)
@@ -0,0 +1,2 @@
*startfile:
crti%O%s crtbegin%O%s
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "xparameters.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "xil_cache.h"
#include <metal/sys.h>
#include <metal/irq.h>
#include "platform_info.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
static XScuGic xInterruptController;
/* Interrupt Controller setup */
static int app_gic_initialize(void)
{
u32 Status;
XScuGic_Config *IntcConfig; /* The configuration parameters of the interrupt controller */
Xil_ExceptionDisable();
/*
* Initialize the interrupt controller driver
*/
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(&xInterruptController, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Register the interrupt handler to the hardware interrupt handling
* logic in the ARM processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&xInterruptController);
Xil_ExceptionEnable();
/* Connect notificaiton interrupt ID with ISR */
XScuGic_Connect(&xInterruptController, SGI_NOTIFICATION,
(Xil_ExceptionHandler)metal_irq_isr,
(void *)SGI_NOTIFICATION);
return 0;
}
/* Main hw machinery initialization entry point, called from main()*/
/* return 0 on success */
int init_system(void)
{
struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
/* Low level abstraction layer for openamp initialization */
metal_init(&metal_param);
/* configure the global interrupt controller */
app_gic_initialize();
return 0;
}
void cleanup_system()
{
metal_finish();
Xil_DCacheDisable();
Xil_ICacheDisable();
Xil_DCacheInvalidate();
Xil_ICacheInvalidate();
}
@@ -0,0 +1,228 @@
/* Linker script for Xilinx Zynq-7000
*
* Version: Sourcery CodeBench Lite 2013.11-24
* Support: https://sourcery.mentor.com/GNUToolchain/
*
* Copyright (c) 2007-2010 CodeSourcery, Inc.
* Copyright (c) 2010-2013 Mentor Graphics, Inc.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
ENTRY(__cs3_reset)
SEARCH_DIR(.)
GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3arm)
MEMORY
{
ram (rwx) : ORIGIN = 0x10000000, LENGTH = 256M
rom (rx) : ORIGIN = 0xe4000000, LENGTH = 64M
}
/* These force the linker to search for particular symbols from
* the start of the link process and thus ensure the user's
* overrides are picked up
*/
EXTERN(__cs3_reset __cs3_reset_zynq7000_ram)
EXTERN(__cs3_start_asm _start)
/* Bring in the interrupt routines & vector */
INCLUDE arm-names.inc
EXTERN(__cs3_interrupt_vector_arm)
EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end)
/* Provide fall-back values */
PROVIDE(__cs3_heap_start = _end);
PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram);
PROVIDE(__cs3_region_num = (__cs3_regions_end - __cs3_regions) / 20);
PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram);
SECTIONS
{
.text :
{
CREATE_OBJECT_SYMBOLS
__cs3_region_start_ram = .;
_ftext = .;
*(.cs3.region-head.ram)
ASSERT (. == __cs3_region_start_ram, ".cs3.region-head.ram not permitted");
__cs3_interrupt_vector = __cs3_interrupt_vector_arm;
*(.cs3.interrupt_vector)
/* Make sure we pulled in an interrupt vector. */
ASSERT (. != __cs3_interrupt_vector_arm, "No interrupt vector");
PROVIDE(__cs3_reset = __cs3_reset_zynq7000_ram);
*(.cs3.reset)
_start = DEFINED(__cs3_start_asm) ? __cs3_start_asm : _start;
*(.text.cs3.init)
*(.text .text.* .gnu.linkonce.t.*)
*(.plt)
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
*(.ARM.extab* .gnu.linkonce.armextab.*)
*(.gcc_except_table)
} >ram
.eh_frame_hdr : ALIGN (4)
{
KEEP (*(.eh_frame_hdr))
*(.eh_frame_entry .eh_frame_entry.*)
} >ram
.eh_frame : ALIGN (4)
{
KEEP (*(.eh_frame)) *(.eh_frame.*)
} >ram
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >ram
PROVIDE_HIDDEN (__exidx_end = .);
.rodata : ALIGN (4)
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(0x4);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
__cs3_regions = .;
LONG (0)
LONG (__cs3_region_init_ram)
LONG (__cs3_region_start_ram)
LONG (__cs3_region_init_size_ram)
LONG (__cs3_region_zero_size_ram)
__cs3_regions_end = .;
. = ALIGN (8);
_etext = .;
} >ram
ASSERT (!(__cs3_region_init_ram & 7), "__cs3_region_init_ram not aligned")
ASSERT (!(__cs3_region_start_ram & 7), "__cs3_region_start_ram not aligned")
ASSERT (!(__cs3_region_init_size_ram & 7), "__cs3_region_init_size_ram not aligned")
ASSERT (!(__cs3_region_zero_size_ram & 7), "__cs3_region_zero_size_ram not aligned")
.cs3.rom : ALIGN (8)
{
__cs3_region_start_rom = .;
*(.cs3.region-head.rom)
*(.rom)
. = ALIGN (8);
} >rom
.cs3.rom.bss :
{
*(.rom.b .bss.rom)
. = ALIGN (8);
} >rom
/* __cs3_region_end_rom is deprecated */
__cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom);
__cs3_region_size_rom = LENGTH(rom);
__cs3_region_init_rom = LOADADDR (.cs3.rom);
__cs3_region_init_size_rom = LOADADDR (.cs3.rom.bss) - LOADADDR (.cs3.rom);
__cs3_region_zero_size_rom = SIZEOF(.cs3.rom.bss);
.data : ALIGN (8)
{
KEEP(*(.jcr))
*(.got.plt) *(.got)
*(.shdata)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN (8);
*(.ram)
. = ALIGN (8);
_edata = .;
} >ram
.bss : ALIGN (8)
{
*(.shbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
*(.ram.b .bss.ram)
. = ALIGN (8);
_end = .;
__end = .;
} >ram
/* __cs3_region_end_ram is deprecated */
__cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram);
__cs3_region_size_ram = LENGTH(ram);
__cs3_region_init_ram = LOADADDR (.text);
__cs3_region_init_size_ram = _edata - ADDR (.text);
__cs3_region_zero_size_ram = _end - _edata;
.stab 0 (NOLOAD) : { *(.stab) }
.stabstr 0 (NOLOAD) : { *(.stabstr) }
/* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to
* the beginning of the section so we begin them at 0.
*/
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* DWARF 2.1 */
.debug_ranges 0 : { *(.debug_ranges) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) }
}
/* checksum: b15b0bf76673e544380111 */
@@ -0,0 +1,290 @@
/*******************************************************************/
/* */
/* This file is automatically generated by linker script generator.*/
/* */
/* Version: */
/* */
/* Copyright (c) 2010 Xilinx, Inc. All rights reserved. */
/* */
/* Description : Cortex-A9 Linker Script */
/* */
/*******************************************************************/
_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 : 4096;
_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
{
ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x3e000000, LENGTH = 0x00400000
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00030000
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x0000FE00
}
/* Specify the default entry point to the program */
ENTRY(_vector_table)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.text : {
_binary_firmware1_start = 0;
_binary_firmware1_end = 0;
_binary_firmware2_start = 0;
_binary_firmware2_end = 0;
*(.vectors)
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > ps7_ddr_0_S_AXI_BASEADDR
.init : {
KEEP (*(.init))
} > ps7_ddr_0_S_AXI_BASEADDR
.fini : {
KEEP (*(.fini))
} > ps7_ddr_0_S_AXI_BASEADDR
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.got : {
*(.got)
} > ps7_ddr_0_S_AXI_BASEADDR
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
___DTORS_END___ = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.eh_frame : {
*(.eh_frame)
} > ps7_ddr_0_S_AXI_BASEADDR
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.gcc_except_table : {
*(.gcc_except_table)
} > ps7_ddr_0_S_AXI_BASEADDR
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.bss (NOLOAD) : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
__bss_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
_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 = .;
} > ps7_ddr_0_S_AXI_BASEADDR
.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 = .;
} > ps7_ddr_0_S_AXI_BASEADDR
_end = .;
}
@@ -0,0 +1,14 @@
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}\"")
set (_linker_large_text_script "${CMAKE_CURRENT_SOURCE_DIR}/linker_large_text.ld")
set_property (GLOBAL PROPERTY APP_LINKER_LARGE_TEXT_OPT "-T\"${_linker_large_text_script}\"")
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)
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "xparameters.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "xil_cache.h"
#include <metal/sys.h>
#include <metal/irq.h>
#include "platform_info.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
static XScuGic xInterruptController;
/* Interrupt Controller setup */
static int app_gic_initialize(void)
{
uint32_t status;
XScuGic_Config *int_ctrl_config; /* interrupt controller configuration params */
uint32_t int_id;
uint32_t mask_cpu_id = ((u32)0x1 << XPAR_CPU_ID);
uint32_t target_cpu;
mask_cpu_id |= mask_cpu_id << 8U;
mask_cpu_id |= mask_cpu_id << 16U;
Xil_ExceptionDisable();
/*
* Initialize the interrupt controller driver
*/
int_ctrl_config = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == int_ctrl_config) {
return XST_FAILURE;
}
status = XScuGic_CfgInitialize(&xInterruptController, int_ctrl_config,
int_ctrl_config->CpuBaseAddress);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
/* Only associate interrupt needed to this CPU */
for (int_id = 32U; int_id<XSCUGIC_MAX_NUM_INTR_INPUTS;int_id=int_id+4U) {
target_cpu = XScuGic_DistReadReg(&xInterruptController,
XSCUGIC_SPI_TARGET_OFFSET_CALC(int_id));
/* Remove current CPU from interrupt target register */
target_cpu &= ~mask_cpu_id;
XScuGic_DistWriteReg(&xInterruptController,
XSCUGIC_SPI_TARGET_OFFSET_CALC(int_id), target_cpu);
}
XScuGic_InterruptMaptoCpu(&xInterruptController, XPAR_CPU_ID, IPI_IRQ_VECT_ID);
/*
* Register the interrupt handler to the hardware interrupt handling
* logic in the ARM processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&xInterruptController);
Xil_ExceptionEnable();
/* Connect Interrupt ID with ISR */
XScuGic_Connect(&xInterruptController, IPI_IRQ_VECT_ID,
(Xil_ExceptionHandler)metal_irq_isr,
(void *)IPI_IRQ_VECT_ID);
return 0;
}
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)
{
struct metal_init_params metal_param = {
.log_handler = system_metal_logger,
.log_level = METAL_LOG_INFO,
};
/* Low level abstraction layer for openamp initialization */
metal_init(&metal_param);
/* configure the global interrupt controller */
app_gic_initialize();
return 0;
}
void cleanup_system()
{
metal_finish();
Xil_DCacheDisable();
Xil_ICacheDisable();
Xil_DCacheInvalidate();
Xil_ICacheInvalidate();
}
@@ -0,0 +1,321 @@
/******************************************************************************
*
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
_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 */
/* TCM size is set to 2*0x20000 for R5 in lockstep mode */
MEMORY
{
psu_ddr_S_AXI_BASEADDR : ORIGIN = 0x3ED00000, LENGTH = 0x00040000
psu_ocm_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000
psu_r5_tcm_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00020000
psu_r5_tcm_ram_1_S_AXI_BASEADDR : ORIGIN = 0x00020000, LENGTH = 0x00020000
}
/* Specify the default entry point to the program */
/* ENTRY(_boot) */
ENTRY(_vector_table)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.vectors : {
KEEP (*(.vectors))
*(.boot)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.text : {
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > psu_ddr_S_AXI_BASEADDR
.init : {
KEEP (*(.init))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.fini : {
KEEP (*(.fini))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.interp : {
KEEP (*(.interp))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.note-ABI-tag : {
KEEP (*(.note-ABI-tag))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.got : {
*(.got)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.eh_frame : {
*(.eh_frame)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.gcc_except_table : {
*(.gcc_except_table)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.bss (NOLOAD) : {
. = ALIGN(4);
__bss_start__ = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
_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_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.resource_table 0x3ed20000 : {
. = ALIGN(4);
*(.resource_table)
} > psu_ddr_S_AXI_BASEADDR
_end = .;
}
@@ -0,0 +1,321 @@
/******************************************************************************
*
* Copyright (C) 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
_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 */
/* TCM size is set to 2*0x20000 for R5 in lockstep mode */
MEMORY
{
psu_ddr_S_AXI_BASEADDR : ORIGIN = 0x3ED00000, LENGTH = 0x00040000
psu_ocm_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000
psu_r5_tcm_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00020000
psu_r5_tcm_ram_1_S_AXI_BASEADDR : ORIGIN = 0x00020000, LENGTH = 0x00020000
}
/* Specify the default entry point to the program */
/* ENTRY(_boot) */
ENTRY(_vector_table)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.vectors : {
KEEP (*(.vectors))
*(.boot)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.text : {
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > psu_r5_tcm_ram_1_S_AXI_BASEADDR
.init : {
KEEP (*(.init))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.fini : {
KEEP (*(.fini))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.interp : {
KEEP (*(.interp))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.note-ABI-tag : {
KEEP (*(.note-ABI-tag))
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.got : {
*(.got)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.eh_frame : {
*(.eh_frame)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.gcc_except_table : {
*(.gcc_except_table)
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
.bss (NOLOAD) : {
. = ALIGN(4);
__bss_start__ = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > psu_r5_tcm_ram_0_S_AXI_BASEADDR
_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_tcm_ram_0_S_AXI_BASEADDR
.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_tcm_ram_0_S_AXI_BASEADDR
.resource_table 0x3ed20000 : {
. = ALIGN(4);
*(.resource_table)
} > psu_ddr_S_AXI_BASEADDR
_end = .;
}
@@ -0,0 +1 @@
add_subdirectory (machine)
@@ -0,0 +1,3 @@
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")
add_subdirectory (${PROJECT_MACHINE})
endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")
@@ -0,0 +1,6 @@
collect (APP_COMMON_SOURCES helper.c)
collect (APP_COMMON_SOURCES rsc_table.c)
collect (APP_COMMON_SOURCES platform_info.c)
collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <stdio.h>
#include <metal/sys.h>
#include <metal/shmem.h>
#include <metal/device.h>
#include <metal/io.h>
int init_system()
{
struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
metal_param.log_level = LOG_DEBUG;
metal_init(&metal_param);
return 0;
}
void cleanup_system()
{
metal_finish();
}
@@ -0,0 +1,551 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2016 Xilinx, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* platform_info.c
*
* DESCRIPTION
*
* This file implements APIs to get platform specific
* information for OpenAMP.
*
**************************************************************************/
#include <metal/alloc.h>
#include <metal/atomic.h>
#include <metal/io.h>
#include <metal/irq.h>
#include <metal/shmem.h>
#include <metal/utilities.h>
#include <openamp/remoteproc.h>
#include <openamp/rpmsg_virtio.h>
#include <poll.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include "rsc_table.h"
#define IPI_CHAN_NUMS 2
#define IPI_CHAN_SEND 0
#define IPI_CHAN_RECV 1
#define UNIX_PREFIX "unix:"
#define UNIXS_PREFIX "unixs:"
#define RSC_MEM_PA 0x0UL
#define SHARED_BUF_PA 0x10000UL
#define SHARED_BUF_SIZE 0x40000UL
#define _rproc_wait() metal_cpu_yield()
struct vring_ipi_info {
/* Socket file path */
const char *path;
int fd;
atomic_int sync;
};
struct remoteproc_priv {
const char *shm_file;
int shm_size;
struct metal_io_region *shm_old_io;
struct metal_io_region shm_new_io;
struct remoteproc_mem shm;
struct vring_ipi_info ipi;
};
static struct remoteproc_priv rproc_priv_table [] = {
{
.shm_file = "openamp.shm",
.shm_size = 0x80000,
.ipi = {
.path = "unixs:/tmp/openamp.event.0",
},
},
{
.shm_file = "openamp.shm",
.shm_size = 0x80000,
.ipi = {
.path = "unix:/tmp/openamp.event.0",
},
},
};
static struct remoteproc rproc_inst;
/* External functions */
extern int init_system(void);
extern void cleanup_system(void);
static int linux_proc_block_read(struct metal_io_region *io,
unsigned long offset,
void *restrict dst,
memory_order order,
int len)
{
void *src = metal_io_virt(io, offset);
(void)order;
(void)memcpy(dst, src, len);
return len;
}
static int linux_proc_block_write(struct metal_io_region *io,
unsigned long offset,
const void *restrict src,
memory_order order,
int len)
{
void *dst = metal_io_virt(io, offset);
(void)order;
(void)memcpy(dst, src, len);
return len;
}
static void linux_proc_block_set(struct metal_io_region *io,
unsigned long offset,
unsigned char value,
memory_order order,
int len)
{
void *dst = metal_io_virt(io, offset);
(void)order;
(void)memset(dst, value, len);
return;
}
static struct metal_io_ops linux_proc_io_ops = {
.write = NULL,
.read = NULL,
.block_read = linux_proc_block_read,
.block_write = linux_proc_block_write,
.block_set = linux_proc_block_set,
.close = NULL,
};
static int sk_unix_client(const char *descr)
{
struct sockaddr_un addr;
int fd;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&addr, 0, sizeof addr);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, descr + strlen(UNIX_PREFIX),
sizeof addr.sun_path);
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
printf("connected to %s\n", descr + strlen(UNIX_PREFIX));
return fd;
}
close(fd);
return -1;
}
static int sk_unix_server(const char *descr)
{
struct sockaddr_un addr;
int fd, nfd;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, descr + strlen(UNIXS_PREFIX),
sizeof addr.sun_path);
unlink(addr.sun_path);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
goto fail;
}
listen(fd, 5);
printf("Waiting for connection on %s\n", addr.sun_path);
nfd = accept(fd, NULL, NULL);
close(fd);
return nfd;
fail:
close(fd);
return -1;
}
static inline int is_sk_unix_server(const char *descr)
{
if (memcmp(UNIXS_PREFIX, descr, strlen(UNIXS_PREFIX)))
return 0;
else
return 1;
}
static int event_open(const char *descr)
{
int fd = -1;
int i;
if (descr == NULL) {
return fd;
}
if (!is_sk_unix_server(descr)) {
/* UNIX client. Retry to connect a few times to give the peer
* a chance to setup. */
for (i = 0; i < 100 && fd == -1; i++) {
fd = sk_unix_client(descr);
if (fd == -1)
usleep(i * 10 * 1000);
}
} else {
/* UNIX server. */
fd = sk_unix_server(descr);
}
printf("Open IPI: %s\n", descr);
return fd;
}
static int linux_proc_irq_handler(int vect_id, void *data)
{
char dummy_buf[32];
struct vring_ipi_info *ipi = data;
read(vect_id, dummy_buf, sizeof(dummy_buf));
atomic_flag_clear(&ipi->sync);
return 0;
}
static struct remoteproc *
linux_proc_init(struct remoteproc *rproc,
struct remoteproc_ops *ops, void *arg)
{
struct remoteproc_priv *prproc = arg;
struct metal_io_region *io;
struct remoteproc_mem *shm;
struct vring_ipi_info *ipi;
int ret;
if (!rproc || !prproc)
return NULL;
rproc->priv = prproc;
/* Create shared memory io */
ret = metal_shmem_open(prproc->shm_file, prproc->shm_size, &io);
if (ret) {
printf("Failed to init rproc, failed to open shm %s.\n",
prproc->shm_file);
return NULL;
}
prproc->shm_old_io = io;
shm = &prproc->shm;
shm->pa = 0;
shm->da = 0;
shm->size = prproc->shm_size;
metal_io_init(&prproc->shm_new_io, io->virt, &shm->pa,
shm->size, -1, 0, &linux_proc_io_ops);
shm->io = &prproc->shm_new_io;
/* Open IPI */
ipi = &prproc->ipi;
if (!ipi->path) {
fprintf(stderr,
"ERROR: No IPI sock path specified.\n");
goto err;
}
ipi->fd = event_open(ipi->path);
if (ipi->fd < 0) {
fprintf(stderr,
"ERROR: Failed to open sock %s for IPI.\n",
ipi->path);
goto err;
}
metal_irq_register(ipi->fd, linux_proc_irq_handler, NULL, ipi);
rproc->ops = ops;
return rproc;
err:
return NULL;
}
static void linux_proc_remove(struct remoteproc *rproc)
{
struct remoteproc_priv *prproc;
struct vring_ipi_info *ipi;
struct metal_io_region *io;
if (!rproc)
return;
prproc = rproc->priv;
/* Close IPI */
ipi = &prproc->ipi;
if (ipi->fd >= 0) {
metal_irq_unregister(ipi->fd, 0, NULL, ipi);
close(ipi->fd);
}
/* Close shared memory */
io = prproc->shm_old_io;
if (io && io->ops.close) {
io->ops.close(io);
prproc->shm_old_io = NULL;
}
}
static void *
linux_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;
struct remoteproc_priv *prproc;
metal_phys_addr_t lpa, lda;
void *va;
(void)attribute;
(void)size;
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;
if (!rproc)
return NULL;
prproc = rproc->priv;
mem = &prproc->shm;
va = metal_io_phys_to_virt(mem->io, lpa);
if (va) {
if (io)
*io = mem->io;
metal_list_add_tail(&rproc->mems, &mem->node);
}
return va;
}
static int linux_proc_notify(struct remoteproc *rproc, uint32_t id)
{
struct remoteproc_priv *prproc;
struct vring_ipi_info *ipi;
char dummy = 1;
(void)id;
if (!rproc)
return -1;
prproc = rproc->priv;
ipi = &prproc->ipi;
send(ipi->fd, &dummy, 1, MSG_NOSIGNAL);
return 0;
}
/* processor operations from r5 to a53. It defines
* notification operation and remote processor managementi operations. */
static struct remoteproc_ops linux_proc_ops = {
.init = linux_proc_init,
.remove = linux_proc_remove,
.mmap = linux_proc_mmap,
.notify = linux_proc_notify,
.start = NULL,
.stop = NULL,
.shutdown = NULL,
};
/* RPMsg virtio shared buffer pool */
static struct rpmsg_virtio_shm_pool shpool;
static int platform_slave_setup_resource_table(const char *shm_file,
int shm_size,
void *rsc_table, int rsc_size,
metal_phys_addr_t rsc_pa)
{
struct metal_io_region *io;
void *rsc_shm;
int ret;
ret = metal_shmem_open(shm_file, shm_size, &io);
if (ret) {
printf("Failed to init rproc, failed to open shm %s.\n",
shm_file);
return -1;
}
rsc_shm = metal_io_virt(io, rsc_pa);
memcpy(rsc_shm, rsc_table, rsc_size);
io->ops.close(io);
free(io);
return 0;
}
static struct remoteproc *
platform_create_proc(int proc_index, int rsc_index)
{
struct remoteproc_priv *prproc;
void *rsc_table, *rsc_table_shm;
int rsc_size;
int ret;
metal_phys_addr_t pa;
(void)proc_index;
rsc_table = get_resource_table(rsc_index, &rsc_size);
prproc = &rproc_priv_table[proc_index];
/* Setup resource table
* This step can be done out of the application.
* Assumes the unix server side setup resource table. */
if (is_sk_unix_server(prproc->ipi.path)) {
ret = platform_slave_setup_resource_table(prproc->shm_file,
prproc->shm_size,
rsc_table, rsc_size,
RSC_MEM_PA);
if (ret) {
printf("Failed to initialize resource table\n");
return NULL;
}
}
/* Initialize remoteproc instance */
if (!remoteproc_init(&rproc_inst, &linux_proc_ops, prproc))
return NULL;
/* Mmap resource table */
pa = RSC_MEM_PA;
rsc_table_shm = remoteproc_mmap(&rproc_inst, &pa, NULL, rsc_size,
0, &rproc_inst.rsc_io);
/* parse resource table to remoteproc */
ret = remoteproc_set_rsc_table(&rproc_inst, rsc_table_shm, rsc_size);
if (ret) {
printf("Failed to set resource table to remoteproc\r\n");
remoteproc_remove(&rproc_inst);
return NULL;
}
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) {
fprintf(stderr, "Failed to initialize platform, NULL pointer"
"to store platform data.\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) {
fprintf(stderr, "Failed to create remoteproc device.\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;
/* Setup resource table */
rpmsg_vdev = metal_allocate_memory(sizeof(*rpmsg_vdev));
if (!rpmsg_vdev)
return NULL;
shbuf_io = remoteproc_get_io_with_pa(rproc, SHARED_BUF_PA);
if (!shbuf_io)
return NULL;
shbuf = metal_io_phys_to_virt(shbuf_io, SHARED_BUF_PA);
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) {
printf("failed remoteproc_create_virtio\r\n");
goto err1;
}
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_BUF_SIZE);
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) {
printf("failed rpmsg_init_vdev\r\n");
goto err2;
}
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;
struct remoteproc_priv *prproc;
struct vring_ipi_info *ipi;
unsigned int flags;
prproc = rproc->priv;
ipi = &prproc->ipi;
while(1) {
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&ipi->sync))) {
metal_irq_restore_enable(flags);
remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY);
break;
}
_rproc_wait();
metal_irq_restore_enable(flags);
}
return 0;
}
void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev)
{
(void)rpdev;
}
void platform_cleanup(void *platform)
{
struct remoteproc *rproc = platform;
if (rproc)
remoteproc_remove(rproc);
cleanup_system();
}
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2016 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 */
#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
/**
* platform_init - initialize the platform
*
* It will initialize the platform.
*
* @argc: number of arguments
* @argv: array of the input arguements
* @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
*
* It will create rpmsg virtio device, and returns 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 */
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2016 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"
#define RPMSG_IPU_C0_FEATURES 1
/* VirtIO rpmsg device id */
#define VIRTIO_ID_RPMSG_ 7
/* Remote supports Name Service announcement */
#define VIRTIO_RPMSG_F_NS 0
#define NUM_VRINGS 0x02
#define VRING_ALIGN 0x1000
#define RING_TX 0x00004000
#define RING_RX 0x00008000
#define VRING_SIZE 256
#define NUM_TABLE_ENTRIES 1
struct remote_resource_table 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;
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2016 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 */
#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 1
/* Resource table for the given remote */
struct 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_ */
@@ -0,0 +1,2 @@
collect (APP_COMMON_SOURCES helper.c)
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <stdio.h>
#include <metal/sys.h>
int init_system()
{
struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
metal_init(&metal_param);
return 0;
}
void cleanup_system()
{
metal_finish();
}
@@ -0,0 +1,2 @@
add_subdirectory (msg)
@@ -0,0 +1,48 @@
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS} -fdata-sections -ffunction-sections")
set (_fw_dir "${APPS_SHARE_DIR}")
collector_list (_list PROJECT_INC_DIRS)
collector_list (_app_list APP_INC_DIRS)
include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
collector_list (_list PROJECT_LIB_DIRS)
collector_list (_app_list APP_LIB_DIRS)
link_directories (${_list} ${_app_list})
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
collector_list (_deps PROJECT_LIB_DEPS)
set (OPENAMP_LIB open_amp)
foreach (_app msg-test-rpmsg-ping msg-test-rpmsg-update msg-test-rpmsg-flood-ping)
collector_list (_sources APP_COMMON_SOURCES)
if (${_app} STREQUAL "msg-test-rpmsg-ping")
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-ping.c")
elseif (${_app} STREQUAL "msg-test-rpmsg-update")
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-update.c")
elseif (${_app} STREQUAL "msg-test-rpmsg-flood-ping")
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-flood-ping.c")
endif (${_app} STREQUAL "msg-test-rpmsg-ping")
if (WITH_SHARED_LIB)
add_executable (${_app}-shared ${_sources})
target_link_libraries (${_app}-shared ${OPENAMP_LIB}-shared ${_deps})
install (TARGETS ${_app}-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (WITH_SHARED_LIB)
if (WITH_STATIC_LIB)
if (${PROJECT_SYSTEM} STREQUAL "linux")
add_executable (${_app}-static ${_sources})
target_link_libraries (${_app}-static ${OPENAMP_LIB}-static ${_deps})
install (TARGETS ${_app}-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
else (${PROJECT_SYSTEM})
add_executable (${_app}.out ${_sources})
set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections ${_linker_opt} -Wl,--start-group ${OPENAMP_LIB}-static ${_deps} -Wl,--end-group)
install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif (${PROJECT_SYSTEM} STREQUAL "linux" )
endif (WITH_STATIC_LIB)
endforeach(_app)
@@ -0,0 +1,209 @@
/* This is a test application to send rpmsgs in flood mode.
* That is it will keep sending messages until there is no available
* buffers.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openamp/open_amp.h>
#include <metal/alloc.h>
#include "platform_info.h"
#include "rpmsg-ping.h"
#define APP_EPT_ADDR 0
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
struct _payload {
unsigned long num;
unsigned long size;
unsigned char data[];
};
static int err_cnt;
#define PAYLOAD_MIN_SIZE 1
#define NUMS_PACKAGES 0x100000
/* Globals */
static struct rpmsg_endpoint lept;
static struct _payload *i_payload;
static int rnum = 0;
static int err_cnt = 0;
static int ept_deleted = 0;
/* External functions */
extern int init_system();
extern void cleanup_system();
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
struct _payload *r_payload = (struct _payload *)data;
(void)ept;
(void)src;
(void)priv;
(void)len;
if (r_payload->size == 0) {
LPERROR(" Invalid size of package is received.\n");
err_cnt++;
return RPMSG_SUCCESS;
}
/* Validate data buffer integrity. */
if (memcmp(r_payload->data, i_payload->data, r_payload->size) != 0) {
LPRINTF("Data corruption %lu, size %lu\n",
r_payload->num, r_payload->size);
err_cnt++;
}
rnum = r_payload->num + 1;
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&lept);
LPRINTF("echo test: service is destroyed\n");
ept_deleted = 1;
}
static void rpmsg_name_service_bind_cb(struct rpmsg_device *rdev,
const char *name, uint32_t dest)
{
LPRINTF("new endpoint notification is received.\n");
if (strcmp(name, RPMSG_SERVICE_NAME))
LPERROR("Unexpected name service %s.\n", name);
else
(void)rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
APP_EPT_ADDR, dest,
rpmsg_endpoint_cb,
rpmsg_service_unbind);
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app (struct rpmsg_device *rdev, void *priv)
{
int ret;
int i, s, max_size;
int num_pkgs;
LPRINTF(" 1 - Send data to remote core, retrieve the echo");
LPRINTF(" and validate its integrity ..\n");
num_pkgs = NUMS_PACKAGES;
max_size = rpmsg_virtio_get_buffer_size(rdev);
if (max_size < 0) {
LPERROR("No avaiable buffer size.\n");
return -1;
}
i_payload = (struct _payload *)metal_allocate_memory(max_size);
if (!i_payload) {
LPERROR("memory allocation failed.\n");
return -1;
}
max_size -= sizeof(struct _payload);
/* Create RPMsg endpoint */
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME, APP_EPT_ADDR,
RPMSG_ADDR_ANY,
rpmsg_endpoint_cb, rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create RPMsg endpoint.\n");
return ret;
}
while (!is_rpmsg_ept_ready(&lept))
platform_poll(priv);
LPRINTF("RPMSG endpoint is binded with remote.\n");
memset(&(i_payload->data[0]), 0xA5, max_size);
for (s = PAYLOAD_MIN_SIZE; s <= max_size; s++) {
int size;
i_payload->size = s;
size = sizeof(struct _payload) + s;
LPRINTF("echo test: package size %d, num of packages: %d\n",
size, num_pkgs);
rnum = 0;
for (i = 0; i < num_pkgs; i++) {
i_payload->num = i;
while (!err_cnt && !ept_deleted) {
ret = rpmsg_trysend(&lept, i_payload, size);
if (ret == RPMSG_ERR_NO_BUFF) {
platform_poll(priv);
} else if (ret < 0) {
LPERROR("Failed to send data...\n");
break;
} else {
break;
}
}
if (ret < 0 || err_cnt || ept_deleted)
break;
}
if (ret < 0)
break;
while (rnum < num_pkgs && !err_cnt && !ept_deleted)
platform_poll(priv);
if (err_cnt || ept_deleted)
break;
}
if (ept_deleted)
LPRINTF("Remote RPMsg endpoint is destroyed unexpected.\r\n");
LPRINTF("**********************************\n");
LPRINTF(" Test Results: Error count = %d \n", err_cnt);
LPRINTF("**********************************\n");
/* Destroy the RPMsg endpoint */
rpmsg_destroy_ept(&lept);
LPRINTF("Quitting application .. Echo test end\n");
metal_free_memory(i_payload);
return 0;
}
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_MASTER,
NULL,
rpmsg_name_service_bind_cb);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,206 @@
/* This is a sample demonstration application that showcases usage of rpmsg
This application is meant to run on the remote CPU running baremetal code.
This application echoes back data that was sent to it by the master core. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openamp/open_amp.h>
#include <metal/alloc.h>
#include "platform_info.h"
#include "rpmsg-ping.h"
#define APP_EPT_ADDR 0
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
struct _payload {
unsigned long num;
unsigned long size;
unsigned char data[];
};
static int err_cnt;
#define PAYLOAD_MIN_SIZE 1
/* Globals */
static struct rpmsg_endpoint lept;
static struct _payload *i_payload;
static int rnum = 0;
static int err_cnt = 0;
static int ept_deleted = 0;
/* External functions */
extern int init_system();
extern void cleanup_system();
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
int i;
struct _payload *r_payload = (struct _payload *)data;
(void)ept;
(void)src;
(void)priv;
LPRINTF(" received payload number %lu of size %lu \r\n",
r_payload->num, (unsigned long)len);
if (r_payload->size == 0) {
LPERROR(" Invalid size of package is received.\n");
err_cnt++;
return RPMSG_SUCCESS;
}
/* Validate data buffer integrity. */
for (i = 0; i < (int)r_payload->size; i++) {
if (r_payload->data[i] != 0xA5) {
LPRINTF("Data corruption at index %d\n", i);
err_cnt++;
break;
}
}
rnum = r_payload->num + 1;
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&lept);
LPRINTF("echo test: service is destroyed\n");
ept_deleted = 1;
}
static void rpmsg_name_service_bind_cb(struct rpmsg_device *rdev,
const char *name, uint32_t dest)
{
LPRINTF("new endpoint notification is received.\n");
if (strcmp(name, RPMSG_SERVICE_NAME))
LPERROR("Unexpected name service %s.\n", name);
else
(void)rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
APP_EPT_ADDR, dest,
rpmsg_endpoint_cb,
rpmsg_service_unbind);
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app (struct rpmsg_device *rdev, void *priv)
{
int ret;
int i;
int size, max_size, num_payloads;
int expect_rnum = 0;
LPRINTF(" 1 - Send data to remote core, retrieve the echo");
LPRINTF(" and validate its integrity ..\n");
max_size = rpmsg_virtio_get_buffer_size(rdev);
if (max_size < 0) {
LPERROR("No avaiable buffer size.\n");
return -1;
}
max_size -= sizeof(struct _payload);
num_payloads = max_size - PAYLOAD_MIN_SIZE + 1;
i_payload =
(struct _payload *)metal_allocate_memory(2 * sizeof(unsigned long) +
max_size);
if (!i_payload) {
LPERROR("memory allocation failed.\n");
return -1;
}
/* Create RPMsg endpoint */
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME, APP_EPT_ADDR,
RPMSG_ADDR_ANY,
rpmsg_endpoint_cb, rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create RPMsg endpoint.\n");
return ret;
}
while (!is_rpmsg_ept_ready(&lept))
platform_poll(priv);
LPRINTF("RPMSG endpoint is binded with remote.\n");
for (i = 0, size = PAYLOAD_MIN_SIZE; i < num_payloads; i++, size++) {
i_payload->num = i;
i_payload->size = size;
/* Mark the data buffer. */
memset(&(i_payload->data[0]), 0xA5, size);
LPRINTF("sending payload number %lu of size %lu\n",
i_payload->num,
(unsigned long)(2 * sizeof(unsigned long)) + size);
ret = rpmsg_send(&lept, i_payload,
(2 * sizeof(unsigned long)) + size);
if (ret < 0) {
LPERROR("Failed to send data...\n");
break;
}
LPRINTF("echo test: sent : %lu\n",
(unsigned long)(2 * sizeof(unsigned long)) + size);
expect_rnum++;
do {
platform_poll(priv);
} while ((rnum < expect_rnum) && !err_cnt && !ept_deleted);
}
LPRINTF("**********************************\n");
LPRINTF(" Test Results: Error count = %d \n", err_cnt);
LPRINTF("**********************************\n");
/* Destroy the RPMsg endpoint */
rpmsg_destroy_ept(&lept);
LPRINTF("Quitting application .. Echo test end\n");
metal_free_memory(i_payload);
return 0;
}
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_MASTER,
NULL,
rpmsg_name_service_bind_cb);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,6 @@
#ifndef RPMSG_PING_H
#define RPMSG_PING_H
#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
#endif /* RPMSG_PING_H */
@@ -0,0 +1,130 @@
/* This is a sample demonstration application that showcases usage of rpmsg
This application is meant to run on the remote CPU running baremetal code.
This application echoes back data that was sent to it by the master core. */
#include <stdio.h>
#include <openamp/open_amp.h>
#include <metal/alloc.h>
#include "platform_info.h"
#include "rpmsg-ping.h"
#define SHUTDOWN_MSG 0xEF56A55A
#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
//#define LPRINTF(format, ...)
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
static struct rpmsg_endpoint lept;
static int shutdown_req = 0;
/* External functions */
extern int init_system(void);
extern void cleanup_system(void);
/*-----------------------------------------------------------------------------*
* RPMSG endpoint callbacks
*-----------------------------------------------------------------------------*/
static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
{
(void)priv;
(void)src;
/* On reception of a shutdown we signal the application to terminate */
if ((*(unsigned int *)data) == SHUTDOWN_MSG) {
LPRINTF("shutdown message is received.\n");
shutdown_req = 1;
return RPMSG_SUCCESS;
}
/* Send data back to master */
while (1) {
int ret;
ret = rpmsg_send(ept, data, len);
if (ret == RPMSG_ERR_NO_BUFF) {
LPRINTF("%s, wait for buffer\n", __func__);
continue;
} else {
if (ret < 0)
LPERROR("rpmsg_send, size %lu failed %d\r\n",
(unsigned long)len, ret);
break;
}
}
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
LPRINTF("unexpected Remote endpoint destroy\n");
shutdown_req = 1;
}
/*-----------------------------------------------------------------------------*
* Application
*-----------------------------------------------------------------------------*/
int app(struct rpmsg_device *rdev, void *priv)
{
int ret;
/* Initialize RPMSG framework */
LPRINTF("Try to create rpmsg endpoint.\n");
ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
0, RPMSG_ADDR_ANY, rpmsg_endpoint_cb,
rpmsg_service_unbind);
if (ret) {
LPERROR("Failed to create endpoint.\n");
return -1;
}
LPRINTF("Successfully created rpmsg endpoint.\n");
while(1) {
platform_poll(priv);
/* we got a shutdown request, exit */
if (shutdown_req) {
break;
}
}
rpmsg_destroy_ept(&lept);
return 0;
}
/*-----------------------------------------------------------------------------*
* Application entry point
*-----------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
void *platform;
struct rpmsg_device *rpdev;
int ret;
LPRINTF("Starting application...\n");
/* Initialize platform */
ret = platform_init(argc, argv, &platform);
if (ret) {
LPERROR("Failed to initialize platform.\n");
ret = -1;
} else {
rpdev = platform_create_rpmsg_vdev(platform, 0,
VIRTIO_DEV_SLAVE,
NULL, NULL);
if (!rpdev) {
LPERROR("Failed to create rpmsg virtio device.\n");
ret = -1;
} else {
app(rpdev, platform);
platform_release_rpmsg_vdev(rpdev);
ret = 0;
}
}
LPRINTF("Stopping application...\n");
platform_cleanup(platform);
return ret;
}
@@ -0,0 +1,40 @@
function (collector_create name base)
set_property (GLOBAL PROPERTY "COLLECT_${name}_LIST")
set_property (GLOBAL PROPERTY "COLLECT_${name}_BASE" "${base}")
endfunction (collector_create)
function (collector_list var name)
get_property (_list GLOBAL PROPERTY "COLLECT_${name}_LIST")
set (${var} "${_list}" PARENT_SCOPE)
endfunction (collector_list)
function (collector_base var name)
get_property (_base GLOBAL PROPERTY "COLLECT_${name}_BASE")
set (${var} "${_base}" PARENT_SCOPE)
endfunction (collector_base)
function (collect name)
collector_base (_base ${name})
string(COMPARE NOTEQUAL "${_base}" "" _is_rel)
set (_list)
foreach (s IN LISTS ARGN)
if (_is_rel)
get_filename_component (s "${s}" ABSOLUTE)
file (RELATIVE_PATH s "${_base}" "${s}")
else (_is_rel)
get_filename_component (ts "${s}" ABSOLUTE)
if (EXISTS "${ts}")
set (s "${ts}")
endif (EXISTS "${ts}")
endif (_is_rel)
list (APPEND _list "${s}")
endforeach ()
set_property (GLOBAL APPEND PROPERTY "COLLECT_${name}_LIST" "${_list}")
endfunction (collect)
# Create global collectors
collector_create (PROJECT_INC_DIRS "")
collector_create (PROJECT_LIB_DIRS "")
collector_create (PROJECT_LIB_DEPS "")
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,23 @@
if (WITH_LIBMETAL_FIND)
find_package (Libmetal REQUIRED)
collect (PROJECT_INC_DIRS "${LIBMETAL_INCLUDE_DIR}")
collect (PROJECT_LIB_DIRS "${LIBMETAL_LIB_DIR}")
collect (PROJECT_LIB_DEPS "${LIBMETAL_LIB}")
endif (WITH_LIBMETAL_FIND)
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
check_include_files (stdatomic.h HAVE_STDATOMIC_H)
check_include_files (fcntl.h HAVE_FCNTL_H)
else ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
set (_saved_cmake_required_flags ${CMAKE_REQUIRED_FLAGS})
set (CMAKE_REQUIRED_FLAGS "-c")
check_include_files (stdatomic.h HAVE_STDATOMIC_H)
check_include_files (fcntl.h HAVE_FCNTL_H)
set (CMAKE_REQUIRED_FLAGS ${_saved_cmake_required_flags})
endif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
if (NOT HAVE_FCNTL_H)
unset (WITH_PROXY CACHE)
endif (NOT HAVE_FCNTL_H)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,31 @@
# FindLibmetal
# --------
#
# Find Libmetal
#
# Find the native Libmetal includes and library this module defines
#
# ::
#
# LIBMETAL_INCLUDE_DIR, where to find metal/sysfs.h, etc.
# LIBSYSFS_LIB_DIR, where to find libmetal library.
# FIX ME, CMAKE_FIND_ROOT_PATH doesn't work
# even use the following
# set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
# set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
# set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
find_path(LIBMETAL_INCLUDE_DIR NAMES metal/sys.h PATHS ${CMAKE_FIND_ROOT_PATH})
find_library(LIBMETAL_LIB NAMES metal PATHS ${CMAKE_FIND_ROOT_PATH})
get_filename_component(LIBMETAL_LIB_DIR ${LIBMETAL_LIB} DIRECTORY)
# handle the QUIETLY and REQUIRED arguments and set HUGETLBFS_FOUND to TRUE if
# all listed variables are TRUE
include (FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS (LIBMETAL DEFAULT_MSG LIBMETAL_LIB LIBMETAL_INCLUDE_DIR)
if (LIBMETAL_FOUND)
set (LIBMETAL_LIBS ${LIBMETAL_LIB})
endif (LIBMETAL_FOUND)
mark_as_advanced (LIBMETAL_LIB LIBMETAL_INCLUDE_DIR LIBMETAL_LIB_DIR)
@@ -0,0 +1,73 @@
set (PROJECT_VER_MAJOR 0)
set (PROJECT_VER_MINOR 1)
set (PROJECT_VER_PATCH 0)
set (PROJECT_VER 0.1.0)
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Debug)
endif (NOT CMAKE_BUILD_TYPE)
if (NOT CMAKE_INSTALL_LIBDIR)
set (CMAKE_INSTALL_LIBDIR "lib")
endif (NOT CMAKE_INSTALL_LIBDIR)
if (NOT CMAKE_INSTALL_BINDIR)
set (CMAKE_INSTALL_BINDIR "bin")
endif (NOT CMAKE_INSTALL_BINDIR)
set (_host "${CMAKE_HOST_SYSTEM_NAME}/${CMAKE_HOST_SYSTEM_PROCESSOR}")
message ("-- Host: ${_host}")
set (_target "${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}")
message ("-- Target: ${_target}")
if (NOT DEFINED MACHINE)
set (MACHINE "Generic")
endif (NOT DEFINED MACHINE)
message ("-- Machine: ${MACHINE}")
string (TOLOWER ${CMAKE_SYSTEM_NAME} PROJECT_SYSTEM)
string (TOUPPER ${CMAKE_SYSTEM_NAME} PROJECT_SYSTEM_UPPER)
string (TOLOWER ${CMAKE_SYSTEM_PROCESSOR} PROJECT_PROCESSOR)
string (TOUPPER ${CMAKE_SYSTEM_PROCESSOR} PROJECT_PROCESSOR_UPPER)
string (TOLOWER ${MACHINE} PROJECT_MACHINE)
string (TOUPPER ${MACHINE} PROJECT_MACHINE_UPPER)
# Select which components are in the openamp lib
option (WITH_PROXY "Build with proxy(access device controlled by other processor)" ON)
option (WITH_APPS "Build with sample applicaitons" OFF)
option (WITH_PROXY_APPS "Build with proxy sample applicaitons" OFF)
if (WITH_APPS)
if (WITH_PROXY)
set (WITH_PROXY_APPS ON)
endif (WITH_PROXY)
endif (WITH_APPS)
option (WITH_VIRTIO_MASTER "Build with virtio master enabled" ON)
option (WITH_VIRTIO_SLAVE "Build with virtio slave enabled" ON)
if (NOT WITH_VIRTIO_MASTER)
add_definitions(-DVIRTIO_SLAVE_ONLY)
endif (NOT WITH_VIRTIO_MASTER)
if (NOT WITH_VIRTIO_SLAVE)
add_definitions(-DVIRTIO_MASTER_ONLY)
endif (NOT WITH_VIRTIO_SLAVE)
# Set the complication flags
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
option (WITH_STATIC_LIB "Build with a static library" ON)
if ("${PROJECT_SYSTEM}" STREQUAL "linux")
option (WITH_SHARED_LIB "Build with a shared library" ON)
endif ("${PROJECT_SYSTEM}" STREQUAL "linux")
if (WITH_ZEPHYR)
option (WITH_ZEPHYR_LIB "Build open-amp as a zephyr library" OFF)
endif (WITH_ZEPHYR)
option (WITH_LIBMETAL_FIND "Check Libmetal library can be found" ON)
message ("-- C_FLAGS : ${CMAKE_C_FLAGS}")
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,12 @@
set (CMAKE_SYSTEM_NAME "Generic" CACHE STRING "")
include (CMakeForceCompiler)
CMAKE_FORCE_C_COMPILER ("${CROSS_PREFIX}gcc" GNU)
CMAKE_FORCE_CXX_COMPILER ("${CROSS_PREFIX}g++" GNU)
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER CACHE STRING "")
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,9 @@
set (CMAKE_SYSTEM_NAME "Linux")
set (CMAKE_C_COMPILER "${CROSS_PREFIX}gcc")
set (CMAKE_CXX_COMPILER "${CROSS_PREFIX}g++")
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,8 @@
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "zynq7" CACHE STRING "")
set (CROSS_PREFIX "arm-none-eabi-" CACHE STRING "")
set (CMAKE_C_FLAGS "-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard" CACHE STRING "")
include (cross_generic_gcc)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,6 @@
set (CMAKE_SYSTEM_PROCESSOR "arm")
set (CROSS_PREFIX "arm-xilinx-linux-gnueabi-")
include (cross-linux-gcc)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,6 @@
set (CMAKE_SYSTEM_PROCESSOR "arm64")
set (CROSS_PREFIX "aarch64-none-elf-")
include (cross_generic_gcc)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,7 @@
set (CMAKE_SYSTEM_PROCESSOR "arm64")
set (CROSS_PREFIX "aarch64-linux-gnu-")
set (MACHINE "zynqmp" CACHE STRING "")
include (cross_linux_gcc)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,10 @@
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "zynqmp_r5" CACHE STRING "")
set (CROSS_PREFIX "armr5-none-eabi-" CACHE STRING "")
# Xilinx SDK version earlier than 2017.2 use mfloat-abi=soft by default to generat libxil
set (CMAKE_C_FLAGS "-mfloat-abi=hard -mfpu=vfpv3-d16 -mcpu=cortex-r5" CACHE STRING "")
include (cross_generic_gcc)
# vim: expandtab:ts=2:sw=2:smartindent
@@ -0,0 +1,13 @@
# use "Generic" as CMAKE_SYSTEM_NAME
if (WITH_ZEPHYR)
set (CMAKE_SYSTEM_NAME "Generic" CACHE STRING "")
string (TOLOWER "Zephyr" PROJECT_SYSTEM)
string (TOUPPER "Zephyr" PROJECT_SYSTEM_UPPER)
if (NOT WITH_ZEPHYR_LIB)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
endif ()
if (CONFIG_CPU_CORTEX_M)
set (MACHINE "cortexm" CACHE STRING "")
endif (CONFIG_CPU_CORTEX_M)
endif (WITH_ZEPHYR)
@@ -0,0 +1,58 @@
# echo_test
This readme is about the OpenAMP echo_test demo.
The echo_test is about one processor sends message to the other one, and the other one echo back the message. The processor which sends the message will verify the echo message.
For now, it implements Linux sends the message, and the baremetal echos back.
## Compilation
### Baremetal Compilation
Option `WITH_ECHO_TEST` is to control if the application will be built.
By default this option is `ON` when `WITH_APPS` is on.
Here is an example:
```
$ cmake ../open-amp -DCMAKE_TOOLCHAIN_FILE=zynq7_generic -DWITH_OBSOLETE=on -DWITH_APPS=ON
```
### Linux Compilation
#### Linux Kernel Compilation
You will need to manually compile the following kernel modules with your Linux kernel (Please refer to Linux kernel documents for how to add kernel module):
* Your machine's remoteproc kernel driver
* `obsolete/apps/echo_test/system/linux/kernelspace/rpmsg_user_dev_driver` if you want to run the echo_test app in Linux user space.
* `obsolete/system/linux/kernelspace/rpmsg_echo_test_kern_app` if you want to run the echo_test app in Linux kernel space.
#### Linux Userspace Compliation
* Compile `obsolete/apps/echo_test/system/linux/userspace/echo_test` into your Linux OS.
* If you are running generic(baremetal) system as remoteproc slave, and Linux as remoteproc master, please also add the built generic `echo_test` executable to the firmware of your Linux OS.
## Run the Demo
### Load the Demo
After Linux boots,
* Load the machine remoteproc. If Linux runs as remoteproc master, you will need to pass the other processor's echo_test binary as firmware arguement to the remoteproc module.
* If you run the Linux kernel application demo, load the `rpmsg_echo_test_kern_app` module. You will see the kernel application send the message to remote and the remote reply back and the kernel application will verify the result.
* If you run the userspace application demo, load the `rpmsg_user_dev_driver` module.
* If you run the userspace application demo, you will see the similar output on the console:
```
****************************************
Please enter command and press enter key
****************************************
1 - Send data to remote core, retrieve the echo and validate its integrity ..
2 - Quit this application ..
CMD>
```
* Input `1` to send packages.
* Input `2` to exit the application.
After you run the demo, you will need to unload the kernel modules.
### Unload the Demo
* If you run the userspace application demo, unload the `rpmsg_user_dev_driver` module.
* If you run the kernelspace application demo, unload the `rpmsg_echo_test_kern_app` module.
* Unload the machine remoteproc driver.
@@ -0,0 +1,59 @@
# matrix_multiply
This readme is about the OpenAMP matrix_multiply demo.
The matrix_multiply is about one processor generates two matrices, and send them to the one, and the other one calcuate the matrix multiplicaiton and return the result matrix.
For now, it implements Linux generates the matrices, and the baremetal calculate the matrix mulitplication and send back the result.
## Compilation
### Baremetal Compilation
Option `WITH_MATRIX_MULTIPLY` is to control if the application will be built.
By default this option is `ON` when `WITH_APPS` is on.
Here is an example:
```
$ cmake ../open-amp -DCMAKE_TOOLCHAIN_FILE=zynq7_generic -DWITH_OBSOLETE=on -DWITH_APPS=ON
```
### Linux Compilation
#### Linux Kernel Compilation
You will need to manually compile the following kernel modules with your Linux kernel (Please refer to Linux kernel documents for how to add kernel module):
* Your machine's remoteproc kernel driver
* `obsolete/system/linux/kernelspace/rpmsg_user_dev_driver` if you want to run the matrix_multiply app in Linux user space.
* `obsolete/apps/matrix_multiply/system/linux/kernelspace/rpmsg_mat_mul_kern_app` if you want to run the matrix_multiply app in Linux kernel space.
#### Linux Userspace Compliation
* Compile `obsolete/apps/matrix_multiply/system/linux/userspace/mat_mul_demo` into your Linux OS.
* If you are running generic(baremetal) system as remoteproc slave, and Linux as remoteproc master, please also add the built generic `matrix_multiply` executable to the firmware of your Linux OS.
## Run the Demo
### Load the Demo
After Linux boots,
* Load the machine remoteproc. If Linux runs as remoteproc master, you will need to pass the other processor's matrix_multiply binary as firmware arguement to the remoteproc module.
* If you run the Linux kernel application demo, load the `rpmsg_mat_mul_kern_app` module, you will see the kernel app will generate two matrices to the other processor, and output the result matrix returned by the other processor.
* If you run the userspace application demo, load the `rpmsg_user_dev_driver` module.
* If you run the userspace application demo `mat_mul_demo`, you will see the similar output on the console:
```
****************************************
Please enter command and press enter key
****************************************
1 - Generates random 6x6 matrices and transmits them to remote core over rpmsg
..
2 - Quit this application ..
CMD>
```
* Input `1` to run the matrix multiplication.
* Input `2` to exit the application.
After you run the demo, you will need to unload the kernel modules.
### Unload the Demo
* If you run the userspace application demo, unload the `rpmsg_user_dev_driver` module.
* If you run the kernelspace application demo, unload the `rpmsg_mat_mul_kern_app` module.
* Unload the machine remoteproc driver.
@@ -0,0 +1,38 @@
# rpc_demo
This readme is about the OpenAMP rpc_demo demo.
The rpc_demo is about one processor uses the UART on the other processor and create file on the other processor's filesystem with file operations.
For now, It implements the processor running generic(baremetal) applicaiton access the devices on the Linux.
## Compilation
### Baremetal Compilation
Option `WITH_RPC_DEMO` is to control if the application will be built.
By default this option is `ON` when `WITH_APPS` is on.
Here is an example:
```
$ cmake ../open-amp -DCMAKE_TOOLCHAIN_FILE=zynq7_generic -DWITH_OBSOLETE=on -DWITH_APPS=ON
```
### Linux Compilation
#### Linux Kernel Compilation
You will need to manually compile the following kernel modules with your Linux kernel (Please refer to Linux kernel documents for how to add kernel module):
* Your machine's remoteproc kernel driver
* `obsolete/apps/rpc_demo/system/linux/kernelspace/rpmsg_proxy_dev_driver`
#### Linux Userspace Compliation
* Compile `obsolete/apps/rpc_demo/system/linux/userspace/proxy_app` into your Linux OS.
* Add the built generic `rpc_demo` executable to the firmware of your Linux OS.
## Run the Demo
After Linux boots, run `proxy_app` as follows:
```
# proxy_app [-m REMOTEPROC_MODULE] [-f PATH_OF_THE_RPC_DEMO_FIRMWARE]
```
The demo application will load the remoteproc module, then the proxy rpmsg module, will output message sent from the other processor, send the console input back to the other processor. When the demo application exits, it will unload the kernel modules.
@@ -0,0 +1,168 @@
Libmetal helper data struct
===========================
```
struct metal_io_region {
char name[64]; /**< I/O region name */
void *virt; /**< base virtual address */
const metal_phys_addr_t *physmap; /**< table of base physical address
of each of the pages in the I/O
region */
size_t size; /**< size of the I/O region */
unsigned long page_shift; /**< page shift of I/O region */
metal_phys_addr_t page_mask; /**< page mask of I/O region */
unsigned int mem_flags; /**< memory attribute of the
I/O region */
struct metal_io_ops ops; /**< I/O region operations */
};
/** Libmetal device structure. */
struct metal_device {
const char *name; /**< Device name */
struct metal_bus *bus; /**< Bus that contains device */
unsigned num_regions; /**< Number of I/O regions in
device */
struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of
I/O regions in device*/
struct metal_list node; /**< Node on bus' list of devices */
int irq_num; /**< Number of IRQs per device */
void *irq_info; /**< IRQ ID */
};
```
Remoteproc data struct
===========================
```
struct remoteproc {
struct metal_device dev; /**< Each remoteproc has a device, each device knows its memories regions */
metal_mutex_t lock; /**< mutex lock */
void *rsc_table; /**< pointer to resource table */
size_t rsc_len; /**< length of the resoruce table */
struct remoteproc_ops *ops; /**< pointer to remoteproc operation */
metal_phys_addr_t bootaddr; /**< boot address */
struct loader_ops *loader_ops; /**< image loader operation */
unsigned int state; /**< remoteproc state */
struct metal_list vdevs; /**< list of vdevs (can we limited to one for code size but linux and resource table supports multiple */
void *priv; /**< remoteproc private data */
};
struct remoteproc_vdev {
struct metal_list node; /**< node */
struct remoteproc *rproc; /**< pointer to the remoteproc instance */
struct virtio_dev; /**< virtio device */
uint32_t notify_id; /**< virtio device notification ID */
void *vdev_rsc; /**< pointer to the vdev space in resource table */
struct metal_io_region *vdev_io; /**< pointer to the vdev space I/O region */
int vrings_num; /**< number of vrings */
struct rproc_vrings[1]; /**< vrings array */
};
struct remoteproc_vring {
struct remoteproc_vdev *rpvdev; /**< pointer to the remoteproc vdev */
uint32_t notify_id; /**< vring notify id */
size_t len; /**< vring length */
uint32_t alignment; /**< vring alignment */
void *va; /**< vring start virtual address */
struct metal_io_region *io; /**< pointer to the vring I/O region */
};
```
Virtio Data struct
===========================
```
struct virtio_dev {
int index; /**< unique position on the virtio bus */
struct virtio_device_id id; /**< the device type identification (used to match it with a driver). */
struct metal_device *dev; /**< do we need this in virtio device ? */
metal_spinlock lock; /**< spin lock */
uint64_t features; /**< the features supported by both ends. */
unsigned int role; /**< if it is virtio backend or front end. */
void (*rst_cb)(struct virtio_dev *vdev); /**< user registered virtio device callback */
void *priv; /**< pointer to virtio_dev private data */
int vrings_num; /**< number of vrings */
struct virtqueue vqs[1]; /**< array of virtqueues */
};
struct virtqueue {
char vq_name[VIRTQUEUE_MAX_NAME_SZ]; /**< virtqueue name */
struct virtio_device *vdev; /**< pointer to virtio device */
uint16_t vq_queue_index;
uint16_t vq_nentries;
uint32_t vq_flags;
int vq_alignment;
int vq_ring_size;
boolean vq_inuse;
void *vq_ring_mem;
void (*callback) (struct virtqueue * vq); /**< virtqueue callback */
void (*notify) (struct virtqueue * vq); /**< virtqueue notify remote function */
int vq_max_indirect_size;
int vq_indirect_mem_size;
struct vring vq_ring;
uint16_t vq_free_cnt;
uint16_t vq_queued_cnt;
struct metal_io_region *buffers_io; /**< buffers shared memory */
/*
* Head of the free chain in the descriptor table. If
* there are no free descriptors, this will be set to
* VQ_RING_DESC_CHAIN_END.
*/
uint16_t vq_desc_head_idx;
/*
* Last consumed descriptor in the used table,
* trails vq_ring.used->idx.
*/
uint16_t vq_used_cons_idx;
/*
* Last consumed descriptor in the available table -
* used by the consumer side.
*/
uint16_t vq_available_idx;
uint8_t padd;
/*
* Used by the host side during callback. Cookie
* holds the address of buffer received from other side.
* Other fields in this structure are not used currently.
* Do we needed??/
struct vq_desc_extra {
void *cookie;
struct vring_desc *indirect;
uint32_t indirect_paddr;
uint16_t ndescs;
} vq_descx[0];
};
struct vring {
unsigned int num; /**< number of buffers of the vring */
struct vring_desc *desc;
struct vring_avail *avail;
struct vring_used *used;
};
```
RPMsg Data struct
===========================
```
struct rpmsg_virtio_device {
struct virtio_dev *vdev; /**< pointer to the virtio device */
struct virtqueue *rvq; /**< pointer to receive virtqueue */
struct virtqueue *svq; /**< pointer to send virtqueue */
int buffers_number; /**< number of shared buffers */
struct metal_io_region *shbuf_io; /**< pointer to the shared buffer I/O region */
void *shbuf;
int (*new_endpoint_cb)(const char *name, uint32_t addr); /**< name service announcement user designed callback which is used for when there is a name service announcement, there is no local endpoints waiting to bind */
struct metal_list endpoints; /**< list of endpoints */
};
struct rpmsg_endpoint {
char name[SERVICE_NAME_SIZE];
struct rpmsg_virtio_dev *rvdev; /**< pointer to the RPMsg virtio device */
uint32_t addr; /**< endpoint local address */
uint32_t dest_addr; /**< endpoint default target address */
int (*cb)(struct rpmsg_endpoint *ept, void *data, struct metal_io_region *io, size_t len, uint32_t addr); /**< endpoint callback */
void (*destroy)(struct rpmsg_endpoint *ept); /**< user registerd endpoint destory callback */
/* Whether we need another callback for ack ns announcement? */
};
```
@@ -0,0 +1,97 @@
// RPMsg dynamic endpoint creation
digraph G {
rankdir="LR";
subgraph roles {
node [style="filled", fillcolor="lightblue"];
master [label="Master"];
slave [label="Slave"];
}
subgraph m_comment_nodes {
node [group=m_comment, shape="note", style="filled", fillcolor="yellow"];
rank="same";
m_remoteproc_init_comment [label="this is initialize rproc call"];
m_remoteproc_boot_comment [label="it will setup vdev before booting the remote"];
m_rpmsg_vdev_init_comment [label="\l* It will initialize vrings with the shared memory\l* If vdev supports name service, it will create name service endpoint;\l* it sets vdev status to DRVIER_READY, And will notify remote.\l"];
m_rpmsg_create_ep_comment [label="\if vdev supports name service,\lit will send out name service.\l"];
m_rpmsg_send_comment [label="\lIf endpoint hasn't binded, it fail\lreturn failure to indicate ep hasn't been binded.\l"];
}
subgraph m_flow_nodes {
node [shape="box"];
rank="same";
m_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"]
m_remoteproc_load [label="calls remoteproc_load() to load applicaiton"];
m_remoteproc_boot [shape="box", label="ret=remoteproc_boot(&rproc)"];
m_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, MASTER, NULL);"];
m_rpmsg_shmpool_init[label="rpmsg_virtio_init_shm_pool(shpool, shbuf, shbuf_pool_size);"];
m_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, shpool);"];
m_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, call ns_bind_cb.\l"];
m_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"];
m_rpmsg_send [label="rpmsg_send(ept,data)"];
m_rpmsg_rx_cb [label="rpmsg_rx_callback()"];
m_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"];
m_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"];
m_remoteproc_init -> m_remoteproc_load -> m_remoteproc_boot -> m_remoteproc_get_vdev ->
m_rpmsg_shmpool_init -> m_rpmsg_vdev_init -> m_rpmsg_create_ep -> m_rpmsg_ns_cb -> m_rpmsg_send;
m_rpmsg_send -> m_rpmsg_rx_cb -> m_ep_cb ->
m_rpmsg_destroy_ep [dir="none", style="dashed"];
}
subgraph s_flow_nodes {
rank="same";
node [shape="box"];
s_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"];
s_remoteproc_parse_rsc [label="ret = remoteproc_set_rsc_table(rproc, &rsc_table, rsc_size)"];
s_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, SLAVE, rst_cb);"];
s_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, NULL);"];
s_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, it will call ns_bind_cb()."];
s_rpmsg_ns_bind_cb [label="s_rpsmg_ns_bind_cb(ept_name, remote_addr)"];
s_rpmsg_create_ep [label="\lept=rpmsg_create_endpoint(ept, rdev, ept_name, ept_addr, remote_addr,\lendpoint_cb, ns_unbind_cb);\l"];
s_rpmsg_send [label="rpmsg_send(ept,data)"];
s_rpmsg_rx_cb [label="rpmsg_rx_callback()"];
s_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"];
s_rpmsg_ns_unbind_cb [label="\lrpmsg_ns_callback() will call the previous\lregistered endpoint unbind callback\l"];
s_remoteproc_init -> s_remoteproc_parse_rsc -> s_remoteproc_get_vdev ->
s_rpmsg_vdev_init -> s_rpmsg_ns_cb -> s_rpmsg_ns_bind_cb ->
s_rpmsg_create_ep;
s_rpmsg_create_ep-> s_rpmsg_rx_cb -> s_ep_cb -> s_rpmsg_send ->
s_rpmsg_ns_unbind_cb [dir="none", style="dash"];
}
subgraph s_comment_nodes {
node [group=s_comment, shape="note", style="filled", fillcolor="yellow"];
rank="same";
s_rpmsg_vdev_init_comment [label="\l* If vdev supports name service, it will create name service endpoint;\l* It will not return until the master set status to DRIVER READY\l"];
s_rpmsg_rx_cb_comment [label="\l* It will look for the endpoint which matches the destination address.\lIf the two endpoints hasn't binded yet,\lit will set the local endpoint's destination address with the source address in the message\l"];
}
master -> m_remoteproc_init [dir="none"];
slave -> s_remoteproc_init [dir="none"];
s_rpmsg_create_ep -> m_rpmsg_ns_cb [label="NS annoucement"];
m_rpmsg_create_ep -> s_rpmsg_ns_cb [label="NS annoucement"];
m_rpmsg_send -> s_rpmsg_rx_cb [label="RPMsg data"];
s_rpmsg_send -> m_rpmsg_rx_cb [label="RPMsg data"];
m_rpmsg_destroy_ep -> s_rpmsg_ns_unbind_cb [label="Endpoint destroy NS"];
m_remoteproc_init_comment -> m_remoteproc_init [dir="none"];
m_remoteproc_boot_comment -> m_remoteproc_boot [dir="none"];
m_rpmsg_vdev_init_comment -> m_rpmsg_vdev_init [dir="none"];
m_rpmsg_create_ep_comment -> m_rpmsg_create_ep [dir="none"];
m_rpmsg_send_comment -> m_rpmsg_send [dir="none"];
s_rpmsg_vdev_init -> s_rpmsg_vdev_init_comment [dir="none"];
s_rpmsg_rx_cb -> s_rpmsg_rx_cb_comment [dir="none"];
{rank=same; master; m_remoteproc_init}
{rank=same; slave; s_remoteproc_init}
}
@@ -0,0 +1,95 @@
// RPMsg dynamic endpoints binding
digraph G {
rankdir="LR";
subgraph roles {
node [style="filled", fillcolor="lightblue"];
master [label="Master"];
slave [label="Slave"];
}
subgraph m_comment_nodes {
node [group=m_comment, shape="note", style="filled", fillcolor="yellow"];
rank="same";
m_remoteproc_init_comment [label="this is initialize rproc call"];
m_remoteproc_boot_comment [label="it will setup vdev before booting the remote"];
m_rpmsg_vdev_init_comment [label="\l* It will initialize vrings with the shared memory\l* As vdev doesn't support name service, it will not create name service endpoint;\l* it sets vdev status to DRVIER_READY, And will notify remote.\l"];
m_rpmsg_create_ep_comment [label="\lIf vdev supports name service,\lit will send out name service.\l"];
m_rpmsg_send_comment [label="\lIf endpoint hasn't binded, it fail\lreturn failure to indicate ep hasn't been binded.\l"];
}
subgraph m_flow_nodes {
node [shape="box"];
rank="same";
m_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"]
m_remoteproc_load [label="calls remoteproc_load() to load applicaiton"];
m_remoteproc_boot [shape="box", label="ret=remoteproc_boot(&rproc)"];
m_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, MASTER, NULL);"];
m_rpmsg_shmpool_init[label="rpmsg_virtio_init_shm_pool(shpool, shbuf, shbuf_pool_size);"];
m_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, shpool);"];
m_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, call ns_bind_cb.\l"];
m_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"];
m_rpmsg_send [label="rpmsg_send(ept,data)"];
m_rpmsg_rx_cb [label="rpmsg_rx_callback()"];
m_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"];
m_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"];
m_remoteproc_init -> m_remoteproc_load -> m_remoteproc_boot -> m_remoteproc_get_vdev ->
m_rpmsg_shmpool_init -> m_rpmsg_vdev_init -> m_rpmsg_ns_cb -> m_rpmsg_create_ep -> m_rpmsg_send;
m_rpmsg_send -> m_rpmsg_rx_cb -> m_ep_cb ->
m_rpmsg_destroy_ep [dir="none", style="dashed"];
}
subgraph s_flow_nodes {
rank="same";
node [shape="box"];
s_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"];
s_remoteproc_parse_rsc [label="ret = remoteproc_set_rsc_table(rproc, &rsc_table, rsc_size)"];
s_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, SLAVE, rst_cb);"];
s_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, NULL);"];
s_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"];
s_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, call ns_binc_cb.\l"];
s_rpmsg_send [label="rpmsg_send(ept,data)"];
s_rpmsg_rx_cb [label="rpmsg_rx_callback()"];
s_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"];
s_rpmsg_ns_unbind_cb [label="\lrpmsg_ns_callback() will call the previous\lregistered endpoint unbind callback\l"];
s_remoteproc_init -> s_remoteproc_parse_rsc -> s_remoteproc_get_vdev ->
s_rpmsg_vdev_init -> s_rpmsg_create_ep;
s_rpmsg_create_ep -> s_rpmsg_ns_cb -> s_rpmsg_rx_cb ->
s_ep_cb -> s_rpmsg_send -> s_rpmsg_ns_unbind_cb [dir="none", style="dash"];
}
subgraph s_comment_nodes {
node [group=s_comment, shape="note", style="filled", fillcolor="yellow"];
rank="same";
s_rpmsg_vdev_init_comment [label="\l* If vdev supports name service, it will create name service endpoint;\l* It will not return until the master set status to DRIVER READY\l"];
s_rpmsg_rx_cb_comment [label="\l* It will look for the endpoint which matches the destination address.\lIf the two endpoints hasn't binded yet,\lit will set the local endpoint's destination address with the source address in the message\l"];
}
master -> m_remoteproc_init [dir="none"];
slave -> s_remoteproc_init [dir="none"];
s_rpmsg_create_ep -> m_rpmsg_ns_cb [label="NS annoucement"];
m_rpmsg_create_ep -> s_rpmsg_ns_cb [label="NS annoucement"];
m_rpmsg_send -> s_rpmsg_rx_cb [label="RPMsg data"];
s_rpmsg_send -> m_rpmsg_rx_cb [label="RPMsg data"];
m_rpmsg_destroy_ep -> s_rpmsg_ns_unbind_cb [label="Endpoint destroy NS"];
m_remoteproc_init_comment -> m_remoteproc_init [dir="none"];
m_remoteproc_boot_comment -> m_remoteproc_boot [dir="none"];
m_rpmsg_vdev_init_comment -> m_rpmsg_vdev_init [dir="none"];
m_rpmsg_create_ep_comment -> m_rpmsg_create_ep [dir="none"];
m_rpmsg_send_comment -> m_rpmsg_send [dir="none"];
s_rpmsg_vdev_init -> s_rpmsg_vdev_init_comment [dir="none"];
s_rpmsg_rx_cb -> s_rpmsg_rx_cb_comment [dir="none"];
{rank=same; master; m_remoteproc_init}
{rank=same; slave; s_remoteproc_init}
}
@@ -0,0 +1,87 @@
// RPMsg static endpoints
digraph G {
rankdir="LR";
subgraph roles {
node [style="filled", fillcolor="lightblue"];
master [label="Master"];
slave [label="Slave"];
}
subgraph m_comment_nodes {
node [group=m_comment, shape="note", style="filled", fillcolor="yellow"];
rank="same";
m_remoteproc_init_comment [label="this is initialize rproc call"];
m_remoteproc_boot_comment [label="it will setup vdev before booting the remote"];
m_rpmsg_vdev_init_comment [label="\l* It will initialize vrings with the shared memory\l* As vdev doesn't support name service, it will not create name service endpoint;\l* it sets vdev status to DRVIER_READY, And will notify remote.\l"];
m_rpmsg_create_ep_comment [label="\lAs vdev doesn't supports name service,\lit will not send out name service.\l"];
}
subgraph m_flow_nodes {
node [shape="box"];
rank="same";
m_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"];
m_remoteproc_load [label="calls remoteproc_load() to load applicaiton"];
m_remoteproc_boot [shape="box", label="ret=remoteproc_boot(&rproc)"];
m_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, MASTER, NULL);"];
m_rpmsg_shmpool_init[label="rpmsg_virtio_init_shm_pool(shpool, shbuf, shbuf_pool_size);"];
m_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, shpool);"];
m_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"];
m_rpmsg_send [label="rpmsg_send(ept,data)"];
m_rpmsg_rx_cb [label="rpmsg_rx_callback()"];
m_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"];
m_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"];
m_remoteproc_init -> m_remoteproc_load -> m_remoteproc_boot -> m_remoteproc_get_vdev ->
m_rpmsg_shmpool_init -> m_rpmsg_vdev_init -> m_rpmsg_create_ep -> m_rpmsg_send;
m_rpmsg_send -> m_rpmsg_rx_cb -> m_ep_cb ->
m_rpmsg_destroy_ep [dir="none", style="dashed"];
}
subgraph s_flow_nodes {
rank="same";
node [shape="box"];
s_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"];
s_remoteproc_parse_rsc [label="ret = remoteproc_set_rsc_table(rproc, &rsc_table, rsc_size)"];
s_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, SLAVE, rst_cb);"];
s_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, NULL);"];
s_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"];
s_rpmsg_send [label="rpmsg_send(ept,data)"];
s_rpmsg_rx_cb [label="rpmsg_rx_callback()"];
s_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"];
s_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"];
s_remoteproc_init -> s_remoteproc_parse_rsc -> s_remoteproc_get_vdev ->
s_rpmsg_vdev_init -> s_rpmsg_create_ep;
s_rpmsg_create_ep -> s_rpmsg_rx_cb ->
s_ep_cb -> s_rpmsg_send -> s_rpmsg_destroy_ep [dir="none", style="dash"];
}
subgraph s_comment_nodes {
node [group=s_comment, shape="note", style="filled", fillcolor="yellow"];
rank="same";
s_rpmsg_vdev_init_comment [label="\l* As vdev doesn't support name service, it will not create name service endpoint;\l* It will not return until the master set status to DRIVER READY\l"];
s_rpmsg_rx_cb_comment [label="\l* It will look for the endpoint which matches the destination address.\lIf no endpoint has found, it will drop the message.\l"];
}
master -> m_remoteproc_init [dir="none"];
slave -> s_remoteproc_init [dir="none"];
m_rpmsg_send -> s_rpmsg_rx_cb [label="RPMsg data"];
s_rpmsg_send -> m_rpmsg_rx_cb [label="RPMsg data"];
m_remoteproc_init_comment -> m_remoteproc_init [dir="none"];
m_remoteproc_boot_comment -> m_remoteproc_boot [dir="none"];
m_rpmsg_vdev_init_comment -> m_rpmsg_vdev_init [dir="none"];
m_rpmsg_create_ep_comment -> m_rpmsg_create_ep [dir="none"];
s_rpmsg_vdev_init -> s_rpmsg_vdev_init_comment [dir="none"];
s_rpmsg_rx_cb -> s_rpmsg_rx_cb_comment [dir="none"];
{rank=same; master; m_remoteproc_init}
{rank=same; slave; s_remoteproc_init}
}
@@ -0,0 +1,56 @@
from graphviz import Digraph
import argparse
import os
import pydot
import sys
import warnings
def gen_graph_from_gv(ifile, odir, oformat="png"):
(graph,) = pydot.graph_from_dot_file(ifile)
gen_graph_func = getattr(graph, "write_" + oformat)
filename = os.path.basename(ifile)
ofile = odir + "/" + os.path.splitext(filename)[0] + "." + oformat
gen_graph_func(ofile)
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('-i', "--infile", action="append",
help="graphviz file path")
parser.add_argument('-o', '--outdir',
help='sum the integers (default: find the max)')
parser.add_argument('-f', '--outformat', default="png",
help='output image format (default: png)')
args = parser.parse_args()
# Image source directory
img_src_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
img_files = []
if args.infile:
for f in args.infile:
if not os.path.isfile(f):
f = img_src_dir + "/" + f
if not os.path.isfile(f):
warnings.warn("Input file: " + f + " doesn't exist.")
else:
img_files.append(f)
else:
for f in os.listdir(img_src_dir):
if f.endswith(".gv"):
img_files.append(img_src_dir + "/" + f)
if not img_files:
sys.exist("ERROR: no found image files.")
oformat = args.outformat
if args.outdir:
odir = args.outdir
if not os.path.isdir(odir):
sys.exit("--outdir " + odir + "doesn't exist")
else:
odir = os.path.dirname(img_src_dir) + "/img"
for f in img_files:
print("Generating " + oformat + " for " + f + " ...")
gen_graph_from_gv(f, odir, oformat)
@@ -0,0 +1,19 @@
// Remoteproc Life Cycle Management State Machine
digraph G {
rankdir="LR"
st_offline [label="Offline"]
st_configured [label="Configured"]
st_ready [label="Ready"]
st_running [label="Running"]
st_stopped [label="Stopped"]
st_offline -> st_configured
st_configured -> st_ready
st_ready -> st_running
st_ready -> st_stopped
st_stopped -> st_offline
st_running -> st_stopped
{rank=same; st_configured; st_ready; st_running}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Some files were not shown because too many files have changed in this diff Show More