/** @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", __func__)); return RETURN_NOT_FOUND; } return RETURN_SUCCESS; } ARM_GIC_ARCH_REVISION EFIAPI ArmGicGetSupportedArchRevision ( VOID ) { return mGicArchRevision; }