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