From 012591c4a51271df5e8de221a6dcd4b64ae982cd Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Fri, 15 Oct 2021 11:56:21 +0200 Subject: [PATCH] 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 --- drivers/mbox/CMakeLists.txt | 1 + drivers/mbox/Kconfig | 16 ++ drivers/mbox/mbox_nrfx_ipc.c | 202 +++++++++++++++++++++ dts/bindings/mbox/nordic,mbox-nrf-ipc.yaml | 22 +++ 4 files changed, 241 insertions(+) create mode 100644 drivers/mbox/mbox_nrfx_ipc.c create mode 100644 dts/bindings/mbox/nordic,mbox-nrf-ipc.yaml diff --git a/drivers/mbox/CMakeLists.txt b/drivers/mbox/CMakeLists.txt index b616f228f9a..81171bd7c3a 100644 --- a/drivers/mbox/CMakeLists.txt +++ b/drivers/mbox/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c) +zephyr_library_sources_ifdef(CONFIG_MBOX_NRFX mbox_nrfx_ipc.c) diff --git a/drivers/mbox/Kconfig b/drivers/mbox/Kconfig index d1c79945f58..ef6fad95256 100644 --- a/drivers/mbox/Kconfig +++ b/drivers/mbox/Kconfig @@ -6,3 +6,19 @@ menuconfig MBOX help Include multi-channel interrupt-based inter-processor mailboxes 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 diff --git a/drivers/mbox/mbox_nrfx_ipc.c b/drivers/mbox/mbox_nrfx_ipc.c new file mode 100644 index 00000000000..eac81666001 --- /dev/null +++ b/drivers/mbox/mbox_nrfx_ipc.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2021 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL +#include +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); diff --git a/dts/bindings/mbox/nordic,mbox-nrf-ipc.yaml b/dts/bindings/mbox/nordic,mbox-nrf-ipc.yaml new file mode 100644 index 00000000000..68059703954 --- /dev/null +++ b/dts/bindings/mbox/nordic,mbox-nrf-ipc.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2021 Carlo Caione +# 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