]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/ArmGicLib.c
IntelFrameworkModulePkg/KeyboardDxe: Use macro to enable/disable page 0
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicLib.c
1 /** @file
2 *
3 * Copyright (c) 2011-2017, 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
23 #define ISENABLER_ADDRESS(base,offset) ((base) + \
24 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * offset))
25
26 #define ICENABLER_ADDRESS(base,offset) ((base) + \
27 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + (4 * offset))
28
29 /**
30 *
31 * Return whether the Source interrupt index refers to a shared interrupt (SPI)
32 */
33 STATIC
34 BOOLEAN
35 SourceIsSpi (
36 IN UINTN Source
37 )
38 {
39 return Source >= 32 && Source < 1020;
40 }
41
42 /**
43 * Return the base address of the GIC redistributor for the current CPU
44 *
45 * @param Revision GIC Revision. The GIC redistributor might have a different
46 * granularity following the GIC revision.
47 *
48 * @retval Base address of the associated GIC Redistributor
49 */
50 STATIC
51 UINTN
52 GicGetCpuRedistributorBase (
53 IN UINTN GicRedistributorBase,
54 IN ARM_GIC_ARCH_REVISION Revision
55 )
56 {
57 UINTN Index;
58 UINTN MpId;
59 UINTN CpuAffinity;
60 UINTN Affinity;
61 UINTN GicRedistributorGranularity;
62 UINTN GicCpuRedistributorBase;
63
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);
70
71 if (Revision == ARM_GIC_ARCH_REVISION_3) {
72 // 2 x 64KB frame:
73 // Redistributor control frame + SGI Control & Generation frame
74 GicRedistributorGranularity = ARM_GICR_CTLR_FRAME_SIZE
75 + ARM_GICR_SGI_PPI_FRAME_SIZE;
76 } else {
77 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
78 return 0;
79 }
80
81 GicCpuRedistributorBase = GicRedistributorBase;
82
83 for (Index = 0; Index < PcdGet32 (PcdCoreCount); Index++) {
84 Affinity = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER) >> 32;
85 if (Affinity == CpuAffinity) {
86 return GicCpuRedistributorBase;
87 }
88
89 // Move to the next GIC Redistributor frame
90 GicCpuRedistributorBase += GicRedistributorGranularity;
91 }
92
93 // The Redistributor has not been found for the current CPU
94 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
95 return 0;
96 }
97
98 UINTN
99 EFIAPI
100 ArmGicGetInterfaceIdentification (
101 IN INTN GicInterruptInterfaceBase
102 )
103 {
104 // Read the GIC Identification Register
105 return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIIDR);
106 }
107
108 UINTN
109 EFIAPI
110 ArmGicGetMaxNumInterrupts (
111 IN INTN GicDistributorBase
112 )
113 {
114 return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F) + 1);
115 }
116
117 VOID
118 EFIAPI
119 ArmGicSendSgiTo (
120 IN INTN GicDistributorBase,
121 IN INTN TargetListFilter,
122 IN INTN CPUTargetList,
123 IN INTN SgiId
124 )
125 {
126 MmioWrite32 (
127 GicDistributorBase + ARM_GIC_ICDSGIR,
128 ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId
129 );
130 }
131
132 /*
133 * Acknowledge and return the value of the Interrupt Acknowledge Register
134 *
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.
138 *
139 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
140 * @param InterruptId InterruptId read from the Interrupt
141 * Acknowledge Register
142 *
143 * @retval value returned by the Interrupt Acknowledge Register
144 *
145 */
146 UINTN
147 EFIAPI
148 ArmGicAcknowledgeInterrupt (
149 IN UINTN GicInterruptInterfaceBase,
150 OUT UINTN *InterruptId
151 )
152 {
153 UINTN Value;
154 ARM_GIC_ARCH_REVISION Revision;
155
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;
164 }
165 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
166 Value = ArmGicV3AcknowledgeInterrupt ();
167 } else {
168 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
169 // Report Spurious interrupt which is what the above controllers would
170 // return if no interrupt was available
171 Value = 1023;
172 }
173
174 return Value;
175 }
176
177 VOID
178 EFIAPI
179 ArmGicEndOfInterrupt (
180 IN UINTN GicInterruptInterfaceBase,
181 IN UINTN Source
182 )
183 {
184 ARM_GIC_ARCH_REVISION Revision;
185
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);
191 } else {
192 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
193 }
194 }
195
196 VOID
197 EFIAPI
198 ArmGicEnableInterrupt (
199 IN UINTN GicDistributorBase,
200 IN UINTN GicRedistributorBase,
201 IN UINTN Source
202 )
203 {
204 UINT32 RegOffset;
205 UINTN RegShift;
206 ARM_GIC_ARCH_REVISION Revision;
207 UINTN GicCpuRedistributorBase;
208
209 // Calculate enable register offset and bit position
210 RegOffset = Source / 32;
211 RegShift = Source % 32;
212
213 Revision = ArmGicGetSupportedArchRevision ();
214 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
215 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
216 SourceIsSpi (Source)) {
217 // Write set-enable register
218 MmioWrite32 (
219 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
220 1 << RegShift
221 );
222 } else {
223 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
224 GicRedistributorBase,
225 Revision
226 );
227 if (GicCpuRedistributorBase == 0) {
228 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
229 return;
230 }
231
232 // Write set-enable register
233 MmioWrite32 (
234 ISENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset),
235 1 << RegShift
236 );
237 }
238 }
239
240 VOID
241 EFIAPI
242 ArmGicDisableInterrupt (
243 IN UINTN GicDistributorBase,
244 IN UINTN GicRedistributorBase,
245 IN UINTN Source
246 )
247 {
248 UINT32 RegOffset;
249 UINTN RegShift;
250 ARM_GIC_ARCH_REVISION Revision;
251 UINTN GicCpuRedistributorBase;
252
253 // Calculate enable register offset and bit position
254 RegOffset = Source / 32;
255 RegShift = Source % 32;
256
257 Revision = ArmGicGetSupportedArchRevision ();
258 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
259 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
260 SourceIsSpi (Source)) {
261 // Write clear-enable register
262 MmioWrite32 (
263 GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
264 1 << RegShift
265 );
266 } else {
267 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
268 GicRedistributorBase,
269 Revision
270 );
271 if (GicCpuRedistributorBase == 0) {
272 return;
273 }
274
275 // Write clear-enable register
276 MmioWrite32 (
277 ICENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset),
278 1 << RegShift
279 );
280 }
281 }
282
283 BOOLEAN
284 EFIAPI
285 ArmGicIsInterruptEnabled (
286 IN UINTN GicDistributorBase,
287 IN UINTN GicRedistributorBase,
288 IN UINTN Source
289 )
290 {
291 UINT32 RegOffset;
292 UINTN RegShift;
293 ARM_GIC_ARCH_REVISION Revision;
294 UINTN GicCpuRedistributorBase;
295 UINT32 Interrupts;
296
297 // Calculate enable register offset and bit position
298 RegOffset = Source / 32;
299 RegShift = Source % 32;
300
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)
307 )
308 & (1 << RegShift)) != 0);
309 } else {
310 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
311 GicRedistributorBase,
312 Revision
313 );
314 if (GicCpuRedistributorBase == 0) {
315 return 0;
316 }
317
318 // Read set-enable register
319 Interrupts = MmioRead32 (
320 ISENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset)
321 );
322 }
323
324 return ((Interrupts & (1 << RegShift)) != 0);
325 }
326
327 VOID
328 EFIAPI
329 ArmGicDisableDistributor (
330 IN INTN GicDistributorBase
331 )
332 {
333 // Disable Gic Distributor
334 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);
335 }
336
337 VOID
338 EFIAPI
339 ArmGicEnableInterruptInterface (
340 IN INTN GicInterruptInterfaceBase
341 )
342 {
343 ARM_GIC_ARCH_REVISION Revision;
344
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 ();
350 } else {
351 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
352 }
353 }
354
355 VOID
356 EFIAPI
357 ArmGicDisableInterruptInterface (
358 IN INTN GicInterruptInterfaceBase
359 )
360 {
361 ARM_GIC_ARCH_REVISION Revision;
362
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 ();
368 } else {
369 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
370 }
371 }