3 * Copyright (c) 2011-2018, 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))
35 * Return whether the Source interrupt index refers to a shared interrupt (SPI)
43 return Source
>= 32 && Source
< 1020;
47 * Return the base address of the GIC redistributor for the current CPU
49 * @param Revision GIC Revision. The GIC redistributor might have a different
50 * granularity following the GIC revision.
52 * @retval Base address of the associated GIC Redistributor
56 GicGetCpuRedistributorBase (
57 IN UINTN GicRedistributorBase
,
58 IN ARM_GIC_ARCH_REVISION Revision
64 UINTN GicCpuRedistributorBase
;
67 MpId
= ArmReadMpidr ();
68 // Define CPU affinity as:
69 // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
70 // whereas Affinity3 is defined at [32:39] in MPIDR
71 CpuAffinity
= (MpId
& (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
)) |
72 ((MpId
& ARM_CORE_AFF3
) >> 8);
74 if (Revision
< ARM_GIC_ARCH_REVISION_3
) {
75 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
79 GicCpuRedistributorBase
= GicRedistributorBase
;
82 TypeRegister
= MmioRead64 (GicCpuRedistributorBase
+ ARM_GICR_TYPER
);
83 Affinity
= ARM_GICR_TYPER_GET_AFFINITY (TypeRegister
);
84 if (Affinity
== CpuAffinity
) {
85 return GicCpuRedistributorBase
;
88 // Move to the next GIC Redistributor frame.
89 // The GIC specification does not forbid a mixture of redistributors
90 // with or without support for virtual LPIs, so we test Virtual LPIs
91 // Support (VLPIS) bit for each frame to decide the granularity.
92 // Note: The assumption here is that the redistributors are adjacent
93 // for all CPUs. However this may not be the case for NUMA systems.
94 GicCpuRedistributorBase
+= (((ARM_GICR_TYPER_VLPIS
& TypeRegister
) != 0)
95 ? GIC_V4_REDISTRIBUTOR_GRANULARITY
96 : GIC_V3_REDISTRIBUTOR_GRANULARITY
);
97 } while ((TypeRegister
& ARM_GICR_TYPER_LAST
) == 0);
99 // The Redistributor has not been found for the current CPU
100 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
106 ArmGicGetInterfaceIdentification (
107 IN INTN GicInterruptInterfaceBase
110 // Read the GIC Identification Register
111 return MmioRead32 (GicInterruptInterfaceBase
+ ARM_GIC_ICCIIDR
);
116 ArmGicGetMaxNumInterrupts (
117 IN INTN GicDistributorBase
120 return 32 * ((MmioRead32 (GicDistributorBase
+ ARM_GIC_ICDICTR
) & 0x1F) + 1);
126 IN INTN GicDistributorBase
,
127 IN INTN TargetListFilter
,
128 IN INTN CPUTargetList
,
133 GicDistributorBase
+ ARM_GIC_ICDSGIR
,
134 ((TargetListFilter
& 0x3) << 24) | ((CPUTargetList
& 0xFF) << 16) | SgiId
139 * Acknowledge and return the value of the Interrupt Acknowledge Register
141 * InterruptId is returned separately from the register value because in
142 * the GICv2 the register value contains the CpuId and InterruptId while
143 * in the GICv3 the register value is only the InterruptId.
145 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
146 * @param InterruptId InterruptId read from the Interrupt
147 * Acknowledge Register
149 * @retval value returned by the Interrupt Acknowledge Register
154 ArmGicAcknowledgeInterrupt (
155 IN UINTN GicInterruptInterfaceBase
,
156 OUT UINTN
*InterruptId
160 ARM_GIC_ARCH_REVISION Revision
;
162 Revision
= ArmGicGetSupportedArchRevision ();
163 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
164 Value
= ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase
);
165 // InterruptId is required for the caller to know if a valid or spurious
166 // interrupt has been read
167 ASSERT (InterruptId
!= NULL
);
168 if (InterruptId
!= NULL
) {
169 *InterruptId
= Value
& ARM_GIC_ICCIAR_ACKINTID
;
171 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
172 Value
= ArmGicV3AcknowledgeInterrupt ();
174 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
175 // Report Spurious interrupt which is what the above controllers would
176 // return if no interrupt was available
185 ArmGicEndOfInterrupt (
186 IN UINTN GicInterruptInterfaceBase
,
190 ARM_GIC_ARCH_REVISION Revision
;
192 Revision
= ArmGicGetSupportedArchRevision ();
193 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
194 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase
, Source
);
195 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
196 ArmGicV3EndOfInterrupt (Source
);
198 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
204 ArmGicEnableInterrupt (
205 IN UINTN GicDistributorBase
,
206 IN UINTN GicRedistributorBase
,
212 ARM_GIC_ARCH_REVISION Revision
;
213 UINTN GicCpuRedistributorBase
;
215 // Calculate enable register offset and bit position
216 RegOffset
= Source
/ 32;
217 RegShift
= Source
% 32;
219 Revision
= ArmGicGetSupportedArchRevision ();
220 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
221 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
222 SourceIsSpi (Source
)) {
223 // Write set-enable register
225 GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
),
229 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
230 GicRedistributorBase
,
233 if (GicCpuRedistributorBase
== 0) {
234 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
238 // Write set-enable register
240 ISENABLER_ADDRESS(GicCpuRedistributorBase
, RegOffset
),
248 ArmGicDisableInterrupt (
249 IN UINTN GicDistributorBase
,
250 IN UINTN GicRedistributorBase
,
256 ARM_GIC_ARCH_REVISION Revision
;
257 UINTN GicCpuRedistributorBase
;
259 // Calculate enable register offset and bit position
260 RegOffset
= Source
/ 32;
261 RegShift
= Source
% 32;
263 Revision
= ArmGicGetSupportedArchRevision ();
264 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
265 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
266 SourceIsSpi (Source
)) {
267 // Write clear-enable register
269 GicDistributorBase
+ ARM_GIC_ICDICER
+ (4 * RegOffset
),
273 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
274 GicRedistributorBase
,
277 if (GicCpuRedistributorBase
== 0) {
281 // Write clear-enable register
283 ICENABLER_ADDRESS(GicCpuRedistributorBase
, RegOffset
),
291 ArmGicIsInterruptEnabled (
292 IN UINTN GicDistributorBase
,
293 IN UINTN GicRedistributorBase
,
299 ARM_GIC_ARCH_REVISION Revision
;
300 UINTN GicCpuRedistributorBase
;
303 // Calculate enable register offset and bit position
304 RegOffset
= Source
/ 32;
305 RegShift
= Source
% 32;
307 Revision
= ArmGicGetSupportedArchRevision ();
308 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
309 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
310 SourceIsSpi (Source
)) {
311 Interrupts
= ((MmioRead32 (
312 GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
)
314 & (1 << RegShift
)) != 0);
316 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
317 GicRedistributorBase
,
320 if (GicCpuRedistributorBase
== 0) {
324 // Read set-enable register
325 Interrupts
= MmioRead32 (
326 ISENABLER_ADDRESS(GicCpuRedistributorBase
, RegOffset
)
330 return ((Interrupts
& (1 << RegShift
)) != 0);
335 ArmGicDisableDistributor (
336 IN INTN GicDistributorBase
339 // Disable Gic Distributor
340 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDDCR
, 0x0);
345 ArmGicEnableInterruptInterface (
346 IN INTN GicInterruptInterfaceBase
349 ARM_GIC_ARCH_REVISION Revision
;
351 Revision
= ArmGicGetSupportedArchRevision ();
352 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
353 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase
);
354 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
355 ArmGicV3EnableInterruptInterface ();
357 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
363 ArmGicDisableInterruptInterface (
364 IN INTN GicInterruptInterfaceBase
367 ARM_GIC_ARCH_REVISION Revision
;
369 Revision
= ArmGicGetSupportedArchRevision ();
370 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
371 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase
);
372 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
373 ArmGicV3DisableInterruptInterface ();
375 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);