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
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:
+13
@@ -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)
|
||||
+12
@@ -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)
|
||||
Vendored
+46
@@ -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)
|
||||
+115
@@ -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;
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef RPMSG_ECHO_H
|
||||
#define RPMSG_ECHO_H
|
||||
|
||||
#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
|
||||
|
||||
#endif /* RPMSG_ECHO_H */
|
||||
+202
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
+32
@@ -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)
|
||||
+250
@@ -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 = ℑ
|
||||
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;
|
||||
}
|
||||
+315
@@ -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 = .;
|
||||
}
|
||||
Vendored
+93
@@ -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,
|
||||
};
|
||||
|
||||
+313
@@ -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,
|
||||
};
|
||||
+41
@@ -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)
|
||||
|
||||
+258
@@ -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;
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef MATRIX_MULTIPLY_H
|
||||
#define MATRIX_MULTIPLY_H
|
||||
|
||||
#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
|
||||
|
||||
#endif /* MATRIX_MULTIPLY_H */
|
||||
+149
@@ -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;
|
||||
}
|
||||
Vendored
+49
@@ -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)
|
||||
Vendored
+169
@@ -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;
|
||||
}
|
||||
Vendored
+371
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -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 */
|
||||
+42
@@ -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)
|
||||
+128
@@ -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;
|
||||
}
|
||||
+180
@@ -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;
|
||||
}
|
||||
|
||||
+3
@@ -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")
|
||||
Vendored
+6
@@ -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)
|
||||
|
||||
Vendored
+261
@@ -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();
|
||||
}
|
||||
Vendored
+107
@@ -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_ */
|
||||
+157
@@ -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);
|
||||
+72
@@ -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;
|
||||
}
|
||||
+44
@@ -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_ */
|
||||
Vendored
+168
@@ -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,
|
||||
};
|
||||
Vendored
+4
@@ -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}")
|
||||
|
||||
+29
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Vendored
+232
@@ -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();
|
||||
}
|
||||
Vendored
+101
@@ -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_ */
|
||||
|
||||
lib/main/STM32H7/Middlewares/Third_Party/OpenAMP/open-amp/apps/machine/zynqmp/zynqmp_linux_r5_proc.c
Vendored
+207
@@ -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,
|
||||
};
|
||||
Vendored
+5
@@ -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}")
|
||||
|
||||
Vendored
+254
@@ -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();
|
||||
}
|
||||
Vendored
+92
@@ -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_ */
|
||||
Vendored
+73
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
+47
@@ -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_ */
|
||||
+180
@@ -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,
|
||||
};
|
||||
+3
@@ -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")
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
add_subdirectory (machine)
|
||||
lib/main/STM32H7/Middlewares/Third_Party/OpenAMP/open-amp/apps/system/generic/machine/CMakeLists.txt
Vendored
+3
@@ -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")
|
||||
+13
@@ -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)
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
*startfile:
|
||||
crti%O%s crtbegin%O%s
|
||||
lib/main/STM32H7/Middlewares/Third_Party/OpenAMP/open-amp/apps/system/generic/machine/zynq7/helper.c
Vendored
+86
@@ -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();
|
||||
}
|
||||
+228
@@ -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 */
|
||||
+290
@@ -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 = .;
|
||||
}
|
||||
+14
@@ -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)
|
||||
+113
@@ -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();
|
||||
}
|
||||
+321
@@ -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 = .;
|
||||
}
|
||||
+321
@@ -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 = .;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
add_subdirectory (machine)
|
||||
Vendored
+3
@@ -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")
|
||||
+6
@@ -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}")
|
||||
|
||||
lib/main/STM32H7/Middlewares/Third_Party/OpenAMP/open-amp/apps/system/linux/machine/generic/helper.c
Vendored
+31
@@ -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();
|
||||
}
|
||||
+551
@@ -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();
|
||||
}
|
||||
+82
@@ -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 */
|
||||
+61
@@ -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;
|
||||
}
|
||||
+42
@@ -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_ */
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
collect (APP_COMMON_SOURCES helper.c)
|
||||
|
||||
Vendored
+26
@@ -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();
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
|
||||
add_subdirectory (msg)
|
||||
+48
@@ -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)
|
||||
Vendored
+209
@@ -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;
|
||||
}
|
||||
|
||||
+206
@@ -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;
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef RPMSG_PING_H
|
||||
#define RPMSG_PING_H
|
||||
|
||||
#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
|
||||
|
||||
#endif /* RPMSG_PING_H */
|
||||
+130
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user