diff options
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/devices/MIMX8QM6/drivers/fsl_sc_event.c')
-rw-r--r-- | lib/chibios-contrib/ext/mcux-sdk/devices/MIMX8QM6/drivers/fsl_sc_event.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/devices/MIMX8QM6/drivers/fsl_sc_event.c b/lib/chibios-contrib/ext/mcux-sdk/devices/MIMX8QM6/drivers/fsl_sc_event.c new file mode 100644 index 000000000..9c3bdf774 --- /dev/null +++ b/lib/chibios-contrib/ext/mcux-sdk/devices/MIMX8QM6/drivers/fsl_sc_event.c | |||
@@ -0,0 +1,399 @@ | |||
1 | /* | ||
2 | * Copyright 2019 NXP | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * SPDX-License-Identifier: BSD-3-Clause | ||
6 | */ | ||
7 | |||
8 | #include "fsl_sc_event.h" | ||
9 | #include "fsl_mu.h" | ||
10 | #include "assert.h" | ||
11 | |||
12 | /******************************************************************************* | ||
13 | * Definitions | ||
14 | ******************************************************************************/ | ||
15 | |||
16 | /* Component ID definition, used by tools. */ | ||
17 | #ifndef FSL_COMPONENT_ID | ||
18 | #define FSL_COMPONENT_ID "platform.drivers.sc_event" | ||
19 | #endif | ||
20 | |||
21 | #if defined(MIMX8QM_CM4_CORE0) | ||
22 | #define IPC_MU CM4_0__MU1_A | ||
23 | #define SCEvent_MU_IRQHandler M4_0_MU1_A_IRQHandler | ||
24 | #define IPC_MU_IRQn M4_0_MU1_A_IRQn | ||
25 | #define IPC_MU_RSRC SC_R_M4_0_MU_1A | ||
26 | #elif defined(MIMX8QM_CM4_CORE1) | ||
27 | #define IPC_MU CM4_1__MU1_A | ||
28 | #define SCEvent_MU_IRQHandler M4_1_MU1_A_IRQHandler | ||
29 | #define IPC_MU_IRQn M4_1_MU1_A_IRQn | ||
30 | #define IPC_MU_RSRC SC_R_M4_1_MU_1A | ||
31 | #else | ||
32 | #error "Unsupported CPU." | ||
33 | #endif | ||
34 | |||
35 | /******************************************************************************* | ||
36 | * Prototypes | ||
37 | ******************************************************************************/ | ||
38 | /* Define a structure to hold SRTM_MESSAGE_BUF_SIZE buffer. */ | ||
39 | typedef struct | ||
40 | { | ||
41 | sc_event_list_t node; | ||
42 | uint8_t buf[sizeof(struct _sc_event_handler) - sizeof(sc_event_list_t)]; | ||
43 | } sc_event_handler_buf_t; | ||
44 | /******************************************************************************* | ||
45 | * Code | ||
46 | ******************************************************************************/ | ||
47 | static volatile bool s_irq; /* MU interrupt status. */ | ||
48 | |||
49 | static uint32_t s_irqEnabled[SC_IRQ_NUM_GROUP] = {0U}; | ||
50 | static sc_event_list_t s_registeredHandler; | ||
51 | static sc_ipc_t ipc; /* ipc handle */ | ||
52 | |||
53 | static sc_event_handler_buf_t s_handlerBuf[SC_EVENT_HANDLER_MEM_POOL_SIZE / sizeof(sc_event_handler_t)]; | ||
54 | static sc_event_list_t s_freeHandlerPool; | ||
55 | |||
56 | static void *s_sem = NULL; | ||
57 | static sc_event_sema4_post_t s_postFunc = NULL; | ||
58 | |||
59 | void SCEvent_MU_IRQHandler(void); | ||
60 | /*! | ||
61 | * @brief Initialize SC Event Handler list head. | ||
62 | * | ||
63 | * @param list SC Event Handler list head pointer. | ||
64 | */ | ||
65 | static inline void SCEvent_List_Init(sc_event_list_t *list) | ||
66 | { | ||
67 | assert(list); | ||
68 | |||
69 | list->prev = list; | ||
70 | list->next = list; | ||
71 | } | ||
72 | |||
73 | /*! | ||
74 | * @brief Check whether SC Event Handler list is empty. | ||
75 | * | ||
76 | * @param list SC Event Handler list head pointer. | ||
77 | * @return TRUE when list is empty, FALSE otherwise. | ||
78 | */ | ||
79 | static inline bool SCEvent_List_IsEmpty(sc_event_list_t *list) | ||
80 | { | ||
81 | assert(list); | ||
82 | |||
83 | return list->next == list; | ||
84 | } | ||
85 | |||
86 | /*! | ||
87 | * @brief Add list node at list tail. | ||
88 | * | ||
89 | * @param list SC Event Handler list head pointer. | ||
90 | * @param node SC Event Handler list node pointer to add. | ||
91 | */ | ||
92 | static inline void SCEvent_List_AddTail(sc_event_list_t *list, sc_event_list_t *node) | ||
93 | { | ||
94 | assert(list); | ||
95 | assert(node); | ||
96 | |||
97 | node->prev = list->prev; | ||
98 | node->next = list; | ||
99 | list->prev->next = node; | ||
100 | list->prev = node; | ||
101 | } | ||
102 | |||
103 | /*! | ||
104 | * @brief Remove list node from list. | ||
105 | * | ||
106 | * @param node SC Event Handler list node pointer to remove. | ||
107 | */ | ||
108 | static inline void SCEvent_List_Remove(sc_event_list_t *node) | ||
109 | { | ||
110 | assert(node); | ||
111 | |||
112 | node->prev->next = node->next; | ||
113 | node->next->prev = node->prev; | ||
114 | /* clear node */ | ||
115 | SCEvent_List_Init(node); | ||
116 | } | ||
117 | |||
118 | /*! | ||
119 | * @brief Allocate memory with specific size. | ||
120 | * | ||
121 | * @param size memory size to allocate. | ||
122 | * | ||
123 | * @return allocated memory address. | ||
124 | */ | ||
125 | static void *SCEvent_Pool_Alloc(uint32_t size) | ||
126 | { | ||
127 | uint32_t i; | ||
128 | void *buf; | ||
129 | uint32_t primask; | ||
130 | |||
131 | if (s_freeHandlerPool.next == NULL) | ||
132 | { | ||
133 | primask = DisableGlobalIRQ(); | ||
134 | if (s_freeHandlerPool.next == NULL) | ||
135 | { | ||
136 | /* Handler list not initialized, initialize now. */ | ||
137 | SCEvent_List_Init(&s_freeHandlerPool); | ||
138 | for (i = 0U; i < sizeof(s_handlerBuf) / sizeof(sc_event_handler_buf_t); i++) | ||
139 | { | ||
140 | SCEvent_List_AddTail(&s_freeHandlerPool, &s_handlerBuf[i].node); | ||
141 | } | ||
142 | } | ||
143 | EnableGlobalIRQ(primask); | ||
144 | } | ||
145 | |||
146 | if (size > sizeof(sc_event_handler_buf_t)) | ||
147 | { | ||
148 | return NULL; | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | primask = DisableGlobalIRQ(); | ||
153 | if (SCEvent_List_IsEmpty(&s_freeHandlerPool)) | ||
154 | { | ||
155 | return NULL; | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | buf = (void *)s_freeHandlerPool.next; | ||
160 | SCEvent_List_Remove(s_freeHandlerPool.next); | ||
161 | EnableGlobalIRQ(primask); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | return buf; | ||
166 | } | ||
167 | |||
168 | /*! | ||
169 | * @brief Free the allocated memory. | ||
170 | * | ||
171 | * @param buf the address of the allocated memory | ||
172 | */ | ||
173 | static void SCEvent_Pool_Free(void *buf) | ||
174 | { | ||
175 | sc_event_handler_t hBuf; | ||
176 | uint32_t primask; | ||
177 | |||
178 | /* buffer locates in handler pool */ | ||
179 | assert(((uint32_t)((sc_event_handler_buf_t*)buf) - (uint32_t)&s_handlerBuf[0]) % sizeof(sc_event_handler_buf_t) == 0U); | ||
180 | hBuf = (sc_event_handler_t)buf; | ||
181 | primask = DisableGlobalIRQ(); | ||
182 | SCEvent_List_AddTail(&s_freeHandlerPool, &hBuf->node); | ||
183 | EnableGlobalIRQ(primask); | ||
184 | } | ||
185 | |||
186 | void SCEvent_Init(uint8_t priority) | ||
187 | { | ||
188 | ipc = SystemGetScfwIpcHandle(); | ||
189 | NVIC_SetPriority(IPC_MU_IRQn, priority); | ||
190 | (void)EnableIRQ(IPC_MU_IRQn); | ||
191 | MU_EnableInterrupts(IPC_MU, MU_SR_GIPn_MASK); | ||
192 | |||
193 | SCEvent_List_Init(&s_registeredHandler); | ||
194 | } | ||
195 | |||
196 | void SCEvent_Deinit(void) | ||
197 | { | ||
198 | sc_event_list_t *list; | ||
199 | sc_event_handler_t handler; | ||
200 | |||
201 | /* Unregister all handler. */ | ||
202 | while (!SCEvent_List_IsEmpty(&s_registeredHandler)) | ||
203 | { | ||
204 | list = s_registeredHandler.next; | ||
205 | SCEvent_List_Remove(list); | ||
206 | handler = SC_EVENT_LIST_OBJ(sc_event_handler_t, node, list); | ||
207 | SCEvent_Pool_Free(handler); | ||
208 | } | ||
209 | |||
210 | MU_DisableInterrupts(IPC_MU, MU_SR_GIPn_MASK); | ||
211 | (void)DisableIRQ(IPC_MU_IRQn); | ||
212 | } | ||
213 | |||
214 | status_t SCEvent_Config(sc_event_t event, bool enable, uint32_t pt) | ||
215 | { | ||
216 | uint32_t status; | ||
217 | sc_err_t err; | ||
218 | uint32_t mask = SC_EVENT_GET_IRQ(event); | ||
219 | uint8_t group = (uint8_t)SC_EVENT_GET_IRQ_GROUP(event); | ||
220 | |||
221 | /* | ||
222 | * The SCFW IRQ pending flags will be set even the IRQ not enabled. If it's the first IRQ to be enabled in the | ||
223 | * group, clear the group's pending IRQ status in case some IRQ has already pending. | ||
224 | */ | ||
225 | if ((s_irqEnabled[group] == 0U) && enable) | ||
226 | { | ||
227 | err = sc_irq_status(ipc, IPC_MU_RSRC, group, &status); | ||
228 | if (err != SC_ERR_NONE) | ||
229 | { | ||
230 | return kStatus_Fail; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | if (mask == SC_EVENT_IRQ_DUMMY) | ||
235 | { | ||
236 | err = sc_irq_enable(ipc, IPC_MU_RSRC, group, (0x1UL << pt), enable); | ||
237 | if (err != SC_ERR_NONE) | ||
238 | { | ||
239 | return kStatus_Fail; | ||
240 | } | ||
241 | |||
242 | if (enable) | ||
243 | { | ||
244 | s_irqEnabled[group] |= 0x1UL << pt; | ||
245 | } | ||
246 | else | ||
247 | { | ||
248 | /* Clear the flag if IRQ disabled. */ | ||
249 | s_irqEnabled[group] &= (~(0x1UL << pt)) & SC_EVENT_IRQ_DUMMY; | ||
250 | } | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | err = sc_irq_enable(ipc, IPC_MU_RSRC, group, mask, enable); | ||
255 | if (err != SC_ERR_NONE) | ||
256 | { | ||
257 | return kStatus_Fail; | ||
258 | } | ||
259 | if (enable) | ||
260 | { | ||
261 | s_irqEnabled[group] |= mask; | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | s_irqEnabled[group] &= ~mask; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | return kStatus_Success; | ||
270 | } | ||
271 | |||
272 | sc_event_handler_t SCEvent_RegisterEventHandler(sc_event_t event, sc_event_callback_t callback, void *userData) | ||
273 | { | ||
274 | assert(callback); | ||
275 | uint32_t primask; | ||
276 | sc_event_handler_t handler = (sc_event_handler_t)SCEvent_Pool_Alloc(sizeof(sc_event_handler_buf_t)); | ||
277 | |||
278 | if (handler == NULL) | ||
279 | { | ||
280 | return NULL; | ||
281 | } | ||
282 | else | ||
283 | { | ||
284 | (void)memset(handler, 0, sizeof(sc_event_handler_buf_t)); | ||
285 | /* clear node */ | ||
286 | SCEvent_List_Init(&handler->node); | ||
287 | |||
288 | handler->event = event; | ||
289 | handler->callback = callback; | ||
290 | handler->data = userData; | ||
291 | |||
292 | /* Add handler into registered handler list. */ | ||
293 | primask = DisableGlobalIRQ(); | ||
294 | SCEvent_List_AddTail(&s_registeredHandler, &handler->node); | ||
295 | EnableGlobalIRQ(primask); | ||
296 | return handler; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | void SCEvent_UnregisterEventHandler(sc_event_handler_t handler) | ||
301 | { | ||
302 | assert(handler); | ||
303 | uint32_t primask; | ||
304 | |||
305 | primask = DisableGlobalIRQ(); | ||
306 | SCEvent_List_Remove(&handler->node); | ||
307 | EnableGlobalIRQ(primask); | ||
308 | |||
309 | SCEvent_Pool_Free(handler); | ||
310 | } | ||
311 | |||
312 | void SCEvent_Process(void) | ||
313 | { | ||
314 | sc_err_t err; | ||
315 | uint32_t mask; /* Enabled IRQ mask. */ | ||
316 | uint8_t group; /* Event group. */ | ||
317 | uint32_t irqStatus[SC_IRQ_NUM_GROUP] = {0U}; | ||
318 | |||
319 | sc_event_list_t *list; | ||
320 | sc_event_handler_t handler; | ||
321 | |||
322 | if (s_irq) | ||
323 | { | ||
324 | for (list = s_registeredHandler.next; list != &s_registeredHandler; list = list->next) | ||
325 | { | ||
326 | handler = SC_EVENT_LIST_OBJ(sc_event_handler_t, node, list); | ||
327 | |||
328 | mask = SC_EVENT_GET_IRQ(handler->event); | ||
329 | group = (uint8_t)SC_EVENT_GET_IRQ_GROUP(handler->event); | ||
330 | /* Only read and clear status once for a group. */ | ||
331 | if (irqStatus[group] == 0U) | ||
332 | { | ||
333 | err = sc_irq_status(ipc, IPC_MU_RSRC, group, &irqStatus[group]); | ||
334 | if (err != SC_ERR_NONE) | ||
335 | { | ||
336 | continue; | ||
337 | } | ||
338 | |||
339 | } | ||
340 | /* If there's event pending and the event IRQ enabled, call the handler. */ | ||
341 | if ((irqStatus[group] & mask & s_irqEnabled[group]) != 0U) | ||
342 | { | ||
343 | handler->callback(irqStatus[group], handler->data); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /* Clean up the status. */ | ||
348 | (void)memset(irqStatus, 0, sizeof(irqStatus)); | ||
349 | |||
350 | s_irq = false; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | status_t SCEvent_WaitEvent(sc_event_sema4_wait_t wait, sc_event_sema4_post_t post, void *sem, uint32_t timeout) | ||
355 | { | ||
356 | status_t ret = kStatus_Success; | ||
357 | uint32_t primask; | ||
358 | |||
359 | assert(post); | ||
360 | assert(wait); | ||
361 | |||
362 | primask = DisableGlobalIRQ(); | ||
363 | if (!s_irq) /* Return immediately if there's event pending. */ | ||
364 | { | ||
365 | s_sem = sem; | ||
366 | s_postFunc = post; | ||
367 | EnableGlobalIRQ(primask); | ||
368 | ret = wait(sem, timeout); | ||
369 | s_postFunc = NULL; | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | EnableGlobalIRQ(primask); | ||
374 | } | ||
375 | |||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | /*! | ||
380 | * IRQ Handler for SCEvent Triggling MU IRQ | ||
381 | */ | ||
382 | void SCEvent_MU_IRQHandler(void) | ||
383 | { | ||
384 | /* Clear interrupt flag */ | ||
385 | MU_ClearStatusFlags(IPC_MU, MU_SR_GIPn_MASK); | ||
386 | |||
387 | if (s_postFunc != NULL) | ||
388 | { | ||
389 | s_postFunc(s_sem); | ||
390 | } | ||
391 | |||
392 | s_irq = true; | ||
393 | |||
394 | /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping | ||
395 | exception return operation might vector to incorrect interrupt */ | ||
396 | #if defined __CORTEX_M && (__CORTEX_M == 4U) | ||
397 | __DSB(); | ||
398 | #endif | ||
399 | } | ||