/** @file
ArmGicArchLib library class implementation for DT based virt platforms
Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
STATIC ARM_GIC_ARCH_REVISION mGicArchRevision;
RETURN_STATUS
EFIAPI
ArmVirtGicArchLibConstructor (
VOID
)
{
UINT32 IccSre;
FDT_CLIENT_PROTOCOL *FdtClient;
CONST UINT64 *Reg;
UINT32 RegSize;
UINTN AddressCells, SizeCells;
UINTN GicRevision;
EFI_STATUS Status;
UINT64 DistBase, CpuBase, RedistBase;
RETURN_STATUS PcdStatus;
Status = gBS->LocateProtocol (
&gFdtClientProtocolGuid,
NULL,
(VOID **)&FdtClient
);
ASSERT_EFI_ERROR (Status);
GicRevision = 2;
Status = FdtClient->FindCompatibleNodeReg (
FdtClient,
"arm,cortex-a15-gic",
(CONST VOID **)&Reg,
&AddressCells,
&SizeCells,
&RegSize
);
if (Status == EFI_NOT_FOUND) {
GicRevision = 3;
Status = FdtClient->FindCompatibleNodeReg (
FdtClient,
"arm,gic-v3",
(CONST VOID **)&Reg,
&AddressCells,
&SizeCells,
&RegSize
);
}
if (EFI_ERROR (Status)) {
return Status;
}
switch (GicRevision) {
case 3:
//
// The GIC v3 DT binding describes a series of at least 3 physical (base
// addresses, size) pairs: the distributor interface (GICD), at least one
// redistributor region (GICR) containing dedicated redistributor
// interfaces for all individual CPUs, and the CPU interface (GICC).
// Under virtualization, we assume that the first redistributor region
// listed covers the boot CPU. Also, our GICv3 driver only supports the
// system register CPU interface, so we can safely ignore the MMIO version
// which is listed after the sequence of redistributor interfaces.
// This means we are only interested in the first two memory regions
// supplied, and ignore everything else.
//
ASSERT (RegSize >= 32);
// RegProp[0..1] == { GICD base, GICD size }
DistBase = SwapBytes64 (Reg[0]);
ASSERT (DistBase < MAX_UINTN);
// RegProp[2..3] == { GICR base, GICR size }
RedistBase = SwapBytes64 (Reg[2]);
ASSERT (RedistBase < MAX_UINTN);
PcdStatus = PcdSet64S (PcdGicDistributorBase, DistBase);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet64S (PcdGicRedistributorsBase, RedistBase);
ASSERT_RETURN_ERROR (PcdStatus);
DEBUG ((
DEBUG_INFO,
"Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",
DistBase,
RedistBase
));
//
// The default implementation of ArmGicArchLib is responsible for enabling
// the system register interface on the GICv3 if one is found. So let's do
// the same here.
//
IccSre = ArmGicV3GetControlSystemRegisterEnable ();
if (!(IccSre & ICC_SRE_EL2_SRE)) {
ArmGicV3SetControlSystemRegisterEnable (IccSre | ICC_SRE_EL2_SRE);
IccSre = ArmGicV3GetControlSystemRegisterEnable ();
}
//
// Unlike the default implementation, there is no fall through to GICv2
// mode if this GICv3 cannot be driven in native mode due to the fact
// that the System Register interface is unavailable.
//
ASSERT (IccSre & ICC_SRE_EL2_SRE);
mGicArchRevision = ARM_GIC_ARCH_REVISION_3;
break;
case 2:
//
// When the GICv2 is emulated with virtualization=on, it adds a virtual
// set of control registers. This means the register property can be
// either 32 or 64 bytes in size.
//
ASSERT ((RegSize == 32) || (RegSize == 64));
DistBase = SwapBytes64 (Reg[0]);
CpuBase = SwapBytes64 (Reg[2]);
ASSERT (DistBase < MAX_UINTN);
ASSERT (CpuBase < MAX_UINTN);
PcdStatus = PcdSet64S (PcdGicDistributorBase, DistBase);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet64S (PcdGicInterruptInterfaceBase, CpuBase);
ASSERT_RETURN_ERROR (PcdStatus);
DEBUG ((DEBUG_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
mGicArchRevision = ARM_GIC_ARCH_REVISION_2;
break;
default:
DEBUG ((DEBUG_ERROR, "%a: No GIC revision specified!\n", __FUNCTION__));
return RETURN_NOT_FOUND;
}
return RETURN_SUCCESS;
}
ARM_GIC_ARCH_REVISION
EFIAPI
ArmGicGetSupportedArchRevision (
VOID
)
{
return mGicArchRevision;
}