summaryrefslogtreecommitdiff
path: root/ReferenceCode/ME/PchMeUma/PchMeUma.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/ME/PchMeUma/PchMeUma.c')
-rw-r--r--ReferenceCode/ME/PchMeUma/PchMeUma.c765
1 files changed, 765 insertions, 0 deletions
diff --git a/ReferenceCode/ME/PchMeUma/PchMeUma.c b/ReferenceCode/ME/PchMeUma/PchMeUma.c
new file mode 100644
index 0000000..dd8b51b
--- /dev/null
+++ b/ReferenceCode/ME/PchMeUma/PchMeUma.c
@@ -0,0 +1,765 @@
+/** @file
+ Framework PEIM to PchMeUma
+
+@copyright
+ Copyright (c) 2010 - 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
+
+**/
+
+//
+// Statements that include other files
+//
+#include "EdkIIGluePeim.h"
+#include "MeAccess.h"
+#include "HeciRegs.h"
+#include "Pci22.h"
+#include "PchMeUma.h"
+#include "PchPlatformLib.h"
+#include "PttHciDeviceLib.h"
+#include "PttHciRegs.h"
+#include EFI_PPI_DEFINITION (PchMeUma)
+#ifdef PTT_FLAG
+#include EFI_PPI_DEFINITION (MePlatformPolicyPei)
+#endif
+#include EFI_PPI_DEFINITION (Stall)
+#include EFI_PPI_CONSUMER (Wdt)
+
+//
+// Function Declarations
+//
+static PCH_ME_UMA_PPI mPchMeUmaPpi = {
+ MeSendUmaSize,
+ CpuReplacementCheck,
+ MeConfigDidReg,
+ HandleMeBiosAction
+};
+
+static EFI_PEI_PPI_DESCRIPTOR mPchMeUmaPpiList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gPchMeUmaPpiGuid,
+ &mPchMeUmaPpi
+ }
+};
+
+/**
+ This procedure will read and return the amount of ME UMA requested
+ by ME ROM from the HECI device.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] FfsHeader Pointer to the FFS file header
+
+ @retval UINT32 Return ME UMA Size
+ @retval EFI_SUCCESS Do not check for ME UMA
+**/
+UINT32
+MeSendUmaSize (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT32 Timeout;
+ HECI_MISC_SHDW_REGISTER MeMiscShdw;
+ HECI_FWS_REGISTER MeHfs;
+ EFI_STATUS Status;
+ PEI_STALL_PPI *StallPpi;
+
+ MeMiscShdw.ul = HeciPciRead32 (R_ME_MISC_SHDW);
+ MeHfs.ul = HeciPciRead32 (R_ME_HFS);
+ Timeout = 0x0;
+
+ if (MeHfs.r.MeOperationMode == ME_OPERATION_MODE_DEBUG) {
+ DEBUG ((EFI_D_INFO, "ME debug mode, do not check for ME UMA. \n"));
+ return EFI_SUCCESS;
+ }
+
+ if (MeHfs.r.ErrorCode != 0) {
+ DEBUG ((EFI_D_INFO, "ME error, do not check for ME UMA. \n"));
+ return EFI_SUCCESS;
+ }
+ ///
+ /// Poll on MUSZV until it indicates a valid size is present or 5s timeout expires.
+ ///
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, (VOID **) &StallPpi);
+ ASSERT_PEI_ERROR (PeiServices, Status);
+
+ PERF_START_EX (FfsHeader, L"MUSZV", NULL, AsmReadTsc (), 0x4000);
+ while ((MeMiscShdw.r.MUSZV == 0) && (Timeout < MUSZV_TIMEOUT_MULTIPLIER)) {
+ StallPpi->Stall (PeiServices, StallPpi, STALL_1_MILLISECOND);
+ MeMiscShdw.ul = HeciPciRead32 (R_ME_MISC_SHDW);
+ Timeout++;
+ }
+
+ if (Timeout >= MUSZV_TIMEOUT_MULTIPLIER) {
+ DEBUG ((EFI_D_INFO, "Timeout occurred waiting for MUSZV. \n"));
+ return EFI_SUCCESS;
+ }
+ PERF_END_EX (FfsHeader, L"MUSZV", NULL, AsmReadTsc (), 0x4001);
+
+ ///
+ /// Return MeUmaSize value
+ ///
+ DEBUG ((EFI_D_INFO, "ME UMA Size Requested: %x\n", MeMiscShdw.r.MUSZ));
+
+ return MeMiscShdw.r.MUSZ;
+}
+
+/**
+ Init and Install ME Hob
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+InstallMeHob (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ ME_DATA_HOB *MeDataHob;
+
+ ///
+ /// Create HOB for ME Data
+ ///
+ Status = (**PeiServices).CreateHob (
+ PeiServices,
+ EFI_HOB_TYPE_GUID_EXTENSION,
+ sizeof (ME_DATA_HOB),
+ &MeDataHob
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Initialize default HOB data
+ ///
+ MeDataHob->EfiHobGuidType.Name = gMeDataHobGuid;
+ ZeroMem (&(MeDataHob->FtpmBufferAddress), sizeof (UINT64));
+
+ DEBUG ((EFI_D_INFO, "ME Data HOB installed\n"));
+
+ return EFI_SUCCESS;
+}
+
+#ifdef PTT_FLAG
+/**
+ Internal function performing Heci platform ME Debug Dump in PEI phase
+
+ @param[in] PeiMePolicyPpi Policy Ppi
+
+ @retval None
+**/
+VOID
+DumpMePlatformPolicyPei (
+ IN PEI_ME_PLATFORM_POLICY_PPI *PeiMePolicyPpi
+ )
+{
+ DEBUG ((EFI_D_INFO, "\n------------------------ MePlatformPolicyPpi Dump Begin -----------------\n"));
+ DEBUG ((EFI_D_INFO, " Revision : 0x%x\n", PeiMePolicyPpi->Revision));
+ DEBUG ((EFI_D_INFO, " FTpmSwitch : 0x%x\n", PeiMePolicyPpi->FTpmSwitch));
+ DEBUG ((EFI_D_INFO, "\n------------------------ MePlatformPolicyPpi Dump End -------------------\n"));
+}
+#endif
+
+/**
+ This procedure will determine whether or not the CPU was replaced
+ during system power loss or via dynamic fusing.
+ Calling this procedure could result in a warm reset (if ME FW is requesting one).
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] FfsHeader Not used.
+ @param[out] ForceFullTraining When set = 0x1, MRC will be forced to perform a full
+ memory training cycle.
+
+ @retval EFI_SUCCESS The function completed successfully.
+**/
+EFI_STATUS
+CpuReplacementCheck (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ OUT UINT8 *ForceFullTraining
+ )
+{
+ HECI_GS_SHDW_REGISTER MeFwsts2;
+ EFI_STATUS Status;
+ UINT32 Timeout;
+ PEI_STALL_PPI *StallPpi;
+ Status = EFI_SUCCESS;
+ Timeout = 0x0;
+
+ ///
+ /// Read ME FWS2
+ ///
+ MeFwsts2.ul = HeciPciRead32 (R_ME_GS_SHDW);
+ DEBUG ((EFI_D_INFO, "MeFwsts2 = %x.\n", MeFwsts2.r));
+
+ ///
+ /// Locate Stall Ppi
+ ///
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, (VOID **) &StallPpi);
+ ASSERT_PEI_ERROR (PeiServices, Status);
+
+ PERF_START_EX (FfsHeader, L"CPURLOP", NULL, AsmReadTsc (), 0x4010);
+ ///
+ /// Poll 50 ms on CPU Replaced Valid bit
+ ///
+ while ((((MeFwsts2.r.CpuReplacedValid == 0) && Timeout < CPURV_TIMEOUT_MULTIPLIER))
+ ) {
+ StallPpi->Stall (PeiServices, StallPpi, STALL_1_MILLISECOND);
+ MeFwsts2.ul = HeciPciRead32 (R_ME_GS_SHDW);
+ Timeout++;
+ }
+ PERF_END_EX (FfsHeader, L"CPURLOP", NULL, AsmReadTsc (), 0x4011);
+
+ DEBUG ((EFI_D_INFO, "CpuReplacedValid = %x, ", MeFwsts2.r.CpuReplacedValid));
+ DEBUG ((EFI_D_INFO, "CpuReplacedStatus = %x, ", MeFwsts2.r.CpuReplacedSts));
+ DEBUG ((EFI_D_INFO, "WarmRstReqForDF = %x.\n", MeFwsts2.r.WarmRstReqForDF));
+
+ if (Timeout >= CPURV_TIMEOUT_MULTIPLIER || MeFwsts2.r.CpuReplacedValid == 0x0) {
+ DEBUG ((EFI_D_ERROR, "Timeout occurred, the CPU Replacement Valid Bit is not set.\n"));
+ *ForceFullTraining = 0x1;
+ } else {
+ if (MeFwsts2.r.CpuReplacedValid == 0x1) {
+ if (MeFwsts2.r.WarmRstReqForDF == 0x1) {
+ ///
+ /// Clear DISB and Issue a Non-Power Cycle Reset
+ ///
+ Status = ClearDisb ();
+ Status = PerformReset (PeiServices, CBM_DIR_NON_PCR);
+ }
+
+ if ((MeFwsts2.r.CpuReplacedSts == 0x1 && MeFwsts2.r.WarmRstReqForDF == 0x0)) {
+ *ForceFullTraining = 0x1;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This procedure will configure the ME Host General Status register,
+ indicating that DRAM Initialization is complete and ME FW may
+ begin using the allocated ME UMA space.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] FfsHeader Pointer to the FFS file header
+ @param[in] MrcBootMode MRC BootMode
+ @param[in] InitStat H_GS[27:24] Status
+ @param[in] FtpmStolenBase The base of FTPM
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+MeConfigDidReg (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN MRC_BOOT_MODE_T MrcBootMode,
+ IN UINT8 InitStat,
+ IN UINT32 FtpmStolenBase,
+ IN UINT32 MeUmaSize
+ )
+{
+ UINT32 MeUmaBase;
+ UINT32 MeUmaBaseExt;
+ UINT32 MeHgs;
+ UINT32 Timeout;
+ HECI_FWS_REGISTER MeHfs;
+ EFI_STATUS Status;
+ PEI_STALL_PPI *StallPpi;
+#ifdef PTT_FLAG
+ PEI_ME_PLATFORM_POLICY_PPI *PeiMePolicyPpi;
+ EFI_GUID gPeiMePlatformPolicyPpiGuid = PEI_ME_PLATFORM_POLICY_PPI_GUID;
+ ME_DATA_HOB *MeDataHob;
+ EFI_GUID gMeDataHobGuid = ME_DATA_HOB_GUID;
+ UINT32 RegRead;
+ UINT32 WaitTime;
+#endif //PTT_FLAG
+
+#ifdef PTT_FLAG
+ ///
+ /// Get platform policy settings through the MePlatformPolicy PPI
+ ///
+ Status = (**PeiServices).LocatePpi (
+ PeiServices,
+ &gPeiMePlatformPolicyPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PeiMePolicyPpi
+ );
+ ASSERT_PEI_ERROR (PeiServices, Status);
+
+ DumpMePlatformPolicyPei (PeiMePolicyPpi);
+#endif //PTT_FLAG
+
+
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, (VOID **) &StallPpi);
+ ASSERT_PEI_ERROR (PeiServices, Status);
+
+ MeHgs = 0x0;
+ Timeout = 0x0;
+ MeHfs.ul = HeciPciRead32 (R_ME_HFS);
+
+ DEBUG ((EFI_D_INFO, "ME status: 0x%08x\n", MeHfs.ul));
+
+ if (MeHfs.r.MeOperationMode == ME_OPERATION_MODE_DEBUG) {
+ DEBUG ((EFI_D_INFO, "ME debug mode, do not check for ME UMA. \n"));
+ return EFI_SUCCESS;
+ }
+
+ if (MeHfs.r.ErrorCode != 0) {
+ DEBUG ((EFI_D_INFO, "ME error, do not check for ME UMA. \n"));
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_INFO, "Entered ME DRAM Init Done procedure.\n"));
+
+#ifdef PTT_FLAG
+ if ((GetPchSeries() == PchLp) &&
+ (MmioRead32 (R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_STS)& BIT0) &&
+ (PeiMePolicyPpi->FTpmSwitch == 0) &&
+ (InitStat != 0x1)) {
+ ///
+ /// Install ME HOBs
+ ///
+ InstallMeHob (PeiServices);
+
+ MeDataHob = NULL;
+ MeDataHob = GetFirstGuidHob (&gMeDataHobGuid);
+
+ if (MeDataHob != NULL) {
+ MeDataHob->FtpmBufferAddress = FtpmStolenBase;
+ DEBUG ((EFI_D_INFO, " Ftpm Allocated Buffer Address: %x\n", MeDataHob->FtpmBufferAddress ));
+
+ ///
+ /// Poll Ready Bit
+ ///
+ RegRead = 0;
+ for (WaitTime = 0; WaitTime < PTT_HCI_TIMEOUT_B * 3; WaitTime += PTT_HCI_POLLING_PERIOD){
+ RegRead = MmioRead32 (R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_STS);
+ DEBUG ((EFI_D_INFO, " Ftpm Waiting on Ready Bit, HCI_STS Register = %x\n", RegRead));
+ if((BIT1 & RegRead) != 0){
+ MmioWrite64 ((UINTN)(R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_CRB),(UINTN) MeDataHob->FtpmBufferAddress );
+ ///
+ /// Issue command to start.
+ ///
+ MmioWrite32 ((UINTN)R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_CA_START, V_PTT_HCI_BUFFER_ADDRESS_RDY);
+ if( MeUmaSize == 32 )
+ {
+ ///
+ /// Trigger interrupt command processing only for 5MB sku
+ ///
+ MmioWrite32 ((UINTN)R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_CMD, 0);
+ }
+ break;
+ }
+ StallPpi->Stall (PeiServices, StallPpi, PTT_HCI_POLLING_PERIOD);
+ }
+
+ ///
+ /// Poll state, wait for Ftpm to finish processing
+ ///
+ for (WaitTime = 0; WaitTime < PTT_HCI_TIMEOUT_B; WaitTime += PTT_HCI_POLLING_PERIOD){
+ RegRead = MmioRead32 (R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_CA_START);
+ if (RegRead == 0){
+ break;
+ }
+ StallPpi->Stall (PeiServices, StallPpi, PTT_HCI_POLLING_PERIOD);
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, "ME DataHob error, MeDataHob not found\n"));
+ }
+ }
+#endif
+
+ ///
+ /// Read MESEGBASE value
+ ///
+ MeUmaBase = PciRead32 (PCI_LIB_ADDRESS (0, 0, 0, R_MESEG_BASE));
+ MeUmaBaseExt = PciRead32 (PCI_LIB_ADDRESS (0, 0, 0, R_MESEG_BASE + 0x04));
+ DEBUG ((EFI_D_INFO, " MeUmaBase read: %x\n", MeUmaBase));
+
+ ///
+ /// Write DRAM Init Done (DID) data to the ME H_GS[23:0].
+ /// H_GS[23:16] = extended UMA base address (reserved)
+ /// H_GS[15:0] = 1M aligned UMA base address
+ /// ME FW will 0 extend these values to determine MeUmaBase
+ ///
+ MeUmaBase = ((MeUmaBaseExt << 28) + (MeUmaBase >> 4)) >> 16;
+ MeHgs = MeUmaBase;
+
+ ///
+ /// Set H_GS[31:28] = 0x1 indicating DRAM Init Done
+ ///
+ MeHgs |= B_ME_DID_TYPE_MASK;
+
+ ///
+ /// RapidStart
+ ///
+ if (InitStat & 0x80) {
+ MeHgs |= B_ME_DID_RAPID_START_BIT;
+ }
+
+ InitStat &= 0x7F;
+
+ ///
+ /// Set H_GS[27:24] = Status
+ /// 0x0 = Success
+ /// 0x1 = No Memory in channels
+ /// 0x2 = Memory Init Error
+ /// 0x3 = Memory not preserved across reset
+ /// 0x4-0xF = Reserved
+ ///
+ MeHgs |= (InitStat << 24);
+
+ PERF_START_EX (FfsHeader, L"DID", NULL, AsmReadTsc (), 0x4020);
+ HeciPciAndThenOr32 (R_ME_H_GS, 0, MeHgs);
+ DEBUG ((EFI_D_INFO, " ME H_GS written: %x\n", MeHgs));
+
+ ///
+ /// ME FW typically responds with the DID ACK w/in 1ms
+ /// Adding short delay to avoid wasting time in the timeout loop
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, STALL_1_MILLISECOND + STALL_100_MICROSECONDS);
+
+ ///
+ /// Read the ME H_FS Register to look for DID ACK.
+ ///
+ MeHfs.ul = HeciPciRead32 (R_ME_HFS);
+ DEBUG ((EFI_D_INFO, " HFS read before DID ACK: %x\n", MeHfs.r));
+
+ ///
+ /// ~5 second Timeout for DID ACK
+ ///
+ while (((MeHfs.r.BiosMessageAck == 0) && Timeout < DID_TIMEOUT_MULTIPLIER)
+ ) {
+ StallPpi->Stall (PeiServices, StallPpi, STALL_1_MILLISECOND);
+ MeHfs.ul = HeciPciRead32 (R_ME_HFS);
+ Timeout++;
+ }
+
+ if ((Timeout >= DID_TIMEOUT_MULTIPLIER)
+ ) {
+ DEBUG ((EFI_D_ERROR, "Timeout occurred waiting for DID ACK.\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "ME DRAM Init Done ACK received.\n"));
+ DEBUG ((EFI_D_INFO, "HFS read after DID ACK: %x\n", MeHfs.r));
+ }
+ PERF_END_EX (FfsHeader, L"DID", NULL, AsmReadTsc (), 0x4021);
+
+ DEBUG ((EFI_D_ERROR, "BiosAction = %x\n", MeHfs.r.AckData));
+
+ return HandleMeBiosAction (PeiServices, MrcBootMode, (UINT8) MeHfs.r.AckData);
+}
+
+/**
+ This procedure will enforce the BIOS Action that was requested by ME FW
+ as part of the DRAM Init Done message.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] MrcBootMode MRC BootMode
+ @param[in] BiosAction Me requests BIOS to act
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS
+**/
+EFI_STATUS
+HandleMeBiosAction (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN MRC_BOOT_MODE_T MrcBootMode,
+ IN UINT8 BiosAction
+ )
+{
+ EFI_STATUS Status;
+ HECI_GS_SHDW_REGISTER MeFwsts2;
+ ///
+ /// Read ME FWS2
+ ///
+ MeFwsts2.ul = HeciPciRead32 (R_ME_GS_SHDW);
+ DEBUG ((EFI_D_INFO, "MeFwsts2 = %x.\n", MeFwsts2.r));
+
+ switch (BiosAction) {
+ case 0:
+ ///
+ /// Case: DID ACK was not received
+ ///
+ DEBUG ((EFI_D_ERROR, "DID Ack was not received, no BIOS Action to process.\n"));
+ break;
+
+ case CBM_DIR_NON_PCR:
+ ///
+ /// Case: Perform Non-Power Cycle Reset
+ ///
+ DEBUG ((EFI_D_ERROR, "ME FW has requested a Non-PCR.\n"));
+ Status = PerformReset (PeiServices, CBM_DIR_NON_PCR);
+ break;
+
+ case CBM_DIR_PCR:
+ ///
+ /// Case: Perform Power Cycle Reset
+ ///
+ DEBUG ((EFI_D_ERROR, "ME FW has requested a PCR.\n"));
+ Status = PerformReset (PeiServices, CBM_DIR_PCR);
+ break;
+
+ case 3:
+ ///
+ /// Case: Go To S3
+ ///
+ DEBUG ((EFI_D_INFO, "ME FW DID ACK has requested entry to S3. Not defined, continuing to POST.\n"));
+ break;
+
+ case 4:
+ ///
+ /// Case: Go To S4
+ ///
+ DEBUG ((EFI_D_INFO, "ME FW DID ACK has requested entry to S4. Not defined, continuing to POST.\n"));
+ break;
+
+ case 5:
+ ///
+ /// Case: Go To S5
+ ///
+ DEBUG ((EFI_D_INFO, "ME FW DID ACK has requested entry to S5. Not defined, continuing to POST.\n"));
+ break;
+
+ case CBM_DIR_GLOBAL_RESET:
+ ///
+ /// Case: Perform Global Reset
+ ///
+ DEBUG ((EFI_D_ERROR, "ME FW has requested a Global Reset.\n"));
+ Status = PerformReset (PeiServices, CBM_DIR_GLOBAL_RESET);
+ break;
+
+ case CBM_DIR_CONTINUE_POST:
+ ///
+ /// Case: Continue to POST
+ ///
+ DEBUG ((EFI_D_INFO, "ME FW DID Ack requested to continue to POST.\n"));
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will issue a Non-Power Cycle, Power Cycle, or Global Rest.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] ResetType Type of reset to be issued.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval All other error conditions encountered result in an ASSERT.
+**/
+EFI_STATUS
+PerformReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ UINT8 ResetType
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ETR3;
+ UINT32 GpioBase;
+ UINT8 Reset;
+ WDT_PPI *Wdt;
+ PCH_SERIES PchSeries;
+
+ ETR3 = 0;
+ Reset = 0;
+ GpioBase = 0;
+ Wdt = NULL;
+ PchSeries = GetPchSeries();
+
+ ///
+ /// Locate WDT PPI for access to Wdt->AllowKnownReset()
+ ///
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gWdtPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &Wdt
+ );
+ ASSERT_PEI_ERROR (PeiServices, Status);
+
+ ///
+ /// Clear CF9GR of PCH (B0/D31/f0 offset 0x0AC[20] = 1b) to indicate Host reset
+ /// Make sure CWORWRE (CF9 Without Resume Well Reset Enable) is cleared
+ ///
+ ETR3 = PciRead32 (PCI_LIB_ADDRESS (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_PMIR));
+ ETR3 = ETR3 &~BIT20;
+ ETR3 = ETR3 &~BIT18;
+ PciWrite32 (PCI_LIB_ADDRESS (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_PMIR), ETR3);
+
+ Reset = IoRead8 (R_PCH_RST_CNT);
+ Reset &= 0xF1;
+
+ ///
+ /// If global reset required
+ ///
+ if (ResetType == CBM_DIR_GLOBAL_RESET) {
+ ///
+ /// Get GPIO Base Address
+ ///
+ GpioBase = PciRead32 (PCI_LIB_ADDRESS (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GPIO_BASE)) &~BIT0;
+ }
+
+ switch (ResetType) {
+ case CBM_DIR_NON_PCR:
+ ///
+ /// Case: Non Power Cycle Reset requested
+ ///
+ DEBUG ((EFI_D_ERROR, "ME FW DID ACK has requested a Non Power Cycle Reset.\n"));
+ Reset |= 0x06;
+ break;
+
+ case CBM_DIR_PCR:
+ ///
+ /// Case: Power Cycle Reset requested
+ ///
+ Wdt->ReloadAndStart (2);
+ DEBUG ((EFI_D_INFO, "ME FW DID ACK has requested a Power Cycle Reset.\n"));
+ Reset |= 0x0E;
+ break;
+
+ case CBM_DIR_GLOBAL_RESET:
+ ///
+ /// Case: Global Reset
+ ///
+ DEBUG ((EFI_D_ERROR, "ME FW DID Ack requested a global reset.\n"));
+
+ ///
+ /// Drive GPIO[30] (SPDNA#) low prior to 0xCF9 write
+ ///
+ if (PchSeries == PchH) {
+ /// 1. Set GPIOBASE + offset 00h[30] = 1b (for non-Deep Sx enabled platforms)
+ /// 2. Set GPIOBASE + offset 04h[30] = 0b (for non-Deep Sx enabled platforms)
+ /// 3. Set GPIOBASE + offset 0Ch[30] = 0b (for non-Deep Sx enabled platforms)
+ /// 4. Set GPIOBASE + offset 60h[30] = 1b (for non-Deep Sx enabled platforms)
+ /// NOTE: For Deep Sx enabled platforms steps 1,2 and 3 should be skipped and pin should be left in native mode
+ /// 5. Set CF9GR bit, D31:F0:ACh[20], issue a Global Reset through a 0xCF9 write of either 06h or 0Eh commands.
+ /// Global Reset MEI Message
+ /// 1. BIOS makes sure GPIO30 is left in native mode (default mode) before sending a Global Reset MEI message.
+ ///
+ IoOr32 ((UINTN) (GpioBase + R_PCH_GPIO_USE_SEL), (UINT32) (BIT30));
+ IoAnd32 ((UINTN) (GpioBase + R_PCH_GPIO_IO_SEL), (UINT32) (~BIT30));
+ IoAnd32 ((UINTN) (GpioBase + R_PCH_GPIO_LVL), (UINT32) (~BIT30));
+ }
+
+ if (PchSeries == PchLp) {
+ /// 1. Set GPIOBASE + offset 1F0h[0] = 1b (for non-Deep Sx enabled platforms)
+ /// 2. Set GPIOBASE + offset 1F0h[2] = 0b (for non-Deep Sx enabled platforms)
+ /// 3. Set GPIOBASE + offset 1F0h[31] = 0b (for non-Deep Sx enabled platforms)
+ /// 4. Set GPIOBASE + offset 60h[30] = 1h (for non-Deep Sx enabled platforms)
+ /// NOTE: For Deep Sx enabled platforms steps 1,2 and 3 should be skipped and pin should be left in native mode
+ /// 5. Set CF9GR bit, D31:F0:ACh[20], issue a Global Reset through a 0xCF9 write of either 06h or 0Eh commands.
+ /// Global Reset MEI Message
+ /// 1. BIOS makes sure GPIO30 is left in native mode (default mode) before sending a Global Reset MEI message.
+ ///
+ IoOr32 ((UINTN) (GpioBase + R_PCH_GP_30_CONFIG0), (UINT32) (B_PCH_GPIO_OWN0_GPIO_USE_SEL));
+ IoAnd32 ((UINTN) (GpioBase + R_PCH_GP_30_CONFIG0), (UINT32) (~B_PCH_GPIO_OWN0_GPIO_IO_SEL));
+ IoAnd32 ((UINTN) (GpioBase + R_PCH_GP_30_CONFIG0), (UINT32) (~B_PCH_GPIO_OWN0_GPO_LVL));
+ }
+
+ IoOr32 ((UINTN) (GpioBase + R_PCH_GP_RST_SEL), (UINT32) (BIT30));
+
+ PciOr32 (
+ PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_PMIR),
+ (UINT32) (B_PCH_LPC_PMIR_CF9GR)
+ );
+
+ ///
+ /// Issue global reset CF9 = 0x0E
+ ///
+ DEBUG ((EFI_D_ERROR, "Issuing global reset.\n"));
+ Reset |= 0x0E;
+ break;
+ }
+ ///
+ /// Write PCH RST CNT, Issue Reset
+ ///
+ Wdt->AllowKnownReset ();
+
+ IoWrite8 (R_PCH_RST_CNT, Reset);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will clear the DISB.
+
+ @param[in] None
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS
+**/
+EFI_STATUS
+ClearDisb (
+ VOID
+ )
+{
+ UINT16 Data16;
+
+ Data16 = PciRead16 (PCI_LIB_ADDRESS (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GEN_PMCON_2));
+ Data16 = Data16 &~B_PCH_LPC_GEN_PMCON_DRAM_INIT;
+ PciWrite16 (PCI_LIB_ADDRESS (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GEN_PMCON_2), Data16);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will clear the DISB.
+
+ @param[in] None
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS
+**/
+EFI_STATUS
+SetDISB (
+ VOID
+ )
+{
+ UINT16 Data16;
+
+ Data16 = PciRead16 (PCI_LIB_ADDRESS (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GEN_PMCON_2));
+ Data16 = Data16 & B_PCH_LPC_GEN_PMCON_DRAM_INIT;
+ PciWrite16 (PCI_LIB_ADDRESS (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GEN_PMCON_2), Data16);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the entry point for this PEI.
+
+ @param[in] FfsHeader Pointer to the FFS file header
+ @param[in] PeiServices Pointer to the PEI services table
+
+ @retval Return Status based on errors that occurred while waiting for time to expire.
+**/
+EFI_STATUS
+EFIAPI
+PchMeUmaEntry (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ Status = EFI_SUCCESS;
+ Status = (*PeiServices)->InstallPpi (PeiServices, mPchMeUmaPpiList);
+
+ return Status;
+}