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