1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT nordic_nrf_vevif_event_rx
7 
8 #include <zephyr/devicetree.h>
9 #include <zephyr/drivers/mbox.h>
10 
11 #include <haly/nrfy_vpr.h>
12 
13 #define EVENTS_IDX_MIN NRF_VPR_EVENTS_TRIGGERED_MIN
14 #define EVENTS_IDX_MAX NRF_VPR_EVENTS_TRIGGERED_MAX
15 
16 #if defined(CONFIG_MBOX_NRF_VEVIF_EVENT_USE_54L_ERRATA_16)
17 #define VEVIF_54L_EVENT_IDX 20
18 BUILD_ASSERT(DT_INST_PROP(0, nordic_events) == 1);
19 BUILD_ASSERT(DT_INST_PROP(0, nordic_events_mask) & BIT(VEVIF_54L_EVENT_IDX));
20 #endif
21 
22 /* callbacks */
23 struct mbox_vevif_event_rx_cbs {
24 	mbox_callback_t cb[EVENTS_IDX_MAX - EVENTS_IDX_MIN + 1U];
25 	void *user_data[EVENTS_IDX_MAX - EVENTS_IDX_MIN + 1U];
26 	uint32_t enabled_mask;
27 };
28 
29 struct mbox_vevif_event_rx_conf {
30 	NRF_VPR_Type *vpr;
31 	uint32_t events_mask;
32 	uint8_t events;
33 	void (*irq_connect)(void);
34 };
35 
trigger_callback(const struct device * dev,struct mbox_vevif_event_rx_cbs * cbs,uint8_t id)36 static void trigger_callback(const struct device *dev, struct mbox_vevif_event_rx_cbs *cbs,
37 			     uint8_t id)
38 {
39 	uint8_t idx = id - EVENTS_IDX_MIN;
40 
41 	if ((cbs->enabled_mask & BIT(id)) && (cbs->cb[idx] != NULL)) {
42 		cbs->cb[idx](dev, id, cbs->user_data[idx], NULL);
43 	}
44 }
45 
vevif_event_rx_isr(const void * device)46 static void vevif_event_rx_isr(const void *device)
47 {
48 	const struct device *dev = (struct device *)device;
49 	struct mbox_vevif_event_rx_cbs *cbs = dev->data;
50 
51 #if !defined(CONFIG_MBOX_NRF_VEVIF_EVENT_USE_54L_ERRATA_16)
52 	const struct mbox_vevif_event_rx_conf *config = dev->config;
53 
54 	for (uint8_t id = EVENTS_IDX_MIN; id < EVENTS_IDX_MAX + 1U; id++) {
55 		nrf_vpr_event_t event = nrfy_vpr_triggered_event_get(id);
56 		if (nrfy_vpr_event_check(config->vpr, event)) {
57 			nrfy_vpr_event_clear(config->vpr, event);
58 			trigger_callback(dev, cbs, id);
59 		}
60 	}
61 #else
62 	trigger_callback(dev, cbs, VEVIF_54L_EVENT_IDX);
63 #endif
64 }
65 
vevif_event_rx_event_is_valid(uint32_t events_mask,uint32_t id)66 static inline bool vevif_event_rx_event_is_valid(uint32_t events_mask, uint32_t id)
67 {
68 	return ((id <= EVENTS_IDX_MAX) && ((events_mask & BIT(id)) != 0U));
69 }
70 
vevif_event_rx_max_channels_get(const struct device * dev)71 static uint32_t vevif_event_rx_max_channels_get(const struct device *dev)
72 {
73 	const struct mbox_vevif_event_rx_conf *config = dev->config;
74 
75 	return config->events;
76 }
77 
vevif_event_rx_register_callback(const struct device * dev,uint32_t id,mbox_callback_t cb,void * user_data)78 static int vevif_event_rx_register_callback(const struct device *dev, uint32_t id,
79 					    mbox_callback_t cb, void *user_data)
80 {
81 	const struct mbox_vevif_event_rx_conf *config = dev->config;
82 	struct mbox_vevif_event_rx_cbs *cbs = dev->data;
83 	uint8_t idx = id - EVENTS_IDX_MIN;
84 
85 	if (!vevif_event_rx_event_is_valid(config->events_mask, id)) {
86 		return -EINVAL;
87 	}
88 
89 	cbs->cb[idx] = cb;
90 	cbs->user_data[idx] = user_data;
91 
92 	return 0;
93 }
94 
vevif_event_rx_set_enabled(const struct device * dev,uint32_t id,bool enable)95 static int vevif_event_rx_set_enabled(const struct device *dev, uint32_t id, bool enable)
96 {
97 	const struct mbox_vevif_event_rx_conf *config = dev->config;
98 	struct mbox_vevif_event_rx_cbs *cbs = dev->data;
99 
100 	if (!vevif_event_rx_event_is_valid(config->events_mask, id)) {
101 		return -EINVAL;
102 	}
103 
104 	if (enable) {
105 		if ((cbs->enabled_mask & BIT(id)) != 0U) {
106 			return -EALREADY;
107 		}
108 
109 		cbs->enabled_mask |= BIT(id);
110 		nrfy_vpr_int_enable(config->vpr, BIT(id));
111 	} else {
112 		if ((cbs->enabled_mask & BIT(id)) == 0U) {
113 			return -EALREADY;
114 		}
115 
116 		cbs->enabled_mask &= ~BIT(id);
117 		nrfy_vpr_int_disable(config->vpr, BIT(id));
118 	}
119 
120 	return 0;
121 }
122 
123 static DEVICE_API(mbox, vevif_event_rx_driver_api) = {
124 	.max_channels_get = vevif_event_rx_max_channels_get,
125 	.register_callback = vevif_event_rx_register_callback,
126 	.set_enabled = vevif_event_rx_set_enabled,
127 };
128 
vevif_event_rx_init(const struct device * dev)129 static int vevif_event_rx_init(const struct device *dev)
130 {
131 	const struct mbox_vevif_event_rx_conf *config = dev->config;
132 
133 	config->irq_connect();
134 
135 	return 0;
136 }
137 
138 #define VEVIF_EVENT_RX_DEFINE(inst)                                                                \
139 	BUILD_ASSERT(DT_INST_PROP(inst, nordic_events) <= NRF_VPR_EVENTS_TRIGGERED_COUNT,          \
140 		     "Number of events exceeds maximum");                                          \
141                                                                                                    \
142 	static void irq_connect##inst(void)                                                        \
143 	{                                                                                          \
144 		IRQ_CONNECT(DT_IRQN(DT_DRV_INST(inst)), DT_IRQ(DT_DRV_INST(inst), priority),       \
145 			    vevif_event_rx_isr, (const void *)DEVICE_DT_GET(DT_DRV_INST(inst)),    \
146 			    0);                                                                    \
147 		irq_enable(DT_IRQN(DT_DRV_INST(inst)));                                            \
148 	};                                                                                         \
149                                                                                                    \
150 	static struct mbox_vevif_event_rx_cbs data##inst = {                                       \
151 		.enabled_mask = 0,                                                                 \
152 	};                                                                                         \
153 	static const struct mbox_vevif_event_rx_conf conf##inst = {                                \
154 		.vpr = (NRF_VPR_Type *)DT_REG_ADDR(DT_INST_PARENT(inst)),                          \
155 		.events = DT_INST_PROP(inst, nordic_events),                                       \
156 		.events_mask = DT_INST_PROP(inst, nordic_events_mask),                             \
157 		.irq_connect = irq_connect##inst,                                                  \
158 	};                                                                                         \
159                                                                                                    \
160 	DEVICE_DT_INST_DEFINE(inst, vevif_event_rx_init, NULL, &data##inst, &conf##inst,           \
161 			      POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, &vevif_event_rx_driver_api);
162 
163 DT_INST_FOREACH_STATUS_OKAY(VEVIF_EVENT_RX_DEFINE)
164