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