]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmGic/ArmGicLib.c
MdeModulePkg/VariableLock: downgrade compatibility warnings to DEBUG_WARN
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicLib.c
CommitLineData
397bdc99
OM
1/** @file\r
2*\r
301402fa 3* Copyright (c) 2011-2018, ARM Limited. All rights reserved.\r
397bdc99 4*\r
4059386c 5* SPDX-License-Identifier: BSD-2-Clause-Patent\r
397bdc99
OM
6*\r
7**/\r
8\r
60775c51 9#include <Base.h>\r
397bdc99 10#include <Library/ArmGicLib.h>\r
8705cb38 11#include <Library/ArmLib.h>\r
1b0ac0de 12#include <Library/DebugLib.h>\r
60775c51 13#include <Library/IoLib.h>\r
8705cb38 14#include <Library/PcdLib.h>\r
397bdc99 15\r
301402fa
SM
16// In GICv3, there are 2 x 64KB frames:\r
17// Redistributor control frame + SGI Control & Generation frame\r
18#define GIC_V3_REDISTRIBUTOR_GRANULARITY (ARM_GICR_CTLR_FRAME_SIZE \\r
19 + ARM_GICR_SGI_PPI_FRAME_SIZE)\r
20\r
21// In GICv4, there are 2 additional 64KB frames:\r
22// VLPI frame + Reserved page frame\r
23#define GIC_V4_REDISTRIBUTOR_GRANULARITY (GIC_V3_REDISTRIBUTOR_GRANULARITY \\r
24 + ARM_GICR_SGI_VLPI_FRAME_SIZE \\r
25 + ARM_GICR_SGI_RESERVED_FRAME_SIZE)\r
b0393756
EL
26\r
27#define ISENABLER_ADDRESS(base,offset) ((base) + \\r
f7ee9e92 28 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))\r
b0393756
EL
29\r
30#define ICENABLER_ADDRESS(base,offset) ((base) + \\r
f7ee9e92 31 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))\r
b0393756 32\r
0996a788
MH
33#define IPRIORITY_ADDRESS(base,offset) ((base) + \\r
34 ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))\r
35\r
28f8d28f
AB
36/**\r
37 *\r
38 * Return whether the Source interrupt index refers to a shared interrupt (SPI)\r
39 */\r
40STATIC\r
41BOOLEAN\r
42SourceIsSpi (\r
43 IN UINTN Source\r
44 )\r
45{\r
46 return Source >= 32 && Source < 1020;\r
47}\r
48\r
8705cb38
OM
49/**\r
50 * Return the base address of the GIC redistributor for the current CPU\r
51 *\r
52 * @param Revision GIC Revision. The GIC redistributor might have a different\r
53 * granularity following the GIC revision.\r
54 *\r
55 * @retval Base address of the associated GIC Redistributor\r
56 */\r
57STATIC\r
58UINTN\r
59GicGetCpuRedistributorBase (\r
60 IN UINTN GicRedistributorBase,\r
61 IN ARM_GIC_ARCH_REVISION Revision\r
62 )\r
63{\r
8705cb38
OM
64 UINTN MpId;\r
65 UINTN CpuAffinity;\r
66 UINTN Affinity;\r
8705cb38 67 UINTN GicCpuRedistributorBase;\r
301402fa 68 UINT64 TypeRegister;\r
8705cb38
OM
69\r
70 MpId = ArmReadMpidr ();\r
b0393756
EL
71 // Define CPU affinity as:\r
72 // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]\r
8705cb38 73 // whereas Affinity3 is defined at [32:39] in MPIDR\r
b0393756
EL
74 CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) |\r
75 ((MpId & ARM_CORE_AFF3) >> 8);\r
8705cb38 76\r
301402fa 77 if (Revision < ARM_GIC_ARCH_REVISION_3) {\r
8705cb38
OM
78 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
79 return 0;\r
80 }\r
81\r
82 GicCpuRedistributorBase = GicRedistributorBase;\r
83\r
301402fa
SM
84 do {\r
85 TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);\r
86 Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);\r
8705cb38
OM
87 if (Affinity == CpuAffinity) {\r
88 return GicCpuRedistributorBase;\r
89 }\r
90\r
301402fa
SM
91 // Move to the next GIC Redistributor frame.\r
92 // The GIC specification does not forbid a mixture of redistributors\r
93 // with or without support for virtual LPIs, so we test Virtual LPIs\r
94 // Support (VLPIS) bit for each frame to decide the granularity.\r
95 // Note: The assumption here is that the redistributors are adjacent\r
96 // for all CPUs. However this may not be the case for NUMA systems.\r
97 GicCpuRedistributorBase += (((ARM_GICR_TYPER_VLPIS & TypeRegister) != 0)\r
98 ? GIC_V4_REDISTRIBUTOR_GRANULARITY\r
99 : GIC_V3_REDISTRIBUTOR_GRANULARITY);\r
100 } while ((TypeRegister & ARM_GICR_TYPER_LAST) == 0);\r
8705cb38
OM
101\r
102 // The Redistributor has not been found for the current CPU\r
103 ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
104 return 0;\r
105}\r
106\r
397bdc99
OM
107UINTN\r
108EFIAPI\r
109ArmGicGetInterfaceIdentification (\r
110 IN INTN GicInterruptInterfaceBase\r
111 )\r
112{\r
113 // Read the GIC Identification Register\r
114 return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIIDR);\r
115}\r
116\r
117UINTN\r
118EFIAPI\r
119ArmGicGetMaxNumInterrupts (\r
120 IN INTN GicDistributorBase\r
121 )\r
122{\r
123 return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F) + 1);\r
124}\r
125\r
126VOID\r
127EFIAPI\r
128ArmGicSendSgiTo (\r
129 IN INTN GicDistributorBase,\r
130 IN INTN TargetListFilter,\r
131 IN INTN CPUTargetList,\r
132 IN INTN SgiId\r
133 )\r
134{\r
b0393756
EL
135 MmioWrite32 (\r
136 GicDistributorBase + ARM_GIC_ICDSGIR,\r
137 ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId\r
138 );\r
397bdc99
OM
139}\r
140\r
1b0ac0de
OM
141/*\r
142 * Acknowledge and return the value of the Interrupt Acknowledge Register\r
143 *\r
144 * InterruptId is returned separately from the register value because in\r
145 * the GICv2 the register value contains the CpuId and InterruptId while\r
146 * in the GICv3 the register value is only the InterruptId.\r
147 *\r
148 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface\r
b0393756
EL
149 * @param InterruptId InterruptId read from the Interrupt\r
150 * Acknowledge Register\r
1b0ac0de
OM
151 *\r
152 * @retval value returned by the Interrupt Acknowledge Register\r
153 *\r
154 */\r
397bdc99
OM
155UINTN\r
156EFIAPI\r
157ArmGicAcknowledgeInterrupt (\r
1b0ac0de
OM
158 IN UINTN GicInterruptInterfaceBase,\r
159 OUT UINTN *InterruptId\r
397bdc99
OM
160 )\r
161{\r
1b0ac0de 162 UINTN Value;\r
d5c6b7fc
OM
163 ARM_GIC_ARCH_REVISION Revision;\r
164\r
165 Revision = ArmGicGetSupportedArchRevision ();\r
166 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
167 Value = ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase);\r
168 // InterruptId is required for the caller to know if a valid or spurious\r
169 // interrupt has been read\r
170 ASSERT (InterruptId != NULL);\r
171 if (InterruptId != NULL) {\r
172 *InterruptId = Value & ARM_GIC_ICCIAR_ACKINTID;\r
173 }\r
d7133859
OM
174 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
175 Value = ArmGicV3AcknowledgeInterrupt ();\r
d5c6b7fc
OM
176 } else {\r
177 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
178 // Report Spurious interrupt which is what the above controllers would\r
179 // return if no interrupt was available\r
180 Value = 1023;\r
1b0ac0de
OM
181 }\r
182\r
183 return Value;\r
397bdc99
OM
184}\r
185\r
186VOID\r
187EFIAPI\r
188ArmGicEndOfInterrupt (\r
189 IN UINTN GicInterruptInterfaceBase,\r
190 IN UINTN Source\r
191 )\r
192{\r
d5c6b7fc
OM
193 ARM_GIC_ARCH_REVISION Revision;\r
194\r
195 Revision = ArmGicGetSupportedArchRevision ();\r
196 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
197 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase, Source);\r
d7133859
OM
198 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
199 ArmGicV3EndOfInterrupt (Source);\r
d5c6b7fc
OM
200 } else {\r
201 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
202 }\r
397bdc99
OM
203}\r
204\r
0d49b82e
QN
205VOID\r
206EFIAPI\r
207ArmGicSetInterruptPriority (\r
208 IN UINTN GicDistributorBase,\r
209 IN UINTN GicRedistributorBase,\r
210 IN UINTN Source,\r
211 IN UINTN Priority\r
212 )\r
213{\r
214 UINT32 RegOffset;\r
215 UINTN RegShift;\r
216 ARM_GIC_ARCH_REVISION Revision;\r
217 UINTN GicCpuRedistributorBase;\r
218\r
219 // Calculate register offset and bit position\r
220 RegOffset = Source / 4;\r
221 RegShift = (Source % 4) * 8;\r
222\r
223 Revision = ArmGicGetSupportedArchRevision ();\r
224 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
225 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
226 SourceIsSpi (Source)) {\r
227 MmioAndThenOr32 (\r
228 GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),\r
229 ~(0xff << RegShift),\r
230 Priority << RegShift\r
231 );\r
232 } else {\r
233 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
234 GicRedistributorBase,\r
235 Revision\r
236 );\r
237 if (GicCpuRedistributorBase == 0) {\r
238 return;\r
239 }\r
240\r
241 MmioAndThenOr32 (\r
0996a788 242 IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),\r
0d49b82e
QN
243 ~(0xff << RegShift),\r
244 Priority << RegShift\r
245 );\r
246 }\r
247}\r
248\r
397bdc99
OM
249VOID\r
250EFIAPI\r
251ArmGicEnableInterrupt (\r
252 IN UINTN GicDistributorBase,\r
41fb5d46 253 IN UINTN GicRedistributorBase,\r
397bdc99
OM
254 IN UINTN Source\r
255 )\r
256{\r
41fb5d46
OM
257 UINT32 RegOffset;\r
258 UINTN RegShift;\r
259 ARM_GIC_ARCH_REVISION Revision;\r
260 UINTN GicCpuRedistributorBase;\r
397bdc99
OM
261\r
262 // Calculate enable register offset and bit position\r
263 RegOffset = Source / 32;\r
264 RegShift = Source % 32;\r
265\r
41fb5d46 266 Revision = ArmGicGetSupportedArchRevision ();\r
28f8d28f
AB
267 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
268 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
269 SourceIsSpi (Source)) {\r
41fb5d46 270 // Write set-enable register\r
b0393756
EL
271 MmioWrite32 (\r
272 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),\r
273 1 << RegShift\r
274 );\r
41fb5d46 275 } else {\r
b0393756
EL
276 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
277 GicRedistributorBase,\r
278 Revision\r
279 );\r
41fb5d46
OM
280 if (GicCpuRedistributorBase == 0) {\r
281 ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
282 return;\r
283 }\r
284\r
285 // Write set-enable register\r
b0393756
EL
286 MmioWrite32 (\r
287 ISENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset),\r
288 1 << RegShift\r
289 );\r
41fb5d46 290 }\r
397bdc99
OM
291}\r
292\r
293VOID\r
294EFIAPI\r
295ArmGicDisableInterrupt (\r
296 IN UINTN GicDistributorBase,\r
41fb5d46 297 IN UINTN GicRedistributorBase,\r
397bdc99
OM
298 IN UINTN Source\r
299 )\r
300{\r
41fb5d46
OM
301 UINT32 RegOffset;\r
302 UINTN RegShift;\r
303 ARM_GIC_ARCH_REVISION Revision;\r
304 UINTN GicCpuRedistributorBase;\r
397bdc99
OM
305\r
306 // Calculate enable register offset and bit position\r
307 RegOffset = Source / 32;\r
308 RegShift = Source % 32;\r
309\r
41fb5d46 310 Revision = ArmGicGetSupportedArchRevision ();\r
28f8d28f
AB
311 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
312 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
313 SourceIsSpi (Source)) {\r
41fb5d46 314 // Write clear-enable register\r
b0393756
EL
315 MmioWrite32 (\r
316 GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),\r
317 1 << RegShift\r
318 );\r
41fb5d46 319 } else {\r
b0393756
EL
320 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
321 GicRedistributorBase,\r
322 Revision\r
323 );\r
41fb5d46
OM
324 if (GicCpuRedistributorBase == 0) {\r
325 return;\r
326 }\r
327\r
328 // Write clear-enable register\r
b0393756
EL
329 MmioWrite32 (\r
330 ICENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset),\r
331 1 << RegShift\r
332 );\r
41fb5d46 333 }\r
397bdc99
OM
334}\r
335\r
336BOOLEAN\r
337EFIAPI\r
338ArmGicIsInterruptEnabled (\r
339 IN UINTN GicDistributorBase,\r
41fb5d46 340 IN UINTN GicRedistributorBase,\r
397bdc99
OM
341 IN UINTN Source\r
342 )\r
343{\r
41fb5d46
OM
344 UINT32 RegOffset;\r
345 UINTN RegShift;\r
346 ARM_GIC_ARCH_REVISION Revision;\r
347 UINTN GicCpuRedistributorBase;\r
348 UINT32 Interrupts;\r
397bdc99
OM
349\r
350 // Calculate enable register offset and bit position\r
351 RegOffset = Source / 32;\r
352 RegShift = Source % 32;\r
353\r
41fb5d46 354 Revision = ArmGicGetSupportedArchRevision ();\r
28f8d28f
AB
355 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
356 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
357 SourceIsSpi (Source)) {\r
b0393756
EL
358 Interrupts = ((MmioRead32 (\r
359 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)\r
360 )\r
361 & (1 << RegShift)) != 0);\r
41fb5d46 362 } else {\r
b0393756
EL
363 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
364 GicRedistributorBase,\r
365 Revision\r
366 );\r
41fb5d46
OM
367 if (GicCpuRedistributorBase == 0) {\r
368 return 0;\r
369 }\r
370\r
371 // Read set-enable register\r
b0393756
EL
372 Interrupts = MmioRead32 (\r
373 ISENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset)\r
374 );\r
41fb5d46
OM
375 }\r
376\r
377 return ((Interrupts & (1 << RegShift)) != 0);\r
397bdc99 378}\r
60775c51
OM
379\r
380VOID\r
381EFIAPI\r
382ArmGicDisableDistributor (\r
383 IN INTN GicDistributorBase\r
384 )\r
385{\r
386 // Disable Gic Distributor\r
387 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);\r
388}\r
62d441fb 389\r
793ca69f
OM
390VOID\r
391EFIAPI\r
392ArmGicEnableInterruptInterface (\r
393 IN INTN GicInterruptInterfaceBase\r
394 )\r
395{\r
d5c6b7fc
OM
396 ARM_GIC_ARCH_REVISION Revision;\r
397\r
398 Revision = ArmGicGetSupportedArchRevision ();\r
399 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
400 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase);\r
d7133859
OM
401 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
402 ArmGicV3EnableInterruptInterface ();\r
d5c6b7fc
OM
403 } else {\r
404 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
405 }\r
793ca69f
OM
406}\r
407\r
408VOID\r
409EFIAPI\r
410ArmGicDisableInterruptInterface (\r
411 IN INTN GicInterruptInterfaceBase\r
412 )\r
413{\r
d5c6b7fc
OM
414 ARM_GIC_ARCH_REVISION Revision;\r
415\r
416 Revision = ArmGicGetSupportedArchRevision ();\r
417 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
418 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase);\r
d7133859
OM
419 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
420 ArmGicV3DisableInterruptInterface ();\r
d5c6b7fc
OM
421 } else {\r
422 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
423 }\r
793ca69f 424}\r