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  * 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