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