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