alder_lake_bios/Intel/AlderLake/ClientOneSiliconPkg/Pch/PchInit/Dxe/PchInit.c

502 lines
15 KiB
C

/** @file
This is the Common driver that initializes the Intel PCH.
;******************************************************************************
;* Copyright (c) 2019, Insyde Software Corporation. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
@copyright
INTEL CONFIDENTIAL
Copyright 1999 - 2021 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains an 'Intel Peripheral Driver' and is 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.
@par Specification Reference:
**/
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/PciSegmentLib.h>
#include <Library/TimerLib.h>
#include <Library/S3BootScriptLib.h>
#include <Library/HobLib.h>
#include "PchInit.h"
#include <PchPolicyCommon.h>
#include <Library/SpiCommonLib.h>
#include <Library/PmcPrivateLib.h>
#include <Library/PchDmiLib.h>
#include <Library/SiScheduleResetLib.h>
#include <Library/PchCycleDecodingLib.h>
#include <Library/PchPcrLib.h>
#include <IndustryStandard/Pci30.h>
#include <Library/SpiAccessPrivateLib.h>
#include <Library/EspiAccessPrivateLib.h>
#include <Register/PchRegs.h>
#include <Register/PchPcrRegs.h>
#include <Register/PchRegsLpc.h>
#include <Register/SpiRegs.h>
#include <Register/PchRegsPsth.h>
#include <Register/TcoRegs.h>
#include <Register/HdaRegs.h>
#include <Library/GpioCheckConflictLib.h>
#include <Library/PchPciBdfLib.h>
#include <Library/PchInfoLib.h>
#include <Library/UsbLib.h>
#include <Library/DciPrivateLib.h>
//
// Module variables
//
GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB *mPchConfigHob;
//
// EFI_EVENT
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_EVENT mHeciEvent;
/**
Common PchInit Module Entry Point
**/
VOID
PchInitEntryPointCommon (
VOID
)
{
EFI_PEI_HOB_POINTERS HobPtr;
DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() Start\n"));
//
// Get PCH Config HOB.
//
HobPtr.Guid = GetFirstGuidHob (&gPchConfigHobGuid);
ASSERT (HobPtr.Guid != NULL);
mPchConfigHob = (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA (HobPtr.Guid);
DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n"));
return;
}
/**
Lock SPI register before boot
**/
VOID
LockSpiConfiguration (
VOID
)
{
UINTN Index;
//[-start-171027-IB10870405-remove]//
// UINT16 Data16;
// UINT16 Data16And;
// UINT16 Data16Or;
//[-end-171027-IB10870405-remove]//
UINT32 Data32;
UINT32 DlockValue;
UINT64 PciSpiRegBase;
UINT32 PchSpiBar0;
//[-start-171027-IB10870405-remove]//
// UINT32 Timer;
//[-end-171027-IB10870405-remove]//
PciSpiRegBase = SpiPciCfgBase ();
//
// Check for SPI controller presence before programming
//
if (PciSegmentRead16 (PciSpiRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
return;
}
//
// Make sure SPI BAR0 has fixed address before writing to boot script.
// The same base address is set in PEI and will be used during resume.
//
PchSpiBar0 = PCH_SPI_BASE_ADDRESS;
PciSegmentAnd8 (PciSpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE);
PciSegmentWrite32 (PciSpiRegBase + R_SPI_CFG_BAR0, PchSpiBar0);
PciSegmentOr8 (PciSpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
//
// Locking for security reasons only if Extended BIOS Range Decode is supported
//
if (IsExtendedBiosRangeDecodeSupported ()) {
//
// Before setting FLOCKDN lock Extended BIOS Range configuration
// All configuration of this feature shall be done already at this moment
//
PciSegmentOr32 (PciSpiRegBase + R_SPI_CFG_BC, B_SPI_CFG_BC_EXT_BIOS_LOCK);
S3BootScriptSavePciCfgWrite (
S3BootScriptWidthUint32,
(UINTN) PciSpiRegBase + R_SPI_CFG_BC,
1,
(VOID *) (UINTN) (PciSpiRegBase + R_SPI_CFG_BC)
);
}
//
// Program the Flash Protection Range Register based on policy
//
DlockValue = MmioRead32 (PchSpiBar0 + R_SPI_MEM_DLOCK);
for (Index = 0; Index < PCH_FLASH_PROTECTED_RANGES; ++Index) {
if ((mPchConfigHob->ProtectRange[Index].WriteProtectionEnable ||
mPchConfigHob->ProtectRange[Index].ReadProtectionEnable) != TRUE) {
continue;
}
//
// Proceed to program the register after ensure it is enabled
//
Data32 = 0;
Data32 |= (mPchConfigHob->ProtectRange[Index].WriteProtectionEnable == TRUE) ? B_SPI_MEM_PRX_WPE : 0;
Data32 |= (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable == TRUE) ? B_SPI_MEM_PRX_RPE : 0;
Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeLimit << N_SPI_MEM_PRX_PRL) & B_SPI_MEM_PRX_PRL_MASK;
Data32 |= ((UINT32) mPchConfigHob->ProtectRange[Index].ProtectedRangeBase << N_SPI_MEM_PRX_PRB) & B_SPI_MEM_PRX_PRB_MASK;
DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index, Data32));
DlockValue |= (UINT32) (B_SPI_MEM_DLOCK_PR0LOCKDN << Index);
MmioWrite32 ((UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))), Data32);
S3BootScriptSaveMemWrite (
S3BootScriptWidthUint32,
(UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX))),
1,
(VOID *) (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * S_SPI_MEM_PRX)))
);
}
//
// Program DLOCK register
//
MmioWrite32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), DlockValue);
S3BootScriptSaveMemWrite (
S3BootScriptWidthUint32,
(UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK),
1,
(VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK)
);
///
/// PCH BIOS Spec Section 3.6 Flash Security Recommendation
/// In PCH SPI controller the BIOS should set the Flash Configuration Lock-Down bit
/// (SPI_BAR0 + 04[15]) at end of post. When set to 1, those Flash Program Registers
/// that are locked down by this FLOCKDN bit cannot be written.
/// Please refer to the EDS for which program registers are impacted.
/// Additionally BIOS must program SPI_BAR0 + 0x04 BIT11 (WRSDIS) to disable Write Status in HW sequencing
///
//
// Ensure there is no pending SPI trasaction before setting lock bits
//
//[-start-171025-IB10870405-remove]//
// Timer = 0;
// while (MmioRead16 (PchSpiBar0 + R_SPI_MEM_HSFSC) & B_SPI_MEM_HSFSC_SCIP) {
// if (Timer > SPI_WAIT_TIME) {
// //
// // SPI transaction is pending too long at this point, exit with error.
// //
// DEBUG ((DEBUG_ERROR, "SPI Cycle timeout\n"));
// ASSERT (FALSE);
// break;
// }
// MicroSecondDelay (SPI_WAIT_PERIOD);
// Timer += SPI_WAIT_PERIOD;
// }
//
// Data16And = B_SPI_MEM_HSFSC_SCIP;
// Data16 = 0;
// S3BootScriptSaveMemPoll (
// S3BootScriptWidthUint16,
// PchSpiBar0 + R_SPI_MEM_HSFSC,
// &Data16And,
// &Data16,
// SPI_WAIT_PERIOD,
// SPI_WAIT_TIME / SPI_WAIT_PERIOD
// );
//
// //
// // Clear any outstanding status
// //
// Data16Or = B_SPI_MEM_HSFSC_SAF_DLE
// | B_SPI_MEM_HSFSC_SAF_ERROR
// | B_SPI_MEM_HSFSC_AEL
// | B_SPI_MEM_HSFSC_FCERR
// | B_SPI_MEM_HSFSC_FDONE;
// Data16And = 0xFFFF;
// MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);
// S3BootScriptSaveMemReadWrite (
// S3BootScriptWidthUint16,
// PchSpiBar0 + R_SPI_MEM_HSFSC,
// &Data16Or,
// &Data16And
// );
//
// //
// // Set WRSDIS
// //
// Data16Or = B_SPI_MEM_HSFSC_WRSDIS;
// Data16And = 0xFFFF;
// MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);
// S3BootScriptSaveMemReadWrite (
// S3BootScriptWidthUint16,
// PchSpiBar0 + R_SPI_MEM_HSFSC,
// &Data16Or,
// &Data16And
// );
//
// //
// // Set FLOCKDN
// //
// Data16Or = B_SPI_MEM_HSFSC_FLOCKDN;
// Data16And = 0xFFFF;
// MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, Data16Or);
// S3BootScriptSaveMemReadWrite (
// S3BootScriptWidthUint16,
// PchSpiBar0 + R_SPI_MEM_HSFSC,
// &Data16Or,
// &Data16And
// );
//[-end-171025-IB10870405-remove]//
///
/// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock
/// It is strongly recommended that BIOS sets the Vendor Component Lock (VCL) bits. VCL applies
/// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Without the VCL bits set, it is
/// possible to make Host/GbE VSCC register(s) changes in that can cause undesired host and
/// integrated GbE Serial Flash functionality.
///
MmioOr32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0), B_SPI_MEM_SFDP0_VSCC0_VCL);
S3BootScriptSaveMemWrite (
S3BootScriptWidthUint32,
(UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0),
1,
(VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0)
);
}
/**
Process all the lock downs
**/
VOID
ProcessAllLocks (
VOID
)
{
UINT16 Data16And;
UINT16 Data16Or;
UINT16 TcoBase;
PchTcoBaseGet (&TcoBase);
//
// Lock function disable (ST and NST PG) register fields.
//
PmcLockFunctionDisableConfigWithS3BootScript ();
///
/// CNL PCH BWG Additional PCH DMI and OP-DMI Programming Steps
/// Lock DMI.
///
PchDmiSetLockWithS3BootScript ();
//
// Lock SPI register before boot.
//
LockSpiConfiguration ();
///
/// Additional Power Management Programming
/// Step 3
/// Lock configuration after stretch and ACPI base programming completed.
///
PmcLockSlpSxStretchingPolicyWithS3BootScript ();
//
// Set BiosLock amd BIOS interface lock.
//
SpiBiosLockEnableAndBiosInterfaceLockWithS3BootScript (
(BOOLEAN) mPchConfigHob->LockDown.BiosLock,
(BOOLEAN) mPchConfigHob->LockDown.BiosInterface,
(BOOLEAN) mPchConfigHob->LockDown.SpiEiss
);
EspiBiosLockEnableAndBiosInterfaceLockWithS3BootScript (
(BOOLEAN) mPchConfigHob->LockDown.BiosLock,
(BOOLEAN) mPchConfigHob->LockDown.BiosInterface,
(BOOLEAN) mPchConfigHob->LockDown.SpiEiss
);
//
// Lock Down TCO
//
Data16And = 0xFFFF;
Data16Or = B_TCO_IO_TCO1_CNT_LOCK;
IoOr16 (TcoBase + R_TCO_IO_TCO1_CNT, Data16Or);
S3BootScriptSaveIoReadWrite (
S3BootScriptWidthUint16,
(UINTN) (TcoBase + R_TCO_IO_TCO1_CNT),
&Data16Or, // Data to be ORed
&Data16And // Data to be ANDed
);
///
/// PCH BIOS Spec Section 5.15.1 Additional Chipset Initialization
/// Step 1
/// Lock PMC Set Strap Message Interface
///
PmcLockSetStrapMsgInterfaceWithS3BootScript ();
//
// Lock Down PMC
//
PmcLockWithS3BootScript ();
}
/**
Set HD Audio PME bit
**/
VOID
ConfigureHdAudioPme (
VOID
)
{
UINT64 HdaPciBase;
HdaPciBase = HdaPciCfgBase ();
if (PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
return;
}
///
/// PME Enable for Audio controller
///
if (mPchConfigHob->HdAudio.Pme == TRUE) {
PciSegmentOr32 (HdaPciBase + R_HDA_CFG_PCS, (UINT32) B_HDA_CFG_PCS_PMEE);
}
}
/**
Set eSPI BME bit
**/
VOID
ConfigureEspiBme (
VOID
)
{
UINT64 EspiPciBase;
EspiPciBase = EspiPciCfgBase ();
if (PciSegmentRead16 (EspiPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
return;
}
if ((PciSegmentRead32 (EspiPciBase + R_ESPI_CFG_PCBC) & B_ESPI_CFG_PCBC_ESPI_EN) == 0) {
return;
}
//
// Refer to PCH BWG.
// To enable eSPI bus mastering BIOS must enable BME in eSPI controller
// and also set BME bit in the respective target devices through Configuration
// and Capabilities register of each target using Get_Configuration and Set_Configuration functionality.
//
// NOTE: The setting is also done in PEI, but might be cleared by PCI bus during PCI enumeration.
// Therefore, reeable it after PCI enumeration done.
//
if (mPchConfigHob->Espi.BmeMasterSlaveEnabled == TRUE) {
PciSegmentOr8 (EspiPciBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_BUS_MASTER);
}
}
/**
Common PCH initialization before Boot Sript Table is closed
**/
VOID
PchOnPciEnumCompleteCommon (
VOID
)
{
UINT32 Data32Or;
UINT32 Data32And;
BOOLEAN ResetStatus;
DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() Start\n"));
if (SiScheduleResetIsRequired ()) {
ResetStatus = SiScheduleResetPerformReset ();
ASSERT (!ResetStatus);
}
ProcessAllLocks ();
//
// PSTHCTL (0xD00h[2]) = 1, PSTH IOSF Primary Trunk Clock Gating Enable (PSTHIOSFPTCGE)
//
Data32And = 0xFFFFFFFF;
Data32Or = B_PSTH_PCR_PSTHIOSFPTCGE;
PchPcrAndThenOr32 (PID_PSTH, R_PSTH_PCR_PSTHCTL, Data32And, Data32Or);
PCH_PCR_BOOT_SCRIPT_READ_WRITE (
S3BootScriptWidthUint32,
PID_PSTH, R_PSTH_PCR_PSTHCTL,
&Data32Or,
&Data32And
);
//
// Set eSPI BME after PCI enumeration
//
ConfigureEspiBme ();
//
// Set HD Audio PME after PCI Enumeration since bit gets cleared by PCI bus driver
//
ConfigureHdAudioPme ();
///
/// Clear Global Reset Status, Power Failure and Host Reset Status bits
///
PmcClearGlobalResetStatus ();
PmcClearPowerFailureStatus ();
PmcClearHostResetStatus ();
#ifndef MDEPKG_NDEBUG
GpioCheckConflict ();
#endif // MDEPKG_NDEBUG
if (IsDciDebugEnabled ()) {
//
// Enable workaround for Windows kernel debugger connected through Xhci
//
XhciMmioEnable ();
}
DEBUG ((DEBUG_INFO, "PchOnPciEnumCompleteCommon() End\n"));
}