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 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 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 86 ArmGicGetMaxNumInterrupts ( 87 IN INTN GicDistributorBase 88 ) 89 { 90 return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F) + 1); 91 } 92 93 VOID 94 EFIAPI 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 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 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 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 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 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 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 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 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