]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmGic/ArmGicLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicLib.c
CommitLineData
397bdc99
OM
1/** @file\r
2*\r
e1999b26 3* Copyright (c) 2011-2021, 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 26\r
429309e0 27#define ISENABLER_ADDRESS(base, offset) ((base) +\\r
f7ee9e92 28 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))\r
b0393756 29\r
429309e0 30#define ICENABLER_ADDRESS(base, offset) ((base) +\\r
f7ee9e92 31 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))\r
b0393756 32\r
429309e0 33#define IPRIORITY_ADDRESS(base, offset) ((base) +\\r
0996a788
MH
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
429309e0
MK
60 IN UINTN GicRedistributorBase,\r
61 IN ARM_GIC_ARCH_REVISION Revision\r
8705cb38
OM
62 )\r
63{\r
429309e0
MK
64 UINTN MpId;\r
65 UINTN CpuAffinity;\r
66 UINTN Affinity;\r
67 UINTN GicCpuRedistributorBase;\r
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
429309e0 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
429309e0 110 IN INTN GicInterruptInterfaceBase\r
397bdc99
OM
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
429309e0 120 IN INTN GicDistributorBase\r
397bdc99
OM
121 )\r
122{\r
429309e0 123 UINTN ItLines;\r
e1999b26
AS
124\r
125 ItLines = MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F;\r
126\r
127 //\r
128 // Interrupt ID 1020-1023 are reserved.\r
129 //\r
130 return (ItLines == 0x1f) ? 1020 : 32 * (ItLines + 1);\r
397bdc99
OM
131}\r
132\r
133VOID\r
134EFIAPI\r
135ArmGicSendSgiTo (\r
429309e0
MK
136 IN INTN GicDistributorBase,\r
137 IN INTN TargetListFilter,\r
138 IN INTN CPUTargetList,\r
139 IN INTN SgiId\r
397bdc99
OM
140 )\r
141{\r
b0393756
EL
142 MmioWrite32 (\r
143 GicDistributorBase + ARM_GIC_ICDSGIR,\r
144 ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId\r
145 );\r
397bdc99
OM
146}\r
147\r
1b0ac0de
OM
148/*\r
149 * Acknowledge and return the value of the Interrupt Acknowledge Register\r
150 *\r
151 * InterruptId is returned separately from the register value because in\r
152 * the GICv2 the register value contains the CpuId and InterruptId while\r
153 * in the GICv3 the register value is only the InterruptId.\r
154 *\r
155 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface\r
b0393756
EL
156 * @param InterruptId InterruptId read from the Interrupt\r
157 * Acknowledge Register\r
1b0ac0de
OM
158 *\r
159 * @retval value returned by the Interrupt Acknowledge Register\r
160 *\r
161 */\r
397bdc99
OM
162UINTN\r
163EFIAPI\r
164ArmGicAcknowledgeInterrupt (\r
429309e0
MK
165 IN UINTN GicInterruptInterfaceBase,\r
166 OUT UINTN *InterruptId\r
397bdc99
OM
167 )\r
168{\r
429309e0
MK
169 UINTN Value;\r
170 ARM_GIC_ARCH_REVISION Revision;\r
d5c6b7fc
OM
171\r
172 Revision = ArmGicGetSupportedArchRevision ();\r
173 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
174 Value = ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase);\r
175 // InterruptId is required for the caller to know if a valid or spurious\r
176 // interrupt has been read\r
177 ASSERT (InterruptId != NULL);\r
178 if (InterruptId != NULL) {\r
179 *InterruptId = Value & ARM_GIC_ICCIAR_ACKINTID;\r
180 }\r
d7133859
OM
181 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
182 Value = ArmGicV3AcknowledgeInterrupt ();\r
d5c6b7fc
OM
183 } else {\r
184 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
185 // Report Spurious interrupt which is what the above controllers would\r
186 // return if no interrupt was available\r
187 Value = 1023;\r
1b0ac0de
OM
188 }\r
189\r
190 return Value;\r
397bdc99
OM
191}\r
192\r
193VOID\r
194EFIAPI\r
195ArmGicEndOfInterrupt (\r
429309e0
MK
196 IN UINTN GicInterruptInterfaceBase,\r
197 IN UINTN Source\r
397bdc99
OM
198 )\r
199{\r
429309e0 200 ARM_GIC_ARCH_REVISION Revision;\r
d5c6b7fc
OM
201\r
202 Revision = ArmGicGetSupportedArchRevision ();\r
203 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
204 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase, Source);\r
d7133859
OM
205 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
206 ArmGicV3EndOfInterrupt (Source);\r
d5c6b7fc
OM
207 } else {\r
208 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
209 }\r
397bdc99
OM
210}\r
211\r
0d49b82e
QN
212VOID\r
213EFIAPI\r
214ArmGicSetInterruptPriority (\r
429309e0
MK
215 IN UINTN GicDistributorBase,\r
216 IN UINTN GicRedistributorBase,\r
217 IN UINTN Source,\r
218 IN UINTN Priority\r
0d49b82e
QN
219 )\r
220{\r
429309e0
MK
221 UINT32 RegOffset;\r
222 UINTN RegShift;\r
223 ARM_GIC_ARCH_REVISION Revision;\r
224 UINTN GicCpuRedistributorBase;\r
0d49b82e
QN
225\r
226 // Calculate register offset and bit position\r
227 RegOffset = Source / 4;\r
429309e0 228 RegShift = (Source % 4) * 8;\r
0d49b82e
QN
229\r
230 Revision = ArmGicGetSupportedArchRevision ();\r
231 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
232 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
429309e0
MK
233 SourceIsSpi (Source))\r
234 {\r
0d49b82e
QN
235 MmioAndThenOr32 (\r
236 GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),\r
237 ~(0xff << RegShift),\r
238 Priority << RegShift\r
239 );\r
240 } else {\r
241 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
242 GicRedistributorBase,\r
243 Revision\r
244 );\r
245 if (GicCpuRedistributorBase == 0) {\r
246 return;\r
247 }\r
248\r
249 MmioAndThenOr32 (\r
0996a788 250 IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),\r
0d49b82e
QN
251 ~(0xff << RegShift),\r
252 Priority << RegShift\r
253 );\r
254 }\r
255}\r
256\r
397bdc99
OM
257VOID\r
258EFIAPI\r
259ArmGicEnableInterrupt (\r
429309e0
MK
260 IN UINTN GicDistributorBase,\r
261 IN UINTN GicRedistributorBase,\r
262 IN UINTN Source\r
397bdc99
OM
263 )\r
264{\r
429309e0
MK
265 UINT32 RegOffset;\r
266 UINTN RegShift;\r
267 ARM_GIC_ARCH_REVISION Revision;\r
268 UINTN GicCpuRedistributorBase;\r
397bdc99
OM
269\r
270 // Calculate enable register offset and bit position\r
271 RegOffset = Source / 32;\r
429309e0 272 RegShift = Source % 32;\r
397bdc99 273\r
41fb5d46 274 Revision = ArmGicGetSupportedArchRevision ();\r
28f8d28f
AB
275 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
276 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
429309e0
MK
277 SourceIsSpi (Source))\r
278 {\r
41fb5d46 279 // Write set-enable register\r
b0393756
EL
280 MmioWrite32 (\r
281 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),\r
282 1 << RegShift\r
283 );\r
41fb5d46 284 } else {\r
b0393756
EL
285 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
286 GicRedistributorBase,\r
287 Revision\r
288 );\r
41fb5d46
OM
289 if (GicCpuRedistributorBase == 0) {\r
290 ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
291 return;\r
292 }\r
293\r
294 // Write set-enable register\r
b0393756 295 MmioWrite32 (\r
429309e0 296 ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),\r
b0393756
EL
297 1 << RegShift\r
298 );\r
41fb5d46 299 }\r
397bdc99
OM
300}\r
301\r
302VOID\r
303EFIAPI\r
304ArmGicDisableInterrupt (\r
429309e0
MK
305 IN UINTN GicDistributorBase,\r
306 IN UINTN GicRedistributorBase,\r
307 IN UINTN Source\r
397bdc99
OM
308 )\r
309{\r
429309e0
MK
310 UINT32 RegOffset;\r
311 UINTN RegShift;\r
312 ARM_GIC_ARCH_REVISION Revision;\r
313 UINTN GicCpuRedistributorBase;\r
397bdc99
OM
314\r
315 // Calculate enable register offset and bit position\r
316 RegOffset = Source / 32;\r
429309e0 317 RegShift = Source % 32;\r
397bdc99 318\r
41fb5d46 319 Revision = ArmGicGetSupportedArchRevision ();\r
28f8d28f
AB
320 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
321 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
429309e0
MK
322 SourceIsSpi (Source))\r
323 {\r
41fb5d46 324 // Write clear-enable register\r
b0393756
EL
325 MmioWrite32 (\r
326 GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),\r
327 1 << RegShift\r
328 );\r
41fb5d46 329 } else {\r
b0393756 330 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
429309e0
MK
331 GicRedistributorBase,\r
332 Revision\r
333 );\r
41fb5d46
OM
334 if (GicCpuRedistributorBase == 0) {\r
335 return;\r
336 }\r
337\r
338 // Write clear-enable register\r
b0393756 339 MmioWrite32 (\r
429309e0 340 ICENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),\r
b0393756
EL
341 1 << RegShift\r
342 );\r
41fb5d46 343 }\r
397bdc99
OM
344}\r
345\r
346BOOLEAN\r
347EFIAPI\r
348ArmGicIsInterruptEnabled (\r
429309e0
MK
349 IN UINTN GicDistributorBase,\r
350 IN UINTN GicRedistributorBase,\r
351 IN UINTN Source\r
397bdc99
OM
352 )\r
353{\r
429309e0
MK
354 UINT32 RegOffset;\r
355 UINTN RegShift;\r
356 ARM_GIC_ARCH_REVISION Revision;\r
357 UINTN GicCpuRedistributorBase;\r
358 UINT32 Interrupts;\r
397bdc99
OM
359\r
360 // Calculate enable register offset and bit position\r
361 RegOffset = Source / 32;\r
429309e0 362 RegShift = Source % 32;\r
397bdc99 363\r
41fb5d46 364 Revision = ArmGicGetSupportedArchRevision ();\r
28f8d28f
AB
365 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
366 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
429309e0
MK
367 SourceIsSpi (Source))\r
368 {\r
7861b24d
RK
369 Interrupts = MmioRead32 (\r
370 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)\r
371 );\r
41fb5d46 372 } else {\r
b0393756
EL
373 GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
374 GicRedistributorBase,\r
375 Revision\r
376 );\r
41fb5d46
OM
377 if (GicCpuRedistributorBase == 0) {\r
378 return 0;\r
379 }\r
380\r
381 // Read set-enable register\r
b0393756 382 Interrupts = MmioRead32 (\r
429309e0 383 ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset)\r
b0393756 384 );\r
41fb5d46
OM
385 }\r
386\r
387 return ((Interrupts & (1 << RegShift)) != 0);\r
397bdc99 388}\r
60775c51
OM
389\r
390VOID\r
391EFIAPI\r
392ArmGicDisableDistributor (\r
429309e0 393 IN INTN GicDistributorBase\r
60775c51
OM
394 )\r
395{\r
396 // Disable Gic Distributor\r
397 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);\r
398}\r
62d441fb 399\r
793ca69f
OM
400VOID\r
401EFIAPI\r
402ArmGicEnableInterruptInterface (\r
429309e0 403 IN INTN GicInterruptInterfaceBase\r
793ca69f
OM
404 )\r
405{\r
429309e0 406 ARM_GIC_ARCH_REVISION Revision;\r
d5c6b7fc
OM
407\r
408 Revision = ArmGicGetSupportedArchRevision ();\r
409 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
410 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase);\r
d7133859
OM
411 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
412 ArmGicV3EnableInterruptInterface ();\r
d5c6b7fc
OM
413 } else {\r
414 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
415 }\r
793ca69f
OM
416}\r
417\r
418VOID\r
419EFIAPI\r
420ArmGicDisableInterruptInterface (\r
429309e0 421 IN INTN GicInterruptInterfaceBase\r
793ca69f
OM
422 )\r
423{\r
429309e0 424 ARM_GIC_ARCH_REVISION Revision;\r
d5c6b7fc
OM
425\r
426 Revision = ArmGicGetSupportedArchRevision ();\r
427 if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
428 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase);\r
d7133859
OM
429 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
430 ArmGicV3DisableInterruptInterface ();\r
d5c6b7fc
OM
431 } else {\r
432 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
433 }\r
793ca69f 434}\r