blob: f511d0d4a2c6a1c0378119ff501ec0a5985e1d75 [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/k230/k230_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 <assert.h>
#include <debug.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <nuttx/nuttx.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/kthread.h>
#include <nuttx/semaphore.h>
#include <nuttx/spi/spi.h>
#include <nuttx/wqueue.h>
#include <nuttx/rptun/openamp.h>
#include <nuttx/rptun/rptun.h>
#include <nuttx/drivers/addrenv.h>
#include <nuttx/list.h>
#include <arch/barriers.h>
#include <arch/board/board.h>
#include "hardware/k230_memorymap.h"
#include "riscv_internal.h"
#include "k230_hart.h"
#include "k230_ipi.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define rpinfo rpmsginfo
#define rpwarn rpmsgwarn
#define rperr rpmsgerr
/* Vring config parameters taken from nrf53_rptun */
#define VRINGS 2 /* Number of vrings */
#define VRING_ALIGN 8 /* Vring alignment */
#define VRING_NR 8 /* Number of descriptors */
#define VRING_SIZE 512 /* Size of one descriptor */
/* The RPMSG default channel used with only one RPMSG channel */
#define VRING_SHMEM (CONFIG_K230_RPTUN_SHM_ADDR) /* Vring addr */
#define VRING0_NOTIFYID (RSC_NOTIFY_ID_ANY) /* Vring0 id */
#define VRING1_NOTIFYID (RSC_NOTIFY_ID_ANY) /* Vring1 id */
#define VRING_SHMEM_END (VRING_SHMEM + CONFIG_K230_RPTUN_SHM_SIZE)
/* Design notes:
*
* Though there are 16 IPI lines per K230 IPI device, we use only 1 IPI
* line for each core to notify the peer. Later we will see if more lines
* are really needed.
*
* For configurations, master and remote builds should use same IPI device
* defined by CONFIG_K230_RPTUN_IPI_DEVN otherwise the IPI notifications
* won't reach each other.
*/
#define RPTUN_IPI_DEVN CONFIG_K230_RPTUN_IPI_DEV
#define RPTUN_IPI_LINE 0
#define RPTUN_IPI_LINE_MASK (1 << RPTUN_IPI_LINE)
#if RPTUN_IPI_DEVN < 0 || RPTUN_IPI_DEVN > K230_IPI_DEVN_MAX
#error Invalid K230_RPTUN_IPI_DEV number
#endif
#ifdef CONFIG_K230_RPTUN_MASTER
#define RPTUN_IPI_ROLE IPI_ROLE_MASTER
#else
#define RPTUN_IPI_ROLE IPI_ROLE_REMOTE
#endif
/****************************************************************************
* Private Types
****************************************************************************/
struct k230_rptun_shmem_s
{
volatile uintptr_t base;
struct rptun_rsc_s rsc;
};
struct k230_rptun_dev_s
{
struct rptun_dev_s rptun;
rptun_callback_t callback;
void *arg;
bool master;
struct k230_rptun_shmem_s *shmem;
struct simple_addrenv_s addrenv[VRINGS];
char peername[RPMSG_NAME_SIZE + 1];
};
#define as_k230_rptun_dev(d) container_of(d, struct k230_rptun_dev_s, rptun)
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static const char *rp_get_cpuname(struct rptun_dev_s *dev);
static struct rptun_rsc_s *rp_get_resource(struct rptun_dev_s *dev);
static bool rp_is_autostart(struct rptun_dev_s *dev);
static bool rp_is_master(struct rptun_dev_s *dev);
static int rp_start(struct rptun_dev_s *dev);
static int rp_stop(struct rptun_dev_s *dev);
static int rp_notify(struct rptun_dev_s *dev, uint32_t notifyid);
static int rp_set_callback(struct rptun_dev_s *, rptun_callback_t, void *);
static void k230_rptun_callback(uint16_t comb, void *args);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct rptun_ops_s g_k230_rptun_ops =
{
.get_cpuname = rp_get_cpuname,
.get_resource = rp_get_resource,
.is_autostart = rp_is_autostart,
.is_master = rp_is_master,
.start = rp_start,
.stop = rp_stop,
.notify = rp_notify,
.register_callback = rp_set_callback,
};
#define SHMEM (struct k230_rptun_shmem_s*)VRING_SHMEM
#define SHMEM_SIZE sizeof(struct k230_rptun_shmem_s)
#define SHMEM_END (VRING_SHMEM + SHMEM_SIZE)
static struct k230_rptun_dev_s g_rptun_dev;
/****************************************************************************
* Private Functions
****************************************************************************/
static const char *rp_get_cpuname(struct rptun_dev_s *dev)
{
struct k230_rptun_dev_s *priv = as_k230_rptun_dev(dev);
return priv->peername;
}
static struct rptun_rsc_s *rp_get_resource(struct rptun_dev_s *dev)
{
struct k230_rptun_dev_s *priv = as_k230_rptun_dev(dev);
struct rptun_rsc_s *rsc;
if (priv->shmem != NULL)
{
return &priv->shmem->rsc;
}
priv->shmem = SHMEM;
if (priv->master)
{
/* Perform initial setup */
rsc = &priv->shmem->rsc;
rsc->rsc_tbl_hdr.ver = 1;
rsc->rsc_tbl_hdr.num = 1;
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;
priv->shmem->base = (uintptr_t)priv->shmem;
rpinfo("shmem:%lx, dev:%p\n", priv->shmem->base, dev);
}
else
{
/* TODO: use IPI later, polling now. */
rpinfo("wait for shmem %p...\n", priv->shmem);
while (priv->shmem->base == 0)
{
nxsig_usleep(100);
}
rpinfo("shmem:%lx, dev:%p\n", priv->shmem->base, dev);
}
return &priv->shmem->rsc;
}
static bool rp_is_autostart(struct rptun_dev_s *dev)
{
return true;
}
static bool rp_is_master(struct rptun_dev_s *dev)
{
struct k230_rptun_dev_s *priv = as_k230_rptun_dev(dev);
return priv->master;
}
static int rp_start(struct rptun_dev_s *dev)
{
rpinfo("%p\n", dev);
#ifdef CONFIG_K230_RPTUN_MASTER
k230_hart_big_boot(0x7000000);
#endif
return 0;
}
static int rp_stop(struct rptun_dev_s *dev)
{
rpinfo("%p\n", dev);
#ifdef CONFIG_K230_RPTUN_MASTER
k230_hart_big_stop();
#endif
return 0;
}
static int rp_notify(struct rptun_dev_s *dev, uint32_t vqid)
{
UNUSED(dev);
UNUSED(vqid);
k230_ipi_notify(RPTUN_IPI_DEVN, RPTUN_IPI_LINE);
return 0;
}
static int rp_set_callback(struct rptun_dev_s *dev, rptun_callback_t cb,
void *arg)
{
struct k230_rptun_dev_s *priv = as_k230_rptun_dev(dev);
priv->callback = cb;
priv->arg = arg;
return 0;
}
static void k230_rptun_callback(uint16_t comb, void *args)
{
UNUSED(comb);
struct k230_rptun_dev_s *dev = args;
if (dev->callback) dev->callback(dev->arg, RPTUN_NOTIFY_ALL);
}
/****************************************************************************
* Public Functions
****************************************************************************/
int k230_rptun_init(const char *peername)
{
struct k230_rptun_dev_s *dev = &g_rptun_dev;
int ret = OK;
memset(dev, 0, sizeof(*dev));
#ifdef CONFIG_K230_RPTUN_MASTER
/* master is responsible for initializing shmem */
memset((void *)SHMEM, 0, SHMEM_SIZE);
rpinfo("cleared %ld @ %p\n", SHMEM_SIZE, SHMEM);
dev->master = true;
#else
dev->master = false;
#endif
ret = k230_ipi_init(RPTUN_IPI_DEVN, RPTUN_IPI_LINE_MASK, RPTUN_IPI_ROLE,
k230_rptun_callback, dev);
if (ret < 0)
{
rperr("k230_ipi_init failed %d\n", ret);
goto ipierr;
}
/* Configure device */
dev->rptun.ops = &g_k230_rptun_ops;
strncpy(dev->peername, peername, RPMSG_NAME_SIZE);
ret = rptun_initialize(&dev->rptun);
if (ret < 0)
{
rperr("rptun_initialize failed %d!\n", ret);
goto errout;
}
return 0;
errout:
k230_ipi_finish(RPTUN_IPI_DEVN, RPTUN_IPI_LINE_MASK);
ipierr:
return ret;
}