1 /**************************************************************************//**
3 * @brief Interrupt controller handling implementation for GIC
5 * @date 30. October 2022
6 ******************************************************************************/
8 * Copyright (c) 2017-2022 ARM Limited. All rights reserved.
10 * SPDX-License-Identifier: Apache-2.0
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
16 * www.apache.org/licenses/LICENSE-2.0
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.
27 #include "RTE_Components.h"
28 #include CMSIS_device_header
32 #if defined(__GIC_PRESENT) && (__GIC_PRESENT == 1U)
34 /// Number of implemented interrupt lines
35 #ifndef IRQ_GIC_LINE_COUNT
36 #define IRQ_GIC_LINE_COUNT (1020U)
39 #ifndef IRQ_GIC_EXTERN_IRQ_TABLE
40 static IRQHandler_t IRQTable[IRQ_GIC_LINE_COUNT] = { 0U };
42 extern IRQHandler_t IRQTable[IRQ_GIC_LINE_COUNT];
44 static uint32_t IRQ_ID0;
46 /// Initialize interrupt controller.
47 __WEAK int32_t IRQ_Initialize (void) {
48 #ifndef IRQ_GIC_EXTERN_IRQ_TABLE
51 for (i = 0U; i < IRQ_GIC_LINE_COUNT; i++) {
52 IRQTable[i] = (IRQHandler_t)NULL;
60 /// Register interrupt handler.
61 __WEAK int32_t IRQ_SetHandler (IRQn_ID_t irqn, IRQHandler_t handler) {
64 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
65 IRQTable[irqn] = handler;
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) {
80 GIC_EndInterrupt (irqn);
84 /// Get the registered interrupt handler.
85 __WEAK IRQHandler_t IRQ_GetHandler (IRQn_ID_t irqn) {
88 // Ignore CPUID field (software generated interrupts)
91 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
101 /// Enable interrupt.
102 __WEAK int32_t IRQ_Enable (IRQn_ID_t irqn) {
105 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
106 GIC_EnableIRQ ((IRQn_Type)irqn);
116 /// Disable interrupt.
117 __WEAK int32_t IRQ_Disable (IRQn_ID_t irqn) {
120 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
121 GIC_DisableIRQ ((IRQn_Type)irqn);
131 /// Get interrupt enable state.
132 __WEAK uint32_t IRQ_GetEnableState (IRQn_ID_t irqn) {
135 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
136 enable = GIC_GetEnableIRQ((IRQn_Type)irqn);
145 /// Configure interrupt request mode.
146 __WEAK int32_t IRQ_SetMode (IRQn_ID_t irqn, uint32_t mode) {
153 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
154 // Check triggering mode
155 val = (mode & IRQ_MODE_TRIG_Msk);
157 if (val == IRQ_MODE_TRIG_LEVEL) {
159 } else if (val == IRQ_MODE_TRIG_EDGE) {
166 val = (mode & IRQ_MODE_MODEL_Msk);
167 if (val == IRQ_MODE_MODEL_1N) {
168 cfg |= 1; // 1-N model
171 // Check interrupt type
172 val = mode & IRQ_MODE_TYPE_Msk;
174 if (val != IRQ_MODE_TYPE_IRQ) {
178 // Check interrupt domain
179 val = mode & IRQ_MODE_DOMAIN_Msk;
181 if (val == IRQ_MODE_DOMAIN_NONSECURE) {
184 // Check security extensions support
185 val = GIC_DistributorInfo() & (1UL << 10U);
188 // Security extensions are supported
196 // Check interrupt CPU targets
197 val = mode & IRQ_MODE_CPU_Msk;
199 if (val == IRQ_MODE_CPU_ALL) {
202 cpu = (uint8_t)(val >> IRQ_MODE_CPU_Pos);
205 // Apply configuration if no mode error
207 GIC_SetConfiguration((IRQn_Type)irqn, cfg);
208 GIC_SetTarget ((IRQn_Type)irqn, cpu);
211 GIC_SetGroup ((IRQn_Type)irqn, secure);
220 /// Get interrupt mode configuration.
221 __WEAK uint32_t IRQ_GetMode (IRQn_ID_t irqn) {
225 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
226 mode = IRQ_MODE_TYPE_IRQ;
229 val = GIC_GetConfiguration((IRQn_Type)irqn);
231 if ((val & 2U) != 0U) {
232 // Corresponding interrupt is edge triggered
233 mode |= IRQ_MODE_TRIG_EDGE;
235 // Corresponding interrupt is level triggered
236 mode |= IRQ_MODE_TRIG_LEVEL;
240 mode |= IRQ_MODE_MODEL_1N;
242 // Get interrupt CPU targets
243 mode |= GIC_GetTarget ((IRQn_Type)irqn) << IRQ_MODE_CPU_Pos;
246 mode = IRQ_MODE_ERROR;
253 /// Get ID number of current interrupt request (IRQ).
254 __WEAK IRQn_ID_t IRQ_GetActiveIRQ (void) {
258 /* Dummy read to avoid GIC 390 errata 801120 */
259 GIC_GetHighPendingIRQ();
261 irqn = GIC_AcknowledgePending();
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. */
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);
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 */
284 /* End of Workaround GIC 390 errata 733075 */
291 /// Get ID number of current fast interrupt request (FIQ).
292 __WEAK IRQn_ID_t IRQ_GetActiveFIQ (void) {
293 return ((IRQn_ID_t)-1);
297 /// Signal end of interrupt processing.
298 __WEAK int32_t IRQ_EndOfInterrupt (IRQn_ID_t irqn) {
300 IRQn_Type irq = (IRQn_Type)irqn;
304 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
305 GIC_EndInterrupt (irq);
320 /// Set interrupt pending flag.
321 __WEAK int32_t IRQ_SetPending (IRQn_ID_t irqn) {
324 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
325 GIC_SetPendingIRQ ((IRQn_Type)irqn);
334 /// Get interrupt pending flag.
335 __WEAK uint32_t IRQ_GetPending (IRQn_ID_t irqn) {
338 if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
339 pending = GIC_GetPendingIRQ ((IRQn_Type)irqn);
344 return (pending & 1U);
348 /// Clear interrupt pending flag.
349 __WEAK int32_t IRQ_ClearPending (IRQn_ID_t irqn) {
352 if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
353 GIC_ClearPendingIRQ ((IRQn_Type)irqn);
363 /// Set interrupt priority value.
364 __WEAK int32_t IRQ_SetPriority (IRQn_ID_t irqn, uint32_t priority) {
367 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
368 GIC_SetPriority ((IRQn_Type)irqn, priority);
378 /// Get interrupt priority.
379 __WEAK uint32_t IRQ_GetPriority (IRQn_ID_t irqn) {
382 if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
383 priority = GIC_GetPriority ((IRQn_Type)irqn);
385 priority = IRQ_PRIORITY_ERROR;
392 /// Set priority masking threshold.
393 __WEAK int32_t IRQ_SetPriorityMask (uint32_t priority) {
394 GIC_SetInterfacePriorityMask (priority);
399 /// Get priority masking threshold
400 __WEAK uint32_t IRQ_GetPriorityMask (void) {
401 return GIC_GetInterfacePriorityMask();
405 /// Set priority grouping field split point
406 __WEAK int32_t IRQ_SetPriorityGroupBits (uint32_t bits) {
409 if (bits == IRQ_PRIORITY_Msk) {
414 GIC_SetBinaryPoint (7U - bits);
424 /// Get priority grouping field split point
425 __WEAK uint32_t IRQ_GetPriorityGroupBits (void) {
428 bp = GIC_GetBinaryPoint() & 0x07U;