3 * Copyright (c) 2011-2017, ARM Limited. All rights reserved.
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Library/ArmGicLib.h>
17 #include <Library/ArmLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/IoLib.h>
20 #include <Library/PcdLib.h>
23 #define ISENABLER_ADDRESS(base,offset) ((base) + \
24 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * offset))
26 #define ICENABLER_ADDRESS(base,offset) ((base) + \
27 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + (4 * offset))
31 * Return whether the Source interrupt index refers to a shared interrupt (SPI)
39 return Source
>= 32 && Source
< 1020;
43 * Return the base address of the GIC redistributor for the current CPU
45 * @param Revision GIC Revision. The GIC redistributor might have a different
46 * granularity following the GIC revision.
48 * @retval Base address of the associated GIC Redistributor
52 GicGetCpuRedistributorBase (
53 IN UINTN GicRedistributorBase
,
54 IN ARM_GIC_ARCH_REVISION Revision
61 UINTN GicRedistributorGranularity
;
62 UINTN GicCpuRedistributorBase
;
64 MpId
= ArmReadMpidr ();
65 // Define CPU affinity as:
66 // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
67 // whereas Affinity3 is defined at [32:39] in MPIDR
68 CpuAffinity
= (MpId
& (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
)) |
69 ((MpId
& ARM_CORE_AFF3
) >> 8);
71 if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
73 // Redistributor control frame + SGI Control & Generation frame
74 GicRedistributorGranularity
= ARM_GICR_CTLR_FRAME_SIZE
75 + ARM_GICR_SGI_PPI_FRAME_SIZE
;
77 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
81 GicCpuRedistributorBase
= GicRedistributorBase
;
83 for (Index
= 0; Index
< PcdGet32 (PcdCoreCount
); Index
++) {
84 Affinity
= MmioRead64 (GicCpuRedistributorBase
+ ARM_GICR_TYPER
) >> 32;
85 if (Affinity
== CpuAffinity
) {
86 return GicCpuRedistributorBase
;
89 // Move to the next GIC Redistributor frame
90 GicCpuRedistributorBase
+= GicRedistributorGranularity
;
93 // The Redistributor has not been found for the current CPU
94 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
100 ArmGicGetInterfaceIdentification (
101 IN INTN GicInterruptInterfaceBase
104 // Read the GIC Identification Register
105 return MmioRead32 (GicInterruptInterfaceBase
+ ARM_GIC_ICCIIDR
);
110 ArmGicGetMaxNumInterrupts (
111 IN INTN GicDistributorBase
114 return 32 * ((MmioRead32 (GicDistributorBase
+ ARM_GIC_ICDICTR
) & 0x1F) + 1);
120 IN INTN GicDistributorBase
,
121 IN INTN TargetListFilter
,
122 IN INTN CPUTargetList
,
127 GicDistributorBase
+ ARM_GIC_ICDSGIR
,
128 ((TargetListFilter
& 0x3) << 24) | ((CPUTargetList
& 0xFF) << 16) | SgiId
133 * Acknowledge and return the value of the Interrupt Acknowledge Register
135 * InterruptId is returned separately from the register value because in
136 * the GICv2 the register value contains the CpuId and InterruptId while
137 * in the GICv3 the register value is only the InterruptId.
139 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
140 * @param InterruptId InterruptId read from the Interrupt
141 * Acknowledge Register
143 * @retval value returned by the Interrupt Acknowledge Register
148 ArmGicAcknowledgeInterrupt (
149 IN UINTN GicInterruptInterfaceBase
,
150 OUT UINTN
*InterruptId
154 ARM_GIC_ARCH_REVISION Revision
;
156 Revision
= ArmGicGetSupportedArchRevision ();
157 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
158 Value
= ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase
);
159 // InterruptId is required for the caller to know if a valid or spurious
160 // interrupt has been read
161 ASSERT (InterruptId
!= NULL
);
162 if (InterruptId
!= NULL
) {
163 *InterruptId
= Value
& ARM_GIC_ICCIAR_ACKINTID
;
165 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
166 Value
= ArmGicV3AcknowledgeInterrupt ();
168 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
169 // Report Spurious interrupt which is what the above controllers would
170 // return if no interrupt was available
179 ArmGicEndOfInterrupt (
180 IN UINTN GicInterruptInterfaceBase
,
184 ARM_GIC_ARCH_REVISION Revision
;
186 Revision
= ArmGicGetSupportedArchRevision ();
187 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
188 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase
, Source
);
189 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
190 ArmGicV3EndOfInterrupt (Source
);
192 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
198 ArmGicEnableInterrupt (
199 IN UINTN GicDistributorBase
,
200 IN UINTN GicRedistributorBase
,
206 ARM_GIC_ARCH_REVISION Revision
;
207 UINTN GicCpuRedistributorBase
;
209 // Calculate enable register offset and bit position
210 RegOffset
= Source
/ 32;
211 RegShift
= Source
% 32;
213 Revision
= ArmGicGetSupportedArchRevision ();
214 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
215 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
216 SourceIsSpi (Source
)) {
217 // Write set-enable register
219 GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
),
223 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
224 GicRedistributorBase
,
227 if (GicCpuRedistributorBase
== 0) {
228 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
232 // Write set-enable register
234 ISENABLER_ADDRESS(GicCpuRedistributorBase
, RegOffset
),
242 ArmGicDisableInterrupt (
243 IN UINTN GicDistributorBase
,
244 IN UINTN GicRedistributorBase
,
250 ARM_GIC_ARCH_REVISION Revision
;
251 UINTN GicCpuRedistributorBase
;
253 // Calculate enable register offset and bit position
254 RegOffset
= Source
/ 32;
255 RegShift
= Source
% 32;
257 Revision
= ArmGicGetSupportedArchRevision ();
258 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
259 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
260 SourceIsSpi (Source
)) {
261 // Write clear-enable register
263 GicDistributorBase
+ ARM_GIC_ICDICER
+ (4 * RegOffset
),
267 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
268 GicRedistributorBase
,
271 if (GicCpuRedistributorBase
== 0) {
275 // Write clear-enable register
277 ICENABLER_ADDRESS(GicCpuRedistributorBase
, RegOffset
),
285 ArmGicIsInterruptEnabled (
286 IN UINTN GicDistributorBase
,
287 IN UINTN GicRedistributorBase
,
293 ARM_GIC_ARCH_REVISION Revision
;
294 UINTN GicCpuRedistributorBase
;
297 // Calculate enable register offset and bit position
298 RegOffset
= Source
/ 32;
299 RegShift
= Source
% 32;
301 Revision
= ArmGicGetSupportedArchRevision ();
302 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
303 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
304 SourceIsSpi (Source
)) {
305 Interrupts
= ((MmioRead32 (
306 GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
)
308 & (1 << RegShift
)) != 0);
310 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (
311 GicRedistributorBase
,
314 if (GicCpuRedistributorBase
== 0) {
318 // Read set-enable register
319 Interrupts
= MmioRead32 (
320 ISENABLER_ADDRESS(GicCpuRedistributorBase
, RegOffset
)
324 return ((Interrupts
& (1 << RegShift
)) != 0);
329 ArmGicDisableDistributor (
330 IN INTN GicDistributorBase
333 // Disable Gic Distributor
334 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDDCR
, 0x0);
339 ArmGicEnableInterruptInterface (
340 IN INTN GicInterruptInterfaceBase
343 ARM_GIC_ARCH_REVISION Revision
;
345 Revision
= ArmGicGetSupportedArchRevision ();
346 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
347 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase
);
348 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
349 ArmGicV3EnableInterruptInterface ();
351 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
357 ArmGicDisableInterruptInterface (
358 IN INTN GicInterruptInterfaceBase
361 ARM_GIC_ARCH_REVISION Revision
;
363 Revision
= ArmGicGetSupportedArchRevision ();
364 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
365 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase
);
366 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
367 ArmGicV3DisableInterruptInterface ();
369 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);