mbox: Introduce MBOX NRFX IPC driver
Rewrite the NRFX IPC driver to properly support multi-channel addressing leveraging the newly introduced MBOX APIs. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
1976f33e87
commit
012591c4a5
4 changed files with 241 additions and 0 deletions
|
@ -3,3 +3,4 @@
|
||||||
zephyr_library()
|
zephyr_library()
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_MBOX_NRFX mbox_nrfx_ipc.c)
|
||||||
|
|
|
@ -6,3 +6,19 @@ menuconfig MBOX
|
||||||
help
|
help
|
||||||
Include multi-channel interrupt-based inter-processor mailboxes
|
Include multi-channel interrupt-based inter-processor mailboxes
|
||||||
drivers in system configuration
|
drivers in system configuration
|
||||||
|
|
||||||
|
if MBOX
|
||||||
|
|
||||||
|
config MBOX_NRFX
|
||||||
|
bool "MBOX NRF driver"
|
||||||
|
depends on HAS_HW_NRF_IPC
|
||||||
|
select NRFX_IPC
|
||||||
|
help
|
||||||
|
Driver for Nordic nRF messaging unit, based
|
||||||
|
on nRF IPC peripheral HW.
|
||||||
|
|
||||||
|
module = MBOX
|
||||||
|
module-str = mbox
|
||||||
|
source "subsys/logging/Kconfig.template.log_config"
|
||||||
|
|
||||||
|
endif # MBOX
|
||||||
|
|
202
drivers/mbox/mbox_nrfx_ipc.c
Normal file
202
drivers/mbox/mbox_nrfx_ipc.c
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <drivers/mbox.h>
|
||||||
|
#include <nrfx_ipc.h>
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(mbox_nrfx_ipc);
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT nordic_mbox_nrf_ipc
|
||||||
|
|
||||||
|
struct mbox_nrf_data {
|
||||||
|
mbox_callback_t cb[IPC_CONF_NUM];
|
||||||
|
void *user_data[IPC_CONF_NUM];
|
||||||
|
const struct device *dev;
|
||||||
|
uint32_t enabled_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mbox_nrf_data nrfx_mbox_data;
|
||||||
|
|
||||||
|
static struct mbox_nrf_conf {
|
||||||
|
uint32_t rx_mask;
|
||||||
|
uint32_t tx_mask;
|
||||||
|
} nrfx_mbox_conf = {
|
||||||
|
.rx_mask = DT_INST_PROP(0, rx_mask),
|
||||||
|
.tx_mask = DT_INST_PROP(0, tx_mask),
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool is_rx_channel_valid(const struct device *dev, uint32_t ch)
|
||||||
|
{
|
||||||
|
const struct mbox_nrf_conf *conf = dev->config;
|
||||||
|
|
||||||
|
return ((ch < IPC_CONF_NUM) && (conf->rx_mask & BIT(ch)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_tx_channel_valid(const struct device *dev, uint32_t ch)
|
||||||
|
{
|
||||||
|
const struct mbox_nrf_conf *conf = dev->config;
|
||||||
|
|
||||||
|
return ((ch < IPC_CONF_NUM) && (conf->tx_mask & BIT(ch)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mbox_dispatcher(uint32_t event_mask, void *p_context)
|
||||||
|
{
|
||||||
|
struct mbox_nrf_data *data = (struct mbox_nrf_data *) p_context;
|
||||||
|
const struct device *dev = data->dev;
|
||||||
|
|
||||||
|
while (event_mask) {
|
||||||
|
uint32_t channel = __CLZ(__RBIT(event_mask));
|
||||||
|
|
||||||
|
if (!is_rx_channel_valid(dev, channel)) {
|
||||||
|
LOG_WRN("RX event on illegal channel");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(data->enabled_mask & BIT(channel))) {
|
||||||
|
LOG_WRN("RX event on disabled channel");
|
||||||
|
}
|
||||||
|
|
||||||
|
event_mask &= ~BIT(channel);
|
||||||
|
|
||||||
|
if (data->cb[channel] != NULL) {
|
||||||
|
data->cb[channel](dev, channel, data->user_data[channel], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mbox_nrf_send(const struct device *dev, uint32_t channel,
|
||||||
|
const struct mbox_msg *msg)
|
||||||
|
{
|
||||||
|
if (msg) {
|
||||||
|
LOG_WRN("Sending data not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_tx_channel_valid(dev, channel)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nrfx_ipc_signal(channel);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mbox_nrf_register_callback(const struct device *dev, uint32_t channel,
|
||||||
|
mbox_callback_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct mbox_nrf_data *data = dev->data;
|
||||||
|
|
||||||
|
if (!is_rx_channel_valid(dev, channel)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->cb[channel] = cb;
|
||||||
|
data->user_data[channel] = user_data;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mbox_nrf_mtu_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
/* We only support signalling */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t mbox_nrf_max_channels_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
return IPC_CONF_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mbox_nrf_set_enabled(const struct device *dev, uint32_t channel, bool enable)
|
||||||
|
{
|
||||||
|
struct mbox_nrf_data *data = dev->data;
|
||||||
|
|
||||||
|
if (!is_rx_channel_valid(dev, channel)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((enable == 0 && (!(data->enabled_mask & BIT(channel)))) ||
|
||||||
|
(enable != 0 && (data->enabled_mask & BIT(channel)))) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable && data->enabled_mask == 0) {
|
||||||
|
irq_enable(DT_INST_IRQN(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
data->enabled_mask |= BIT(channel);
|
||||||
|
compiler_barrier();
|
||||||
|
nrfx_ipc_receive_event_enable(channel);
|
||||||
|
} else {
|
||||||
|
nrfx_ipc_receive_event_disable(channel);
|
||||||
|
compiler_barrier();
|
||||||
|
data->enabled_mask &= ~BIT(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->enabled_mask == 0) {
|
||||||
|
irq_disable(DT_INST_IRQN(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enable_dt_channels(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct mbox_nrf_conf *conf = dev->config;
|
||||||
|
nrfx_ipc_config_t ch_config = { 0 };
|
||||||
|
|
||||||
|
if (conf->tx_mask >= BIT(IPC_CONF_NUM)) {
|
||||||
|
LOG_WRN("tx_mask too big (or IPC_CONF_NUM too small)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->rx_mask >= BIT(IPC_CONF_NUM)) {
|
||||||
|
LOG_WRN("rx_mask too big (or IPC_CONF_NUM too small)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable the interrupts on .set_enabled() only */
|
||||||
|
ch_config.receive_events_enabled = 0;
|
||||||
|
|
||||||
|
for (size_t ch = 0; ch < IPC_CONF_NUM; ch++) {
|
||||||
|
if (conf->tx_mask & BIT(ch)) {
|
||||||
|
ch_config.send_task_config[ch] = BIT(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->rx_mask & BIT(ch)) {
|
||||||
|
ch_config.receive_event_config[ch] = BIT(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nrfx_ipc_config_load(&ch_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mbox_nrf_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct mbox_nrf_data *data = dev->data;
|
||||||
|
|
||||||
|
data->dev = dev;
|
||||||
|
|
||||||
|
nrfx_ipc_init(0, mbox_dispatcher, (void *) data);
|
||||||
|
|
||||||
|
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
|
||||||
|
nrfx_isr, nrfx_ipc_irq_handler, 0);
|
||||||
|
|
||||||
|
enable_dt_channels(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct mbox_driver_api mbox_nrf_driver_api = {
|
||||||
|
.send = mbox_nrf_send,
|
||||||
|
.register_callback = mbox_nrf_register_callback,
|
||||||
|
.mtu_get = mbox_nrf_mtu_get,
|
||||||
|
.max_channels_get = mbox_nrf_max_channels_get,
|
||||||
|
.set_enabled = mbox_nrf_set_enabled,
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE_DT_INST_DEFINE(0, mbox_nrf_init, NULL, &nrfx_mbox_data, &nrfx_mbox_conf,
|
||||||
|
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||||
|
&mbox_nrf_driver_api);
|
22
dts/bindings/mbox/nordic,mbox-nrf-ipc.yaml
Normal file
22
dts/bindings/mbox/nordic,mbox-nrf-ipc.yaml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: Nordic nRF family IPC (MBOX Interprocessor Communication)
|
||||||
|
|
||||||
|
compatible: "nordic,mbox-nrf-ipc"
|
||||||
|
|
||||||
|
include: base.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
tx-mask:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: TX supported channels mask
|
||||||
|
|
||||||
|
rx-mask:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: RX supported channels mask
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
required: true
|
Loading…
Add table
Add a link
Reference in a new issue