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