3 * Copyright (c) 2011-2021, Arm Limited. All rights reserved.
5 * SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/ArmGicLib.h>
11 #include <Library/ArmLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/PcdLib.h>
16 // In GICv3, there are 2 x 64KB frames:
17 // Redistributor control frame + SGI Control & Generation frame
18 #define GIC_V3_REDISTRIBUTOR_GRANULARITY (ARM_GICR_CTLR_FRAME_SIZE \
19 + ARM_GICR_SGI_PPI_FRAME_SIZE)
21 // In GICv4, there are 2 additional 64KB frames:
22 // VLPI frame + Reserved page frame
23 #define GIC_V4_REDISTRIBUTOR_GRANULARITY (GIC_V3_REDISTRIBUTOR_GRANULARITY \
24 + ARM_GICR_SGI_VLPI_FRAME_SIZE \
25 + ARM_GICR_SGI_RESERVED_FRAME_SIZE)
27 #define ISENABLER_ADDRESS(base, offset) ((base) +\
28 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))
30 #define ICENABLER_ADDRESS(base, offset) ((base) +\
31 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))
33 #define IPRIORITY_ADDRESS(base, offset) ((base) +\
34 ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))
38 * Return whether the Source interrupt index refers to a shared interrupt (SPI)
46 return Source
>= 32 && Source
< 1020;
50 * Return the base address of the GIC redistributor for the current CPU
52 * @param Revision GIC Revision. The GIC redistributor might have a different
53 * granularity following the GIC revision.
55 * @retval Base address of the associated GIC Redistributor
59 GicGetCpuRedistributorBase (
60 IN UINTN GicRedistributorBase
,
61 IN ARM_GIC_ARCH_REVISION Revision
67 UINTN GicCpuRedistributorBase
;
70 MpId
= ArmReadMpidr ();
71 // Define CPU affinity as:
72 // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
73 // whereas Affinity3 is defined at [32:39] in MPIDR
74 CpuAffinity
= (MpId
& (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
)) |
75 ((MpId
& ARM_CORE_AFF3
) >> 8);
77 if (Revision
< ARM_GIC_ARCH_REVISION_3
) {
78 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
82 GicCpuRedistributorBase
= GicRedistributorBase
;
85 TypeRegister
= MmioRead64 (GicCpuRedistributorBase
+ ARM_GICR_TYPER
);
86 Affinity
= ARM_GICR_TYPER_GET_AFFINITY (TypeRegister
);
87 if (Affinity
== CpuAffinity
) {
88 return GicCpuRedistributorBase
;
91 // Move to the next GIC Redistributor frame.
92 // The GIC specification does not forbid a mixture of redistributors
93 // with or without support for virtual LPIs, so we test Virtual LPIs
94 // Support (VLPIS) bit for each frame to decide the granularity.
95 // Note: The assumption here is that the redistributors are adjacent
96 // for all CPUs. However this may not be the case for NUMA systems.
97 GicCpuRedistributorBase
+= (((ARM_GICR_TYPER_VLPIS
& TypeRegister
) != 0)
98 ? GIC_V4_REDISTRIBUTOR_GRANULARITY
99 : GIC_V3_REDISTRIBUTOR_GRANULARITY
);
100 } while ((TypeRegister
& ARM_GICR_TYPER_LAST
) == 0);
102 // The Redistributor has not been found for the current CPU
103 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
109 ArmGicGetInterfaceIdentification (
110 IN INTN GicInterruptInterfaceBase
113 // Read the GIC Identification Register
114 return MmioRead32 (GicInterruptInterfaceBase
+ ARM_GIC_ICCIIDR
);
119 ArmGicGetMaxNumInterrupts (
120 IN INTN GicDistributorBase
125 ItLines
= MmioRead32 (GicDistributorBase
+ ARM_GIC_ICDICTR
) & 0x1F;
128 // Interrupt ID 1020-1023 are reserved.
130 return (ItLines
== 0x1f) ? 1020 : 32 * (ItLines
+ 1);
136 IN INTN GicDistributorBase
,
137 IN INTN TargetListFilter
,
138 IN INTN CPUTargetList
,
143 GicDistributorBase
+ ARM_GIC_ICDSGIR
,
144 ((TargetListFilter
& 0x3) << 24) | ((CPUTargetList
& 0xFF) << 16) | SgiId
149 * Acknowledge and return the value of the Interrupt Acknowledge Register
151 * InterruptId is returned separately from the register value because in
152 * the GICv2 the register value contains the CpuId and InterruptId while
153 * in the GICv3 the register value is only the InterruptId.
155 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
156 * @param InterruptId InterruptId read from the Interrupt
157 * Acknowledge Register
159 * @retval value returned by the Interrupt Acknowledge Register
164 ArmGicAcknowledgeInterrupt (
165 IN UINTN GicInterruptInterfaceBase
,
166 OUT UINTN
*InterruptId
170 ARM_GIC_ARCH_REVISION Revision
;
172 Revision
= ArmGicGetSupportedArchRevision ();
173 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
174 Value
= ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase
);
175 // InterruptId is required for the caller to know if a valid or spurious
176 // interrupt has been read
177 ASSERT (InterruptId
!= NULL
);
178 if (InterruptId
!= NULL
) {
179 *InterruptId
= Value
& ARM_GIC_ICCIAR_ACKINTID
;
181 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
182 Value
= ArmGicV3AcknowledgeInterrupt ();
184 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
185 // Report Spurious interrupt which is what the above controllers would
186 // return if no interrupt was available
195 ArmGicEndOfInterrupt (
196 IN UINTN GicInterruptInterfaceBase
,
200 ARM_GIC_ARCH_REVISION Revision
;
202 Revision
= ArmGicGetSupportedArchRevision ();
203 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
204 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase
, Source
);
205 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
206 ArmGicV3EndOfInterrupt (Source
);
208 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
214 ArmGicSetInterruptPriority (
215 IN UINTN GicDistributorBase
,
216 IN UINTN GicRedistributorBase
,
223 ARM_GIC_ARCH_REVISION Revision
;
224 UINTN GicCpuRedistributorBase
;
226 // Calculate register offset and bit position
227 RegOffset
= Source
/ 4;
228 RegShift
= (Source
% 4) * 8;
230 Revision
= ArmGicGetSupportedArchRevision ();
231 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
232 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
233 SourceIsSpi (Source
))
236 GicDistributorBase
+ ARM_GIC_ICDIPR
+ (4 * RegOffset
),
241 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
242 GicRedistributorBase
,
245 if (GicCpuRedistributorBase
== 0) {
250 IPRIORITY_ADDRESS (GicCpuRedistributorBase
, RegOffset
),
259 ArmGicEnableInterrupt (
260 IN UINTN GicDistributorBase
,
261 IN UINTN GicRedistributorBase
,
267 ARM_GIC_ARCH_REVISION Revision
;
268 UINTN GicCpuRedistributorBase
;
270 // Calculate enable register offset and bit position
271 RegOffset
= Source
/ 32;
272 RegShift
= Source
% 32;
274 Revision
= ArmGicGetSupportedArchRevision ();
275 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
276 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
277 SourceIsSpi (Source
))
279 // Write set-enable register
281 GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
),
285 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
286 GicRedistributorBase
,
289 if (GicCpuRedistributorBase
== 0) {
290 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
294 // Write set-enable register
296 ISENABLER_ADDRESS (GicCpuRedistributorBase
, RegOffset
),
304 ArmGicDisableInterrupt (
305 IN UINTN GicDistributorBase
,
306 IN UINTN GicRedistributorBase
,
312 ARM_GIC_ARCH_REVISION Revision
;
313 UINTN GicCpuRedistributorBase
;
315 // Calculate enable register offset and bit position
316 RegOffset
= Source
/ 32;
317 RegShift
= Source
% 32;
319 Revision
= ArmGicGetSupportedArchRevision ();
320 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
321 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
322 SourceIsSpi (Source
))
324 // Write clear-enable register
326 GicDistributorBase
+ ARM_GIC_ICDICER
+ (4 * RegOffset
),
330 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
331 GicRedistributorBase
,
334 if (GicCpuRedistributorBase
== 0) {
338 // Write clear-enable register
340 ICENABLER_ADDRESS (GicCpuRedistributorBase
, RegOffset
),
348 ArmGicIsInterruptEnabled (
349 IN UINTN GicDistributorBase
,
350 IN UINTN GicRedistributorBase
,
356 ARM_GIC_ARCH_REVISION Revision
;
357 UINTN GicCpuRedistributorBase
;
360 // Calculate enable register offset and bit position
361 RegOffset
= Source
/ 32;
362 RegShift
= Source
% 32;
364 Revision
= ArmGicGetSupportedArchRevision ();
365 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
366 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
367 SourceIsSpi (Source
))
369 Interrupts
= MmioRead32 (
370 GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
)
373 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
374 GicRedistributorBase
,
377 if (GicCpuRedistributorBase
== 0) {
381 // Read set-enable register
382 Interrupts
= MmioRead32 (
383 ISENABLER_ADDRESS (GicCpuRedistributorBase
, RegOffset
)
387 return ((Interrupts
& (1 << RegShift
)) != 0);
392 ArmGicDisableDistributor (
393 IN INTN GicDistributorBase
396 // Disable Gic Distributor
397 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDDCR
, 0x0);
402 ArmGicEnableInterruptInterface (
403 IN INTN GicInterruptInterfaceBase
406 ARM_GIC_ARCH_REVISION Revision
;
408 Revision
= ArmGicGetSupportedArchRevision ();
409 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
410 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase
);
411 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
412 ArmGicV3EnableInterruptInterface ();
414 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
420 ArmGicDisableInterruptInterface (
421 IN INTN GicInterruptInterfaceBase
424 ARM_GIC_ARCH_REVISION Revision
;
426 Revision
= ArmGicGetSupportedArchRevision ();
427 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
428 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase
);
429 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
430 ArmGicV3DisableInterruptInterface ();
432 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);