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