Home | History | Annotate | Download | only in ArmVirtGicArchLib
      1 /** @file
      2   ArmGicArchLib library class implementation for DT based virt platforms
      3 
      4   Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <Base.h>
     17 #include <Uefi.h>
     18 
     19 #include <Library/ArmGicLib.h>
     20 #include <Library/ArmGicArchLib.h>
     21 #include <Library/BaseLib.h>
     22 #include <Library/DebugLib.h>
     23 #include <Library/PcdLib.h>
     24 #include <Library/UefiBootServicesTableLib.h>
     25 
     26 #include <Protocol/FdtClient.h>
     27 
     28 STATIC ARM_GIC_ARCH_REVISION        mGicArchRevision;
     29 
     30 RETURN_STATUS
     31 EFIAPI
     32 ArmVirtGicArchLibConstructor (
     33   VOID
     34   )
     35 {
     36   UINT32                IccSre;
     37   FDT_CLIENT_PROTOCOL   *FdtClient;
     38   CONST UINT64          *Reg;
     39   UINT32                RegSize;
     40   UINTN                 AddressCells, SizeCells;
     41   UINTN                 GicRevision;
     42   EFI_STATUS            Status;
     43   UINT64                DistBase, CpuBase, RedistBase;
     44   RETURN_STATUS         PcdStatus;
     45 
     46   Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,
     47                   (VOID **)&FdtClient);
     48   ASSERT_EFI_ERROR (Status);
     49 
     50   GicRevision = 2;
     51   Status = FdtClient->FindCompatibleNodeReg (FdtClient, "arm,cortex-a15-gic",
     52                         (CONST VOID **)&Reg, &AddressCells, &SizeCells,
     53                         &RegSize);
     54   if (Status == EFI_NOT_FOUND) {
     55     GicRevision = 3;
     56     Status = FdtClient->FindCompatibleNodeReg (FdtClient, "arm,gic-v3",
     57                           (CONST VOID **)&Reg, &AddressCells, &SizeCells,
     58                           &RegSize);
     59   }
     60   if (EFI_ERROR (Status)) {
     61     return Status;
     62   }
     63 
     64   switch (GicRevision) {
     65 
     66   case 3:
     67     //
     68     // The GIC v3 DT binding describes a series of at least 3 physical (base
     69     // addresses, size) pairs: the distributor interface (GICD), at least one
     70     // redistributor region (GICR) containing dedicated redistributor
     71     // interfaces for all individual CPUs, and the CPU interface (GICC).
     72     // Under virtualization, we assume that the first redistributor region
     73     // listed covers the boot CPU. Also, our GICv3 driver only supports the
     74     // system register CPU interface, so we can safely ignore the MMIO version
     75     // which is listed after the sequence of redistributor interfaces.
     76     // This means we are only interested in the first two memory regions
     77     // supplied, and ignore everything else.
     78     //
     79     ASSERT (RegSize >= 32);
     80 
     81     // RegProp[0..1] == { GICD base, GICD size }
     82     DistBase = SwapBytes64 (Reg[0]);
     83     ASSERT (DistBase < MAX_UINTN);
     84 
     85     // RegProp[2..3] == { GICR base, GICR size }
     86     RedistBase = SwapBytes64 (Reg[2]);
     87     ASSERT (RedistBase < MAX_UINTN);
     88 
     89     PcdStatus = PcdSet64S (PcdGicDistributorBase, DistBase);
     90     ASSERT_RETURN_ERROR (PcdStatus);
     91     PcdStatus = PcdSet64S (PcdGicRedistributorsBase, RedistBase);
     92     ASSERT_RETURN_ERROR (PcdStatus);
     93 
     94     DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",
     95       DistBase, RedistBase));
     96 
     97     //
     98     // The default implementation of ArmGicArchLib is responsible for enabling
     99     // the system register interface on the GICv3 if one is found. So let's do
    100     // the same here.
    101     //
    102     IccSre = ArmGicV3GetControlSystemRegisterEnable ();
    103     if (!(IccSre & ICC_SRE_EL2_SRE)) {
    104       ArmGicV3SetControlSystemRegisterEnable (IccSre | ICC_SRE_EL2_SRE);
    105       IccSre = ArmGicV3GetControlSystemRegisterEnable ();
    106     }
    107 
    108     //
    109     // Unlike the default implementation, there is no fall through to GICv2
    110     // mode if this GICv3 cannot be driven in native mode due to the fact
    111     // that the System Register interface is unavailable.
    112     //
    113     ASSERT (IccSre & ICC_SRE_EL2_SRE);
    114 
    115     mGicArchRevision = ARM_GIC_ARCH_REVISION_3;
    116     break;
    117 
    118   case 2:
    119     ASSERT (RegSize == 32);
    120 
    121     DistBase = SwapBytes64 (Reg[0]);
    122     CpuBase  = SwapBytes64 (Reg[2]);
    123     ASSERT (DistBase < MAX_UINTN);
    124     ASSERT (CpuBase < MAX_UINTN);
    125 
    126     PcdStatus = PcdSet64S (PcdGicDistributorBase, DistBase);
    127     ASSERT_RETURN_ERROR (PcdStatus);
    128     PcdStatus = PcdSet64S (PcdGicInterruptInterfaceBase, CpuBase);
    129     ASSERT_RETURN_ERROR (PcdStatus);
    130 
    131     DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
    132 
    133     mGicArchRevision = ARM_GIC_ARCH_REVISION_2;
    134     break;
    135 
    136   default:
    137     DEBUG ((EFI_D_ERROR, "%a: No GIC revision specified!\n", __FUNCTION__));
    138     return RETURN_NOT_FOUND;
    139   }
    140   return RETURN_SUCCESS;
    141 }
    142 
    143 ARM_GIC_ARCH_REVISION
    144 EFIAPI
    145 ArmGicGetSupportedArchRevision (
    146   VOID
    147   )
    148 {
    149   return mGicArchRevision;
    150 }
    151