samples: add openamp sample relying on resource table
This sample is designed to respond to the Linux rpmsg sample client. It should be platform independent and based on the the integration of a resource table in the elf file. Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
This commit is contained in:
parent
325331b7f9
commit
f6800aa1c4
7 changed files with 443 additions and 0 deletions
19
samples/subsys/ipc/openamp_rsc_table/CMakeLists.txt
Normal file
19
samples/subsys/ipc/openamp_rsc_table/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
cmake_minimum_required(VERSION 3.13.1)
|
||||
# Copyright (c) 2020 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
project(openamp_rsc_table_remote)
|
||||
|
||||
# METAL_MAX_DEVICE_REGIONS is used to give the number of memory regions shared
|
||||
# between processors. By default only one region is defined for the vrings
|
||||
# and rpmsg buffers. The METAL_MAX_DEVICE_REGIONS has to be redifined to add a
|
||||
# second region for the resource table.
|
||||
zephyr_compile_definitions(METAL_MAX_DEVICE_REGIONS=2)
|
||||
|
||||
target_include_directories(app PRIVATE ${LIBMETAL_INCLUDE_DIR} ${OPENAMP_INCLUDE_DIR} ${PLATFORM_DIR})
|
||||
|
||||
target_sources(app PRIVATE src/main_remote.c)
|
15
samples/subsys/ipc/openamp_rsc_table/Kconfig
Normal file
15
samples/subsys/ipc/openamp_rsc_table/Kconfig
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Private config options for openamp sample app
|
||||
|
||||
# Copyright (c) 2020 STMicroelectronics
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Workaround for not being able to have commas in macro arguments
|
||||
DT_CHOSEN_Z_IPC := zephyr,ipc
|
||||
|
||||
config OPENAMP_IPC_DEV_NAME
|
||||
string
|
||||
default "$(dt_chosen_label,$(DT_CHOSEN_Z_IPC))"
|
||||
help
|
||||
This option specifies the device name for the IPC device to be used
|
||||
|
||||
source "Kconfig.zephyr"
|
72
samples/subsys/ipc/openamp_rsc_table/README.rst
Normal file
72
samples/subsys/ipc/openamp_rsc_table/README.rst
Normal file
|
@ -0,0 +1,72 @@
|
|||
.. _openAMP_rsc_table_sample:
|
||||
|
||||
OpenAMP Sample Application using resource table
|
||||
###############################################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This application demonstrates how to use OpenAMP with Zephyr based on a resource
|
||||
table. It is designed to respond to the `Linux rpmsg client sample <https://elixir.bootlin.com/linux/latest/source/samples/rpmsg/rpmsg_client_sample.c>`_.
|
||||
This sample implementation is compatible with platforms that embed
|
||||
a Linux kernel OS on the main processor and a Zephyr application on
|
||||
the co-processor.
|
||||
|
||||
Building the application
|
||||
*************************
|
||||
|
||||
Zephyr
|
||||
-------
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/subsys/ipc/openamp_rsc_table
|
||||
:goals: test
|
||||
|
||||
Linux
|
||||
------
|
||||
|
||||
Enable SAMPLE_RPMSG_CLIENT configuration to build and install
|
||||
the rpmsg_client_sample.ko module on the target.
|
||||
|
||||
Running the sample
|
||||
*******************
|
||||
|
||||
Zephyr console
|
||||
---------------
|
||||
|
||||
Open a serial terminal (minicom, putty, etc.) and connect the board with the
|
||||
following settings:
|
||||
|
||||
- Speed: 115200
|
||||
- Data: 8 bits
|
||||
- Parity: None
|
||||
- Stop bits: 1
|
||||
|
||||
Reset the board.
|
||||
|
||||
Linux console
|
||||
---------------
|
||||
|
||||
Open a Linux shell (minicom, ssh, etc.) and insert a module into the Linux Kernel
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@linuxshell: insmod rpmsg_client_sample.ko
|
||||
|
||||
Result on Zephyr console
|
||||
-------------------------
|
||||
|
||||
The following message will appear on the corresponding Zephyr console:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
***** Booting Zephyr OS v#.##.#-####-g########## *****
|
||||
Starting application thread!
|
||||
|
||||
OpenAMP demo started
|
||||
Remote core received message 1: hello world!
|
||||
Remote core received message 2: hello world!
|
||||
Remote core received message 3: hello world!
|
||||
...
|
||||
Remote core received message 100: hello world!
|
||||
OpenAMP demo ended.
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2020, STMICROLECTRONICS
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
/*
|
||||
* shared memory reserved for the inter-processor communication
|
||||
*/
|
||||
zephyr,ipc_shm = &mcusram3;
|
||||
zephyr,ipc = &mailbox;
|
||||
};
|
||||
|
||||
mcusram3: memory1@10040000 {
|
||||
compatible = "mmio-sram";
|
||||
reg = <0x10040000 DT_SIZE_K(64)>;
|
||||
};
|
||||
};
|
||||
|
||||
&mcusram {
|
||||
reg = <0x10000000 DT_SIZE_K(256)>;
|
||||
};
|
11
samples/subsys/ipc/openamp_rsc_table/prj.conf
Normal file
11
samples/subsys/ipc/openamp_rsc_table/prj.conf
Normal file
|
@ -0,0 +1,11 @@
|
|||
CONFIG_KERNEL_BIN_NAME="zephyr_openamp_rsc_table"
|
||||
CONFIG_PRINTK=n
|
||||
CONFIG_IPM=y
|
||||
CONFIG_IPM_MCUX=y
|
||||
CONFIG_PLATFORM_SPECIFIC_INIT=n
|
||||
CONFIG_MAIN_STACK_SIZE=1024
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=1024
|
||||
CONFIG_OPENAMP=y
|
||||
CONFIG_OPENAMP_RSC_TABLE_NUM_RPMSG_BUFF=8
|
||||
CONFIG_OPENAMP_RSC_TABLE=y
|
||||
CONFIG_OPENAMP_MASTER=n
|
9
samples/subsys/ipc/openamp_rsc_table/sample.yaml
Normal file
9
samples/subsys/ipc/openamp_rsc_table/sample.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
sample:
|
||||
description: This app provides an example of how to integrate OpenAMP
|
||||
with Zephyr in cluding a esource table.
|
||||
name: OpenAMP with resource table example integration
|
||||
tests:
|
||||
sample.subsys.ipc.openamp_rs_table:
|
||||
build_only: true
|
||||
platform_whitelist: stm32mp157c_dk2
|
||||
tags: ipm
|
293
samples/subsys/ipc/openamp_rsc_table/src/main_remote.c
Normal file
293
samples/subsys/ipc/openamp_rsc_table/src/main_remote.c
Normal file
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright (c) 2020, STMICROLECTRONICS
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <device.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drivers/ipm.h>
|
||||
|
||||
#include <openamp/open_amp.h>
|
||||
#include <metal/device.h>
|
||||
#include <resource_table.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(openamp_rsc_table, LOG_LEVEL_DBG);
|
||||
|
||||
#define RPMSG_CHAN_NAME "rpmsg-client-sample"
|
||||
#define SHM_DEVICE_NAME "shm"
|
||||
|
||||
/* constant derivated from linker symbols */
|
||||
#define SHM_START_ADDR DT_IPC_SHM_BASE_ADDRESS
|
||||
#define SHM_SIZE (DT_IPC_SHM_SIZE * 1024)
|
||||
|
||||
#define APP_TASK_STACK_SIZE (512)
|
||||
K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE);
|
||||
static struct k_thread thread_data;
|
||||
|
||||
static struct device *ipm_handle;
|
||||
|
||||
static metal_phys_addr_t shm_physmap = SHM_START_ADDR;
|
||||
|
||||
struct metal_device shm_device = {
|
||||
.name = SHM_DEVICE_NAME,
|
||||
.num_regions = 2,
|
||||
.regions = {
|
||||
{.virt = NULL}, /* shared memory */
|
||||
{.virt = NULL}, /* rsc_table memory */
|
||||
},
|
||||
.node = { NULL },
|
||||
.irq_num = 0,
|
||||
.irq_info = NULL
|
||||
};
|
||||
|
||||
static struct metal_io_region *shm_io;
|
||||
static struct rpmsg_virtio_shm_pool shpool;
|
||||
|
||||
static struct metal_io_region *rsc_io;
|
||||
static struct rpmsg_virtio_device rvdev;
|
||||
|
||||
static void *rsc_table;
|
||||
|
||||
static char rcv_msg[20]; /* should receive "Hello world!" */
|
||||
static unsigned int rcv_len;
|
||||
static struct rpmsg_endpoint rcv_ept;
|
||||
|
||||
static K_SEM_DEFINE(data_sem, 0, 1);
|
||||
static K_SEM_DEFINE(data_rx_sem, 0, 1);
|
||||
|
||||
static void platform_ipm_callback(void *context, u32_t id, volatile void *data)
|
||||
{
|
||||
LOG_DBG("%s: msg received from mb %d\n", __func__, id);
|
||||
k_sem_give(&data_sem);
|
||||
}
|
||||
|
||||
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data,
|
||||
size_t len, uint32_t src, void *priv)
|
||||
{
|
||||
memcpy(rcv_msg, data, len);
|
||||
rcv_len = len;
|
||||
k_sem_give(&data_rx_sem);
|
||||
|
||||
return RPMSG_SUCCESS;
|
||||
}
|
||||
|
||||
static void receive_message(unsigned char **msg, unsigned int *len)
|
||||
{
|
||||
while (k_sem_take(&data_rx_sem, K_NO_WAIT) != 0) {
|
||||
int status = k_sem_take(&data_sem, K_FOREVER);
|
||||
|
||||
if (status == 0) {
|
||||
rproc_virtio_notified(rvdev.vdev, VRING1_ID);
|
||||
}
|
||||
}
|
||||
*len = rcv_len;
|
||||
*msg = rcv_msg;
|
||||
}
|
||||
|
||||
static void new_service_cb(struct rpmsg_device *rdev, const char *name,
|
||||
uint32_t src)
|
||||
{
|
||||
LOG_ERR("%s: unexpected ns service receive for name %s\n",
|
||||
__func__, name);
|
||||
}
|
||||
|
||||
int mailbox_notify(void *priv, uint32_t id)
|
||||
{
|
||||
ARG_UNUSED(priv);
|
||||
|
||||
LOG_DBG("%s: msg received\n", __func__);
|
||||
ipm_send(ipm_handle, 0, id, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int platform_init(void)
|
||||
{
|
||||
void *rsc_tab_addr;
|
||||
int rsc_size;
|
||||
struct metal_device *device;
|
||||
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
|
||||
int status;
|
||||
|
||||
status = metal_init(&metal_params);
|
||||
if (status) {
|
||||
LOG_DBG("metal_init: failed: %d\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = metal_register_generic_device(&shm_device);
|
||||
if (status) {
|
||||
LOG_DBG("Couldn't register shared memory: %d\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = metal_device_open("generic", SHM_DEVICE_NAME, &device);
|
||||
if (status) {
|
||||
LOG_DBG("metal_device_open failed: %d\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* declare shared memory region */
|
||||
metal_io_init(&device->regions[0], (void *)SHM_START_ADDR, &shm_physmap,
|
||||
SHM_SIZE, -1, 0, NULL);
|
||||
|
||||
shm_io = metal_device_io_region(device, 0);
|
||||
if (!shm_io) {
|
||||
LOG_DBG("Failed to get shm_io region\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* declare resource table region */
|
||||
rsc_table_get(&rsc_tab_addr, &rsc_size);
|
||||
rsc_table = (struct st_resource_table *)rsc_tab_addr;
|
||||
|
||||
metal_io_init(&device->regions[1], rsc_table,
|
||||
(metal_phys_addr_t *)rsc_table, rsc_size, -1, 0, NULL);
|
||||
|
||||
rsc_io = metal_device_io_region(device, 1);
|
||||
if (!rsc_io) {
|
||||
LOG_DBG("Failed to get rsc_io region\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* setup IPM */
|
||||
ipm_handle = device_get_binding(CONFIG_OPENAMP_IPC_DEV_NAME);
|
||||
if (!ipm_handle) {
|
||||
LOG_DBG("Failed to find ipm device\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipm_register_callback(ipm_handle, platform_ipm_callback, NULL);
|
||||
|
||||
status = ipm_set_enabled(ipm_handle, 1);
|
||||
if (status) {
|
||||
LOG_DBG("ipm_set_enabled failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup_system(void)
|
||||
{
|
||||
ipm_set_enabled(ipm_handle, 0);
|
||||
rpmsg_deinit_vdev(&rvdev);
|
||||
metal_finish();
|
||||
}
|
||||
|
||||
struct rpmsg_device *
|
||||
platform_create_rpmsg_vdev(unsigned int vdev_index,
|
||||
unsigned int role,
|
||||
void (*rst_cb)(struct virtio_device *vdev),
|
||||
rpmsg_ns_bind_cb ns_cb)
|
||||
{
|
||||
struct fw_rsc_vdev_vring *vring_rsc;
|
||||
struct virtio_device *vdev;
|
||||
int ret;
|
||||
|
||||
vdev = rproc_virtio_create_vdev(VIRTIO_DEV_SLAVE, VDEV_ID,
|
||||
rsc_table_to_vdev(rsc_table),
|
||||
rsc_io, NULL, mailbox_notify, NULL);
|
||||
|
||||
if (!vdev) {
|
||||
LOG_DBG("failed to create vdev\r\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* wait master rpmsg init completion */
|
||||
rproc_virtio_wait_remote_ready(vdev);
|
||||
|
||||
vring_rsc = rsc_table_get_vring0(rsc_table);
|
||||
ret = rproc_virtio_init_vring(vdev, 0, vring_rsc->notifyid,
|
||||
(void *)vring_rsc->da, rsc_io,
|
||||
vring_rsc->num, vring_rsc->align);
|
||||
if (ret) {
|
||||
LOG_DBG("failed to init vring 0\r\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
vring_rsc = rsc_table_get_vring1(rsc_table);
|
||||
ret = rproc_virtio_init_vring(vdev, 1, vring_rsc->notifyid,
|
||||
(void *)vring_rsc->da, rsc_io,
|
||||
vring_rsc->num, vring_rsc->align);
|
||||
if (ret) {
|
||||
LOG_DBG("failed to init vring 1\r\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
rpmsg_virtio_init_shm_pool(&shpool, NULL, SHM_SIZE);
|
||||
ret = rpmsg_init_vdev(&rvdev, vdev, ns_cb, shm_io, &shpool);
|
||||
|
||||
if (ret) {
|
||||
LOG_DBG("failed rpmsg_init_vdev\r\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return rpmsg_virtio_get_rpmsg_device(&rvdev);
|
||||
|
||||
failed:
|
||||
rproc_virtio_remove_vdev(vdev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void app_task(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
ARG_UNUSED(arg1);
|
||||
ARG_UNUSED(arg2);
|
||||
ARG_UNUSED(arg3);
|
||||
struct rpmsg_device *rpdev;
|
||||
unsigned char *msg;
|
||||
unsigned int len, msg_cnt = 0;
|
||||
int ret = 0;
|
||||
|
||||
printk("\r\nOpenAMP[remote] linux responder demo started\r\n");
|
||||
|
||||
/* Initialize platform */
|
||||
ret = platform_init();
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to initialize platform\n");
|
||||
ret = -1;
|
||||
goto task_end;
|
||||
}
|
||||
|
||||
rpdev = platform_create_rpmsg_vdev(0, VIRTIO_DEV_SLAVE, NULL,
|
||||
new_service_cb);
|
||||
if (!rpdev) {
|
||||
LOG_ERR("Failed to create rpmsg virtio device\n");
|
||||
ret = -1;
|
||||
goto task_end;
|
||||
}
|
||||
|
||||
ret = rpmsg_create_ept(&rcv_ept, rpdev, RPMSG_CHAN_NAME,
|
||||
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
|
||||
rpmsg_recv_callback, NULL);
|
||||
if (ret != 0)
|
||||
LOG_ERR("error while creating endpoint(%d)\n", ret);
|
||||
|
||||
while (msg_cnt < 100) {
|
||||
receive_message(&msg, &len);
|
||||
msg_cnt++;
|
||||
rpmsg_send(&rcv_ept, msg, len);
|
||||
}
|
||||
rpmsg_destroy_ept(&rcv_ept);
|
||||
|
||||
task_end:
|
||||
cleanup_system();
|
||||
|
||||
printk("OpenAMP demo ended\n");
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
printk("Starting application thread!\n");
|
||||
k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE,
|
||||
(k_thread_entry_t)app_task,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue