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