STATIC EFI_STATUS PrepareFdt ( IN OUT VOID *Fdt, IN UINTN FdtSize ) { EFI_STATUS Status; INT32 Node; INT32 CpuNode; UINTN Index; ARM_CORE_INFO *ArmCoreInfoTable; UINTN ArmCoreCount; INT32 MapNode; INT32 ClusterNode; INT32 PmuNode; PMU_INTERRUPT PmuInt; INT32 Phandle[NUM_CORES]; UINT32 ClusterIndex; UINT32 CoreIndex; UINT32 ClusterCount; UINT32 CoresInCluster; UINT32 ClusterId; UINTN MpId; CHAR8 Name[10]; AMD_MP_CORE_INFO_PROTOCOL *AmdMpCoreInfoProtocol; // // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms. // // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file // in the kernel documentation: // Documentation/devicetree/bindings/arm/cpus.txt // Status = gBS->LocateProtocol ( &gAmdMpCoreInfoProtocolGuid, NULL, (VOID **)&AmdMpCoreInfoProtocol ); ASSERT_EFI_ERROR (Status); // Get pointer to ARM core info table ArmCoreInfoTable = AmdMpCoreInfoProtocol->GetArmCoreInfoTable (&ArmCoreCount); ASSERT (ArmCoreInfoTable != NULL); ASSERT (ArmCoreCount <= NUM_CORES); // Get Id from primary CPU MpId = (UINTN)ArmReadMpidr (); // Create /pmu node PmuNode = fdt_add_subnode(Fdt, 0, "pmu"); if (PmuNode >= 0) { fdt_setprop_string (Fdt, PmuNode, "compatible", "arm,armv8-pmuv3"); // append PMU interrupts for (Index = 0; Index < ArmCoreCount; Index++) { MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId, ArmCoreInfoTable[Index].CoreId); Status = AmdMpCoreInfoProtocol->GetPmuSpiFromMpId (MpId, &PmuInt.IntId); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "FDT: Error getting PMU interrupt for MpId '0x%x'\n", MpId)); return Status; } PmuInt.Flag = cpu_to_fdt32 (PMU_INT_FLAG_SPI); PmuInt.IntId = cpu_to_fdt32 (PmuInt.IntId); PmuInt.Type = cpu_to_fdt32 (PMU_INT_TYPE_HIGH_LEVEL); fdt_appendprop (Fdt, PmuNode, "interrupts", &PmuInt, sizeof(PmuInt)); } } else { DEBUG ((DEBUG_ERROR, "FDT: Error creating 'pmu' node\n")); return EFI_INVALID_PARAMETER; } // Create /cpus noide Node = fdt_add_subnode (Fdt, 0, "cpus"); if (Node >= 0) { // Configure the 'cpus' node fdt_setprop_string (Fdt, Node, "name", "cpus"); fdt_setprop_cell (Fdt, Node, "#address-cells", sizeof (UINTN) / 4); fdt_setprop_cell (Fdt, Node, "#size-cells", 0); } else { DEBUG ((DEBUG_ERROR, "FDT: Error creating 'cpus' node\n")); return EFI_INVALID_PARAMETER; } // // Walk the processor table in reverse order for proper listing in FDT // Index = ArmCoreCount; while (Index--) { // Create 'cpu' node AsciiSPrint (Name, sizeof (Name), "CPU%d", Index); CpuNode = fdt_add_subnode (Fdt, Node, Name); if (CpuNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error on creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } Phandle[Index] = fdt_alloc_phandle (Fdt); fdt_setprop_cell (Fdt, CpuNode, "phandle", Phandle[Index]); fdt_setprop_cell (Fdt, CpuNode, "linux,phandle", Phandle[Index]); fdt_setprop_string (Fdt, CpuNode, "enable-method", "psci"); MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId, ArmCoreInfoTable[Index].CoreId); MpId = cpu_to_fdt64 (MpId); fdt_setprop (Fdt, CpuNode, "reg", &MpId, sizeof (MpId)); fdt_setprop_string (Fdt, CpuNode, "compatible", "arm,armv8"); fdt_setprop_string (Fdt, CpuNode, "device_type", "cpu"); } // Create /cpu-map node MapNode = fdt_add_subnode (Fdt, Node, "cpu-map"); if (MapNode >= 0) { ClusterIndex = ArmCoreCount - 1; ClusterCount = NumberOfClustersInTable (ArmCoreInfoTable, ArmCoreCount); while (ClusterCount--) { // Create 'cluster' node AsciiSPrint (Name, sizeof (Name), "cluster%d", ClusterCount); ClusterNode = fdt_add_subnode (Fdt, MapNode, Name); if (ClusterNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } ClusterId = ArmCoreInfoTable[ClusterIndex].ClusterId; CoreIndex = ClusterIndex; CoresInCluster = NumberOfCoresInCluster (ArmCoreInfoTable, ArmCoreCount, ClusterId); while (CoresInCluster--) { // Create 'core' node AsciiSPrint (Name, sizeof (Name), "core%d", CoresInCluster); CpuNode = fdt_add_subnode (Fdt, ClusterNode, Name); if (CpuNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } fdt_setprop_cell (Fdt, CpuNode, "cpu", Phandle[CoreIndex]); // iterate to next core in cluster if (CoresInCluster) { do { --CoreIndex; } while (ClusterId != ArmCoreInfoTable[CoreIndex].ClusterId); } } // iterate to next cluster if (ClusterCount) { do { --ClusterIndex; } while (ClusterInRange (ArmCoreInfoTable, ArmCoreInfoTable[ClusterIndex].ClusterId, ClusterIndex + 1, ArmCoreCount - 1)); } } } else { DEBUG ((DEBUG_ERROR,"FDT: Error creating 'cpu-map' node\n")); return EFI_INVALID_PARAMETER; } SetSocIdStatus (Fdt); SetXgbeStatus (Fdt); // Update the real size of the Device Tree fdt_pack (Fdt); return EFI_SUCCESS; }
/** Initialize the state information for the CPU Architectural Protocol @param ImageHandle of the loaded driver @param SystemTable Pointer to the System Table @retval EFI_SUCCESS Protocol registered @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure @retval EFI_DEVICE_ERROR Hardware problems **/ EFI_STATUS GicV3DxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINTN Index; UINT32 RegOffset; UINTN RegShift; UINT64 CpuTarget; UINT64 MpId; // Make sure the Interrupt Controller Protocol is not already installed in the system. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); mGicDistributorBase = PcdGet32 (PcdGicDistributorBase); mGicRedistributorsBase = PcdGet32 (PcdGicRedistributorsBase); mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase); // // We will be driving this GIC in native v3 mode, i.e., with Affinity // Routing enabled. So ensure that the ARE bit is set. // if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) { MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE); } for (Index = 0; Index < mGicNumInterrupts; Index++) { GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index); // Set Priority RegOffset = Index / 4; RegShift = (Index % 4) * 8; MmioAndThenOr32 ( mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset), ~(0xff << RegShift), ARM_GIC_DEFAULT_PRIORITY << RegShift ); } // // Targets the interrupts to the Primary Cpu // if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) { // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31. // More Info in the GIC Specification about "Interrupt Processor Targets Registers" // // Read the first Interrupt Processor Targets Register (that corresponds to the 4 // first SGIs) CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR); // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value // is 0 when we run on a uniprocessor platform. if (CpuTarget != 0) { // The 8 first Interrupt Processor Targets Registers are read-only for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) { MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget); } } } else { MpId = ArmReadMpidr (); CpuTarget = MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3); if ((MmioRead32 (mGicDistributorBase + ARM_GIC_ICDDCR) & ARM_GIC_ICDDCR_DS) != 0) { // // If the Disable Security (DS) control bit is set, we are dealing with a // GIC that has only one security state. In this case, let's assume we are // executing in non-secure state (which is appropriate for DXE modules) // and that no other firmware has performed any configuration on the GIC. // This means we need to reconfigure all interrupts to non-secure Group 1 // first. // MmioWrite32 (mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR, 0xffffffff); for (Index = 32; Index < mGicNumInterrupts; Index += 32) { MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDISR + Index / 8, 0xffffffff); } } // Route the SPIs to the primary CPU. SPIs start at the INTID 32 for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) { MmioWrite32 (mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8), CpuTarget | ARM_GICD_IROUTER_IRM); } } // Set binary point reg to 0x7 (no preemption) ArmGicV3SetBinaryPointer (0x7); // Set priority mask reg to 0xff to allow all priorities through ArmGicV3SetPriorityMask (0xff); // Enable gic cpu interface ArmGicV3EnableInterruptInterface (); // Enable gic distributor ArmGicEnableDistributor (mGicDistributorBase); Status = InstallAndRegisterInterruptService ( &gHardwareInterruptV3Protocol, GicV3IrqInterruptHandler, GicV3ExitBootServicesEvent); return Status; }