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