/** @file This is the driver that initializes the Intel System Agent. @copyright INTEL CONFIDENTIAL Copyright 2015 - 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 "SaInitDxe.h" #include "SaInit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPcieIoTrapAddress; /// /// Global Variables /// extern SA_CONFIG_HOB *mSaConfigHob; VOID EFIAPI SaOnReadyToBoot ( IN EFI_EVENT Event, IN VOID *Context ); /** SystemAgent Dxe Initialization. @param[in] ImageHandle Handle for the image of this driver @param[in] SystemTable Pointer to the EFI System Table @retval EFI_SUCCESS The function completed successfully @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate **/ EFI_STATUS EFIAPI SaInitEntryPointDxe ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *Registration; #if FixedPcdGetBool(PcdFspWrapperEnable) == 0 EFI_EVENT Event; #endif EFI_EVENT ReadyToBoot; DEBUG ((DEBUG_INFO, "SaInitDxe Start\n")); #if (FixedPcdGetBool (PcdVmdEnable) == 1) ClearVmdTempBars(); #endif SaInitEntryPoint (); Status = SaAcpiInit (ImageHandle); /// /// Create PCI Enumeration Completed callback for CPU PCIe /// EfiCreateProtocolNotifyEvent ( &gEfiPciEnumerationCompleteProtocolGuid, TPL_CALLBACK, CpuPciEnumCompleteCallback, NULL, &Registration ); #if FixedPcdGetBool(PcdFspWrapperEnable) == 0 DEBUG ((DEBUG_INFO, "RegisterForExitBootService() to set PAM lock before OS handoff\n")); Status = EfiCreateEventLegacyBootEx ( TPL_CALLBACK, SaPamLockDxe, NULL, &Event ); ASSERT_EFI_ERROR (Status); Status = gBS->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, SaPamLockDxe, NULL, &Event ); ASSERT_EFI_ERROR (Status); #endif // // Register a Ready to boot event to config PCIE power management setting after OPROM executed // Status = EfiCreateEventReadyToBootEx ( TPL_CALLBACK, SaOnReadyToBoot, NULL, &ReadyToBoot ); ASSERT_EFI_ERROR (Status); DEBUG ((DEBUG_INFO, "SaInitDxe End\n")); return EFI_SUCCESS; } /** Do PCIE power management while resume from S3 **/ VOID ReconfigureCpuPciePowerManagementForS3 ( VOID ) { EFI_STATUS Status; UINT32 Data32; SA_IOTRAP_SMI_PROTOCOL *CpuPcieIoTrapProtocol; Status = gBS->LocateProtocol (&gCpuPcieIoTrapProtocolGuid, NULL, (VOID **) &CpuPcieIoTrapProtocol); if (EFI_ERROR (Status)) { return; } mPcieIoTrapAddress = CpuPcieIoTrapProtocol->SaIotrapSmiAddress; DEBUG ((DEBUG_INFO, "PcieIoTrapAddress: %0x\n", mPcieIoTrapAddress)); if (mPcieIoTrapAddress != 0) { // // Save PCH PCIE IoTrap address to re-config PCIE power management setting after resume from S3 // Data32 = CpuPciePmTrap; S3BootScriptSaveIoWrite ( S3BootScriptWidthUint32, (UINTN) (mPcieIoTrapAddress), 1, &Data32 ); } else { ASSERT (FALSE); } } /** This function updates dekel register based on L0s is enabled or not **/ VOID EFIAPI CpuPcieDekelRegUpdate ( VOID ) { UINT32 RpIndex; UINT64 RpBase; UINT8 CapId; UINT16 Data16; CPU_SB_DEVICE_PID CpuSbDevicePid; DEBUG ((DEBUG_INFO, "CpuPcieDekelRegUpdate () Start\n")); for (RpIndex = 0; RpIndex < GetMaxCpuPciePortNum(); RpIndex++) { if (GetCpuPcieSipInfo(RpIndex) == PCIE_SIP16) { RpBase = CpuPcieBase (RpIndex); CapId = PcieBaseFindCapId (RpBase, EFI_PCI_CAPABILITY_ID_PCIEXP); Data16 = ((PciSegmentRead16 (RpBase + CapId + R_PCIE_LCTL_OFFSET)) & B_PCIE_LCTL_ASPM); CpuSbDevicePid = CPU_SB_PID_PCIE_PHYx4_0; if (RpIndex == 2) { CpuSbDevicePid = CPU_SB_PID_PCIE_PHYx4_2; } if (Data16 == V_PCIE_LCTL_ASPM_L0S || Data16 == V_PCIE_LCTL_ASPM_L0S_L1) { CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_CMN_DIG_DWORD54, 0x3A2024A0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE0_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE1_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE2_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE3_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0); } else { CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_CMN_DIG_DWORD54, 0x3A202FA0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE0_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE1_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE2_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0); CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE3_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0); } } } DEBUG ((DEBUG_INFO, "CpuPcieDekelRegUpdate () End\n")); } /** SA initialization before boot to OS @param[in] Event A pointer to the Event that triggered the callback. @param[in] Context A pointer to private data registered with the callback function. **/ VOID EFIAPI SaOnReadyToBoot ( IN EFI_EVENT Event, IN VOID *Context ) { DEBUG ((DEBUG_INFO, "Uefi SaOnReadyToBoot() Start\n")); if (Event != NULL) { gBS->CloseEvent (Event); } // // Trigger an Iotrap SMI to config PCIE power management setting after PCI enumrate is done // #if FixedPcdGetBool(PcdCpuPcieEnable) == 1 if (mPcieIoTrapAddress != 0) { IoWrite32 ((UINTN) mPcieIoTrapAddress, CpuPciePmTrap); } else { ASSERT(FALSE); } #endif // // Update Dekel register // if (!IsSimicsEnvironment ()) { CpuPcieDekelRegUpdate (); } DEBUG ((DEBUG_INFO, "Uefi SaOnReadyToBoot() End\n")); } /** This function gets registered as a callback to perform CPU PCIe initialization before EndOfDxe @param[in] Event - A pointer to the Event that triggered the callback. @param[in] Context - A pointer to private data registered with the callback function. **/ VOID EFIAPI CpuPciEnumCompleteCallback ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *ProtocolPointer; DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback Start\n")); /// /// Check if this is first time called by EfiCreateProtocolNotifyEvent() or not, /// if it is, we will skip it until real event is triggered /// Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **) &ProtocolPointer); if (EFI_SUCCESS != Status) { return; } gBS->CloseEvent (Event); ReconfigureCpuPciePowerManagementForS3 (); SaveGfxBarForS3 (); SaveIpuBarForS3 (); // // Routine for update DMAR // UpdateDmarEndOfPcieEnum (); UpdateSaGnvsForMmioResourceBaseLength (); #if FixedPcdGetBool(PcdFspWrapperEnable) == 0 TelemetryMseEn (); #endif DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback End\n")); return; } /** This function locks the PAM register as part of the SA Security requirements. @param[in] Event - A pointer to the Event that triggered the callback. @param[in] Context - A pointer to private data registered with the callback function. **/ VOID EFIAPI SaPamLockDxe ( IN EFI_EVENT Event, IN VOID *Context ) { DEBUG ((DEBUG_INFO, "SaPamLockDxe Start\n")); SaPamLock (); DEBUG ((DEBUG_INFO, "SaPamLockDxe End\n")); }