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