Commit bace4a10 authored by Jakub Zymelka's avatar Jakub Zymelka Committed by Anas Nashif
Browse files

drivers: mbox: add initial driver for nRF VEVIF event



Add a mailbox driver for VEVIF events (VPR irq).
The driver can be built in either 'rx' or 'tx' configuration.
The VPR sends the event, so it uses the 'tx' configuration,
while the master core uses the 'rx' configuration of the driver
to receive the VPR events.

Signed-off-by: default avatarJakub Zymelka <jakub.zymelka@nordicsemi.no>
parent 25fa41c2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@ zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_MAILBOX mbox_nxp_mailbox.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_ANDES_PLIC_SW   mbox_andes_plic_sw.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_VEVIF_LOCAL mbox_nrf_vevif_local.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_VEVIF_REMOTE mbox_nrf_vevif_remote.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_VEVIF_EVENT_RX mbox_nrf_vevif_event_rx.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_VEVIF_EVENT_TX mbox_nrf_vevif_event_tx.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_BELLBOARD_LOCAL mbox_nrf_bellboard_local.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_BELLBOARD_REMOTE mbox_nrf_bellboard_remote.c)
zephyr_library_sources_ifdef(CONFIG_MBOX_STM32_HSEM   mbox_stm32_hsem.c)
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ source "drivers/mbox/Kconfig.nxp_imx"
source "drivers/mbox/Kconfig.nxp_mailbox"
source "drivers/mbox/Kconfig.andes"
source "drivers/mbox/Kconfig.nrf_vevif"
source "drivers/mbox/Kconfig.nrf_vevif_event"
source "drivers/mbox/Kconfig.nrf_bellboard"
source "drivers/mbox/Kconfig.stm32_hsem"

+16 −0
Original line number Diff line number Diff line
# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

config MBOX_NRF_VEVIF_EVENT_RX
	bool "nRF VEVIF event RX driver"
	depends on DT_HAS_NORDIC_NRF_VEVIF_EVENT_RX_ENABLED
	default y
	help
	  Mailbox driver for receiving events triggered by VPR

config MBOX_NRF_VEVIF_EVENT_TX
	bool "nRF VEVIF event TX driver"
	depends on DT_HAS_NORDIC_NRF_VEVIF_EVENT_TX_ENABLED
	default y
	help
	  Mailbox driver for transmitting events from VPR to a remote core
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT nordic_nrf_vevif_event_rx

#include <zephyr/devicetree.h>
#include <zephyr/drivers/mbox.h>

#include <haly/nrfy_vpr.h>

#if defined(CONFIG_SOC_NRF54L15_ENGA_CPUAPP)
#define EVENTS_IDX_MIN 11U
#define EVENTS_IDX_MAX 17U
#else
#define EVENTS_IDX_MIN NRF_VPR_EVENTS_TRIGGERED_MIN
#define EVENTS_IDX_MAX NRF_VPR_EVENTS_TRIGGERED_MAX
#endif

/* callbacks */
struct mbox_vevif_event_rx_cbs {
	mbox_callback_t cb[EVENTS_IDX_MAX - EVENTS_IDX_MIN + 1U];
	void *user_data[EVENTS_IDX_MAX - EVENTS_IDX_MIN + 1U];
	uint32_t enabled_mask;
};

struct mbox_vevif_event_rx_conf {
	NRF_VPR_Type *vpr;
	uint32_t events_mask;
	uint8_t events;
	void (*irq_connect)(void);
};

static void vevif_event_rx_isr(const void *device)
{
	const struct device *dev = (struct device *)device;
	const struct mbox_vevif_event_rx_conf *config = dev->config;
	struct mbox_vevif_event_rx_cbs *cbs = dev->data;

	for (uint8_t id = EVENTS_IDX_MIN; id < EVENTS_IDX_MAX + 1U; id++) {
		nrf_vpr_event_t event = nrfy_vpr_triggered_event_get(id);

		if (nrfy_vpr_event_check(config->vpr, event)) {
			nrfy_vpr_event_clear(config->vpr, event);
			uint8_t idx = id - EVENTS_IDX_MIN;

			if ((cbs->enabled_mask & BIT(id)) && (cbs->cb[idx] != NULL)) {
				cbs->cb[idx](dev, id, cbs->user_data[idx], NULL);
			}
		}
	}
}

static inline bool vevif_event_rx_event_is_valid(uint32_t events_mask, uint32_t id)
{
	return ((id <= EVENTS_IDX_MAX) && ((events_mask & BIT(id)) != 0U));
}

static uint32_t vevif_event_rx_max_channels_get(const struct device *dev)
{
	const struct mbox_vevif_event_rx_conf *config = dev->config;

	return config->events;
}

static int vevif_event_rx_register_callback(const struct device *dev, uint32_t id,
					    mbox_callback_t cb, void *user_data)
{
	const struct mbox_vevif_event_rx_conf *config = dev->config;
	struct mbox_vevif_event_rx_cbs *cbs = dev->data;
	uint8_t idx = id - EVENTS_IDX_MIN;

	if (!vevif_event_rx_event_is_valid(config->events_mask, id)) {
		return -EINVAL;
	}

	cbs->cb[idx] = cb;
	cbs->user_data[idx] = user_data;

	return 0;
}

static int vevif_event_rx_set_enabled(const struct device *dev, uint32_t id, bool enable)
{
	const struct mbox_vevif_event_rx_conf *config = dev->config;
	struct mbox_vevif_event_rx_cbs *cbs = dev->data;

	if (!vevif_event_rx_event_is_valid(config->events_mask, id)) {
		return -EINVAL;
	}

	if (enable) {
		if ((cbs->enabled_mask & BIT(id)) != 0U) {
			return -EALREADY;
		}

		cbs->enabled_mask |= BIT(id);
		nrfy_vpr_int_enable(config->vpr, BIT(id));
	} else {
		if ((cbs->enabled_mask & BIT(id)) == 0U) {
			return -EALREADY;
		}

		cbs->enabled_mask &= ~BIT(id);
		nrfy_vpr_int_disable(config->vpr, BIT(id));
	}

	return 0;
}

static const struct mbox_driver_api vevif_event_rx_driver_api = {
	.max_channels_get = vevif_event_rx_max_channels_get,
	.register_callback = vevif_event_rx_register_callback,
	.set_enabled = vevif_event_rx_set_enabled,
};

static int vevif_event_rx_init(const struct device *dev)
{
	const struct mbox_vevif_event_rx_conf *config = dev->config;

	config->irq_connect();

	return 0;
}

#define VEVIF_EVENT_RX_DEFINE(inst)                                                                \
	BUILD_ASSERT(DT_INST_PROP(inst, nordic_events) <= NRF_VPR_EVENTS_TRIGGERED_COUNT,          \
		     "Number of events exceeds maximum");                                          \
                                                                                                   \
	static void irq_connect##inst(void)                                                        \
	{                                                                                          \
		IRQ_CONNECT(DT_IRQN(DT_DRV_INST(inst)), DT_IRQ(DT_DRV_INST(inst), priority),       \
			    vevif_event_rx_isr, (const void *)DEVICE_DT_GET(DT_DRV_INST(inst)),    \
			    0);                                                                    \
		irq_enable(DT_IRQN(DT_DRV_INST(inst)));                                            \
	};                                                                                         \
                                                                                                   \
	static struct mbox_vevif_event_rx_cbs data##inst = {                                       \
		.enabled_mask = 0,                                                                 \
	};                                                                                         \
	static const struct mbox_vevif_event_rx_conf conf##inst = {                                \
		.vpr = (NRF_VPR_Type *)DT_INST_REG_ADDR(inst),                                     \
		.events = DT_INST_PROP(inst, nordic_events),                                       \
		.events_mask = DT_INST_PROP(inst, nordic_events_mask),                             \
		.irq_connect = irq_connect##inst,                                                  \
	};                                                                                         \
                                                                                                   \
	DEVICE_DT_INST_DEFINE(inst, vevif_event_rx_init, NULL, &data##inst, &conf##inst,           \
			      POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, &vevif_event_rx_driver_api);

DT_INST_FOREACH_STATUS_OKAY(VEVIF_EVENT_RX_DEFINE)
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT nordic_nrf_vevif_event_tx

#include <zephyr/devicetree.h>
#include <zephyr/drivers/mbox.h>

#include <hal/nrf_vpr.h>
#include <hal/nrf_vpr_csr.h>
#include <hal/nrf_vpr_csr_vevif.h>

#if defined(CONFIG_SOC_NRF54L15_ENGA_CPUFLPR)
#define EVENTS_IDX_MAX 17U
#else
#define EVENTS_IDX_MAX NRF_VPR_EVENTS_TRIGGERED_MAX
#endif

#define VEVIF_EVENTS_NUM  DT_INST_PROP(0, nordic_events)
#define VEVIF_EVENTS_MASK DT_INST_PROP(0, nordic_events_mask)

BUILD_ASSERT(DT_INST_PROP(0, nordic_events) <= NRF_VPR_EVENTS_TRIGGERED_COUNT,
	     "Number of events exceeds maximum");

static inline bool vevif_event_tx_is_valid(uint32_t id)
{
	return (id < EVENTS_IDX_MAX) && ((VEVIF_EVENTS_MASK & BIT(id)) != 0U);
}

static int vevif_event_tx_send(const struct device *dev, uint32_t id, const struct mbox_msg *msg)
{
	ARG_UNUSED(dev);

	if (!vevif_event_tx_is_valid(id)) {
		return -EINVAL;
	}

	if (msg != NULL) {
		return -ENOTSUP;
	}

	nrf_vpr_csr_vevif_events_trigger(BIT(id));

	return 0;
}

static int vevif_event_tx_mtu_get(const struct device *dev)
{
	ARG_UNUSED(dev);

	return 0;
}

static uint32_t vevif_event_tx_max_channels_get(const struct device *dev)
{
	ARG_UNUSED(dev);

	return VEVIF_EVENTS_NUM;
}

static const struct mbox_driver_api vevif_event_tx_driver_api = {
	.send = vevif_event_tx_send,
	.mtu_get = vevif_event_tx_mtu_get,
	.max_channels_get = vevif_event_tx_max_channels_get,
};

DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY,
		      &vevif_event_tx_driver_api);
Loading