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>
24 * Return whether the Source interrupt index refers to a shared interrupt (SPI)
32 return Source
>= 32 && Source
< 1020;
36 * Return the base address of the GIC redistributor for the current CPU
38 * @param Revision GIC Revision. The GIC redistributor might have a different
39 * granularity following the GIC revision.
41 * @retval Base address of the associated GIC Redistributor
45 GicGetCpuRedistributorBase (
46 IN UINTN GicRedistributorBase
,
47 IN ARM_GIC_ARCH_REVISION Revision
54 UINTN GicRedistributorGranularity
;
55 UINTN GicCpuRedistributorBase
;
57 MpId
= ArmReadMpidr ();
58 // Define CPU affinity as Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
59 // whereas Affinity3 is defined at [32:39] in MPIDR
60 CpuAffinity
= (MpId
& (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
)) | ((MpId
& ARM_CORE_AFF3
) >> 8);
62 if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
63 // 2 x 64KB frame: Redistributor control frame + SGI Control & Generation frame
64 GicRedistributorGranularity
= ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_SGI_PPI_FRAME_SIZE
;
66 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
70 GicCpuRedistributorBase
= GicRedistributorBase
;
72 for (Index
= 0; Index
< PcdGet32 (PcdCoreCount
); Index
++) {
73 Affinity
= MmioRead64 (GicCpuRedistributorBase
+ ARM_GICR_TYPER
) >> 32;
74 if (Affinity
== CpuAffinity
) {
75 return GicCpuRedistributorBase
;
78 // Move to the next GIC Redistributor frame
79 GicCpuRedistributorBase
+= GicRedistributorGranularity
;
82 // The Redistributor has not been found for the current CPU
83 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
89 ArmGicGetInterfaceIdentification (
90 IN INTN GicInterruptInterfaceBase
93 // Read the GIC Identification Register
94 return MmioRead32 (GicInterruptInterfaceBase
+ ARM_GIC_ICCIIDR
);
99 ArmGicGetMaxNumInterrupts (
100 IN INTN GicDistributorBase
103 return 32 * ((MmioRead32 (GicDistributorBase
+ ARM_GIC_ICDICTR
) & 0x1F) + 1);
109 IN INTN GicDistributorBase
,
110 IN INTN TargetListFilter
,
111 IN INTN CPUTargetList
,
115 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDSGIR
, ((TargetListFilter
& 0x3) << 24) | ((CPUTargetList
& 0xFF) << 16) | SgiId
);
119 * Acknowledge and return the value of the Interrupt Acknowledge Register
121 * InterruptId is returned separately from the register value because in
122 * the GICv2 the register value contains the CpuId and InterruptId while
123 * in the GICv3 the register value is only the InterruptId.
125 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
126 * @param InterruptId InterruptId read from the Interrupt Acknowledge Register
128 * @retval value returned by the Interrupt Acknowledge Register
133 ArmGicAcknowledgeInterrupt (
134 IN UINTN GicInterruptInterfaceBase
,
135 OUT UINTN
*InterruptId
139 ARM_GIC_ARCH_REVISION Revision
;
141 Revision
= ArmGicGetSupportedArchRevision ();
142 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
143 Value
= ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase
);
144 // InterruptId is required for the caller to know if a valid or spurious
145 // interrupt has been read
146 ASSERT (InterruptId
!= NULL
);
147 if (InterruptId
!= NULL
) {
148 *InterruptId
= Value
& ARM_GIC_ICCIAR_ACKINTID
;
150 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
151 Value
= ArmGicV3AcknowledgeInterrupt ();
153 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
154 // Report Spurious interrupt which is what the above controllers would
155 // return if no interrupt was available
164 ArmGicEndOfInterrupt (
165 IN UINTN GicInterruptInterfaceBase
,
169 ARM_GIC_ARCH_REVISION Revision
;
171 Revision
= ArmGicGetSupportedArchRevision ();
172 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
173 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase
, Source
);
174 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
175 ArmGicV3EndOfInterrupt (Source
);
177 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
183 ArmGicEnableInterrupt (
184 IN UINTN GicDistributorBase
,
185 IN UINTN GicRedistributorBase
,
191 ARM_GIC_ARCH_REVISION Revision
;
192 UINTN GicCpuRedistributorBase
;
194 // Calculate enable register offset and bit position
195 RegOffset
= Source
/ 32;
196 RegShift
= Source
% 32;
198 Revision
= ArmGicGetSupportedArchRevision ();
199 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
200 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
201 SourceIsSpi (Source
)) {
202 // Write set-enable register
203 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
), 1 << RegShift
);
205 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (GicRedistributorBase
, Revision
);
206 if (GicCpuRedistributorBase
== 0) {
207 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
211 // Write set-enable register
212 MmioWrite32 (GicCpuRedistributorBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_ISENABLER
+ (4 * RegOffset
), 1 << RegShift
);
218 ArmGicDisableInterrupt (
219 IN UINTN GicDistributorBase
,
220 IN UINTN GicRedistributorBase
,
226 ARM_GIC_ARCH_REVISION Revision
;
227 UINTN GicCpuRedistributorBase
;
229 // Calculate enable register offset and bit position
230 RegOffset
= Source
/ 32;
231 RegShift
= Source
% 32;
233 Revision
= ArmGicGetSupportedArchRevision ();
234 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
235 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
236 SourceIsSpi (Source
)) {
237 // Write clear-enable register
238 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDICER
+ (4 * RegOffset
), 1 << RegShift
);
240 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (GicRedistributorBase
, Revision
);
241 if (GicCpuRedistributorBase
== 0) {
245 // Write clear-enable register
246 MmioWrite32 (GicCpuRedistributorBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_ICENABLER
+ (4 * RegOffset
), 1 << RegShift
);
252 ArmGicIsInterruptEnabled (
253 IN UINTN GicDistributorBase
,
254 IN UINTN GicRedistributorBase
,
260 ARM_GIC_ARCH_REVISION Revision
;
261 UINTN GicCpuRedistributorBase
;
264 // Calculate enable register offset and bit position
265 RegOffset
= Source
/ 32;
266 RegShift
= Source
% 32;
268 Revision
= ArmGicGetSupportedArchRevision ();
269 if ((Revision
== ARM_GIC_ARCH_REVISION_2
) ||
270 FeaturePcdGet (PcdArmGicV3WithV2Legacy
) ||
271 SourceIsSpi (Source
)) {
272 Interrupts
= ((MmioRead32 (GicDistributorBase
+ ARM_GIC_ICDISER
+ (4 * RegOffset
)) & (1 << RegShift
)) != 0);
274 GicCpuRedistributorBase
= GicGetCpuRedistributorBase (GicRedistributorBase
, Revision
);
275 if (GicCpuRedistributorBase
== 0) {
279 // Read set-enable register
280 Interrupts
= MmioRead32 (GicCpuRedistributorBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GICR_ISENABLER
+ (4 * RegOffset
));
283 return ((Interrupts
& (1 << RegShift
)) != 0);
288 ArmGicDisableDistributor (
289 IN INTN GicDistributorBase
292 // Disable Gic Distributor
293 MmioWrite32 (GicDistributorBase
+ ARM_GIC_ICDDCR
, 0x0);
298 ArmGicEnableInterruptInterface (
299 IN INTN GicInterruptInterfaceBase
302 ARM_GIC_ARCH_REVISION Revision
;
304 Revision
= ArmGicGetSupportedArchRevision ();
305 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
306 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase
);
307 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
308 ArmGicV3EnableInterruptInterface ();
310 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);
316 ArmGicDisableInterruptInterface (
317 IN INTN GicInterruptInterfaceBase
320 ARM_GIC_ARCH_REVISION Revision
;
322 Revision
= ArmGicGetSupportedArchRevision ();
323 if (Revision
== ARM_GIC_ARCH_REVISION_2
) {
324 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase
);
325 } else if (Revision
== ARM_GIC_ARCH_REVISION_3
) {
326 ArmGicV3DisableInterruptInterface ();
328 ASSERT_EFI_ERROR (EFI_UNSUPPORTED
);