Signed-off-by: Ben Levinsky ben.levinsky@xilinx.com --- apps/examples/CMakeLists.txt | 1 + apps/examples/oob_echo/CMakeLists.txt | 47 +++++++ apps/examples/oob_echo/rpmsg-echo.h | 6 + apps/examples/oob_echo/rpmsg-oob-echo.c | 141 ++++++++++++++++++++ apps/examples/oob_echo/rpmsg-oob-ping.c | 223 ++++++++++++++++++++++++++++++++ 5 files changed, 418 insertions(+) create mode 100644 apps/examples/oob_echo/CMakeLists.txt create mode 100644 apps/examples/oob_echo/rpmsg-echo.h create mode 100644 apps/examples/oob_echo/rpmsg-oob-echo.c create mode 100644 apps/examples/oob_echo/rpmsg-oob-ping.c
diff --git a/apps/examples/CMakeLists.txt b/apps/examples/CMakeLists.txt index 319f01e..f0ae8cd 100644 --- a/apps/examples/CMakeLists.txt +++ b/apps/examples/CMakeLists.txt @@ -2,6 +2,7 @@ option (WITH_LOAD_FW "Include loading firmware example" OFF)
add_subdirectory (echo) +add_subdirectory (oob_echo) add_subdirectory (rpmsg_sample_echo) add_subdirectory (matrix_multiply) if (WITH_LOAD_FW) diff --git a/apps/examples/oob_echo/CMakeLists.txt b/apps/examples/oob_echo/CMakeLists.txt new file mode 100644 index 0000000..eab1dbf --- /dev/null +++ b/apps/examples/oob_echo/CMakeLists.txt @@ -0,0 +1,47 @@ + +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-oob-echo-ping rpmsg-oob-echo) + collector_list (_sources APP_COMMON_SOURCES) + if (${_app} STREQUAL "rpmsg-oob-echo-ping") + list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-oob-ping.c") + elseif (${_app} STREQUAL "rpmsg-oob-echo") + list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-oob-echo.c") + endif (${_app} STREQUAL "rpmsg-oob-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) + diff --git a/apps/examples/oob_echo/rpmsg-echo.h b/apps/examples/oob_echo/rpmsg-echo.h new file mode 100644 index 0000000..d15eb56 --- /dev/null +++ b/apps/examples/oob_echo/rpmsg-echo.h @@ -0,0 +1,6 @@ +#ifndef RPMSG_ECHO_H +#define RPMSG_ECHO_H + +#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel" + +#endif /* RPMSG_ECHO_H */ diff --git a/apps/examples/oob_echo/rpmsg-oob-echo.c b/apps/examples/oob_echo/rpmsg-oob-echo.c new file mode 100644 index 0000000..8c92df3 --- /dev/null +++ b/apps/examples/oob_echo/rpmsg-oob-echo.c @@ -0,0 +1,141 @@ +/* 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" +//#include "xil_printf.h" + +#define OUT_OF_BAND (0x1UL<<31) +#define INIT_MSG 0x2UL +#define ACK_MSG 0X3UL +#define DATA_MSG 0x4UL +#define SHUTDOWN_MSG 0x5UL + +#define TABLE_BASE_ADDRESS 0x3ee20000UL +#define BUFFER_SIZE 0x10000UL //64K.. can change to 65K as needed +#define NUM_BUFFERS 16 +#define NUM_MESSAGES_TO_SEND 32 + +static struct packet { + unsigned packet_type; + unsigned buffer_index; + unsigned packet_length; +}; + +static int demo_status = 0; + +#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) +{ + + struct packet * p = (struct packet *)data; + struct packet ack_packet; + + (void)priv; + (void)src; + (void)len; + LPRINTF("RPU message is received.\r\n" ); + LPRINTF("RPU message contents : packet_type %x buffer_index %x packet_length %x\r\n", + p->packet_type, p->buffer_index, p->packet_length ); + + LPRINTF("RPU: Data location at %x \r\n", (unsigned)(TABLE_BASE_ADDRESS+ (BUFFER_SIZE * p->buffer_index))); + LPRINTF("RPU: contents of message %x \r\n", *(char*)((TABLE_BASE_ADDRESS+ (BUFFER_SIZE * p->buffer_index)))); + /* notify remote that message is received */ + ack_packet.packet_type = OUT_OF_BAND | ACK_MSG; + if (rpmsg_send(ept, &ack_packet, sizeof(struct packet)) < 0){ + LPERROR("RPU rpmsg_send failed\r\n"); + return RPMSG_ERR_PARAM; + } + + return RPMSG_SUCCESS; +} + +static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) +{ + (void)ept; + LPRINTF("RPU unexpected Remote endpoint destroy\r\n"); + shutdown_req = 1; +} + +/*-----------------------------------------------------------------------------* + * Application + *-----------------------------------------------------------------------------*/ +int app(struct rpmsg_device *rdev, void *priv) +{ + int ret; + + /* Initialize RPMSG framework */ + LPRINTF("Try to create rpmsg endpoint.\r\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.\r\n"); + return -1; + } + + LPRINTF("Successfully created rpmsg endpoint.\r\n"); + while(1) { + platform_poll(priv); + /* err or INIT */ + if (shutdown_req ) { + LPRINTF("got shutdown request \r\n"); + break; + } + } + LPRINTF("destroying rpmsg endpoint \r\n"); + 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...\r\n"); + + /* Initialize platform */ + ret = platform_init(argc, argv, &platform); + if (ret) { + LPERROR("Failed to initialize platform.\r\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.\r\n"); + ret = -1; + } else { + app(rpdev, platform); + platform_release_rpmsg_vdev(rpdev); + ret = 0; + } + } + + LPRINTF("Stopping application...\r\n"); + platform_cleanup(platform); + + return ret; +} diff --git a/apps/examples/oob_echo/rpmsg-oob-ping.c b/apps/examples/oob_echo/rpmsg-oob-ping.c new file mode 100644 index 0000000..8dc6a3b --- /dev/null +++ b/apps/examples/oob_echo/rpmsg-oob-ping.c @@ -0,0 +1,223 @@ +/* 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" +#include <metal/io.h> +#include <metal/device.h> + +#define APP_EPT_ADDR 0 +#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__) +#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__) + + +#define OUT_OF_BAND (0x1UL<<31) +#define INIT_MSG 0x2UL +#define ACK_MSG 0X3UL +#define DATA_MSG 0x4UL +#define SHUTDOWN_MSG 0x5UL + +#define TABLE_BASE_ADDRESS 0x3ee20000UL +#define BUFFER_SIZE 0x10000UL //64K.. can change to 65K as needed +#define NUM_BUFFERS 16 +#define NUM_MESSAGES_TO_SEND 32 + +#define DEV_BUS_NAME "platform" + + +static struct packet { + unsigned packet_type; + unsigned buffer_index; + unsigned packet_length; +}; + + +static void* large_buffer; + +static char data_to_send[BUFFER_SIZE]; +/* Globals */ +static struct rpmsg_endpoint lept; +static int ept_deleted = 0; + +static struct metal_device *large_buffer_shm_device; +static struct metal_io_region * large_buffer_io; + +static int setup_buffer(struct packet * p, unsigned buffer_index, unsigned packet_length, void * data){ + int ret; + + if (buffer_index > NUM_BUFFERS || packet_length > BUFFER_SIZE || !data) + LPERROR("send_buffer failed\r\n"); + p->packet_type = OUT_OF_BAND | DATA_MSG; + p->buffer_index = buffer_index; + p->packet_length = packet_length; + ret = metal_io_block_write(large_buffer_io, (BUFFER_SIZE * buffer_index), data, packet_length); + if (ret < 0){ + LPERROR("Unable to metal_io_block_write()\n"); + return -1; + } + LPRINTF("APU copied to large buffer \r\n"); + + return 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; + (void)len; + (void)ept; + + struct packet * p = (struct packet *)data; + + LPRINTF("APU message is received.\r\n" ); + LPRINTF("APU message contents : packet_type %x buffer_index %x packet_length %x\r\n", + p->packet_type, p->buffer_index, p->packet_length ); + if (p->packet_type & ACK_MSG){ + LPRINTF("APU received ACK_MSG"); + } + return RPMSG_SUCCESS; + +} + +static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) +{ + (void)ept; + rpmsg_destroy_ept(&lept); + LPRINTF("echo test: service is destroyed\r\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.\r\n"); + if (strcmp(name, RPMSG_SERVICE_NAME)) + LPERROR("Unexpected name service %s.\r\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; + + + /* 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.\r\n"); + return ret; + } + while (!is_rpmsg_ept_ready(&lept)) + platform_poll(priv); + + struct packet * p; + p = (struct packet *)metal_allocate_memory(sizeof(struct packet)); + if (!p){ + LPERROR("memory allocation failed for packet.\r\n"); + return -1; + } + + large_buffer = metal_allocate_memory(sizeof(BUFFER_SIZE*sizeof(char))); + if (!large_buffer){ + LPERROR("memory allocation failed for packet.\r\n"); + return -1; + } + + LPRINTF("APU begin demo \r\n"); + for(int number_messages_sent = 0; number_messages_sent < 3; number_messages_sent++) { + *data_to_send = number_messages_sent; + LPRINTF("APU: contents of message %i \r\n", number_messages_sent); + + ret = setup_buffer(p, number_messages_sent % NUM_BUFFERS, sizeof(data_to_send), data_to_send); + if (ret){ + LPERROR("setup_buffer failed \r\n"); + return RPMSG_ERR_PARAM; + } + + if (rpmsg_send(&lept, p, sizeof(struct packet)) < 0){ + LPERROR("rpmsg_send failed\r\n"); + return RPMSG_ERR_PARAM; + } + sleep(2); + + } + LPRINTF("APU side ending demo \r\n"); + metal_free_memory(p); + + rpmsg_destroy_ept(&lept); + + return 0; +} + +int main(int argc, char *argv[]) +{ + void *platform; + struct rpmsg_device *rpdev; + int ret; + + ret = platform_init(argc, argv, &platform); + if (ret) { + LPERROR("Failed to initialize platform.\r\n"); + ret = -1; + } else { + /* Initialize platform */ + printf("try to open device \r\n"); + ret = metal_device_open(DEV_BUS_NAME, "3ee20000.shm", &large_buffer_shm_device); + if (ret) { + fprintf(stderr, "ERROR: failed to open large_buffer_shm_device device: %d.\r\n", ret); + return -1; + } + + printf("able to open device. now try to get io region from device \r\n"); + printf("large_buffer_shm_device->num_regions %u \r\n", large_buffer_shm_device->num_regions); + large_buffer_io = metal_device_io_region(large_buffer_shm_device, 0); + if (!large_buffer_io){ + fprintf(stderr, "ERROR: failed to open large_buffer_io \r\n"); + return -1; + } + + printf("able to get io region from device \r\n"); + + 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.\r\n"); + ret = -1; + } else { + app(rpdev, platform); + platform_release_rpmsg_vdev(rpdev); + ret = 0; + } + } + + LPRINTF("Stopping application...\r\n"); + platform_cleanup(platform); + + return ret; +} +