xref: /btstack/port/stm32-f4discovery-usb/Drivers/CMSIS/Core_A/Source/irq_ctrl_gic.c (revision a8f7f3fcbcd51f8d2e92aca076b6a9f812db358c)
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.
IRQ_Initialize(void)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.
IRQ_SetHandler(IRQn_ID_t irqn,IRQHandler_t 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.
IRQ_GetHandler(IRQn_ID_t irqn)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.
IRQ_Enable(IRQn_ID_t irqn)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.
IRQ_Disable(IRQn_ID_t irqn)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.
IRQ_GetEnableState(IRQn_ID_t irqn)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.
IRQ_SetMode(IRQn_ID_t irqn,uint32_t 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.
IRQ_GetMode(IRQn_ID_t irqn)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).
IRQ_GetActiveIRQ(void)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).
IRQ_GetActiveFIQ(void)269 __WEAK IRQn_ID_t IRQ_GetActiveFIQ (void) {
270   return ((IRQn_ID_t)-1);
271 }
272 
273 
274 /// Signal end of interrupt processing.
IRQ_EndOfInterrupt(IRQn_ID_t irqn)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.
IRQ_SetPending(IRQn_ID_t irqn)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.
IRQ_GetPending(IRQn_ID_t irqn)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.
IRQ_ClearPending(IRQn_ID_t irqn)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.
IRQ_SetPriority(IRQn_ID_t irqn,uint32_t priority)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.
IRQ_GetPriority(IRQn_ID_t irqn)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.
IRQ_SetPriorityMask(uint32_t priority)370 __WEAK int32_t IRQ_SetPriorityMask (uint32_t priority) {
371   GIC_SetInterfacePriorityMask (priority);
372   return (0);
373 }
374 
375 
376 /// Get priority masking threshold
IRQ_GetPriorityMask(void)377 __WEAK uint32_t IRQ_GetPriorityMask (void) {
378   return GIC_GetInterfacePriorityMask();
379 }
380 
381 
382 /// Set priority grouping field split point
IRQ_SetPriorityGroupBits(uint32_t bits)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
IRQ_GetPriorityGroupBits(void)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
411