1 /*
2  * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/mbox.h>
8 #include <nrfx_ipc.h>
9 
10 #define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL
11 #include <zephyr/logging/log.h>
12 #include <zephyr/irq.h>
13 LOG_MODULE_REGISTER(mbox_nrfx_ipc);
14 
15 #define DT_DRV_COMPAT nordic_mbox_nrf_ipc
16 
17 struct mbox_nrf_data {
18 	mbox_callback_t cb[IPC_CONF_NUM];
19 	void *user_data[IPC_CONF_NUM];
20 	const struct device *dev;
21 	uint32_t enabled_mask;
22 };
23 
24 static struct mbox_nrf_data nrfx_mbox_data;
25 
26 static struct mbox_nrf_conf {
27 	uint32_t rx_mask;
28 	uint32_t tx_mask;
29 } nrfx_mbox_conf = {
30 	.rx_mask = DT_INST_PROP(0, rx_mask),
31 	.tx_mask = DT_INST_PROP(0, tx_mask),
32 };
33 
is_rx_channel_valid(const struct device * dev,uint32_t ch)34 static inline bool is_rx_channel_valid(const struct device *dev, uint32_t ch)
35 {
36 	const struct mbox_nrf_conf *conf = dev->config;
37 
38 	return ((ch < IPC_CONF_NUM) && (conf->rx_mask & BIT(ch)));
39 }
40 
is_tx_channel_valid(const struct device * dev,uint32_t ch)41 static inline bool is_tx_channel_valid(const struct device *dev, uint32_t ch)
42 {
43 	const struct mbox_nrf_conf *conf = dev->config;
44 
45 	return ((ch < IPC_CONF_NUM) && (conf->tx_mask & BIT(ch)));
46 }
47 
mbox_dispatcher(uint8_t event_idx,void * p_context)48 static void mbox_dispatcher(uint8_t event_idx, void *p_context)
49 {
50 	struct mbox_nrf_data *data = (struct mbox_nrf_data *) p_context;
51 	const struct device *dev = data->dev;
52 
53 	uint32_t channel = event_idx;
54 
55 	if (!is_rx_channel_valid(dev, channel)) {
56 		LOG_WRN("RX event on illegal channel");
57 	}
58 
59 	if (!(data->enabled_mask & BIT(channel))) {
60 		LOG_WRN("RX event on disabled channel");
61 	}
62 
63 	if (data->cb[channel] != NULL) {
64 		data->cb[channel](dev, channel, data->user_data[channel], NULL);
65 	}
66 }
67 
mbox_nrf_send(const struct device * dev,uint32_t channel,const struct mbox_msg * msg)68 static int mbox_nrf_send(const struct device *dev, uint32_t channel,
69 			 const struct mbox_msg *msg)
70 {
71 	if (msg) {
72 		LOG_WRN("Sending data not supported");
73 	}
74 
75 	if (!is_tx_channel_valid(dev, channel)) {
76 		return -EINVAL;
77 	}
78 
79 	nrfx_ipc_signal(channel);
80 
81 	return 0;
82 }
83 
mbox_nrf_register_callback(const struct device * dev,uint32_t channel,mbox_callback_t cb,void * user_data)84 static int mbox_nrf_register_callback(const struct device *dev, uint32_t channel,
85 				      mbox_callback_t cb, void *user_data)
86 {
87 	struct mbox_nrf_data *data = dev->data;
88 
89 	if (channel >= IPC_CONF_NUM) {
90 		return -EINVAL;
91 	}
92 
93 	data->cb[channel] = cb;
94 	data->user_data[channel] = user_data;
95 
96 	return 0;
97 }
98 
mbox_nrf_mtu_get(const struct device * dev)99 static int mbox_nrf_mtu_get(const struct device *dev)
100 {
101 	/* We only support signalling */
102 	return 0;
103 }
104 
mbox_nrf_max_channels_get(const struct device * dev)105 static uint32_t mbox_nrf_max_channels_get(const struct device *dev)
106 {
107 	return IPC_CONF_NUM;
108 }
109 
mbox_nrf_set_enabled(const struct device * dev,uint32_t channel,bool enable)110 static int mbox_nrf_set_enabled(const struct device *dev, uint32_t channel, bool enable)
111 {
112 	struct mbox_nrf_data *data = dev->data;
113 
114 	if (!is_rx_channel_valid(dev, channel)) {
115 		return -EINVAL;
116 	}
117 
118 	if ((enable == 0 && (!(data->enabled_mask & BIT(channel)))) ||
119 	    (enable != 0 &&   (data->enabled_mask & BIT(channel)))) {
120 		return -EALREADY;
121 	}
122 
123 	if (enable && (data->cb[channel] == NULL)) {
124 		LOG_WRN("Enabling channel without a registered callback\n");
125 	}
126 
127 	if (enable && data->enabled_mask == 0) {
128 		irq_enable(DT_INST_IRQN(0));
129 	}
130 
131 	if (enable) {
132 		data->enabled_mask |= BIT(channel);
133 		compiler_barrier();
134 		nrfx_ipc_receive_event_enable(channel);
135 	} else {
136 		nrfx_ipc_receive_event_disable(channel);
137 		compiler_barrier();
138 		data->enabled_mask &= ~BIT(channel);
139 	}
140 
141 	if (data->enabled_mask == 0) {
142 		irq_disable(DT_INST_IRQN(0));
143 	}
144 
145 	return 0;
146 }
147 
enable_dt_channels(const struct device * dev)148 static void enable_dt_channels(const struct device *dev)
149 {
150 	const struct mbox_nrf_conf *conf = dev->config;
151 	nrfx_ipc_config_t ch_config = { 0 };
152 
153 	if (conf->tx_mask >= BIT(IPC_CONF_NUM)) {
154 		LOG_WRN("tx_mask too big (or IPC_CONF_NUM too small)");
155 	}
156 
157 	if (conf->rx_mask >= BIT(IPC_CONF_NUM)) {
158 		LOG_WRN("rx_mask too big (or IPC_CONF_NUM too small)");
159 	}
160 
161 	/* Enable the interrupts on .set_enabled() only */
162 	ch_config.receive_events_enabled = 0;
163 
164 	for (size_t ch = 0; ch < IPC_CONF_NUM; ch++) {
165 		if (conf->tx_mask & BIT(ch)) {
166 			ch_config.send_task_config[ch] = BIT(ch);
167 		}
168 
169 		if (conf->rx_mask & BIT(ch)) {
170 			ch_config.receive_event_config[ch] = BIT(ch);
171 		}
172 	}
173 
174 	nrfx_ipc_config_load(&ch_config);
175 }
176 
mbox_nrf_init(const struct device * dev)177 static int mbox_nrf_init(const struct device *dev)
178 {
179 	struct mbox_nrf_data *data = dev->data;
180 
181 	data->dev = dev;
182 
183 	nrfx_ipc_init(0, mbox_dispatcher, (void *) data);
184 
185 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
186 		    nrfx_isr, nrfx_ipc_irq_handler, 0);
187 
188 	enable_dt_channels(dev);
189 
190 	return 0;
191 }
192 
193 static DEVICE_API(mbox, mbox_nrf_driver_api) = {
194 	.send = mbox_nrf_send,
195 	.register_callback = mbox_nrf_register_callback,
196 	.mtu_get = mbox_nrf_mtu_get,
197 	.max_channels_get = mbox_nrf_max_channels_get,
198 	.set_enabled = mbox_nrf_set_enabled,
199 };
200 
201 DEVICE_DT_INST_DEFINE(0, mbox_nrf_init, NULL, &nrfx_mbox_data, &nrfx_mbox_conf,
202 		    POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY,
203 		    &mbox_nrf_driver_api);
204