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