]>
Commit | Line | Data |
---|---|---|
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 | |
40 | STATIC\r | |
41 | BOOLEAN\r | |
42 | SourceIsSpi (\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 | |
57 | STATIC\r | |
58 | UINTN\r | |
59 | GicGetCpuRedistributorBase (\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 |
107 | UINTN\r |
108 | EFIAPI\r | |
109 | ArmGicGetInterfaceIdentification (\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 | |
117 | UINTN\r | |
118 | EFIAPI\r | |
119 | ArmGicGetMaxNumInterrupts (\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 | |
133 | VOID\r | |
134 | EFIAPI\r | |
135 | ArmGicSendSgiTo (\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 |
162 | UINTN\r |
163 | EFIAPI\r | |
164 | ArmGicAcknowledgeInterrupt (\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 | |
193 | VOID\r | |
194 | EFIAPI\r | |
195 | ArmGicEndOfInterrupt (\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 |
212 | VOID\r |
213 | EFIAPI\r | |
214 | ArmGicSetInterruptPriority (\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 |
257 | VOID\r |
258 | EFIAPI\r | |
259 | ArmGicEnableInterrupt (\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 | |
302 | VOID\r | |
303 | EFIAPI\r | |
304 | ArmGicDisableInterrupt (\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 | |
346 | BOOLEAN\r | |
347 | EFIAPI\r | |
348 | ArmGicIsInterruptEnabled (\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 |
390 | VOID\r | |
391 | EFIAPI\r | |
392 | ArmGicDisableDistributor (\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 |
400 | VOID\r |
401 | EFIAPI\r | |
402 | ArmGicEnableInterruptInterface (\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 | |
418 | VOID\r | |
419 | EFIAPI\r | |
420 | ArmGicDisableInterruptInterface (\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 |