]> begriffs open source - cmsis/blob - CMSIS/Core_A/Source/irq_ctrl_gic.c
Build: Update IAR support for 5.8.0
[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.1.0
5  * @date     03. March 2020
6  ******************************************************************************/
7 /*
8  * Copyright (c) 2017-2020 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     val = (mode & IRQ_MODE_MODEL_Msk);
152     if (val == IRQ_MODE_MODEL_1N) {
153       cfg |= 1;   // 1-N model
154     }
155
156     // Check interrupt type
157     val = mode & IRQ_MODE_TYPE_Msk;
158
159     if (val != IRQ_MODE_TYPE_IRQ) {
160       status = -1;
161     }
162
163     // Check interrupt domain
164     val = mode & IRQ_MODE_DOMAIN_Msk;
165
166     if (val == IRQ_MODE_DOMAIN_NONSECURE) {
167       secure = 0U;
168     } else {
169       // Check security extensions support
170       val = GIC_DistributorInfo() & (1UL << 10U);
171
172       if (val != 0U) {
173         // Security extensions are supported
174         secure = 1U;
175       } else {
176         secure = 0U;
177         status = -1;
178       }
179     }
180
181     // Check interrupt CPU targets
182     val = mode & IRQ_MODE_CPU_Msk;
183
184     if (val == IRQ_MODE_CPU_ALL) {
185       cpu = 0xFFU;
186     } else {
187       cpu = (uint8_t)(val >> IRQ_MODE_CPU_Pos);
188     }
189
190     // Apply configuration if no mode error
191     if (status == 0) {
192       GIC_SetConfiguration((IRQn_Type)irqn, cfg);
193       GIC_SetTarget       ((IRQn_Type)irqn, cpu);
194
195       if (secure != 0U) {
196         GIC_SetGroup ((IRQn_Type)irqn, secure);
197       }
198     }
199   }
200
201   return (status);
202 }
203
204
205 /// Get interrupt mode configuration.
206 __WEAK uint32_t IRQ_GetMode (IRQn_ID_t irqn) {
207   uint32_t mode;
208   uint32_t val;
209
210   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
211     mode = IRQ_MODE_TYPE_IRQ;
212
213     // Get trigger mode
214     val = GIC_GetConfiguration((IRQn_Type)irqn);
215
216     if ((val & 2U) != 0U) {
217       // Corresponding interrupt is edge triggered
218       mode |= IRQ_MODE_TRIG_EDGE;
219     } else {
220       // Corresponding interrupt is level triggered
221       mode |= IRQ_MODE_TRIG_LEVEL;
222     }
223
224     if (val & 1U) {
225       mode |= IRQ_MODE_MODEL_1N;
226     }
227     // Get interrupt CPU targets
228     mode |= GIC_GetTarget ((IRQn_Type)irqn) << IRQ_MODE_CPU_Pos;
229
230   } else {
231     mode = IRQ_MODE_ERROR;
232   }
233
234   return (mode);
235 }
236
237
238 /// Get ID number of current interrupt request (IRQ).
239 __WEAK IRQn_ID_t IRQ_GetActiveIRQ (void) {
240   IRQn_ID_t irqn;
241   uint32_t prio;
242
243   /* Dummy read to avoid GIC 390 errata 801120 */
244   GIC_GetHighPendingIRQ();
245
246   irqn = GIC_AcknowledgePending();
247
248   __DSB();
249
250   /* Workaround GIC 390 errata 733075 (GIC-390_Errata_Notice_v6.pdf, 09-Jul-2014)  */
251   /* The following workaround code is for a single-core system.  It would be       */
252   /* different in a multi-core system.                                             */
253   /* If the ID is 0 or 0x3FE or 0x3FF, then the GIC CPU interface may be locked-up */
254   /* so unlock it, otherwise service the interrupt as normal.                      */
255   /* Special IDs 1020=0x3FC and 1021=0x3FD are reserved values in GICv1 and GICv2  */
256   /* so will not occur here.                                                       */
257
258   if ((irqn == 0) || (irqn >= 0x3FE)) {
259     /* Unlock the CPU interface with a dummy write to Interrupt Priority Register */
260     prio = GIC_GetPriority((IRQn_Type)0);
261     GIC_SetPriority ((IRQn_Type)0, prio);
262
263     __DSB();
264
265     if ((irqn == 0U) && ((GIC_GetIRQStatus ((IRQn_Type)irqn) & 1U) != 0U) && (IRQ_ID0 == 0U)) {
266       /* If the ID is 0, is active and has not been seen before */
267       IRQ_ID0 = 1U;
268     }
269     /* End of Workaround GIC 390 errata 733075 */
270   }
271
272   return (irqn);
273 }
274
275
276 /// Get ID number of current fast interrupt request (FIQ).
277 __WEAK IRQn_ID_t IRQ_GetActiveFIQ (void) {
278   return ((IRQn_ID_t)-1);
279 }
280
281
282 /// Signal end of interrupt processing.
283 __WEAK int32_t IRQ_EndOfInterrupt (IRQn_ID_t irqn) {
284   int32_t status;
285   IRQn_Type irq = (IRQn_Type)irqn;
286
287   irqn &= 0x3FFU;
288
289   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
290     GIC_EndInterrupt (irq);
291
292     if (irqn == 0) {
293       IRQ_ID0 = 0U;
294     }
295
296     status = 0;
297   } else {
298     status = -1;
299   }
300
301   return (status);
302 }
303
304
305 /// Set interrupt pending flag.
306 __WEAK int32_t IRQ_SetPending (IRQn_ID_t irqn) {
307   int32_t status;
308
309   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
310     GIC_SetPendingIRQ ((IRQn_Type)irqn);
311     status = 0;
312   } else {
313     status = -1;
314   }
315
316   return (status);
317 }
318
319 /// Get interrupt pending flag.
320 __WEAK uint32_t IRQ_GetPending (IRQn_ID_t irqn) {
321   uint32_t pending;
322
323   if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
324     pending = GIC_GetPendingIRQ ((IRQn_Type)irqn);
325   } else {
326     pending = 0U;
327   }
328
329   return (pending & 1U);
330 }
331
332
333 /// Clear interrupt pending flag.
334 __WEAK int32_t IRQ_ClearPending (IRQn_ID_t irqn) {
335   int32_t status;
336
337   if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
338     GIC_ClearPendingIRQ ((IRQn_Type)irqn);
339     status = 0;
340   } else {
341     status = -1;
342   }
343
344   return (status);
345 }
346
347
348 /// Set interrupt priority value.
349 __WEAK int32_t IRQ_SetPriority (IRQn_ID_t irqn, uint32_t priority) {
350   int32_t status;
351
352   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
353     GIC_SetPriority ((IRQn_Type)irqn, priority);
354     status = 0;
355   } else {
356     status = -1;
357   }
358
359   return (status);
360 }
361
362
363 /// Get interrupt priority.
364 __WEAK uint32_t IRQ_GetPriority (IRQn_ID_t irqn) {
365   uint32_t priority;
366
367   if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
368     priority = GIC_GetPriority ((IRQn_Type)irqn);
369   } else {
370     priority = IRQ_PRIORITY_ERROR;
371   }
372
373   return (priority);
374 }
375
376
377 /// Set priority masking threshold.
378 __WEAK int32_t IRQ_SetPriorityMask (uint32_t priority) {
379   GIC_SetInterfacePriorityMask (priority);
380   return (0);
381 }
382
383
384 /// Get priority masking threshold
385 __WEAK uint32_t IRQ_GetPriorityMask (void) {
386   return GIC_GetInterfacePriorityMask();
387 }
388
389
390 /// Set priority grouping field split point
391 __WEAK int32_t IRQ_SetPriorityGroupBits (uint32_t bits) {
392   int32_t status;
393
394   if (bits == IRQ_PRIORITY_Msk) {
395     bits = 7U;
396   }
397
398   if (bits < 8U) {
399     GIC_SetBinaryPoint (7U - bits);
400     status = 0;
401   } else {
402     status = -1;
403   }
404
405   return (status);
406 }
407
408
409 /// Get priority grouping field split point
410 __WEAK uint32_t IRQ_GetPriorityGroupBits (void) {
411   uint32_t bp;
412
413   bp = GIC_GetBinaryPoint() & 0x07U;
414
415   return (7U - bp);
416 }
417
418 #endif