/** @file
  The SC Init After Memory PEI module.

 @copyright
  INTEL CONFIDENTIAL
  Copyright 2013 - 2017 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 "ScInitPei.h"
#include "CpuPowerMgmt.h"
#include <Library/SteppingLib.h>
#include <Library/HeciMsgLib.h>
#include <Private/ScPmcFunctionDisableResetHob.h>
#include <Library/CpuMailboxLib.h>

#include "Include/ConfigBlock/HdAudioConfig.h"


#include <ScRegs/RegsHda.h>
#include <Library/ConfigBlockLib.h>


HDAUDIO_VERB_TABLE*
LocateVerbTable (
  IN      SC_HDAUDIO_CONFIG       *HdaConfig,
  IN      UINT32                  VendorDeviceId,
  IN      UINT8                   RevisionId,
  IN      UINT8                   SdiNo
  );

EFI_STATUS
SendCodecCommand (
  IN      UINT32          HdaBar,
  IN OUT  UINT32          *CodecCommandData,
  IN      BOOLEAN         ReadBack
  );



/**
  Sc End of PEI callback function. This is the last event before entering DXE and OS in S3 resume.

  @param[in]  None

  @retval  None
**/

EFI_STATUS
SendCodecCommand (
  IN      UINT32          HdaBar,
  IN OUT  UINT32          *CodecCommandData,
  IN      BOOLEAN         ReadBack
  );






VOID
ScOnEndOfPei (
  VOID
  )
{
  EFI_STATUS      Status;
  SC_POLICY_PPI   *ScPolicy;
  SI_POLICY_PPI   *SiPolicy;
  UINTN           P2sbBase;
  EFI_BOOT_MODE   BootMode;
  SC_LPSS_CONFIG  *LpssConfig;
  HDAUDIO_VERB_TABLE            *VerbTable;
  UINT32                        CodecCmdData;
  UINT32          Index;
  UINT32	      HdaBar;
  UINT32          RevisionId;


  SC_HDAUDIO_CONFIG *HdaConfig;

  UINTN             HdaPciBase;
  UINT32			VendorDeviceId=0;
  


  PostCode (0xB40);
  DEBUG ((DEBUG_INFO, "ScOnEndOfPei after memory PEI module - Start\n"));
  //
  // Get Policy settings through the SiPolicy PPI
  //
  Status = PeiServicesLocatePpi (
             &gSiPolicyPpiGuid,
             0,
             NULL,
             (VOID **) &SiPolicy
             );
  if (Status != EFI_SUCCESS) {
    //
    // SI_POLICY_PPI must be installed at this point
    //
    ASSERT (FALSE);
    return;
  }

  //
  // Get Policy settings through the ScPolicy PPI
  //
  Status = PeiServicesLocatePpi (
             &gScPolicyPpiGuid,
             0,
             NULL,
             (VOID **) &ScPolicy
             );
  if (Status != EFI_SUCCESS) {
    //
    // SC_POLICY_PPI must be installed at this point
    //
    ASSERT (FALSE);
    return;
  }

  P2sbBase = MmPciBase (
               DEFAULT_PCI_BUS_NUMBER_SC,
               PCI_DEVICE_NUMBER_P2SB,
               PCI_FUNCTION_NUMBER_P2SB
               );

  Status = PeiServicesGetBootMode (&BootMode);
  ASSERT_EFI_ERROR (Status);

  //
  // For S3 path:
  //   Hide P2SB
  //   Hide UART2 if Kernel Debug Enabled
  //
  if (BootMode == BOOT_ON_S3_RESUME) {
#ifndef FSP_FLAG
	  MmioWrite8(P2sbBase + R_SC_P2SB_CFG_P2SBC + 1, BIT0);
#endif
    // Hide the UART2 device to prevent an OS driver from loading against it
    Status = GetConfigBlock ((VOID *) ScPolicy, &gLpssConfigGuid, (VOID *) &LpssConfig);
    ASSERT_EFI_ERROR (Status);
    if (LpssConfig->OsDbgEnable) {
      SideBandAndThenOr32(
        SB_PORTID_PSF3,
		R_SC_PCH_PCR_PSF_3_AGNT_T0_SHDW_CFG_DIS_LPSS_RS0_D24_F2,
        0xFFFFFFFF,
		B_SC_PCH_PCR_PSF_3_AGNT_T0_SHDW_CFG_DIS_LPSS_RS0_D24_F2_CFGDIS
        );
    }
  }

  HdaPciBase = MmPciBase (
				   DEFAULT_PCI_BUS_NUMBER_SC,
				   PCI_DEVICE_NUMBER_HDA,
				   PCI_FUNCTION_NUMBER_HDA
				   );
  

  Status = GetConfigBlock ((VOID *) ScPolicy, &gHdAudioConfigGuid, (VOID *) &HdaConfig);
  ASSERT_EFI_ERROR (Status);

  DEBUG ((DEBUG_ERROR, "HdaConfig Status %X - 1! \n",Status));

  MmPci32Or 	 (0, 0, 0xe, 0, 0x10, SiPolicy->TempMemBaseAddr);

  //MSE Enable for BAR to be valid
  MmPci8Or		 (0, 0, 0xe, 0, 0x4, 0x7);	  
  
  HdaBar=  MmPci32( 0, 0, 0xe, 0x0, 0x10 );

  HdaBar = HdaBar & 0xFFFFFFF0;


  DEBUG ((DEBUG_ERROR, "HdaBar %8X, HdaPciBase  %8X - 1! \n",HdaBar,HdaPciBase));

  //
  // 200F0000, Bit 29 is for  HD Display Audio Verb table
  //
  
  VendorDeviceId = 0x200F0000;
  SendCodecCommand (HdaBar, &VendorDeviceId, TRUE);

  DEBUG ((DEBUG_INFO, "Vendor ID %x \n",VendorDeviceId));

  

  if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "Read the Codec Vendor ID/Device ID fail! \n"));
      goto ExitInitCodec1;
    }
    ///
    /// Read the Revision ID from the attached codec
    ///
  RevisionId  = 0x200F0002; 
  DEBUG ((DEBUG_ERROR, "RevisionId = %x\n", RevisionId));
  Status      = SendCodecCommand (HdaBar, &RevisionId, TRUE);
  if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "Read the Codec Revision ID fail! \n"));
      goto ExitInitCodec1;
  }
  RevisionId = (RevisionId >> 8) & 0xFF;

	// Locate the Display Audio Verb table 

  VerbTable = LocateVerbTable (HdaConfig, VendorDeviceId, (UINT8) RevisionId, 4);
  if (VerbTable == NULL) {
		DEBUG ((DEBUG_ERROR | DEBUG_INFO, "VerbTableData of VendorID:0x%X is null.\n", VendorDeviceId));
		Status = EFI_INVALID_PARAMETER;
		goto ExitInitCodec1;
  }

  DEBUG ((DEBUG_INFO, "VerbTable for Display Audio Found\n"));
  for (Index = 0; Index < VerbTable->VerbTableHeader.DataDwords; Index++) {
      ///
      /// Clear CAd Field
      ///
      CodecCmdData  = VerbTable->VerbTableData[Index] & (UINT32) ~(BIT31 | BIT30 | BIT29 | BIT28);
      ///
      /// Program CAd Field per the SDI number got during codec detection
      ///
      CodecCmdData  |= (UINT32) (2 << 28);
	  
	  
      DEBUG ((DEBUG_INFO, "CodecCmdData VerbTable first DWORD is CodecCmdData %8x set\n",CodecCmdData));
      Status        = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
      if (EFI_ERROR (Status)) {
        ///
        /// Skip the HD-Audio verb table loading when find the verb table content is not
        /// properly matched with the HDA hardware, though IDs match.
        ///
      DEBUG (
          (DEBUG_ERROR | DEBUG_INFO,
          "Detected HD-Audio Codec of VendorID:0x%X, error occurs during loading verb table.\n",
          VendorDeviceId)
          );
        goto ExitInitCodec1;

	  	}
    
  }

  // Clear the BAR
  MmPci32Or 	(0, 0, 0xe, 0, 0x10, 0);

  // Clear the MSE  
  MmPci8Or		(0, 0, 0xe, 0, 0x4, 0);


 ExitInitCodec1:
	 

 DEBUG ((DEBUG_INFO, "ScOnEndOfPei after memory PEI module - End\n"));
  PostCode (0xB4F);
}

/**
  Adjust VNN VR for EMMC
**/
VOID
ConfigureVnn(
 )
{
  EFI_STATUS                  Status;
  UINT32                      MailboxData;
  UINT32                      MailboxCmd;
  UINT32                      MailboxStatus;
  UINT32                      MailboxType;

  DEBUG ((DEBUG_INFO, "Override VNN VR's for emmc\n"));
  MailboxType = MAILBOX_TYPE_PCODE;
  MailboxCmd  = EMMC_VNN_BUMP_CMD;
  MailboxData = 0x0;
  Status = MailboxWrite(MailboxType, MailboxCmd, MailboxData, &MailboxStatus);
  if (EFI_ERROR(Status) || (MailboxStatus != PCODE_MAILBOX_CC_SUCCESS)) {
    DEBUG ((DEBUG_ERROR, "VR: Error writing eMMC VR Adjust CONFIG command. EFI_STATUS = %X, Mailbox Status = %X\n", Status, MailboxStatus));
  }
}

/**
  Perform DCI configuration.

  @param[in] ScPolicy    The SC Policy PPI instance
**/
VOID
DciConfiguration (
  IN  SC_POLICY_PPI  *ScPolicyPpi
  )
{
  EFI_STATUS    Status;
  UINT32        Data32;
  BOOLEAN       DciEnabled;
  BOOLEAN       DciDetected;
  SC_DCI_CONFIG *DciConfig;

  DciEnabled  = FALSE;
  DciDetected = FALSE;

  ///
  /// Set PCR[DCI] + 30h bit[5] to 1, and clear 30h bit[0] = 0
  ///
  SideBandAndThenOr32 (
    PID_DCI,
    R_SC_DCI_PCR_PCE,
    (UINT32)~B_SC_DCI_PCR_PCE_PMCRE,
    B_SC_DCI_PCR_PCE_HAE
    );

  Status = GetConfigBlock ((VOID *) ScPolicyPpi, &gDciConfigGuid, (VOID *) &DciConfig);
  ASSERT_EFI_ERROR (Status);

  DciEnabled = (BOOLEAN)DciConfig->DciEn;
  ///
  /// If DCI is not enabled, and DCI AUTO MODE is enable, then detects DCI connected.
  ///
  if ((DciEnabled == FALSE) && (DciConfig->DciAutoDetect == TRUE)) {
    //
    // Detect DCI being available (PCR[DCI] + 0x4[9] == 1 or PCR[DCI] + 0x4[10] == 1)
    //
    Data32 = SideBandRead32 (PID_DCI, R_SC_DCI_PCR_ECTRL);
    DciDetected = (Data32 & (BIT9 | BIT10)) != 0;
  }
  if (DciEnabled || DciDetected) {
    if (DciEnabled) {
      //
      // Set PCR[DCI] + 4h bit[4] to 1 if DCI is enabled.
      //
      SideBandAndThenOr32 (PID_DCI, R_SC_DCI_PCR_ECTRL, ~0u, B_SC_DCI_PCR_ECTRL_HDCIEN);
    }
  } else {
    //
    // Set PCR[DCI] + 4h bit[4] to 0
    //
    SideBandAndThenOr32 (PID_DCI, R_SC_DCI_PCR_ECTRL, (UINT32) ~(B_SC_DCI_PCR_ECTRL_HDCIEN), 0);
  }
}

/**
  Sc init after memory PEI module

  @param[in] SiPolicy    The Silicon Policy PPI instance
  @param[in] ScPolicy    The SC Policy PPI instance

  @retval None
**/
VOID
EFIAPI
ScInit (
  IN  SI_POLICY_PPI  *SiPolicy,
  IN  SC_POLICY_PPI  *ScPolicyPpi
  )
{
  EFI_STATUS                        Status;
  SC_PCIE_DEVICE_OVERRIDE           *PcieDeviceTable;
  VOID                              *HobPtr;
  UINTN                             Count;
  UINT32                            PmcBase;
  UINT32                            FuncDisableReg;
  UINT32                            FuncDisable1Reg;
  UINT32                            OriginalFuncDisableReg;
  UINT32                            OriginalFuncDisable1Reg;
  UINT32                            NewFuncDisableReg;
  UINT32                            NewFuncDisable1Reg;
  UINT32                            FuncDisableChangeStatus;
  UINT32                            FuncDisable1ChangeStatus;
  BXT_STEPPING                      Stepping;
  SC_LOCK_DOWN_CONFIG               *LockDownConfig;
  SC_GENERAL_CONFIG                 *GeneralConfig;
  UINT8                             IpcWbuffer[4] = {0, 0, 0, 0};
  UINT32                            Data32And;
  SC_PMC_FUNCTION_DISABLE_RESET_HOB FuncDisHob;

  PostCode (0xB00); // SC PostMem Entry
  DEBUG ((DEBUG_INFO, "ScInit - Start\n"));

  //
  // Locate and PCIe device override table and add to HOB area.
  //
  Status = PeiServicesLocatePpi (
             &gScPcieDeviceTablePpiGuid,
             0,
             NULL,
             (VOID **)&PcieDeviceTable
             );

  if (Status == EFI_SUCCESS) {
    for (Count = 0; PcieDeviceTable[Count].DeviceId != 0; Count++) {
    }
    DEBUG ((DEBUG_INFO, "SC Installing PcieDeviceTable HOB (%d entries)\n", Count));
    HobPtr = BuildGuidDataHob (
               &gScDeviceTableHobGuid,
               PcieDeviceTable,
               Count * sizeof (SC_PCIE_DEVICE_OVERRIDE)
               );
    ASSERT (HobPtr != 0);
  }

  Status = GetConfigBlock ((VOID *) ScPolicyPpi, &gScGeneralConfigGuid, (VOID *) &GeneralConfig);
  ASSERT_EFI_ERROR (Status);
  Status = GetConfigBlock ((VOID *) ScPolicyPpi, &gLockDownConfigGuid, (VOID *) &LockDownConfig);
  ASSERT_EFI_ERROR (Status);

  PmcBase = GeneralConfig->PmcBase;
  OriginalFuncDisableReg = MmioRead32(PmcBase + R_SC_PMC_MEM_FUNC_DIS);
  OriginalFuncDisable1Reg = MmioRead32(PmcBase + R_SC_PMC_MEM_FUNC_DIS_1);

  FuncDisableReg  = 0;
  FuncDisable1Reg = 0;
  DEBUG ((DEBUG_INFO, "FuncDisableReg: 0x%08X\n", OriginalFuncDisableReg));
  DEBUG ((DEBUG_INFO, "FuncDisable1Reg: 0x%08X\n", OriginalFuncDisable1Reg));

  //
  // Set and enable P2SB base
  //
  ScP2sbInit(GeneralConfig->P2sbBase);
  //
  // Program HSIO
  //
  PostCode (0xB01);
  ScHsioBiosProg (SiPolicy, ScPolicyPpi);

  //
  // Init RTC
  //
  ConfigureRtc ();

  //
  // Misc SC config init
  //
  ScMiscInit (ScPolicyPpi);

  //
  // Init IoApic
  //
  ScIoApicInit (ScPolicyPpi);

  //
  // Init BXTP & Glk specific IPs
  //
  if ((GetBxtSeries() == BxtP) || (GetBxtSeries() == Glk)) {
    //
    // Init Smbus
    //
    PostCode (0xB02);
    ScSmbusConfigure(ScPolicyPpi);
    //
    // Init LPC
    //
    PostCode (0xB03);
    ScLpcInit ();
    //
    // Init Sata
    //
    PostCode (0xB04);
    ScSataInit (ScPolicyPpi, SiPolicy->TempMemBaseAddr, &FuncDisable1Reg);
  }

  //
  // Init PciExpress
  //
  Stepping = BxtStepping ();
  if ((Stepping >= BxtB0)) {
    PostCode (0xB05);
    ScInitRootPorts (ScPolicyPpi, SiPolicy->TempPciBusMin, SiPolicy->TempPciBusMax, &OriginalFuncDisableReg, &OriginalFuncDisable1Reg, &FuncDisableReg, &FuncDisable1Reg);
  }

  //
  // Program SVID and SID of SC devices.
  // Program SVID and SID before most SC device init since some device might be locked after init.
  //
  Status = ProgramSvidSid (ScPolicyPpi);
  ASSERT_EFI_ERROR (Status);

  if ((GetBxtSeries() == BxtP) || (GetBxtSeries() == Glk)) {
    //
    // Configure Serial IRQ
    //
    ScConfigureSerialIrq (ScPolicyPpi);
  }

  //
  // Configure PM settings
  //
  Status = ScPmInit (ScPolicyPpi);

  ///
  ///
  /// Miscellaneous power management handling
  ///
  Status = ConfigureMiscPm (ScPolicyPpi, PmcBase);

  ///
  /// S0ix Enabling
  ///
  if (GeneralConfig->S0ixSupport == TRUE) {
    Status = ConfigureS0ix (PmcBase);
  }
  ///
  /// Perform SC initialization sequence
  ///
  Status = ConfigureMiscItems (PmcBase);

  ///
  /// Configure USB
  ///
  PostCode (0xB06);
  ScUsbInit (SiPolicy, ScPolicyPpi, &FuncDisableReg);
  //
  // Configure DCI
  //
  DciConfiguration (ScPolicyPpi);
  //
  // Enable ModPHY power gating
  //
  IpcWbuffer[0] |= BIT4;
  IpcSendCommandEx (IPC_CMD_ID_PHY_CFG,IPC_SUBCMD_ID_PHY_CFG_COMPLETE, &IpcWbuffer, 2);

  ////
  ///  Configure OTG Device
  ///
  PostCode (0xB07);
  Status = ConfigureXdci (SiPolicy, ScPolicyPpi, &FuncDisableReg);
  ///
  /// Detect and initialize the type of codec present in the system
  ///
  PostCode (0xB08);
  Status = ConfigureHda (SiPolicy, ScPolicyPpi, &FuncDisableReg);

  ///
  /// Configure GMM
  ///
  PostCode (0xB09);
  Status = ConfigureGmm (SiPolicy, ScPolicyPpi, &FuncDisableReg);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Configure LPSS Devices
  ///
  PostCode (0xB0A);
  Status = ConfigureLpss (SiPolicy, ScPolicyPpi, &FuncDisableReg);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Configure SCS Devices
  ///
  PostCode (0xB0B);
  Status = ConfigureScs (SiPolicy, ScPolicyPpi, &FuncDisableReg, &FuncDisable1Reg);
  ASSERT_EFI_ERROR (Status);

  if (GetBxtSeries() == Glk && BxtStepping() == GlkA1) {
    ConfigureVnn();
  }

  ///
  /// Configure ISH Devices
  ///
  PostCode (0xB0C);
  Status = ConfigureIsh (ScPolicyPpi, &FuncDisableReg);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Configure IOSF Devices
  ///
  Status = ConfigureIosf ();
  ASSERT_EFI_ERROR (Status);

  ///
  /// Configure ITSS Devices
  ///
  PostCode (0xB0D);
  Status = ConfigureItss (ScPolicyPpi);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Configure PMC Devices
  ///
  Status = ConfigurePmc (SiPolicy);
  ASSERT_EFI_ERROR (Status);

  VtdInit(ScPolicyPpi);

  //
  // Configure interrupts.
  //
  PostCode (0xB0E);
  Status = ScConfigureInterrupts (ScPolicyPpi);
  ASSERT_EFI_ERROR (Status);

#if (CNVI_ENABLE == 1)
  if (GetBxtSeries () == Glk) {
      ///
      /// Configure CNVi
      ///
      Status = ScCnviInit (ScPolicyPpi, OriginalFuncDisable1Reg ,&FuncDisable1Reg);
      ASSERT_EFI_ERROR (Status);
  }
#endif

  ///
  ///
  /// Perform clock gating register settings
  /// No clock gating configuration is required for now until there is fix needed by BIOS.
  ///
  Status = ConfigureClockGating (ScPolicyPpi);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Perform power gating register settings
  ///
  Status = ConfigurePowerGating (ScPolicyPpi);
  ASSERT_EFI_ERROR (Status);

  HobPtr = NULL;
  HobPtr = BuildGuidDataHob (&gScPolicyHobGuid, ScPolicyPpi, ScGetConfigBlockTotalSize ());
  ASSERT (HobPtr != 0);

  ///
  /// Set the PMC Function Disable Registers
  ///
  NewFuncDisableReg  = OriginalFuncDisableReg | FuncDisableReg;     // Updating originalfunc disable values with new bits sets in funcdisable
  NewFuncDisable1Reg = OriginalFuncDisable1Reg | FuncDisable1Reg;   // Updating originalfunc1 disable values with new bits sets in funcdisable1
  MmioAndThenOr32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS), ~0u, NewFuncDisableReg);
  MmioAndThenOr32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS_1), ~0u, NewFuncDisable1Reg);

  ///
  /// Reads back for posted write to take effect
  ///
  DEBUG((DEBUG_INFO, "FuncDisableReg: 0x%08X\n", MmioRead32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS))));
  DEBUG((DEBUG_INFO, "FuncDisable1Reg: 0x%08X\n", MmioRead32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS_1))));

  FuncDisableChangeStatus  = FuncDisableReg ^ OriginalFuncDisableReg;
  FuncDisable1ChangeStatus = FuncDisable1Reg ^ OriginalFuncDisable1Reg;
  FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_NO_RESET;
  if (FuncDisableChangeStatus & B_SC_PMC_MEM_FUNC_DIS_AVS) {
	  if (FuncDisableReg & B_SC_PMC_MEM_FUNC_DIS_AVS) {
      FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_COLD_RESET;   // Changing from Enabled to Disabled
    } else {
		  MmioAnd32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS), (UINT32)~B_SC_PMC_MEM_FUNC_DIS_AVS);
      FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_GLOBAL_RESET; // Changing from Disabled to Enabled
    }
  }
  if (FuncDisableChangeStatus & B_SC_PMC_MEM_FUNC_DIS_ISH) {
	  if (FuncDisableReg & B_SC_PMC_MEM_FUNC_DIS_ISH) {
      FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_COLD_RESET;   // Changing from Enabled to Disabled
    } else {
		  MmioAnd32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS), (UINT32)~B_SC_PMC_MEM_FUNC_DIS_ISH);
      FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_GLOBAL_RESET; // Changing from Disabled to Enabled
    }
  }

  if (FuncDisable1ChangeStatus & B_SC_PMC_MEM_FUNC_DIS_1_SATA) {
	  if ((FuncDisable1Reg & B_SC_PMC_MEM_FUNC_DIS_1_SATA) != B_SC_PMC_MEM_FUNC_DIS_1_SATA) {
		  MmioAnd32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS_1), (UINT32)~B_SC_PMC_MEM_FUNC_DIS_1_SATA);
      FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_GLOBAL_RESET; // Changing from Disabled to Enabled
    } else {
      FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_COLD_RESET; // Changing from Enabled to Disabled
    }
  }

  #if (CNVI_ENABLE == 1)
	if (GetBxtSeries() == Glk) {
		if (FuncDisable1ChangeStatus & B_SC_PMC_MEM_FUNC_DIS_CNVI) {
			if (FuncDisable1Reg & B_SC_PMC_MEM_FUNC_DIS_CNVI) {
				FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_COLD_RESET;   // Changing from Enabled to Disabled
			} else {
				MmioAnd32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS_1), (UINT32)~B_SC_PMC_MEM_FUNC_DIS_CNVI);
				FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_GLOBAL_RESET; // Changing from Disabled to Enabled
			}
		}
	}
 #endif
  if (BxtStepping() >= BxtB0) {
	  if (FuncDisableChangeStatus & (B_SC_PMC_MEM_FUNC_DIS_PCIE0_P0 | B_SC_PMC_MEM_FUNC_DIS_PCIE0_P1)) {
		  if ((B_SC_PMC_MEM_FUNC_DIS_PCIE0_P0 & OriginalFuncDisableReg) &&
			  (B_SC_PMC_MEM_FUNC_DIS_PCIE0_P1 & OriginalFuncDisableReg)) {
			  Data32And = ~(~FuncDisableReg & (B_SC_PMC_MEM_FUNC_DIS_PCIE0_P0 | B_SC_PMC_MEM_FUNC_DIS_PCIE0_P1));
			  MmioAnd32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS), Data32And);
        FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_GLOBAL_RESET; // Changing from Disabled to Enabled
      }
		  if ((FuncDisableReg & B_SC_PMC_MEM_FUNC_DIS_PCIE0_P0) &&
			  (FuncDisableReg & B_SC_PMC_MEM_FUNC_DIS_PCIE0_P1)) {
        FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_COLD_RESET;   // Changing from Enabled to Disabled
      }
    }
  }
  if ((GetBxtSeries() == BxtP) || (GetBxtSeries() == Glk)) {
	  if (FuncDisable1ChangeStatus & (B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P0 |
		  B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P1 |
		  B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P2 |
		  B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P3)) {
		  if ((B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P0 & OriginalFuncDisable1Reg) &&
			  (B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P1 & OriginalFuncDisable1Reg) &&
			  (B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P2 & OriginalFuncDisable1Reg) &&
			  (B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P3 & OriginalFuncDisable1Reg)) {
			  Data32And = ~(~FuncDisable1Reg & (B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P0 | B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P1 | B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P2 | B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P3));
			  MmioAnd32((UINTN)(PmcBase + R_SC_PMC_MEM_FUNC_DIS_1), Data32And);
        FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_GLOBAL_RESET; // Changing from Disabled to Enabled
      }
		  if ((FuncDisable1Reg & B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P0) &&
			  (FuncDisable1Reg & B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P1) &&
			  (FuncDisable1Reg & B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P2) &&
			  (FuncDisable1Reg & B_SC_PMC_MEM_FUNC_DIS_1_PCIE1_P3)) {
        FuncDisHob.ResetType = SC_PMC_FUNCTION_DISABLE_COLD_RESET;   // Changing from Enabled to Disabled
      }
    }
  }
  HobPtr = NULL;
  HobPtr = BuildGuidDataHob (&gScPmcFunctionDisableResetHobGuid, (VOID *) &FuncDisHob, sizeof (SC_PMC_FUNCTION_DISABLE_RESET_HOB));
  ASSERT (HobPtr != 0);

  ///
  /// Ensure PME_EN Bits are Cleared to Prevent SMI Interrupt Storm
  ///
  ///  Will be set by the OS driver during OSPM (D3 flow)
  ///  Enables setting of the *_PME_STS bit to generate a wake event and/or an SCI or SMI#
  ///
  {
	UINT32	PmeEn = (UINT32)(
		~(B_SC_ACPI_IO_GPE0a_EN_XHCI_PME_EN |
		B_SC_ACPI_IO_GPE0a_EN_PCIE_GPE_EN |
		B_SC_ACPI_IO_GPE0a_EN_AVS_PME_EN |
		B_SC_ACPI_IO_GPE0a_EN_XDCI_PME_EN |
		B_SC_ACPI_IO_GPE0a_EN_CSE_PME_EN)
					   );

	if (GetBxtSeries() == Glk) {
		PmeEn &= (UINT32)(~(B_SC_ACPI_IO_GPE0a_EN_CNV_PME_EN |
			B_SC_ACPI_IO_GPE0a_EN_SPI_PME_EN));
	}
	IoAnd32(GeneralConfig->AcpiBase + R_SC_ACPI_IO_GPE0a_EN,
			  PmeEn);
  }

  PostCode (0xB7F);  // SC PostMem Exit
  DEBUG ((DEBUG_INFO, "ScInit - End\n"));
}
