bluetooth: hci: rpmsg: Use RPMsg Service
This patch modifies Bluetooth HCI RPMsg drivers and samples to use RPMsg Service instead of configuring OpenAMP directly in the driver or the sample. Co-authored-by: Piotr Szkotak <piotr.szkotak@nordicsemi.no> Signed-off-by: Hubert Miś <hubert.mis@nordicsemi.no>
This commit is contained in:
parent
9f1ea0f8c7
commit
5548917e69
5 changed files with 68 additions and 471 deletions
|
@ -112,26 +112,16 @@ config BT_RPMSG_NRF53
|
||||||
bool "nRF53 configuration of RPMsg"
|
bool "nRF53 configuration of RPMsg"
|
||||||
default y if SOC_NRF5340_CPUAPP
|
default y if SOC_NRF5340_CPUAPP
|
||||||
depends on BT_RPMSG
|
depends on BT_RPMSG
|
||||||
select IPM
|
select RPMSG_SERVICE
|
||||||
select IPM_NRFX
|
|
||||||
select IPM_MSG_CH_1_ENABLE
|
|
||||||
select IPM_MSG_CH_0_ENABLE
|
|
||||||
select IPM_MSG_CH_0_TX
|
|
||||||
select IPM_MSG_CH_1_RX
|
|
||||||
select OPENAMP
|
|
||||||
help
|
help
|
||||||
Enable RPMsg configuration for nRF53. Two channels of the IPM driver
|
Enable RPMsg configuration for nRF53. Two channels of the IPM driver
|
||||||
are used in the HCI driver: channel 0 for TX and channel 1 for RX.
|
are used in the HCI driver: channel 0 for TX and channel 1 for RX.
|
||||||
|
|
||||||
if BT_RPMSG_NRF53
|
if BT_RPMSG_NRF53
|
||||||
|
|
||||||
config BT_RPMSG_NRF53_RX_STACK_SIZE
|
choice RPMSG_SERVICE_MODE
|
||||||
int "RPMsg stack size for RX thread"
|
default RPMSG_SERVICE_MODE_MASTER
|
||||||
default 1024
|
endchoice
|
||||||
|
|
||||||
config BT_RPMSG_NRF53_RX_PRIO
|
|
||||||
int "RPMsg RX thread priority"
|
|
||||||
default 8
|
|
||||||
|
|
||||||
endif # BT_RPMSG_NRF53
|
endif # BT_RPMSG_NRF53
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
int bt_rpmsg_platform_init(void);
|
int bt_rpmsg_platform_init(void);
|
||||||
int bt_rpmsg_platform_send(struct net_buf *buf);
|
int bt_rpmsg_platform_send(struct net_buf *buf);
|
||||||
|
int bt_rpmsg_platform_endpoint_is_bound(void);
|
||||||
|
|
||||||
static bool is_hci_event_discardable(const uint8_t *evt_data)
|
static bool is_hci_event_discardable(const uint8_t *evt_data)
|
||||||
{
|
{
|
||||||
|
@ -234,7 +235,10 @@ static int bt_rpmsg_open(void)
|
||||||
{
|
{
|
||||||
BT_DBG("");
|
BT_DBG("");
|
||||||
|
|
||||||
return bt_rpmsg_platform_init();
|
while (!bt_rpmsg_platform_endpoint_is_bound()) {
|
||||||
|
k_sleep(K_MSEC(1));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct bt_hci_driver drv = {
|
static const struct bt_hci_driver drv = {
|
||||||
|
@ -251,7 +255,20 @@ static int bt_rpmsg_init(const struct device *unused)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(unused);
|
ARG_UNUSED(unused);
|
||||||
|
|
||||||
return bt_hci_driver_register(&drv);
|
int err;
|
||||||
|
|
||||||
|
err = bt_rpmsg_platform_init();
|
||||||
|
if (err < 0) {
|
||||||
|
BT_ERR("Failed to initialize BT RPMSG (err %d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_hci_driver_register(&drv);
|
||||||
|
if (err < 0) {
|
||||||
|
BT_ERR("Failed to register BT HIC driver (err %d)", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYS_INIT(bt_rpmsg_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
SYS_INIT(bt_rpmsg_init, POST_KERNEL, CONFIG_RPMSG_SERVICE_EP_REG_PRIORITY);
|
||||||
|
|
|
@ -6,10 +6,7 @@
|
||||||
|
|
||||||
#include <drivers/ipm.h>
|
#include <drivers/ipm.h>
|
||||||
|
|
||||||
#include <openamp/open_amp.h>
|
#include <ipc/rpmsg_service.h>
|
||||||
#include <metal/sys.h>
|
|
||||||
#include <metal/device.h>
|
|
||||||
#include <metal/alloc.h>
|
|
||||||
|
|
||||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||||
#define LOG_MODULE_NAME bt_hci_driver_nrf53
|
#define LOG_MODULE_NAME bt_hci_driver_nrf53
|
||||||
|
@ -20,107 +17,10 @@ void bt_rpmsg_rx(uint8_t *data, size_t len);
|
||||||
static K_SEM_DEFINE(ready_sem, 0, 1);
|
static K_SEM_DEFINE(ready_sem, 0, 1);
|
||||||
static K_SEM_DEFINE(rx_sem, 0, 1);
|
static K_SEM_DEFINE(rx_sem, 0, 1);
|
||||||
|
|
||||||
static K_KERNEL_STACK_DEFINE(bt_rpmsg_rx_thread_stack,
|
|
||||||
CONFIG_BT_RPMSG_NRF53_RX_STACK_SIZE);
|
|
||||||
static struct k_thread bt_rpmsg_rx_thread_data;
|
|
||||||
|
|
||||||
static const struct device *ipm_tx_handle;
|
|
||||||
static const struct device *ipm_rx_handle;
|
|
||||||
|
|
||||||
/* Configuration defines */
|
|
||||||
|
|
||||||
#define SHM_NODE DT_CHOSEN(zephyr_ipc_shm)
|
|
||||||
#define SHM_BASE_ADDRESS DT_REG_ADDR(SHM_NODE)
|
|
||||||
|
|
||||||
#define SHM_START_ADDR (SHM_BASE_ADDRESS + 0x400)
|
|
||||||
#define SHM_SIZE 0x7c00
|
|
||||||
#define SHM_DEVICE_NAME "sram0.shm"
|
|
||||||
|
|
||||||
BUILD_ASSERT((SHM_START_ADDR + SHM_SIZE - SHM_BASE_ADDRESS)
|
|
||||||
<= DT_REG_SIZE(SHM_NODE),
|
|
||||||
"Allocated size exceeds available shared memory reserved for IPC");
|
|
||||||
|
|
||||||
#define VRING_COUNT 2
|
|
||||||
#define VRING_TX_ADDRESS (SHM_START_ADDR + SHM_SIZE - 0x400)
|
|
||||||
#define VRING_RX_ADDRESS (VRING_TX_ADDRESS - 0x400)
|
|
||||||
#define VRING_ALIGNMENT 4
|
|
||||||
#define VRING_SIZE 16
|
|
||||||
|
|
||||||
#define VDEV_STATUS_ADDR SHM_BASE_ADDRESS
|
|
||||||
|
|
||||||
BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE >= 1024,
|
BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE >= 1024,
|
||||||
"Not enough heap memory for RPMsg queue allocation");
|
"Not enough heap memory for RPMsg queue allocation");
|
||||||
|
|
||||||
/* End of configuration defines */
|
static int endpoint_id;
|
||||||
|
|
||||||
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,
|
|
||||||
.regions = {
|
|
||||||
{
|
|
||||||
.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 struct virtqueue *vq[2];
|
|
||||||
static struct rpmsg_endpoint ep;
|
|
||||||
|
|
||||||
static unsigned char virtio_get_status(struct virtio_device *vdev)
|
|
||||||
{
|
|
||||||
return VIRTIO_CONFIG_STATUS_DRIVER_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_set_status(struct virtio_device *vdev, unsigned char status)
|
|
||||||
{
|
|
||||||
sys_write8(status, VDEV_STATUS_ADDR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t virtio_get_features(struct virtio_device *vdev)
|
|
||||||
{
|
|
||||||
return BIT(VIRTIO_RPMSG_F_NS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_set_features(struct virtio_device *vdev, uint32_t features)
|
|
||||||
{
|
|
||||||
/* No need for implementation */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_notify(struct virtqueue *vq)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
|
|
||||||
status = ipm_send(ipm_tx_handle, 0, 0, NULL, 0);
|
|
||||||
if (status != 0) {
|
|
||||||
BT_ERR("ipm_send failed to notify: %d", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct virtio_dispatch dispatch = {
|
|
||||||
.get_status = virtio_get_status,
|
|
||||||
.set_status = virtio_set_status,
|
|
||||||
.get_features = virtio_get_features,
|
|
||||||
.set_features = virtio_set_features,
|
|
||||||
.notify = virtio_notify,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ipm_callback(const struct device *dev, void *context,
|
|
||||||
uint32_t id, volatile void *data)
|
|
||||||
{
|
|
||||||
BT_DBG("Got callback of id %u", id);
|
|
||||||
k_sem_give(&rx_sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
|
static int endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
|
||||||
uint32_t src, void *priv)
|
uint32_t src, void *priv)
|
||||||
|
@ -133,146 +33,28 @@ static int endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
|
||||||
return RPMSG_SUCCESS;
|
return RPMSG_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
|
|
||||||
{
|
|
||||||
rpmsg_destroy_ept(ep);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
|
|
||||||
{
|
|
||||||
(void)rpmsg_create_ept(&ep,
|
|
||||||
rdev,
|
|
||||||
name,
|
|
||||||
RPMSG_ADDR_ANY,
|
|
||||||
dest,
|
|
||||||
endpoint_cb,
|
|
||||||
rpmsg_service_unbind);
|
|
||||||
|
|
||||||
k_sem_give(&ready_sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bt_rpmsg_rx_thread(void *p1, void *p2, void *p3)
|
|
||||||
{
|
|
||||||
ARG_UNUSED(p1);
|
|
||||||
ARG_UNUSED(p2);
|
|
||||||
ARG_UNUSED(p3);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
int status = k_sem_take(&rx_sem, K_FOREVER);
|
|
||||||
|
|
||||||
if (status == 0) {
|
|
||||||
virtqueue_notification(vq[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int bt_rpmsg_platform_init(void)
|
int bt_rpmsg_platform_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
|
|
||||||
|
|
||||||
static struct virtio_vring_info rvrings[2];
|
err = rpmsg_service_register_endpoint("nrf_bt_hci", endpoint_cb);
|
||||||
static struct rpmsg_virtio_shm_pool shpool;
|
|
||||||
static struct virtio_device vdev;
|
|
||||||
static struct rpmsg_virtio_device rvdev;
|
|
||||||
static struct metal_io_region *io;
|
|
||||||
static struct metal_device *device;
|
|
||||||
|
|
||||||
/* Setup thread for RX data processing. */
|
if (err < 0) {
|
||||||
k_thread_create(&bt_rpmsg_rx_thread_data, bt_rpmsg_rx_thread_stack,
|
LOG_ERR("Registering endpoint failed with %d", err);
|
||||||
K_KERNEL_STACK_SIZEOF(bt_rpmsg_rx_thread_stack),
|
return RPMSG_ERR_INIT;
|
||||||
bt_rpmsg_rx_thread, NULL, NULL, NULL,
|
|
||||||
K_PRIO_COOP(CONFIG_BT_RPMSG_NRF53_RX_PRIO),
|
|
||||||
0, K_NO_WAIT);
|
|
||||||
|
|
||||||
/* Libmetal setup */
|
|
||||||
err = metal_init(&metal_params);
|
|
||||||
if (err) {
|
|
||||||
BT_ERR("metal_init: failed - error code %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = metal_register_generic_device(&shm_device);
|
endpoint_id = err;
|
||||||
if (err) {
|
|
||||||
BT_ERR("Couldn't register shared memory device: %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = metal_device_open("generic", SHM_DEVICE_NAME, &device);
|
return RPMSG_SUCCESS;
|
||||||
if (err) {
|
|
||||||
BT_ERR("metal_device_open failed: %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
io = metal_device_io_region(device, 0);
|
|
||||||
if (!io) {
|
|
||||||
BT_ERR("metal_device_io_region failed to get region");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IPM setup */
|
|
||||||
ipm_tx_handle = device_get_binding("IPM_0");
|
|
||||||
if (!ipm_tx_handle) {
|
|
||||||
BT_ERR("Could not get TX IPM device handle");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipm_rx_handle = device_get_binding("IPM_1");
|
|
||||||
if (!ipm_rx_handle) {
|
|
||||||
BT_ERR("Could not get RX IPM device handle");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipm_register_callback(ipm_rx_handle, ipm_callback, NULL);
|
|
||||||
|
|
||||||
/* Virtqueue setup */
|
|
||||||
vq[0] = virtqueue_allocate(VRING_SIZE);
|
|
||||||
if (!vq[0]) {
|
|
||||||
BT_ERR("virtqueue_allocate failed to alloc vq[0]");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
vq[1] = virtqueue_allocate(VRING_SIZE);
|
|
||||||
if (!vq[1]) {
|
|
||||||
BT_ERR("virtqueue_allocate failed to alloc vq[1]");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.role = RPMSG_MASTER;
|
|
||||||
vdev.vrings_num = VRING_COUNT;
|
|
||||||
vdev.func = &dispatch;
|
|
||||||
vdev.vrings_info = &rvrings[0];
|
|
||||||
|
|
||||||
rpmsg_virtio_init_shm_pool(&shpool, (void *)SHM_START_ADDR, SHM_SIZE);
|
|
||||||
err = rpmsg_init_vdev(&rvdev, &vdev, ns_bind_cb, io, &shpool);
|
|
||||||
if (err) {
|
|
||||||
BT_ERR("rpmsg_init_vdev failed %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait til nameservice ep is setup */
|
|
||||||
err = k_sem_take(&ready_sem, K_SECONDS(3));
|
|
||||||
if (err) {
|
|
||||||
BT_ERR("No contact with network core EP (err %d)", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_rpmsg_platform_send(struct net_buf *buf)
|
int bt_rpmsg_platform_send(struct net_buf *buf)
|
||||||
{
|
{
|
||||||
return rpmsg_send(&ep, buf->data, buf->len);
|
return rpmsg_service_send(endpoint_id, buf->data, buf->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_rpmsg_platform_endpoint_is_bound(void)
|
||||||
|
{
|
||||||
|
return rpmsg_service_endpoint_is_bound(endpoint_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
CONFIG_OPENAMP=y
|
|
||||||
|
|
||||||
CONFIG_IPM=y
|
CONFIG_RPMSG_SERVICE=y
|
||||||
CONFIG_IPM_NRFX=y
|
CONFIG_RPMSG_SERVICE_MODE_REMOTE=y
|
||||||
|
|
||||||
CONFIG_IPM_MSG_CH_1_ENABLE=y
|
|
||||||
CONFIG_IPM_MSG_CH_1_TX=y
|
|
||||||
CONFIG_IPM_MSG_CH_0_ENABLE=y
|
|
||||||
CONFIG_IPM_MSG_CH_0_RX=y
|
|
||||||
|
|
||||||
CONFIG_HEAP_MEM_POOL_SIZE=8192
|
CONFIG_HEAP_MEM_POOL_SIZE=8192
|
||||||
|
|
||||||
|
@ -18,3 +12,7 @@ CONFIG_BT_HCI_RAW=y
|
||||||
CONFIG_BT_MAX_CONN=16
|
CONFIG_BT_MAX_CONN=16
|
||||||
CONFIG_BT_CTLR_ASSERT_HANDLER=y
|
CONFIG_BT_CTLR_ASSERT_HANDLER=y
|
||||||
CONFIG_BT_HCI_RAW_RESERVE=1
|
CONFIG_BT_HCI_RAW_RESERVE=1
|
||||||
|
|
||||||
|
CONFIG_ASSERT=y
|
||||||
|
CONFIG_DEBUG_INFO=y
|
||||||
|
CONFIG_EXCEPTION_STACK_TRACE=y
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
* Copyright (c) 2019-2021 Nordic Semiconductor ASA
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -21,6 +21,8 @@
|
||||||
#include <metal/device.h>
|
#include <metal/device.h>
|
||||||
#include <metal/alloc.h>
|
#include <metal/alloc.h>
|
||||||
|
|
||||||
|
#include <ipc/rpmsg_service.h>
|
||||||
|
|
||||||
#include <net/buf.h>
|
#include <net/buf.h>
|
||||||
#include <bluetooth/bluetooth.h>
|
#include <bluetooth/bluetooth.h>
|
||||||
#include <bluetooth/l2cap.h>
|
#include <bluetooth/l2cap.h>
|
||||||
|
@ -32,108 +34,7 @@
|
||||||
#define LOG_MODULE_NAME hci_rpmsg
|
#define LOG_MODULE_NAME hci_rpmsg
|
||||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
|
|
||||||
/* Configuration defines */
|
static int endpoint_id;
|
||||||
#if !DT_HAS_CHOSEN(zephyr_ipc_shm)
|
|
||||||
#error "Sample requires definition of shared memory for rpmsg"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SHM_NODE DT_CHOSEN(zephyr_ipc_shm)
|
|
||||||
#define SHM_BASE_ADDRESS DT_REG_ADDR(SHM_NODE)
|
|
||||||
#define SHM_START_ADDR (SHM_BASE_ADDRESS + 0x400)
|
|
||||||
#define SHM_SIZE 0x7c00
|
|
||||||
#define SHM_DEVICE_NAME "sram0.shm"
|
|
||||||
|
|
||||||
BUILD_ASSERT((SHM_START_ADDR + SHM_SIZE - SHM_BASE_ADDRESS)
|
|
||||||
<= DT_REG_SIZE(SHM_NODE),
|
|
||||||
"Allocated size exceeds available shared memory reserved for IPC");
|
|
||||||
|
|
||||||
#define VRING_COUNT 2
|
|
||||||
#define VRING_TX_ADDRESS (SHM_START_ADDR + SHM_SIZE - 0x400)
|
|
||||||
#define VRING_RX_ADDRESS (VRING_TX_ADDRESS - 0x400)
|
|
||||||
#define VRING_ALIGNMENT 4
|
|
||||||
#define VRING_SIZE 16
|
|
||||||
|
|
||||||
#define VDEV_STATUS_ADDR SHM_BASE_ADDRESS
|
|
||||||
|
|
||||||
/* End of configuration defines */
|
|
||||||
|
|
||||||
static const struct device *ipm_tx_handle;
|
|
||||||
static const struct device *ipm_rx_handle;
|
|
||||||
|
|
||||||
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,
|
|
||||||
.regions = {
|
|
||||||
{
|
|
||||||
.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 struct virtqueue *vq[2];
|
|
||||||
static struct rpmsg_endpoint ep;
|
|
||||||
|
|
||||||
static struct k_work ipm_work;
|
|
||||||
|
|
||||||
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 BIT(VIRTIO_RPMSG_F_NS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_set_status(struct virtio_device *vdev, unsigned char status)
|
|
||||||
{
|
|
||||||
sys_write8(status, VDEV_STATUS_ADDR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void virtio_notify(struct virtqueue *vq)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
|
|
||||||
status = ipm_send(ipm_tx_handle, 0, 0, NULL, 0);
|
|
||||||
if (status != 0) {
|
|
||||||
LOG_ERR("ipm_send failed to notify: %d", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct virtio_dispatch dispatch = {
|
|
||||||
.get_status = virtio_get_status,
|
|
||||||
.set_status = virtio_set_status,
|
|
||||||
.get_features = virtio_get_features,
|
|
||||||
.notify = virtio_notify,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ipm_callback_process(struct k_work *work)
|
|
||||||
{
|
|
||||||
virtqueue_notification(vq[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipm_callback(const struct device *dev, void *context,
|
|
||||||
uint32_t id, volatile void *data)
|
|
||||||
{
|
|
||||||
LOG_INF("Got callback of id %u", id);
|
|
||||||
k_work_submit(&ipm_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
|
|
||||||
{
|
|
||||||
rpmsg_destroy_ept(ep);
|
|
||||||
}
|
|
||||||
|
|
||||||
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
||||||
static struct k_thread tx_thread_data;
|
static struct k_thread tx_thread_data;
|
||||||
|
@ -323,7 +224,7 @@ static int hci_rpmsg_send(struct net_buf *buf)
|
||||||
net_buf_push_u8(buf, pkt_indicator);
|
net_buf_push_u8(buf, pkt_indicator);
|
||||||
|
|
||||||
LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:");
|
LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:");
|
||||||
rpmsg_send(&ep, buf->data, buf->len);
|
rpmsg_service_send(endpoint_id, buf->data, buf->len);
|
||||||
|
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
|
|
||||||
|
@ -346,110 +247,6 @@ int endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src
|
||||||
return RPMSG_SUCCESS;
|
return RPMSG_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hci_rpmsg_init(void)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
|
|
||||||
|
|
||||||
static struct virtio_vring_info rvrings[2];
|
|
||||||
static struct virtio_device vdev;
|
|
||||||
static struct rpmsg_device *rdev;
|
|
||||||
static struct rpmsg_virtio_device rvdev;
|
|
||||||
static struct metal_io_region *io;
|
|
||||||
static struct metal_device *device;
|
|
||||||
|
|
||||||
/* Setup IPM workqueue item */
|
|
||||||
k_work_init(&ipm_work, ipm_callback_process);
|
|
||||||
|
|
||||||
/* Libmetal setup */
|
|
||||||
err = metal_init(&metal_params);
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("metal_init: failed - error code %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = metal_register_generic_device(&shm_device);
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("Couldn't register shared memory device: %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = metal_device_open("generic", SHM_DEVICE_NAME, &device);
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("metal_device_open failed: %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
io = metal_device_io_region(device, 0);
|
|
||||||
if (!io) {
|
|
||||||
LOG_ERR("metal_device_io_region failed to get region");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IPM setup */
|
|
||||||
ipm_tx_handle = device_get_binding("IPM_1");
|
|
||||||
if (!ipm_tx_handle) {
|
|
||||||
LOG_ERR("Could not get TX IPM device handle");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipm_rx_handle = device_get_binding("IPM_0");
|
|
||||||
if (!ipm_rx_handle) {
|
|
||||||
LOG_ERR("Could not get RX IPM device handle");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipm_register_callback(ipm_rx_handle, ipm_callback, NULL);
|
|
||||||
|
|
||||||
vq[0] = virtqueue_allocate(VRING_SIZE);
|
|
||||||
if (!vq[0]) {
|
|
||||||
LOG_ERR("virtqueue_allocate failed to alloc vq[0]");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
vq[1] = virtqueue_allocate(VRING_SIZE);
|
|
||||||
if (!vq[1]) {
|
|
||||||
LOG_ERR("virtqueue_allocate failed to alloc vq[1]");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.role = RPMSG_REMOTE;
|
|
||||||
vdev.vrings_num = VRING_COUNT;
|
|
||||||
vdev.func = &dispatch;
|
|
||||||
vdev.vrings_info = &rvrings[0];
|
|
||||||
|
|
||||||
/* setup rvdev */
|
|
||||||
err = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL);
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("rpmsg_init_vdev failed %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
|
|
||||||
|
|
||||||
err = rpmsg_create_ept(&ep, rdev, "bt_hci", RPMSG_ADDR_ANY,
|
|
||||||
RPMSG_ADDR_ANY, endpoint_cb,
|
|
||||||
rpmsg_service_unbind);
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("rpmsg_create_ept failed %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -457,12 +254,6 @@ void main(void)
|
||||||
/* incoming events and data from the controller */
|
/* incoming events and data from the controller */
|
||||||
static K_FIFO_DEFINE(rx_queue);
|
static K_FIFO_DEFINE(rx_queue);
|
||||||
|
|
||||||
/* initialize RPMSG */
|
|
||||||
err = hci_rpmsg_init();
|
|
||||||
if (err != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("Start");
|
LOG_DBG("Start");
|
||||||
|
|
||||||
/* Enable the raw interface, this will in turn open the HCI driver */
|
/* Enable the raw interface, this will in turn open the HCI driver */
|
||||||
|
@ -486,3 +277,22 @@ void main(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure we register endpoint before RPMsg Service is initialized. */
|
||||||
|
int register_endpoint(const struct device *arg)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = rpmsg_service_register_endpoint("nrf_bt_hci", endpoint_cb);
|
||||||
|
|
||||||
|
if (status < 0) {
|
||||||
|
LOG_ERR("Registering endpoint failed with %d", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_id = status;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(register_endpoint, POST_KERNEL, CONFIG_RPMSG_SERVICE_EP_REG_PRIORITY);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue