As of today <zephyr/zephyr.h> is 100% equivalent to <zephyr/kernel.h>. This patch proposes to then include <zephyr/kernel.h> instead of <zephyr/zephyr.h> since it is more clear that you are including the Kernel APIs and (probably) nothing else. <zephyr/zephyr.h> sounds like a catch-all header that may be confusing. Most applications need to include a bunch of other things to compile, e.g. driver headers or subsystem headers like BT, logging, etc. The idea of a catch-all header in Zephyr is probably not feasible anyway. Reason is that Zephyr is not a library, like it could be for example `libpython`. Zephyr provides many utilities nowadays: a kernel, drivers, subsystems, etc and things will likely grow. A catch-all header would be massive, difficult to keep up-to-date. It is also likely that an application will only build a small subset. Note that subsystem-level headers may use a catch-all approach to make things easier, though. NOTE: This patch is **NOT** removing the header, just removing its usage in-tree. I'd advocate for its deprecation (add a #warning on it), but I understand many people will have concerns. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
265 lines
5.9 KiB
C
265 lines
5.9 KiB
C
/*
|
|
* Copyright (c) 2018, NXP
|
|
* Copyright (c) 2018, Nordic Semiconductor ASA
|
|
* Copyright (c) 2018-2019, Linaro Limited
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/drivers/ipm.h>
|
|
#include <zephyr/sys/printk.h>
|
|
#include <zephyr/device.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <openamp/open_amp.h>
|
|
#include <metal/device.h>
|
|
|
|
#include "common.h"
|
|
|
|
#define APP_TASK_STACK_SIZE (1024)
|
|
K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE);
|
|
static struct k_thread thread_data;
|
|
|
|
static const struct device *const ipm_handle =
|
|
DEVICE_DT_GET(DT_CHOSEN(zephyr_ipc));
|
|
|
|
static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR };
|
|
static struct metal_device shm_device = {
|
|
.name = SHM_DEVICE_NAME,
|
|
.bus = NULL,
|
|
.num_regions = 1,
|
|
{
|
|
{
|
|
.virt = (void *) SHM_START_ADDR,
|
|
.physmap = shm_physmap,
|
|
.size = SHM_SIZE,
|
|
.page_shift = 0xffffffff,
|
|
.page_mask = 0xffffffff,
|
|
.mem_flags = 0,
|
|
.ops = { NULL },
|
|
},
|
|
},
|
|
.node = { NULL },
|
|
.irq_num = 0,
|
|
.irq_info = NULL
|
|
};
|
|
|
|
static volatile unsigned int received_data;
|
|
|
|
static struct virtio_vring_info rvrings[2] = {
|
|
[0] = {
|
|
.info.align = VRING_ALIGNMENT,
|
|
},
|
|
[1] = {
|
|
.info.align = VRING_ALIGNMENT,
|
|
},
|
|
};
|
|
static struct virtio_device vdev;
|
|
static struct rpmsg_virtio_device rvdev;
|
|
static struct metal_io_region *io;
|
|
static struct virtqueue *vq[2];
|
|
|
|
static unsigned char virtio_get_status(struct virtio_device *vdev)
|
|
{
|
|
return sys_read8(VDEV_STATUS_ADDR);
|
|
}
|
|
|
|
static uint32_t virtio_get_features(struct virtio_device *vdev)
|
|
{
|
|
return 1 << VIRTIO_RPMSG_F_NS;
|
|
}
|
|
|
|
static void virtio_notify(struct virtqueue *vq)
|
|
{
|
|
#if defined(CONFIG_SOC_MPS2_AN521) || \
|
|
defined(CONFIG_SOC_V2M_MUSCA_B1)
|
|
uint32_t current_core = sse_200_platform_get_cpu_id();
|
|
|
|
ipm_send(ipm_handle, 0, current_core ? 0 : 1, 0, 1);
|
|
#else
|
|
uint32_t dummy_data = 0x00110011; /* Some data must be provided */
|
|
|
|
ipm_send(ipm_handle, 0, 0, &dummy_data, sizeof(dummy_data));
|
|
#endif /* #if defined(CONFIG_SOC_MPS2_AN521) */
|
|
}
|
|
|
|
struct virtio_dispatch dispatch = {
|
|
.get_status = virtio_get_status,
|
|
.get_features = virtio_get_features,
|
|
.notify = virtio_notify,
|
|
};
|
|
|
|
static K_SEM_DEFINE(data_sem, 0, 1);
|
|
static K_SEM_DEFINE(data_rx_sem, 0, 1);
|
|
|
|
static void platform_ipm_callback(const struct device *dev, void *context,
|
|
uint32_t id, volatile void *data)
|
|
{
|
|
k_sem_give(&data_sem);
|
|
}
|
|
|
|
int endpoint_cb(struct rpmsg_endpoint *ept, void *data,
|
|
size_t len, uint32_t src, void *priv)
|
|
{
|
|
received_data = *((unsigned int *) data);
|
|
|
|
k_sem_give(&data_rx_sem);
|
|
|
|
return RPMSG_SUCCESS;
|
|
}
|
|
|
|
static K_SEM_DEFINE(ept_sem, 0, 1);
|
|
|
|
struct rpmsg_endpoint my_ept;
|
|
struct rpmsg_endpoint *ep = &my_ept;
|
|
|
|
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
|
|
{
|
|
(void)ept;
|
|
rpmsg_destroy_ept(ep);
|
|
}
|
|
|
|
static unsigned int receive_message(void)
|
|
{
|
|
while (k_sem_take(&data_rx_sem, K_NO_WAIT) != 0) {
|
|
int status = k_sem_take(&data_sem, K_FOREVER);
|
|
|
|
if (status == 0) {
|
|
virtqueue_notification(vq[1]);
|
|
}
|
|
}
|
|
return received_data;
|
|
}
|
|
|
|
static int send_message(unsigned int message)
|
|
{
|
|
return rpmsg_send(ep, &message, sizeof(message));
|
|
}
|
|
|
|
void app_task(void *arg1, void *arg2, void *arg3)
|
|
{
|
|
ARG_UNUSED(arg1);
|
|
ARG_UNUSED(arg2);
|
|
ARG_UNUSED(arg3);
|
|
int status = 0;
|
|
unsigned int message = 0U;
|
|
struct metal_device *device;
|
|
struct rpmsg_device *rdev;
|
|
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
|
|
|
|
printk("\r\nOpenAMP[remote] demo started\r\n");
|
|
|
|
status = metal_init(&metal_params);
|
|
if (status != 0) {
|
|
printk("metal_init: failed - error code %d\n", status);
|
|
return;
|
|
}
|
|
|
|
status = metal_register_generic_device(&shm_device);
|
|
if (status != 0) {
|
|
printk("Couldn't register shared memory device: %d\n", status);
|
|
return;
|
|
}
|
|
|
|
status = metal_device_open("generic", SHM_DEVICE_NAME, &device);
|
|
if (status != 0) {
|
|
printk("metal_device_open failed: %d\n", status);
|
|
return;
|
|
}
|
|
|
|
io = metal_device_io_region(device, 0);
|
|
if (io == NULL) {
|
|
printk("metal_device_io_region failed to get region\n");
|
|
return;
|
|
}
|
|
|
|
/* setup IPM */
|
|
if (!device_is_ready(ipm_handle)) {
|
|
printk("IPM device is not ready\n");
|
|
return;
|
|
}
|
|
|
|
ipm_register_callback(ipm_handle, platform_ipm_callback, NULL);
|
|
|
|
status = ipm_set_enabled(ipm_handle, 1);
|
|
if (status != 0) {
|
|
printk("ipm_set_enabled failed\n");
|
|
return;
|
|
}
|
|
|
|
/* setup vdev */
|
|
vq[0] = virtqueue_allocate(VRING_SIZE);
|
|
if (vq[0] == NULL) {
|
|
printk("virtqueue_allocate failed to alloc vq[0]\n");
|
|
return;
|
|
}
|
|
vq[1] = virtqueue_allocate(VRING_SIZE);
|
|
if (vq[1] == NULL) {
|
|
printk("virtqueue_allocate failed to alloc vq[1]\n");
|
|
return;
|
|
}
|
|
|
|
vdev.role = RPMSG_REMOTE;
|
|
vdev.vrings_num = VRING_COUNT;
|
|
vdev.func = &dispatch;
|
|
rvrings[0].io = io;
|
|
rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS;
|
|
rvrings[0].info.num_descs = VRING_SIZE;
|
|
rvrings[0].info.align = VRING_ALIGNMENT;
|
|
rvrings[0].vq = vq[0];
|
|
|
|
rvrings[1].io = io;
|
|
rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS;
|
|
rvrings[1].info.num_descs = VRING_SIZE;
|
|
rvrings[1].info.align = VRING_ALIGNMENT;
|
|
rvrings[1].vq = vq[1];
|
|
|
|
vdev.vrings_info = &rvrings[0];
|
|
|
|
/* setup rvdev */
|
|
status = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL);
|
|
if (status != 0) {
|
|
printk("rpmsg_init_vdev failed %d\n", status);
|
|
return;
|
|
}
|
|
|
|
rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
|
|
|
|
status = rpmsg_create_ept(ep, rdev, "k", RPMSG_ADDR_ANY,
|
|
RPMSG_ADDR_ANY, endpoint_cb, rpmsg_service_unbind);
|
|
if (status != 0) {
|
|
printk("rpmsg_create_ept failed %d\n", status);
|
|
return;
|
|
}
|
|
|
|
while (message < 99) {
|
|
message = receive_message();
|
|
printk("Remote core received a message: %d\n", message);
|
|
|
|
message++;
|
|
status = send_message(message);
|
|
if (status < 0) {
|
|
printk("send_message(%d) failed with status %d\n",
|
|
message, status);
|
|
goto _cleanup;
|
|
}
|
|
}
|
|
|
|
_cleanup:
|
|
rpmsg_deinit_vdev(&rvdev);
|
|
metal_finish();
|
|
|
|
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);
|
|
}
|