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