/** @file This is the driver that initializes the Intel PCH. @copyright Copyright (c) 1999 - 2015 Intel Corporation. All rights reserved This software and associated documentation (if any) is furnished under a license and may only be used or copied in accordance with the terms of the license. Except as permitted by such license, no part of this software or documentation may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. This file contains an 'Intel Peripheral Driver' and uniquely identified as "Intel Reference Module" and is licensed for Intel CPUs and chipsets under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to additional terms of the license agreement **/ #include "PchInit.h" #include "HeciMsgLib.h" #include "ChipsetInitHob.h" // [ EIP357393 ]+>>> #define AMI_PCI_BUS_EXT_PROTOCOL_GUID \ { 0xf42a009d, 0x977f, 0x4f08, 0x94, 0x40, 0xbc, 0xa5, 0xa3, 0xbe, 0xd9, 0xaf }; static EFI_GUID gAmiExtPciBusProtocolGuid = AMI_PCI_BUS_EXT_PROTOCOL_GUID; // [ EIP357393 ]+<<< // // Global Variables // EFI_HANDLE mImageHandle; #ifdef USB_PRECONDITION_ENABLE_FLAG extern EFI_USB_HC_PORT_PRECONDITION *mPrivatePreConditionList; #endif // USB_PRECONDITION_ENABLE_FLAG // // GUID Definitions // EFI_GUID gChipsetInitHobGuid = CHIPSET_INIT_INFO_HOB_GUID; EFI_GUID gEfiHeciProtocolGuid = HECI_PROTOCOL_GUID; // // EFI_EVENT // EFI_EVENT mHeciEvent; // // Local function prototypes // EFI_STATUS InitializePchDevice ( IN OUT PCH_INSTANCE_PRIVATE_DATA *PchInstance, IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN UINT32 RootComplexBar, IN UINT16 PmBase, IN UINT16 GpioBase ); EFI_STATUS ProgramSvidSid ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN UINT32 RootComplexBar ); VOID EFIAPI PchExitBootServicesEvent ( IN EFI_EVENT Event, IN VOID *Context ); VOID EFIAPI PchInitBeforeBoot ( IN EFI_EVENT Event, IN VOID *Context ); // [ EIP357393 ]+>>> EFI_STATUS EFIAPI PchSpiLockBeforeEndOfDxe ( IN EFI_EVENT Event, IN VOID *Context ); // [ EIP357393 ]+<<< EFI_STATUS ChipsetInitSettingsCheck ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy ); /** Configures PCH IOBP and stores this configuration in S3 boot script @param[in] RootComplexBar RootComplexBar value of this PCH device @param[in] Address Address of the IOBP register block @param[in] AndMask Mask to AND with the register @param[in] OrMask Mask to OR with the register **/ VOID ProgramIobpWithScript ( IN UINT32 RootComplexBar, IN UINT32 Address, IN UINT32 AndMask, IN UINT32 OrMask ) { EFI_STATUS Status; Status = ProgramIobp (RootComplexBar, Address, AndMask, OrMask); ASSERT_EFI_ERROR (Status); Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM ( RootComplexBar, Address, AndMask, OrMask ); ASSERT_EFI_ERROR (Status); } /** Configures 32-bit MMIO register and stores this configuration in S3 boot script @param[in] RootComplexBar RootComplexBar value of this PCH device @param[in] Address Address of the IOBP register block @param[in] AndMask Mask to AND with the register @param[in] OrMask Mask to OR with the register **/ VOID MmioAndThenOr32WithScript ( IN UINTN Address, IN UINT32 AndMask, IN UINT32 OrMask ) { MmioAndThenOr32 (Address, AndMask, OrMask); PCH_INIT_COMMON_SCRIPT_MEM_READ_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, Address, &OrMask, &AndMask ); } /** This is the standard EFI driver point that detects whether there is an PCH southbridge in the system and if so, initializes the chip. @param[in] ImageHandle Handle for the image of this driver @param[in] SystemTable Pointer to the EFI System Table @retval EFI_SUCCESS The function completed successfully @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver **/ EFI_STATUS EFIAPI PchInitEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINT8 BusNumber; UINT32 RootComplexBar; DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy; UINTN NumHandles; EFI_HANDLE *HandleBuffer; UINT32 Index; PCH_INSTANCE_PRIVATE_DATA *PchInstance; UINT16 PmBase; UINT16 GpioBase; UINTN PciD31F0RegBase; DEBUG ((EFI_D_INFO, "PchInitEntryPoint() Start\n")); PchInstance = NULL; PchPlatformPolicy = NULL; INITIALIZE_SCRIPT (ImageHandle, SystemTable); mImageHandle = ImageHandle; /// /// Retrieve all instances of PCH Platform Policy protocol /// Status = gBS->LocateHandleBuffer ( ByProtocol, &gDxePchPlatformPolicyProtocolGuid, NULL, &NumHandles, &HandleBuffer ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gDxePchPlatformPolicyProtocolGuid, (VOID **) &PchPlatformPolicy ); ASSERT_EFI_ERROR (Status); /// /// Allocate and install the PCH Info protocol /// BusNumber = PchPlatformPolicy->BusNumber; PciD31F0RegBase = MmPciAddress ( 0, PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_LPC, PCI_FUNCTION_NUMBER_PCH_LPC, 0 ); RootComplexBar = MmioRead32 (PciD31F0RegBase + R_PCH_LPC_RCBA) & B_PCH_LPC_RCBA_BAR; PmBase = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_ACPI_BASE) & B_PCH_LPC_ACPI_BASE_BAR; GpioBase = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GPIO_BASE) & B_PCH_LPC_GPIO_BASE_BAR; ASSERT (RootComplexBar != 0); ASSERT (PmBase != 0); ASSERT (GpioBase != 0); DEBUG ((EFI_D_INFO, "PCH Device:\n-------------\n")); DEBUG ((EFI_D_INFO, " RCBA 0x%X\n", RootComplexBar)); DEBUG ((EFI_D_INFO, " PmBase 0x%X\n", PmBase)); DEBUG ((EFI_D_INFO, " GpioBase 0x%X\n", GpioBase)); DEBUG ((EFI_D_INFO, "-------------\n")); /// /// Dump whole DXE_PCH_PLATFORM_POLICY_PROTOCOL and serial out. /// PchDumpPlatformProtocol (PchPlatformPolicy); /// /// Initialize the PCH device /// InitializePchDevice (PchInstance, PchPlatformPolicy, RootComplexBar, PmBase, GpioBase); PchInstance = AllocateZeroPool (sizeof (PCH_INSTANCE_PRIVATE_DATA)); if (PchInstance == NULL) { ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } PchInstance->PchInfo.Revision = PCH_INFO_PROTOCOL_REVISION_2; PchInstance->PchInfo.BusNumber = BusNumber; PchInstance->PchInfo.RCVersion = PCH_RC_VERSION; #ifdef USB_PRECONDITION_ENABLE_FLAG PchInstance->PchInfo.Preconditioned = mPrivatePreConditionList; #endif // USB_PRECONDITION_ENABLE_FLAG Status = gBS->InstallMultipleProtocolInterfaces ( &(HandleBuffer[Index]), &gEfiPchInfoProtocolGuid, &(PchInstance->PchInfo), NULL ); } (gBS->FreePool) (HandleBuffer); DEBUG ((EFI_D_INFO, "PchInitEntryPoint() End\n")); return EFI_SUCCESS; } /** Initialize the PCH device according to the PCH Platform Policy protocol @param[in, out] PchInstance PCH instance private data. May get updated by this function @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance @param[in] RootComplexBar RootComplexBar value of this PCH device @param[in] PmBase Power Management IO base address of this PCH device @param[in] GpioBase GPIO base address of this PCH device @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS InitializePchDevice ( IN OUT PCH_INSTANCE_PRIVATE_DATA *PchInstance, IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN UINT32 RootComplexBar, IN UINT16 PmBase, IN UINT16 GpioBase ) { EFI_STATUS Status; BOOLEAN AzaliaEnable; UINT32 FuncDisableReg; VOID *Registration; VOID *Registration1; // [ EIP357393 ] EFI_EVENT LegacyBootEvent; EFI_EVENT ExitBootServicesEvent; UINT16 LpcDeviceId; DEBUG ((EFI_D_INFO, "InitializePchDevice() Start\n")); FuncDisableReg = MmioRead32 (RootComplexBar + R_PCH_RCRB_FUNC_DIS); LpcDeviceId = MmioRead16 ( MmPciAddress ( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, PCI_FUNCTION_NUMBER_PCH_LPC, 0 ) + R_PCH_LPC_DEVICE_ID); /// /// Take care of any ChipsetInit settings before going any further. /// Status = ChipsetInitSettingsCheck(PchPlatformPolicy); ASSERT_EFI_ERROR (Status); /// /// Miscellaneous power management handling /// Status = ConfigureMiscPm (PchPlatformPolicy, RootComplexBar, GpioBase); ASSERT_EFI_ERROR (Status); /// /// Additional power management setting /// Status = ConfigureAdditionalPm (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); /// /// Configures PCH DMI power management configuration /// Status = ConfigureDmiPm (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); /// /// Deep Sx Enabling /// Status = ProgramDeepSx (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); /// /// Perform PCH initialization sequence /// Status = ConfigureMiscItems (PchPlatformPolicy, RootComplexBar, &FuncDisableReg); ASSERT_EFI_ERROR (Status); #ifdef ADSP_FLAG /// /// Configure AudioDSP /// if(IS_PCH_LPTLP_LPC_DEVICE_ID(LpcDeviceId)) { Status = ConfigureAudioDsp (PchPlatformPolicy, RootComplexBar, &FuncDisableReg); ASSERT_EFI_ERROR (Status); } #endif // ADSP_FLAG /// /// Detect and initialize the type of codec present in the system /// Status = ConfigureAzalia (PchPlatformPolicy, RootComplexBar, &AzaliaEnable); ASSERT_EFI_ERROR (Status); /// /// Check to disable Azalia controller /// if (!AzaliaEnable) { FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_AZALIA; } /// /// Initialize LAN /// Status = ConfigureLan (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); /// /// Configure USB /// Status = ConfigureUsb (PchPlatformPolicy, RootComplexBar, &FuncDisableReg); ASSERT_EFI_ERROR (Status); /// /// Initialize PCIE root ports /// Status = PchInitRootPorts (PchPlatformPolicy, RootComplexBar, PmBase, &FuncDisableReg); ASSERT_EFI_ERROR (Status); /// /// Thermal controller already enabled in PEI /// /// /// Sata Controllers /// Status = ConfigureSata (PchPlatformPolicy, RootComplexBar, &FuncDisableReg, GpioBase); ASSERT_EFI_ERROR (Status); /// /// Display link /// Status = ConfigureDisplay (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); /// /// Set the PCH Function Disable Register /// MmioWrite32 ((UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS), (UINT32) (FuncDisableReg)); /// /// Reads back for posted write to take effect /// MmioRead32 (RootComplexBar + R_PCH_RCRB_FUNC_DIS); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS), 1, &FuncDisableReg ); /// /// Reads back for posted write to take effect /// SCRIPT_MEM_POLL ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS), &FuncDisableReg, // BitMask &FuncDisableReg, // BitValue 1, // Duration 1 // LoopTimes ); /// /// Perform clock gating register settings /// PCH BIOS Spec Rev 0.5.0, section 19.10 Enabling Clock Gating /// Status = ConfigureClockGating (PchPlatformPolicy, RootComplexBar, FuncDisableReg); ASSERT_EFI_ERROR (Status); Status = ConfigureIoApic (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); Status = ProgramSvidSid (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); #ifdef SERIAL_IO_FLAG /// /// Configure Serial IO Controllers /// if(IS_PCH_LPTLP_LPC_DEVICE_ID(LpcDeviceId)) { Status = ConfigureSerialIo (PchPlatformPolicy, RootComplexBar); ASSERT_EFI_ERROR (Status); } #endif // SERIAL_IO_FLAG // [ EIP357393 ]+>>> // Create an AMI ExtPciBus protocol call back event. // EfiCreateProtocolNotifyEvent ( &gAmiExtPciBusProtocolGuid, EFI_TPL_CALLBACK, PchSpiLockBeforeEndOfDxe, NULL, &Registration1 ); // [ EIP357393 ]+<<< /// /// Create an ExitPmAuth protocol call back event. /// EfiCreateProtocolNotifyEvent ( &gExitPmAuthProtocolGuid, EFI_TPL_CALLBACK, PchInitBeforeBoot, NULL, &Registration ); /// /// Create events for PCH to do the task before ExitBootServices/LegacyBoot. /// It is guaranteed that only one of two events below will be signalled /// Status = gBS->CreateEvent ( EVENT_SIGNAL_EXIT_BOOT_SERVICES, EFI_TPL_CALLBACK, PchExitBootServicesEvent, NULL, &ExitBootServicesEvent ); ASSERT_EFI_ERROR (Status); Status = EfiCreateEventLegacyBootEx ( EFI_TPL_CALLBACK, PchExitBootServicesEvent, NULL, &LegacyBootEvent ); ASSERT_EFI_ERROR (Status); DEBUG ((EFI_D_INFO, "InitializePchDevice() End\n")); return Status; } /** Program Pch devices Subsystem Vendor Identifier (SVID) and Subsystem Identifier (SID). @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance @param[in] RootComplexBar RootComplexBar value of this PCH device @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS ProgramSvidSid ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN UINT32 RootComplexBar ) { UINT8 Index; UINT16 EhciAccessCntl; UINT8 BusNumber; UINTN PciEAddressBase; UINT8 DeviceNumber; UINT8 FunctionNumber; UINT8 SvidRegOffset; BOOLEAN IsPchEhci; STATIC PCH_SVID_SID_INIT_ENTRY SvidSidInitTable[] = { { 31, 0, R_PCH_LPC_SS }, { 31, 2, R_PCH_SATA_AHCI_SVID }, { 31, 5, R_PCH_SATA_AHCI_SVID }, { 31, 3, R_PCH_SMBUS_SVID }, { 31, 6, R_PCH_THERMAL_SVID }, { 29, 0, R_PCH_EHCI_SVID }, { 26, 0, R_PCH_EHCI_SVID }, { 20, 0, R_PCH_XHCI_SVID }, { 27, 0, R_PCH_HDA_SVID }, { 28, 0, R_PCH_PCIE_SVID }, { 28, 1, R_PCH_PCIE_SVID }, { 28, 2, R_PCH_PCIE_SVID }, { 28, 3, R_PCH_PCIE_SVID }, { 28, 4, R_PCH_PCIE_SVID }, { 28, 5, R_PCH_PCIE_SVID }, { 28, 6, R_PCH_PCIE_SVID }, { 28, 7, R_PCH_PCIE_SVID }, { 25, 0, R_PCH_LAN_SVID }, /* HECI */ { 22, 0, PCI_SVID_OFFSET }, { 22, 1, PCI_SVID_OFFSET }, { 22, 2, PCI_SVID_OFFSET }, { 22, 3, PCI_SVID_OFFSET } }; PCH_SERIES PchSeries; DEBUG ((EFI_D_INFO, "ProgramSvidSid() Start\n")); PchSeries = GetPchSeries(); EhciAccessCntl = 0; BusNumber = PchPlatformPolicy->BusNumber; if ((PchPlatformPolicy->DefaultSvidSid->SubSystemVendorId != 0) || (PchPlatformPolicy->DefaultSvidSid->SubSystemId != 0)) { for (Index = 0; Index < (sizeof (SvidSidInitTable) / sizeof (PCH_SVID_SID_INIT_ENTRY)); Index++) { DeviceNumber = SvidSidInitTable[Index].DeviceNumber; FunctionNumber = SvidSidInitTable[Index].FunctionNumber; SvidRegOffset = SvidSidInitTable[Index].SvidRegOffset; PciEAddressBase = MmPciAddress ( 0, BusNumber, DeviceNumber, FunctionNumber, 0 ); /// /// Skip if the device is disabled /// if (MmioRead16 (PciEAddressBase) != V_PCH_INTEL_VENDOR_ID) { continue; } IsPchEhci = FALSE; if (PchSeries == PchH) { IsPchEhci = IS_PCH_H_EHCI (DeviceNumber, FunctionNumber); } else if (PchSeries == PchLp) { IsPchEhci = IS_PCH_LP_EHCI (DeviceNumber, FunctionNumber); } /// /// Set EHCI devices WRT_RDONLY bit (D29:F0,D26:F0:80h, bit 0) to 1, to make SVID and SID registers are writable /// if (IsPchEhci) { EhciAccessCntl = MmioRead16 ((UINTN) (PciEAddressBase + R_PCH_EHCI_ACCESS_CNTL)); MmioOr16 ((UINTN) (PciEAddressBase + R_PCH_EHCI_ACCESS_CNTL), B_PCH_EHCI_ACCESS_CNTL_ENABLE); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciEAddressBase + R_PCH_EHCI_ACCESS_CNTL), 1, (VOID *) (UINTN) (PciEAddressBase + R_PCH_EHCI_ACCESS_CNTL) ); } if ((DeviceNumber == 22 && FunctionNumber == 2) || (DeviceNumber == 22 && FunctionNumber == 3)) { /// /// Sub System Identifiers register of D22:F2&F3 is 32bit access and write once /// MmioWrite32 ( (UINTN) (PciEAddressBase + SvidRegOffset), (UINT32) (PchPlatformPolicy->DefaultSvidSid->SubSystemVendorId | (PchPlatformPolicy->DefaultSvidSid->SubSystemId << 16)) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciEAddressBase + SvidRegOffset), 1, (VOID *) (UINTN) (PciEAddressBase + SvidRegOffset) ); } else { /// /// Program Pch devices Subsystem Vendor Identifier (SVID) /// MmioWrite16 ( (UINTN) (PciEAddressBase + SvidRegOffset), PchPlatformPolicy->DefaultSvidSid->SubSystemVendorId ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciEAddressBase + SvidRegOffset), 1, (VOID *) (UINTN) (PciEAddressBase + SvidRegOffset) ); /// /// Program Pch devices Subsystem Identifier (SID) /// MmioWrite16 ( (UINTN) (PciEAddressBase + SvidRegOffset + 2), PchPlatformPolicy->DefaultSvidSid->SubSystemId ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciEAddressBase + SvidRegOffset + 2), 1, (VOID *) (PciEAddressBase + SvidRegOffset + 2) ); } /// /// Restore the EHCI devices WRT_RDONLY bit (D29:F0,D26:F0:80h, bit 0) value /// if (IsPchEhci) { MmioWrite16 ((UINTN) (PciEAddressBase + R_PCH_EHCI_ACCESS_CNTL), EhciAccessCntl); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciEAddressBase + R_PCH_EHCI_ACCESS_CNTL), 1, &EhciAccessCntl ); } } } DEBUG ((EFI_D_INFO, "ProgramSvidSid() End\n")); return EFI_SUCCESS; } /** Initialize R/WO Registers that described in PCH BIOS Spec @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance @param[in] RootComplexBar RootComplexBar address of this PCH device @param[in, out] FuncDisableReg The value of Function disable register @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS PciERWORegInit ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN UINT32 RootComplexBar, IN OUT UINT32 *FuncDisableReg ) { UINTN Index; UINTN PciD31F5RegBase; UINT8 BusNumber; UINT8 RootPortFunction; UINTN RPBase; UINT32 Data32; UINT16 Data16; UINT8 Data8; PCH_SERIES PchSeries; DEBUG ((EFI_D_INFO, "PciERWORegInit() Start\n")); PchSeries = GetPchSeries(); BusNumber = PchPlatformPolicy->BusNumber; PciD31F5RegBase = 0; if (PchSeries == PchH) { PciD31F5RegBase = MmPciAddress (0, BusNumber, 31, 5, 0); } /// /// PCH BIOS Spec Rev 0.5.0, Section 5.12 R/WO Registers, Table 5-4 /// System BIOS must read the register and write the same value back to the register /// before passing control to the operating system. /// Dev:Func/Type Register Offset Register Name Bits /// D28:F0-F7 034h Capabilities Pointer 7:0 /// D28:F0-F7 040h Capabilities List 15:8 /// D28:F0-F7 042h PCI Express Capabilities 8 /// D28:F0~F7 044h Device Capabilities 2:0 /// D28:F0-F7 04Ch Link Capabilities 11:10, 17:15 /// D28:F0-F7 050h Link Control 3 /// D28:F0-F7 054h Slot Capabilities 31:19, 16:5 /// D28:F0-F7 064h Device Capabilities 2 11 /// D28:F0-F7 080h Message Signaled Interrupt Capability ID 15:8 /// D28:F0-F7 090h Port Mapping Regster 15:8 /// D28:F0-F7 094h Subsystem Vendor ID 31:0 /// D28:F0-F7 0D8h Miscellaneous Port Configuration 23, 2 /// D28:F0-F7 404h Latency Tolerance Reporting Override 2 2 /// RCBA 21A4h Link Capabilities 17:15 For PCH H /// D31:F5 0A8h Next Capabilities Pointer 15:8 /// D31:F5 0B2h Capabilities List 9:8 /// for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) { if (((*FuncDisableReg) & (B_PCH_RCRB_FUNC_DIS_PCI_EX_PORT1 << Index)) == 0) { RootPortFunction = GetPchPcieRpfn(RootComplexBar, (UINT8)Index); RPBase = MmPciAddress (0, BusNumber, PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, RootPortFunction, 0); Data32 = MmioRead32 (RPBase + R_PCH_PCIE_LCAP); MmioWrite32 (RPBase + R_PCH_PCIE_LCAP, Data32); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RPBase + R_PCH_PCIE_LCAP), 1, &Data32 ); Data32 = MmioRead32 (RPBase + R_PCH_PCIE_SVID); MmioWrite32 (RPBase + R_PCH_PCIE_SVID, Data32); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RPBase + R_PCH_PCIE_SVID), 1, &Data32 ); Data32 = MmioRead32 (RPBase + R_PCH_PCIE_SLCAP); MmioWrite32 (RPBase + R_PCH_PCIE_SLCAP, Data32); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RPBase + R_PCH_PCIE_SLCAP), 1, &Data32 ); /// /// Added PCIe register to be lockdown /// Data8 = MmioRead8 (RPBase + R_PCH_PCIE_CAPP); MmioWrite8 (RPBase + R_PCH_PCIE_CAPP, Data8); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (RPBase + R_PCH_PCIE_CAPP), 1, &Data8 ); Data16 = MmioRead16 (RPBase + R_PCH_PCIE_CLIST); MmioWrite16 (RPBase + R_PCH_PCIE_CLIST, Data16); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (RPBase + R_PCH_PCIE_CLIST), 1, &Data16 ); Data16 = MmioRead16 (RPBase + R_PCH_PCIE_DCAP); MmioWrite16 (RPBase + R_PCH_PCIE_DCAP, Data16); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (RPBase + R_PCH_PCIE_DCAP), 1, &Data16 ); Data16 = MmioRead16 (RPBase + R_PCH_PCIE_MID); MmioWrite16 (RPBase + R_PCH_PCIE_MID, Data16); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (RPBase + R_PCH_PCIE_MID), 1, &Data16 ); Data16 = MmioRead16 (RPBase + R_PCH_PCIE_SVCAP); MmioWrite16 (RPBase + R_PCH_PCIE_SVCAP, Data16); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (RPBase + R_PCH_PCIE_SVCAP), 1, &Data16 ); if (PchSeries == PchLp) { Data32 = MmioRead32 (RPBase + R_PCH_PCIE_L1SECH); Data32 |= V_PCH_PCIE_L1SECH_L1SUBST_CAP_ID; MmioWrite32 (RPBase + R_PCH_PCIE_L1SECH, Data32); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RPBase + R_PCH_PCIE_L1SECH), 1, &Data32 ); Data32 = MmioRead32 (RPBase + R_PCH_PCIE_L1SCAP); MmioWrite32 (RPBase + R_PCH_PCIE_L1SCAP, Data32); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RPBase + R_PCH_PCIE_L1SCAP), 1, &Data32 ); } } } if (PchSeries == PchH) { /// /// D31:F5:A8h[15:8] /// Data16 = MmioRead16 (PciD31F5RegBase + R_PCH_SATA_CR0); MmioWrite16 (PciD31F5RegBase + R_PCH_SATA_CR0, Data16); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F5RegBase + R_PCH_SATA_CR0), 1, &Data16 ); /// /// D31:F5:B2h[9:8] /// Data16 = MmioRead16 (PciD31F5RegBase + R_PCH_SATA_FLR_CLV); MmioWrite16 (PciD31F5RegBase + R_PCH_SATA_FLR_CLV, Data16); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD31F5RegBase + R_PCH_SATA_FLR_CLV), 1, &Data16 ); } /// /// D28:F0-F7:42h[8] (PCI Express Capabilities) has been done in PchInitRootPorts(). /// D28:F0-F7:4Ch[17:15] (Link Capabilities) has been done in PchInitSingleRootPort(). /// D28:F0-F7:404h[2] (Latency Tolerance Reporting Override 2) has been done in PchInitSingleRootPort(). /// RCBA + 21A4h[17:15] (Link Capabilities) has been done in ConfigureDmiPm() for PCH H. /// DEBUG ((EFI_D_INFO, "PciERWORegInit() End\n")); return EFI_SUCCESS; } /** Set a Root Port Downstream devices ASPM and LTR S3 dispatch item, this function may assert if any error happend @param[in] RootPortBus Pci Bus Number of the root port @param[in] RootPortDevice Pci Device Number of the root port @param[in] RootPortFunc Pci Function Number of the root port @param[in] RootPortAspm Root port Aspm configuration @param[in] NumOfDevAspmOverride Number of Device specific ASPM policy override items @param[in] DevAspmOverride Pointer to array of Device specific ASPM policy override items @param[in] TempBusNumberMin Minimal temp bus number that can be assigned to the root port (as secondary bus number) and its down stream switches @param[in] TempBusNumberMax Maximal temp bus number that can be assigned to the root port (as subordinate bus number) and its down stream switches @param[in] NumOfDevLtrOverride Number of Device specific LTR override items @param[in] DevLtrOverride Pointer to array of Device specific LTR policy override items @param[in] PchPwrOptPcie Pcie Power Optimizer Configuration @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS SetPciePmS3Item ( IN UINT8 RootPortBus, IN UINT8 RootPortDevice, IN UINT8 RootPortFunc, IN PCH_PCI_EXPRESS_ASPM_CONTROL RootPortAspm, IN UINT8 NumOfDevAspmOverride, IN PCH_PCIE_DEVICE_ASPM_OVERRIDE *DevAspmOverride, IN UINT8 TempBusNumberMin, IN UINT8 TempBusNumberMax, IN UINT8 NumOfDevLtrOverride, IN PCH_PCIE_DEVICE_LTR_OVERRIDE *DevLtrOverride, IN PCH_PCIE_PWR_OPT *PchPwrOptPcie, IN PCH_PCIE_EXPRESS_L1SUBSTATES_CONTROL L1SubstatesConfig, IN UINT8 PolicyRevision, IN BOOLEAN FirstRPToSetPm, IN BOOLEAN L1SupportedInAllEnabledPorts, IN BOOLEAN ClkreqSupportedInAllEnabledPorts ) { EFI_STATUS Status; #ifdef EFI_S3_RESUME STATIC EFI_PCH_S3_SUPPORT_PROTOCOL *PchS3Support; STATIC EFI_PCH_S3_PARAMETER_PCIE_SET_PM S3ParameterSetPm; STATIC EFI_PCH_S3_DISPATCH_ITEM S3DispatchItem = { PchS3ItemTypePcieSetPm, &S3ParameterSetPm }; EFI_PHYSICAL_ADDRESS S3DispatchEntryPoint; if (!PchS3Support) { DEBUG ((EFI_D_INFO, "Locating the S3 Support Protocol - PCH Init\n")); /// /// Get the PCH S3 Support Protocol /// Status = gBS->LocateProtocol ( &gEfiPchS3SupportProtocolGuid, NULL, (VOID **) &PchS3Support ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } DEBUG ((EFI_D_INFO, "Located the S3 Support Protocol - PCH Init: %x\n", (UINTN)PchS3Support)); } DEBUG ((EFI_D_INFO, "Attempting to set Custom PCH Init Dispatch Item\n")); S3ParameterSetPm.RootPortBus = RootPortBus; S3ParameterSetPm.RootPortDevice = RootPortDevice; S3ParameterSetPm.RootPortFunc = RootPortFunc; S3ParameterSetPm.RootPortAspm = RootPortAspm; S3ParameterSetPm.NumOfDevAspmOverride = NumOfDevAspmOverride; S3ParameterSetPm.DevAspmOverrideAddr = (UINT32) (UINTN) DevAspmOverride; S3ParameterSetPm.TempBusNumberMin = TempBusNumberMin; S3ParameterSetPm.TempBusNumberMax = TempBusNumberMax; S3ParameterSetPm.PchPwrOptPcie = (UINT32) (UINTN) PchPwrOptPcie; S3ParameterSetPm.NumOfDevLtrOverride = NumOfDevLtrOverride; S3ParameterSetPm.DevLtrOverrideAddr = (UINT32) (UINTN) DevLtrOverride; S3ParameterSetPm.L1SubstatesConfig = L1SubstatesConfig; S3ParameterSetPm.PolicyRevision = PolicyRevision; S3ParameterSetPm.FirstRPToSetPm = FirstRPToSetPm; S3ParameterSetPm.L1SupportedInAllEnabledPorts = L1SupportedInAllEnabledPorts; S3ParameterSetPm.ClkreqSupportedInAllEnabledPorts = ClkreqSupportedInAllEnabledPorts; Status = PchS3Support->SetDispatchItem ( PchS3Support, &S3DispatchItem, &S3DispatchEntryPoint ); ASSERT_EFI_ERROR (Status); /// /// Save the script dispatch item in the Boot Script /// SCRIPT_DISPATCH (EFI_ACPI_S3_RESUME_SCRIPT_TABLE, S3DispatchEntryPoint); #else Status = EFI_SUCCESS; #endif return Status; } /** PCH initialization before ExitBootServices / LegacyBoot events Useful for operations which must happen later than at EndOfPost event @param[in] Event A pointer to the Event that triggered the callback. @param[in] Context A pointer to private data registered with the callback function. @retval None **/ VOID EFIAPI PchExitBootServicesEvent ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; UINTN NumHandles; EFI_HANDLE *HandleBuffer; DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy; UINTN Index; UINT32 AhciBar; UINTN PciD31F2RegBase; UINT16 SataModeSelect; UINT16 LpcDeviceId; UINT32 PxSctlDet; UINT32 PxCmdSud; UINT16 OrgCmdWord; /// /// Closed the event to avoid call twice /// gBS->CloseEvent (Event); LpcDeviceId = MmioRead16 ( MmPciAddress ( 0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, PCI_FUNCTION_NUMBER_PCH_LPC, 0 ) + R_PCH_LPC_DEVICE_ID); /// /// Retrieve all instances of PCH Platform Policy protocol /// Status = gBS->LocateHandleBuffer ( ByProtocol, &gDxePchPlatformPolicyProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Failed to locate handle buffer for PCH Policy protocol.\n")); return; } for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gDxePchPlatformPolicyProtocolGuid, (VOID **) &PchPlatformPolicy ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Failed to find PCH Policy protocol.\n")); return; } ConfigureXhciAtBoot (PchPlatformPolicy); #ifdef SERIAL_IO_FLAG ConfigureSerialIoAtBoot(PchPlatformPolicy); #endif // SERIAL_IO_FLAG /// /// eSATA port support only up to Gen2 /// PciD31F2RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_SATA, PCI_FUNCTION_NUMBER_PCH_SATA, 0); // // Make sure SATA device exists. // if (MmioRead16 (PciD31F2RegBase + R_PCH_SATA_VENDOR_ID) != 0xFFFF) { SataModeSelect = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_MAP) & B_PCH_SATA_MAP_SMS_MASK; if ((SataModeSelect == V_PCH_SATA_MAP_SMS_AHCI) || (SataModeSelect == V_PCH_SATA_MAP_SMS_RAID)) { AhciBar = MmioRead32 (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR) & B_PCH_SATA_AHCI_BAR_BA; // // Make sure the AhciBar is valid. // if ((AhciBar != 0x00000000) && (AhciBar != 0xFFFFFFFF)) { /// /// Keep original CMD word, and enable MSE /// OrgCmdWord = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_COMMAND); if ((OrgCmdWord & B_PCH_SATA_COMMAND_MSE) == 0) { MmioOr16 ((PciD31F2RegBase + R_PCH_SATA_COMMAND), B_PCH_SATA_COMMAND_MSE); } for (Index = 0; Index < GetPchMaxSataPortNum (); Index++) { if (PchPlatformPolicy->SataConfig->PortSettings[Index].External == PCH_DEVICE_ENABLE) { PxSctlDet = MmioRead32(AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))) & B_PCH_SATA_AHCI_PXSCTL_DET; PxCmdSud = MmioRead32(AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index))) & B_PCH_SATA_AHCI_PxCMD_SUD; /// /// Limit speed to Gen2 /// MmioAndThenOr32 ( (UINTN) (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index))), (UINT32)~(B_PCH_SATA_AHCI_PXSCTL_SPD), (UINT32) V_PCH_SATA_AHCI_PXSCTL_SPD_2 ); /// /// If port is not offline, and it's spin up, need to port reset. /// After port reset, clear the SERR. /// - Set DET=1, and then set DET=0. /// if ((PxSctlDet == V_PCH_SATA_AHCI_PXSCTL_DET_0) && (PxCmdSud == B_PCH_SATA_AHCI_PxCMD_SUD)) { MmioOr32 (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), V_PCH_SATA_AHCI_PXSCTL_DET_1); PchPmTimerStall (1000); MmioAnd32(AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), (UINT32) ~(B_PCH_SATA_AHCI_PXSCTL_DET)); MmioWrite32 (AhciBar + (R_PCH_SATA_AHCI_P0SERR + (0x80 * Index)), (UINT32)~0u); } /// /// If port is offline, and it's not spin up, meets the power bug. /// Need to do the W/A to spin up the port and then spin down. /// Then entering back to offline and listen. /// - Set DET=0, SUD=1, and then set SUD=0, DET=4. /// if ((PxSctlDet == V_PCH_SATA_AHCI_PXSCTL_DET_4) && (PxCmdSud == 0)) { MmioAnd32(AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), (UINT32) ~(B_PCH_SATA_AHCI_PXSCTL_DET)); MmioOr32 (AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index)), B_PCH_SATA_AHCI_PxCMD_SUD); PchPmTimerStall (1000); MmioAnd32(AhciBar + (R_PCH_SATA_AHCI_P0CMD + (0x80 * Index)), (UINT32) ~(B_PCH_SATA_AHCI_PxCMD_SUD)); MmioOr32 (AhciBar + (R_PCH_SATA_AHCI_P0SCTL + (0x80 * Index)), V_PCH_SATA_AHCI_PXSCTL_DET_4); } } } /// /// Restore original CMD word. /// if ((OrgCmdWord & B_PCH_SATA_COMMAND_MSE) == 0) { MmioWrite16 ((PciD31F2RegBase + R_PCH_SATA_COMMAND), OrgCmdWord); } } // AhciBar is vaild } // SATA mode is AHCI or RAID } // if D31F2 is existed } return; } /** PCH checkes the HECI protocol and sends ChipsetInitSyncMsg @param[in] Event Event objext @param[in] *Context VOID Pointer @retval None **/ VOID EFIAPI ChipsetInitSyncCallback ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; EFI_HECI_PROTOCOL *Heci; CHIPSET_INIT_INFO_HOB *ChipsetInitHob; ChipsetInitHob = NULL; Status = EFI_SUCCESS; DEBUG ((EFI_D_INFO, "ChipsetInitSyncCallback() Start\n")); // // Get the HECI protocol to make sure HECI is ready. // Status = gBS->LocateProtocol (&gEfiHeciProtocolGuid, NULL, (VOID **) &Heci); if (EFI_ERROR (Status)) { return; } if (mHeciEvent) { gBS->CloseEvent (mHeciEvent); } // // Search for the ChipsetInit Info PEIM GUID HOB. // ChipsetInitHob = GetFirstGuidHob (&gChipsetInitHobGuid); if (ChipsetInitHob == NULL) { DEBUG ((EFI_D_INFO, "ChipsetInitHob not found.\n")); return; } // // If ChipsetInitTableUpdReq == 0, settings are already in sync and no furhter work needed // if (ChipsetInitHob->ChipsetInitTableUpdReq == 1) { // // If we do not have the ChipsetInit table that ME FW expects us to have, // we must send the current ChipsetInit table to ME FW via HECI message. // Status = HeciChipsetInitSyncMsg(ChipsetInitHob->ChipsetInitTable, ChipsetInitHob->ChipsetInitTableLen); } DEBUG ((EFI_D_INFO, "ChipsetInitSyncCallback() End\n")); return; } /** Register the HECI protocol callback function for the ChipsetInit sync message. @param[in] *PchPlatformPolicy A pointer to the PchPlatformPolicy. @retval EFI_STATUS **/ EFI_STATUS ChipsetInitSettingsCheck ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy ) { EFI_STATUS Status; VOID *HeciRegistration; DEBUG ((EFI_D_INFO, "ChipsetInitSettingsCheck() Start\n")); Status = gBS->CreateEvent ( EFI_EVENT_NOTIFY_SIGNAL, EFI_TPL_CALLBACK, ChipsetInitSyncCallback, NULL, &mHeciEvent ); ASSERT_EFI_ERROR(Status); Status = gBS->RegisterProtocolNotify ( &gEfiHeciProtocolGuid, mHeciEvent, &HeciRegistration ); ASSERT_EFI_ERROR(Status); ChipsetInitSyncCallback (NULL, NULL); return Status; } /** Update ASL object before Boot @param[in] *PchPlatformPolicy A pointer to the PchPlatformPolicy. @param[in] RootComplexBar RootComplexBar value of this PCH device @retval EFI_STATUS @retval EFI_NOT_READY The Acpi protocols are not ready. **/ EFI_STATUS PchUpdateAslObjects ( IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, IN UINT32 RootComplexBar ) { EFI_STATUS Status; UINTN Index; UINTN VariableSize; UINT32 PciMemBase; PCH_LATE_INIT_SMM_VARIABLE SaveRestoreData; UINT32 AslSignature; UINT32 RpFn; UINT32 Data32; Status = InitializePchAslUpdateLib(); DEBUG ((EFI_D_INFO, "InitializePchAslUpdateLib Status %x\n", Status)); ASSERT_EFI_ERROR (Status); if(EFI_ERROR(Status)) { return EFI_NOT_READY; } // // Update SRMB, Save & Restore Memroy Base // VariableSize = sizeof (PCH_LATE_INIT_SMM_VARIABLE); Status = gRT->GetVariable ( PCH_INIT_PEI_VARIABLE_NAME, &gPchInitPeiVariableGuid, NULL, &VariableSize, &SaveRestoreData ); PciMemBase = SaveRestoreData.PciMemBase; Status = UpdateNameAslCode(EFI_SIGNATURE_32('S','R','M','B'), &PciMemBase, sizeof(PciMemBase)); RpFn = MmioRead32 (RootComplexBar + R_PCH_RCRB_RPFN); for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) { // // Update RPA0, RPA1, RPA2, RPA3, RPA4, RPA5, RPA6, RPA7 for root port function swapping // Data32 = '0' + (UINT32)Index; AslSignature = EFI_SIGNATURE_32('R','P','A',Data32); Data32 = (UINT32)((RpFn >> (Index * S_PCH_RCRB_PRFN_RP_FIELD)) & B_PCH_RCRB_RPFN_RP1FN); Data32 |= (UINT32)(PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16); Status = UpdateNameAslCode(AslSignature, &Data32, sizeof(UINT32)); DEBUG ((EFI_D_INFO, "Update RPAx %x %x\n", Index, Data32)); ASSERT_EFI_ERROR (Status); // // Update Maximum Snoop Latency and Maximum No-Snoop Latency values for PCIE // if (PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_7) { AslSignature = EFI_SIGNATURE_32('P','M','L',(UINT32)('1' + Index)); Data32 = (UINT32) PchPlatformPolicy->PwrOptConfig->PchPwrOptPcie[Index].LtrMaxSnoopLatency; Status = UpdateNameAslCode(AslSignature, &Data32, sizeof(UINT32)); DEBUG ((EFI_D_INFO, "Update PMLx %x %x\n", Index+1, Data32)); ASSERT_EFI_ERROR (Status); AslSignature = EFI_SIGNATURE_32('P','N','L',(UINT32)('1' + Index)); Data32 = (UINT32) PchPlatformPolicy->PwrOptConfig->PchPwrOptPcie[Index].LtrMaxNoSnoopLatency; Status = UpdateNameAslCode(AslSignature, &Data32, sizeof(UINT32)); DEBUG ((EFI_D_INFO, "Update PNLx %x %x\n", Index+1, Data32)); ASSERT_EFI_ERROR (Status); } } // // Update PCHS. // Data32 = (UINT32) GetPchSeries(); Status = UpdateNameAslCode(EFI_SIGNATURE_32('P','C','H','S'), &Data32, sizeof(UINT32)); return EFI_SUCCESS; } /** PCH initialization before Boot Sript Table is closed @param[in] Event A pointer to the Event that triggered the callback. @param[in] Context A pointer to private data registered with the callback function. @retval None **/ VOID EFIAPI PchInitBeforeBoot ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; UINTN NumHandles; EFI_HANDLE *HandleBuffer; UINTN Index; DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy; UINT32 RootComplexBar; UINT32 FuncDisableReg; UINTN PciD25F0RegBase; UINTN PciD31F2RegBase; UINT32 GbEMemBar; UINTN PciD31F0RegBase; UINTN GbeRootPortNumber; UINT16 PmBase; UINT16 GpioBase; UINT32 Data32And; UINT32 Data32Or; UINT32 Data32; UINT16 Data16And; UINT16 Data16Or; UINT8 Data8; VOID *ProtocolPointer; UINTN AzaliaBase; const UINT8 StrEnabled[sizeof (PCH_CRID_ENABLED)] = PCH_CRID_ENABLED; const UINT8 StrDisabled[sizeof (PCH_CRID_DISABLED)] = PCH_CRID_DISABLED; EFI_HANDLE Handle; PCH_SERIES PchSeries; BOOLEAN L1SubstatesSupportedPerPort; PCI_DATA_STRUCTURE *PcirBlockPtr; EFI_PCI_IO_PROTOCOL *PciIo; PCI_EXPANSION_ROM_HEADER *RomImage; BOOLEAN FoundLegacyRaid; EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; CHAR16 RstDriverName1[] = L"Intel RST"; CHAR16 RstDriverName2[] = L"Intel(R) RST"; EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL *DriverEfiVersion; EFI_STRING DriverName; UINT16 AspmVal; BOOLEAN ClkreqPerPortSupported; BOOLEAN ClkreqSupportedInAllEnabledPorts; BOOLEAN L1SupportedInAllEnabledPorts; BOOLEAN FirstRPToSetPm; #ifdef EFI_S3_RESUME STATIC EFI_PCH_S3_SUPPORT_PROTOCOL *PchS3Support; #endif UINTN RPBase; UINT8 PortIndex; PCH_PCIE_DEVICE_ASPM_OVERRIDE *S3DevAspmOverrideTbl; PCH_PCIE_PWR_OPT *S3PchPwrOptPcie; UINT32 DevAspmOverrideTblSize; PCH_PCI_EXPRESS_ASPM_CONTROL RootPortAspmVal; UINT8 NumOfDevltrOverride; PCH_PCIE_DEVICE_LTR_OVERRIDE *S3DevLtrOverrideTbl; PCH_PCIE_DEVICE_LTR_OVERRIDE *DevLtrOverrideTbl; UINT32 DevLtrOverrideTblSize; PCH_PCIE_EXPRESS_L1SUBSTATES_CONTROL L1SubVal; BOOLEAN LtrSupported; S3DevLtrOverrideTbl = NULL; DevLtrOverrideTbl = NULL; NumOfDevltrOverride = 0; LtrSupported = TRUE; L1SubstatesSupportedPerPort = FALSE; Handle = NULL; PchSeries = GetPchSeries(); AspmVal = 0; ClkreqPerPortSupported = FALSE; ClkreqSupportedInAllEnabledPorts = TRUE; L1SupportedInAllEnabledPorts = TRUE; FirstRPToSetPm = TRUE; /// /// Check whether this is real ExitPmAuth notification, or just a SignalEvent /// Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, (VOID **) &ProtocolPointer); if (EFI_ERROR (Status)) { return; } DEBUG ((EFI_D_INFO, "PchInitBeforeBoot() Start\n")); /// /// Closed the event to avoid call twice when launch shell /// gBS->CloseEvent (Event); /// /// Retrieve all instances of PCH Platform Policy protocol /// Status = gBS->LocateHandleBuffer ( ByProtocol, &gDxePchPlatformPolicyProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Failed to locate handle buffer for PCH Policy protocol.\n")); return; } /// /// Find the matching PCH Policy protocol /// for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gDxePchPlatformPolicyProtocolGuid, (VOID **) &PchPlatformPolicy ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Failed to find PCH Policy protocol.\n")); return; } InitFviDataHubCbContext ( PchPlatformPolicy->MiscConfig->FviSmbiosType, (UINT8) mPchFviElements, &mPchFviVersionData ); RootComplexBar = PCH_RCRB_BASE; FuncDisableReg = MmioRead32 (RootComplexBar + R_PCH_RCRB_FUNC_DIS); PciD31F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 0, 0); GpioBase = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GPIO_BASE) & B_PCH_LPC_GPIO_BASE_BAR; PmBase = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_ACPI_BASE) & B_PCH_LPC_ACPI_BASE_BAR; Status = PciERWORegInit (PchPlatformPolicy, RootComplexBar, &FuncDisableReg); ASSERT_EFI_ERROR (Status); /// /// Locking Thermal Reporting Settings prior to end of POST /// Status = ThermalLockDown (PchPlatformPolicy, GpioBase); ASSERT_EFI_ERROR (Status); if ((FuncDisableReg & B_PCH_RCRB_FUNC_DIS_AZALIA) == 0) { AzaliaBase = MmPciAddress ( 0, PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_AZALIA, PCI_FUNCTION_NUMBER_PCH_AZALIA, 0 ); /// /// PCH BIOS Spec Rev 0.5.0 Section 9.5 /// Additional High Definition Audio Programming Steps /// Step 5 /// Set D27:F0:40h[1] = 1b after all settings done including 19.10.5 /// MmioOr8 (AzaliaBase + R_PCH_HDA_HDCTL, B_PCH_HDA_HDCTL_BCLD); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (AzaliaBase + R_PCH_HDA_HDCTL), 1, (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_HDCTL) ); } /// /// PCH BIOS Spec Rev 0.5.0 Section 19.4 /// Step 29 /// Set RCBA + Offset 3A6Ch[31:0] = 0x00000001, after step #26 to #28 are done /// MmioWrite32 ( (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A6C), (UINT32) (0x00000001) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A6C), 1, (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A6C) ); if (PchSeries == PchH) { /// /// PCH BIOS Spec Rev 0.5.5, Section 19.4 Additional Power Management Programming /// Step 30 /// Set RCBA + Offset 2344h[31:24] = 0xFF /// Set RCBA + Offset 2344h[7:0] = 0x0C /// Data32And = (UINT32)~(0xFF00000F); Data32Or = (UINT32) (0xFF00000C); MmioAndThenOr32 ( (UINTN) (RootComplexBar + 0x2344), Data32And, Data32Or ); SCRIPT_MEM_READ_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + 0x2344), &Data32Or, // Data to be ORed &Data32And // Data to be ANDed ); } else if (PchSeries == PchLp) { /// /// PCH BIOS Spec Rev 0.3.0 Section 31.7.2 /// Step 5 /// Set RCBA + Offset 2618h [25] = 1b. /// MmioOr32 ( (UINTN) (RootComplexBar + 0x2618), (UINT32) (BIT25) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + 0x2618), 1, (VOID *) (UINTN) (RootComplexBar + 0x2618) ); } /* // [ EIP357393 ]+>>> /// /// SPI Flash Programming Guide Section 5.5.1 Flash Configuration Lockdown /// It is strongly recommended that BIOS sets the Host and GbE Flash Configuration Lock-Down (FLOCKDN) /// bits (located at SPIBAR + 04h and MBAR + 04h respectively) to 1 on production platforms /// if (PchSeries == PchH) { MmioOr16 ((UINTN) (RootComplexBar + R_PCH_SPI_HSFS), (UINT16) (B_PCH_SPI_HSFS_FLOCKDN + B_PCH_SPI_PRR3PRR4_LOCKDN)); } else if (PchSeries == PchLp) { MmioOr16 ((UINTN) (RootComplexBar + R_PCH_SPI_HSFS), (UINT16) (B_PCH_SPI_HSFS_FLOCKDN)); } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (RootComplexBar + R_PCH_SPI_HSFS), 1, (VOID *) (UINTN) (RootComplexBar + R_PCH_SPI_HSFS) ); */ // [ EIP357393 ]+<<< /// /// Set the GbE Flash Configuration Lock-Down (FLOCKDN) bit (MBAR + 04h[15]) to 1 /// if (PchPlatformPolicy->DeviceEnabling->Lan == PCH_DEVICE_ENABLE) { PciD25F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 25, 0, 0); /// /// Enable memory space decoding in command register /// Data16And = 0xFFFF; Data16Or = (UINT16) B_PCH_LAN_CMD_MSE; MmioOr16 (PciD25F0RegBase + R_PCH_LAN_CMD, Data16Or); SCRIPT_MEM_READ_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD25F0RegBase + R_PCH_LAN_CMD), &Data16Or, // Data to be ORed &Data16And // Data to be ANDed ); /* // [ EIP357393 ]+>>> GbEMemBar = MmioRead32 (PciD25F0RegBase + R_PCH_LAN_MBARB) & B_PCH_LAN_MBARB_BA; /// /// Assert if the memory data of GbEMemBar is invalid. /// if (MmioRead32 (GbEMemBar) == 0xFFFFFFFF) { ASSERT (FALSE); } else { SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD25F0RegBase + R_PCH_LAN_MBARB), 1, (VOID *) (UINTN) (PciD25F0RegBase + R_PCH_LAN_MBARB) ); MmioOr16 (GbEMemBar + 0x04, BIT15); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (GbEMemBar + 0x04), 1, (VOID *) (UINTN) (GbEMemBar + 0x04) ); } */ // [ EIP357393 ]+<<< /// /// PCH BIOS Spec Rev 0.5.0 Section 10.5 Additional GbE Controller Configurations for WOL Support /// System BIOS requires to program the registers listed below for internal GbE. /// Step 1, Set MBARA + Offset 2Ch [31] = 1b /// Step 2, If WOL is enabled set MBARA + Offset 2Ch [30] = 1b /// else if disabled set MBARA + Offset 2Ch [30] = 0b /// /// Additional Steppings: /// Set MBARA + Offset 10h [31] = 1b /// GbEMemBar = MmioRead32 (PciD25F0RegBase + R_PCH_LAN_MEM_BASE_A) & B_PCH_LAN_MBARA_BA; /// /// Assert if the memory data of GbEMemBar is invalid. /// if (MmioRead32 (GbEMemBar) == 0xFFFFFFFF) { ASSERT (FALSE); } else { SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD25F0RegBase + R_PCH_LAN_MEM_BASE_A), 1, (VOID *) (UINTN) (PciD25F0RegBase + R_PCH_LAN_MEM_BASE_A) ); MmioOr32 (GbEMemBar + 0x2c, (BIT31)); if (PchPlatformPolicy->MiscPmConfig->WakeConfig.WolEnableOverride) { MmioOr32 (GbEMemBar + 0x2c, (BIT30)); } else { MmioAnd32 (GbEMemBar + 0x2c, (UINT32) (~BIT30)); } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (GbEMemBar + 0x2c), 1, (VOID *) (UINTN) (GbEMemBar + 0x2c) ); /// /// Set GbEMemBar + 0x10[31] to 1b if Gbe Clkreq is in native mode (0b) /// if (PchSeries == PchLp) { GbeRootPortNumber = PchGetGbePortNumber(); Data32 = (IoRead32 ((UINTN) (GpioBase + R_PCH_GP_X_CONFIG0(18 + GbeRootPortNumber))) & B_PCH_GPIO_OWN0_GPIO_USE_SEL); if (Data32 == 0) { MmioOr32 (GbEMemBar + 0x10, BIT31); } else { MmioAnd32 (GbEMemBar + 0x10, (UINT32) (~BIT31)); } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (GbEMemBar + 0x10), 1, (VOID *) (UINTN) (GbEMemBar + 0x10) ); } } } /// /// PCH BIOS Spec Rev 0.5.0 section 14.1.7 Additional Programming Requirements during /// SATA Initialization /// Step 11 /// Program D31:F2:98h [29] to 1b /// PciD31F2RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 2, 0); MmioOr32 ((UINTN) (PciD31F2RegBase + 0x98), BIT29); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + 0x98), 1, (VOID *) (UINTN) (PciD31F2RegBase + 0x98) ); /// /// Step 14 /// Program D31:F2:9Ch [31] to 1b /// MmioOr32 ((UINTN) (PciD31F2RegBase + 0x9C), BIT31); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD31F2RegBase + 0x9C), 1, (VOID *) (UINTN) (PciD31F2RegBase + 0x9C) ); /// /// Do the Pcie ASPM enable prior to the end of POST /// /// PCH BIOS Spec Rev 0.5.0, Section 8.3.1 ASPM on DMI and the PCI Express* Root Ports /// /// Allcoate and Copy the entire Aspm override table pointed by DevAspmOverride to < 4G EfiReservedMemory /// It's for S3 resume used. /// DevAspmOverrideTblSize = PchPlatformPolicy->PciExpressConfig->NumOfDevAspmOverride * sizeof (PCH_PCIE_DEVICE_ASPM_OVERRIDE); S3DevAspmOverrideTbl = AllocateReservedCopyPool ( DevAspmOverrideTblSize, PchPlatformPolicy->PciExpressConfig->DevAspmOverride ); ASSERT_EFI_ERROR (S3DevAspmOverrideTbl != NULL); /// /// Allcoate and Copy the entire LTR override table pointed by DevLtrOverride to < 4G EfiReservedMemory /// It's used for S3 resume used. /// DevLtrOverrideTbl = PchPlatformPolicy->PwrOptConfig->DevLtrOverride; NumOfDevltrOverride = PchPlatformPolicy->PwrOptConfig->NumOfDevLtrOverride; if ((DevLtrOverrideTbl != NULL) && (NumOfDevltrOverride != 0)) { DevLtrOverrideTblSize = NumOfDevltrOverride * sizeof (PCH_PCIE_DEVICE_LTR_OVERRIDE); S3DevLtrOverrideTbl = AllocateReservedCopyPool ( DevLtrOverrideTblSize, DevLtrOverrideTbl ); ASSERT_EFI_ERROR (S3DevLtrOverrideTbl != NULL); } /// /// Check all the enabled root ports and end point devices if they support Clkreq Per Port, L1 and L1 substates /// for (PortIndex = 0; PortIndex < GetPchMaxPciePortNum (); PortIndex++) { RPBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, GetPchPcieRpfn(RootComplexBar, PortIndex), 0); if (((FuncDisableReg & (B_PCH_RCRB_FUNC_DIS_PCI_EX_PORT1 << PortIndex)) == 0) && ((MmioRead16 (RPBase + R_PCH_PCIE_SLSTS) & B_PCH_PCIE_SLSTS_PDS) != 0)) { RootPortAspmVal = PchPlatformPolicy->PciExpressConfig->RootPort[PortIndex].Aspm; L1SubVal = PchPcieL1SubstatesL1_1_2; if (PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_2) { L1SubVal = PchPlatformPolicy->PciExpressConfig->RootPort[PortIndex].L1Substates; } Status = PcieCheckPmConfig ( PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, GetPchPcieRpfn(RootComplexBar, PortIndex), RootPortAspmVal, PchPlatformPolicy->PciExpressConfig->NumOfDevAspmOverride, PchPlatformPolicy->PciExpressConfig->DevAspmOverride, PchPlatformPolicy->PciExpressConfig->TempRootPortBusNumMin, PchPlatformPolicy->PciExpressConfig->TempRootPortBusNumMax, NumOfDevltrOverride, DevLtrOverrideTbl, &(PchPlatformPolicy->PwrOptConfig->PchPwrOptPcie[PortIndex]), &L1SubstatesSupportedPerPort, L1SubVal, PchPlatformPolicy->Revision, &AspmVal, &ClkreqPerPortSupported, &LtrSupported ); if ((AspmVal & V_PCH_PCIE_LCTL_APMC_L1) != V_PCH_PCIE_LCTL_APMC_L1) { L1SupportedInAllEnabledPorts = FALSE; } ClkreqSupportedInAllEnabledPorts &= ClkreqPerPortSupported; } } for (PortIndex = 0; PortIndex < GetPchMaxPciePortNum (); PortIndex++) { if ((FuncDisableReg & (B_PCH_RCRB_FUNC_DIS_PCI_EX_PORT1 << PortIndex)) == 0) { S3PchPwrOptPcie = AllocateReservedCopyPool ( sizeof (PCH_PCIE_PWR_OPT), &PchPlatformPolicy->PwrOptConfig->PchPwrOptPcie[PortIndex] ); ASSERT_EFI_ERROR (S3PchPwrOptPcie != NULL); RootPortAspmVal = PchPlatformPolicy->PciExpressConfig->RootPort[PortIndex].Aspm; L1SubVal = PchPcieL1SubstatesL1_1_2; if (PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_2) { L1SubVal = PchPlatformPolicy->PciExpressConfig->RootPort[PortIndex].L1Substates; } Status = PcieSetPm ( PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, GetPchPcieRpfn(RootComplexBar, PortIndex), RootPortAspmVal, PchPlatformPolicy->PciExpressConfig->NumOfDevAspmOverride, PchPlatformPolicy->PciExpressConfig->DevAspmOverride, PchPlatformPolicy->PciExpressConfig->TempRootPortBusNumMin, PchPlatformPolicy->PciExpressConfig->TempRootPortBusNumMax, NumOfDevltrOverride, DevLtrOverrideTbl, &(PchPlatformPolicy->PwrOptConfig->PchPwrOptPcie[PortIndex]), &L1SubstatesSupportedPerPort, L1SubVal, PchPlatformPolicy->Revision, FirstRPToSetPm, L1SupportedInAllEnabledPorts, ClkreqSupportedInAllEnabledPorts, &LtrSupported ); Status = SetPciePmS3Item ( PchPlatformPolicy->BusNumber, PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, GetPchPcieRpfn(RootComplexBar, PortIndex), RootPortAspmVal, PchPlatformPolicy->PciExpressConfig->NumOfDevAspmOverride, S3DevAspmOverrideTbl, PchPlatformPolicy->PciExpressConfig->TempRootPortBusNumMin, PchPlatformPolicy->PciExpressConfig->TempRootPortBusNumMax, NumOfDevltrOverride, S3DevLtrOverrideTbl, S3PchPwrOptPcie, L1SubVal, PchPlatformPolicy->Revision, FirstRPToSetPm, L1SupportedInAllEnabledPorts, ClkreqSupportedInAllEnabledPorts ); FirstRPToSetPm = FALSE; } } /// /// LPT-LP only: If not all devices support LTR, set RCBA + 0x3320 to 0x00010003 /// if (!LtrSupported && (PchSeries == PchLp) ) { MmioAndThenOr32 ( (RootComplexBar + 0x3320), 0, 0x00010003); } /// /// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock /// It is strongly recommended that BIOS sets the Vendor Component Lock (VCL) bits. VCL applies /// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Without the VCL bits set, it is /// possible to make Host/GbE VSCC register(s) changes in that can cause undesired host and /// integrated GbE Serial Flash functionality. /// MmioOr32 ((UINTN) (RootComplexBar + R_PCH_SPI_VSCC0), B_PCH_SPI_VSCC0_VCL); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_SPI_VSCC0), 1, (VOID *) (UINTN) (RootComplexBar + R_PCH_SPI_VSCC0) ); /// /// PCH BIOS Spec Rev 0.5.0, Section 19.4 Additional Power Management Programming /// Step 3 /// Set GEN_PMCON_LOCK register, D31:F0:A6h = 06h, after stretch and ACPI base programming completed. /// MmioOr8 ( (UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_LOCK), (UINT8) (B_PCH_LPC_GEN_PMCON_LOCK_S4_STRET_LD | B_PCH_LPC_GEN_PMCON_LOCK_ABASE_LK) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_LOCK), 1, (VOID *) (UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_LOCK) ); /// /// PCH BIOS Spec Rev 0.5.0, Section 3.6 Flash Security Recommendation /// Step 1 /// Intel strongly recommends that BIOS enables the BIOS Lock Enable (BLE) feature of the PCH. /// Left to platform code to register an callback function to handle IchnBiosWp SMI /// /// Step 2 /// Intel strongly recommends that BIOS enables SMI_LOCK (B0:D31:F0:Offset A0h [4]=1) /// which prevent writes to the Global SMI Enable bit (GLB_SMI_EN PMBASE + 30h Bit /// [0]). Enabling this bit will mitigate malicious software attempts to gain system management /// mode privileges. /// if (PchPlatformPolicy->LockDownConfig->GlobalSmi == PCH_DEVICE_ENABLE) { /// /// Save Global SMI Enable bit setting before BIOS enables SMI_LOCK during S3 resume /// Data32Or = IoRead32 ((UINTN) (PmBase + R_PCH_SMI_EN)); if ((Data32Or & B_PCH_SMI_EN_GBL_SMI) != 0) { Data32And = 0xFFFFFFFF; Data32Or &= B_PCH_SMI_EN_GBL_SMI; SCRIPT_IO_READ_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PmBase + R_PCH_SMI_EN), &Data32Or, // Data to be ORed &Data32And // Data to be ANDed ); } MmioOr8 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), B_PCH_LPC_GEN_PMCON_SMI_LOCK); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), 1, (VOID *) (UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1) ); } /// /// Step 3 /// Intel strongly recommends that BIOS sets the BIOS Interface Lock Down bit /// (RCBA+3410[0]=1 General Control and Status - BILD). Setting this bit will prevent writes /// to the Backup Control Register Top Swap bit (BUC.TS RCBA + 3414 [0]) and the General /// Control and Status Registers Boot BIOS Straps (RCBA + 3410h [11:10]). Enabling this bit /// will mitigate malicious software attempts to replace the system BIOS option ROM with its own code. /// if (PchPlatformPolicy->LockDownConfig->BiosInterface == PCH_DEVICE_ENABLE) { MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_GCS), (UINT32) B_PCH_RCRB_GCS_BILD); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_GCS), 1, (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_GCS) ); /// /// Reads back for posted write to take effect /// Data32Or = MmioRead32 ((UINTN) (RootComplexBar + R_PCH_RCRB_GCS)); SCRIPT_MEM_POLL ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_GCS), &Data32Or, // BitMask &Data32Or, // BitValue 1, // Duration 1 // LoopTimes ); } /// /// PCH EDS Rev 1.0, Section 14.1.35.1.2 /// SATA Indexed Register 1Ch Bit18, 1 = This bit allows entrance to the PCH SATA test modes when set. /// This bit should only be set when following the PCH MSQT for system board testing. /// It is recommended to set this bit manually. /// /// /// PCH BIOS Spec Rev 0.5.0, Section 5.15 IntelR Stable Image Platform Program (SIPP) /// For platforms supporting Intel(R) SIPP, System BIOS will need to enable the CRID feature by: /// Write the value 1Dh to to the RevID field in B0:D31:F0 Offset 08h /// /// /// Update CRID FVI record /// mPchFviElementsData[CRID_ORIGINAL].Element.Version.BuildNum = (UINT16) MmioRead8 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_RID)); if (PchPlatformPolicy->DeviceEnabling->Crid == PCH_DEVICE_ENABLE) { Data8 = 0x1D; MmioWrite8 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_RID), Data8); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F0RegBase + R_PCH_LPC_RID), 1, &Data8 ); CopyMem (mPchFviElementsData[CRID_STATUS].Element.VerString, StrEnabled, sizeof (StrEnabled)); } else { CopyMem (mPchFviElementsData[CRID_STATUS].Element.VerString, StrDisabled, sizeof (StrDisabled)); } mPchFviElementsData[CRID_NEW].Element.Version.BuildNum = (UINT16) MmioRead8 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_RID)); /// /// PCH BIOS Spec Rev 0.5.0, Section 16.4 GPIO Registers Lockdown /// If GPIO configurations are not used after boot, it is recommended that the GLE Lockdown Enable /// and the GPIO_UNLOCK_SMI_EN bits are set by BIOS prior to end of POST. /// if (PchPlatformPolicy->LockDownConfig->GpioLockDown == PCH_DEVICE_ENABLE) { /// /// Set GPIO Lockdown Enable bit /// MmioOr8 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GPIO_CNT), (UINT8) B_PCH_LPC_GPIO_LOCKDOWN_EN); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F0RegBase + R_PCH_LPC_GPIO_CNT), 1, (VOID *) (UINTN) (PciD31F0RegBase + R_PCH_LPC_GPIO_CNT) ); /// /// Please locate SMM ICHn SMI Dispatch Extended Protocol and register the callback function to /// IchnExGpioUnlock to set GPIO_UNLOCK_SMI_EN bit in the platform code. /// } /// /// PCH BIOS Spec Rev 0.5.0, Section 5.13 BIOS guide on using RTC RAM /// For Data integrity protection, set RTC Memory locks (Upper 128 Byte Lock and /// Lower 128 Byte Lock) at RCBA + 3400h[4] and RCBA + 3400h[3]. Note once locked /// bytes 0x38 - 0x3F in each of the Upper and Lower Byte blocks, respectively, /// cannot be unlocked until next reset. /// if (PchPlatformPolicy->LockDownConfig->RtcLock == PCH_DEVICE_ENABLE) { MmioOr32 ( (UINTN) (RootComplexBar + R_PCH_RCRB_RTC_CONF), (UINT32) (B_PCH_RCRB_RTC_CONF_UCMOS_LOCK | B_PCH_RCRB_RTC_CONF_LCMOS_LOCK) ); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_RTC_CONF), 1, (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_RTC_CONF) ); } /// /// /// PCH BIOS Spec Rev 0.5.0, Section 3.6 Flash Security Recommendation /// Step 1 /// BIOS needs to enable the BIOS Lock Enable (BLE) feature of the PCH by setting /// B0:D31:F0:DCh[1] = 1b. When this bit is set, attempts to write the BIOS Write /// Enable (BIOSWE) bit in PCH will cause a SMI which will allow the BIOS to verify /// that the write is from a valid source. Remember that BIOS needs to set B0:D31:F0 /// Offset DC [0] = 0b to enable BIOS region protection before exiting the SMI handler. /// Also, TCO_EN bit needs to be set (SMI_EN Register, PMBASE + 30h[13] = 1b) to keep /// BLE feature enabled after booting to the OS. /// /// Generate PCH IO TRAP SMI to register IchnBiosWp callback function in /// PchBiosLockIoTrapCallback() to handle TCO BIOSWR SMI /// if ((PchPlatformPolicy->LockDownConfig->BiosLock == PCH_DEVICE_ENABLE)) { DEBUG ( (EFI_D_ERROR, "PchBiosLockIoTrapAddress = 0x%x\n", PchPlatformPolicy->LockDownConfig->PchBiosLockIoTrapAddress) ); if (PchPlatformPolicy->LockDownConfig->PchBiosLockIoTrapAddress != 0) { /// /// Write PCH_BWP_SIGNATURE to IoTrap Address /// IoWrite32 (PchPlatformPolicy->LockDownConfig->PchBiosLockIoTrapAddress, PCH_BWP_SIGNATURE); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint8, (UINTN) (PciD31F0RegBase + R_PCH_LPC_BIOS_CNTL), 1, (VOID *) (UINTN) (PciD31F0RegBase + R_PCH_LPC_BIOS_CNTL) ); } } /// /// Lock Down TCO /// Data16And = 0xFFFF; Data16Or = B_PCH_TCO_CNT_LOCK; IoOr16(PmBase + PCH_TCO_BASE + R_PCH_TCO1_CNT, Data16Or); SCRIPT_IO_READ_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PmBase + PCH_TCO_BASE + R_PCH_TCO1_CNT), &Data16Or, // Data to be ORed &Data16And // Data to be ANDed ); /// /// PCH BIOS Spec Rev 0.5.0, Section 5.15.1 Additional Chipset Initialization /// Step 1 /// Set SPIBAR + F0h [0] to 1b /// MmioOr8 ((UINTN) (RootComplexBar + R_PCH_SPI_SRDL), B_PCH_SPI_SRDL_SSL); /// /// Check to disable Smbus controller /// if (PchPlatformPolicy->DeviceEnabling->Smbus == PCH_DEVICE_DISABLE) { MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS), (UINT32) B_PCH_RCRB_FUNC_DIS_SMBUS); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS), 1, (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS) ); /// /// Reads back for posted write to take effect /// Data32Or = MmioRead32 ((UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS)); SCRIPT_MEM_POLL ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS), &Data32Or, // BitMask &Data32Or, // BitValue 1, // Duration 1 // LoopTimes ); } UsbInitBeforeBoot (PchPlatformPolicy); FoundLegacyRaid = FALSE; /// /// Get all PCI IO protocols /// Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (!EFI_ERROR (Status)) { /// /// Find the RAID BIOS by checking each PCI IO handle for RST OPROM /// for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo ); if (EFI_ERROR (Status) || (PciIo->RomImage == NULL)) { /// /// If this PCI device doesn't have a ROM image, skip to the next device. /// continue; } RomImage = PciIo->RomImage; /// /// Get pointer to PCIR structure /// PcirBlockPtr = (PCI_DATA_STRUCTURE *) ((UINTN) RomImage + RomImage->PcirOffset); /// /// Check if we have an RAID BIOS OPROM. /// if ((RomImage->Signature == 0xAA55) && (PcirBlockPtr->ClassCode[0] == 0x00) && (PcirBlockPtr->ClassCode[1] == 0x04) && (PcirBlockPtr->ClassCode[2] == 0x01) ) { mPchFviElementsData[RAID_VER].Element.Version.MajorVersion = (UINT8) ((PcirBlockPtr->CodeRevision & 0xFF00) >> 8); mPchFviElementsData[RAID_VER].Element.Version.MinorVersion = (UINT8) (PcirBlockPtr->CodeRevision & 0x00FF); mPchFviElementsData[RAID_VER].Element.Version.Revision = 0; mPchFviElementsData[RAID_VER].Element.Version.BuildNum = 0; FoundLegacyRaid = TRUE; } } } /// /// Search EFI RST OPROM /// if (FoundLegacyRaid == FALSE) { Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiDriverSupportedEfiVersionProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (!EFI_ERROR (Status)) { for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiComponentName2ProtocolGuid, (VOID **) &ComponentName2 ); if (EFI_ERROR(Status)) { continue; } Status = ComponentName2->GetDriverName (ComponentName2, LANGUAGE_CODE_ENGLISH, &DriverName); if (EFI_ERROR(Status)) { continue; } if ((StrnCmp (DriverName, RstDriverName1, (sizeof (RstDriverName1) / sizeof (CHAR16)) - 1) == 0) || (StrnCmp (DriverName, RstDriverName2, (sizeof (RstDriverName2) / sizeof (CHAR16)) - 1) == 0)) { Status = gBS->HandleProtocol( HandleBuffer[Index], &gEfiDriverSupportedEfiVersionProtocolGuid, (VOID**)&DriverEfiVersion); mPchFviElementsData[RAID_VER].Element.Version.MajorVersion = (UINT8) ((DriverEfiVersion->FirmwareVersion & 0x00FF0000) >> 16); mPchFviElementsData[RAID_VER].Element.Version.MinorVersion = (UINT8) (DriverEfiVersion->FirmwareVersion & 0x000000FF); mPchFviElementsData[RAID_VER].Element.Version.Revision = 0; mPchFviElementsData[RAID_VER].Element.Version.BuildNum = 0; } } } } if (PchSeries == PchLp) { #ifdef SERIAL_IO_FLAG ConfigureSerialIoBeforeBoot(PchPlatformPolicy, RootComplexBar); #endif // SERIAL_IO_FLAG #ifdef ADSP_FLAG ConfigureAudioDspBeforeBoot (PchPlatformPolicy, RootComplexBar); #endif // ADSP_FLAG } // // Update ASL objects // PchUpdateAslObjects (PchPlatformPolicy, RootComplexBar); // // Create RC FVI data hubs // CreateRcFviDatahub (&mPchFviVersionData); } #ifdef EFI_S3_RESUME if (!PchS3Support) { DEBUG ((EFI_D_INFO, "Locating the S3 Support Protocol - PCH Init before Boot\n")); /// /// Get the PCH S3 Support Protocol /// Status = gBS->LocateProtocol ( &gEfiPchS3SupportProtocolGuid, NULL, (VOID **) &PchS3Support ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return; } Status = PchS3Support->ReadyToLock(PchS3Support); if (EFI_ERROR (Status)) { return; } } #endif DEBUG ((EFI_D_INFO, "PchInitBeforeBoot() End\n")); return; } // [ EIP357393 ]+>>> EFI_STATUS EFIAPI PchSpiLockBeforeEndOfDxe ( IN EFI_EVENT Event, IN VOID *Context ) /*++ Routine Description: Locking SPI configuration before End of Dxe Arguments: Event A pointer to the Event that triggered the callback. Context A pointer to private data registered with the callback function. Returns: EFI_SUCCESS The function completed successfully --*/ { EFI_STATUS Status; UINTN NumHandles; EFI_HANDLE *HandleBuffer; UINTN Index; DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy; UINT32 RootComplexBar; UINTN PciD25F0RegBase; UINT32 GbEMemBar; PCH_SERIES PchSeries = GetPchSeries(); // UINT32 Data32And; // UINT32 Data32Or; UINT16 Data16And; UINT16 Data16Or; // UINT8 Data8; VOID *ProtocolPointer; // // Check whether this is real AMI ExtPciBusProtocol notification, or just a SignalEvent // Status = gBS->LocateProtocol (&gAmiExtPciBusProtocolGuid, NULL, &ProtocolPointer); if (EFI_ERROR (Status)) { return EFI_SUCCESS; } // // Closed the event to avoid call twice when launch shell // gBS->CloseEvent (Event); // // Retrieve all instances of PCH Platform Policy protocol // Status = gBS->LocateHandleBuffer ( ByProtocol, &gDxePchPlatformPolicyProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Failed to locate handle buffer for PCH Policy protocol.\n")); return Status; } // // Find the matching PCH Policy protocol // for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gDxePchPlatformPolicyProtocolGuid, &PchPlatformPolicy ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Failed to find PCH Policy protocol.\n")); return Status; } RootComplexBar = PCH_RCRB_BASE; /// /// SPI Flash Programming Guide Section 5.5.1 Flash Configuration Lockdown /// It is strongly recommended that BIOS sets the Host and GbE Flash Configuration Lock-Down (FLOCKDN) /// bits (located at SPIBAR + 04h and MBAR + 04h respectively) to 1 on production platforms /// if (PchSeries == PchH) { MmioOr16 ((UINTN) (RootComplexBar + R_PCH_SPI_HSFS), (UINT16) (B_PCH_SPI_HSFS_FLOCKDN + B_PCH_SPI_PRR3PRR4_LOCKDN)); } else if (PchSeries == PchLp) { MmioOr16 ((UINTN) (RootComplexBar + R_PCH_SPI_HSFS), (UINT16) (B_PCH_SPI_HSFS_FLOCKDN)); } SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (RootComplexBar + R_PCH_SPI_HSFS), 1, (VOID *) (UINTN) (RootComplexBar + R_PCH_SPI_HSFS) ); // // Set the GbE Flash Configuration Lock-Down (FLOCKDN) bit (MBAR + 04h[15]) to 1 // if (PchPlatformPolicy->DeviceEnabling->Lan == PCH_DEVICE_ENABLE) { PciD25F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 25, 0, 0); GbEMemBar = MmioRead32 (PciD25F0RegBase + R_PCH_LAN_MBARB) & B_PCH_LAN_MBARB_BA; if (GbEMemBar) { // // Enable memory space decoding in command register // Data16And = 0xFFFF; Data16Or = (UINT16) B_PCH_LAN_CMD_MSE; MmioOr16 (PciD25F0RegBase + R_PCH_LAN_CMD, Data16Or); SCRIPT_MEM_READ_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (PciD25F0RegBase + R_PCH_LAN_CMD), &Data16Or, // Data to be ORed &Data16And // Data to be ANDed ); /// /// Assert if the memory data of GbEMemBar is invalid. /// if (MmioRead32 (GbEMemBar) == 0xFFFFFFFF) { ASSERT (FALSE); } else { SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint32, (UINTN) (PciD25F0RegBase + R_PCH_LAN_MBARB), 1, (VOID *) (UINTN) (PciD25F0RegBase + R_PCH_LAN_MBARB) ); MmioOr16 (GbEMemBar + 0x04, BIT15); SCRIPT_MEM_WRITE ( EFI_ACPI_S3_RESUME_SCRIPT_TABLE, EfiBootScriptWidthUint16, (UINTN) (GbEMemBar + 0x04), 1, (VOID *) (UINTN) (GbEMemBar + 0x04) ); } } } } return EFI_SUCCESS; } // [ EIP357393 ]+<<<