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