1 /*
2 * Copyright (c) 2019 ST Microelectronics Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_stm32_ipcc_mailbox
8
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/device.h>
11 #include <errno.h>
12 #include <zephyr/drivers/ipm.h>
13 #include <soc.h>
14 #include <stm32_ll_ipcc.h>
15
16 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
17
18 #include <zephyr/logging/log.h>
19 #include <zephyr/irq.h>
20 LOG_MODULE_REGISTER(ipm_stm32_ipcc, CONFIG_IPM_LOG_LEVEL);
21
22 #define MBX_STRUCT(dev) \
23 ((IPCC_TypeDef *) \
24 ((const struct stm32_ipcc_mailbox_config * const)(dev)->config)->uconf.base)
25
26 #define IPCC_ALL_MR_TXF_CH_MASK 0xFFFF0000
27 #define IPCC_ALL_MR_RXO_CH_MASK 0x0000FFFF
28 #define IPCC_ALL_SR_CH_MASK 0x0000FFFF
29
30 #if (CONFIG_IPM_STM32_IPCC_PROCID == 1)
31
32 #define IPCC_EnableIT_TXF(hipcc) LL_C1_IPCC_EnableIT_TXF(hipcc)
33 #define IPCC_DisableIT_TXF(hipcc) LL_C1_IPCC_DisableIT_TXF(hipcc)
34
35 #define IPCC_EnableIT_RXO(hipcc) LL_C1_IPCC_EnableIT_RXO(hipcc)
36 #define IPCC_DisableIT_RXO(hipcc) LL_C1_IPCC_DisableIT_RXO(hipcc)
37
38 #define IPCC_EnableReceiveChannel(hipcc, ch) \
39 LL_C1_IPCC_EnableReceiveChannel(hipcc, 1 << ch)
40 #define IPCC_EnableTransmitChannel(hipcc, ch) \
41 LL_C1_IPCC_EnableTransmitChannel(hipcc, 1 << ch)
42 #define IPCC_DisableReceiveChannel(hipcc, ch) \
43 LL_C2_IPCC_DisableReceiveChannel(hipcc, 1 << ch)
44 #define IPCC_DisableTransmitChannel(hipcc, ch) \
45 LL_C1_IPCC_DisableTransmitChannel(hipcc, 1 << ch)
46
47 #define IPCC_ClearFlag_CHx(hipcc, ch) LL_C1_IPCC_ClearFlag_CHx(hipcc, 1 << ch)
48 #define IPCC_SetFlag_CHx(hipcc, ch) LL_C1_IPCC_SetFlag_CHx(hipcc, 1 << ch)
49
50 #define IPCC_IsActiveFlag_CHx(hipcc, ch) \
51 LL_C1_IPCC_IsActiveFlag_CHx(hipcc, 1 << ch)
52
53 #define IPCC_ReadReg(hipcc, reg) READ_REG(hipcc->C1##reg)
54
55 #define IPCC_ReadReg_SR(hipcc) READ_REG(hipcc->C1TOC2SR)
56 #define IPCC_ReadOtherInstReg_SR(hipcc) READ_REG(hipcc->C2TOC1SR)
57
58 #else
59
60 #define IPCC_EnableIT_TXF(hipcc) LL_C2_IPCC_EnableIT_TXF(hipcc)
61 #define IPCC_DisableIT_TXF(hipcc) LL_C2_IPCC_DisableIT_TXF(hipcc)
62
63 #define IPCC_EnableIT_RXO(hipcc) LL_C2_IPCC_EnableIT_RXO(hipcc)
64 #define IPCC_DisableIT_RXO(hipcc) LL_C2_IPCC_DisableIT_RXO(hipcc)
65
66 #define IPCC_EnableReceiveChannel(hipcc, ch) \
67 LL_C2_IPCC_EnableReceiveChannel(hipcc, 1 << ch)
68 #define IPCC_EnableTransmitChannel(hipcc, ch) \
69 LL_C2_IPCC_EnableTransmitChannel(hipcc, 1 << ch)
70 #define IPCC_DisableReceiveChannel(hipcc, ch) \
71 LL_C2_IPCC_DisableReceiveChannel(hipcc, 1 << ch)
72 #define IPCC_DisableTransmitChannel(hipcc, ch) \
73 LL_C2_IPCC_DisableTransmitChannel(hipcc, 1 << ch)
74
75 #define IPCC_ClearFlag_CHx(hipcc, ch) LL_C2_IPCC_ClearFlag_CHx(hipcc, 1 << ch)
76 #define IPCC_SetFlag_CHx(hipcc, ch) LL_C2_IPCC_SetFlag_CHx(hipcc, 1 << ch)
77
78 #define IPCC_IsActiveFlag_CHx(hipcc, ch) \
79 LL_C2_IPCC_IsActiveFlag_CHx(hipcc, 1 << ch)
80
81 #define IPCC_ReadReg(hipcc, reg) READ_REG(hipcc->C2##reg)
82
83 #define IPCC_ReadReg_SR(hipcc) READ_REG(hipcc->C2TOC1SR)
84 #define IPCC_ReadOtherInstReg_SR(hipcc) READ_REG(hipcc->C1TOC2SR)
85
86 #endif
87
88 struct stm32_ipcc_mailbox_config {
89 void (*irq_config_func)(const struct device *dev);
90 IPCC_TypeDef *ipcc;
91 struct stm32_pclken pclken;
92 };
93
94 struct stm32_ipcc_mbx_data {
95 uint32_t num_ch;
96 ipm_callback_t callback;
97 void *user_data;
98 };
99
100 static struct stm32_ipcc_mbx_data stm32_IPCC_data;
101
stm32_ipcc_mailbox_rx_isr(const struct device * dev)102 static void stm32_ipcc_mailbox_rx_isr(const struct device *dev)
103 {
104 struct stm32_ipcc_mbx_data *data = dev->data;
105 const struct stm32_ipcc_mailbox_config *cfg = dev->config;
106 unsigned int value = 0;
107 uint32_t mask, i;
108
109 mask = (~IPCC_ReadReg(cfg->ipcc, MR)) & IPCC_ALL_MR_RXO_CH_MASK;
110 mask &= IPCC_ReadOtherInstReg_SR(cfg->ipcc) & IPCC_ALL_SR_CH_MASK;
111
112 for (i = 0; i < data->num_ch; i++) {
113 if (!((1 << i) & mask)) {
114 continue;
115 }
116 LOG_DBG("%s channel = %x\r\n", __func__, i);
117 /* mask the channel Free interrupt */
118 IPCC_DisableReceiveChannel(cfg->ipcc, i);
119
120 if (data->callback) {
121 /* Only one MAILBOX, id is unused and set to 0 */
122 data->callback(dev, data->user_data, i, &value);
123 }
124 /* clear status to acknowledge message reception */
125 IPCC_ClearFlag_CHx(cfg->ipcc, i);
126 IPCC_EnableReceiveChannel(cfg->ipcc, i);
127 }
128 }
129
stm32_ipcc_mailbox_tx_isr(const struct device * dev)130 static void stm32_ipcc_mailbox_tx_isr(const struct device *dev)
131 {
132 struct stm32_ipcc_mbx_data *data = dev->data;
133 const struct stm32_ipcc_mailbox_config *cfg = dev->config;
134 uint32_t mask, i;
135
136 mask = (~IPCC_ReadReg(cfg->ipcc, MR)) & IPCC_ALL_MR_TXF_CH_MASK;
137 mask = mask >> IPCC_C1MR_CH1FM_Pos;
138
139 mask &= ~IPCC_ReadReg_SR(cfg->ipcc) & IPCC_ALL_SR_CH_MASK;
140
141 for (i = 0; i < data->num_ch; i++) {
142 if (!((1 << i) & mask)) {
143 continue;
144 }
145 LOG_DBG("%s channel = %x\r\n", __func__, i);
146 /* mask the channel Free interrupt */
147 IPCC_DisableTransmitChannel(cfg->ipcc, i);
148 }
149 }
150
stm32_ipcc_mailbox_ipm_send(const struct device * dev,int wait,uint32_t id,const void * buff,int size)151 static int stm32_ipcc_mailbox_ipm_send(const struct device *dev, int wait,
152 uint32_t id,
153 const void *buff, int size)
154 {
155 struct stm32_ipcc_mbx_data *data = dev->data;
156 const struct stm32_ipcc_mailbox_config *cfg = dev->config;
157
158 ARG_UNUSED(wait);
159 ARG_UNUSED(buff);
160
161 /* No data transmission, only doorbell */
162 if (size) {
163 return -EMSGSIZE;
164 }
165
166 if (id >= data->num_ch) {
167 LOG_ERR("invalid id (%d)\r\n", id);
168 return -EINVAL;
169 }
170
171 LOG_DBG("Send msg on channel %d\r\n", id);
172
173 /* Check that the channel is free (otherwise wait) */
174 if (IPCC_IsActiveFlag_CHx(cfg->ipcc, id)) {
175 LOG_DBG("Waiting for channel to be freed\r\n");
176 while (IPCC_IsActiveFlag_CHx(cfg->ipcc, id)) {
177 ;
178 }
179 }
180 IPCC_EnableTransmitChannel(cfg->ipcc, id);
181 IPCC_SetFlag_CHx(cfg->ipcc, id);
182
183 return 0;
184 }
185
stm32_ipcc_mailbox_ipm_max_data_size_get(const struct device * dev)186 static int stm32_ipcc_mailbox_ipm_max_data_size_get(const struct device *dev)
187 {
188 ARG_UNUSED(dev);
189
190 /* no data transfer capability */
191 return 0;
192 }
193
stm32_ipcc_mailbox_ipm_max_id_val_get(const struct device * d)194 static uint32_t stm32_ipcc_mailbox_ipm_max_id_val_get(const struct device *d)
195 {
196 struct stm32_ipcc_mbx_data *data = d->data;
197
198 return data->num_ch - 1;
199 }
200
stm32_ipcc_mailbox_ipm_register_callback(const struct device * d,ipm_callback_t cb,void * user_data)201 static void stm32_ipcc_mailbox_ipm_register_callback(const struct device *d,
202 ipm_callback_t cb,
203 void *user_data)
204 {
205 struct stm32_ipcc_mbx_data *data = d->data;
206
207 data->callback = cb;
208 data->user_data = user_data;
209 }
210
stm32_ipcc_mailbox_ipm_set_enabled(const struct device * dev,int enable)211 static int stm32_ipcc_mailbox_ipm_set_enabled(const struct device *dev,
212 int enable)
213 {
214 struct stm32_ipcc_mbx_data *data = dev->data;
215 const struct stm32_ipcc_mailbox_config *cfg = dev->config;
216 uint32_t i;
217
218 /* For now: nothing to be done */
219 LOG_DBG("%s %s mailbox\r\n", __func__, enable ? "enable" : "disable");
220 if (enable) {
221 /* Enable RX and TX interrupts */
222 IPCC_EnableIT_TXF(cfg->ipcc);
223 IPCC_EnableIT_RXO(cfg->ipcc);
224 for (i = 0; i < data->num_ch; i++) {
225 IPCC_EnableReceiveChannel(cfg->ipcc, i);
226 }
227 } else {
228 /* Disable RX and TX interrupts */
229 IPCC_DisableIT_TXF(cfg->ipcc);
230 IPCC_DisableIT_RXO(cfg->ipcc);
231 for (i = 0; i < data->num_ch; i++) {
232 IPCC_DisableReceiveChannel(cfg->ipcc, i);
233 }
234 }
235
236 return 0;
237 }
238
stm32_ipcc_mailbox_init(const struct device * dev)239 static int stm32_ipcc_mailbox_init(const struct device *dev)
240 {
241
242 struct stm32_ipcc_mbx_data *data = dev->data;
243 const struct stm32_ipcc_mailbox_config *cfg = dev->config;
244 const struct device *clk;
245 uint32_t i;
246
247 clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
248
249 if (!device_is_ready(clk)) {
250 LOG_ERR("clock control device not ready");
251 return -ENODEV;
252 }
253
254 /* enable clock */
255 if (clock_control_on(clk,
256 (clock_control_subsys_t)&cfg->pclken) != 0) {
257 return -EIO;
258 }
259
260 /* Disable RX and TX interrupts */
261 IPCC_DisableIT_TXF(cfg->ipcc);
262 IPCC_DisableIT_RXO(cfg->ipcc);
263
264 data->num_ch = LL_IPCC_GetChannelConfig(cfg->ipcc);
265
266 for (i = 0; i < data->num_ch; i++) {
267 /* Clear RX status */
268 IPCC_ClearFlag_CHx(cfg->ipcc, i);
269 /* mask RX and TX interrupts */
270 IPCC_DisableReceiveChannel(cfg->ipcc, i);
271 IPCC_DisableTransmitChannel(cfg->ipcc, i);
272 }
273
274 cfg->irq_config_func(dev);
275
276 return 0;
277 }
278
279 static const struct ipm_driver_api stm32_ipcc_mailbox_driver_api = {
280 .send = stm32_ipcc_mailbox_ipm_send,
281 .register_callback = stm32_ipcc_mailbox_ipm_register_callback,
282 .max_data_size_get = stm32_ipcc_mailbox_ipm_max_data_size_get,
283 .max_id_val_get = stm32_ipcc_mailbox_ipm_max_id_val_get,
284 .set_enabled = stm32_ipcc_mailbox_ipm_set_enabled,
285 };
286
287 static void stm32_ipcc_mailbox_config_func(const struct device *dev);
288
289 /* Config MAILBOX 0 */
290 static const struct stm32_ipcc_mailbox_config stm32_ipcc_mailbox_0_config = {
291 .irq_config_func = stm32_ipcc_mailbox_config_func,
292 .ipcc = (IPCC_TypeDef *)DT_INST_REG_ADDR(0),
293 .pclken = { .bus = DT_INST_CLOCKS_CELL(0, bus),
294 .enr = DT_INST_CLOCKS_CELL(0, bits)
295 },
296
297 };
298
299 DEVICE_DT_INST_DEFINE(0,
300 &stm32_ipcc_mailbox_init,
301 NULL,
302 &stm32_IPCC_data, &stm32_ipcc_mailbox_0_config,
303 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
304 &stm32_ipcc_mailbox_driver_api);
305
stm32_ipcc_mailbox_config_func(const struct device * dev)306 static void stm32_ipcc_mailbox_config_func(const struct device *dev)
307 {
308 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, rxo, irq),
309 DT_INST_IRQ_BY_NAME(0, rxo, priority),
310 stm32_ipcc_mailbox_rx_isr, DEVICE_DT_INST_GET(0), 0);
311
312 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, txf, irq),
313 DT_INST_IRQ_BY_NAME(0, txf, priority),
314 stm32_ipcc_mailbox_tx_isr, DEVICE_DT_INST_GET(0), 0);
315
316 irq_enable(DT_INST_IRQ_BY_NAME(0, rxo, irq));
317 irq_enable(DT_INST_IRQ_BY_NAME(0, txf, irq));
318 }
319