3 * Copyright (c) 2011-2015, 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 * Return the base address of the GIC redistributor for the current CPU
25 * @param Revision GIC Revision. The GIC redistributor might have a different
26 * granularity following the GIC revision.
28 * @retval Base address of the associated GIC Redistributor
32 GicGetCpuRedistributorBase (
33 IN UINTN GicRedistributorBase
,
34 IN ARM_GIC_ARCH_REVISION Revision
41 UINTN GicRedistributorGranularity
;
42 UINTN GicCpuRedistributorBase
;
44 MpId
= ArmReadMpidr ();
45 // Define CPU affinity as Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
46 // whereas Affinity3 is defined at [32:39] in MPIDR
47 CpuAffinity
= (MpId
& (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
)) | ((MpId
& ARM_CORE_AFF3
) >> 8);
49 if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
50 // 2 x 64KB frame: Redistributor control frame + SGI Control & Generation frame
51 GicRedistributorGranularity
= ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_SGI_PPI_FRAME_SIZE
;
53 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
57 GicCpuRedistributorBase
= GicRedistributorBase
;
59 for (Index
= 0; Index
< PcdGet32 (PcdCoreCount
); Index
++) {
60 Affinity
= MmioRead64 (GicCpuRedistributorBase
+ ARM_GICR_TYPER
) >> 32;
61 if (Affinity
== CpuAffinity
) {
62 return GicCpuRedistributorBase
;
65 // Move to the next GIC Redistributor frame
66 GicRedistributorBase
+= GicRedistributorGranularity
;
69 // The Redistributor has not been found for the current CPU
70 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
76 ArmGicGetInterfaceIdentification (
77 IN INTN GicInterruptInterfaceBase
80 // Read the GIC Identification Register
81 return MmioRead32 (GicInterruptInterfaceBase
+ ARM_GIC_ICCIIDR
);
86 ArmGicGetMaxNumInterrupts (
87 IN INTN GicDistributorBase
90 return 32 * ((MmioRead32 (GicDistributorBase
+ ARM_GIC_ICDICTR
) & 0x1F) + 1);
96 IN INTN GicDistributorBase
,
97 IN INTN TargetListFilter
,
98 IN INTN CPUTargetList
,
102 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDSGIR
, ((TargetListFilter
& 0x3) << 24) | ((CPUTargetList
& 0xFF) << 16) | SgiId
);
106 * Acknowledge and return the value of the Interrupt Acknowledge Register
108 * InterruptId is returned separately from the register value because in
109 * the GICv2 the register value contains the CpuId and InterruptId while
110 * in the GICv3 the register value is only the InterruptId.
112 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
113 * @param InterruptId InterruptId read from the Interrupt Acknowledge Register
115 * @retval value returned by the Interrupt Acknowledge Register
120 ArmGicAcknowledgeInterrupt (
121 IN UINTN GicInterruptInterfaceBase
,
122 OUT UINTN
*InterruptId
126 ARM_GIC_ARCH_REVISION Revision
;
128 Revision
= ArmGicGetSupportedArchRevision ();
129 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
130 Value
= ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase
);
131 // InterruptId is required for the caller to know if a valid or spurious
132 // interrupt has been read
133 ASSERT (InterruptId
!= NULL
);
134 if (InterruptId
!= NULL
) {
135 *InterruptId
= Value
& ARM_GIC_ICCIAR_ACKINTID
;
137 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
138 Value
= ArmGicV3AcknowledgeInterrupt ();
140 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
141 // Report Spurious interrupt which is what the above controllers would
142 // return if no interrupt was available
151 ArmGicEndOfInterrupt (
152 IN UINTN GicInterruptInterfaceBase
,
156 ARM_GIC_ARCH_REVISION Revision
;
158 Revision
= ArmGicGetSupportedArchRevision ();
159 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
160 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase
, Source
);
161 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
162 ArmGicV3EndOfInterrupt (Source
);
164 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
170 ArmGicEnableInterrupt (
171 IN UINTN GicDistributorBase
,
172 IN UINTN GicRedistributorBase
,
178 ARM_GIC_ARCH_REVISION Revision
;
179 UINTN GicCpuRedistributorBase
;
181 // Calculate enable register offset and bit position
182 RegOffset
= Source
/ 32;
183 RegShift
= Source
% 32;
185 Revision
= ArmGicGetSupportedArchRevision ();
186 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) || FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
187 // Write set-enable register
188 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
), 1 << RegShift
);
190 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (GicRedistributorBase
, Revision
);
191 if (GicCpuRedistributorBase
== 0) {
192 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
196 // Write set-enable register
197 MmioWrite32 (GicCpuRedistributorBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_ISENABLER
+ (4 * RegOffset
), 1 << RegShift
);
203 ArmGicDisableInterrupt (
204 IN UINTN GicDistributorBase
,
205 IN UINTN GicRedistributorBase
,
211 ARM_GIC_ARCH_REVISION Revision
;
212 UINTN GicCpuRedistributorBase
;
214 // Calculate enable register offset and bit position
215 RegOffset
= Source
/ 32;
216 RegShift
= Source
% 32;
218 Revision
= ArmGicGetSupportedArchRevision ();
219 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) || FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
220 // Write clear-enable register
221 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDICER
+ (4 * RegOffset
), 1 << RegShift
);
223 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (GicRedistributorBase
, Revision
);
224 if (GicCpuRedistributorBase
== 0) {
228 // Write clear-enable register
229 MmioWrite32 (GicCpuRedistributorBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_ICENABLER
+ (4 * RegOffset
), 1 << RegShift
);
235 ArmGicIsInterruptEnabled (
236 IN UINTN GicDistributorBase
,
237 IN UINTN GicRedistributorBase
,
243 ARM_GIC_ARCH_REVISION Revision
;
244 UINTN GicCpuRedistributorBase
;
247 // Calculate enable register offset and bit position
248 RegOffset
= Source
/ 32;
249 RegShift
= Source
% 32;
251 Revision
= ArmGicGetSupportedArchRevision ();
252 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) || FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
253 Interrupts
= ((MmioRead32 (GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
)) & (1 << RegShift
)) != 0);
255 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (GicRedistributorBase
, Revision
);
256 if (GicCpuRedistributorBase
== 0) {
260 // Read set-enable register
261 Interrupts
= MmioRead32 (GicCpuRedistributorBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_ISENABLER
+ (4 * RegOffset
));
264 return ((Interrupts
& (1 << RegShift
)) != 0);
269 ArmGicDisableDistributor (
270 IN INTN GicDistributorBase
273 // Disable Gic Distributor
274 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDDCR
, 0x0);
279 ArmGicEnableInterruptInterface (
280 IN INTN GicInterruptInterfaceBase
283 ARM_GIC_ARCH_REVISION Revision
;
285 Revision
= ArmGicGetSupportedArchRevision ();
286 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
287 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase
);
288 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
289 ArmGicV3EnableInterruptInterface ();
291 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
297 ArmGicDisableInterruptInterface (
298 IN INTN GicInterruptInterfaceBase
301 ARM_GIC_ARCH_REVISION Revision
;
303 Revision
= ArmGicGetSupportedArchRevision ();
304 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
305 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase
);
306 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
307 ArmGicV3DisableInterruptInterface ();
309 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);