1 /**************************************************************************//**
2  * @file     gic_v3.h
3  * @brief    CMSIS Cortex-A53 Generic Interrupt Controller API header file
4  * @version  V1.0.1
5  * @date     05. october 2021
6  ******************************************************************************/
7 /*
8  * Copyright (c) 2021 Arm Limited. All rights reserved.
9  * Copyright 2021-2023 NXP
10  *
11  * SPDX-License-Identifier: Apache-2.0
12  *
13  * Licensed under the Apache License, Version 2.0 (the License); you may
14  * not use this file except in compliance with the License.
15  * You may obtain a copy of the License at
16  *
17  * www.apache.org/licenses/LICENSE-2.0
18  *
19  * Unless required by applicable law or agreed to in writing, software
20  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
21  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  * See the License for the specific language governing permissions and
23  * limitations under the License.
24  */
25 
26 #if   defined ( __ICCARM__ )
27   #pragma system_include         /* treat file as system include file for MISRA check */
28 #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
29   #pragma clang system_header   /* treat file as system include file */
30 #endif
31 
32 #ifndef __GIC_V3_H
33 #define __GIC_V3_H
34 
35 #ifdef __cplusplus
36  extern "C" {
37 #endif
38 
39 /*******************************************************************************
40  *                 GIC Data Types
41  ******************************************************************************/
42 
43 /** \brief  AArch64 System registers to access the Generic Interrupt Controller CPU interface
44 */
45 #if defined(__GNUC__)
46   #define ICC_BPR0_EL1           S3_0_C12_C8_3
47   #define ICC_BPR1_EL1           S3_0_C12_C12_3
48   #define ICC_CTLR_EL1           S3_0_C12_C12_4
49   #define ICC_CTLR_EL3           S3_6_C12_C12_4
50   #define ICC_EOIR0_EL1          S3_0_C12_C8_1
51   #define ICC_EOIR1_EL1          S3_0_C12_C12_1
52   #define ICC_HPPIR0_EL1         S3_0_C12_C8_2
53   #define ICC_HPPIR1_EL1         S3_0_C12_C12_2
54   #define ICC_IAR0_EL1           S3_0_C12_C8_0
55   #define ICC_IAR1_EL1           S3_0_C12_C12_0
56   #define ICC_IGRPEN0_EL1        S3_0_C12_C12_6
57   #define ICC_IGRPEN1_EL1        S3_0_C12_C12_7
58   #define ICC_IGRPEN1_EL3        S3_6_C12_C12_7
59   #define ICC_PMR_EL1            S3_0_C4_C6_0
60   #define ICC_RPR_EL1            S3_0_C12_C11_3
61   #define ICC_SGI0R_EL1          S3_0_C12_C11_7
62   #define ICC_SGI1R_EL1          S3_0_C12_C11_5
63   #define ICC_SRE_EL1            S3_0_C12_C12_5
64   #define ICC_SRE_EL2            S3_4_C12_C9_5
65   #define ICC_SRE_EL3            S3_6_C12_C12_5
66 #endif /* __GNUC__ */
67 
68 /* ICC_SGIR */
69 #define ICC_SGIR_TARGETLIST_SHIFT	(0)
70 #define ICC_SGIR_TARGETLIST_MASK	(0xffff)
71 #define ICC_SGIR_AFF_MASK		(0xff)
72 #define ICC_SGIR_AFF1_SHIFT		(16)
73 #define ICC_SGIR_INTID_SHIFT		(24)
74 #define ICC_SGIR_INTID_MASK		(0xf)
75 #define ICC_SGIR_AFF2_SHIFT		(32)
76 #define ICC_SGIR_IRM_SHIFT		(40)
77 #define ICC_SGIR_IRM_MASK		(0x1)
78 #define ICC_SGIR_RS_SHIFT		(44)
79 #define ICC_SGIR_RS_MASK		(0xf)
80 #define ICC_SGIR_AFF3_SHIFT		(48)
81 
82 #define MPIDR_TO_RS(mpidr)		(MPIDR_TO_AFF_LEVEL(mpidr, 0) >> 4)
83 
84 #define COMPOSE_ICC_SGIR_VALUE(aff3, aff2, aff1, intid, irm, rs, tlist)	\
85 	((((uint64_t)(aff3) & ICC_SGIR_AFF_MASK) << ICC_SGIR_AFF3_SHIFT) |	\
86 	 (((uint64_t)(rs) & ICC_SGIR_RS_MASK) << ICC_SGIR_RS_SHIFT) |		\
87 	 (((uint64_t)(irm) & ICC_SGIR_IRM_MASK) << ICC_SGIR_IRM_SHIFT) |	\
88 	 (((uint64_t)(aff2) & ICC_SGIR_AFF_MASK) << ICC_SGIR_AFF2_SHIFT) |	\
89 	 (((intid) & ICC_SGIR_INTID_MASK) << ICC_SGIR_INTID_SHIFT) |		\
90 	 (((aff1) & ICC_SGIR_AFF_MASK) << ICC_SGIR_AFF1_SHIFT) |		\
91 	 (((tlist) & ICC_SGIR_TARGETLIST_MASK) << ICC_SGIR_TARGETLIST_SHIFT))
92 
93 #define GIC_REDISTRIBUTOR_STRIDE	(0x20000)
94 #define GICR_SGI_BASE_OFF		(0x10000)
95 
96 #define GICR_TYPER_LAST_SHIFT		(4)
97 #define GICR_TYPER_LAST_MASK		(1 << GICR_TYPER_LAST_SHIFT)
98 #define GICR_TYPER_AFF_SHIFT		(32)
99 
100 #define GICR_WAKER_PS_SHIFT		(1)
101 #define GICR_WAKER_CA_SHIFT		(2)
102 
103 
104 /** \brief  Structure type to access the Generic Interrupt Controller Distributor (GICD)
105 */
106 typedef struct
107 {
108   __IOM uint32_t CTLR;                 /*!< \brief  Offset: 0x000 (R/W) Distributor Control Register */
109   __IM  uint32_t TYPER;                /*!< \brief  Offset: 0x004 (R/ ) Interrupt Controller Type Register */
110   __IM  uint32_t IIDR;                 /*!< \brief  Offset: 0x008 (R/ ) Distributor Implementer Identification Register */
111         RESERVED(0, uint32_t)
112   __IOM uint32_t STATUSR;              /*!< \brief  Offset: 0x010 (R/W) Error Reporting Status Register, optional */
113         RESERVED(1[11], uint32_t)
114   __OM  uint32_t SETSPI_NSR;           /*!< \brief  Offset: 0x040 ( /W) Set SPI Register */
115         RESERVED(2, uint32_t)
116   __OM  uint32_t CLRSPI_NSR;           /*!< \brief  Offset: 0x048 ( /W) Clear SPI Register */
117         RESERVED(3, uint32_t)
118   __OM  uint32_t SETSPI_SR;            /*!< \brief  Offset: 0x050 ( /W) Set SPI, Secure Register */
119         RESERVED(4, uint32_t)
120   __OM  uint32_t CLRSPI_SR;            /*!< \brief  Offset: 0x058 ( /W) Clear SPI, Secure Register */
121         RESERVED(5[9], uint32_t)
122   __IOM uint32_t IGROUPR[32];          /*!< \brief  Offset: 0x080 (R/W) Interrupt Group Registers */
123   __IOM uint32_t ISENABLER[32];        /*!< \brief  Offset: 0x100 (R/W) Interrupt Set-Enable Registers */
124   __IOM uint32_t ICENABLER[32];        /*!< \brief  Offset: 0x180 (R/W) Interrupt Clear-Enable Registers */
125   __IOM uint32_t ISPENDR[32];          /*!< \brief  Offset: 0x200 (R/W) Interrupt Set-Pending Registers */
126   __IOM uint32_t ICPENDR[32];          /*!< \brief  Offset: 0x280 (R/W) Interrupt Clear-Pending Registers */
127   __IOM uint32_t ISACTIVER[32];        /*!< \brief  Offset: 0x300 (R/W) Interrupt Set-Active Registers */
128   __IOM uint32_t ICACTIVER[32];        /*!< \brief  Offset: 0x380 (R/W) Interrupt Clear-Active Registers */
129   __IOM uint32_t IPRIORITYR[255];      /*!< \brief  Offset: 0x400 (R/W) Interrupt Priority Registers */
130         RESERVED(6, uint32_t)
131   __IOM uint32_t  ITARGETSR[255];      /*!< \brief  Offset: 0x800 (R/W) Interrupt Targets Registers */
132         RESERVED(7, uint32_t)
133   __IOM uint32_t ICFGR[64];            /*!< \brief  Offset: 0xC00 (R/W) Interrupt Configuration Registers */
134   __IOM uint32_t IGRPMODR[32];         /*!< \brief  Offset: 0xD00 (R/W) Interrupt Group Modifier Registers */
135         RESERVED(8[32], uint32_t)
136   __IOM uint32_t NSACR[64];            /*!< \brief  Offset: 0xE00 (R/W) Non-secure Access Control Registers */
137   __OM  uint32_t SGIR;                 /*!< \brief  Offset: 0xF00 ( /W) Software Generated Interrupt Register */
138         RESERVED(9[3], uint32_t)
139   __IOM uint32_t CPENDSGIR[4];         /*!< \brief  Offset: 0xF10 (R/W) SGI Clear-Pending Registers */
140   __IOM uint32_t SPENDSGIR[4];         /*!< \brief  Offset: 0xF20 (R/W) SGI Set-Pending Registers */
141         RESERVED(10[5172], uint32_t)
142   __IOM uint64_t IROUTER[988];         /*!< \brief  Offset: 0x6000(R/W) Interrupt Routing Registers */
143 }  GICDistributor_Type;
144 
145 #define GICDistributor      ((GICDistributor_Type      *)     GIC_DISTRIBUTOR_BASE ) /*!< \brief GIC Distributor register set access pointer */
146 
147 /** \brief  Structure type to access the Generic Interrupt Controller Redistributor (GICR)
148 */
149 typedef struct
150 {
151   __IOM uint32_t CTLR;                 /*!< \brief  Offset: 0x000 (R/W) Redistributor Control Register */
152   __IM  uint32_t IIDR;                 /*!< \brief  Offset: 0x004 (R/ ) Implementer Identification Register */
153   __IM  uint64_t TYPER;                /*!< \brief  Offset: 0x008 (R/ ) Redistributor Type Register */
154   __IOM uint32_t STATUSR;              /*!< \brief  Offset: 0x010 (R/W) Error Reporting Status Register, optional */
155   __IOM uint32_t WAKER;                /*!< \brief  Offset: 0x014 (R/W) Redistributor Wake Register */
156   __IM  uint32_t MPAMIDR;              /*!< \brief  Offset: 0x018 (R/ ) Report maximum PARTID and PMG Register */
157   __IOM uint32_t PARTIDR;              /*!< \brief  Offset: 0x01C (R/W) Set PARTID and PMG Register */
158         RESERVED(1[8], uint32_t)
159   __OM  uint32_t SETLPIR;              /*!< \brief  Offset: 0x040 ( /W) Set LPI Pending Register */
160         RESERVED(2, uint32_t)
161   __OM  uint32_t CLRLPIR;              /*!< \brief  Offset: 0x048 ( /W) Clear LPI Pending Register */
162         RESERVED(3[9], uint32_t)
163   __IOM uint32_t PROPBASER;            /*!< \brief  Offset: 0x070 (R/W) Redistributor Properties Base Address Register */
164         RESERVED(4, uint32_t)
165   __IOM uint32_t PENDBASER;            /*!< \brief  Offset: 0x078 (R/W) Redistributor LPI Pending Table Base Address Register */
166         RESERVED(5[9], uint32_t)
167   __OM  uint32_t INVLPIR;              /*!< \brief  Offset: 0x0A0 ( /W) Redistributor Invalidate LPI Register */
168         RESERVED(6[3], uint32_t)
169   __OM  uint32_t INVALLR;              /*!< \brief  Offset: 0x0B0 ( /W) Redistributor Invalidate All Register */
170         RESERVED(7[3], uint32_t)
171   __IM  uint32_t SYNCR;                /*!< \brief  Offset: 0x0C0 (R/ ) Redistributor Synchronize Register */
172 }  GICRedistributor_Type;
173 
174 /* Memory mapped GIC interface may be disabled when ICC_SRE_ELx.SRE set 1 by hypervisor.
175    In this case we will be using MSR/MRS system registers.  */
176 #ifdef GIC_INTERFACE_BASE
177 
178 /** \brief  Structure type to access the Generic Interrupt Controller Interface (GICC)
179 */
180 typedef struct
181 {
182   __IOM uint32_t CTLR;                 /*!< \brief  Offset: 0x000 (R/W) CPU Interface Control Register */
183   __IOM uint32_t PMR;                  /*!< \brief  Offset: 0x004 (R/W) Interrupt Priority Mask Register */
184   __IOM uint32_t BPR;                  /*!< \brief  Offset: 0x008 (R/W) Binary Point Register */
185   __IM  uint32_t IAR;                  /*!< \brief  Offset: 0x00C (R/ ) Interrupt Acknowledge Register */
186   __OM  uint32_t EOIR;                 /*!< \brief  Offset: 0x010 ( /W) End Of Interrupt Register */
187   __IM  uint32_t RPR;                  /*!< \brief  Offset: 0x014 (R/ ) Running Priority Register */
188   __IM  uint32_t HPPIR;                /*!< \brief  Offset: 0x018 (R/ ) Highest Priority Pending Interrupt Register */
189   __IOM uint32_t ABPR;                 /*!< \brief  Offset: 0x01C (R/W) Aliased Binary Point Register */
190   __IM  uint32_t AIAR;                 /*!< \brief  Offset: 0x020 (R/ ) Aliased Interrupt Acknowledge Register */
191   __OM  uint32_t AEOIR;                /*!< \brief  Offset: 0x024 ( /W) Aliased End Of Interrupt Register */
192   __IM  uint32_t AHPPIR;               /*!< \brief  Offset: 0x028 (R/ ) Aliased Highest Priority Pending Interrupt Register */
193   __IOM uint32_t STATUSR;              /*!< \brief  Offset: 0x02C (R/W) Error Reporting Status Register, optional */
194         RESERVED(1[40], uint32_t)
195   __IOM uint32_t APR[4];               /*!< \brief  Offset: 0x0D0 (R/W) Active Priority Register */
196   __IOM uint32_t NSAPR[4];             /*!< \brief  Offset: 0x0E0 (R/W) Non-secure Active Priority Register */
197         RESERVED(2[3], uint32_t)
198   __IM  uint32_t IIDR;                 /*!< \brief  Offset: 0x0FC (R/ ) CPU Interface Identification Register */
199         RESERVED(3[960], uint32_t)
200   __OM  uint32_t DIR;                  /*!< \brief  Offset: 0x1000( /W) Deactivate Interrupt Register */
201 }  GICInterface_Type;
202 
203 #define GICInterface        ((GICInterface_Type        *)     GIC_INTERFACE_BASE )   /*!< \brief GIC Interface register set access pointer */
204 #endif /* GIC_INTERFACE_BASE */
205 
206 /* ctrl register access in non-secure */
207 #define GICD_CTLR_RWP		31
208 #define GICD_CTLR_ARE_NS	4
209 #define GICD_CTLR_ENGRP1A	1
210 #define GICD_CTLR_ENGRP1	0
211 
212 #define GICR_CTLR_RWP		3
213 
214 enum gic_rwp {
215   GICD_RWP,
216   GICR_RWP,
217 };
218 
219 /*******************************************************************************
220  *                 GIC Functions
221  ******************************************************************************/
222 
223 /* ##########################  GIC functions  ###################################### */
224 
225 /** \brief Get the recomposed MPIDR_EL1 Affinity fields.
226 * the recomposed Affinity value format is (aff3:aff2:aff1:aff0)
227 */
GIC_MPIDRtoAffinity(void)228 __STATIC_INLINE uint32_t GIC_MPIDRtoAffinity(void)
229 {
230   uint32_t aff3, aff2, aff1, aff0, aff;
231   uint64_t mpidr = __get_MPIDR_EL1();
232 
233   aff0 = MPIDR_TO_AFF_LEVEL(mpidr, 0);
234   aff1 = MPIDR_TO_AFF_LEVEL(mpidr, 1);
235   aff2 = MPIDR_TO_AFF_LEVEL(mpidr, 2);
236   aff3 = MPIDR_TO_AFF_LEVEL(mpidr, 3);
237 
238   aff = (aff0 & MPIDR_AFFLVL_MASK) << 0  |
239         (aff1 & MPIDR_AFFLVL_MASK) << 8  |
240         (aff2 & MPIDR_AFFLVL_MASK) << 16 |
241         (aff3 & MPIDR_AFFLVL_MASK) << 24;
242 
243   return aff;
244 }
245 
246 /** \brief Get the Redistributor base.
247 */
GIC_GetRdist(void)248 __STATIC_INLINE GICRedistributor_Type *GIC_GetRdist(void)
249 {
250   uintptr_t rd_addr = GIC_REDISTRIBUTOR_BASE;
251   uint32_t rd_aff, aff = GIC_MPIDRtoAffinity();
252   uint64_t rd_typer;
253 
254   do {
255     rd_typer = ((GICRedistributor_Type *)rd_addr)->TYPER;
256     rd_aff = rd_typer >> GICR_TYPER_AFF_SHIFT;
257 
258     if (rd_aff == aff)
259       return (GICRedistributor_Type *)rd_addr;
260 
261     rd_addr += GIC_REDISTRIBUTOR_STRIDE;
262   } while (!(rd_typer & GICR_TYPER_LAST_MASK));
263 
264   return NULL;
265 }
266 
267 /** \brief Get the Redistributor SGI_base.
268 */
GIC_GetRdistSGIBase(void * rd_base)269 __STATIC_INLINE void *GIC_GetRdistSGIBase(void *rd_base)
270 {
271   return (void *)((uintptr_t)rd_base + GICR_SGI_BASE_OFF);
272 }
273 
274 /** \brief Wait for register write pending.
275 */
GIC_WaitRWP(enum gic_rwp rwp)276 __STATIC_INLINE void GIC_WaitRWP(enum gic_rwp rwp)
277 {
278   uint32_t rwp_mask;
279   uint32_t __IM *base;
280 
281   if (rwp == GICR_RWP) {
282     base = &GIC_GetRdist()->CTLR;
283     if (!base)
284       return;
285     rwp_mask = BIT(GICR_CTLR_RWP);
286   } else if (rwp == GICD_RWP) {
287     base = &GICDistributor->CTLR;
288     rwp_mask = BIT(GICD_CTLR_RWP);
289   } else {
290     return;
291   }
292 
293   while (*base & rwp_mask)
294     ;
295 }
296 
297 /** \brief Get the Affinity Routing status.
298 */
GIC_GetARE(void)299 __STATIC_INLINE bool GIC_GetARE(void)
300 {
301   return !!(GICDistributor->CTLR & 0x30);
302 }
303 
304 /** \brief Disable the interrupt distributor using the GIC's CTLR register.
305 */
GIC_DisableDistributor(void)306 __STATIC_INLINE void GIC_DisableDistributor(void)
307 {
308   GICDistributor->CTLR &=~1U;
309   GIC_WaitRWP(GICD_RWP);
310 }
311 
312 /** \brief Read the GIC's TYPER register.
313 * \return GICDistributor_Type::TYPER
314 */
GIC_DistributorInfo(void)315 __STATIC_INLINE uint32_t GIC_DistributorInfo(void)
316 {
317   return (GICDistributor->TYPER);
318 }
319 
320 /** \brief Reads the GIC's IIDR register.
321 * \return GICDistributor_Type::IIDR
322 */
GIC_DistributorImplementer(void)323 __STATIC_INLINE uint32_t GIC_DistributorImplementer(void)
324 {
325   return (GICDistributor->IIDR);
326 }
327 
328 /** \brief Sets the GIC's ITARGETSR register for the given interrupt.
329 * \param [in] IRQn Interrupt to be configured.
330 * \param [in] cpu_target CPU interfaces to assign this interrupt to.
331 */
GIC_SetTarget(IRQn_Type IRQn,uint64_t cpu_target)332 __STATIC_INLINE void GIC_SetTarget(IRQn_Type IRQn, uint64_t cpu_target)
333 {
334   if (IRQn >= 32)
335   {
336     if (GIC_GetARE())
337     {
338       /* affinity routing */
339       GICDistributor->IROUTER[IRQn] = cpu_target;
340     }
341     else
342     {
343       /* legacy */
344       uint32_t mask = GICDistributor->ITARGETSR[IRQn / 4U] & ~(0xFFUL << ((IRQn % 4U) * 8U));
345       GICDistributor->ITARGETSR[IRQn / 4U] = mask | ((cpu_target & 0xFFUL) << ((IRQn % 4U) * 8U));
346     }
347   }
348 }
349 
350 /** \brief Get the target core of the interrupt.
351 * \param [in] IRQn Interrupt to acquire the configuration for.
352 *
353 * \return:
354 * For SPI: GICDistributor_Type::ITARGETSR when Affinity Routing isn't enabled,
355 * or GICDistributor_Type::IROUTER when Affinity Routing is enabled
356 * For SGI/PPI: The Affinity fields of the MPIDR_EL1.
357 */
GIC_GetTarget(IRQn_Type IRQn)358 __STATIC_INLINE uint64_t GIC_GetTarget(IRQn_Type IRQn)
359 {
360   uint64_t cpu_target = 0;
361 
362   if (IRQn >= 32)
363   {
364     if (GIC_GetARE())
365     {
366       /* affinity routing */
367       cpu_target = GICDistributor->IROUTER[IRQn];
368     }
369     else
370     {
371       /* legacy */
372       cpu_target = (GICDistributor->ITARGETSR[IRQn / 4U] >> ((IRQn % 4U) * 8U)) & 0xFFUL;
373     }
374   }
375   else
376   {
377       /* local */
378       cpu_target = __get_MPIDR_EL1() & MPIDR_AFFINITY_MASK;
379   }
380 
381   return cpu_target;
382 }
383 
384 /** \brief Enables the given interrupt using GIC's ISENABLER register.
385 * \param [in] IRQn The interrupt to be enabled.
386 */
GIC_EnableIRQ(IRQn_Type IRQn)387 __STATIC_INLINE void GIC_EnableIRQ(IRQn_Type IRQn)
388 {
389   uint64_t mpidr = __get_MPIDR_EL1();
390   GICDistributor_Type *s_RedistPPIBaseAddrs;
391 
392   GIC_SetTarget(IRQn, mpidr & MPIDR_AFFINITY_MASK);
393 
394   if (IRQn < 32) {
395     s_RedistPPIBaseAddrs = GIC_GetRdistSGIBase(GIC_GetRdist());
396     s_RedistPPIBaseAddrs->ISENABLER[0] = 1U << IRQn;
397   } else {
398     GICDistributor->ISENABLER[IRQn / 32U] = 1U << (IRQn % 32U);
399   }
400 }
401 
402 /** \brief Get interrupt enable status using GIC's ISENABLER register.
403 * \param [in] IRQn The interrupt to be queried.
404 * \return 0 - interrupt is not enabled, 1 - interrupt is enabled.
405 */
GIC_GetEnableIRQ(IRQn_Type IRQn)406 __STATIC_INLINE uint32_t GIC_GetEnableIRQ(IRQn_Type IRQn)
407 {
408   return (GICDistributor->ISENABLER[IRQn / 32U] >> (IRQn % 32U)) & 1UL;
409 }
410 
411 /** \brief Disables the given interrupt using GIC's ICENABLER register.
412 * \param [in] IRQn The interrupt to be disabled.
413 */
GIC_DisableIRQ(IRQn_Type IRQn)414 __STATIC_INLINE void GIC_DisableIRQ(IRQn_Type IRQn)
415 {
416   GICDistributor_Type *s_RedistPPIBaseAddrs;
417 
418   if (IRQn < 32) {
419     s_RedistPPIBaseAddrs = GIC_GetRdistSGIBase(GIC_GetRdist());
420     s_RedistPPIBaseAddrs->ICENABLER[0] = 1U << IRQn;
421     GIC_WaitRWP(GICR_RWP);
422   } else {
423     GICDistributor->ICENABLER[IRQn / 32U] = 1U << (IRQn % 32U);
424     GIC_WaitRWP(GICD_RWP);
425   }
426 }
427 
428 /** \brief Get interrupt pending status from GIC's ISPENDR register.
429 * \param [in] IRQn The interrupt to be queried.
430 * \return 0 - interrupt is not pending, 1 - interrupt is pendig.
431 */
GIC_GetPendingIRQ(IRQn_Type IRQn)432 __STATIC_INLINE uint32_t GIC_GetPendingIRQ(IRQn_Type IRQn)
433 {
434   uint32_t pend;
435 
436   if (IRQn >= 16) {
437     pend = (GICDistributor->ISPENDR[IRQn / 32U] >> (IRQn % 32U)) & 1UL;
438   } else {
439     // INTID 0-15 Software Generated Interrupt
440     pend = (GICDistributor->SPENDSGIR[IRQn / 4U] >> ((IRQn % 4U) * 8U)) & 0xFFUL;
441     // No CPU identification offered
442     if (pend != 0U) {
443       pend = 1U;
444     } else {
445       pend = 0U;
446     }
447   }
448 
449   return (pend);
450 }
451 
452 /** \brief Sets the given interrupt as pending using GIC's ISPENDR register.
453 * \param [in] IRQn The interrupt to be enabled.
454 */
GIC_SetPendingIRQ(IRQn_Type IRQn)455 __STATIC_INLINE void GIC_SetPendingIRQ(IRQn_Type IRQn)
456 {
457   if (IRQn >= 16) {
458     GICDistributor->ISPENDR[IRQn / 32U] = 1U << (IRQn % 32U);
459   } else {
460     // INTID 0-15 Software Generated Interrupt
461     GICDistributor->SPENDSGIR[IRQn / 4U] = 1U << ((IRQn % 4U) * 8U);
462     // Forward the interrupt to the CPU interface that requested it
463     GICDistributor->SGIR = (IRQn | 0x02000000U);
464   }
465 }
466 
467 /** \brief Clears the given interrupt from being pending using GIC's ICPENDR register.
468 * \param [in] IRQn The interrupt to be enabled.
469 */
GIC_ClearPendingIRQ(IRQn_Type IRQn)470 __STATIC_INLINE void GIC_ClearPendingIRQ(IRQn_Type IRQn)
471 {
472   if (IRQn >= 16) {
473     GICDistributor->ICPENDR[IRQn / 32U] = 1U << (IRQn % 32U);
474   } else {
475     // INTID 0-15 Software Generated Interrupt
476     GICDistributor->CPENDSGIR[IRQn / 4U] = 1U << ((IRQn % 4U) * 8U);
477   }
478 }
479 
480 /** \brief Sets the interrupt configuration using GIC's ICFGR register.
481 * \param [in] IRQn The interrupt to be configured.
482 * \param [in] int_config Int_config field value. Bit 0: Reserved (0 - N-N model, 1 - 1-N model for some GIC before v1)
483 *                                           Bit 1: 0 - level sensitive, 1 - edge triggered
484 */
GIC_SetConfiguration(IRQn_Type IRQn,uint32_t int_config)485 __STATIC_INLINE void GIC_SetConfiguration(IRQn_Type IRQn, uint32_t int_config)
486 {
487   uint32_t icfgr = GICDistributor->ICFGR[IRQn / 16U];
488   uint32_t shift = (IRQn % 16U) << 1U;
489 
490   icfgr &= (~(3U         << shift));
491   icfgr |= (  int_config << shift);
492 
493   GICDistributor->ICFGR[IRQn / 16U] = icfgr;
494 }
495 
496 /** \brief Get the interrupt configuration from the GIC's ICFGR register.
497 * \param [in] IRQn Interrupt to acquire the configuration for.
498 * \return Int_config field value. Bit 0: Reserved (0 - N-N model, 1 - 1-N model for some GIC before v1)
499 *                                 Bit 1: 0 - level sensitive, 1 - edge triggered
500 */
GIC_GetConfiguration(IRQn_Type IRQn)501 __STATIC_INLINE uint32_t GIC_GetConfiguration(IRQn_Type IRQn)
502 {
503   return (GICDistributor->ICFGR[IRQn / 16U] >> ((IRQn % 16U) >> 1U));
504 }
505 
GIC_SetRedistPriority(IRQn_Type IRQn,uint32_t priority)506 __STATIC_INLINE void GIC_SetRedistPriority(IRQn_Type IRQn, uint32_t priority)
507 {
508   GICDistributor_Type *s_RedistPPIBaseAddrs = GIC_GetRdistSGIBase(GIC_GetRdist());
509   uint32_t mask = s_RedistPPIBaseAddrs->IPRIORITYR[IRQn / 4U] & ~(0xFFUL << ((IRQn % 4U) * 8U));
510 
511   s_RedistPPIBaseAddrs->IPRIORITYR[IRQn / 4U] = mask | ((priority & 0xFFUL) << ((IRQn % 4U) * 8U));
512 }
513 
514 /** \brief Set the priority for the given interrupt.
515 * \param [in] IRQn The interrupt to be configured.
516 * \param [in] priority The priority for the interrupt, lower values denote higher priorities.
517 */
GIC_SetPriority(IRQn_Type IRQn,uint32_t priority)518 __STATIC_INLINE void GIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
519 {
520   uint32_t mask;
521 
522   if ((IRQn < 32) && (GIC_GetARE())) {
523     GIC_SetRedistPriority(IRQn, priority);
524   } else {
525     mask = GICDistributor->IPRIORITYR[IRQn / 4U] & ~(0xFFUL << ((IRQn % 4U) * 8U));
526     GICDistributor->IPRIORITYR[IRQn / 4U] = mask | ((priority & 0xFFUL) << ((IRQn % 4U) * 8U));
527   }
528 }
529 
GIC_RedistWakeUp(void)530 __STATIC_INLINE void GIC_RedistWakeUp(void)
531 {
532   GICRedistributor_Type *const s_RedistBaseAddrs = GIC_GetRdist();
533 
534   if (!s_RedistBaseAddrs)
535     return;
536 
537   if (!(s_RedistBaseAddrs->WAKER & (1 << GICR_WAKER_CA_SHIFT)))
538     return;
539 
540   s_RedistBaseAddrs->WAKER &= ~ (1 << GICR_WAKER_PS_SHIFT);
541   while (s_RedistBaseAddrs->WAKER & (1 << GICR_WAKER_CA_SHIFT))
542     ;
543 }
544 
GIC_GetRedistPriority(IRQn_Type IRQn)545 __STATIC_INLINE uint32_t GIC_GetRedistPriority(IRQn_Type IRQn)
546 {
547   GICDistributor_Type *s_RedistPPIBaseAddrs;
548 
549   s_RedistPPIBaseAddrs = GIC_GetRdistSGIBase(GIC_GetRdist());
550   return (s_RedistPPIBaseAddrs->IPRIORITYR[IRQn / 4U] >> ((IRQn % 4U) * 8U)) & 0xFFUL;
551 }
552 
553 /** \brief Read the current interrupt priority from GIC's IPRIORITYR register.
554 * \param [in] IRQn The interrupt to be queried.
555 */
GIC_GetPriority(IRQn_Type IRQn)556 __STATIC_INLINE uint32_t GIC_GetPriority(IRQn_Type IRQn)
557 {
558   if ((IRQn < 32) && (GIC_GetARE())) {
559     return GIC_GetRedistPriority(IRQn);
560   } else {
561     return (GICDistributor->IPRIORITYR[IRQn / 4U] >> ((IRQn % 4U) * 8U)) & 0xFFUL;
562   }
563 }
564 
565 /** \brief Get the status for a given interrupt.
566 * \param [in] IRQn The interrupt to get status for.
567 * \return 0 - not pending/active, 1 - pending, 2 - active, 3 - pending and active
568 */
GIC_GetIRQStatus(IRQn_Type IRQn)569 __STATIC_INLINE uint32_t GIC_GetIRQStatus(IRQn_Type IRQn)
570 {
571   uint32_t pending, active;
572 
573   active = ((GICDistributor->ISACTIVER[IRQn / 32U])  >> (IRQn % 32U)) & 1UL;
574   pending = ((GICDistributor->ISPENDR[IRQn / 32U]) >> (IRQn % 32U)) & 1UL;
575 
576   return ((active<<1U) | pending);
577 }
578 
579 /** \brief Generate a software interrupt (Affinity Routing version).
580 * \param [in] IRQn Software interrupt to be generated.
581 * \param [in] target_aff Target affinity in MPIDR form.
582 * \param [in] tlist List of CPUs the software interrupt should be forwarded to.
583 */
GIC_SendSGI_ARE(IRQn_Type IRQn,uint64_t target_aff,uint16_t tlist)584 __STATIC_INLINE void GIC_SendSGI_ARE(IRQn_Type IRQn, uint64_t target_aff, uint16_t tlist)
585 {
586   uint32_t aff3, aff2, aff1, rs;
587   uint64_t val;
588 
589   if (IRQn >= 16)
590     return;
591 
592   aff1 = MPIDR_TO_AFF_LEVEL(target_aff, 1);
593   aff2 = MPIDR_TO_AFF_LEVEL(target_aff, 2);
594   aff3 = MPIDR_TO_AFF_LEVEL(target_aff, 3);
595   rs = MPIDR_TO_RS(target_aff);
596   val = COMPOSE_ICC_SGIR_VALUE(aff3, aff2, aff1, IRQn, 0, rs, tlist);
597 
598   __DSB();
599   __MSR(ICC_SGI1R_EL1, val);
600   __ISB();
601 }
602 
603 /** \brief Generate a software interrupt.
604 * \param [in] IRQn Software interrupt to be generated.
605 * \param [in] target_aff Target affinity in MPIDR form.
606 * \param [in] target_list List of CPUs the software interrupt should be forwarded to.
607 */
GIC_SendSGI(IRQn_Type IRQn,uint64_t target_aff,uint16_t target_list)608 __STATIC_INLINE void GIC_SendSGI(IRQn_Type IRQn, uint64_t target_aff, uint16_t target_list)
609 {
610   if (IRQn >= 16)
611     return;
612 
613   if (GIC_GetARE()) {
614     /* affinity routing */
615     GIC_SendSGI_ARE(IRQn, target_aff, target_list);
616   } else {
617     GICDistributor->SGIR = ((target_list & 0xFFUL) << 16U) | (IRQn & 0x0FUL);
618   }
619 }
620 
621 /** \brief Set the interrupt group from the GIC's IGROUPR register.
622 * \param [in] IRQn The interrupt to be queried.
623 * \param [in] group Interrupt group number: 0 - Group 0, 1 - Group 1
624 */
GIC_SetGroup(IRQn_Type IRQn,uint32_t group)625 __STATIC_INLINE void GIC_SetGroup(IRQn_Type IRQn, uint32_t group)
626 {
627   uint32_t igroupr = GICDistributor->IGROUPR[IRQn / 32U];
628   uint32_t shift   = (IRQn % 32U);
629 
630   igroupr &= (~(1U          << shift));
631   igroupr |= ( (group & 1U) << shift);
632 
633   GICDistributor->IGROUPR[IRQn / 32U] = igroupr;
634 }
635 #define GIC_SetSecurity         GIC_SetGroup
636 
GIC_SetRedistGroup(IRQn_Type IRQn,uint32_t group)637 __STATIC_INLINE void GIC_SetRedistGroup(IRQn_Type IRQn, uint32_t group)
638 {
639   GICDistributor_Type *s_RedistPPIBaseAddrs;
640   uint32_t shift   = (IRQn % 32U);
641   uint32_t igroupr;
642 
643   s_RedistPPIBaseAddrs = GIC_GetRdistSGIBase(GIC_GetRdist());
644   igroupr = s_RedistPPIBaseAddrs->IGROUPR[IRQn / 32U];
645 
646   igroupr &= (~(1U          << shift));
647   igroupr |= ( (group & 1U) << shift);
648 
649   s_RedistPPIBaseAddrs->IGROUPR[IRQn / 32U] = igroupr;
650 }
651 #define GIC_SetSecurity         GIC_SetGroup
652 
653 /** \brief Get the interrupt group from the GIC's IGROUPR register.
654 * \param [in] IRQn The interrupt to be queried.
655 * \return 0 - Group 0, 1 - Group 1
656 */
GIC_GetGroup(IRQn_Type IRQn)657 __STATIC_INLINE uint32_t GIC_GetGroup(IRQn_Type IRQn)
658 {
659   return (GICDistributor->IGROUPR[IRQn / 32U] >> (IRQn % 32U)) & 1UL;
660 }
661 #define GIC_GetSecurity         GIC_GetGroup
662 
663 /** \brief Initialize the interrupt distributor.
664 */
GIC_DistInit(void)665 __STATIC_INLINE void GIC_DistInit(void)
666 {
667   uint32_t i;
668   uint32_t num_irq = 0U;
669   uint32_t priority_field;
670   uint32_t ppi_priority;
671 
672   //A reset sets all bits in the IGROUPRs corresponding to the SPIs to 0,
673   //configuring all of the interrupts as Secure.
674 
675   //Disable interrupt forwarding
676   GIC_DisableDistributor();
677   //Get the maximum number of interrupts that the GIC supports
678   num_irq = 32U * ((GIC_DistributorInfo() & 0x1FU) + 1U);
679 
680   /* Priority level is implementation defined.
681    To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
682    priority field and read back the value stored.
683    Use PPI, as it is always accessible, even for a Guest OS using a hypervisor.
684    Then restore the initial state.*/
685   ppi_priority = GIC_GetPriority((IRQn_Type)31U);
686   GIC_SetPriority((IRQn_Type)31U, 0xFFU);
687   priority_field = GIC_GetPriority((IRQn_Type)31U);
688   GIC_SetPriority((IRQn_Type)31U, ppi_priority);
689 
690   for (i = 32U; i < num_irq; i++)
691   {
692       /* Use non secure group1 for all SPI */
693       GIC_SetGroup(i, 1);
694       //Disable the SPI interrupt
695       GIC_DisableIRQ((IRQn_Type)i);
696       //Set level-sensitive (and N-N model)
697       GIC_SetConfiguration((IRQn_Type)i, 0U);
698       //Set priority
699       GIC_SetPriority((IRQn_Type)i, priority_field*2U/3U);
700   }
701 
702   /* Enable distributor with ARE_NS and NS_Group1 */
703   GICDistributor->CTLR = ((1U << GICD_CTLR_ARE_NS) | (1U <<  GICD_CTLR_ENGRP1A));
704   GIC_WaitRWP(GICD_RWP);
705 }
706 
707 /** \brief Initialize the interrupt redistributor.
708 */
GIC_RedistInit(void)709 __STATIC_INLINE void GIC_RedistInit(void)
710 {
711   uint32_t i;
712   uint32_t priority_field;
713 
714   /* Priority level is implementation defined.
715    To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
716    priority field and read back the value stored.*/
717   GIC_SetRedistPriority((IRQn_Type)31U, 0xFFU);
718   priority_field = GIC_GetRedistPriority((IRQn_Type)31U);
719 
720   /* Wakeup the GIC */
721   GIC_RedistWakeUp();
722 
723   for (i = 0; i < 32; i++)
724   {
725       //Disable the SPI interrupt
726       GIC_DisableIRQ((IRQn_Type)i);
727       //Set priority
728       GIC_SetRedistPriority((IRQn_Type)i, priority_field*2U/3U);
729   }
730 }
731 
732 #ifdef GICInterface
733 
734 /** \brief Enable the CPU's interrupt interface.
735 */
GIC_EnableInterface(void)736 __STATIC_INLINE void GIC_EnableInterface(void)
737 {
738   GICInterface->CTLR |= 1U; //enable interface
739 }
740 
741 /** \brief Disable the CPU's interrupt interface.
742 */
GIC_DisableInterface(void)743 __STATIC_INLINE void GIC_DisableInterface(void)
744 {
745   GICInterface->CTLR &=~1U; //disable distributor
746 }
747 
748 /** \brief Read the CPU's IAR register.
749 * \return GICInterface_Type::IAR
750 */
GIC_AcknowledgePending(void)751 __STATIC_INLINE IRQn_Type GIC_AcknowledgePending(void)
752 {
753   return (IRQn_Type)(GICInterface->IAR);
754 }
755 
756 /** \brief Writes the given interrupt number to the CPU's EOIR register.
757 * \param [in] IRQn The interrupt to be signaled as finished.
758 */
GIC_EndInterrupt(IRQn_Type IRQn)759 __STATIC_INLINE void GIC_EndInterrupt(IRQn_Type IRQn)
760 {
761   GICInterface->EOIR = IRQn;
762 }
763 
764 
765 /** \brief Set the interrupt priority mask using CPU's PMR register.
766 * \param [in] priority Priority mask to be set.
767 */
GIC_SetInterfacePriorityMask(uint32_t priority)768 __STATIC_INLINE void GIC_SetInterfacePriorityMask(uint32_t priority)
769 {
770   GICInterface->PMR = priority & 0xFFUL; //set priority mask
771 }
772 
773 /** \brief Read the current interrupt priority mask from CPU's PMR register.
774 * \result GICInterface_Type::PMR
775 */
GIC_GetInterfacePriorityMask(void)776 __STATIC_INLINE uint32_t GIC_GetInterfacePriorityMask(void)
777 {
778   return GICInterface->PMR;
779 }
780 
781 /** \brief Configures the group priority and subpriority split point using CPU's BPR register.
782 * \param [in] binary_point Amount of bits used as subpriority.
783 */
GIC_SetBinaryPoint(uint32_t binary_point)784 __STATIC_INLINE void GIC_SetBinaryPoint(uint32_t binary_point)
785 {
786   GICInterface->BPR = binary_point & 7U; //set binary point
787 }
788 
789 /** \brief Read the current group priority and subpriority split point from CPU's BPR register.
790 * \return GICInterface_Type::BPR
791 */
GIC_GetBinaryPoint(void)792 __STATIC_INLINE uint32_t GIC_GetBinaryPoint(void)
793 {
794   return GICInterface->BPR;
795 }
796 
797 /** \brief Get the interrupt number of the highest interrupt pending from CPU's HPPIR register.
798 * \return GICInterface_Type::HPPIR
799 */
GIC_GetHighPendingIRQ(void)800 __STATIC_INLINE uint32_t GIC_GetHighPendingIRQ(void)
801 {
802   return GICInterface->HPPIR;
803 }
804 
805 /** \brief Provides information about the implementer and revision of the CPU interface.
806 * \return GICInterface_Type::IIDR
807 */
GIC_GetInterfaceId(void)808 __STATIC_INLINE uint32_t GIC_GetInterfaceId(void)
809 {
810   return GICInterface->IIDR;
811 }
812 
813 #else /* GICInterface */
814 
815 /** \brief Enable the CPU's interrupt interface.
816 */
GIC_EnableInterface(void)817 __STATIC_INLINE void GIC_EnableInterface(void)
818 {
819   __MSR(ICC_IGRPEN1_EL1, 1);
820 }
821 
822 /** \brief Disable the CPU's interrupt interface.
823 */
GIC_DisableInterface(void)824 __STATIC_INLINE void GIC_DisableInterface(void)
825 {
826   __MSR(ICC_IGRPEN1_EL1, 0);
827 }
828 
829 /** \brief Read the CPU's IAR register.
830 * \return GICInterface_Type::IAR
831 */
GIC_AcknowledgePending(void)832 __STATIC_INLINE IRQn_Type GIC_AcknowledgePending(void)
833 {
834   uint32_t result;
835   __MRS(ICC_IAR1_EL1, &result);
836   return (IRQn_Type)(result);
837 }
838 
839 /** \brief Writes the given interrupt number to the CPU's EOIR register.
840 * \param [in] IRQn The interrupt to be signaled as finished.
841 */
GIC_EndInterrupt(IRQn_Type IRQn)842 __STATIC_INLINE void GIC_EndInterrupt(IRQn_Type IRQn)
843 {
844   __MSR(ICC_EOIR1_EL1, (uint32_t)IRQn);
845 }
846 
847 /** \brief Set the interrupt priority mask using CPU's PMR register.
848 * \param [in] priority Priority mask to be set.
849 */
GIC_SetInterfacePriorityMask(uint32_t priority)850 __STATIC_INLINE void GIC_SetInterfacePriorityMask(uint32_t priority)
851 {
852   __MSR(ICC_PMR_EL1, priority & 0xFFUL);
853 }
854 
855 /** \brief Read the current interrupt priority mask from CPU's PMR register.
856 * \result GICInterface_Type::PMR
857 */
GIC_GetInterfacePriorityMask(void)858 __STATIC_INLINE uint32_t GIC_GetInterfacePriorityMask(void)
859 {
860   uint32_t result;
861   __MRS(ICC_PMR_EL1, &result);
862   return result;
863 }
864 
865 /** \brief Configures the group priority and subpriority split point using CPU's BPR register.
866 * \param [in] binary_point Amount of bits used as subpriority.
867 */
GIC_SetBinaryPoint(uint32_t binary_point)868 __STATIC_INLINE void GIC_SetBinaryPoint(uint32_t binary_point)
869 {
870   __MSR(ICC_BPR1_EL1, binary_point & 7U);
871 }
872 
873 /** \brief Read the current group priority and subpriority split point from CPU's BPR register.
874 * \return GICInterface_Type::BPR
875 */
GIC_GetBinaryPoint(void)876 __STATIC_INLINE uint32_t GIC_GetBinaryPoint(void)
877 {
878   uint32_t result;
879   __MRS(ICC_BPR1_EL1, &result);
880   return result;
881 }
882 
883 /** \brief Get the interrupt number of the highest interrupt pending from CPU's HPPIR register.
884 * \return GICInterface_Type::HPPIR
885 */
GIC_GetHighPendingIRQ(void)886 __STATIC_INLINE uint32_t GIC_GetHighPendingIRQ(void)
887 {
888   uint32_t result;
889   __MRS(ICC_HPPIR1_EL1, &result);
890   return result;
891 }
892 
893 #endif
894 
GIC_CPUInterfaceInit(void)895 __STATIC_INLINE void GIC_CPUInterfaceInit(void)
896 {
897   uint32_t i;
898   uint32_t priority_field;
899 
900   //A reset sets all bits in the IGROUPRs corresponding to the SPIs to 0,
901   //configuring all of the interrupts as Secure.
902 
903   //Disable interrupt forwarding
904   GIC_DisableInterface();
905 
906   /* Priority level is implementation defined.
907    To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
908    priority field and read back the value stored.*/
909   GIC_SetPriority((IRQn_Type)0U, 0xFFU);
910   priority_field = GIC_GetPriority((IRQn_Type)0U);
911 
912   //SGI and PPI
913   for (i = 0U; i < 32U; i++)
914   {
915     if (i > 15U) {
916       //Set level-sensitive (and N-N model) for PPI
917       GIC_SetConfiguration((IRQn_Type)i, 0U);
918     }
919     //Disable SGI and PPI interrupts
920     GIC_DisableIRQ((IRQn_Type)i);
921     //Set priority
922     GIC_SetPriority((IRQn_Type)i, priority_field*2U/3U);
923   }
924 
925   //Set binary point to 0
926   GIC_SetBinaryPoint(0U);
927   //Set priority mask
928   GIC_SetInterfacePriorityMask(0xFFU);
929   //Enable interface
930   GIC_EnableInterface();
931 }
932 
933 /** \brief Initialize and enable the GIC
934 */
GIC_Enable(int init_dist)935 __STATIC_INLINE void GIC_Enable(int init_dist)
936 {
937   /* Only one core should be responsible for the GIC distributor setup */
938   if (init_dist)
939     GIC_DistInit();
940 
941   GIC_RedistInit();
942   GIC_CPUInterfaceInit(); //per CPU
943 }
944 
945 #ifdef __cplusplus
946 }
947 #endif
948 
949 #endif /* __GIC_V3_H */
950