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.
IRQ_Initialize(void)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.
IRQ_SetHandler(IRQn_ID_t irqn,IRQHandler_t 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.
IRQ_Handler(void)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.
IRQ_GetHandler(IRQn_ID_t irqn)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.
IRQ_Enable(IRQn_ID_t irqn)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.
IRQ_Disable(IRQn_ID_t irqn)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.
IRQ_GetEnableState(IRQn_ID_t irqn)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.
IRQ_SetMode(IRQn_ID_t irqn,uint32_t 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.
IRQ_GetMode(IRQn_ID_t irqn)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).
IRQ_GetActiveIRQ(void)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).
IRQ_GetActiveFIQ(void)292 __WEAK IRQn_ID_t IRQ_GetActiveFIQ (void) {
293   return ((IRQn_ID_t)-1);
294 }
295 
296 
297 /// Signal end of interrupt processing.
IRQ_EndOfInterrupt(IRQn_ID_t irqn)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.
IRQ_SetPending(IRQn_ID_t irqn)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.
IRQ_GetPending(IRQn_ID_t irqn)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.
IRQ_ClearPending(IRQn_ID_t irqn)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.
IRQ_SetPriority(IRQn_ID_t irqn,uint32_t priority)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.
IRQ_GetPriority(IRQn_ID_t irqn)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.
IRQ_SetPriorityMask(uint32_t priority)393 __WEAK int32_t IRQ_SetPriorityMask (uint32_t priority) {
394   GIC_SetInterfacePriorityMask (priority);
395   return (0);
396 }
397 
398 
399 /// Get priority masking threshold
IRQ_GetPriorityMask(void)400 __WEAK uint32_t IRQ_GetPriorityMask (void) {
401   return GIC_GetInterfacePriorityMask();
402 }
403 
404 
405 /// Set priority grouping field split point
IRQ_SetPriorityGroupBits(uint32_t bits)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
IRQ_GetPriorityGroupBits(void)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
434