123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- /** @file
- Arm Gic cpu parser.
- Copyright (c) 2021 - 2022, 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
- - linux/Documentation/devicetree/bindings/arm/pmu.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,armv8" },
- { "arm,cortex-a15" },
- { "arm,cortex-a7" },
- { "arm,cortex-a57" }
- };
- /** COMPATIBILITY_INFO structure for CPU nodes.
- */
- STATIC CONST COMPATIBILITY_INFO CpuCompatibleInfo = {
- ARRAY_SIZE (CpuCompatibleStr),
- CpuCompatibleStr
- };
- /** Pmu compatible strings.
- Any other "compatible" value is not supported by this module.
- */
- STATIC CONST COMPATIBILITY_STR PmuCompatibleStr[] = {
- { "arm,armv8-pmuv3" }
- };
- /** COMPATIBILITY_INFO structure for the PmuCompatibleStr.
- */
- CONST COMPATIBILITY_INFO PmuCompatibleInfo = {
- ARRAY_SIZE (PmuCompatibleStr),
- PmuCompatibleStr
- };
- /** 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;
- }
- /** Parse a Pmu compatible node, extracting Pmu information.
- This function modifies a CM_OBJ_DESCRIPTOR object.
- The following CM_ARM_GICC_INFO fields are patched:
- - PerformanceInterruptGsiv;
- @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
- GicCPmuNodeParser (
- IN CONST VOID *Fdt,
- IN INT32 GicIntcNode,
- IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
- )
- {
- EFI_STATUS Status;
- INT32 IntCells;
- INT32 PmuNode;
- UINT32 PmuNodeCount;
- UINT32 PmuIrq;
- UINT32 Index;
- CM_ARM_GICC_INFO *GicCInfo;
- CONST UINT8 *Data;
- INT32 DataSize;
- if (GicCCmObjDesc == NULL) {
- ASSERT (GicCCmObjDesc != NULL);
- return EFI_INVALID_PARAMETER;
- }
- GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
- PmuNode = 0;
- // Count the number of pmu nodes.
- Status = FdtCountCompatNodeInBranch (
- Fdt,
- 0,
- &PmuCompatibleInfo,
- &PmuNodeCount
- );
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
- if (PmuNodeCount == 0) {
- return EFI_NOT_FOUND;
- }
- Status = FdtGetNextCompatNodeInBranch (
- Fdt,
- 0,
- &PmuCompatibleInfo,
- &PmuNode
- );
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- if (Status == EFI_NOT_FOUND) {
- // Should have found the node.
- Status = EFI_ABORTED;
- }
- }
- // Get the number of cells used to encode an interrupt.
- Status = FdtGetInterruptCellsInfo (Fdt, GicIntcNode, &IntCells);
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
- Data = fdt_getprop (Fdt, PmuNode, "interrupts", &DataSize);
- if ((Data == NULL) || (DataSize != (IntCells * sizeof (UINT32)))) {
- // If error or not 1 interrupt.
- ASSERT (Data != NULL);
- ASSERT (DataSize == (IntCells * sizeof (UINT32)));
- return EFI_ABORTED;
- }
- PmuIrq = FdtGetInterruptId ((CONST UINT32 *)Data);
- // Only supports PPI 23 for now.
- // According to BSA 1.0 s3.6 PPI assignments, PMU IRQ ID is 23. A non BSA
- // compliant system may assign a different IRQ for the PMU, however this
- // is not implemented for now.
- if (PmuIrq != BSA_PMU_IRQ) {
- ASSERT (PmuIrq == BSA_PMU_IRQ);
- return EFI_ABORTED;
- }
- for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
- GicCInfo[Index].PerformanceInterruptGsiv = PmuIrq;
- }
- 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; // {Populated}
- 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;
- 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;
- }
- // Parse the Pmu Interrupt.
- Status = GicCPmuNodeParser (Fdt, IntcNode, NewCmObjDesc);
- if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
- ASSERT_EFI_ERROR (Status);
- 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;
- }
|