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