aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios-contrib/ext/mcux-sdk/devices/MIMX8QM6/drivers/fsl_sc_event.c
diff options
context:
space:
mode:
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.c399
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. */
39typedef 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 ******************************************************************************/
47static volatile bool s_irq; /* MU interrupt status. */
48
49static uint32_t s_irqEnabled[SC_IRQ_NUM_GROUP] = {0U};
50static sc_event_list_t s_registeredHandler;
51static sc_ipc_t ipc; /* ipc handle */
52
53static sc_event_handler_buf_t s_handlerBuf[SC_EVENT_HANDLER_MEM_POOL_SIZE / sizeof(sc_event_handler_t)];
54static sc_event_list_t s_freeHandlerPool;
55
56static void *s_sem = NULL;
57static sc_event_sema4_post_t s_postFunc = NULL;
58
59void SCEvent_MU_IRQHandler(void);
60/*!
61 * @brief Initialize SC Event Handler list head.
62 *
63 * @param list SC Event Handler list head pointer.
64 */
65static 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 */
79static 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 */
92static 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 */
108static 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 */
125static 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 */
173static 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
186void 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
196void 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
214status_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
272sc_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
300void 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
312void 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
354status_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 */
382void 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}