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