* arch/arm/src/nrf53/nrf53_rptun.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <debug.h>
#include <nuttx/nuttx.h>
#include <nuttx/kthread.h>
#include <nuttx/rptun/rptun.h>
#include <nuttx/signal.h>
#include <nuttx/semaphore.h>
#include "arm_internal.h"
#include "nrf53_ipc.h"
#ifdef CONFIG_NRF53_APPCORE
# include "nrf53_cpunet.h"
#endif
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_NRF53_FLASH_PREFETCH
# warning rptun doesnt seem to work correctly with FLASH cache enabled
#endif
#define VRINGS (2)
#define VRING_ALIGN (8)
#define VRING_NR (8)
#define VRING_SIZE (512)
* We use the last 32kB of the App core RAM as a shared memory.
*/
#define VRING_SHMEM (0x20078000)
#define VRING0_NOTIFYID (RSC_NOTIFY_ID_ANY)
#define VRING1_NOTIFYID (RSC_NOTIFY_ID_ANY)
#define RPTUN_IPC_CHAN_MASTER_RX (0)
#define RPTUN_IPC_CHAN_SLAVE_RX (1)
#define RPTUN_IPC_CHAN_SLAVE_RESET (2)
#define RPTUN_IPC_CHAN_SLAVE_PANIC (3)
* Private Types
****************************************************************************/
struct nrf53_rptun_shmem_s
{
volatile uintptr_t base;
struct rptun_rsc_s rsc;
};
struct nrf53_rptun_dev_s
{
struct rptun_dev_s rptun;
rptun_callback_t callback;
void *arg;
bool master;
struct nrf53_rptun_shmem_s *shmem;
char cpuname[RPMSG_NAME_SIZE + 1];
};
* Private Function Prototypes
****************************************************************************/
static const char *nrf53_rptun_get_cpuname(struct rptun_dev_s *dev);
static struct resource_table *
nrf53_rptun_get_resource(struct rptun_dev_s *dev);
static bool nrf53_rptun_is_autostart(struct rptun_dev_s *dev);
static bool nrf53_rptun_is_master(struct rptun_dev_s *dev);
static int nrf53_rptun_start(struct rptun_dev_s *dev);
static int nrf53_rptun_stop(struct rptun_dev_s *dev);
static int nrf53_rptun_notify(struct rptun_dev_s *dev, uint32_t vqid);
static int nrf53_rptun_register_callback(struct rptun_dev_s *dev,
rptun_callback_t callback,
void *arg);
#ifdef CONFIG_NRF53_APPCORE
static void nrf53_rptun_reset(struct rptun_dev_s *dev, unsigned long value);
#endif
* Private Data
****************************************************************************/
static const struct rptun_ops_s g_nrf53_rptun_ops =
{
.get_cpuname = nrf53_rptun_get_cpuname,
.get_resource = nrf53_rptun_get_resource,
.is_autostart = nrf53_rptun_is_autostart,
.is_master = nrf53_rptun_is_master,
.start = nrf53_rptun_start,
.stop = nrf53_rptun_stop,
.notify = nrf53_rptun_notify,
.register_callback = nrf53_rptun_register_callback,
#ifdef CONFIG_NRF53_APPCORE
.reset = nrf53_rptun_reset,
#endif
};
#ifdef CONFIG_NRF53_APPCORE
static struct nrf53_rptun_shmem_s g_shmem __attribute__((section(".shmem")));
#endif
struct nrf53_rptun_dev_s g_rptun_dev;
static sem_t g_nrf53_rx_sig = SEM_INITIALIZER(0);
* Private Functions
****************************************************************************/
* Name: nrf53_rptun_get_cpuname
****************************************************************************/
static const char *nrf53_rptun_get_cpuname(struct rptun_dev_s *dev)
{
struct nrf53_rptun_dev_s *priv = container_of(dev,
struct nrf53_rptun_dev_s, rptun);
return priv->cpuname;
}
* Name: nrf53_rptun_get_resource
****************************************************************************/
static struct resource_table *
nrf53_rptun_get_resource(struct rptun_dev_s *dev)
{
struct nrf53_rptun_dev_s *priv = container_of(dev,
struct nrf53_rptun_dev_s, rptun);
struct rptun_rsc_s *rsc;
if (priv->shmem != NULL)
{
return &priv->shmem->rsc.rsc_tbl_hdr;
}
#ifdef CONFIG_NRF53_APPCORE
priv->shmem = &g_shmem;
#else
priv->shmem = (struct nrf53_rptun_shmem_s *)VRING_SHMEM;
#endif
if (priv->master)
{
rsc = &priv->shmem->rsc;
priv->shmem->base = (uintptr_t)priv->shmem;
rsc->rsc_tbl_hdr.ver = 1;
rsc->rsc_tbl_hdr.num = 2;
rsc->rsc_tbl_hdr.reserved[0] = 0;
rsc->rsc_tbl_hdr.reserved[1] = 0;
rsc->offset[0] = offsetof(struct rptun_rsc_s,
rpmsg_vdev);
rsc->rpmsg_vdev.type = RSC_VDEV;
rsc->rpmsg_vdev.id = VIRTIO_ID_RPMSG;
rsc->rpmsg_vdev.dfeatures = 1 << VIRTIO_RPMSG_F_NS
| 1 << VIRTIO_RPMSG_F_ACK
| 1 << VIRTIO_RPMSG_F_BUFSZ;
rsc->rpmsg_vdev.config_len = sizeof(struct fw_rsc_config);
rsc->rpmsg_vdev.num_of_vrings = VRINGS;
rsc->rpmsg_vring0.align = VRING_ALIGN;
rsc->rpmsg_vring0.num = VRING_NR;
rsc->rpmsg_vring0.notifyid = VRING0_NOTIFYID;
rsc->rpmsg_vring1.align = VRING_ALIGN;
rsc->rpmsg_vring1.num = VRING_NR;
rsc->rpmsg_vring1.notifyid = VRING1_NOTIFYID;
rsc->config.r2h_buf_size = VRING_SIZE;
rsc->config.h2r_buf_size = VRING_SIZE;
rsc->offset[1] = offsetof(struct rptun_rsc_s,
carveout);
rsc->carveout.type = RSC_CARVEOUT;
rsc->carveout.da = (uintptr_t)rsc + ALIGN_UP(sizeof
(struct rptun_rsc_s), VRING_ALIGN);
rsc->carveout.pa = FW_RSC_U32_ADDR_ANY;
rsc->carveout.len = VRING_SIZE * VRING_NR * VRINGS +
0x1000;
memcpy(rsc->carveout.name, "rpmsg_shm", 10);
}
else
{
while (priv->shmem->base == 0)
{
nxsig_usleep(100);
}
}
return &priv->shmem->rsc.rsc_tbl_hdr;
}
* Name: nrf53_rptun_is_autostart
****************************************************************************/
static bool nrf53_rptun_is_autostart(struct rptun_dev_s *dev)
{
return true;
}
* Name: nrf53_rptun_is_master
****************************************************************************/
static bool nrf53_rptun_is_master(struct rptun_dev_s *dev)
{
struct nrf53_rptun_dev_s *priv = container_of(dev,
struct nrf53_rptun_dev_s, rptun);
return priv->master;
}
* Name: nrf53_rptun_start
****************************************************************************/
static int nrf53_rptun_start(struct rptun_dev_s *dev)
{
return 0;
}
* Name: nrf53_rptun_stop
****************************************************************************/
static int nrf53_rptun_stop(struct rptun_dev_s *dev)
{
return 0;
}
* Name: nrf53_rptun_notify
****************************************************************************/
static int nrf53_rptun_notify(struct rptun_dev_s *dev, uint32_t vqid)
{
#ifdef CONFIG_NRF53_APPCORE
nrf53_ipc_signal(RPTUN_IPC_CHAN_SLAVE_RX);
#else
nrf53_ipc_signal(RPTUN_IPC_CHAN_MASTER_RX);
#endif
return 0;
}
* Name: nrf53_rptun_register_callback
****************************************************************************/
static int nrf53_rptun_register_callback(struct rptun_dev_s *dev,
rptun_callback_t callback,
void *arg)
{
struct nrf53_rptun_dev_s *priv = container_of(dev,
struct nrf53_rptun_dev_s, rptun);
priv->callback = callback;
priv->arg = arg;
return 0;
}
#ifdef CONFIG_NRF53_APPCORE
* Name: nrf53_rptun_reset
****************************************************************************/
static void nrf53_rptun_reset(struct rptun_dev_s *dev, unsigned long value)
{
if (value == (unsigned long)BOARDIOC_SOFTRESETCAUSE_PANIC)
{
nrf53_ipc_signal(RPTUN_IPC_CHAN_SLAVE_PANIC);
}
else if (value == 0)
{
nrf53_cpunet_power(false);
nrf53_cpunet_power(true);
}
else
{
nrf53_ipc_signal(RPTUN_IPC_CHAN_SLAVE_RESET);
}
}
#endif
#ifdef CONFIG_NRF53_APPCORE
* Name: nrf53_ipc_master_callback
****************************************************************************/
static void nrf53_ipc_master_callback(int id, void *arg)
{
ipcinfo("Rptun IPC master %d\n", id);
switch (id)
{
case RPTUN_IPC_CHAN_MASTER_RX:
{
nxsem_post(&g_nrf53_rx_sig);
break;
}
default:
{
DEBUGASSERT(0);
}
}
}
* Name: nrf53_rptun_ipc_app
****************************************************************************/
static void nrf53_rptun_ipc_app(struct nrf53_rptun_dev_s *dev)
{
DEBUGASSERT(dev);
nrf53_ipc_subscribe(RPTUN_IPC_CHAN_MASTER_RX,
nrf53_ipc_master_callback,
dev);
nrf53_ipc_send_cfg(RPTUN_IPC_CHAN_SLAVE_RX);
nrf53_ipc_send_cfg(RPTUN_IPC_CHAN_SLAVE_RESET);
nrf53_ipc_send_cfg(RPTUN_IPC_CHAN_SLAVE_PANIC);
}
#else
* Name: nrf53_ipc_slave_callback
****************************************************************************/
static void nrf53_ipc_slave_callback(int id, void *arg)
{
ipcinfo("Rptun IPC slave %d\n", id);
switch (id)
{
case RPTUN_IPC_CHAN_SLAVE_RX:
{
nxsem_post(&g_nrf53_rx_sig);
break;
}
case RPTUN_IPC_CHAN_SLAVE_RESET:
{
break;
}
case RPTUN_IPC_CHAN_SLAVE_PANIC:
{
PANIC();
}
default:
{
DEBUGASSERT(0);
}
}
}
* Name: nrf53_rptun_ipc_net
****************************************************************************/
static void nrf53_rptun_ipc_net(struct nrf53_rptun_dev_s *dev)
{
DEBUGASSERT(dev);
nrf53_ipc_subscribe(RPTUN_IPC_CHAN_SLAVE_RX,
nrf53_ipc_slave_callback,
dev);
nrf53_ipc_subscribe(RPTUN_IPC_CHAN_SLAVE_RESET,
nrf53_ipc_slave_callback,
dev);
nrf53_ipc_subscribe(RPTUN_IPC_CHAN_SLAVE_PANIC,
nrf53_ipc_slave_callback,
dev);
nrf53_ipc_send_cfg(RPTUN_IPC_CHAN_MASTER_RX);
}
#endif
* Name: nrf53_rptun_thread
****************************************************************************/
static int nrf53_rptun_thread(int argc, char *argv[])
{
struct nrf53_rptun_dev_s *dev = &g_rptun_dev;
while (1)
{
if (dev->callback != NULL)
{
dev->callback(dev->arg, RPTUN_NOTIFY_ALL);
}
nxsem_wait(&g_nrf53_rx_sig);
}
return 0;
}
* Public Functions
****************************************************************************/
int nrf53_rptun_init(const char *cpuname)
{
struct nrf53_rptun_dev_s *dev = &g_rptun_dev;
int ret = OK;
nrf53_ipc_init();
#ifdef CONFIG_NRF53_APPCORE
memset(&g_shmem, 0, sizeof(struct nrf53_rptun_shmem_s));
dev->master = true;
#else
dev->master = false;
#endif
#ifdef CONFIG_NRF53_APPCORE
nrf53_rptun_ipc_app(dev);
#else
nrf53_rptun_ipc_net(dev);
#endif
dev->rptun.ops = &g_nrf53_rptun_ops;
strncpy(dev->cpuname, cpuname, RPMSG_NAME_SIZE);
ret = rptun_initialize(&dev->rptun);
if (ret < 0)
{
ipcerr("ERROR: rptun_initialize failed %d!\n", ret);
goto errout;
}
ret = kthread_create("nrf53-rptun", CONFIG_RPTUN_PRIORITY,
CONFIG_RPTUN_STACKSIZE, nrf53_rptun_thread, NULL);
if (ret < 0)
{
ipcerr("ERROR: kthread_create failed %d\n", ret);
}
errout:
return ret;
}