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