/** @file
  This file provides services for PEI policy default initialization

Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/
#include "PeiSaPolicyLibrary.h"
#include <Library/GpioLib.h>
#include <GpioPinsSklH.h>
#include <Library/CpuPlatformLib.h>
#include <MrcTypes.h>
#include "MrcInterface.h"


extern EFI_GUID gSaMiscPeiPreMemConfigGuid;
extern EFI_GUID gMemoryConfigGuid;
extern EFI_GUID gMemoryConfigNoCrcGuid;
extern EFI_GUID gGraphicsPeiConfigGuid;
extern EFI_GUID gVtdConfigGuid;

#define DEFAULT_OPTION_ROM_TEMP_BAR            0x80000000
#define DEFAULT_OPTION_ROM_TEMP_MEM_LIMIT      0xC0000000

//
// Function call to Load defaults for Individial IP Blocks
//
VOID
LoadSaMiscPeiPreMemDefault (
  IN   VOID          *ConfigBlockPointer
  )
{
  SA_MISC_PEI_PREMEM_CONFIG            *MiscPeiPreMemConfig;

  MiscPeiPreMemConfig = ConfigBlockPointer;

  DEBUG ((DEBUG_INFO, "MiscPeiPreMemConfig->Header.GuidHob.Name = %g\n", &MiscPeiPreMemConfig->Header.GuidHob.Name));
  DEBUG ((DEBUG_INFO, "MiscPeiPreMemConfig->Header.GuidHob.Header.HobLength = 0x%x\n", MiscPeiPreMemConfig->Header.GuidHob.Header.HobLength));

  //
  // Policy initialization commented out here is because it's the same with default 0 and no need to re-do again.
  //
  MiscPeiPreMemConfig->LockPTMregs                      = 1;

  //
  // Initialize the Platform Configuration
  //
  MiscPeiPreMemConfig->MchBar              = (UINT32) PcdGet64 (PcdMchBaseAddress);
  MiscPeiPreMemConfig->DmiBar              = 0xFED18000;
  MiscPeiPreMemConfig->EpBar               = 0xFED19000;
  MiscPeiPreMemConfig->EdramBar            = 0xFED80000;
  MiscPeiPreMemConfig->SmbusBar            = PcdGet16 (PcdSmbusBaseAddress);
  MiscPeiPreMemConfig->TsegSize            = PcdGet32 (PcdTsegSize);
  MiscPeiPreMemConfig->GdxcBar             = 0xFED84000;

  //
  // Initialize the Switchable Graphics Default Configuration
  //
  MiscPeiPreMemConfig->SgDelayAfterHoldReset  = 100; //100ms
  MiscPeiPreMemConfig->SgDelayAfterPwrEn      = 300; //300ms
  MiscPeiPreMemConfig->SgDelayAfterOffMethod  = 0;
  MiscPeiPreMemConfig->SgDelayAfterLinkEnable = 0;
  MiscPeiPreMemConfig->SgGenSpeedChangeEnable = 0;

  ///
  /// Initialize the DataPtr for S3 resume
  ///
  MiscPeiPreMemConfig->S3DataPtr = NULL;
  MiscPeiPreMemConfig->OpRomScanTempMmioBar      = DEFAULT_OPTION_ROM_TEMP_BAR;
  MiscPeiPreMemConfig->OpRomScanTempMmioLimit    = DEFAULT_OPTION_ROM_TEMP_MEM_LIMIT;
}

VOID
LoadVtdDefault (
  IN VOID   *ConfigBlockPointer
  )
{
  VTD_CONFIG   *Vtd;

  Vtd = ConfigBlockPointer;
  DEBUG ((DEBUG_INFO, "Vtd->Header.GuidHob.Name = %g\n", &Vtd->Header.GuidHob.Name));
  DEBUG ((DEBUG_INFO, "Vtd->Header.GuidHob.Header.HobLength = 0x%x\n", Vtd->Header.GuidHob.Header.HobLength));

  //
  // Initialize the Vtd Configuration
  //
  Vtd->BaseAddress[0]  = 0xFED90000;
  Vtd->BaseAddress[1]  = 0xFED91000;
}

VOID
LoadGraphichsPeiDefault (
  IN VOID    *ConfigBlockPointer
  )
{
  GRAPHICS_PEI_CONFIG                         *GtConfig;

  GtConfig = ConfigBlockPointer;
  DEBUG ((DEBUG_INFO, "GtConfig->Header.GuidHob.Name = %g\n", &GtConfig->Header.GuidHob.Name));
  DEBUG ((DEBUG_INFO, "GtConfig->Header.GuidHob.Header.HobLength = 0x%x\n", GtConfig->Header.GuidHob.Header.HobLength));
}

VOID
LoadMemConfigNoCrcDefault (
  IN VOID    *ConfigBlockPointer
  )
{

  MEMORY_CONFIG_NO_CRC                    *MemConfigNoCrc;

  MemConfigNoCrc = ConfigBlockPointer;
  DEBUG ((DEBUG_INFO, "MemConfigNoCrc->Header.GuidHob.Name = %g\n", &MemConfigNoCrc->Header.GuidHob.Name));
  DEBUG ((DEBUG_INFO, "MemConfigNoCrc->Header.GuidHob.Header.HobLength = 0x%x\n", MemConfigNoCrc->Header.GuidHob.Header.HobLength));
  //
  // Allocating memory space for pointer structures inside MemConfigNoCrc
  //
  MemConfigNoCrc->SpdData = (SPD_DATA_BUFFER *) AllocateZeroPool (sizeof (SPD_DATA_BUFFER));
  ASSERT (MemConfigNoCrc->SpdData != NULL);
  if (MemConfigNoCrc->SpdData == NULL) {
    return;
  }

  MemConfigNoCrc->DqByteMap = (SA_MEMORY_DQ_MAPPING *) AllocateZeroPool (sizeof (SA_MEMORY_DQ_MAPPING));
  ASSERT (MemConfigNoCrc->DqByteMap != NULL);
  if (MemConfigNoCrc->DqByteMap == NULL) {
    return;
  }

  MemConfigNoCrc->DqsMap = (SA_MEMORY_DQS_MAPPING *) AllocateZeroPool (sizeof (SA_MEMORY_DQS_MAPPING));
  ASSERT (MemConfigNoCrc->DqsMap != NULL);
  if (MemConfigNoCrc->DqsMap == NULL) {
    return;
  }

  MemConfigNoCrc->RcompData = (SA_MEMORY_RCOMP *) AllocateZeroPool (sizeof (SA_MEMORY_RCOMP));
  ASSERT (MemConfigNoCrc->RcompData != NULL);
  if (MemConfigNoCrc->RcompData == NULL) {
    return;
  }

  //
  // Set PlatformMemory Size
  //
  MemConfigNoCrc->PlatformMemorySize = PcdGet32 (PcdPeiMinMemorySize);

  MemConfigNoCrc->SerialDebugLevel  = 3;  //< Enable MRC debug message

}


VOID
LoadMemConfigDefault (
  IN VOID *ConfigBlockPointer
  )
{
  MEMORY_CONFIGURATION                    *MemConfig;
  CPU_SKU                                 CpuSku;
  UINT16                                  DeviceId;
  BOOLEAN                                 HasEdram;

  CpuSku = GetCpuSku ();
  DeviceId    = MmioRead16 (MmPciBase (SA_MC_BUS, 0, 0) + R_SA_MC_DEVICE_ID);
  HasEdram    = ((AsmReadMsr64 (MSR_PLATFORM_INFO) & B_PLATFORM_INFO_EDRAM_EN) != 0);


  MemConfig = ConfigBlockPointer;
  DEBUG ((DEBUG_INFO, "MemConfig->Header.GuidHob.Name = %g\n", &MemConfig->Header.GuidHob.Name));
  DEBUG ((DEBUG_INFO, "MemConfig->Header.GuidHob.Header.HobLength = 0x%x\n", MemConfig->Header.GuidHob.Header.HobLength));
  //
  // Initialize the Memory Configuration
  //
  MemConfig->EccSupport         = 1;
  MemConfig->ScramblerSupport   = 1;
  MemConfig->PowerDownMode      = 0xFF;
  MemConfig->RankInterleave     = TRUE;
  MemConfig->EnhancedInterleave = TRUE;
  MemConfig->CmdTriStateDis     = 0;
  MemConfig->EnCmdRate          = 3;
  MemConfig->AutoSelfRefreshSupport = TRUE;
  MemConfig->ExtTemperatureSupport  = TRUE;

  //
  // Thermal Management Configuration
  //
  MemConfig->ThermalManagement  = 1;
  //
  // Channel Hash Configuration
  //
  MemConfig->ChHashEnable         = TRUE;
  MemConfig->ChHashMask           = ((CpuSku == EnumCpuUlt) && (HasEdram)) ? 0x30D0 : 0x30C8;
  MemConfig->ChHashInterleaveBit  = 2;
  //
  // Options for Thermal settings
  //
  MemConfig->EnablePwrDn            = 1;
  MemConfig->EnablePwrDnLpddr       = 1;
  MemConfig->DdrThermalSensor     = 1;

  MemConfig->EnergyScaleFact        = 3;
  MemConfig->WarmThresholdCh0Dimm0  = 0xFF;
  MemConfig->WarmThresholdCh0Dimm1  = 0xFF;
  MemConfig->WarmThresholdCh1Dimm0  = 0xFF;
  MemConfig->WarmThresholdCh1Dimm1  = 0xFF;
  MemConfig->HotThresholdCh0Dimm0   = 0xFF;
  MemConfig->HotThresholdCh0Dimm1   = 0xFF;
  MemConfig->HotThresholdCh1Dimm0   = 0xFF;
  MemConfig->HotThresholdCh1Dimm1   = 0xFF;
  MemConfig->WarmBudgetCh0Dimm0     = 0xFF;
  MemConfig->WarmBudgetCh0Dimm1     = 0xFF;
  MemConfig->WarmBudgetCh1Dimm0     = 0xFF;
  MemConfig->WarmBudgetCh1Dimm1     = 0xFF;
  MemConfig->HotBudgetCh0Dimm0      = 0xFF;
  MemConfig->HotBudgetCh0Dimm1      = 0xFF;
  MemConfig->HotBudgetCh1Dimm0      = 0xFF;
  MemConfig->HotBudgetCh1Dimm1      = 0xFF;

  MemConfig->SrefCfgEna             = 1;
  MemConfig->SrefCfgIdleTmr         = 0x200;
  MemConfig->ThrtCkeMinTmr          = 0x30;
  MemConfig->ThrtCkeMinDefeatLpddr = 1;
  MemConfig->ThrtCkeMinTmrLpddr    = 0x40;

  //
  // CA Vref routing: board-dependent
  // 0 - VREF_CA goes to both CH_A and CH_B (LPDDR3/DDR3L)
  // 1 - VREF_CA to CH_A, VREF_DQ_A to CH_B (should not be used)
  // 2 - VREF_CA to CH_A, VREF_DQ_B to CH_B (DDR4)
  //
  //MemConfig->CaVrefConfig = 0;

  MemConfig->VttTermination     = ((CpuSku == EnumCpuUlx) || (CpuSku == EnumCpuUlt));
  MemConfig->VttCompForVsshi    = 1;

  MemConfig->McLock               = TRUE;

  MemConfig->GdxcIotSize          = 4;
  MemConfig->GdxcMotSize          = 12;

  //
  // MRC training steps
  //
  MemConfig->ERDMPRTC2D           = 1;
  MemConfig->SOT                  = 1;
  MemConfig->RDMPRT               = 1;
  MemConfig->RCVET                = 1;
  MemConfig->JWRL                 = 1;
  MemConfig->EWRTC2D              = 1;
  MemConfig->ERDTC2D              = 1;
  MemConfig->WRTC1D               = 1;
  MemConfig->WRVC1D               = 1;
  MemConfig->RDTC1D               = 1;
  MemConfig->DIMMODTT             = 1;
  MemConfig->DIMMRONT             = 1;
  MemConfig->WRSRT                = 1;
  MemConfig->RDODTT               = 1;
  MemConfig->RDEQT                = 1;
  MemConfig->RDAPT                = 1;
  MemConfig->WRTC2D               = 1;
  MemConfig->RDTC2D               = 1;
  MemConfig->CMDVC                = 1;
  MemConfig->WRVC2D               = 1;
  MemConfig->RDVC2D               = 1;
  MemConfig->LCT                  = 1;
  MemConfig->RTL                  = 1;
  MemConfig->TAT                  = 1;
  MemConfig->ALIASCHK             = 1;
  MemConfig->RCVENC1D             = 1;
  MemConfig->RMC                  = 1;
  MemConfig->CMDSR                = 1;
  MemConfig->CMDDSEQ              = 1;
  MemConfig->CMDNORM              = 1;
  MemConfig->EWRDSEQ              = 1;

  // MrcFastBoot enabled by default
  MemConfig->MrcFastBoot          = TRUE;
  MemConfig->RemapEnable          = TRUE;
  MemConfig->BClkFrequency        = 100 * 1000 * 1000;

  MemConfig->Vc1ReadMeter           = TRUE;
  MemConfig->Vc1ReadMeterTimeWindow = 0x320;
  MemConfig->Vc1ReadMeterThreshold  = 0x118;
  MemConfig->StrongWkLeaker         = 7;

  MemConfig->MobilePlatform     = (IS_SA_DEVICE_ID_MOBILE (DeviceId)) ? TRUE : FALSE;
  MemConfig->PciIndex           = 0xCF8;
  MemConfig->PciData            = 0xCFC;
  MemConfig->CkeRankMapping     = 0xAA;
  //
  // SA GV: 0 - Disabled, 1 - FixedLow, 2 - FixedHigh, 3 - Enabled
  //
  //
  // Current Simics will fail in MRC training when SAGV enabled so need to by default disable SAGV.
  //
  MemConfig->SaGv               = 3;  // This only affects ULX/ULT and CPU steppings C0/J0 and above; otherwise SA GV is disabled.

  MemConfig->Idd3n              = 26;
  MemConfig->Idd3p              = 11;

  MemConfig->RhPrevention       = TRUE;         // Row Hammer prevention.
  MemConfig->RhSolution         = HardwareRhp;  // Type of solution to be used for RHP - 0/1 = HardwareRhp/Refresh2x
  MemConfig->RhActProbability   = OneIn2To11;    // Activation probability for Hardware RHP

  MemConfig->LpddrMemWriteLatencySet = 1;  // Enable LPDDR3 WL Set B if supported by DRAM
  MemConfig->EvLoaderDelay           = 1;

  MemConfig->DllBwEn1 = 1;
  MemConfig->DllBwEn2 = 2;
  MemConfig->DllBwEn3 = 2;

  MemConfig->RetrainOnFastFail = 1; //  Restart MRC in Cold mode if SW MemTest fails during Fast flow. 0 = Disabled, 1 = Enabled
}


static COMPONENT_BLOCK_ENTRY  mSaIpBlocksPreMem[] = {
  { &gSaMiscPeiPreMemConfigGuid, sizeof(SA_MISC_PEI_PREMEM_CONFIG), SA_MISC_PEI_PREMEM_CONFIG_REVISION, LoadSaMiscPeiPreMemDefault },
  { &gMemoryConfigGuid, sizeof(MEMORY_CONFIGURATION), MEMORY_CONFIG_REVISION, LoadMemConfigDefault },
  { &gMemoryConfigNoCrcGuid, sizeof(MEMORY_CONFIG_NO_CRC), MEMORY_CONFIG_REVISION, LoadMemConfigNoCrcDefault }
};

static COMPONENT_BLOCK_ENTRY  mSaIpBlocks [] = {
  {&gGraphicsPeiConfigGuid,     sizeof (GRAPHICS_PEI_CONFIG),  GRAPHICS_PEI_CONFIG_REVISION,     LoadGraphichsPeiDefault},
  {&gVtdConfigGuid,             sizeof (VTD_CONFIG),           VTD_CONFIG_REVISION,              LoadVtdDefault}
};

/**
  Get SA config block table total size.

  @retval     Size of SA config block table
**/
UINT16
EFIAPI
SaGetConfigBlockTotalSize (
  VOID
  )
{
  return GetComponentConfigBlockTotalSize (&mSaIpBlocks[0], sizeof (mSaIpBlocks) / sizeof (COMPONENT_BLOCK_ENTRY));
}

/**
  Get SA config block table total size.

  @retval      Size of SA config block table
**/
UINT16
EFIAPI
SaGetConfigBlockTotalSizePreMem (
  VOID
  )
{
  return GetComponentConfigBlockTotalSize (&mSaIpBlocksPreMem[0], sizeof (mSaIpBlocksPreMem) / sizeof (COMPONENT_BLOCK_ENTRY));
}

/**
  SaAddConfigBlocksPreMem add all SA config blocks.

  @param[in] ConfigBlockTableAddress    The pointer to add SA config blocks

  @retval EFI_SUCCESS                   The policy default is initialized.
  @retval EFI_OUT_OF_RESOURCES          Insufficient resources to create buffer
**/
EFI_STATUS
EFIAPI
SaAddConfigBlocksPreMem (
  IN VOID           *ConfigBlockTableAddress
  )
{
  EFI_STATUS  Status;

  DEBUG ((DEBUG_INFO, "SA AddConfigBlocks. TotalBlockCount = 0x%x\n",  sizeof (mSaIpBlocksPreMem) / sizeof (COMPONENT_BLOCK_ENTRY)));
  Status = AddComponentConfigBlocks (ConfigBlockTableAddress, &mSaIpBlocksPreMem[0], sizeof (mSaIpBlocksPreMem) / sizeof (COMPONENT_BLOCK_ENTRY));
  if (Status == EFI_SUCCESS) {
    SaLoadSamplePolicyPreMem (ConfigBlockTableAddress);
  }
  return Status;
}

/**
  SaAddConfigBlocks add all SA config blocks.

  @param[in] ConfigBlockTableAddress    The pointer to add SA config blocks

  @retval EFI_SUCCESS                   The policy default is initialized.
  @retval EFI_OUT_OF_RESOURCES          Insufficient resources to create buffer
**/
EFI_STATUS
EFIAPI
SaAddConfigBlocks (
  IN VOID           *ConfigBlockTableAddress
  )
{
  DEBUG ((DEBUG_INFO, "SA AddConfigBlocks. TotalBlockCount = 0x%x\n",  sizeof (mSaIpBlocks) / sizeof (COMPONENT_BLOCK_ENTRY)));

  return AddComponentConfigBlocks (ConfigBlockTableAddress, &mSaIpBlocks[0], sizeof (mSaIpBlocks) / sizeof (COMPONENT_BLOCK_ENTRY));
}
