Commit 012591c4 authored by Carlo Caione's avatar Carlo Caione Committed by Carles Cufi
Browse files

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: default avatarCarlo Caione <ccaione@baylibre.com>
parent 1976f33e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+16 −0
Original line number Diff line number Diff line
@@ -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
+202 −0
Original line number Diff line number Diff line
/*
 * 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 −0
Original line number Diff line number Diff line
# 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