/**
 * @file
 *
 * AMD Family_10 specific utility functions.
 *
 * Provides numerous utility functions specific to family 10h.
 *
 * @xrefitem bom "File Content Label" "Release Content"
 * @e project:      AGESA
 * @e sub-project:  CPU/F10
 * @e \$Revision: 44323 $   @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
 *
 */
/*
 ******************************************************************************
 *
 * Copyright (c) 2011, Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */

/*----------------------------------------------------------------------------------------
 *                             M O D U L E S    U S E D
 *----------------------------------------------------------------------------------------
 */
#include "AGESA.h"
#include "amdlib.h"
#include "Ids.h"
#include "cpuRegisters.h"
#include "cpuFamilyTranslation.h"
#include "cpuF10PowerMgmt.h"
#include "cpuApicUtilities.h"
#include "cpuServices.h"
#include "GeneralServices.h"
#include "cpuF10Utilities.h"
#include "cpuPostInit.h"
#include "Filecode.h"
#define FILECODE PROC_CPU_FAMILY_0X10_CPUF10UTILITIES_FILECODE

/*----------------------------------------------------------------------------------------
 *                   D E F I N I T I O N S    A N D    M A C R O S
 *----------------------------------------------------------------------------------------
 */
// Register encodings for F3xD8[VSRampTime/VSSlamTime]
CONST UINT32 ROMDATA VSSlamTime[8] =
{
  10,   // 000b: 10us
  20,   // 001b: 20us
  30,   // 010b: 30us
  40,   // 011b: 40us
  60,   // 100b: 60us
  100,  // 101b: 100us
  200,  // 110b: 200us
  500   // 111b: 500us
};

/*----------------------------------------------------------------------------------------
 *                  T Y P E D E F S     A N D     S T R U C T U R E S
 *----------------------------------------------------------------------------------------
 */

/*----------------------------------------------------------------------------------------
 *           P R O T O T Y P E S     O F     L O C A L     F U N C T I O N S
 *----------------------------------------------------------------------------------------
 */

/*----------------------------------------------------------------------------------------
 *                          E X P O R T E D    F U N C T I O N S
 *----------------------------------------------------------------------------------------
 */
AGESA_STATUS
F10GetNbFrequency (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
  IN       PCI_ADDR *PciAddress,
     OUT   UINT32 *FrequencyInMHz,
     OUT   UINT32 *VoltageInuV,
  IN       AMD_CONFIG_PARAMS *StdHeader
  );
VOID
F10GetHtLinkFeatures (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  OUT      UINTN                  *Link,
  IN       PCI_ADDR               *LinkBase,
  OUT      HT_HOST_FEATS          *HtHostFeats,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );
BOOLEAN
F10DoesLinkHaveHtPhyFeats (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       PCI_ADDR           CapabilitySet,
  IN       UINT32             Link,
  IN       HT_PHY_LINK_FEATS  *HtPhyLinkType,
  OUT      BOOLEAN            *MatchedSublink1,
  OUT      HT_FREQUENCIES     *Frequency0,
  OUT      HT_FREQUENCIES     *Frequency1,
  IN       AMD_CONFIG_PARAMS  *StdHeader
  );
VOID
F10SetHtPhyRegister (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       HT_PHY_TYPE_ENTRY_DATA  *HtPhyEntry,
  IN       PCI_ADDR                 CapabilitySet,
  IN       UINT32                   Link,
  IN       AMD_CONFIG_PARAMS       *StdHeader
  );
VOID
F10SetRegisterForHtLinkTokenEntry (
  IN       TABLE_ENTRY_DATA       *Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/*---------------------------------------------------------------------------------------*/
/**
 *  Performs the necessary steps for the 'Software Initiated CPU
 *  Voltage Transitions.'
 *
 *  @param[in]   VidCode       VID code to transition to
 *  @param[in]   StdHeader     Header for library and services
 *
 */
VOID
F10PmSwVoltageTransition (
  IN       UINT32 VidCode,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32    PciRegister;
  UINT32    Socket;
  UINT32    Module;
  UINT32    Ignored;
  UINT64    MsrRegister;
  PCI_ADDR  PciAddress;
  AGESA_STATUS IgnoredSts;

  IdentifyCore (StdHeader, &Socket, &Module, &Ignored, &IgnoredSts);
  GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);

  PciAddress.Address.Function = FUNC_3;
  PciAddress.Address.Register = PW_CTL_MISC_REG;
  LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
  if (((POWER_CTRL_MISC_REGISTER *) &PciRegister)->SlamVidMode == 1) {
    LibAmdMsrRead (MSR_COFVID_CTL, &MsrRegister, StdHeader);
    ((COFVID_CTRL_MSR *) &MsrRegister)->CpuVid = VidCode;
    LibAmdMsrWrite (MSR_COFVID_CTL, &MsrRegister, StdHeader);
    F10WaitOutVoltageTransition  (TRUE, StdHeader);
  } else
    return;
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Performs the necessary steps for the 'Software Initiated NB
 *  Voltage Transitions.'
 *
 *  This can only be run by a local core 0.
 *
 *  @param[in]   VidCode       VID code to transition to
 *  @param[in]   SlamMode      Whether voltage is to be slammed, or stepped
 *  @param[in]   StdHeader     Header for library and services
 *
 */
VOID
F10PmSwVoltageTransitionServerNb (
  IN       UINT32 VidCode,
  IN       BOOLEAN SlamMode,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 Core;
  UINT32 NbVidStatus;
  UINT32 Socket;
  UINT32 IgnoredModule;
  UINT32 IgnoredCore;
  UINT32 CoreNum;
  AP_TASK TaskPtr;
  AGESA_STATUS IgnoredSts;
  SW_VOLT_TRANS_NB RemoteInput;

  RemoteInput.VidCode = VidCode;
  RemoteInput.SlamMode = SlamMode;
  TaskPtr.FuncAddress.PfApTaskIO = F10SwVoltageTransitionServerNbCore;
  TaskPtr.DataTransfer.DataSizeInDwords = SIZE_IN_DWORDS (SW_VOLT_TRANS_NB);
  TaskPtr.DataTransfer.DataPtr = &RemoteInput;
  TaskPtr.DataTransfer.DataTransferFlags = 0;
  TaskPtr.ExeFlags = WAIT_FOR_CORE;

  IdentifyCore (StdHeader, &Socket, &IgnoredModule, &IgnoredCore, &IgnoredSts);
  GetActiveCoresInCurrentSocket (&CoreNum, StdHeader);

  do {
    NbVidStatus = TaskPtr.FuncAddress.PfApTaskIO (&RemoteInput, StdHeader);
    for (Core = 1; Core < (UINT8) CoreNum; Core++) {
      NbVidStatus |= ApUtilRunCodeOnSocketCore ((UINT8)Socket, (UINT8)Core, &TaskPtr, StdHeader);
    }
    F10WaitOutVoltageTransition (SlamMode, StdHeader);
  } while (NbVidStatus != 0);
  return;
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Returns current VsSlamTime in microseconds.
 *
 *  @param[out]  VsTimeUsecs   Provides the wait time needed for a Slam Voltage transition.
 *  @param[in]   SlamMode      Whether voltage is to be slammed, or stepped
 *  @param[in]   StdHeader     Header for library and services
 *
 */
VOID
F10GetCurrentVsTimeInUsecs (
     OUT   UINT32  *VsTimeUsecs,
  IN       BOOLEAN SlamMode,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT8     RegisterEncoding;
  UINT32    PciRegister;
  UINT32    Socket;
  UINT32    Module;
  UINT32    Ignored;
  CONST UINT16    SlamTimes[8] = {10, 20, 30, 40, 60, 100, 200, 500};
  PCI_ADDR  PciAddress;
  AGESA_STATUS IgnoredSts;

  IdentifyCore (StdHeader, &Socket, &Module, &Ignored, &IgnoredSts);
  GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);

  PciAddress.Address.Function = FUNC_3;
  PciAddress.Address.Register = CPTC1_REG;
  LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);

  if (SlamMode) {
    RegisterEncoding = (UINT8) ((CLK_PWR_TIMING_CTRL1_REGISTER *) &PciRegister)->VSSlamTime;
  } else {
    RegisterEncoding = (UINT8) ((CLK_PWR_TIMING_CTRL1_REGISTER *) &PciRegister)->VSRampTime;
  }

  *VsTimeUsecs = (UINT32) SlamTimes[RegisterEncoding];
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Spins until VsSlamTime microseconds have expired.
 *
 *  @param[in]   SlamMode      Whether voltage is to be slammed, or stepped
 *  @param[in]   StdHeader     Header for library and services
 *
 */
VOID
F10WaitOutVoltageTransition (
  IN       BOOLEAN SlamMode,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 VsTimeUsecs;

  F10GetCurrentVsTimeInUsecs (&VsTimeUsecs, SlamMode, StdHeader);
  WaitMicroseconds (VsTimeUsecs, StdHeader);
  return;
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Code required to be run on every local core in order to perform
 *  the steps necessary for 'Software Initiated NB Voltage
 *  Transitions.'
 *
 *  @param[out]  InputData     Family specific data needed to perform a Voltage transition.
 *  @param[in]   StdHeader     Header for library and services.
 *
 *  @retval     zero           All Voltage Transitions are completed.
 *  @retval     one            There are Voltage transitions remaining to reach target.
 *
 */
UINT32
F10SwVoltageTransitionServerNbCore (
  IN       VOID  *InputData,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 VidCode;
  UINT64 MsrRegister;

  if (((SW_VOLT_TRANS_NB *) InputData)->SlamMode) {
    VidCode = ((SW_VOLT_TRANS_NB *) InputData)->VidCode;
  } else {
    LibAmdMsrRead (MSR_COFVID_STS, &MsrRegister, StdHeader);
    VidCode = (UINT32) (((COFVID_STS_MSR *) &MsrRegister)->CurNbVid);
    if (VidCode > ((SW_VOLT_TRANS_NB *) InputData)->VidCode) {
      --VidCode;
    } else if (VidCode < ((SW_VOLT_TRANS_NB *) InputData)->VidCode) {
      ++VidCode;
    }
  }
  LibAmdMsrRead (MSR_COFVID_CTL, &MsrRegister, StdHeader);
  ((COFVID_CTRL_MSR *) &MsrRegister)->NbVid = VidCode;
  LibAmdMsrWrite (MSR_COFVID_CTL, &MsrRegister, StdHeader);

  if (VidCode == ((SW_VOLT_TRANS_NB *) InputData)->VidCode) {
    return 0;
  } else {
    return 1;
  }
}


/*---------------------------------------------------------------------------------------*/
/**
 * Calculate and reprogram F3xD8[VSSlamTime] based on the algorithm in the BKDG.
 *
 * This function determines the largest voltage step that the core will have
 * to make, calculates how much time it will take for the voltage to stabilize,
 * and programs the necessary encoded value for the amount of time discovered.
 *
 * @param[in]  PciAddress         Segment/bus/device of a module on the socket
 *                                to program.
 * @param[in]  CpuEarlyParams     Service parameters
 * @param[in]  StdHeader          Config handle for library and services.
 *
 */
VOID
F10ProgramVSSlamTimeOnSocket (
  IN       PCI_ADDR             *PciAddress,
  IN       AMD_CPU_EARLY_PARAMS *CpuEarlyParams,
  IN       AMD_CONFIG_PARAMS    *StdHeader
  )
{
  UINT8    NbVid;
  UINT8    P0VidCode;
  UINT8    PminVidCode;
  UINT32   AndMask;
  UINT32   MsrAddr;
  UINT32   OrMask;
  UINT32   PciRegister;
  UINT64   MsrRegister;
  BOOLEAN  IsPviMode;
  PCI_ADDR LocalPciAddress;

  // Get F3xA0[PviMode]
  LocalPciAddress.AddressValue = PciAddress->AddressValue;
  LocalPciAddress.Address.Function = FUNC_3;
  LocalPciAddress.Address.Register = PW_CTL_MISC_REG;
  LibAmdPciRead (AccessWidth32, LocalPciAddress, &PciRegister, StdHeader);
  if (((POWER_CTRL_MISC_REGISTER *) &PciRegister)->PviMode == 1) {
    IsPviMode = TRUE;
  } else {
    IsPviMode = FALSE;
  }

  // Get P0's voltage
  LibAmdMsrRead (PS_REG_BASE, &MsrRegister, StdHeader);
  P0VidCode = (UINT8) (((PSTATE_MSR *) &MsrRegister)->CpuVid);

  // If SVI, we only care about CPU VID.
  // If PVI, determine the higher voltage between NB and CPU
  if (IsPviMode) {
    NbVid = (UINT8) (((PSTATE_MSR *) &MsrRegister)->NbVid);
    if (P0VidCode > NbVid) {
      P0VidCode = NbVid;
    }
  }

  // Get Pmin's index
  LibAmdMsrRead (MSR_PSTATE_CURRENT_LIMIT, &MsrRegister, StdHeader);
  MsrAddr = (UINT32) ((((PSTATE_CURLIM_MSR *) &MsrRegister)->PstateMaxVal) + PS_REG_BASE);

  // Get Pmin's VID
  LibAmdMsrRead (MsrAddr, &MsrRegister, StdHeader);
  PminVidCode = (UINT8) (((PSTATE_MSR *) &MsrRegister)->CpuVid);

  // If SVI, we only care about CPU VID.
  // If PVI, determine the higher voltage b/t NB and CPU
  if (IsPviMode) {
    NbVid = (UINT8) (((PSTATE_MSR *) &MsrRegister)->NbVid);
    if (PminVidCode > NbVid) {
      PminVidCode = NbVid;
    }
  }

  // Program F3xD8[VSSlamTime]
  LocalPciAddress.Address.Register = CPTC1_REG;
  AndMask = 0xFFFFFFFF;
  ((CLK_PWR_TIMING_CTRL1_REGISTER *) &AndMask)->VSSlamTime = 0;
  OrMask = 0x00000000;
  ((CLK_PWR_TIMING_CTRL1_REGISTER *) &OrMask)->VSSlamTime =
    F10GetSlamTimeEncoding (P0VidCode, PminVidCode, CpuEarlyParams, VSSlamTime, StdHeader);
  ModifyCurrentSocketPci (&LocalPciAddress, AndMask, OrMask, StdHeader);
}


/*---------------------------------------------------------------------------------------*/
/**
 * Returns the encoded voltage stabilization slam time for the executing
 * family 10h core.
 *
 * This function looks up the appropriate encoded value for the desired
 * VID codes.
 *
 * @param[in]  HighVoltageVid     VID code of the higher voltage.
 * @param[in]  LowVoltageVid      VID code of the lower voltage.
 * @param[in]  CpuEarlyParams     Service parameters
 * @param[in]  SlamTimeTable      Look-up table of slam times.
 * @param[in]  StdHeader          Config handle for library and services.
 *
 * @retval     Encoded register value.
 *
 */
UINT32
F10GetSlamTimeEncoding (
  IN       UINT8  HighVoltageVid,
  IN       UINT8  LowVoltageVid,
  IN       AMD_CPU_EARLY_PARAMS *CpuEarlyParams,
  IN       CONST UINT32 *SlamTimeTable,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 SlamTime;
  UINT32 EncodedSlamTime;
  UINT32 VoltageDifference;

  ASSERT (LowVoltageVid >= HighVoltageVid);
  ASSERT (CpuEarlyParams->PlatformConfig.VrmProperties.SlewRate != 0);

  // Calculate Slam Time
  //   VSSlamTime = 0.4us/mV (or 0.2us/mV) * Vhigh - Vlow
  //   In our case, we will scale the values by 100 to avoid
  //   decimals.

  VoltageDifference = (UINT32) ((LowVoltageVid - HighVoltageVid) * 12500);
  SlamTime = (VoltageDifference / CpuEarlyParams->PlatformConfig.VrmProperties.SlewRate) + CpuEarlyParams->PlatformConfig.VrmProperties.AdditionalDelay;
  if (VoltageDifference % CpuEarlyParams->PlatformConfig.VrmProperties.SlewRate) {
    SlamTime++;
  }

  // Now round up to nearest register setting
  for (EncodedSlamTime = 0; EncodedSlamTime < 8; EncodedSlamTime++) {
    if (SlamTime <= SlamTimeTable[EncodedSlamTime]) {
      break;
    }
  }

  if (EncodedSlamTime > 7) {
    // The VRMs are too slow for this CPU.  Set to max, and fire an error trap.
    IDS_ERROR_TRAP;
    EncodedSlamTime = 7;
  }

  return (EncodedSlamTime);
}


/*---------------------------------------------------------------------------------------*/
/**
 *  Calculates the power in milliWatts of the desired P-state.
 *
 *  @CpuServiceMethod{::F_CPU_GET_PSTATE_POWER}.
 *
 *  @param[in]   FamilySpecificServices   The current Family Specific Services.
 *  @param[in]   StateNumber              Which P-state to analyze
 *  @param[out]  PowerInMw                The Power in milliWatts of that P-State
 *  @param[in]   StdHeader                Header for library and services
 *
 *  @retval      AGESA_SUCCESS Always succeeds.
 */
AGESA_STATUS
F10GetPstatePower (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
  IN       UINT8 StateNumber,
     OUT   UINT32 *PowerInMw,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32  CpuVid;
  UINT32  IddValue;
  UINT32  IddDiv;
  UINT32  Socket;
  UINT32  Module;
  UINT32  Ignored;
  BOOLEAN PviFlag;
  UINT32  V_x10000;
  UINT32  Power;
  PCI_ADDR PciAddress;
  UINT32  TempVar_a;
  UINT64  MsrRegister;
  AGESA_STATUS IgnoredSts;

  ASSERT (StateNumber < NM_PS_REG);
  LibAmdMsrRead (PS_REG_BASE + (UINT32) StateNumber, &MsrRegister, StdHeader);
  ASSERT (((PSTATE_MSR *) &MsrRegister)->PsEnable == 1);
  CpuVid = (UINT32) (((PSTATE_MSR *) &MsrRegister)->CpuVid);
  IddValue = (UINT32) (((PSTATE_MSR *) &MsrRegister)->IddValue);
  IddDiv = (UINT32) (((PSTATE_MSR *) &MsrRegister)->IddDiv);

  IdentifyCore (StdHeader, &Socket, &Module, &Ignored, &IgnoredSts);
  GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);

  PciAddress.Address.Function = FUNC_3;
  PciAddress.Address.Register = POWER_CTRL_MISCELLANEOUS_REG;
  LibAmdPciRead (AccessWidth32, PciAddress, &TempVar_a, StdHeader);
  if ((TempVar_a & 0x00000100) != 0) {
    PviFlag = TRUE;
  } else {
    PviFlag = FALSE;
  }
  if (PviFlag) {
    // Set CpuVid value in case CPU is in PVI mode
    if (CpuVid > 0x5D) {
      CpuVid = 0x3F;
    } else if (CpuVid > 0x3E) {
      CpuVid = CpuVid - 0x1F;
    } else {
      CpuVid = (CpuVid >> 1);
    }

    // PVI Encoding
    if (CpuVid >= 0x20) {
      V_x10000 = 7625L - (125L * (CpuVid - 0x20));
    } else {
      V_x10000 = 15500L - (250L * CpuVid);
    }
  } else {
    if (CpuVid >= 0x7C) {
      V_x10000 = 0;
    } else {
      V_x10000 = 15500L - (125L * CpuVid);
    }
  }

  Power = V_x10000 * IddValue;

  switch (IddDiv) {
  case 0:
    *PowerInMw = Power / 10L;
    break;
  case 1:
    *PowerInMw = Power / 100L;
    break;
  case 2:
    *PowerInMw = Power / 1000L;
    break;
  default:
    // IddDiv is set to an undefined value.  This is due to either a misfused CPU, or
    // an invalid P-state MSR write.
    ASSERT (FALSE);
    *PowerInMw = 0;
    break;
  }
  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Calculates the frequency in megahertz of the desired P-state.
 *
 *  @CpuServiceMethod{::F_CPU_GET_PSTATE_FREQ}.
 *
 *  @param[in]   FamilySpecificServices   The current Family Specific Services.
 *  @param[in]   StateNumber              The P-State to analyze.
 *  @param[out]  FrequencyInMHz           The P-State's frequency in MegaHertz
 *  @param[in]   StdHeader                Header for library and services
 *
 *  @retval      AGESA_SUCCESS   Always Succeeds.
 */
AGESA_STATUS
F10GetPstateFrequency (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
  IN       UINT8 StateNumber,
     OUT   UINT32 *FrequencyInMHz,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT8 TempValue;
  UINT32 CpuDid;
  UINT32 CpuFid;
  UINT64 MsrRegister;

  ASSERT (StateNumber < NM_PS_REG);
  LibAmdMsrRead (PS_REG_BASE + (UINT32) StateNumber, &MsrRegister, StdHeader);
  ASSERT (((PSTATE_MSR *) &MsrRegister)->PsEnable == 1);
  CpuDid = (UINT32) (((PSTATE_MSR *) &MsrRegister)->CpuDid);
  CpuFid = (UINT32) (((PSTATE_MSR *) &MsrRegister)->CpuFid);

  switch (CpuDid) {
  case 0:
    TempValue = 1;
    break;
  case 1:
    TempValue = 2;
    break;
  case 2:
    TempValue = 4;
    break;
  case 3:
    TempValue = 8;
    break;
  case 4:
    TempValue  =  16;
    break;
  default:
    // CpuDid is set to an undefined value.  This is due to either a misfused CPU, or
    // an invalid P-state MSR write.
    ASSERT (FALSE);
    TempValue = 1;
    break;
  }
  *FrequencyInMHz = (100 * (CpuFid + 0x10) / TempValue);
  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Disables the desired P-state.
 *
 *  @CpuServiceMethod{::F_CPU_DISABLE_PSTATE}.
 *
 *  @param[in]   FamilySpecificServices   The current Family Specific Services.
 *  @param[in]   StateNumber              The P-State to disable.
 *  @param[in]   StdHeader                Header for library and services
 *
 *  @retval      AGESA_SUCCESS Always succeeds.
 */
AGESA_STATUS
F10DisablePstate (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
  IN       UINT8 StateNumber,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT64 MsrRegister;

  ASSERT (StateNumber < NM_PS_REG);
  LibAmdMsrRead (PS_REG_BASE + (UINT32) StateNumber, &MsrRegister, StdHeader);
  ((PSTATE_MSR *) &MsrRegister)->PsEnable = 0;
  LibAmdMsrWrite (PS_REG_BASE + (UINT32) StateNumber, &MsrRegister, StdHeader);
  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Transitions the executing core to the desired P-state.
 *
 *  @CpuServiceMethod{::F_CPU_TRANSITION_PSTATE}.
 *
 *  @param[in]   FamilySpecificServices   The current Family Specific Services.
 *  @param[in]   StateNumber              The new P-State to make effective.
 *  @param[in]   WaitForTransition        True if the caller wants the transition completed upon return.
 *  @param[in]   StdHeader                Header for library and services
 *
 *  @retval      AGESA_SUCCESS       Always Succeeds
 */
AGESA_STATUS
F10TransitionPstate (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
  IN       UINT8              StateNumber,
  IN       BOOLEAN            WaitForTransition,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT64 MsrRegister;

  ASSERT (StateNumber < NM_PS_REG);
  LibAmdMsrRead (PS_REG_BASE + (UINT32) StateNumber, &MsrRegister, StdHeader);
  ASSERT (((PSTATE_MSR *) &MsrRegister)->PsEnable == 1);
  LibAmdMsrRead (MSR_PSTATE_CTL, &MsrRegister, StdHeader);
  ((PSTATE_CTRL_MSR *) &MsrRegister)->PstateCmd = (UINT64) StateNumber;
  LibAmdMsrWrite (MSR_PSTATE_CTL, &MsrRegister, StdHeader);
  if (WaitForTransition) {
    do {
      LibAmdMsrRead (MSR_PSTATE_STS, &MsrRegister, StdHeader);
    } while (((PSTATE_STS_MSR *) &MsrRegister)->CurPstate != (UINT64) StateNumber);
  }
  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Determines the rate at which the executing core's time stamp counter is
 *  incrementing.
 *
 *  @CpuServiceMethod{::F_CPU_GET_TSC_RATE}.
 *
 *  @param[in]   FamilySpecificServices   The current Family Specific Services.
 *  @param[out]  FrequencyInMHz           TSC actual frequency.
 *  @param[in]   StdHeader                Header for library and services.
 *
 *  @return      The most severe status of all called services
 */
AGESA_STATUS
F10GetTscRate (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
     OUT   UINT32 *FrequencyInMHz,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 Socket;
  UINT32 Module;
  UINT32 Ignored;
  UINT64 MsrRegister;
  PCI_ADDR PciAddress;
  AGESA_STATUS IgnoredSts;

  LibAmdMsrRead (0xC0010015, &MsrRegister, StdHeader);
  if ((MsrRegister & 0x01000000) != 0) {
    return (FamilySpecificServices->GetPstateFrequency (FamilySpecificServices, 0, FrequencyInMHz, StdHeader));
  } else {
    IdentifyCore (StdHeader, &Socket, &Module, &Ignored, &IgnoredSts);
    GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);
    return (FamilySpecificServices->GetNbFrequency (FamilySpecificServices, &PciAddress, FrequencyInMHz, &Ignored, StdHeader));
  }
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Determines the NB clock on the desired node.
 *
 *  @CpuServiceMethod{::F_CPU_GET_NB_FREQ}.
 *
 *  @param[in]   FamilySpecificServices   The current Family Specific Services.
 *  @param[in]   PciAddress               The northbridge to query
 *  @param[out]  FrequencyInMHz           Northbridge clock frequency in MHz.
 *  @param[out]  VoltageInuV              Northbridge voltage in uV.
 *  @param[in]   StdHeader                Header for library and services
 *
 *  @retval      AGESA_UNSUPPORTED   Unknown revs of F10 will return unsupported.
 */
AGESA_STATUS
F10GetNbFrequency (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
  IN       PCI_ADDR *PciAddress,
     OUT   UINT32 *FrequencyInMHz,
     OUT   UINT32 *VoltageInuV,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  // This was called by an unknown rev of F10 CPU.
  return (AGESA_UNSUPPORTED);
}

/*---------------------------------------------------------------------------------------*/
/**
 * Initially launches the desired core to run from the reset vector.
 *
 * @CpuServiceMethod{::F_CPU_AP_INITIAL_LAUNCH}.
 *
 * @param[in]   FamilySpecificServices   The current Family Specific Services.
 * @param[in]   SocketNum                The Processor on which the core is to be launched
 * @param[in]   ModuleNum                The Module in that processor containing that core
 * @param[in]   CoreNum                  The Core to launch
 * @param[in]   PrimaryCoreNum           The id of the module's primary core.
 * @param[in]   StdHeader                Header for library and services
 *
 * @retval      TRUE          The core was launched
 * @retval      FALSE         The core was previously launched
 */
BOOLEAN
F10LaunchApCore (
  IN       CPU_SPECIFIC_SERVICES *FamilySpecificServices,
  IN       UINT32 SocketNum,
  IN       UINT32 ModuleNum,
  IN       UINT32 CoreNum,
  IN       UINT32 PrimaryCoreNum,
  IN       AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32    NodeRelativeCoreNum;
  UINT32    PciRegister;
  PCI_ADDR  PciAddress;
  BOOLEAN   LaunchFlag;
  AGESA_STATUS Ignored;

  // Code Start
  LaunchFlag = FALSE;
  NodeRelativeCoreNum = CoreNum - PrimaryCoreNum;
  GetPciAddress (StdHeader, SocketNum, ModuleNum, &PciAddress, &Ignored);
  PciAddress.Address.Function = FUNC_0;

  switch (NodeRelativeCoreNum) {
  case 0:
    PciAddress.Address.Register = HT_INIT_CTRL;
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
    if ((PciRegister & HT_INIT_CTRL_REQ_DIS) != 0) {
      PciRegister &= ~HT_INIT_CTRL_REQ_DIS;
      LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister, StdHeader);
      LaunchFlag = TRUE;
    } else {
      LaunchFlag = FALSE;
    }
    break;

  case 1:
    PciAddress.Address.Register = HT_TRANS_CTRL;
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
    if ((PciRegister & HT_TRANS_CTRL_CPU1_EN) == 0) {
      PciRegister |= HT_TRANS_CTRL_CPU1_EN;
      LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister, StdHeader);
      LaunchFlag = TRUE;
    } else {
      LaunchFlag = FALSE;
    }
    break;

  case 2:
    PciAddress.Address.Register = ECS_HT_TRANS_CTRL;
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);

    if ((PciRegister & ECS_HT_TRANS_CTRL_CPU2_EN) == 0) {
      PciRegister |= ECS_HT_TRANS_CTRL_CPU2_EN;
      LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister,
                      StdHeader);
      LaunchFlag = TRUE;
    } else {
      LaunchFlag = FALSE;
    }
    break;

  case 3:
    PciAddress.Address.Register = ECS_HT_TRANS_CTRL;
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
    if ((PciRegister & ECS_HT_TRANS_CTRL_CPU3_EN) == 0) {
      PciRegister |= ECS_HT_TRANS_CTRL_CPU3_EN;
      LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister, StdHeader);
      LaunchFlag = TRUE;
    } else {
      LaunchFlag = FALSE;
    }
    break;

  case 4:
    PciAddress.Address.Register = ECS_HT_TRANS_CTRL;
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
    if ((PciRegister & ECS_HT_TRANS_CTRL_CPU4_EN) == 0) {
      PciRegister |= ECS_HT_TRANS_CTRL_CPU4_EN;
      LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister, StdHeader);
      LaunchFlag = TRUE;
    } else {
      LaunchFlag = FALSE;
    }
    break;

  case 5:
    PciAddress.Address.Register = ECS_HT_TRANS_CTRL;
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
    if ((PciRegister & ECS_HT_TRANS_CTRL_CPU5_EN) == 0) {
      PciRegister |= ECS_HT_TRANS_CTRL_CPU5_EN;
      LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister, StdHeader);
      LaunchFlag = TRUE;
    } else {
      LaunchFlag = FALSE;
    }
    break;


  default:
    break;
  }

  return (LaunchFlag);
}

/*---------------------------------------------------------------------------------------*/
/**
 *    This function will return the CpuFid and CpuDid in MHz, using the formula
 *    described in the BKDG MSRC001_00[68:64] P-State [4:0] Registers:bit 8:0
 *
 *    @param[in]       FamilySpecificServices   The current Family Specific Services.
 *    @param[in]       PStateNumber             P-state number to check.
 *    @param[in]       Frequency                Leveled target frequency for PStateNumber.
 *    @param[out]      *CpuFidPtr               New leveled FID.
 *    @param[out]      *CpuDidPtr1              New leveled DID info 1.
 *    @param[out]      *CpuDidPtr2              New leveled DID info 2.
 *    @param[in]       *StdHeader               Header for library and services.
 *
 *    @retval       AGESA_WARNING           This P-State does not need to be modified.
 *    @retval       AGESA_SUCCESS           This P-State must be modified to be level.
 */
AGESA_STATUS
F10GetFrequencyXlatRegInfo (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       UINT8                  PStateNumber,
  IN       UINT32                 Frequency,
     OUT   UINT32                 *CpuFidPtr,
     OUT   UINT32                 *CpuDidPtr1,
     OUT   UINT32                 *CpuDidPtr2,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  )
{
  UINT32 i;
  UINT32 j;
  AGESA_STATUS Status;
  UINT32 FrequencyInMHz;

  FrequencyInMHz = 0;
  *CpuDidPtr2 = 0xFFFF;

  Status = AGESA_SUCCESS;

  FamilySpecificServices->GetPstateFrequency (FamilySpecificServices, PStateNumber, &FrequencyInMHz, StdHeader);
  if (FrequencyInMHz == Frequency) {
    Status |= AGESA_WARNING;
  }

  // CPU Frequency = 100 MHz * (CpuFid + 10h) / (2^CpuDid)
  // In this for loop i = 2^CpuDid


  for (i = 1; i < 17; (i += i)) {
    for (j = 0; j < 64; j++) {
      if (Frequency == ((100 * (j + 0x10)) / i )) {
        *CpuFidPtr = j;
        if (i == 1) {
          *CpuDidPtr1 = 0;
        } else if (i == 2) {
          *CpuDidPtr1 = 1;
        } else if (i == 4) {
          *CpuDidPtr1 = 2;
        } else if (i == 8) {
          *CpuDidPtr1 = 3;
        } else if (i == 16) {
          *CpuDidPtr1 = 4;
        } else {
          *CpuFidPtr = 0xFFFF;
          *CpuDidPtr1 = 0xFFFF;
        }
        // Success
        return Status;
      }
    }
  }

  // Error Condition
  *CpuFidPtr = 0x00FF;
  *CpuDidPtr1 = 0x00FF;
  *CpuDidPtr2 = 0x00FF;

  return AGESA_ERROR;
}

/*---------------------------------------------------------------------------------------*/
/**
 * This function sets the Pstate MSR to each APs base on Pstate Buffer.
 *
 * @CpuServiceMethod{::F_CPU_SET_PSTATE_LEVELING_REG}.
 *
 * This function should be called for every core in the system.
 *
 * @param[in]       FamilySpecificServices   The current Family Specific Services.
 * @param[in]       CpuAmdPState             Gathered P-state data structure for whole system.
 * @param[in]       StdHeader                Config for library and services.
 *
 * @retval          AGESA_STATUS    @todo document return *values*.
 *
 */
AGESA_STATUS
F10PstateLevelingCoreMsrModify (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       S_CPU_AMD_PSTATE   *CpuAmdPState,
  IN       AMD_CONFIG_PARAMS  *StdHeader
  )
{
  UINT32             i;
  UINT32             Ignored;
  UINT32             k;
  UINT32             TempVar_d;
  UINT32             TempVar_e;
  UINT32             TempVar_f;
  UINT64             MsrValue;
  AGESA_STATUS       Status;
  UINT32             Socket;
  UINT32             Module;
  UINT32             Core;
  PSTATE_LEVELING    *PStateBufferPtr;
  PSTATE_LEVELING    *PStateBufferPtrTmp;
  S_CPU_AMD_PSTATE   *CpuAmdPstatePtr;
  UINT32             LogicalSocketCount;
  PCI_ADDR           PciAddress;
  UINT32             PciRegister;

  Ignored = 0;
  CpuAmdPstatePtr = (S_CPU_AMD_PSTATE *) CpuAmdPState;
  PStateBufferPtrTmp = CpuAmdPstatePtr->PStateLevelingStruc;
  PStateBufferPtr = CpuAmdPstatePtr->PStateLevelingStruc;
  LogicalSocketCount = CpuAmdPstatePtr->TotalSocketInSystem;
  PciAddress.AddressValue = 0;

  //
  //Try to find the Pstate buffer specific to this core(socket).
  //
  IdentifyCore (StdHeader, &Socket, &Module, &Core, &Status);
  for (i = 0; i < LogicalSocketCount; i++) {
    CpuGetPStateLevelStructure (&PStateBufferPtrTmp, CpuAmdPstatePtr, i, StdHeader);
    if (PStateBufferPtrTmp->SocketNumber == Socket) {
      break;
    }
  }

  if (PStateBufferPtr[0].OnlyOneEnabledPState) {
    //
    //If all processors have only 1 enabled P-state, the following sequence should be performed on all cores:
    //

    //1. Write the appropriate CpuFid value resulting from the matched CPU COF to MSRC001_0064[CpuFid].
    LibAmdMsrRead (MSR_PSTATE_0, &MsrValue, StdHeader);
    Status = F10GetFrequencyXlatRegInfo (FamilySpecificServices, 0, PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[0].CoreFreq, &TempVar_d, &TempVar_e, &Ignored, StdHeader);
    // Bits 5:0
    ((PSTATE_MSR *) &MsrValue)->CpuFid = TempVar_d;
    // Bits 8:6
    ((PSTATE_MSR *) &MsrValue)->CpuDid = TempVar_e;
    // Bits 39:32
    ((PSTATE_MSR *) &MsrValue)->IddValue = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[0].IddValue;
    // Bits 41:40
    ((PSTATE_MSR *) &MsrValue)->IddDiv = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[0].IddDiv;
    // Enable the P-State
    ((PSTATE_MSR *) &MsrValue)->PsEnable = 1;
    LibAmdMsrWrite (MSR_PSTATE_0, &MsrValue, StdHeader);

    //2. Copy MSRC001_0064 to MSRC001_0065.
    LibAmdMsrWrite (MSR_PSTATE_1, &MsrValue, StdHeader);

    //3. Write 001b to F3xDC[PstatemaxVal].
    GetPciAddress (StdHeader, Socket, Module, &PciAddress, &Status);
    PciAddress.Address.Register = CPTC2_REG;
    PciAddress.Address.Function = FUNC_3;
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
    ((CLK_PWR_TIMING_CTRL2_REGISTER *) &PciRegister)->PstateMaxVal = 1;
    LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister, StdHeader);

    //4. Write 001b to MSRC001_0062[PstateCmd].
    FamilySpecificServices->TransitionPstate (FamilySpecificServices, (UINT8) 1, (BOOLEAN) FALSE, StdHeader);

    //5. Wait for MSRC001_0071[CurCpuFid] = MSRC001_0065[CpuFid].
    do {
      LibAmdMsrRead (MSR_COFVID_STS, &MsrValue, StdHeader);
    } while (((COFVID_STS_MSR *) &MsrValue)->CurCpuFid != TempVar_d);

    //6. Write 000b to MSRC001_0062[PstateCmd].
    FamilySpecificServices->TransitionPstate (FamilySpecificServices, (UINT8) 0, (BOOLEAN) FALSE, StdHeader);

    //7. Wait for MSRC001_0071[CurCpuFid] = MSRC001_0064[CpuFid].
    do {
      LibAmdMsrRead (MSR_COFVID_STS, &MsrValue, StdHeader);
    } while (((COFVID_STS_MSR *) &MsrValue)->CurCpuFid != TempVar_d);

    //8. Write 0b to MSRC001_0065[PstateEn].
    LibAmdMsrRead (MSR_PSTATE_1, &MsrValue, StdHeader);
    ((PSTATE_MSR *) &MsrValue)->PsEnable = 0;
    LibAmdMsrWrite (MSR_PSTATE_1, &MsrValue, StdHeader);

    //9. Write 000b to F3xDC[PstateMaxVal] and exit the sequence (no further steps are required).
    LibAmdPciRead (AccessWidth32, PciAddress, &PciRegister, StdHeader);
    ((CLK_PWR_TIMING_CTRL2_REGISTER *) &PciRegister)->PstateMaxVal = 0;
    LibAmdPciWrite (AccessWidth32, PciAddress, &PciRegister, StdHeader);

  } else {
    TempVar_f = MSR_PSTATE_0;

    for (k = 0; k <= PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue; k++, TempVar_f++) {
      // If pState is not disabled then do update
      LibAmdMsrRead (TempVar_f, &MsrValue, StdHeader);

      if (PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].PStateEnable == 1) {
        Status = F10GetFrequencyXlatRegInfo (FamilySpecificServices, (UINT8) k, PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].CoreFreq, &TempVar_d, &TempVar_e, &Ignored, StdHeader);
        if (Status != AGESA_ERROR) {
          // Bits 5:0
          ((PSTATE_MSR *) &MsrValue)->CpuFid = TempVar_d;
          // Bits 8:6
          ((PSTATE_MSR *) &MsrValue)->CpuDid = TempVar_e;
        }

        // Bits 39:32
        ((PSTATE_MSR *) &MsrValue)->IddValue = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].IddValue;
        // Bits 41:40
        ((PSTATE_MSR *) &MsrValue)->IddDiv = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].IddDiv;
        // Enable the P-State
        ((PSTATE_MSR *) &MsrValue)->PsEnable = 1;
        LibAmdMsrWrite (TempVar_f, &MsrValue, StdHeader);
      } else {
        // Disable the P-State
        ((PSTATE_MSR *) &MsrValue)->PsEnable = 0;
        LibAmdMsrWrite (TempVar_f, &MsrValue, StdHeader);
      }
    }
  }
  return AGESA_SUCCESS;
}

/**
 *---------------------------------------------------------------------------------------
 *
 *  F10GetPowerStepValueInTime
 *
 *  Description:
 *    Convert power step value in time
 *
 *  Parameters:
 *    @param[out]     *PowerStepPtr
 *
 *    @retval       VOID
 *
 *---------------------------------------------------------------------------------------
 **/
STATIC VOID
F10GetPowerStepValueInTime (
  IN OUT   UINT32  *PowerStepPtr
  )
{
  UINT32 TempVar_a;

  TempVar_a = *PowerStepPtr;

  if (TempVar_a < 0x4) {
    *PowerStepPtr = 400 - (TempVar_a * 100);
  } else if (TempVar_a <  0x9) {
    *PowerStepPtr = 130 - (TempVar_a * 10);
  } else {
    *PowerStepPtr = 90 - (TempVar_a * 5);
  }
}


/**
 *---------------------------------------------------------------------------------------
 *
 *  F10GetPllValueInTime
 *
 *  Description:
 *    Convert PLL Value in time
 *
 *  Parameters:
 *    @param[out]     *PllLockTimePtr
 *
 *    @retval       VOID
 *
 *---------------------------------------------------------------------------------------
 **/
STATIC VOID
F10GetPllValueInTime (
  IN OUT   UINT32  *PllLockTimePtr
  )
{
  if (*PllLockTimePtr < 4) {
    *PllLockTimePtr = *PllLockTimePtr + 1;
  } else if (*PllLockTimePtr == 4) {
    *PllLockTimePtr = 8;
  } else if (*PllLockTimePtr == 5) {
    *PllLockTimePtr = 16;
  } else
    *PllLockTimePtr = 0;
}
/*---------------------------------------------------------------------------------------*/
/**
 *  Get Pstate Transition Latency.
 *
 *  @CpuServiceMethod{::F_CPU_PSTATE_TRANSITION_LATENCY}.
 *
 *  Calculate TransitionLatency by power step value and pll value.
 *
 *  @param[in]     FamilySpecificServices            The current Family Specific Services.
 *  @param[in]     PStateLevelingBufferStructPtr     Pstate row data buffer pointer
 *  @param[in]     PciAddress                        Pci address
 *  @param[out]    TransitionLatency                 The transition latency.
 *  @param[in]     StdHeader                         Header for library and services
 *
 *  @retval      AGESA_SUCCESS Always succeeds.
 */
AGESA_STATUS
F10GetPstateTransLatency (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       PSTATE_LEVELING        *PStateLevelingBufferStructPtr,
  IN       PCI_ADDR               *PciAddress,
     OUT   UINT32                 *TransitionLatency,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  )
{
  UINT32               TempVar_b;
  UINT32               TempVar_c;
  UINT32               TempVar_d;
  UINT32               TempVar8_a;
  UINT32               TempVar8_b;
  UINT32               Ignored;
  UINT32               k;
  UINT32               CpuFidSameFlag;
  UINT8                PStateMaxValueOnCurrentCore;
  UINT32               TransAndBusMastLatency;

  CpuFidSameFlag = 1;

  F10GetFrequencyXlatRegInfo (
    FamilySpecificServices,
    0,
    PStateLevelingBufferStructPtr->PStateCoreStruct[0].PStateStruct[0].CoreFreq,
    &TempVar_b,
    &TempVar_c,
    &Ignored,
    StdHeader
    );

  TempVar_d = TempVar_b;
  PStateMaxValueOnCurrentCore = PStateLevelingBufferStructPtr->PStateCoreStruct[0].PStateMaxValue;

  //
  //Check if MSRC001_00[68:64][CpuFid] is the same value for all P-states where
  //MSRC001_00[68:64][PstateEn]=1
  //
  for (k = 1; k <= PStateMaxValueOnCurrentCore; k++) {
    if (PStateLevelingBufferStructPtr->PStateCoreStruct[0].PStateStruct[k].PStateEnable != 0) {
      F10GetFrequencyXlatRegInfo (
        FamilySpecificServices,
        (UINT8) k,
        PStateLevelingBufferStructPtr->PStateCoreStruct[0].PStateStruct[k].CoreFreq,
        &TempVar_b,
        &TempVar_c,
        &Ignored,
        StdHeader
        );
    }

    if (TempVar_d != TempVar_b) {
      CpuFidSameFlag = 0;
      break;
    }
  }

  PciAddress->Address.Register = 0xD4;
  PciAddress->Address.Function = FUNC_3;
  LibAmdPciRead (AccessWidth32, *PciAddress, &TempVar_d, StdHeader);

  // PowerStepDown - Bits 20:23
  TempVar8_a = (TempVar_d & 0x00F00000) >> 20;

  // PowerStepUp   - Bits 24:27
  TempVar8_b = (TempVar_d & 0x0F000000) >> 24;

  // Convert the raw numbers in TempVar8_a and TempVar8_b into time
  F10GetPowerStepValueInTime (&TempVar8_a);
  F10GetPowerStepValueInTime (&TempVar8_b);

  //
  //(12 * (F3xD4[PowerStepDown] + F3xD4[PowerStepUp]) /1000) us
  //
  TransAndBusMastLatency =
  (12 * (TempVar8_a + TempVar8_b) + 999) / 1000;

  if (CpuFidSameFlag == 0) {
    //
    //+ F3xA0[PllLockTime]
    //
    PciAddress->Address.Register = 0xA0;
    LibAmdPciRead (AccessWidth32, *PciAddress, &TempVar_d, StdHeader);

    TempVar8_a = (0x00003800 & TempVar_d) >> 11;
    F10GetPllValueInTime (&TempVar8_a);
    TransAndBusMastLatency += TempVar8_a;
  }

  *TransitionLatency = TransAndBusMastLatency;

  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Get CPU pstate register Informations.
 *
 *  @CpuServiceMethod{::F_CPU_GET_PSTATE_REGISTER_INFO}.
 *
 *    This function will check if PState is Enabled by reading MSR.
 *    This function also returns the MSR Value, that contains IddValue, IddDiv.
 *
 *  @param[in]     FamilySpecificServices    The current Family Specific Services.
 *  @param[in]     PState                    Input Pstate number for query.
 *  @param[out]    PStateEnabled             Boolean flag return pstate enable.
 *  @param[in,out] IddVal                    Pstate current value.
 *  @param[in,out] IddDiv                    Pstate current divisor.
 *  @param[in]     StdHeader                 Handle of Header for calling lib functions and services.
 *
 *  @retval      AGESA_SUCCESS Always succeeds.
 */
AGESA_STATUS
F10GetPstateRegisterInfo (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       UINT32              PState,
     OUT   BOOLEAN             *PStateEnabled,
  IN OUT   UINT32              *IddVal,
  IN OUT   UINT32              *IddDiv,
  IN       AMD_CONFIG_PARAMS   *StdHeader
  )
{
  UINT64 MsrRegister;

  ASSERT (PState < NM_PS_REG);

  // Read PSTATE MSRs
  LibAmdMsrRead (PS_REG_BASE + (UINT32) PState, &MsrRegister, StdHeader);

  if (((PSTATE_MSR *) &MsrRegister)->PsEnable == 1) {
    // PState enable = bit 63
    *PStateEnabled = TRUE;
  } else {
    *PStateEnabled = FALSE;
  }

  // Bits 39:32 (high 32 bits [7:0])
  *IddVal = (UINT32) ((PSTATE_MSR *) &MsrRegister)->IddValue;
  // Bits 41:40 (high 32 bits [9:8])
  *IddDiv = (UINT32) ((PSTATE_MSR *) &MsrRegister)->IddDiv;

  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Get CPU pstate max state.
 *
 *  @CpuServiceMethod{::F_CPU_GET_PSTATE_MAX_STATE}.
 *
 *    This function returns the MaxPStateNumber.
 *
 *  @param[in]     FamilySpecificServices    The current Family Specific Services.
 *  @param[out]    MaxPStateNumber             Boolean flag return pstate enable.
 *  @param[in]     StdHeader              Handle of Header for calling lib functions and services.
 *
 *  @retval      AGESA_SUCCESS Always succeeds.
 */
AGESA_STATUS
F10GetPstateMaxState (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
     OUT   UINT32              *MaxPStateNumber,
  IN       AMD_CONFIG_PARAMS   *StdHeader
  )
{
  UINT64              MsrValue;

  //
  // Read PstateMaxVal [6:4] from MSR C001_0061
  // So, we will know the max pstate state in this socket.
  //
  LibAmdMsrRead (MSR_PSTATE_CURRENT_LIMIT, &MsrValue, StdHeader);
  *MaxPStateNumber = (UINT32) (((PSTATE_CURLIM_MSR *) & MsrValue)->PstateMaxVal);

  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 *  Get CPU Specific Platform Type Info.
 *
 *  @CpuServiceMethod{::F_CPU_GET_PLATFORM_TYPE_SPECIFIC_INFO}.
 *
 *    This function returns Returns the platform features.
 *
 *  @param[in]     FamilySpecificServices         The current Family Specific Services.
 *  @param[in,out] Features                       The Features supported by this platform.
 *  @param[in]     StdHeader                      Handle of Header for calling lib functions and services.
 *
 *  @retval      AGESA_SUCCESS Always succeeds.
 */
AGESA_STATUS
F10GetPlatformTypeSpecificInfo (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN OUT   PLATFORM_FEATS         *Features,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  )
{
  return (AGESA_SUCCESS);
}

/*---------------------------------------------------------------------------------------*/
/**
 * Provide the features of the given HT link.
 *
 *  @CpuServiceMethod{::F_GET_HT_LINK_FEATURES}.
 *
 * This method is different than the HT Phy Features method, because for the phy registers
 * sublink 1 matches and should be programmed if the link is ganged but for PCI config
 * registers sublink 1 is reserved if the link is ganged.
 *
 * @param[in]     FamilySpecificServices    The current Family Specific Services.
 * @param[out]    Link                      The link number, for accessing non-capability set registers.
 * @param[in]     LinkBase                  The base HT Host capability PCI address for the link.
 * @param[out]    HtHostFeats               The link's features.
 * @param[in]     StdHeader                 Standard Head Pointer
 */
VOID
F10GetHtLinkFeatures (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
     OUT   UINTN                  *Link,
  IN       PCI_ADDR               *LinkBase,
     OUT   HT_HOST_FEATS          *HtHostFeats,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  )
{
  PCI_ADDR  PciAddress;
  UINT32    RegValue;
  UINT32    ExtendedFreq;
  UINTN     LinkOffset;

  ASSERT (FamilySpecificServices != NULL);

  // No features present unless link is good and connected.
  HtHostFeats->HtHostValue = 0;

  // Compute link number
  *Link = (((LinkBase->Address.Function == 4) ? 4 : 0) + ((LinkBase->Address.Register - 0x80) >> 5));

  // Check coherency (HTHOST_LINK_TYPE_REG = 0x18)
  PciAddress = *LinkBase;
  PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_TYPE_REG_OFFSET;
  LibAmdPciReadBits (PciAddress, 4, 0, &RegValue, StdHeader);
  if (RegValue  == 3) {
    HtHostFeats->HtHostFeatures.Coherent = 1;
  } else if (RegValue == 7) {
    HtHostFeats->HtHostFeatures.NonCoherent = 1;
  }

  // If link was not connected, don't check other attributes, make sure
  // to return zero, no match.
  if ((HtHostFeats->HtHostFeatures.Coherent == 1) || (HtHostFeats->HtHostFeatures.NonCoherent == 1)) {
    // Check gen3
    PciAddress = *LinkBase;
    PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_EXTENDED_FREQ;
    LibAmdPciRead (AccessWidth32, PciAddress, &ExtendedFreq, StdHeader);
    PciAddress = *LinkBase;
    PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_FREQ_OFFSET;
    LibAmdPciRead (AccessWidth32, PciAddress, &RegValue, StdHeader);
    RegValue = (((ExtendedFreq & 0x1) << 4) | ((RegValue & 0x00000F00) >> 8));
    if (RegValue > 6) {
      HtHostFeats->HtHostFeatures.Ht3 = 1;
    } else {
      HtHostFeats->HtHostFeatures.Ht1 = 1;
    }
    // Check ganged.
    LinkOffset = (*Link) * 4;
    PciAddress = *LinkBase;
    PciAddress.Address.Function = 0;
    PciAddress.Address.Register = ((UINT32)LinkOffset + 0x170);
    LibAmdPciReadBits (PciAddress, 0, 0, &RegValue, StdHeader);
    if (RegValue == 0) {
      HtHostFeats->HtHostFeatures.UnGanged = 1;
    } else {
      HtHostFeats->HtHostFeatures.Ganged = 1;
    }
  }
}

/*---------------------------------------------------------------------------------------*/
/**
 * Checks to see if the HT phy register table entry should be applied
 *
 * @CpuServiceMethod{::F_DOES_LINK_HAVE_HTFPY_FEATS}.
 *
 * This function determines if the link type field matches the HT link
 * passed in.
 *
 * This method will match for sublink 1 if the link is ganged and sublink 0 matches.
 *
 * @param[in]     FamilySpecificServices    The current Family Specific Services.
 * @param[in]     CapabilitySet    Address of the HT capability block
 * @param[in]     Link             Zero based HT link to check
 * @param[in]     HtPhyLinkType    Link type field from a register table entry to compare against
 * @param[out]    MatchedSublink1  TRUE: It is actually just sublink 1 that matches, FALSE: any other condition.
 * @param[out]    Frequency0       The frequency of sublink0 (200 MHz if not connected).
 * @param[out]    Frequency1       The frequency of sublink1 (200 MHz if not connected).
 * @param[in]     StdHeader        Standard Head Pointer
 *
 * @retval        TRUE             Link matches
 * @retval        FALSE            Link does not match
 *
 */
BOOLEAN
F10DoesLinkHaveHtPhyFeats (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       PCI_ADDR           CapabilitySet,
  IN       UINT32             Link,
  IN       HT_PHY_LINK_FEATS  *HtPhyLinkType,
     OUT   BOOLEAN            *MatchedSublink1,
     OUT   HT_FREQUENCIES     *Frequency0,
     OUT   HT_FREQUENCIES     *Frequency1,
  IN       AMD_CONFIG_PARAMS  *StdHeader
  )
{
  UINT32    RegValue;
  UINT32    ExtendedFreq;
  PCI_ADDR  PciAddress;
  PCI_ADDR  SubLink1Address;
  HT_PHY_LINK_FEATS LinkType;
  BOOLEAN   IsReallyCheckingBoth;

  ASSERT (Link < 4);
  ASSERT (HtPhyLinkType != NULL);
  // error checks: No unknown link type bits set and not a "match none"
  ASSERT ((HtPhyLinkType->HtPhyLinkValue & ~(HTPHY_LINKTYPE_ALL)) == 0);
  ASSERT (HtPhyLinkType->HtPhyLinkValue != 0);

  *Frequency0 = 0;
  *Frequency1 = 0;
  IsReallyCheckingBoth = FALSE;
  *MatchedSublink1 = FALSE;
  LinkType.HtPhyLinkValue = 0;

  // Set the link indicators.  This assumes each sublink set is contiguous, that is, links 3, 2, 1, 0 and 7, 6, 5, 4.
  LinkType.HtPhyLinkValue |= (HTPHY_LINKTYPE_SL0_LINK0 << Link);
  LinkType.HtPhyLinkValue |= (HTPHY_LINKTYPE_SL1_LINK4 << Link);

  // if ganged, don't read sublink 1, but use sublink 0 to check.
  SubLink1Address = CapabilitySet;

  // Check ganged. Since we got called for sublink 0, sublink 1 is implemented also,
  // but only access it if it is also unganged.
  Link *= 4;
  PciAddress = CapabilitySet;
  PciAddress.Address.Function = 0;
  PciAddress.Address.Register = (Link + 0x170);
  LibAmdPciRead (AccessWidth32, PciAddress, &RegValue, StdHeader);
  RegValue = (RegValue & 0x01);
  if (RegValue == 0) {
    // Then really read sublink1, rather than using sublink0
    SubLink1Address.Address.Function = 4;
    IsReallyCheckingBoth = TRUE;
  }

  // Checks for Sublink 0

  // Check coherency (HTHOST_LINK_TYPE_REG = 0x18)
  PciAddress = CapabilitySet;
  PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_TYPE_REG_OFFSET;
  LibAmdPciRead (AccessWidth32, PciAddress, &RegValue, StdHeader);
  if ((RegValue & 0x1F) == 3) {
    LinkType.HtPhyLinkFeatures.HtPhySL0Coh = 1;
  } else if ((RegValue & 0x1F) == 7) {
    LinkType.HtPhyLinkFeatures.HtPhySL0NonCoh = 1;
  }

  // If link was not connected, don't check other attributes, make sure
  // to return zero, no match. (Phy may be powered off.)
  if ((LinkType.HtPhyLinkFeatures.HtPhySL0Coh) || (LinkType.HtPhyLinkFeatures.HtPhySL0NonCoh)) {
    // Check gen3
    PciAddress = CapabilitySet;
    PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_EXTENDED_FREQ;
    LibAmdPciRead (AccessWidth32, PciAddress, &ExtendedFreq, StdHeader);
    PciAddress = CapabilitySet;
    PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_FREQ_OFFSET;
    LibAmdPciRead (AccessWidth32, PciAddress, &RegValue, StdHeader);
    RegValue = (((ExtendedFreq & 0x1) << 4) | ((RegValue & 0x00000F00) >> 8));
    *Frequency0 = RegValue;
    if (RegValue > 6) {
      LinkType.HtPhyLinkFeatures.HtPhySL0Ht3 = 1;
    } else {
      LinkType.HtPhyLinkFeatures.HtPhySL0Ht1 = 1;
    }
  } else {
    LinkType.HtPhyLinkValue &= ~(HTPHY_LINKTYPE_SL0_ALL);
  }

  // Checks for Sublink 1
  // Check coherency (HTHOST_LINK_TYPE_REG = 0x18)
  PciAddress = SubLink1Address;
  PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_TYPE_REG_OFFSET;
  LibAmdPciRead (AccessWidth32, PciAddress, &RegValue, StdHeader);
  if ((RegValue & 0x1F) == 3) {
    LinkType.HtPhyLinkFeatures.HtPhySL1Coh = 1;
  } else if ((RegValue & 0x1F) == 7) {
    LinkType.HtPhyLinkFeatures.HtPhySL1NonCoh = 1;
  }

  if ((LinkType.HtPhyLinkFeatures.HtPhySL1Coh) || (LinkType.HtPhyLinkFeatures.HtPhySL1NonCoh)) {
    // Check gen3
    PciAddress = SubLink1Address;
    PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_EXTENDED_FREQ;
    LibAmdPciRead (AccessWidth32, PciAddress, &ExtendedFreq, StdHeader);
    PciAddress = SubLink1Address;
    PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_FREQ_OFFSET;
    LibAmdPciRead (AccessWidth32, PciAddress, &RegValue, StdHeader);
    RegValue = (((ExtendedFreq & 0x1) << 4) | ((RegValue & 0x00000F00) >> 8));
    *Frequency1 = RegValue;
    if (RegValue > 6) {
      LinkType.HtPhyLinkFeatures.HtPhySL1Ht3 = 1;
    } else {
      LinkType.HtPhyLinkFeatures.HtPhySL1Ht1 = 1;
    }
  } else {
    LinkType.HtPhyLinkValue &= ~(HTPHY_LINKTYPE_SL1_ALL);
  }

  // For Deemphasis checking, indicate whether it was actually sublink 1 that matched.
  // If the link is ganged or only sublink 0 matched, or the link features didn't match, this is false.
  if ((LinkType.HtPhyLinkValue & HtPhyLinkType->HtPhyLinkValue) != 0) {
    if (IsReallyCheckingBoth &&
        (((LinkType.HtPhyLinkValue & HtPhyLinkType->HtPhyLinkValue) & (HTPHY_LINKTYPE_SL1_ALL)) != 0)) {
      *MatchedSublink1 = TRUE;
    }
    return TRUE;  // Link matches at least one of the desired characteristics
  } else {
    return FALSE; // Link does not match any criteria
  }
}

/*---------------------------------------------------------------------------------------*/
/**
 * Applies an HT Phy read-modify-write based on an HT Phy register table entry.
 *
 * @CpuServiceMethod{::F_SET_HT_PHY_REGISTER}.
 *
 * This function performs the necessary sequence of PCI reads, writes, and waits
 * necessary to program an HT Phy register.
 *
 * @param[in]  FamilySpecificServices    The current Family Specific Services.
 * @param[in]  HtPhyEntry    HT Phy register table entry to apply
 * @param[in]  CapabilitySet The link's HT Host base address.
 * @param[in]  Link          Zero based, node, link number (not package link).
 * @param[in]  StdHeader     Config handle for library and services
 *
 */
VOID
F10SetHtPhyRegister (
  IN       CPU_SPECIFIC_SERVICES  *FamilySpecificServices,
  IN       HT_PHY_TYPE_ENTRY_DATA  *HtPhyEntry,
  IN       PCI_ADDR                 CapabilitySet,
  IN       UINT32                   Link,
  IN       AMD_CONFIG_PARAMS       *StdHeader
  )
{
  UINT32    Temp;
  UINT32    PhyReg;
  PCI_ADDR  PhyBase;

  // Determine the PCI config address of the HT Phy portal
  PhyBase = CapabilitySet;
  PhyBase.Address.Function = FUNC_4;
  PhyBase.Address.Register = ((Link << 3) + REG_HT4_PHY_OFFSET_BASE_4X180);

  LibAmdPciRead (AccessWidth32, PhyBase, &PhyReg, StdHeader);

  // Handle direct map registers if needed
  PhyReg &= ~(HTPHY_DIRECT_OFFSET_MASK);
  if (HtPhyEntry->Address > 0x1FF) {
    PhyReg |= HTPHY_DIRECT_MAP;
  }

  PhyReg |= (HtPhyEntry->Address);
  // Ask the portal to read the HT Phy Register contents
  LibAmdPciWrite (AccessWidth32, PhyBase, &PhyReg, StdHeader);
  do
  {
    LibAmdPciRead (AccessWidth32, PhyBase, &Temp, StdHeader);
  } while (!(Temp & HTPHY_IS_COMPLETE_MASK));

  // Get the current register contents and do the update requested by the table
  PhyBase.AddressValue += 4;
  LibAmdPciRead (AccessWidth32, PhyBase, &Temp, StdHeader);
  Temp &= ~(HtPhyEntry->Mask);
  Temp |= (HtPhyEntry->Data);
  LibAmdPciWrite (AccessWidth32, PhyBase, &Temp, StdHeader);

  PhyBase.AddressValue -= 4;
  // Ask the portal to write our updated value to the HT Phy
  PhyReg |= HTPHY_WRITE_CMD;
  LibAmdPciWrite (AccessWidth32, PhyBase, &PhyReg, StdHeader);
  do
  {
    LibAmdPciRead (AccessWidth32, PhyBase, &Temp, StdHeader);
  } while (!(Temp & HTPHY_IS_COMPLETE_MASK));
}

/*---------------------------------------------------------------------------------------*/
/**
 * Set the HT Link Token Count registers (F3X1[54,50,4C,48]).
 *
 * @TableEntryTypeMethod{::HtTokenPciRegister}.
 *
 * Make the current core's PCI address with the function and register for the entry.
 * For all HT links, check the link's feature set for a match to the entry.
 * Read - Modify - Write the PCI register, clearing masked bits, and setting the data bits.
 *
 * @param[in]     Entry             The Link Token register entry to perform
 * @param[in]     PlatformConfig    Config handle for platform specific information
 * @param[in]     StdHeader         Config handle for library and services.
 *
 */
VOID
F10SetRegisterForHtLinkTokenEntry (
  IN       TABLE_ENTRY_DATA       *Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  )
{
  UINTN                 Link;
  UINTN                 LinkCount;
  UINT32                MySocket;
  UINT32                MyModule;
  AGESA_STATUS          IgnoredStatus;
  UINT32                Ignored;
  CPU_LOGICAL_ID        CpuFamilyRevision;
  CPU_SPECIFIC_SERVICES *FamilySpecificServices;
  PCI_ADDR              CapabilitySet;
  HT_HOST_FEATS         HtHostFeats;
  PERFORMANCE_PROFILE_FEATS PlatformProfile;
  UINTN                 ProcessorCount;
  UINT32                RegisterData;
  PCI_ADDR              PciAddress;

  // Errors:  Possible values in unused entry space, extra type features, value range checks.
  // Check that the entry type is correct and the actual supplied entry data is appropriate for that entry.
  ASSERT (((Entry->HtTokenEntry.LinkFeats.HtHostValue & ~((HT_HOST_FEATURES_ALL) | (HT_HOST_AND))) == 0) &&
          ((Entry->HtTokenEntry.PerformanceFeats.PerformanceProfileValue & ~((PERFORMANCE_PROFILE_ALL) | (PERFORMANCE_AND))) == 0) &&
          (Entry->HtTokenEntry.Mask != 0));

  HtHostFeats.HtHostValue = 0;
  IdentifyCore (StdHeader, &MySocket, &MyModule, &Ignored, &IgnoredStatus);
  GetPciAddress (StdHeader, MySocket, MyModule, &CapabilitySet, &IgnoredStatus);
  GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
  GetCpuServicesFromLogicalId (&CpuFamilyRevision, &FamilySpecificServices, StdHeader);

  // Check if the actual processor count is in either range.
  ProcessorCount = GetNumberOfProcessors (StdHeader);
  if (IsEitherCountInRange (ProcessorCount, ProcessorCount, Entry->HtTokenEntry.ProcessorCounts.ProcessorCountRanges)) {
    // Check for any performance profile features.
    GetPerformanceFeatures (&PlatformProfile, PlatformConfig, StdHeader);
    if (DoesEntryTypeSpecificInfoMatch (PlatformProfile.PerformanceProfileValue,
                                        Entry->HtTokenEntry.PerformanceFeats.PerformanceProfileValue)) {
      // Check the link features.
      LinkCount = 0;
      while (LinkCount < 4) {
        if (FindHtHostCapability (LinkCount, &CapabilitySet, StdHeader)) {
          FamilySpecificServices->GetHtLinkFeatures (FamilySpecificServices, &Link, &CapabilitySet, &HtHostFeats, StdHeader);
          if (DoesEntryTypeSpecificInfoMatch (HtHostFeats.HtHostValue, Entry->HtTokenEntry.LinkFeats.HtHostValue)) {
            // Do the HT Host PCI register update.
            PciAddress = CapabilitySet;
            PciAddress.Address.Function = 3;
            PciAddress.Address.Register = LINK_TO_XCS_TOKEN_COUNT_REG_3X148 + ((UINT32)Link * 4);
            LibAmdPciRead (AccessWidth32, PciAddress, &RegisterData, StdHeader);
            RegisterData = RegisterData & (~(Entry->HtTokenEntry.Mask));
            RegisterData = RegisterData | Entry->HtTokenEntry.Data;
            LibAmdPciWrite (AccessWidth32, PciAddress, &RegisterData, StdHeader);
          }
        } else {
          // No more Capabilities.
          break;
        }
        LinkCount ++;
      }
    }
  }
}

