diff options
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchPm.c')
-rw-r--r-- | ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchPm.c | 3389 |
1 files changed, 3389 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchPm.c b/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchPm.c new file mode 100644 index 0000000..b2f53d7 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchPm.c @@ -0,0 +1,3389 @@ +/** @file + Initializes PCH power management features. +@copyright + Copyright (c) 1999 - 2013 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" + +/** + Set an PCH IOBP programming S3 dispatch item, this function may assert if any error happend + + @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 + + @retval EFI_SUCCESS The function completed successfully + @retval EFI_OUT_OF_RESOURCES Out of resources + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_NOT_FOUND Protocol interface not found +**/ +EFI_STATUS +SetProgramIobpS3Item ( + IN UINT32 RootComplexBar, + IN UINT32 Address, + IN UINT32 AndMask, + IN UINT32 OrMask + ) +{ + EFI_STATUS Status; +#ifdef EFI_S3_RESUME + STATIC EFI_PCH_S3_SUPPORT_PROTOCOL *PchS3Support; + STATIC EFI_PCH_S3_PARAMETER_PROG_IOBP S3ParameterProgramIobp; + STATIC EFI_PCH_S3_DISPATCH_ITEM S3DispatchItem = { + PchS3ItemTypeProgramIobp, + &S3ParameterProgramIobp + }; + EFI_PHYSICAL_ADDRESS S3DispatchEntryPoint; + + if (!PchS3Support) { + /// + /// Get the PCH S3 Support Protocol + /// + Status = gBS->LocateProtocol ( + &gEfiPchS3SupportProtocolGuid, + NULL, + (VOID **) &PchS3Support + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + } + + S3ParameterProgramIobp.RootComplexBar = RootComplexBar; + S3ParameterProgramIobp.Address = Address; + S3ParameterProgramIobp.AndMask = AndMask; + S3ParameterProgramIobp.OrMask = OrMask; + 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; +} + +/** + Locking Thermal Reporting Settings + + @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance + @param[in] GpioBase GPIO base address of this PCH device + + @retval EFI_SUCCESS The function completed successfully +**/ +EFI_STATUS +ThermalLockDown ( + IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, + UINT16 GpioBase + ) +{ + UINTN PciD31F6RegBase; + UINTN PciD31F2RegBase; + UINT32 ThermalBaseB; + UINT32 ThermalBase; + EFI_PHYSICAL_ADDRESS MemBaseAddress; + EFI_STATUS Status; + UINT8 Index; + UINT8 RegData8; + UINT16 RegData16; + UINT32 RegData32; + UINT32 RootComplexBar; + UINT32 Data32And; + UINT32 Data32Or = 0; + UINT16 Data16And; + UINT16 Data16Or; + UINT32 PchTTLevels = 0; + BOOLEAN PchHotEnable; + PCH_SERIES PchSeries; + EFI_CPUID_REGISTER Cpuid; + MSR_REGISTER TempMsr; + UINT32 temperature; + UINT8 MaxSataPortNum; + + DEBUG ((EFI_D_INFO, "ThermalLockDown() Start\n")); + + PchSeries = GetPchSeries(); + /// + /// Check if TBARB is already initialized by platform code + /// + PciD31F6RegBase = MmPciAddress ( + 0, + PchPlatformPolicy->BusNumber, + PCI_DEVICE_NUMBER_PCH_THERMAL, + PCI_FUNCTION_NUMBER_PCH_THERMAL, + 0 + ); + PciD31F2RegBase = MmPciAddress ( + 0, + PchPlatformPolicy->BusNumber, + PCI_DEVICE_NUMBER_PCH_SATA, + PCI_FUNCTION_NUMBER_PCH_SATA, + 0 + ); + RootComplexBar = PCH_RCRB_BASE; + ThermalBaseB = MmioRead32 (PciD31F6RegBase + R_PCH_THERMAL_TBARB); + MemBaseAddress = 0x0ffffffff; + + if (ThermalBaseB & B_PCH_THERMAL_SPTYPEN) { + /// + /// Check if TBARB is already initialized and if so use it. + /// + ThermalBaseB &= B_PCH_THERMAL_TBARB_MASK; + } else { +#ifndef AMI_OVERRIDE_FOR_PCH + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMemoryTypeMemoryMappedIo, + N_PCH_THREMAL_TBARB_ALIGNMENT, + V_PCH_THERMAL_TBARB_SIZE, + &MemBaseAddress, + mImageHandle, + NULL + ); +#else + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchBottomUp, + EfiGcdMemoryTypeMemoryMappedIo, + N_PCH_THREMAL_TBARB_ALIGNMENT, + V_PCH_THERMAL_TBARB_SIZE, + &MemBaseAddress, + mImageHandle, + NULL + ); +#endif + if (EFI_ERROR (Status)) { + return Status; + } + + ThermalBaseB = (UINT32) MemBaseAddress; + MmioWrite32 (PciD31F6RegBase + R_PCH_THERMAL_TBARB, ThermalBaseB); + MmioWrite32 (PciD31F6RegBase + R_PCH_THERMAL_TBARBH, 0); + MmioOr32 (PciD31F6RegBase + R_PCH_THERMAL_TBARB, (UINT32) B_PCH_THERMAL_SPTYPEN); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBARB), + 1, + (VOID *) (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBARB) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBARBH), + 1, + (VOID *) (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBARBH) + ); + } + /// + /// PCH BIOS Spec Rev 0.5.0, 17.3.1 Initializing Lynx Point Thermal Sensors + /// Step 1 + /// TSC must then be written to 0x81 to enable the power down and lock the register. + /// + RegData8 = MmioRead8 (ThermalBaseB + R_PCH_TBARB_TSC); + /// + /// Enable Catastrophic Power Down + /// + RegData8 |= (UINT8) B_PCH_TBARB_TSC_CPDE; + /// + /// Step 8.1 + /// It is recommended that TSC [7] set to 1 to lock the CAT Trip behavior. + /// + if (PchPlatformPolicy->ThermalConfig->ThermalAlertEnable.TscLock == PCH_DEVICE_ENABLE) { + RegData8 |= (UINT8) B_PCH_TBARB_TSC_PLD; + } + + MmioWrite8 (ThermalBaseB + R_PCH_TBARB_TSC, RegData8); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TSC), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TSC) + ); + /// + /// Step 8.2 + /// TSMIC [7] locks SMI reporting of thermal events + /// + if (PchPlatformPolicy->ThermalConfig->ThermalAlertEnable.TsmicLock == PCH_DEVICE_ENABLE) { + MmioWrite8 (ThermalBaseB + R_PCH_TBARB_TSMIC, 0x80); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TSMIC), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TSMIC) + ); + } + + /// + /// Step 5 + /// If the PCH_Hot pin reporting is supported, then write the temperature value and set the enable in PHL. + /// + PchHotEnable = FALSE; +#ifdef TRAD_FLAG + if (PchSeries == PchH) { + /// + /// Note: For PCHHOT# support, we need to make sure if GPIO74 is set to native mode and PCHSTRP9[22] is + /// set to 1. + /// Check if GPIO74 is set to native mode. + /// + RegData8 = (UINT8)((IoRead32 ((UINTN) (GpioBase + R_PCH_GPIO_USE_SEL3)) & BIT10) >> 10); + } +#endif // TRAD_FLAG + +#ifdef ULT_FLAG + if (PchSeries == PchLp) { + /// + /// Note: For PCHHOT# support, we need to make sure if GPIO73 is set to native mode and PCHSTRP9[22] is + /// set to 1. + /// Check if GPIO73 is set to native mode. + /// + RegData8 = (UINT8)(IoRead32 ((UINTN) (GpioBase + R_PCH_GP_73_CONFIG0)) & B_PCH_GPIO_OWN0_GPIO_USE_SEL); + } +#endif // ULT_FLAG + + if(RegData8 == 0x00) { + /// + /// Check if PCHSTRP9[22] is set to 1 (PCHHOT# is the native functionality of GPIO74) + /// + if ((MmioRead16 (RootComplexBar + R_PCH_SPI_HSFS) & B_PCH_SPI_HSFS_FDV) == B_PCH_SPI_HSFS_FDV) { + MmioAnd32 ((RootComplexBar + R_PCH_SPI_FDOC), (UINT32) (~(B_PCH_SPI_FDOC_FDSS_MASK | B_PCH_SPI_FDOC_FDSI_MASK))); + MmioOr32 ((RootComplexBar + R_PCH_SPI_FDOC), (UINT32) (V_PCH_SPI_FDOC_FDSS_PCHS | R_PCH_SPI_STRP9)); + if (MmioRead32 (RootComplexBar + R_PCH_SPI_FDOD) & B_PCH_SPI_STRP9_HOT_SML1_SEL) { + PchHotEnable = TRUE; + } + } + } + + /// + /// The value in PHL register is valid only if it is between 00h and 1FFh. + /// + if ((PchHotEnable == TRUE) && (PchPlatformPolicy->ThermalConfig->PchHotLevel < 0x0200)) { + /// + /// Program PHL register according to PchHotLevel setting. + /// + RegData16 = (PchPlatformPolicy->ThermalConfig->PchHotLevel | B_PCH_TBARB_PHLE); + MmioWrite16 (ThermalBaseB + R_PCH_TBARB_PHL, RegData16); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (ThermalBaseB + R_PCH_TBARB_PHL), + 1, + &RegData16 + ); + } + /// + /// Step 8.3 + /// PHLC [0] locks the PHL and PHLC registers for PCH_Hot# + /// + if (PchPlatformPolicy->ThermalConfig->ThermalAlertEnable.PhlcLock == PCH_DEVICE_ENABLE) { + MmioWrite8 (ThermalBaseB + R_PCH_TBARB_PHLC, 0x01); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (ThermalBaseB + R_PCH_TBARB_PHLC), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_PHLC) + ); + } + /// + /// PCH BIOS Spec Rev 0.5.0, Section 17.5 Thermal Throttling + /// Step 1 + /// Additional programming to initialize Thermal Throttle device + /// For LPT-H, + /// a. Program ThermalBAR + 0xC0 to 8000390Bh + /// b. Program ThermalBAR + 0xC4 to C11F0201h + /// c. Program ThermalBAR + 0xC8 to 05800000h + /// d. Program ThermalBAR + 0xCC to 0000C000h + /// e. Program ThermalBAR + 0xD0 to 00000320h + /// f. Program ThermalBAR + 0xE0 to 80001E4Fh + /// g. Program ThermalBAR + 0xF0 to 00000003h + /// For LPT-LP, + /// a. Program ThermalBar + 0xC0 to 8000390Bh + /// b. Program ThermalBar + 0xC4 to C11F0401h + /// c. Program ThermalBAR + 0xC8 to 05800000h + /// d. Program ThermalBar + 0xCC to 0000C000h + /// e. Program ThermalBar + 0xD0 to 00000320h + /// f. Program ThermalBar + 0xE0 to 80001EDCh + /// g. Program ThermalBar + 0xF0 to 00000003h + /// + + if (PchSeries == PchH) { + MmioWrite32 (ThermalBaseB + 0xC4, 0xC11F0201); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xC4), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xC4) + ); + + MmioWrite32 (ThermalBaseB + 0xE0, 0x80001E4F); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xE0), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xE0) + ); + } + + if (PchSeries == PchLp) { + MmioWrite32 (ThermalBaseB + 0xC4, 0xC11F0401); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xC4), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xC4) + ); + + MmioWrite32 (ThermalBaseB + 0xE0, 0x80001EDC); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xE0), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xE0) + ); + } + + MmioWrite32 (ThermalBaseB + 0xC0, 0x8000390B); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xC0), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xC0) + ); + + MmioWrite32 (ThermalBaseB + 0xC8, 0x05800000); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xC8), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xC8) + ); + + MmioWrite32 (ThermalBaseB + 0xCC, 0x0000C000); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xCC), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xCC) + ); + + MmioWrite32 (ThermalBaseB + 0xD0, 0x00000320); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xD0), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xD0) + ); + + MmioWrite32 (ThermalBaseB + 0xF0, 0x00000003); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + 0xF0), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xF0) + ); + /// + /// HSW BWG 15.8 : Processor PCH-LP cross throttling + /// + if (PchSeries == PchLp){ + AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx); + if (((Cpuid.RegEax & CPUID_FULL_FAMILY_MODEL) == CPUID_FULL_FAMILY_MODEL_HASWELL_ULT) && + ((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.PchCrossThrottling == PCH_DEVICE_ENABLE) || + (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.SuggestedSetting == PCH_DEVICE_ENABLE))) { + // + // Read MSR 0x1A2 TEMPERATURE_TARGET + // + TempMsr.Qword = AsmReadMsr64 (MSR_TEMPERATURE_TARGET); + /// + /// Tcc activation offset in temperature target MSR changes from 4 bits [27:24] to 6 bits [29:24] on ULT C step onwards + /// since Tcc will never be more than 205C, thus the calculation for PHL will never overflow + /// + if ((Cpuid.RegEax & CPUID_FULL_STEPPING) >= EnumHswUltC0) { + temperature = (TempMsr.Bytes.ThirdByte - (TempMsr.Bytes.FouthByte & 0x3F)); + } else { + temperature = (TempMsr.Bytes.ThirdByte - (TempMsr.Bytes.FouthByte & 0xF)); + } + + if (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.SuggestedSetting == PCH_DEVICE_ENABLE) { + /// + /// PCH T0/T1/T2 Level (MMIO TBARB+40h) : + /// T0L = (((MSR TEMPERATURE_TARGET[23:16] - TEMPERATURE_TARGET) + 50) * 2) + /// T1L = T0L + 5C + /// T2L = T1L + 5C + /// + PchTTLevels = (UINT32)((( temperature + 10 + 50) * 2) << 20) | + (UINT32)(((temperature + 5 + 50) * 2) << 10) | + (UINT32)((temperature + 50) * 2); + Data32Or = BIT31 | BIT29; + } else { + PchTTLevels = (UINT32) (((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.T2Level + 10 + 50) * 2) << 20) | + (UINT32) (((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.T1Level + 5 + 50) * 2) << 10) | + (UINT32) ((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.T0Level + 50) * 2); + Data32Or = (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.TTLock << 31) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.TTState13Enable << 30) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.TTEnable << 29); + } + } + } else if (PchSeries == PchH) { + if (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.SuggestedSetting == PCH_DEVICE_ENABLE) { + /// + /// Set TBARB + 40h = 0B485093Ch + /// Program TBARB + 40h[31:28] in separate write + /// + PchTTLevels = 0xB485093C; + Data32Or = BIT31 | BIT29; + }else { + /// + /// PCH BIOS Spec Rev 0.5.5, Section 17.3.1 Initializing Lynx Point Thermal Sensors + /// Trip Point Temperature = (Trip Point Register [8:0]) / 2 - 50 centigrade degree + /// If Trip Point Temperature <= T0Level, the system will be in T0 state. + /// If T1Level >= Trip Point Temperature > T0Level, the system will be in T1 state. + /// If T2Level >= Trip Point Temperature > T1Level, the system will be in T2 state. + /// If Trip Point Temperature > T2Level, the system will be in T3 state. + /// + PchTTLevels = (UINT32) (((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.T2Level + 50) * 2) << 20) | + (UINT32) (((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.T1Level + 50) * 2) << 10) | + (UINT32) ((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.T0Level + 50) * 2); + Data32Or = (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.TTLock << 31) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.TTState13Enable << 30) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.TTEnable << 29); + } + } + + /// + /// Program TBARB + 40h[27:0] + /// + MmioWrite32 (ThermalBaseB + R_PCH_TBARB_TL, PchTTLevels); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TL), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TL) + ); + /// + /// Program TBARB + 40h[31:28] + /// + /// PCH BIOS Spec Rev 0.5.0, 17.3.1 Initializing Lynx Point Thermal Sensors + /// Step 8.4 + /// TL [31] locks the thermal throttling registers + /// + MmioOr32 (ThermalBaseB + R_PCH_TBARB_TL, Data32Or); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TL), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TL) + ); + + if (PchSeries == PchLp) { + /// + /// Processor PCH-LP cross throttling - Set RCBA MMIO offset 0x33C4[26:24] = 101b + /// + AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx); + if (((Cpuid.RegEax & CPUID_FULL_FAMILY_MODEL) == CPUID_FULL_FAMILY_MODEL_HASWELL_ULT) && + ((PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.PchCrossThrottling == PCH_DEVICE_ENABLE) || + (PchPlatformPolicy->ThermalConfig->ThermalThrottling.TTLevels.SuggestedSetting == PCH_DEVICE_ENABLE))) { + Data32And = (UINT32)~(BIT26 | BIT25 | BIT24); + Data32Or = BIT26 | BIT24; + MmioAndThenOr32 ((UINTN) (RootComplexBar + PMSYNC_TPR_CONFIG), Data32And, Data32Or); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + PMSYNC_TPR_CONFIG), + 1, + (VOID *) (UINTN) (RootComplexBar + PMSYNC_TPR_CONFIG) + ); + } + /// + /// Lock PMSYNC_TPR_CFG and PMSYNC_TPR_CFG2 + /// Set RCBA + 0x33C4[31] = 1b. + /// + MmioOr32 (RootComplexBar + PMSYNC_TPR_CONFIG,B_PMSYNC_TPR_CONFIG_LOCK); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + PMSYNC_TPR_CONFIG), + 1, + (VOID *) (UINTN) (RootComplexBar + PMSYNC_TPR_CONFIG) + ); + } + + if (PchSeries == PchH) { + /// + /// PCH BIOS Spec Rev 0.5.0, Section 17.5 Thermal Throttling + /// Step 3 + /// Set Chipset Initialization Register 30 (RCBA + 2238h) = 00000941h + /// + if (PchPlatformPolicy->ThermalConfig->ThermalThrottling.DmiHaAWC.SuggestedSetting == PCH_DEVICE_ENABLE) { + RegData32 = 0x00000941; + } else { + RegData32 = (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.DmiHaAWC.TS3TW << 10) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.DmiHaAWC.TS2TW << 8) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.DmiHaAWC.TS1TW << 6) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.DmiHaAWC.TS0TW << 4) | + (UINT32) PchPlatformPolicy->ThermalConfig->ThermalThrottling.DmiHaAWC.DmiTsawEn; + } + /// + /// If DMI IOT is enabled, set chipset Initialization Register 30 (RCBA + 2238h) = 00000551h + /// + if (PchPlatformPolicy->DmiConfig->DmiIot == PCH_DEVICE_ENABLE) { + RegData32 = 0x00000551; + } + MmioWrite32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CIR2238), RegData32); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2238), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2238) + ); + } + + /// + /// Step 4 + /// Program SATA Indexed Register Index and Data: + /// a. If port 0 is empty, set D31:F2:A0h=A0h and D31:F2:A4h[15:00] = 0000h + /// else if Port 0 has a HDD, set D31:F2:A4h[15:00] = 0039h + /// else if Port 0 has a SSD, set D31:F2:A4h[15:00] = 0F39h + /// b. If port 1 is empty, set D31:F2:A0h=A0h and D31:F2:A4h[31:16] = 0000h + /// else if Port 1 has a HDD, set D31:F2:A4h[31:16] = 0039h + /// else if Port 1 has a SSD, set D31:F2:A4h[31:16] = 0F39h + /// c. If port 2 is empty, set D31:F2:A0h=A4h and D31:F2:A4h[15:00] = 0000h + /// else if Port 2 has a HDD, set D31:F2:A4h[15:00] = 0039h + /// else if Port 2 has a SSD, set D31:F2:A4h[15:00] = 0F39h + /// d. If port 3 is empty, set D31:F2:A0h=A4h and D31:F2:A4h[31:16] = 0000h + /// else if Port 3 has a HDD, set D31:F2:A4h[31:16] = 0039h + /// else if Port 3 has a SSD, set D31:F2:A4h[31:16] = 0F39h + /// e. If port 4 is empty, set D31:F2:A0h=A8h and D31:F2:A4h[15:00] = 0000h + /// else if Port 4 has a HDD, set D31:F2:A4h[15:00] = 0039h + /// else if Port 4 has a SSD, set D31:F2:A4h[15:00] = 0F39h + /// f. If port 5 is empty, set D31:F2:A0h=A8h and D31:F2:A4h[31:16] = 0000h + /// else if Port 5 has a HDD, set D31:F2:A4h[31:16] = 0039h + /// else if Port 5 has a SSD, set D31:F2:A4h[31:16] = 0F39h + /// + MaxSataPortNum = GetPchMaxSataPortNum(); + RegData16 = MmioRead16 (PciD31F2RegBase + R_PCH_SATA_PCS); + for (Index = 0; Index < (MaxSataPortNum / 2); Index++) { + Data32And = 0x70C070C0; + Data32Or = 0x00000000; + if (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.SuggestedSetting == PCH_DEVICE_ENABLE) { + if ((RegData16 & (B_PCH_SATA_PCS_PORT0_DET << (Index * 2))) != 0) { + Data32Or |= 0x00000039; + if (PchPlatformPolicy->SataConfig->PortSettings[0 + (Index * 2)].SolidStateDrive == PCH_DEVICE_ENABLE) { + Data32Or |= 0x00000F00; + } + } + + if ((RegData16 & (B_PCH_SATA_PCS_PORT0_DET << ((Index * 2) + 1))) != 0) { + Data32Or |= 0x00390000; + if (PchPlatformPolicy->SataConfig->PortSettings[1 + (Index * 2)].SolidStateDrive == PCH_DEVICE_ENABLE) { + Data32Or |= 0x0F000000; + } + } + } else { + Data32Or = (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P1TDispFinit << 31) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P1Tinact << 26) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P1TDisp << 24) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P1T3M << 20) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P1T2M << 18) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P1T1M << 16) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P0TDispFinit << 15) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P0Tinact << 10) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P0TDisp << 8) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P0T3M << 4) | + (UINT32) (PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P0T2M << 2) | + (UINT32) PchPlatformPolicy->ThermalConfig->ThermalThrottling.SataTT.P0T1M; + } + + MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, (0xA0 + (Index * 4))); + MmioAndThenOr32 ((UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), Data32And, Data32Or); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) + ); + } + + /// + /// Program ThermalBar + 0xA4 [1:0] = 11b + /// + MmioOr8 (ThermalBaseB + 0xA4, (UINT8) (BIT1 | BIT0)); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (ThermalBaseB + 0xA4), + 1, + (VOID *) (UINTN) (ThermalBaseB + 0xA4) + ); + /// + /// PCH BIOS Spec Rev 0.5.0, 17.3.1 Initializing Lynx Point Thermal Sensors + /// Step 7 + /// Enable thermal sensor by programming TSEL register to 01h + /// This should be done after all thermal initialization steps are finished. + /// + RegData8 = MmioRead8 (ThermalBaseB + R_PCH_TBARB_TSEL); + RegData8 |= (UINT8) B_PCH_TBARB_TSEL_ETS; + /// + /// Step 8.5 + /// TSEL [7] locks the thermal sensor enable, after TAHV and TAHL are programmed by BIOS or driver + /// later in case. + /// + if (PchPlatformPolicy->ThermalConfig->ThermalAlertEnable.TselLock == PCH_DEVICE_ENABLE) { + RegData8 |= (UINT8) B_PCH_TBARB_TSEL_PLD; + } + + MmioWrite8 (ThermalBaseB + R_PCH_TBARB_TSEL, RegData8); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TSEL), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TSEL) + ); + /// + /// Step 8.6 + /// Program ThermalBAR + 0x0A [7] = 1b + /// For LP, Program ThermalBar + 0x0A [7, 0] = 1b, 1b + /// + RegData8 = BIT7; + if (PchSeries == PchLp) { + RegData8 |= BIT0; + } + MmioOr8 (ThermalBaseB + R_PCH_TBARB_TSREL, RegData8); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TSREL), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TSREL) + ); + + /// + /// For LP, Program ThermalBar + 0x1C [14:0] = 48C8h + /// For LP, Program ThermalBar + 0x1C [15] = 1h + /// + if (PchSeries == PchLp) { + Data16And = (B_PCH_TBARB_TSPM_LTT | B_PCH_TBARB_TSPM_MAXTSST | B_PCH_TBARB_TSPM_MINTSST | B_PCH_TBARB_TSPM_DTSSIC0 | + B_PCH_TBARB_TSPM_DTSSS0EN); + Data16Or = (V_PCH_TBARB_TSPM_LTT | V_PCH_TBARB_TSPM_MAXTSST | B_PCH_TBARB_TSPM_DTSSS0EN); + MmioAndThenOr16 (ThermalBaseB + R_PCH_TBARB_TSPM, + (UINT16) Data16And, + (UINT16) Data16Or); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TSPM), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TSPM) + ); + + MmioOr16 (ThermalBaseB + R_PCH_TBARB_TSPM, (UINT16) B_PCH_TBARB_TSPM_TSPMLOCK); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (ThermalBaseB + R_PCH_TBARB_TSPM), + 1, + (VOID *) (UINTN) (ThermalBaseB + R_PCH_TBARB_TSPM) + ); + } + + /// + /// PCH BIOS Spec Rev 0.5.0, Section 17.2, Thermal Subsystem Device Initialization + /// Step 5 + /// BIOS needs to perform the following steps prior to end of POST to free up the PCI resources + /// and hide the thermal subsystem device(OPTIONAL), except on mobile platforms that support + /// Intel DPPM. Also, BIOS may keep the TBARBH programmed if BIOS needs runtime access to PCH + /// thermal subsystem device data. In that case, BIOS must ensure TBARBH memory is reserved and + /// reported to the OS as motherboard resources to avoid memory allocation conflicts. + /// + if (PchPlatformPolicy->ThermalConfig->ThermalDeviceEnable == FALSE) { + /// + /// Step 5.1 + /// Clear the Memory and Bus Master enable bit of D31:F6 + /// + MmioAnd16 ( + PciD31F6RegBase + R_PCH_THERMAL_COMMAND, + (UINT16)~(B_PCH_THERMAL_COMMAND_MSE | B_PCH_THERMAL_COMMAND_BME) + ); + /// + /// Step 5.2 + /// Clear and release memory resource assigned in TBAR (D31:F6:10h-13h) + /// + ThermalBase = MmioRead32 (PciD31F6RegBase + R_PCH_THERMAL_TBAR) & B_PCH_THERMAL_TBAR_MASK; + + if ((ThermalBase != 0) && (ThermalBase != B_PCH_THERMAL_TBAR_MASK)) { + MmioWrite32 (PciD31F6RegBase + R_PCH_THERMAL_TBAR, 0); + MmioWrite32 (PciD31F6RegBase + R_PCH_THERMAL_TBARH, 0); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBAR), + 1, + (VOID *) (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBAR) + ); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBARH), + 1, + (VOID *) (UINTN) (PciD31F6RegBase + R_PCH_THERMAL_TBARH) + ); + + gDS->FreeMemorySpace ( + (EFI_PHYSICAL_ADDRESS) ThermalBase, + V_PCH_THERMAL_TBAR_SIZE + ); + } + /// + /// Step 5.3 + /// Optionally, release and clear memory resource assigned in TBARB (D31:F6:40h-48h) if BIOS/ASL + /// implementation does not require access to PCH thermal subsystem device data during run time. + /// Left this to platform code + /// + /// Step 5.4 + /// Hide D31:F6 PCI configuration space by setting FD.TTD (RCBA + 3418h[24]) + /// + Data32And = 0xFFFFFFFF; + Data32Or = (UINT32) B_PCH_RCRB_FUNC_DIS_THERMAL; + MmioOr32 (RootComplexBar + R_PCH_RCRB_FUNC_DIS, Data32Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_FUNC_DIS), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + /// + /// 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 + ); + } + + DEBUG ((EFI_D_INFO, "ThermalLockDown() End\n")); + + return EFI_SUCCESS; +} + +/** + Perform Clock Gating programming + Enables clock gating in various PCH interfaces and the registers must be restored during S3 resume. + + @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance + @param[in] RootComplexBar RootComplexBar value of this PCH device + @param[in] FuncDisableReg The Function Disable Register + + @retval EFI_SUCCESS The function completed successfully +**/ +EFI_STATUS +ConfigureClockGating ( + IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, + IN UINT32 RootComplexBar, + IN UINT32 FuncDisableReg + ) +{ + UINT8 RegData8; + UINT32 RegData32; + UINT32 RegDataOr32; + UINT32 RegDataAnd32; + UINTN PciD31F0RegBase; + UINT16 LpcDeviceId; + UINT16 Data16Or; + PCH_SERIES PchSeries; + UINT32 D2F0Base; + + DEBUG ((EFI_D_INFO, "ConfigureClockGating() Start\n")); + + PchSeries = GetPchSeries(); + PciD31F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 0, 0); + LpcDeviceId = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_DEVICE_ID); + + /// + /// PCH BIOS Spec Rev 0.5.5, section 19.10 + /// 1 + /// DMI interface + /// Enable Dynamic Clock Gating in the DMIC register by programming + /// For PCH LP + /// RCBA + 2234h [2] to 1b, RCBA + 2234h [0] to 1b + /// RCBA + 2234h [3:0] to 1111b + /// Set D31:F0:A0h[5] = 1b + /// Set D31:F0:A0h[6] = 1b + /// Set D31:F0:A0h[7] = 1b + /// Set D31:F0:A0h[11] = 0b + /// Set D31:F0:A0h[12] = 1b + /// For PCH H + /// RCBA + 2234h [3:0] to 1111b + /// Enable Dynamic Clock Gating in the DMIC register by programming RCBA + 2234h [3:0] to 1111b + /// before enabling ASPM. + /// Set D31:F0:A0h[11] = 1b + /// Set D31:F0:A0h[12] = 1b + /// Set D31:F0:A0h[14] = 1b. + /// System BIOS is also required to set following bit. + /// Dekstop: "Pseudo CLKRUN_EN (PSEUDO_CLKRUN_EN)" bit (D31:F0:A0h[3]) = 1b + /// Mobile: "PCI CLKRUN# Enable" bit (D31:F0:A0h[2]) = 1b + /// + switch (PchSeries) { + case PchLp: + MmioOr8 ((UINTN) (RootComplexBar + R_PCH_RCRB_DMIC), (UINT8) (B_PCH_LP_RCRB_DMIC_DMICGEN)); + break; + + case PchH: + MmioOr8 ((UINTN) (RootComplexBar + R_PCH_RCRB_DMIC), (UINT8) (B_PCH_H_RCRB_DMIC_DMICGEN)); + break; + + default: + break; + } + + if (PchSeries == PchLp) { + Data16Or = (UINT16)(BIT12 | BIT7 | BIT6 | BIT5); + Data16Or |= BIT11; + MmioOr16 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), Data16Or); + } else if (PchSeries == PchH) { + MmioOr16 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), (UINT16) (BIT14 | BIT12 | BIT11)); + } + + if (PchPlatformPolicy->DeviceEnabling->PciClockRun == PCH_DEVICE_DISABLE) { + if (IS_PCH_LPT_LPC_DEVICE_ID_MOBILE (LpcDeviceId)) { + MmioAnd16 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), (UINT16) (~B_PCH_LPC_GEN_PMCON_CLKRUN_EN)); + } else { + MmioAnd16 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), (UINT16) (~B_PCH_LPC_GEN_PMCON_PSEUDO_CLKRUN_EN)); + } + } else { + if (IS_PCH_LPT_LPC_DEVICE_ID_MOBILE (LpcDeviceId)) { + MmioOr16 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), (UINT16) (B_PCH_LPC_GEN_PMCON_CLKRUN_EN)); + } else { + MmioOr16 ((UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), (UINT16) (B_PCH_LPC_GEN_PMCON_PSEUDO_CLKRUN_EN)); + } + } + + RegData8 = MmioRead8 (RootComplexBar + R_PCH_RCRB_DMIC); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (RootComplexBar + R_PCH_RCRB_DMIC), + 1, + &RegData8 + ); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1), + 1, + (VOID *) (UINTN) (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1) + ); + + if (PchSeries == PchLp) { + /// + /// Set RCBA + 2614h[27:25],[14:13],[10],[8] = 101b, 11b, 1b, 1b respectively + /// Set RCBA + 2614h[23:16] = 0x20 + /// Set RCBA + 2614h[30:28] = 0b + /// Set RCBA + 2614h[26] = 1b if D2F0+8 >= 0x0B + /// + D2F0Base = MmPciAddress (0, 0, 2, 0, 0); + RegDataAnd32 = (UINT32) ~(BIT30 | BIT29 | BIT28 | BIT26 | 0x00FF0000); + RegDataOr32 = (UINT32) (BIT27 | BIT25 | BIT21 | BIT14 | BIT13 | BIT10 | BIT8); + if ((MmioRead16 (D2F0Base) != 0xFFFF) && (MmioRead8 (D2F0Base + 8) >= 0x0B)) { + RegDataOr32 |= (UINT32) BIT26; + } + MmioAndThenOr32 ( + (UINTN) (RootComplexBar + 0x2614), + RegDataAnd32, + RegDataOr32 + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2614), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2614) + ); + /// + /// Set Chipset Initialization Register 2 [4:0] (RCBA + 900h) = 11111b + /// Set Chipset Initialization Register 2 [9:8] (RCBA + 900h) = 11b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR0900), + (UINT32) (BIT9 | BIT8 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR0900), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR0900) + ); + } else if (PchSeries == PchH) { + /// + /// Set Chipset Initialization Register 2 [14] (RCBA + 900h) = 1b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR0900), + (UINT32) (BIT14) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR0900), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR0900) + ); + } + /// + /// 2 + /// PCI Express* interface + /// 2.1 + /// For each enabled PCI Express* root port, program D28:F0~F7:Reg E1h[1:0] to 3h to enable dynamic clock gating. + /// System BIOS also require to set D28:F0~F7:Reg E8h[0] = 1b + /// 2.2 + /// Additionally, if port 0 is in x2 mode, these bits should not be set for port 1. + /// Likewise, if port 0 is in x4 mode, these bits should not be set for ports 1, 2, or 3 + /// Done in PchRootPorts.c PcieEnableClockGating + /// 2.2.1 + /// If PCIe root ports 0-3 are all disabled, set B0:D28:F0 + E2h[0] = 1b + /// if PCIe root ports 4-7 are all disabled, set B0:D28:F4 + E2h[0] = 1b + /// 2.3 + /// Set B0:D28:F0&F4 + E1h [5:2] = 1111b + /// 2.4 + /// Set B0:D28:F0&F4:E1h[7] = 1b + /// 2.6 + /// Set B0:D28:F0~F7 + 324h[5] = 1b + /// Done in PchRootPorts.c PcieEnableClockGating + /// + /// Reg RCBA+341C is modified at multiple places, save at the end of the function + /// + /// 3 + /// Serial ATA* + /// - Set bits D31:F2:94h[29:24] to 3Fh as part of the chipset initialization before disabling + /// the SATA function when the SATA interface is not supported on the platform. BIOS can also + /// set PCD bits to disable clocks for the un-routed ports on the platform. + /// - After configuring Port and Control Status (PCS) Register Port x Enabled (PxE) bits accordingly, + /// wait 1.4 micro second, then the PCD bits (D31:F2:Reg 94h[29:24]) should be set to be the inverse + /// of the Port and Control Status (PCS) Register Port x Enabled (PxE) bits + /// Please note that PCS should be set and PCD should not be set when ports are enabled for hot + /// plug support or used for SATA testing in test mode. + /// Done in ConfigureSata(); + /// - Program D31:F2:98h[29] to 1b + /// Done in PchInitBeforeBoot() + /// - Set SATA Initialization Register 70h[31:0] = 3F00BF1Fh (Done in ConfigureMiscPm) + /// Set SATA Initialization Register 54h[31:0] = CF000F0Fh (Done in ConfigureMiscPm) + /// Set SATA Initialization Register 58h[31:0] = 190000h (Done in ConfigureMiscPm) + /// + /// 4 + /// USB 1.1 / USB 2.0 / USB 3.0 + /// + /// ConfigureUsbClockGating() has been moved to ConfigureMiscPm() to run before Function Disable + /// + /// 5 + /// Intel High Definition Audio (HDA) controller. + /// + if (FuncDisableReg & B_PCH_RCRB_FUNC_DIS_AZALIA) { + /// + /// 5.1 + /// If the HD Audio Controller is not being used, D27:F0 can be disabled and statically gated. Only statically + /// gate the Intel High Definition Audio controller if it is not being used in the system by setting RCBA + 341Ch[21]. + /// + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_SCG_HDA)); + } else { + /// + /// 5.2 + /// When the Intel High Definition Audio controller is used in the system, + /// dynamic clock gating can be used by setting RCBA + 341Ch[22]. + /// + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_DCG_HDA)); + } + if (PchSeries == PchLp) { + /// + /// For PchLp, set RCBA + 341Ch[22] + /// + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_DCG_HDA)); + /// + /// 5.3 + /// Set D27:F0:43h[6:5][2:0] = 11b, 111b (Done in ConfigureMiscPm) + /// + } + /// + /// Reg RCBA+341C is modified at multiple places, save at the end of the function + /// + /// 7 + /// LPC. + /// Enable dynamic clock gating by setting RCRB+341C[31] to 1b. + /// + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_DCG_LPC)); + if (PchSeries == PchH) { + /// + /// Reg RCBA+341C is modified at multiple places, save at the end of the function + /// + /// 8 + /// PCI Interface. + /// Enable PCI dynamic clock gating by setting RCBA + 341Ch[16]. + /// + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_DCG_PCI)); + } else if (PchSeries == PchLp) { + /// + /// Set RCRB+341Ch[30][28:26] to 1b, 111b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CG), + (UINT32) (B_PCH_RCRB_CG_EN_DCG_BLA | B_PCH_RCRB_CG_EN_DCG_GPIO | B_PCH_RCRB_CG_EN_DCG_HPET | + B_PCH_RCRB_CG_EN_CG_GPEC)); + /// + /// Set RCRB+3434h[2:0] to 111b + /// + MmioOr8 ( + (UINTN) (RootComplexBar + 0x3434), + (UINT8) (BIT2 | BIT1 | BIT0) + ); + RegData8 = MmioRead8 (RootComplexBar + 0x3434); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (RootComplexBar + 0x3434), + 1, + &RegData8 + ); + /// + /// If RCRB+3454h[4] is 0b, then set RCRB+341C[29] to 1b, else set RCRB+341C[29] to 0b + /// + if ((MmioRead32 (RootComplexBar + R_PCH_RCRB_GSX_CTRL) & B_PCH_RCRB_GSX_BAR_ENABLE) == 0) { + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_SCG_GSX)); + } else { + MmioAnd32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (~B_PCH_RCRB_CG_EN_SCG_GSX)); + } + } + /// + /// PCH BIOS Spec Rev 0.5.0, Section 10.2.1/10.2.2 Enable/Disable the GbE Clock Gating + /// Set RCBA + 341Ch[23] + /// + if (PchPlatformPolicy->DeviceEnabling->Lan == PCH_DEVICE_ENABLE) { + MmioAnd32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (~B_PCH_RCRB_CG_EN_SCG_LAN)); + } else { + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_SCG_LAN)); + } + if (PchSeries == PchLp) { + /// + /// 9 + /// SPI Clock gating. + /// Enable SPI clock gating by programming RCBA + 38C0h [13:10][2:0] to 1111b, 111b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_SPI_AFC), + (UINT32) (BIT13 | BIT12 | BIT11 | BIT10 | B_PCH_SPI_AFC_INF_DCGE | B_PCH_SPI_AFC_CORE_DCGE) + ); + RegData32 = MmioRead32 (RootComplexBar + R_PCH_SPI_AFC); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_SPI_AFC), + 1, + &RegData32 + ); + } else if (PchSeries == PchH) { + /// + /// 9 + /// SPI Clock gating. + /// Enable SPI clock gating by programming RCBA + 38C0h [2:0] to 111b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_SPI_AFC), + (UINT32) (B_PCH_SPI_AFC_INF_DCGE | B_PCH_SPI_AFC_CORE_DCGE) + ); + RegData32 = MmioRead32 (RootComplexBar + R_PCH_SPI_AFC); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_SPI_AFC), + 1, + &RegData32 + ); + } + /// + /// 10 + /// SMBus + /// Enable SMBus dynamic clock gating by setting D31:F3:80h [8, 10, 12 and 14] = 0b respectively (Done in ConfigureMiscPm) + /// + /// + /// PCH BIOS Spec Rev 0.5.5, section 19.10 + /// 11 + /// Misc + /// Set D31:F2:300h [17:16] = 11b (Done in ConfigureMiscPm) + /// + + if (PchSeries == PchLp) { + /// + /// Set D31:F2:98h [31:30], [23] to 00b, 1b (Done in ConfigureMiscPm) + /// + /// Set iobp register CE00C000h[0] to 0b + /// + ProgramIobpWithScript ( + RootComplexBar, + 0xCE00C000, + (UINT32)~(BIT0), + 0 + ); + + /// + /// Disable legacy DMA (8237) if desired + /// Set RCBA + Offset 0x341C[24] = 1 + /// + if ((PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_4) + && PchPlatformPolicy->PwrOptConfig->LegacyDmaDisable) + { + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CG), (UINT32) (B_PCH_RCRB_CG_EN_SCG_8237)); + } + } + /// + /// Save 341C value to the S3 script table. This register is modified at multiple places in this function. So instead of saving + /// at each location read the value once at the end of the function and save in S3 resume script. + /// + RegData32 = MmioRead32 (RootComplexBar + R_PCH_RCRB_CG); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CG), + 1, + &RegData32 + ); + + DEBUG ((EFI_D_INFO, "ConfigureClockGating() End\n")); + + return EFI_SUCCESS; +} + +/** + Configure miscellaneous power management settings + + @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance + @param[in] RootComplexBar RootComplexBar value of this PCH device + @param[in] GpioBase GPIO base address of this PCH device + + @retval EFI_SUCCESS The function completed successfully +**/ +EFI_STATUS +ConfigureMiscPm ( + IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, + IN UINT32 RootComplexBar, + IN UINT16 GpioBase + ) +{ + UINT8 Data8Or; + UINT8 Data8And; + UINT32 RegData32; + UINT16 RegData16; + UINT32 RegData32Tmp; + UINTN PciD31F0RegBase; + UINTN PciD31F3RegBase; + UINTN PciD31F2RegBase; + UINT16 LpcDeviceId; + UINTN PciD27F0RegBase; + PCH_SERIES PchSeries; + UINT32 DsxCfg; + + DEBUG ((EFI_D_INFO, "ConfigureMiscPm() Start\n")); + + PchSeries = GetPchSeries(); + PciD31F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 0, 0); + PciD31F3RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 3, 0); + PciD31F2RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 2, 0); + LpcDeviceId = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_DEVICE_ID); + PciD27F0RegBase = 0; + if (PchSeries == PchLp) { + PciD27F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 27, 0, 0); + } + + /// + /// Clear power / reset status bits on PCH Corporate + /// + RegData32 = 0; + if (PchPlatformPolicy->MiscPmConfig->PowerResetStatusClear.MeWakeSts) { + RegData32 |= B_PCH_RCRB_PRSTS_ME_WAKE_STS; + } + + if (PchPlatformPolicy->MiscPmConfig->PowerResetStatusClear.MeHrstColdSts) { + RegData32 |= B_PCH_RCRB_PRSTS_ME_HRST_COLD_STS; + } + + if (PchPlatformPolicy->MiscPmConfig->PowerResetStatusClear.MeHrstWarmSts) { + RegData32 |= B_PCH_RCRB_PRSTS_ME_HRST_WARM_STS; + } + + if (PchPlatformPolicy->MiscPmConfig->PowerResetStatusClear.MeHostPowerDn) { + RegData32 |= B_PCH_RCRB_PRSTS_ME_HOST_PWRDN; + } + + if (PchPlatformPolicy->MiscPmConfig->PowerResetStatusClear.WolOvrWkSts) { + RegData32 |= B_PCH_RCRB_PRSTS_WOL_OVR_WK_STS; + } + + MmioOr32 (RootComplexBar + R_PCH_RCRB_PRSTS, RegData32); + RegData32Tmp = 0xFFFFFFFF; + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + RootComplexBar + R_PCH_RCRB_PRSTS, + &RegData32, // OR mask + &RegData32Tmp // AND mask + ); + + /// + /// We need to enable GP27_PIN_DSX_EN for Wake from both SX and DSX + /// + DsxCfg = MmioRead32(RootComplexBar + 0x3334); + if (PchPlatformPolicy->MiscPmConfig->WakeConfig.Gp27WakeFromDeepSx == PCH_DEVICE_ENABLE) { + DsxCfg |= BIT0; + } else { + DsxCfg &= ~BIT0; + } + + /// + /// Enable WAKE_PIN__DSX_EN for Wake + /// + if(PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_5) { + if (PchPlatformPolicy->MiscPmConfig->WakeConfig.PcieWakeFromDeepSx == PCH_DEVICE_ENABLE) { + DsxCfg |= BIT2; + } else { + DsxCfg &= ~BIT2; + } + } + MmioWrite32 ((RootComplexBar + 0x3334), DsxCfg); + + /// + /// Handle wake policy + /// Don't need to record in S3 script as R_PCH_LPC_GEN_PMCON_3 is in RTC and SUS power well + /// + RegData16 = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3) & + (UINT16) (~(B_PCH_LPC_GEN_PMCON_PME_B0_S5_DIS + + B_PCH_LPC_GEN_PMCON_WOL_ENABLE_OVERRIDE)); + + if (PchPlatformPolicy->MiscPmConfig->WakeConfig.PmeB0S5Dis) { + RegData16 |= B_PCH_LPC_GEN_PMCON_PME_B0_S5_DIS; + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3, RegData16); + } + + if (PchPlatformPolicy->MiscPmConfig->WakeConfig.WolEnableOverride) { + /// + /// PCH BIOS Spec Rev 0.5.0 Section 10.4 Wake-On-LAN (WOL) Implementation + /// Step 1 + /// Clear D31:F0:A2h[14] = 0b to ensure the LAN PHY will be powered for WOL + /// when the power source is either the AC or the DC battery. + /// + RegData16 = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2); + RegData16 &= (UINT16) ~B_PCH_LPC_GEN_PMCON_DC_PP_DIS; + + /// + /// Step 2 + /// Clear D31:F0:A2h[13] = 0b to ensure the LAN PHY will be powered for WOL in Deep Sx. + /// + RegData16 &= (UINT16) ~B_PCH_LPC_GEN_PMCON_DSX_PP_DIS; + + /// + /// Step 3 + /// Set D31:F0:A2h[12] = 1b to ensure the LAN PHY will be powered for WOL after a G3 transition. + /// + RegData16 |= (UINT16) B_PCH_LPC_GEN_PMCON_AG3_PP_EN; + + /// + /// Step 4 + /// Set D31:F0:A2h[11] = 1b to ensure the LAN PHY will be powered for WOL from Sx. + /// + RegData16 |= (UINT16) B_PCH_LPC_GEN_PMCON_SX_PP_EN; + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2, RegData16); + + /// + /// Step 5 + /// "PME_B0_EN", PMBASE + Offset 28h[13], bit must be programmed to enable wakes + /// from S1-S4 at the Power Management Controller + /// Done in ASL code(_PRW) + /// + /// + /// Step 6 + /// Set "WOL Enable Override", D31:F0:A4h:[13], bit to 1b to guarantee the + /// LAN-Wakes are enabled at the Power Management Controller, even in surprise + /// S5 cases such as power loss/return and Power Button Override + /// + RegData16 = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3); + RegData16 |= (UINT16) B_PCH_LPC_GEN_PMCON_WOL_ENABLE_OVERRIDE; + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3, RegData16); + + /// + /// Step 7 + /// Moreover, system BIOS also require to enables in the LAN device by performing + /// the WOL configuration requirements in the GbE region of the SPI flash. + /// Done in PchSmmSxGoToSleep() SMM handler. + /// + } else { + /// + /// D31:F0:A2h[14:11] and D31:F0:A4h[13] are all in RTC or DSW well, so BIOS also + /// needs to program them while WOL setup option is disabled. + /// + RegData16 = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2); + RegData16 |= (UINT16) (B_PCH_LPC_GEN_PMCON_DC_PP_DIS | B_PCH_LPC_GEN_PMCON_DSX_PP_DIS); + RegData16 &= (UINT16) ~(B_PCH_LPC_GEN_PMCON_AG3_PP_EN | B_PCH_LPC_GEN_PMCON_SX_PP_EN); + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2, RegData16); + + RegData16 = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3); + RegData16 &= (UINT16) ~(B_PCH_LPC_GEN_PMCON_WOL_ENABLE_OVERRIDE); + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3, RegData16); + } + + /// + /// Configure On DC PHY Power Diable according to policy SlpLanLowDc. + /// When this bit is set, SLP_LAN# will be driven low when ACPRESENT is low. + /// This indicates that LAN PHY should be powered off on battery mode. + /// This will override the DC_PP_DIS setting by WolEnableOverride. + /// + if (PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_7) { + RegData16 = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2); + if (PchPlatformPolicy->MiscPmConfig->SlpLanLowDc) { + if ((RegData16 & B_PCH_LPC_GEN_PMCON_DC_PP_DIS) == 0) { + RegData16 |= (UINT16) (B_PCH_LPC_GEN_PMCON_DC_PP_DIS); + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2, RegData16); + } + } else { + if ((RegData16 & B_PCH_LPC_GEN_PMCON_DC_PP_DIS) != 0) { + RegData16 &= (UINT16) ~(B_PCH_LPC_GEN_PMCON_DC_PP_DIS); + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2, RegData16); + } + } + } + + /// + /// - Set SATA Initialization Register 70h[31:0] = 3F00BF1Fh + /// + MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x70); + MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_STRD, 0x3F00BF1F); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) + ); + if (PchSeries == PchLp) { + /// + /// Set SATA Initialization Register 54h[31:0] = CF000F0Fh + /// + MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x54); + MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_STRD, 0xCF000F0F); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) + ); + /// + /// Set SATA Initialization Register 58h[31:0] = 190000h + /// + MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_SIRI, 0x58); + MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_STRD, 0x190000); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_SIRI) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + R_PCH_SATA_STRD) + ); + } + /// + /// 4 + /// USB 1.1 / USB 2.0 / USB 3.0 + /// + ConfigureUsbClockGating (PchPlatformPolicy, RootComplexBar); + + if (PchSeries == PchLp) { + /// + /// 5.3 + /// Set D27:F0:43h[6:5][3:0] = 11b, 111b + /// + Data8And = (UINT8) ~0x0; + Data8Or = (BIT6 | BIT5 | BIT3 | BIT2 | BIT1 | BIT0); + MmioOr8 ((UINTN) (PciD27F0RegBase + 0x43), Data8Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (PciD27F0RegBase + 0x43), + &Data8Or, // Data to be ORed + &Data8And // Data to be ANDed + ); + } + /// + /// 10 + /// SMBus + /// Enable SMBus dynamic clock gating by setting D31:F3:80h [8, 10, 12 and 14] = 0b respectively + /// + MmioAnd16 ((UINTN) (PciD31F3RegBase + 0x80), (UINT16) ~(BIT14 | BIT12 | BIT10 | BIT8)); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (PciD31F3RegBase + 0x80), + 1, + (VOID *) (UINTN) (PciD31F3RegBase + 0x80) + ); + /// + /// PCH BIOS Spec Rev 0.5.5, section 19.10 + /// 11 + /// Misc + /// + /// Set D31:F2:300h [31:29] to 111b and [19] to 1b + /// + MmioOr32 ((UINTN) (PciD31F2RegBase + 0x300), BIT31 | BIT30 | BIT29 | BIT19); + /// + /// Set D31:F2:300h [17:16] = 11b + /// + MmioOr32 ((UINTN) (PciD31F2RegBase + 0x300), BIT17 | BIT16); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F2RegBase + 0x300), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + 0x300) + ); + + if (PchSeries == PchLp) { + /// + /// Set D31:F2:98h [31:30], [23] to 00b, 1b + /// + MmioAndThenOr32(PciD31F2RegBase + 0x98, (UINT32)~(BIT31 | BIT30), BIT23); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F2RegBase + 0x98), + 1, + (VOID *) (UINTN) (PciD31F2RegBase + 0x98) + ); + + /// + /// Set RCBA + 0x333C[23:20] to 1100b + /// + MmioAndThenOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_PM_CFG2), + (UINT32)~(BIT21 | BIT20), + (UINT32) (BIT22 | BIT23) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_PM_CFG2), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_PM_CFG2) + ); + } + DEBUG ((EFI_D_INFO, "ConfigureMiscPm() End\n")); + + return EFI_SUCCESS; +} + +/** + Configure additional power management settings + + @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 +ConfigureAdditionalPm ( + IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, + IN UINT32 RootComplexBar + ) +{ + UINTN PciD31F0RegBase; + UINTN PciD31F2RegBase; + UINTN PciD28F0RegBase; + UINT32 Data32; + UINT8 Data8; + UINT16 LpcDeviceId; + UINT32 Data32And; + UINT32 Data32Or; + EFI_STATUS Status; + PCH_SERIES PchSeries; + + Data32 = 0x0; + PchSeries = GetPchSeries(); + PciD31F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 0, 0); + PciD31F2RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 2, 0); + PciD28F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 28, 0, 0); + LpcDeviceId = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_DEVICE_ID); + + /// + /// PCH BIOS Spec Rev 0.5.0, Section 19.4 Additional Power Management Programming + /// Step 1 + /// Set D31:F0:A9h[7:0] = 46h + /// + MmioWrite8 ( + (UINTN) (PciD31F0RegBase + R_PCH_LPC_CIR4), + (UINT8) (0x46) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (PciD31F0RegBase + R_PCH_LPC_CIR4), + 1, + (VOID *) (UINTN) (PciD31F0RegBase + R_PCH_LPC_CIR4) + ); + /// + /// Step 2 + /// Set Power Management Initialization Register (PMIR) Field 1, D31:F0:ACh[31] = 1b + /// Done in Intel Management Engine Framework Reference Code + /// Step 3 + /// Set GEN_PMCON_LOCK register, D31:F0:A6h = 06h, after stretch and ACPI base programming completed. + /// Done in PchInitBeforeBoot() + if (PchSeries == PchH) { + /// + /// Step 4 + /// Set RCBA + Offset 2238h[0] = 1b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2238), + (UINT32) (BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2238), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2238) + ); + } + /// + /// Step 5 + /// Set RCBA + Offset 232Ch[0] = 1b + /// + if (PchSeries == PchH) { + MmioOr32 ( + (UINTN) (RootComplexBar + 0x232C), + (UINT32) (BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x232C), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x232C) + ); + } + + if (PchSeries == PchLp) { + /// + /// Step 5 + /// Set RCBA + Offset 232Ch[0] = 0b + /// + MmioAnd32 ( + (UINTN) (RootComplexBar + 0x232C), + (UINT32) ~(BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x232C), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x232C) + ); + /// + /// Step 6 + /// If Trunk Clock Gating is enabled: + /// set RCBA + Offset 1100h[15,14,8,5,4,3,2,1,0] all 1b + /// If Trunk Clock Gating is disabled: + /// set RCBA + Offset 1100h[15] = 0b + /// set RCBA + Offset 1100h[14,8,5,4,3,2,1,0] all 1b + /// + + if((PchPlatformPolicy->UsbConfig->Usb30Settings.Mode != PCH_XHCI_MODE_ON) && + (PchPlatformPolicy->UsbConfig->Usb30Settings.Btcg == PCH_DEVICE_DISABLE)) { + MmioAndThenOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100), + (UINT32)~(BIT15), + (UINT32) (BIT14 | BIT8 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0) + ); + } else { + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100), + (UINT32) (BIT15 | BIT14 | BIT8 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0) + ); + } + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100) + ); + } else if (PchSeries == PchH) { + /// + /// Step 6 + /// If Truck Clock Gating is enabled: + /// set RCBA + Offset 1100h[14:13] = 11b + /// If Truck Clock Gating is disabled: + /// set RCBA + Offset 1100h[14:13] = 10b + /// + if((PchPlatformPolicy->UsbConfig->Usb30Settings.Mode != PCH_XHCI_MODE_ON) && + (PchPlatformPolicy->UsbConfig->Usb30Settings.Btcg == PCH_DEVICE_DISABLE)) { + MmioAndThenOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100), (UINT32) ~(BIT13), (UINT32) (BIT14)); + } else { + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100), + (UINT32) (BIT14 | BIT13) + ); + } + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR1100) + ); + } + + if (PchSeries == PchLp) { + /// + /// Set IOBP register 0xCF000000[14:12] = 111b + /// Set IOBP register 0XCF000000[0] = 1b + /// + Data32And = (UINT32)~(0); + Data32Or = 0x7001; + Status = ProgramIobp ( + RootComplexBar, + 0xCF000000, + Data32And, + Data32Or + ); + ASSERT_EFI_ERROR (Status); + Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM ( + RootComplexBar, + 0xCF000000, + Data32And, + Data32Or + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Set IOBP register 0xCA000000[3] = 1b + /// Set IOBP register 0XCA000000[0] = 1b + /// + Data32And = (UINT32)~(0); + Data32Or = (UINT32) (0x09); + Status = ProgramIobp ( + RootComplexBar, + 0xCA000000, + Data32And, + Data32Or + ); + ASSERT_EFI_ERROR (Status); + Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM ( + RootComplexBar, + 0xCA000000, + Data32And, + Data32Or + ); + ASSERT_EFI_ERROR (Status); + } else if (PchSeries == PchH) { + /// + /// Step 7 + /// Set RCBA + Offset 2304h[31:0] = 0xC07B8400 + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_DMC), + (UINT32) (0xC07B8400) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_DMC), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_DMC) + ); + /// + /// Step 8 + /// Set RCBA + Offset 2314h[23 and 5] = 1b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2314), + (UINT32) (BIT23 | BIT5) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2314), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2314) + ); + } + + /// + /// PCH BIOS Spec Rev 0.5.5, Section 19.4 Additional Power Management Programming + /// Step 9 + /// Set B0:D28:F0 + F5h[3:0] = 0101b + /// + MmioAndThenOr8 ( + (UINTN) (PciD28F0RegBase + 0xF5), + (UINT8) ~(BIT3 | BIT1), + (UINT8) (BIT2 | BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint8, + (UINTN) (PciD28F0RegBase + 0xF5), + 1, + (VOID *) (UINTN) (PciD28F0RegBase + 0xF5) + ); + + if (PchSeries == PchH) { + /// + /// Step 10 + /// Set RCBA + Offset 2320h [1] = 1b + /// + MmioOr32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CIR2320), (UINT32) (BIT1)); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2320), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2320) + ); + } + if (PchSeries == PchLp) { + /// + /// Step 10 + /// Set RCBA + Offset 2320h [6:4] = 001b + /// + MmioAndThenOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2320), + (UINT8) ~(BIT6 | BIT5), + (UINT8) (BIT4) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2320), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR2320) + ); + } + switch (PchSeries) { + case PchLp: + /// + /// Step 11 + /// Set RCBA + Offset 3314h[31:0] = 0x00012FFF + /// + Data32 = 0x00012FFF; + break; + + case PchH: + default: + /// + /// Step 11 + /// Set RCBA + Offset 3314h[31:0] = 0x000007BF + /// + Data32 = 0x000007BF; + break; + } + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3314), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3314), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3314) + ); + + switch (PchSeries) { + case PchLp: + /// + /// Step 12 + /// Set RCBA + Offset 3318h[31:0] = 0x0DCF0400 + /// + Data32 = 0x0DCF0400; + break; + + case PchH: + default: + /// + /// Step 12 + /// Set RCBA + Offset 3318h[31:0] = 0x0DCF0020 (Note: Keep BIT5 unchanged) + /// + Data32 = 0x0DCF0020; + break; + } + /// + /// Note: RCBA + 3318h[19:16] are platform dependent settings (0Fh provides longest assertion), + /// please consult with your board design engineers for correct values to be programmed to. + /// + /// For RCBA + 3318h[9:8] Reset Power Cycle Duration could be customized, please refer to EDS + /// and make sure the setting correct, which never less than the following register. + /// - GEN_PMCON_3.SLP_S3_MIN_ASST_WDTH + /// - GEN_PMCON_3.SLP_S4_MIN_ASST_WDTH + /// - PM_CFG.SLP_A_MIN_ASST_WDTH + /// - PM_CFG.SLP_LAN_MIN_ASST_WDTH + /// + Data32 &= (UINT32)~(B_PCH_RCRB_PM_CFG_SSMAW_MASK | B_PCH_RCRB_PM_CFG_SAMAW_MASK); + if (PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_4) { + Data32 &= (UINT32)~(B_PCH_RCRB_PM_CFG_RPCD_MASK); + } + + switch (PchPlatformPolicy->MiscPmConfig->PchSlpSusMinAssert) { + case PchSlpSus0ms: + Data32 |= V_PCH_RCRB_PM_CFG_SSMAW_0S; + break; + + case PchSlpSus500ms: + Data32 |= V_PCH_RCRB_PM_CFG_SSMAW_0_5S; + break; + + case PchSlpSus1s: + Data32 |= V_PCH_RCRB_PM_CFG_SSMAW_1S; + break; + + case PchSlpSus4s: + default: + Data32 |= V_PCH_RCRB_PM_CFG_SSMAW_4S; + break; + } + switch (PchPlatformPolicy->MiscPmConfig->PchSlpAMinAssert) { + case PchSlpA0ms: + Data32 |= V_PCH_RCRB_PM_CFG_SAMAW_0S; + break; + + case PchSlpA4s: + Data32 |= V_PCH_RCRB_PM_CFG_SAMAW_4S; + break; + + case PchSlpA98ms: + Data32 |= V_PCH_RCRB_PM_CFG_SAMAW_98ms; + break; + + case PchSlpA2s: + default: + Data32 |= V_PCH_RCRB_PM_CFG_SAMAW_2S; + break; + } + if (PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_4) { + switch (PchPlatformPolicy->MiscPmConfig->PchPwrCycDur) { + case 0: // treat as PCH default + Data32 |= V_PCH_RCRB_PM_CFG_RPCD_4S; + break; + + case 1: + Data32 |= V_PCH_RCRB_PM_CFG_RPCD_1S; + break; + + case 2: + Data32 |= V_PCH_RCRB_PM_CFG_RPCD_2S; + break; + + case 3: + Data32 |= V_PCH_RCRB_PM_CFG_RPCD_3S; + break; + + case 4: + Data32 |= V_PCH_RCRB_PM_CFG_RPCD_4S; + break; + + default: + Data32 |= V_PCH_RCRB_PM_CFG_RPCD_4S; + DEBUG ((EFI_D_ERROR, "Error. Not a valid PCH reset power cycle duration setting.\n")); + break; + } + } + /// + /// For LP, force bit 5 = 0 + /// For LPT-H, preserve bit 5 + /// + if (PchSeries == PchLp) { + Data32 &= (UINT32) ~(BIT5); + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_PM_CFG), + Data32 + ); + } else { + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_PM_CFG), + Data32 + ); + } + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_PM_CFG), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_PM_CFG) + ); + /// + /// PCH BIOS Spec Rev 0.5.0, Section 19.4 Additional Power Management Programming + /// Step 13 + /// Set RCBA + Offset 3324h[31:0] = 0x04000000 + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3324), + (UINT32) (0x04000000) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3324), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3324) + ); + + if (PchSeries == PchH) { + /// + /// Step 14 + /// Set RCBA + Offset 3340h[31:0] = 0x020DDBFF + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3340), + (UINT32) (0x020DDBFF) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3340), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3340) + ); + /// + /// Step 15 + /// Set RCBA + Offset 3344h[0] = 1b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3344), + (UINT32) (BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3344), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3344) + ); + } + switch (PchSeries) { + case PchLp: + /// + /// Step 16 + /// Set RCBA + Offset 3368h[31:0] = 0x00041400 + /// + Data32 = 0x00041400; + break; + + case PchH: + default: + /// + /// Step 16 + /// Set RCBA + Offset 3368h[31:0] = 0x00041000 + /// + Data32 = 0x00041000; + break; + } + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3368), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3368), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3368) + ); + + if (PchSeries == PchH) { + /// + /// Step 17 + /// Set RCBA + Offset 3378h[31:0] = 3F8DDBFFh + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3378), + (UINT32) (0x3F8DDBFF) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3378), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3378) + ); + /// + /// Step 18 + /// Set RCBA + Offset 337Ch[31:0] = 000001E1h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR337C), + (UINT32) (0x000001E1) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR337C), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR337C) + ); + } + switch (PchSeries) { + case PchLp: + /// + /// Step 19 + /// Set RCBA + Offset 3388h[31:0] = 0x3F8DDBFF + /// + Data32 = 0x3F8DDBFF; + break; + + case PchH: + default: + /// + /// Step 19 + /// Set RCBA + Offset 3388h[31:0] = 0x00001000 + /// + Data32 = 0x00001000; + break; + } + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3388), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3388), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3388) + ); + if (PchSeries == PchH) { + /// + /// Step 20 + /// Set RCBA + Offset 33A0h[31:0] = 00000800h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33A0), + (UINT32) (0x00000800) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33A0), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33A0) + ); + } + switch (PchSeries) { + case PchLp: + /// + /// Step 21 + /// Set RCBA + Offset 33ACh[31:0] = 0x00007001 + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x33AC), + (UINT32) (0x00007001) + ); + break; + + case PchH: + default: + /// + /// Step 21 + /// Set RCBA + Offset 33ACh[31:0] = 00001000h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x33AC), + (UINT32) (0x00001000) + ); + break; + } + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33AC), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33AC) + ); + switch (PchSeries) { + case PchLp: + /// + /// Step 22 + /// Set RCBA + Offset 33B0h[31:0] = 0x00181900 + /// + Data32 = 0x00181900; + break; + + case PchH: + default: + /// + /// Step 22 + /// Set RCBA + Offset 33B0h[31:0] = 0x00001000 + /// + Data32 = 0x00001000; + break; + } + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33B0), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33B0), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33B0) + ); + switch (PchSeries) { + case PchLp: + /// + /// Step 23 + /// Set RCBA + Offset 33C0h[31:0] = 0x00060A00 + /// + Data32 = 0x00060A00; + break; + + case PchH: + default: + /// + /// Step 23 + /// Set RCBA + Offset 33C0h[31:0] = 0x00011900 + /// + Data32 = 0x00011900; + break; + } + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33C0), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33C0), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33C0) + ); + /// + /// Step 24 + /// LP Set RCBA + Offset 33D0h[31:0] = 0x06200840 + /// LP Set RCBA + Offset 33D0h[31:0] = 06004622h for LPT LP A0/A1 only + /// LPT-H Set RCBA + Offset 33D0h[31:0] = 06000802h + switch (PchSeries) { + case PchLp: + if (PchSeries == PchLp && PchStepping() < LptLpB0) { + Data32 = 0x06004622; + } else { + Data32 = 0x06200840; + } + break; + + case PchH: + default: + Data32 = 0x06000802; + break; + } + + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33D0), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33D0), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33D0) + ); + /// + /// Step 25 -- Note, this step has been moved to meet programming sequence requirements + /// Register 3A80 - 3A88 must be program after 3A00-3A3F and before 3A6C + /// Set RCBA + 3A88h[31:0] = 0x00000001 + /// + switch (PchSeries) { + case PchLp: + /// + /// Step 26 + /// Set RCBA + Offset 3A28h[31:0] = 01010101h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A28), + (UINT32) (0x01010101) + ); + break; + + case PchH: + default: + /// + /// Step 26 + /// Set RCBA + Offset 3A28h[31:0] = 01010000h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A28), + (UINT32) (0x01010000) + ); + break; + } + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A28), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A28) + ); + switch (PchSeries) { + case PchLp: + /// + /// Step 27 + /// Set RCBA + Offset 3A2Ch[31:0] = 04040404h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A2C), + (UINT32) (0x04040404) + ); + break; + + case PchH: + default: + /// + /// Step 27 + /// Set RCBA + Offset 3A2Ch[31:0] = 01010404h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A2C), + (UINT32) (0x01010404) + ); + break; + } + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A2C), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A2C) + ); + /// + /// Step 29 + /// Set RCBA + Offset 3A6Ch[31:0] = 00000001h, after all steps in this routine are done + /// Done in PchInitBeforeBoot() + /// + /// Step 30 + /// For PCH H + /// Set RCBA + Offset 2344h[31:24] = 0FFh + /// Set RCBA + Offset 2344h[7:0] = 0Ch + /// Done in PchInitBeforeBoot() + /// + /// Step 31 + /// For LPT-H set RCBA + Offset 33A4h[0] = 1b + /// + if (PchSeries == PchH) { + MmioOr32 ( + (UINTN) (RootComplexBar + 0x33A4), + (UINT32) (BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33A4), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33A4) + ); + } + + if (PchSeries == PchLp) { + /// + /// Step 32 + /// + /// Set RCBA + Offset 2B1Ch + /// [31:30] =2'b00 + /// [29] =0 if Audio DSP is enabled. 1 if disabled (RCBA offset x3418[1]=1). ConfigureAudioDsp will take care of this bit, which is executed later + /// Note1: Must assume enable in this flow because ConfigureAudioDsp only program this in the "audio disable flow" only + /// [28:22] = 7'b0001110 + /// [21:16]=corresponding bit has to be set for each SRC[5:0]CLKRQ# pin that is enabled (ie attached to a PCIe device) + /// [15:0]=0x8033h + /// + Data32 = 0x03808033; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B1C), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B1C), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B1C) + ); + /// + /// Step 33 + /// Set RCBA + Offset 2B34[31:0] = 80000009h + /// Set bit 3 and 0, PMC shutdown time = 16us + /// + Data32 = 0x80000009; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B34), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B34), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B34) + ); + + /// + /// Step 34 + /// Set RCBA + Offset 3348[31:0] = 022DDFFFh + /// + Data32 = 0x022DDFFF; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3348), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3348), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3348) + ); + /// + /// Step 35 + /// Set RCBA + Offset 334C[31:0] = 00000001h + /// + Data32 = 0x00000001; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x334C), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x334C), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x334C) + ); + /// + /// Step 36 + /// Set RCBA + Offset 3358[31:0] = 0001C000h + /// + Data32 = 0x0001C000; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3358), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3358), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3358) + ); + /// + /// Step 37 + /// Set RCBA + Offset 3380[31:0] = 3F8DDBFFh + /// + Data32 = 0x3F8DDBFF; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3380), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3380), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3380) + ); + /// + /// Step 38 + /// Set RCBA + Offset 3384[31:0] = 0001C7E1h + /// + Data32 = 0x0001C7E1; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3384), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3384), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3384) + ); + /// + /// Step 39 + /// Set RCBA + Offset 338C[31:0] = 0x0001C7E1 + /// + Data32 = 0x0001C7E1; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x338C), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x338C), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x338C) + ); + /// + /// Step 40 + /// Set RCBA + Offset 3398[31:0] = 0001C000h + /// + Data32 = 0x0001C000; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3398), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3398), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3398) + ); + /// + /// Step 41 + /// Set RCBA + Offset 33A8[31:0] = 0x00181900 + /// + Data32 = 0x00181900; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x33A8), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33A8), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33A8) + ); + /// + /// Step 42 + /// Set RCBA + Offset 33DC[31:0] = 00080000h + /// + Data32 = 0x00080000; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x33DC), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33DC), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33DC) + ); + /// + /// Step 43 + /// Set RCBA + Offset 33E0[31:0] = 00000001h + /// + Data32 = 0x00000001; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x33E0), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33E0), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33E0) + ); + /// + /// Step 44 + /// Set RCBA + Offset 3A20[31:0] = 00000404h + /// + Data32 = 0x00000404; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3A20), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3A20), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3A20) + ); + /// + /// Step 45 + /// Set RCBA + Offset 3A24[31:0] = 01010101h + /// + Data32 = 0x01010101; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3A24), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3A24), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3A24) + ); + /// + /// Step 46 + /// Set RCBA + Offset 3A30[31:0] = 01010101h + /// + Data32 = 0x01010101; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3A30), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3A30), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3A30) + ); + /// + /// Step 47 + /// Set D31:F0:ACh[21] = 0b + /// + MmioAnd32 ( + (UINTN) (PciD31F0RegBase + R_PCH_LPC_PMIR), + (UINT32) ~(BIT21) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (PciD31F0RegBase + R_PCH_LPC_PMIR), + 1, + (VOID *) (UINTN) (PciD31F0RegBase + R_PCH_LPC_PMIR) + ); + /// + /// Step 48 + /// set RCBA + Offset 410h[1:0] = 11b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + 0x410), + (UINT32) (BIT1 | BIT0) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x410), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x410) + ); + /// + /// Step 49 + /// Set RCBA + 2618h[27] = 1b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + 0x2618), + (UINT32) BIT27 + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2618), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2618) + ); + /// + /// Step 50 + /// Set RCBA + 2300h[1] = 1b + /// + Data32And = 0xFFFFFFFF; + Data32Or = (UINT32) BIT1; + MmioOr32 (RootComplexBar + 0x2300 , Data32Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2300), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + /// + /// Step 51 + /// Set RCBA + 2600h[3] = 1b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + 0x2600), + (UINT32) BIT3 + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2600), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2600) + ); + /// + /// Step 52 + /// Set RCBA + 33B4h[0] = 0x00007001 + /// + Data32 = 0x00007001; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x33B4), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33B4), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33B4) + ); + /// Step 53 + /// Set RCBA + Offset 3350[31:0] = 0x022DDFFF + /// + Data32 = 0x022DDFFF; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3350), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3350), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3350) + ); + /// + /// Step 54 + /// Set RCBA + Offset 3354[31:0] = 0x00000001 + /// + Data32 = 0x00000001; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x3354), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x3354), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x3354) + ); + } + + if ((PchPlatformPolicy->PwrOptConfig->PchPwrOptDmi == PCH_DEVICE_ENABLE)) { + /// + /// PCH BIOS Spec Rev 0.5.0, Section 19.13 Power Optimizer Considerations (MB Only) + /// Notes: Settings is not recommended for Lynx Point Power on ES0 samples + /// Step 1 + /// Enable PM SYNC State 12 + /// Program RCBA + 33D4h[27] = 1b + /// For PCH LP + /// Program RCBA + 2B14[31:0] = 1E0A4616h + /// Program RCBA + 2B24[31:0] = 40000005h + /// For PCH H + /// Program RCBA + 2B14[31:0] = 1E0A0317h + /// Program RCBA + 2B24[31:0] = 4000000Bh + /// Program RCBA + 2B28[31:0] = 00000002h + /// Program RCBA + 2B2C[31:0] = 00008813h + /// + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33D4), + (UINT32) BIT27 + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33D4), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR33D4) + ); + /// + /// Program RCBA + 33C8h[27] = 1b + /// + Data32Or = BIT27; + if (PchSeries == PchLp) { + /// + /// Program RCBA + 33C8h[7] = 1b + /// + Data32Or = BIT7; + } + MmioOr32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_PMSYNC), + (UINT32) Data32Or + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_PMSYNC), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_PMSYNC) + ); + /// + /// For LPT-LP, Program RCBA + 2B10[31:0] = 0000883Ch + /// + if (PchSeries == PchLp) { + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B10), + (UINT32) (0x0000883C) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B10), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B10) + ); + } + /// + /// Program RCBA + 2B14[31:0] = 1E0A0317h + /// For LP Program RCBA + 2B14[31:0] = 1E0A4616h + /// + Data32 = 0x1E0A0317; + if (PchSeries == PchLp) { + Data32 = 0x1E0A4616; + } + if (PchPlatformPolicy->PwrOptConfig->MemCloseStateEn == PCH_DEVICE_DISABLE) { + Data32 &= (UINT32) ~(BIT2); + } + if (PchPlatformPolicy->PwrOptConfig->InternalObffEn == PCH_DEVICE_DISABLE) { + Data32 &= (UINT32) ~(BIT1); + } + if (PchPlatformPolicy->PwrOptConfig->ExternalObffEn == PCH_DEVICE_DISABLE) { + Data32 &= (UINT32) ~(BIT0); + } + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B14), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B14), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B14) + ); + if (PchSeries == PchLp) { + /// + /// Set RCBA + Offset 2B24[31:0] = 0x40000005 + /// + Data32 = 0x40000005; + } else { + /// + /// Set RCBA + Offset 2B24[31:0] = 0x4000000B + /// + Data32 = 0x4000000B; + } + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B24), + Data32 + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B24), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B24) + ); + if (PchSeries == PchH) { + /// + /// Set RCBA + Offset 2B28[31:0] = 0x00000002 + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B28), + (UINT32) (0x00000002) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B28), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B28) + ); + } + if (PchSeries == PchH) { + /// + /// Set RCBA + Offset 2B2C[31:0] = 0x00008813 + /// + Data32 = 0x00008813; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B2C), + Data32 + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B2C), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B2C) + ); + } + /// Step 7 + /// Enable PM Demand in Cx States + /// For LPT-H, use default + /// For LPT-LP Program RCBA + 02B20h[1:0] = 0x0005DB01 + /// + if (PchSeries == PchLp) { + Data32 = 0x0005DB01; + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x2B20), + Data32 + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2B20), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x2B20) + ); + } + } + switch (PchSeries) { + case PchLp: + /// + /// Step 55 + /// Set RCBA + 3A80h[31:0] = 05145005h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A80), + (UINT32) (0x05145005) + ); + break; + case PchH: + default: + /// + /// Step 55 + /// Set RCBA + 3A80h[31:0] = 01040000h + /// + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A80), + (UINT32) (0x01040000) + ); + break; + } + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A80), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A80) + ); + /// + /// Step 56 + /// Ensure this is done after 3A00-3A3C and before 3A6C + /// if PchLp, Set RCBA + Offset 3A84h[31:0] = 0x00001005 + /// if PchH, Set RCBA + Offset 3A84h[31:0] = 0x01041001 + /// if PCS.P0E and PCS.P1E = 0b, Set RCBA + Offset 3A84h[20,18] = 1b, 1b + /// if PCS.P2E and PCS.P3E = 0b, Set RCBA + Offset 3A84h[24,26] = 1b, 1b + /// + if (PchSeries == PchLp) { + Data32 = 0x00001005; + } else { + Data32 = 0x01041001; + } + Data8 = MmioRead8 (PciD31F2RegBase + R_PCH_SATA_PCS); + if((Data8 & (UINT8) (B_PCH_SATA_PCS_PORT0_EN | B_PCH_SATA_PCS_PORT1_EN)) == 0) { + Data32 |= (BIT20 | BIT18); + } + if((Data8 & (UINT8) (B_PCH_SATA_PCS_PORT2_EN | B_PCH_SATA_PCS_PORT3_EN)) == 0) { + Data32 |= (BIT24 | BIT26); + } + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A84), + (UINT32) (Data32) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A84), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A84) + ); + /// + /// Step 57 + /// Set RCBA + 3A88h[31:0] = 0x00000001 + /// + if (PchSeries == PchH) { + MmioWrite32 ( + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A88), + (UINT32) (0x00000001) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A88), + 1, + (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A88) + ); + } + /// + /// Step 58 + /// For LPT-LP Set RCBA + Offset 33D4h = 0x2FFF2FB1, after step #14 to #24 and D31:F0:A9h are done + /// Note for LP only: Preserve bits 31,30,28,15,14,12, which are platform specific + /// For LPT-H Set RCBA + Offset 33D4h = 0xC00BC000, after step #14 to #24 and D31:F0:A9h are done + /// + switch (PchSeries) { + case PchLp: + MmioOr32 ( + (UINTN) (RootComplexBar + 0x33D4), + (UINT32) (0x2FFF2FB1) + ); + break; + + case PchH: + default: + MmioWrite32 ( + (UINTN) (RootComplexBar + 0x33D4), + (UINT32) (0xC00BC000) + ); + break; + } + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33D4), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33D4) + ); + + if (PchSeries == PchLp) { + /// + /// This is the last step which only apply for LPT-LP + /// Set RCBA + Offset 33C8h[15] = 1b + /// + MmioOr32 ( + (UINTN) (RootComplexBar + 0x33C8), + (UINT32) (BIT15) + ); + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x33C8), + 1, + (VOID *) (UINTN) (RootComplexBar + 0x33C8) + ); + } + return EFI_SUCCESS; +} + +/** + Configures PCH DMI according to policies specified in PCH Platform Policy protocol + + @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance + @param[in] RootComplexBar RootComplexBar value of this PCH device + + @retval EFI_SUCCESS Successfully completed. +**/ +EFI_STATUS +EFIAPI +ConfigureDmiPm ( + IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, + IN UINT32 RootComplexBar + ) +{ + UINT32 Data32And; + UINT32 Data32Or; + UINT16 Data16And; + UINT16 Data16Or; + UINTN PciD28F0RegBase; + PCH_PCI_EXPRESS_ASPM_CONTROL DmiAspmCtrl; + PCH_SERIES PchSeries; + + DEBUG ((EFI_D_INFO, "ConfigureDmi() Start\n")); + + PchSeries = GetPchSeries(); + PciD28F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 28, 0, 0); + + /// + /// PCH BIOS Spec Rev 0.5.0 Section 7.1.5 Additional PCH DMI Programming Steps + /// + if (PchSeries == PchH) { + /// Step 4.1 + /// If RCBA + Offset 2320h[1] = 0 and B0:D28:F0 + F5h[0] = 0, set RCBA + Offset 21A4h[17:15] = 010b + /// Else set RCBA + Offset 21A4h[17:15] = 100b + /// + if (((MmioRead32 ((UINTN) RootComplexBar + R_PCH_RCRB_CIR2320) & (UINT32) (BIT1)) == 0) && + ((MmioRead8 (PciD28F0RegBase + 0xF5) & BIT0) == 0)) { + Data32Or = BIT16; + } else { + Data32Or = BIT17; + } + /// + /// Step 4.2 + /// Set RCBA + Offset 21A4h[14:12] = 011b + /// + Data32Or |= BIT13 | BIT12; + Data32And = (UINT32)~(B_PCH_RCRB_LCAP_EL1 | B_PCH_RCRB_LCAP_EL0); + MmioAndThenOr32 (RootComplexBar + R_PCH_RCRB_LCAP, Data32And, Data32Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_LCAP), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + } + /// + /// Step 4.3 + /// Set RCBA + 2348[3:0] = 0h + /// + Data32Or = 0; + Data32And = (UINT32) ~(BIT0 | BIT1 | BIT2 | BIT3); + MmioAnd32 (RootComplexBar + 0x2348, Data32And); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + 0x2348), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + + /// + /// Enable DMI ASPM + /// + /// PCH BIOS Spec Rev 0.5.0, Section 8.3.1 ASPM on DMI and the PCI Express* Root Ports + /// + if (PchPlatformPolicy->DmiConfig->DmiAspm == PCH_DEVICE_ENABLE) { + /// + /// While DmiAspm is enabled, DMI ASPM will be set to Intel recommended value. + /// PCH BIOS Spec Rev 0.5.0, Section 8.3.1 ASPM on DMI and the PCI Express* Root Ports + /// Note: We recommend PCH platforms to enable L0s and L1, but unless both sides of the link have L0s and/or + /// L1 enabled they will be disabled by the link. + /// + DmiAspmCtrl = PchPcieAspmL0sL1; + } else { + DmiAspmCtrl = PchPcieAspmDisabled; + } + + if (DmiAspmCtrl != PchPcieAspmDisabled) { + if (PchSeries == PchH) { + /// + /// PCH BIOS Spec Rev 0.5.0, Section 8.3.1 + /// BIOS should set RCBA + 2304h[10] to 0b prior to enabling DMI ASPM. + /// + Data32And = (UINT32)~(BIT10); + Data32Or = 0; + MmioAnd32 (RootComplexBar + R_PCH_RCRB_DMC, Data32And); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_DMC), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + + /// + /// PCH BIOS Spec Rev 0.5.0, Section 8.3.1 + /// + /// Step 1 + /// RCBA + 21A4h[11:10] = 11b + /// + Data32And = 0xFFFFFFFF; + Data32Or = B_PCH_RCRB_LCAP_APMS; + MmioOr32 (RootComplexBar + R_PCH_RCRB_LCAP, Data32Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_LCAP), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + } + + if (DmiAspmCtrl == PchPcieAspmL0sL1) { + /// + /// Step 2 + /// Enable L0s/L1 on DMI by setting RCBA + offset 21A8h[1:0] to 11b + /// + Data16And = (UINT16) (~(BIT1 + BIT0)); + Data16Or = (UINT16) (BIT1 + BIT0); + + } else { + // + // Do nothing + // + Data16And = 0xFFFF; + Data16Or = 0; + } + if (PchSeries == PchH) { + /// + /// Program RCBA + offset 21A8h[1:0] + /// + MmioAndThenOr16 (RootComplexBar + R_PCH_RCRB_LCTL, Data16And, Data16Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (RootComplexBar + R_PCH_RCRB_LCTL), + &Data16Or, // Data to be ORed + &Data16And // Data to be ANDed + ); + /// + /// BIOS should set RCBA + 2304h[10] back to 1b after enabling DMI ASPM. + /// + Data32And = 0xFFFFFFFF; + Data32Or = (UINT32) (BIT10); + MmioOr32 (RootComplexBar + R_PCH_RCRB_DMC, Data32Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) (RootComplexBar + R_PCH_RCRB_DMC), + &Data32Or, // Data to be ORed + &Data32And // Data to be ANDed + ); + } + } + + if (PchSeries == PchH) { + if (PchPlatformPolicy->DmiConfig->DmiExtSync == PCH_DEVICE_ENABLE) { + Data16And = (UINT16) (~(B_PCH_RCRB_LCTL_ES)); + Data16Or = (UINT16) B_PCH_RCRB_LCTL_ES; + MmioAndThenOr16 (RootComplexBar + R_PCH_RCRB_LCTL, Data16And, Data16Or); + SCRIPT_MEM_READ_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (RootComplexBar + R_PCH_RCRB_LCTL), + &Data16Or, // Data to be ORed + &Data16And // Data to be ANDed + ); + } + } + + DEBUG ((EFI_D_INFO, "ConfigureDmi() End\n")); + + return EFI_SUCCESS; +} + +/** + Configure deep Sx programming + + @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 +ProgramDeepSx ( + DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy, + UINT32 RootComplexBar + ) +{ + UINT32 S3Data32; + UINT32 S4Data32; + UINT32 S5Data32; + UINTN PciD31F0RegBase; + UINT16 LpcDeviceId; + + PciD31F0RegBase = MmPciAddress (0, PchPlatformPolicy->BusNumber, 31, 0, 0); + LpcDeviceId = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_DEVICE_ID); + + /// + /// PCH BIOS Spec Rev 0.5.0, Section 19.11 Deep Sx Power Policies + /// The System BIOS can perform the following register programming guidelines to enable system + /// enter Deep S4 or Deep S5. + /// + /// DPS3_EN_DC DPS3_EN_AC DPS4_EN_DC DPS4_EN_AC DPS5_EN_DC DPS5_EN_AC + /// RCBA+3328h[1] RCBA + 3328h[0] RCBA + 332Ch[1] RCBA + 332Ch[0] RCBA + 3330h[15] RCBA + 3330h[14] + /// Deep Sx disabled 0 0 0 0 0 0 + /// + /// Enabled in S5 0 0 0 0 1 1 + /// + /// Enabled in S4 and S5 0 0 1 1 1 1 + /// + /// Enabled in S3, S4 and S5 1 1 1 1 1 1 + /// + /// Configuration supported by MOBILE: + /// Enabled in S5 0 0 0 0 1 0 + /// (Battery mode) + /// Enabled in S4 and S5 0 0 1 0 1 0 + /// (Battery Mode) + /// Enabled in S3, S4 and S5 1 0 1 0 1 0 + /// (Battery Mode) + /// + /// NOTE: Mobile platforms support Deep S4/S5 in DC ONLY, + /// Desktop and Intel C206 Chipset (LPC Dev ID 0x1C56) platforms support Deep S4/S5 in AC ONLY, + /// Intel C204 Chipset (LPC Dev ID 0x1C54) and Intel C202 Chipset (LPC Dev ID 0x1C52) platforms DO NOT support Deep S4/S5. + /// + /// Deep Sx disabled 0 0 0 0 0 0 + /// + if (IS_PCH_LPT_LPC_DEVICE_ID_DESKTOP (LpcDeviceId) || + IS_PCH_LPT_LPC_DEVICE_ID_SERVER (LpcDeviceId) || + IS_PCH_LPT_LPC_DEVICE_ID_WS (LpcDeviceId)) { + if ((PchPlatformPolicy->MiscPmConfig->PchDeepSxPol == PchMobileDpS5En) || + (PchPlatformPolicy->MiscPmConfig->PchDeepSxPol == PchMobileDpS4S5En) || + (PchPlatformPolicy->MiscPmConfig->PchDeepSxPol == PchMobileDpS3S4S5En)) { + /// + /// Set PchDeepSxPol to PchDeepSxPolDisable for unsupported deep Sx policy + /// + PchPlatformPolicy->MiscPmConfig->PchDeepSxPol = PchDeepSxPolDisable; + DEBUG ((EFI_D_ERROR, "Unsupported Deep Sx policy for desktop system\n")); + } + + } else { + if ((PchPlatformPolicy->MiscPmConfig->PchDeepSxPol == PchDesktopDpS5En) || + (PchPlatformPolicy->MiscPmConfig->PchDeepSxPol == PchDesktopDpS4S5En) || + (PchPlatformPolicy->MiscPmConfig->PchDeepSxPol == PchDesktopDpS3S4S5En)) { + /// + /// Set PchDeepSxPol to PchDeepSxPolDisable for unsupported deep Sx policy + /// + PchPlatformPolicy->MiscPmConfig->PchDeepSxPol = PchDeepSxPolDisable; + DEBUG ((EFI_D_ERROR, "Unsupported Deep Sx policy for mobile system\n")); + } + } + + switch (PchPlatformPolicy->MiscPmConfig->PchDeepSxPol) { + case PchDesktopDpS5En: + /// + /// Configuration 2: Enabled in S5/AC-DC + /// DEEP_S3_POL.DPS3_EN_DC = 0; DEEP_S3_POL.DPS3_EN_AC = 0; + /// DEEP_S4_POL.DPS4_EN_DC = 0; DEEP_S4_POL.DPS4_EN_AC = 0; + /// DEEP_S5_POL.DPS5_EN_DC = 1; DEEP_S5_POL.DPS5_EN_AC = 1; + /// + S3Data32 = 0; + S4Data32 = 0; + S5Data32 = (UINT32) (B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_AC | B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_DC); + break; + + case PchDesktopDpS4S5En: + /// + /// Configuration 4: Enabled only in S4-S5 + /// DEEP_S3_POL.DPS3_EN_DC = 0; DEEP_S3_POL.DPS3_EN_AC = 0; + /// DEEP_S4_POL.DPS4_EN_DC = 1; DEEP_S4_POL.DPS4_EN_AC = 1; + /// DEEP_S5_POL.DPS5_EN_DC = 1; DEEP_S5_POL.DPS5_EN_AC = 1; + /// + S3Data32 = 0; + S4Data32 = (UINT32) (B_PCH_RCRB_DEEP_S4_POL_DPS4_EN_AC | B_PCH_RCRB_DEEP_S4_POL_DPS4_EN_DC); + S5Data32 = (UINT32) (B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_AC | B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_DC); + break; + + case PchDesktopDpS3S4S5En: + /// + /// Configuration 6: Enabled only in S3-S4-S5 + /// DEEP_S3_POL.DPS3_EN_DC = 1; DEEP_S3_POL.DPS3_EN_AC = 1; + /// DEEP_S4_POL.DPS4_EN_DC = 1; DEEP_S4_POL.DPS4_EN_AC = 1; + /// DEEP_S5_POL.DPS5_EN_DC = 1; DEEP_S5_POL.DPS5_EN_AC = 1; + /// + S3Data32 = (UINT32) (B_PCH_RCRB_DEEP_S3_POL_DPS3_EN_AC | B_PCH_RCRB_DEEP_S3_POL_DPS3_EN_DC); + S4Data32 = (UINT32) (B_PCH_RCRB_DEEP_S4_POL_DPS4_EN_AC | B_PCH_RCRB_DEEP_S4_POL_DPS4_EN_DC); + S5Data32 = (UINT32) (B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_AC | B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_DC); + break; + + case PchMobileDpS5En: + /// + /// Configuration 1: Enabled in S5/Battery only + /// DEEP_S3_POL.DPS3_EN_DC = 0; DEEP_S3_POL.DPS3_EN_AC = 0; + /// DEEP_S4_POL.DPS4_EN_DC = 0; DEEP_S4_POL.DPS4_EN_AC = 0; + /// DEEP_S5_POL.DPS5_EN_DC = 1; DEEP_S5_POL.DPS5_EN_AC = 0; + /// + S3Data32 = 0; + S4Data32 = 0; + S5Data32 = (UINT32) (B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_DC); + break; + + case PchMobileDpS4S5En: + /// + /// Configuration 3: Enabled only in S4-S5/Battery Mode + /// DEEP_S3_POL.DPS3_EN_DC = 0; DEEP_S3_POL.DPS3_EN_AC = 0; + /// DEEP_S4_POL.DPS4_EN_DC = 1; DEEP_S4_POL.DPS4_EN_AC = 0; + /// DEEP_S5_POL.DPS5_EN_DC = 1; DEEP_S5_POL.DPS5_EN_AC = 0; + /// + S3Data32 = 0; + S4Data32 = (UINT32) (B_PCH_RCRB_DEEP_S4_POL_DPS4_EN_DC); + S5Data32 = (UINT32) (B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_DC); + break; + + case PchMobileDpS3S4S5En: + /// + /// Configuration 5: Enabled only in S4-S5/Battery Mode + /// DEEP_S3_POL.DPS3_EN_DC = 1; DEEP_S3_POL.DPS3_EN_AC = 0; + /// DEEP_S4_POL.DPS4_EN_DC = 1; DEEP_S4_POL.DPS4_EN_AC = 0; + /// DEEP_S5_POL.DPS5_EN_DC = 1; DEEP_S5_POL.DPS5_EN_AC = 0; + /// + S3Data32 = (UINT32) (B_PCH_RCRB_DEEP_S3_POL_DPS3_EN_DC); + S4Data32 = (UINT32) (B_PCH_RCRB_DEEP_S4_POL_DPS4_EN_DC); + S5Data32 = (UINT32) (B_PCH_RCRB_DEEP_S5_POL_DPS5_EN_DC); + break; + + case PchDeepSxPolDisable: + default: + /// + /// Configuration 5: DeepSx Disabled + /// DEEP_S3_POL.DPS3_EN_DC = 0; DEEP_S3_POL.DPS3_EN_AC = 0; + /// DEEP_S4_POL.DPS4_EN_DC = 0; DEEP_S4_POL.DPS4_EN_AC = 0; + /// DEEP_S5_POL.DPS5_EN_DC = 0; DEEP_S5_POL.DPS5_EN_AC = 0; + /// + S3Data32 = 0; + S4Data32 = 0; + S5Data32 = 0; + break; + } + + MmioWrite32 ((RootComplexBar + R_PCH_RCRB_DEEP_S3_POL), S3Data32); + MmioWrite32 ((RootComplexBar + R_PCH_RCRB_DEEP_S4_POL), S4Data32); + MmioWrite32 ((RootComplexBar + R_PCH_RCRB_DEEP_S5_POL), S5Data32); + + return EFI_SUCCESS; +} |