]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/ArmGicLib.c
ArmPkg/ArmGic: enable ARE bit before driving GICv3 in native mode
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicLib.c
1 /** @file
2 *
3 * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
4 *
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
9 *
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.
12 *
13 **/
14
15 #include <Base.h>
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>
21
22 #include "GicV2/ArmGicV2Lib.h"
23 #include "GicV3/ArmGicV3Lib.h"
24
25 /**
26 * Return the base address of the GIC redistributor for the current CPU
27 *
28 * @param Revision GIC Revision. The GIC redistributor might have a different
29 * granularity following the GIC revision.
30 *
31 * @retval Base address of the associated GIC Redistributor
32 */
33 STATIC
34 UINTN
35 GicGetCpuRedistributorBase (
36 IN UINTN GicRedistributorBase,
37 IN ARM_GIC_ARCH_REVISION Revision
38 )
39 {
40 UINTN Index;
41 UINTN MpId;
42 UINTN CpuAffinity;
43 UINTN Affinity;
44 UINTN GicRedistributorGranularity;
45 UINTN GicCpuRedistributorBase;
46
47 MpId = ArmReadMpidr ();
48 // Define CPU affinity as Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
49 // whereas Affinity3 is defined at [32:39] in MPIDR
50 CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) | ((MpId & ARM_CORE_AFF3) >> 8);
51
52 if (Revision == ARM_GIC_ARCH_REVISION_3) {
53 // 2 x 64KB frame: Redistributor control frame + SGI Control & Generation frame
54 GicRedistributorGranularity = ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_SGI_PPI_FRAME_SIZE;
55 } else {
56 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
57 return 0;
58 }
59
60 GicCpuRedistributorBase = GicRedistributorBase;
61
62 for (Index = 0; Index < PcdGet32 (PcdCoreCount); Index++) {
63 Affinity = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER) >> 32;
64 if (Affinity == CpuAffinity) {
65 return GicCpuRedistributorBase;
66 }
67
68 // Move to the next GIC Redistributor frame
69 GicRedistributorBase += GicRedistributorGranularity;
70 }
71
72 // The Redistributor has not been found for the current CPU
73 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
74 return 0;
75 }
76
77 UINTN
78 EFIAPI
79 ArmGicGetInterfaceIdentification (
80 IN INTN GicInterruptInterfaceBase
81 )
82 {
83 // Read the GIC Identification Register
84 return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIIDR);
85 }
86
87 UINTN
88 EFIAPI
89 ArmGicGetMaxNumInterrupts (
90 IN INTN GicDistributorBase
91 )
92 {
93 return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F) + 1);
94 }
95
96 VOID
97 EFIAPI
98 ArmGicSendSgiTo (
99 IN INTN GicDistributorBase,
100 IN INTN TargetListFilter,
101 IN INTN CPUTargetList,
102 IN INTN SgiId
103 )
104 {
105 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDSGIR, ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId);
106 }
107
108 /*
109 * Acknowledge and return the value of the Interrupt Acknowledge Register
110 *
111 * InterruptId is returned separately from the register value because in
112 * the GICv2 the register value contains the CpuId and InterruptId while
113 * in the GICv3 the register value is only the InterruptId.
114 *
115 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
116 * @param InterruptId InterruptId read from the Interrupt Acknowledge Register
117 *
118 * @retval value returned by the Interrupt Acknowledge Register
119 *
120 */
121 UINTN
122 EFIAPI
123 ArmGicAcknowledgeInterrupt (
124 IN UINTN GicInterruptInterfaceBase,
125 OUT UINTN *InterruptId
126 )
127 {
128 UINTN Value;
129 ARM_GIC_ARCH_REVISION Revision;
130
131 Revision = ArmGicGetSupportedArchRevision ();
132 if (Revision == ARM_GIC_ARCH_REVISION_2) {
133 Value = ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase);
134 // InterruptId is required for the caller to know if a valid or spurious
135 // interrupt has been read
136 ASSERT (InterruptId != NULL);
137 if (InterruptId != NULL) {
138 *InterruptId = Value & ARM_GIC_ICCIAR_ACKINTID;
139 }
140 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
141 Value = ArmGicV3AcknowledgeInterrupt ();
142 } else {
143 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
144 // Report Spurious interrupt which is what the above controllers would
145 // return if no interrupt was available
146 Value = 1023;
147 }
148
149 return Value;
150 }
151
152 VOID
153 EFIAPI
154 ArmGicEndOfInterrupt (
155 IN UINTN GicInterruptInterfaceBase,
156 IN UINTN Source
157 )
158 {
159 ARM_GIC_ARCH_REVISION Revision;
160
161 Revision = ArmGicGetSupportedArchRevision ();
162 if (Revision == ARM_GIC_ARCH_REVISION_2) {
163 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase, Source);
164 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
165 ArmGicV3EndOfInterrupt (Source);
166 } else {
167 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
168 }
169 }
170
171 VOID
172 EFIAPI
173 ArmGicEnableInterrupt (
174 IN UINTN GicDistributorBase,
175 IN UINTN GicRedistributorBase,
176 IN UINTN Source
177 )
178 {
179 UINT32 RegOffset;
180 UINTN RegShift;
181 ARM_GIC_ARCH_REVISION Revision;
182 UINTN GicCpuRedistributorBase;
183
184 // Calculate enable register offset and bit position
185 RegOffset = Source / 32;
186 RegShift = Source % 32;
187
188 Revision = ArmGicGetSupportedArchRevision ();
189 if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
190 // Write set-enable register
191 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset), 1 << RegShift);
192 } else {
193 GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision);
194 if (GicCpuRedistributorBase == 0) {
195 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
196 return;
197 }
198
199 // Write set-enable register
200 MmioWrite32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * RegOffset), 1 << RegShift);
201 }
202 }
203
204 VOID
205 EFIAPI
206 ArmGicDisableInterrupt (
207 IN UINTN GicDistributorBase,
208 IN UINTN GicRedistributorBase,
209 IN UINTN Source
210 )
211 {
212 UINT32 RegOffset;
213 UINTN RegShift;
214 ARM_GIC_ARCH_REVISION Revision;
215 UINTN GicCpuRedistributorBase;
216
217 // Calculate enable register offset and bit position
218 RegOffset = Source / 32;
219 RegShift = Source % 32;
220
221 Revision = ArmGicGetSupportedArchRevision ();
222 if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
223 // Write clear-enable register
224 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset), 1 << RegShift);
225 } else {
226 GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision);
227 if (GicCpuRedistributorBase == 0) {
228 return;
229 }
230
231 // Write clear-enable register
232 MmioWrite32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + (4 * RegOffset), 1 << RegShift);
233 }
234 }
235
236 BOOLEAN
237 EFIAPI
238 ArmGicIsInterruptEnabled (
239 IN UINTN GicDistributorBase,
240 IN UINTN GicRedistributorBase,
241 IN UINTN Source
242 )
243 {
244 UINT32 RegOffset;
245 UINTN RegShift;
246 ARM_GIC_ARCH_REVISION Revision;
247 UINTN GicCpuRedistributorBase;
248 UINT32 Interrupts;
249
250 // Calculate enable register offset and bit position
251 RegOffset = Source / 32;
252 RegShift = Source % 32;
253
254 Revision = ArmGicGetSupportedArchRevision ();
255 if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
256 Interrupts = ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)) & (1 << RegShift)) != 0);
257 } else {
258 GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision);
259 if (GicCpuRedistributorBase == 0) {
260 return 0;
261 }
262
263 // Read set-enable register
264 Interrupts = MmioRead32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * RegOffset));
265 }
266
267 return ((Interrupts & (1 << RegShift)) != 0);
268 }
269
270 VOID
271 EFIAPI
272 ArmGicDisableDistributor (
273 IN INTN GicDistributorBase
274 )
275 {
276 // Disable Gic Distributor
277 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);
278 }
279
280 VOID
281 EFIAPI
282 ArmGicEnableInterruptInterface (
283 IN INTN GicInterruptInterfaceBase
284 )
285 {
286 ARM_GIC_ARCH_REVISION Revision;
287
288 Revision = ArmGicGetSupportedArchRevision ();
289 if (Revision == ARM_GIC_ARCH_REVISION_2) {
290 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase);
291 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
292 ArmGicV3EnableInterruptInterface ();
293 } else {
294 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
295 }
296 }
297
298 VOID
299 EFIAPI
300 ArmGicDisableInterruptInterface (
301 IN INTN GicInterruptInterfaceBase
302 )
303 {
304 ARM_GIC_ARCH_REVISION Revision;
305
306 Revision = ArmGicGetSupportedArchRevision ();
307 if (Revision == ARM_GIC_ARCH_REVISION_2) {
308 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase);
309 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
310 ArmGicV3DisableInterruptInterface ();
311 } else {
312 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
313 }
314 }