summaryrefslogtreecommitdiff
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c777
-rw-r--r--DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h67
2 files changed, 844 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
new file mode 100644
index 0000000..b4e6729
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
@@ -0,0 +1,777 @@
+/** @file
+ Arm Gic cpu parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/arm/cpus.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#include "FdtHwInfoParser.h"
+#include "CmObjectDescUtility.h"
+#include "Gic/ArmGicCParser.h"
+#include "Gic/ArmGicDispatcher.h"
+
+/** List of "compatible" property values for CPU nodes.
+
+ Any other "compatible" value is not supported by this module.
+*/
+STATIC CONST COMPATIBILITY_STR CpuCompatibleStr[] = {
+ { "arm,arm-v7" },
+ { "arm,arm-v8" },
+ { "arm,cortex-a15" },
+ { "arm,cortex-a7" },
+ { "arm,cortex-a57" }
+};
+
+/** COMPATIBILITY_INFO structure for CPU nodes.
+*/
+STATIC CONST COMPATIBILITY_INFO CpuCompatibleInfo = {
+ ARRAY_SIZE (CpuCompatibleStr),
+ CpuCompatibleStr
+};
+
+/** Parse a "cpu" node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] CpuNode Offset of a cpu node.
+ @param [in] GicVersion Version of the GIC.
+ @param [in] AddressCells Number of address cells used for the reg
+ property.
+ @param [out] GicCInfo CM_ARM_GICC_INFO structure to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CpuNodeParser (
+ IN CONST VOID *Fdt,
+ IN INT32 CpuNode,
+ IN UINT32 GicVersion,
+ IN UINT32 AddressCells,
+ OUT CM_ARM_GICC_INFO *GicCInfo
+ )
+{
+ CONST UINT8 *Data;
+ INT32 DataSize;
+ UINT32 ProcUid;
+ UINT64 MpIdr;
+ UINT64 CheckAffMask;
+
+ MpIdr = 0;
+ CheckAffMask = ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2;
+
+ if (GicCInfo == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data = fdt_getprop (Fdt, CpuNode, "reg", &DataSize);
+ if ((Data == NULL) ||
+ ((DataSize != sizeof (UINT32)) &&
+ (DataSize != sizeof (UINT64))))
+ {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ /* If cpus node's #address-cells property is set to 2
+ The first reg cell bits [7:0] must be set to
+ bits [39:32] of MPIDR_EL1.
+ The second reg cell bits [23:0] must be set to
+ bits [23:0] of MPIDR_EL1.
+ */
+ if (AddressCells == 2) {
+ MpIdr = fdt64_to_cpu (*((UINT64 *)Data));
+ CheckAffMask |= ARM_CORE_AFF3;
+ } else {
+ MpIdr = fdt32_to_cpu (*((UINT32 *)Data));
+ }
+
+ if ((MpIdr & ~CheckAffMask) != 0) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // To fit the Affinity [0-3] a 32bits value, place the Aff3 on bits
+ // [31:24] instead of their original place ([39:32]).
+ ProcUid = MpIdr | ((MpIdr & ARM_CORE_AFF3) >> 8);
+
+ /* ACPI 6.3, s5.2.12.14 GIC CPU Interface (GICC) Structure:
+ GIC 's CPU Interface Number. In GICv1/v2 implementations,
+ this value matches the bit index of the associated processor
+ in the GIC distributor's GICD_ITARGETSR register. For
+ GICv3/4 implementations this field must be provided by the
+ platform, if compatibility mode is supported. If it is not supported
+ by the implementation, then this field must be zero.
+
+ Note: We do not support compatibility mode for GicV3
+ */
+ if (GicVersion == 2) {
+ GicCInfo->CPUInterfaceNumber = ProcUid;
+ } else {
+ GicCInfo->CPUInterfaceNumber = 0;
+ }
+
+ GicCInfo->AcpiProcessorUid = ProcUid;
+ GicCInfo->Flags = EFI_ACPI_6_3_GIC_ENABLED;
+ GicCInfo->MPIDR = MpIdr;
+
+ return EFI_SUCCESS;
+}
+
+/** Parse a "cpus" node and its children "cpu" nodes.
+
+ Create as many CM_ARM_GICC_INFO structures as "cpu" nodes.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] CpusNode Offset of a cpus node.
+ @param [in] GicVersion Version of the GIC.
+ @param [out] NewGicCmObjDesc If success, CM_OBJ_DESCRIPTOR containing
+ all the created CM_ARM_GICC_INFO.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CpusNodeParser (
+ IN CONST VOID *Fdt,
+ IN INT32 CpusNode,
+ IN UINT32 GicVersion,
+ OUT CM_OBJ_DESCRIPTOR **NewGicCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ INT32 CpuNode;
+ UINT32 CpuNodeCount;
+ INT32 AddressCells;
+
+ UINT32 Index;
+ CM_ARM_GICC_INFO *GicCInfoBuffer;
+ UINT32 GicCInfoBufferSize;
+
+ if (NewGicCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AddressCells = fdt_address_cells (Fdt, CpusNode);
+ if (AddressCells < 0) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ // Count the number of "cpu" nodes under the "cpus" node.
+ Status = FdtCountNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNodeCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (CpuNodeCount == 0) {
+ ASSERT (0);
+ return EFI_NOT_FOUND;
+ }
+
+ // Allocate memory for CpuNodeCount CM_ARM_GICC_INFO structures.
+ GicCInfoBufferSize = CpuNodeCount * sizeof (CM_ARM_GICC_INFO);
+ GicCInfoBuffer = AllocateZeroPool (GicCInfoBufferSize);
+ if (GicCInfoBuffer == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CpuNode = CpusNode;
+ for (Index = 0; Index < CpuNodeCount; Index++) {
+ Status = FdtGetNextNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+
+ goto exit_handler;
+ }
+
+ // Parse the "cpu" node.
+ if (!FdtNodeIsCompatible (Fdt, CpuNode, &CpuCompatibleInfo)) {
+ ASSERT (0);
+ Status = EFI_UNSUPPORTED;
+ goto exit_handler;
+ }
+
+ Status = CpuNodeParser (
+ Fdt,
+ CpuNode,
+ GicVersion,
+ AddressCells,
+ &GicCInfoBuffer[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ } // for
+
+ Status = CreateCmObjDesc (
+ CREATE_CM_ARM_OBJECT_ID (EArmObjGicCInfo),
+ CpuNodeCount,
+ GicCInfoBuffer,
+ GicCInfoBufferSize,
+ NewGicCmObjDesc
+ );
+ ASSERT_EFI_ERROR (Status);
+
+exit_handler:
+ FreePool (GicCInfoBuffer);
+ return Status;
+}
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicC information generic to Gic v2 and v3.
+
+ This function modifies a CM_OBJ_DESCRIPTOR object.
+ The following CM_ARM_GICC_INFO fields are patched:
+ - VGICMaintenanceInterrupt;
+ - Flags;
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] GicIntcNode Offset of a Gic compatible
+ interrupt-controller node.
+ @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicCIntcNodeParser (
+ IN CONST VOID *Fdt,
+ IN INT32 GicIntcNode,
+ IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ INT32 IntCells;
+ CM_ARM_GICC_INFO *GicCInfo;
+
+ CONST UINT8 *Data;
+ INT32 DataSize;
+
+ if (GicCCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the number of cells used to encode an interrupt.
+ Status = FdtGetInterruptCellsInfo (Fdt, GicIntcNode, &IntCells);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Get the GSIV maintenance interrupt.
+ // According to the DT bindings, this could be the:
+ // "Interrupt source of the parent interrupt controller on secondary GICs"
+ // but it is assumed that only one Gic is available.
+ Data = fdt_getprop (Fdt, GicIntcNode, "interrupts", &DataSize);
+ if ((Data != NULL) && (DataSize == (IntCells * sizeof (UINT32)))) {
+ GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
+ GicCInfo->VGICMaintenanceInterrupt =
+ FdtGetInterruptId ((CONST UINT32 *)Data);
+ GicCInfo->Flags = DT_IRQ_IS_EDGE_TRIGGERED (
+ fdt32_to_cpu (((UINT32 *)Data)[IRQ_FLAGS_OFFSET])
+ ) ?
+ EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
+ 0;
+ return Status;
+ } else if (DataSize < 0) {
+ // This property is optional and was not found. Just return.
+ return Status;
+ }
+
+ // The property exists and its size doesn't match for one interrupt.
+ ASSERT (0);
+ return EFI_ABORTED;
+}
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicCv2 information.
+
+ This function modifies a CM_OBJ_DESCRIPTOR object.
+ The following CM_ARM_GICC_INFO fields are patched:
+ - PhysicalAddress;
+ - GICH;
+ - GICV;
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] Gicv2IntcNode Offset of a Gicv2 compatible
+ interrupt-controller node.
+ @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicCv2IntcNodeParser (
+ IN CONST VOID *Fdt,
+ IN INT32 Gicv2IntcNode,
+ IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ CM_ARM_GICC_INFO *GicCInfo;
+ INT32 AddressCells;
+ INT32 SizeCells;
+
+ CONST UINT8 *GicCValue;
+ CONST UINT8 *GicVValue;
+ CONST UINT8 *GicHValue;
+
+ CONST UINT8 *Data;
+ INT32 DataSize;
+ UINT32 RegSize;
+ UINT32 RegCount;
+
+ if (GicCCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
+ GicVValue = NULL;
+ GicHValue = NULL;
+
+ // Get the #address-cells and #size-cells property values.
+ Status = FdtGetParentAddressInfo (
+ Fdt,
+ Gicv2IntcNode,
+ &AddressCells,
+ &SizeCells
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2) ||
+ (SizeCells < 1) ||
+ (SizeCells > 2))
+ {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
+
+ Data = fdt_getprop (Fdt, Gicv2IntcNode, "reg", &DataSize);
+ if ((Data == NULL) ||
+ (DataSize < 0) ||
+ ((DataSize % RegSize) != 0))
+ {
+ // If error or wrong size.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ RegCount = DataSize/RegSize;
+
+ switch (RegCount) {
+ case 4:
+ {
+ // GicV is at index 3 in the reg property. GicV is optional.
+ GicVValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (3, AddressCells, SizeCells));
+ // fall-through.
+ }
+ case 3:
+ {
+ // GicH is at index 2 in the reg property. GicH is optional.
+ GicHValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (2, AddressCells, SizeCells));
+ // fall-through.
+ }
+ case 2:
+ {
+ // GicC is at index 1 in the reg property. GicC is mandatory.
+ GicCValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (1, AddressCells, SizeCells));
+ break;
+ }
+ default:
+ {
+ // Not enough or too much information.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ }
+
+ // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
+ for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
+ if (AddressCells == 2) {
+ GicCInfo[Index].PhysicalBaseAddress = fdt64_to_cpu (*(UINT64 *)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64 *)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64 *)GicVValue);
+ } else {
+ GicCInfo[Index].PhysicalBaseAddress = fdt32_to_cpu (*(UINT32 *)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32 *)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32 *)GicVValue);
+ }
+ } // for
+
+ return EFI_SUCCESS;
+}
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicCv3 information.
+
+ This function modifies a CM_OBJ_DESCRIPTOR object.
+ The following CM_ARM_GICC_INFO fields are patched:
+ - PhysicalAddress;
+ - GICH;
+ - GICV;
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] Gicv3IntcNode Offset of a Gicv3 compatible
+ interrupt-controller node.
+ @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicCv3IntcNodeParser (
+ IN CONST VOID *Fdt,
+ IN INT32 Gicv3IntcNode,
+ IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ CM_ARM_GICC_INFO *GicCInfo;
+ INT32 AddressCells;
+ INT32 SizeCells;
+ UINT32 AdditionalRedistReg;
+
+ CONST UINT8 *GicCValue;
+ CONST UINT8 *GicVValue;
+ CONST UINT8 *GicHValue;
+
+ CONST UINT8 *Data;
+ INT32 DataSize;
+ UINT32 RegSize;
+ UINT32 RegCount;
+
+ if (GicCCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
+ GicCValue = NULL;
+ GicVValue = NULL;
+ GicHValue = NULL;
+
+ // Get the #address-cells and #size-cells property values.
+ Status = FdtGetParentAddressInfo (
+ Fdt,
+ Gicv3IntcNode,
+ &AddressCells,
+ &SizeCells
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2) ||
+ (SizeCells < 1) ||
+ (SizeCells > 2))
+ {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ // The "#redistributor-regions" property is optional.
+ Data = fdt_getprop (Fdt, Gicv3IntcNode, "#redistributor-regions", &DataSize);
+ if ((Data != NULL) && (DataSize == sizeof (UINT32))) {
+ ASSERT (fdt32_to_cpu (*(UINT32 *)Data) > 1);
+ AdditionalRedistReg = fdt32_to_cpu (*(UINT32 *)Data) - 1;
+ } else {
+ AdditionalRedistReg = 0;
+ }
+
+ RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
+
+ /*
+ Ref: linux/blob/master/Documentation/devicetree/bindings/
+ interrupt-controller/arm%2Cgic-v3.yaml
+
+ reg:
+ description: |
+ Specifies base physical address(s) and size of the GIC
+ registers, in the following order:
+ - GIC Distributor interface (GICD)
+ - GIC Redistributors (GICR), one range per redistributor region
+ - GIC CPU interface (GICC)
+ - GIC Hypervisor interface (GICH)
+ - GIC Virtual CPU interface (GICV)
+ GICC, GICH and GICV are optional.
+ minItems: 2
+ maxItems: 4096
+ */
+ Data = fdt_getprop (Fdt, Gicv3IntcNode, "reg", &DataSize);
+ if ((Data == NULL) ||
+ (DataSize < 0) ||
+ ((DataSize % RegSize) != 0))
+ {
+ // If error or wrong size.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ RegCount = (DataSize / RegSize) - AdditionalRedistReg;
+
+ // The GicD and GicR info is mandatory.
+ switch (RegCount) {
+ case 5:
+ {
+ // GicV is at index 4 in the reg property. GicV is optional.
+ GicVValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (
+ 4 + AdditionalRedistReg,
+ AddressCells,
+ SizeCells
+ ));
+ // fall-through.
+ }
+ case 4:
+ {
+ // GicH is at index 3 in the reg property. GicH is optional.
+ GicHValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (
+ 3 + AdditionalRedistReg,
+ AddressCells,
+ SizeCells
+ ));
+ // fall-through.
+ }
+ case 3:
+ {
+ // GicC is at index 2 in the reg property. GicC is optional.
+ // Even though GicC is optional, it is made mandatory in this parser.
+ GicCValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (
+ 2 + AdditionalRedistReg,
+ AddressCells,
+ SizeCells
+ ));
+ // fall-through
+ }
+ case 2:
+ {
+ // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
+ // GicD is described by the CM_ARM_GICD_INFO object.
+ break;
+ }
+ default:
+ {
+ // Not enough or too much information.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ }
+
+ // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
+ if (AddressCells == 2) {
+ for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
+ // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
+ GicCInfo[Index].GICRBaseAddress = 0;
+ GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64 *)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64 *)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64 *)GicVValue);
+ }
+ } else {
+ for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
+ // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
+ GicCInfo[Index].GICRBaseAddress = 0;
+ GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32 *)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32 *)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32 *)GicVValue);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** CM_ARM_GICC_INFO parser function.
+
+ This parser expects FdtBranch to be the "\cpus" node node.
+ At most one CmObj is created.
+ The following structure is populated:
+ typedef struct CmArmGicCInfo {
+ UINT32 CPUInterfaceNumber; // {Populated}
+ UINT32 AcpiProcessorUid; // {Populated}
+ UINT32 Flags; // {Populated}
+ UINT32 ParkingProtocolVersion; // {default = 0}
+ UINT32 PerformanceInterruptGsiv; // {default = 0}
+ UINT64 ParkedAddress; // {default = 0}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT64 GICV; // {Populated}
+ UINT64 GICH; // {Populated}
+ UINT32 VGICMaintenanceInterrupt; // {Populated}
+ UINT64 GICRBaseAddress; // {default = 0}
+ UINT64 MPIDR; // {Populated}
+ UINT8 ProcessorPowerEfficiencyClass; // {default = 0}
+ UINT16 SpeOverflowInterrupt; // {default = 0}
+ UINT32 ProximityDomain; // {default = 0}
+ UINT32 ClockDomain; // {default = 0}
+ UINT32 AffinityFlags; // {default = 0}
+ } CM_ARM_GICC_INFO;
+
+ The pmu information can be found in the pmu node. There is no support
+ for now.
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicCInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ INT32 IntcNode;
+ UINT32 GicVersion;
+ CM_OBJ_DESCRIPTOR *NewCmObjDesc;
+ VOID *Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+ NewCmObjDesc = NULL;
+
+ // The FdtBranch points to the Cpus Node.
+ // Get the interrupt-controller node associated to the "cpus" node.
+ Status = FdtGetIntcParentNode (Fdt, FdtBranch, &IntcNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+
+ return Status;
+ }
+
+ Status = GetGicVersion (Fdt, IntcNode, &GicVersion);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Parse the "cpus" nodes and its children "cpu" nodes,
+ // and create a CM_OBJ_DESCRIPTOR.
+ Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Parse the interrupt-controller node according to the Gic version.
+ switch (GicVersion) {
+ case 2:
+ {
+ Status = GicCv2IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
+ break;
+ }
+ case 3:
+ {
+ Status = GicCv3IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
+ break;
+ }
+ default:
+ {
+ // Unsupported Gic version.
+ ASSERT (0);
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Parse the Gic information common to Gic v2 and v3.
+ Status = GicCIntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Add all the CmObjs to the Configuration Manager.
+ Status = AddMultipleCmObj (FdtParserHandle, NewCmObjDesc, 0, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+exit_handler:
+ FreeCmObjDesc (NewCmObjDesc);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
new file mode 100644
index 0000000..2a0f966
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
@@ -0,0 +1,67 @@
+/** @file
+ Arm Gic cpu parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#ifndef ARM_GICC_PARSER_H_
+#define ARM_GICC_PARSER_H_
+
+/** CM_ARM_GICC_INFO parser function.
+
+ This parser expects FdtBranch to be the "\cpus" node node.
+ At most one CmObj is created.
+ The following structure is populated:
+ typedef struct CmArmGicCInfo {
+ UINT32 CPUInterfaceNumber; // {Populated}
+ UINT32 AcpiProcessorUid; // {Populated}
+ UINT32 Flags; // {Populated}
+ UINT32 ParkingProtocolVersion; // {default = 0}
+ UINT32 PerformanceInterruptGsiv; // {default = 0}
+ UINT64 ParkedAddress; // {default = 0}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT64 GICV; // {Populated}
+ UINT64 GICH; // {Populated}
+ UINT32 VGICMaintenanceInterrupt; // {Populated}
+ UINT64 GICRBaseAddress; // {default = 0}
+ UINT64 MPIDR; // {Populated}
+ UINT8 ProcessorPowerEfficiencyClass; // {default = 0}
+ UINT16 SpeOverflowInterrupt; // {default = 0}
+ UINT32 ProximityDomain; // {default = 0}
+ UINT32 ClockDomain; // {default = 0}
+ UINT32 AffinityFlags; // {default = 0}
+ } CM_ARM_GICC_INFO;
+
+ The pmu information can be found in the pmu node. There is no support
+ for now.
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicCInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_GICC_PARSER_H_