]>
Commit | Line | Data |
---|---|---|
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 | |
33 | STATIC\r | |
34 | BOOLEAN\r | |
35 | SourceIsSpi (\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 | |
50 | STATIC\r | |
51 | UINTN\r | |
52 | GicGetCpuRedistributorBase (\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 |
98 | UINTN\r |
99 | EFIAPI\r | |
100 | ArmGicGetInterfaceIdentification (\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 | |
108 | UINTN\r | |
109 | EFIAPI\r | |
110 | ArmGicGetMaxNumInterrupts (\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 | |
117 | VOID\r | |
118 | EFIAPI\r | |
119 | ArmGicSendSgiTo (\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 |
146 | UINTN\r |
147 | EFIAPI\r | |
148 | ArmGicAcknowledgeInterrupt (\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 | |
177 | VOID\r | |
178 | EFIAPI\r | |
179 | ArmGicEndOfInterrupt (\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 | |
196 | VOID\r | |
197 | EFIAPI\r | |
198 | ArmGicEnableInterrupt (\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 | |
240 | VOID\r | |
241 | EFIAPI\r | |
242 | ArmGicDisableInterrupt (\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 | |
283 | BOOLEAN\r | |
284 | EFIAPI\r | |
285 | ArmGicIsInterruptEnabled (\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 |
327 | VOID\r | |
328 | EFIAPI\r | |
329 | ArmGicDisableDistributor (\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 |
337 | VOID\r |
338 | EFIAPI\r | |
339 | ArmGicEnableInterruptInterface (\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 | |
355 | VOID\r | |
356 | EFIAPI\r | |
357 | ArmGicDisableInterruptInterface (\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 |