]> begriffs open source - cmsis/blob - CMSIS/Core/Source/irq_ctrl_gic.c
Update workflows and build scripts
[cmsis] / CMSIS / Core / Source / irq_ctrl_gic.c
1 /**************************************************************************//**
2  * @file     irq_ctrl_gic.c
3  * @brief    Interrupt controller handling implementation for GIC
4  * @version  V1.2.0
5  * @date     30. October 2022
6  ******************************************************************************/
7 /*
8  * Copyright (c) 2017-2022 ARM Limited. All rights reserved.
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  *
12  * Licensed under the Apache License, Version 2.0 (the License); you may
13  * not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  * www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
20  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24
25 #include <stddef.h>
26
27 #include "RTE_Components.h"
28 #include CMSIS_device_header
29
30 #include "irq_ctrl.h"
31
32 #if defined(__GIC_PRESENT) && (__GIC_PRESENT == 1U)
33
34 /// Number of implemented interrupt lines
35 #ifndef IRQ_GIC_LINE_COUNT
36 #define IRQ_GIC_LINE_COUNT      (1020U)
37 #endif
38
39 #ifndef IRQ_GIC_EXTERN_IRQ_TABLE
40 static IRQHandler_t IRQTable[IRQ_GIC_LINE_COUNT] = { 0U };
41 #else
42 extern IRQHandler_t IRQTable[IRQ_GIC_LINE_COUNT];
43 #endif
44 static uint32_t     IRQ_ID0;
45
46 /// Initialize interrupt controller.
47 __WEAK int32_t IRQ_Initialize (void) {
48   #ifndef IRQ_GIC_EXTERN_IRQ_TABLE
49     uint32_t i;
50
51     for (i = 0U; i < IRQ_GIC_LINE_COUNT; i++) {
52       IRQTable[i] = (IRQHandler_t)NULL;
53     }
54     GIC_Enable();
55   #endif
56   return (0);
57 }
58
59
60 /// Register interrupt handler.
61 __WEAK int32_t IRQ_SetHandler (IRQn_ID_t irqn, IRQHandler_t handler) {
62   int32_t status;
63
64   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
65     IRQTable[irqn] = handler;
66     status =  0;
67   } else {
68     status = -1;
69   }
70
71   return (status);
72 }
73
74 /// The Interrupt Handler.
75 __WEAK void IRQ_Handler (void) {
76   IRQn_Type irqn = GIC_AcknowledgePending ();
77   if (irqn < (IRQn_Type)IRQ_GIC_LINE_COUNT) {
78     IRQTable[irqn]();
79   }
80   GIC_EndInterrupt (irqn);
81 }
82
83
84 /// Get the registered interrupt handler.
85 __WEAK IRQHandler_t IRQ_GetHandler (IRQn_ID_t irqn) {
86   IRQHandler_t h;
87
88   // Ignore CPUID field (software generated interrupts)
89   irqn &= 0x3FFU;
90
91   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
92     h = IRQTable[irqn];
93   } else {
94     h = (IRQHandler_t)0;
95   }
96
97   return (h);
98 }
99
100
101 /// Enable interrupt.
102 __WEAK int32_t IRQ_Enable (IRQn_ID_t irqn) {
103   int32_t status;
104
105   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
106     GIC_EnableIRQ ((IRQn_Type)irqn);
107     status = 0;
108   } else {
109     status = -1;
110   }
111
112   return (status);
113 }
114
115
116 /// Disable interrupt.
117 __WEAK int32_t IRQ_Disable (IRQn_ID_t irqn) {
118   int32_t status;
119
120   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
121     GIC_DisableIRQ ((IRQn_Type)irqn);
122     status = 0;
123   } else {
124     status = -1;
125   }
126
127   return (status);
128 }
129
130
131 /// Get interrupt enable state.
132 __WEAK uint32_t IRQ_GetEnableState (IRQn_ID_t irqn) {
133   uint32_t enable;
134
135   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
136     enable = GIC_GetEnableIRQ((IRQn_Type)irqn);
137   } else {
138     enable = 0U;
139   }
140
141   return (enable);
142 }
143
144
145 /// Configure interrupt request mode.
146 __WEAK int32_t IRQ_SetMode (IRQn_ID_t irqn, uint32_t mode) {
147   uint32_t val;
148   uint8_t cfg;
149   uint8_t secure;
150   uint8_t cpu;
151   int32_t status = 0;
152
153   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
154     // Check triggering mode
155     val = (mode & IRQ_MODE_TRIG_Msk);
156
157     if (val == IRQ_MODE_TRIG_LEVEL) {
158       cfg = 0x00U;
159     } else if (val == IRQ_MODE_TRIG_EDGE) {
160       cfg = 0x02U;
161     } else {
162       cfg = 0x00U;
163       status = -1;
164     }
165
166     val = (mode & IRQ_MODE_MODEL_Msk);
167     if (val == IRQ_MODE_MODEL_1N) {
168       cfg |= 1;   // 1-N model
169     }
170
171     // Check interrupt type
172     val = mode & IRQ_MODE_TYPE_Msk;
173
174     if (val != IRQ_MODE_TYPE_IRQ) {
175       status = -1;
176     }
177
178     // Check interrupt domain
179     val = mode & IRQ_MODE_DOMAIN_Msk;
180
181     if (val == IRQ_MODE_DOMAIN_NONSECURE) {
182       secure = 0U;
183     } else {
184       // Check security extensions support
185       val = GIC_DistributorInfo() & (1UL << 10U);
186
187       if (val != 0U) {
188         // Security extensions are supported
189         secure = 1U;
190       } else {
191         secure = 0U;
192         status = -1;
193       }
194     }
195
196     // Check interrupt CPU targets
197     val = mode & IRQ_MODE_CPU_Msk;
198
199     if (val == IRQ_MODE_CPU_ALL) {
200       cpu = 0xFFU;
201     } else {
202       cpu = (uint8_t)(val >> IRQ_MODE_CPU_Pos);
203     }
204
205     // Apply configuration if no mode error
206     if (status == 0) {
207       GIC_SetConfiguration((IRQn_Type)irqn, cfg);
208       GIC_SetTarget       ((IRQn_Type)irqn, cpu);
209
210       if (secure != 0U) {
211         GIC_SetGroup ((IRQn_Type)irqn, secure);
212       }
213     }
214   }
215
216   return (status);
217 }
218
219
220 /// Get interrupt mode configuration.
221 __WEAK uint32_t IRQ_GetMode (IRQn_ID_t irqn) {
222   uint32_t mode;
223   uint32_t val;
224
225   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
226     mode = IRQ_MODE_TYPE_IRQ;
227
228     // Get trigger mode
229     val = GIC_GetConfiguration((IRQn_Type)irqn);
230
231     if ((val & 2U) != 0U) {
232       // Corresponding interrupt is edge triggered
233       mode |= IRQ_MODE_TRIG_EDGE;
234     } else {
235       // Corresponding interrupt is level triggered
236       mode |= IRQ_MODE_TRIG_LEVEL;
237     }
238
239     if (val & 1U) {
240       mode |= IRQ_MODE_MODEL_1N;
241     }
242     // Get interrupt CPU targets
243     mode |= GIC_GetTarget ((IRQn_Type)irqn) << IRQ_MODE_CPU_Pos;
244
245   } else {
246     mode = IRQ_MODE_ERROR;
247   }
248
249   return (mode);
250 }
251
252
253 /// Get ID number of current interrupt request (IRQ).
254 __WEAK IRQn_ID_t IRQ_GetActiveIRQ (void) {
255   IRQn_ID_t irqn;
256   uint32_t prio;
257
258   /* Dummy read to avoid GIC 390 errata 801120 */
259   GIC_GetHighPendingIRQ();
260
261   irqn = GIC_AcknowledgePending();
262
263   __DSB();
264
265   /* Workaround GIC 390 errata 733075 (GIC-390_Errata_Notice_v6.pdf, 09-Jul-2014)  */
266   /* The following workaround code is for a single-core system.  It would be       */
267   /* different in a multi-core system.                                             */
268   /* If the ID is 0 or 0x3FE or 0x3FF, then the GIC CPU interface may be locked-up */
269   /* so unlock it, otherwise service the interrupt as normal.                      */
270   /* Special IDs 1020=0x3FC and 1021=0x3FD are reserved values in GICv1 and GICv2  */
271   /* so will not occur here.                                                       */
272
273   if ((irqn == 0) || (irqn >= 0x3FE)) {
274     /* Unlock the CPU interface with a dummy write to Interrupt Priority Register */
275     prio = GIC_GetPriority((IRQn_Type)0);
276     GIC_SetPriority ((IRQn_Type)0, prio);
277
278     __DSB();
279
280     if ((irqn == 0U) && ((GIC_GetIRQStatus ((IRQn_Type)irqn) & 1U) != 0U) && (IRQ_ID0 == 0U)) {
281       /* If the ID is 0, is active and has not been seen before */
282       IRQ_ID0 = 1U;
283     }
284     /* End of Workaround GIC 390 errata 733075 */
285   }
286
287   return (irqn);
288 }
289
290
291 /// Get ID number of current fast interrupt request (FIQ).
292 __WEAK IRQn_ID_t IRQ_GetActiveFIQ (void) {
293   return ((IRQn_ID_t)-1);
294 }
295
296
297 /// Signal end of interrupt processing.
298 __WEAK int32_t IRQ_EndOfInterrupt (IRQn_ID_t irqn) {
299   int32_t status;
300   IRQn_Type irq = (IRQn_Type)irqn;
301
302   irqn &= 0x3FFU;
303
304   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
305     GIC_EndInterrupt (irq);
306
307     if (irqn == 0) {
308       IRQ_ID0 = 0U;
309     }
310
311     status = 0;
312   } else {
313     status = -1;
314   }
315
316   return (status);
317 }
318
319
320 /// Set interrupt pending flag.
321 __WEAK int32_t IRQ_SetPending (IRQn_ID_t irqn) {
322   int32_t status;
323
324   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
325     GIC_SetPendingIRQ ((IRQn_Type)irqn);
326     status = 0;
327   } else {
328     status = -1;
329   }
330
331   return (status);
332 }
333
334 /// Get interrupt pending flag.
335 __WEAK uint32_t IRQ_GetPending (IRQn_ID_t irqn) {
336   uint32_t pending;
337
338   if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
339     pending = GIC_GetPendingIRQ ((IRQn_Type)irqn);
340   } else {
341     pending = 0U;
342   }
343
344   return (pending & 1U);
345 }
346
347
348 /// Clear interrupt pending flag.
349 __WEAK int32_t IRQ_ClearPending (IRQn_ID_t irqn) {
350   int32_t status;
351
352   if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
353     GIC_ClearPendingIRQ ((IRQn_Type)irqn);
354     status = 0;
355   } else {
356     status = -1;
357   }
358
359   return (status);
360 }
361
362
363 /// Set interrupt priority value.
364 __WEAK int32_t IRQ_SetPriority (IRQn_ID_t irqn, uint32_t priority) {
365   int32_t status;
366
367   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
368     GIC_SetPriority ((IRQn_Type)irqn, priority);
369     status = 0;
370   } else {
371     status = -1;
372   }
373
374   return (status);
375 }
376
377
378 /// Get interrupt priority.
379 __WEAK uint32_t IRQ_GetPriority (IRQn_ID_t irqn) {
380   uint32_t priority;
381
382   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
383     priority = GIC_GetPriority ((IRQn_Type)irqn);
384   } else {
385     priority = IRQ_PRIORITY_ERROR;
386   }
387
388   return (priority);
389 }
390
391
392 /// Set priority masking threshold.
393 __WEAK int32_t IRQ_SetPriorityMask (uint32_t priority) {
394   GIC_SetInterfacePriorityMask (priority);
395   return (0);
396 }
397
398
399 /// Get priority masking threshold
400 __WEAK uint32_t IRQ_GetPriorityMask (void) {
401   return GIC_GetInterfacePriorityMask();
402 }
403
404
405 /// Set priority grouping field split point
406 __WEAK int32_t IRQ_SetPriorityGroupBits (uint32_t bits) {
407   int32_t status;
408
409   if (bits == IRQ_PRIORITY_Msk) {
410     bits = 7U;
411   }
412
413   if (bits < 8U) {
414     GIC_SetBinaryPoint (7U - bits);
415     status = 0;
416   } else {
417     status = -1;
418   }
419
420   return (status);
421 }
422
423
424 /// Get priority grouping field split point
425 __WEAK uint32_t IRQ_GetPriorityGroupBits (void) {
426   uint32_t bp;
427
428   bp = GIC_GetBinaryPoint() & 0x07U;
429
430   return (7U - bp);
431 }
432
433 #endif