blob: c319a817de69d3de058c800fdb1a06a75e727fd2 [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* AMD Family_15 specific utility functions.
*
* Provides numerous utility functions specific to family 15h.
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: CPU/Family/0x15
* @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
*
*/
/*
******************************************************************************
*
* Copyright 2008 - 2012 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
*
* AMD is granting you permission to use this software (the Materials)
* pursuant to the terms and conditions of your Software License Agreement
* with AMD. This header does *NOT* give you permission to use the Materials
* or any rights under AMD's intellectual property. Your use of any portion
* of these Materials shall constitute your acceptance of those terms and
* conditions. If you do not agree to the terms and conditions of the Software
* License Agreement, please do not use any portion of these Materials.
*
* CONFIDENTIALITY: The Materials and all other information, identified as
* confidential and provided to you by AMD shall be kept confidential in
* accordance with the terms and conditions of the Software License Agreement.
*
* LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION
* PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE,
* OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE.
* IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER
* (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS
* INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE,
* GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER
* RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE
* EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES,
* THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
*
* AMD does not assume any responsibility for any errors which may appear in
* the Materials or any other related information provided to you by AMD, or
* result from use of the Materials or any related information.
*
* You agree that you will not reverse engineer or decompile the Materials.
*
* NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any
* further information, software, technical information, know-how, or show-how
* available to you. Additionally, AMD retains the right to modify the
* Materials at any time, without notice, and is not obligated to provide such
* modified Materials to you.
*
* U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with
* "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is
* subject to the restrictions as set forth in FAR 52.227-14 and
* DFAR252.227-7013, et seq., or its successor. Use of the Materials by the
* Government constitutes acknowledgement of AMD's proprietary rights in them.
*
* EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any
* direct product thereof will be exported directly or indirectly, into any
* country prohibited by the United States Export Administration Act and the
* regulations thereunder, without the required authorization from the U.S.
* government nor will be used for any purpose prohibited by the same.
******************************************************************************
*/
/*----------------------------------------------------------------------------------------
* 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 "cpuPstateTables.h"
#include "cpuF15PowerMgmt.h"
#include "cpuApicUtilities.h"
#include "cpuServices.h"
#include "GeneralServices.h"
#include "cpuF15Utilities.h"
#include "cpuEarlyInit.h"
#include "cpuPostInit.h"
#include "cpuFeatures.h"
#include "OptionMultiSocket.h"
#include "Filecode.h"
CODE_GROUP (G2_PEI)
RDATA_GROUP (G2_PEI)
#define FILECODE PROC_CPU_FAMILY_0X15_CPUF15UTILITIES_FILECODE
/*----------------------------------------------------------------------------------------
* D E F I N I T I O N S A N D M A C R O S
*----------------------------------------------------------------------------------------
*/
extern CPU_FAMILY_SUPPORT_TABLE PstateFamilyServiceTable;
extern OPTION_MULTISOCKET_CONFIGURATION OptionMultiSocketConfiguration;
// HT Phy registers used in code.
#define HT_PHY_FUSE_PROC_DLL_PROCESS_COMP_RD_SL0 0x4011
#define HT_PHY_FUSE_PROC_DLL_PROCESS_COMP_RD_SL1 0x4411
#define HT_PHY_LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_RD 0x400F
#define HT_PHY_LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_SL0 0x520F
#define HT_PHY_LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_SL1 0x530F
/*----------------------------------------------------------------------------------------
* T Y P E D E F S A N D S T R U C T U R E S
*----------------------------------------------------------------------------------------
*/
/**
* HT PHY DLL Process Compensation Lookup Table.
*
* If the hardware provides compensation values, the value is provided by accessing the bitfield
* [HiBit:LoBit]. Otherwise, a default value will be used.
*
*/
typedef struct {
UINT32 DefaultComp; ///< The default compensation value if not provided by hardware.
UINT8 CtlIndexLoBit; ///< The low bit position of the compensation value.
UINT8 CtlIndexHiBit; ///< The high bit position of the compensation value.
} HT_PHY_DLL_COMP_LOOKUP_TABLE;
/**
* Process Compensation Fuses for HT PHY, Link Phy Receiver Process Fuse Control Register.
*/
typedef struct {
UINT32 :11;
UINT32 DllProcessComp10:2; ///< [12:11] DLL Process Comp bits [1:0], this phy's adjustment.
UINT32 DllProcessComp2:1; ///< [13] DLL Process Comp bit 2, Increment or Decrement.
UINT32 : (31 - 13);
} LINK_PHY_RECEIVER_PROCESS_FUSE_CONTROL_FIELDS;
/// Access register as fields or uint32 value.
typedef union {
UINT32 Value; ///< 32 bit value for register access
LINK_PHY_RECEIVER_PROCESS_FUSE_CONTROL_FIELDS Fields; ///< The register bit fields
} LINK_PHY_RECEIVER_PROCESS_FUSE_CONTROL;
/**
* Link Phy Receiver Process DLL Control Register.
*/
typedef struct {
UINT32 DllProcessFreqCtlIndex2:4; ///< [3:0] The DLL Compensation override.
UINT32 : (12 - 4);
UINT32 DllProcessFreqCtlOverride:1; ///< [12] Enable DLL Compensation overriding.
UINT32 : (31 - 12);
} LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_FIELDS;
/// Access register as fields or uint32 value.
typedef union {
UINT32 Value; ///< 32 bit value for register access
LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_FIELDS Fields; ///< The register bit fields
} LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL;
/**
* Provide the HT PHY DLL compensation value for each HT Link frequency.
*
* The HT Frequency enum is not contiguous, there are skipped values. Rather than complicate
* index calculations, add Invalid entries here marked with an invalid compensation value (invalid
* because real compensation values are 0 .. 15).
*/
CONST STATIC HT_PHY_DLL_COMP_LOOKUP_TABLE ROMDATA HtPhyDllCompLookupTable[] = {
{0xAul, 0, 3}, // HT_FREQUENCY_1200M
{0xAul, 0, 3}, // HT_FREQUENCY_1400M
{0x7ul, 4, 7}, // HT_FREQUENCY_1600M
{0x7ul, 4, 7}, // HT_FREQUENCY_1800M
{0x5ul, 8, 11}, // HT_FREQUENCY_2000M
{0x5ul, 8, 11}, // HT_FREQUENCY_2200M
{0x4ul, 12, 15}, // HT_FREQUENCY_2400M
{0x3ul, 16, 19}, // HT_FREQUENCY_2600M
{0xFFFFFFFFul, 0, 0}, // Invalid
{0xFFFFFFFFul, 0, 0}, // Invalid
{0x3ul, 20, 23}, // HT_FREQUENCY_2800M
{0x2ul, 24, 27}, // HT_FREQUENCY_3000M
{0x2ul, 28, 31} // HT_FREQUENCY_3200M
};
/*----------------------------------------------------------------------------------------
* 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
*----------------------------------------------------------------------------------------
*/
/*---------------------------------------------------------------------------------------*/
/**
* 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
F15DisablePstate (
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN UINT8 StateNumber,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT64 LocalMsrRegister;
ASSERT (StateNumber < NM_PS_REG);
LibAmdMsrRead (PS_REG_BASE + (UINT32) StateNumber, &LocalMsrRegister, StdHeader);
((F15_PSTATE_MSR *) &LocalMsrRegister)->PsEnable = 0;
LibAmdMsrWrite (PS_REG_BASE + (UINT32) StateNumber, &LocalMsrRegister, 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
F15TransitionPstate (
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN UINT8 StateNumber,
IN BOOLEAN WaitForTransition,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT64 LocalMsrRegister;
LibAmdMsrRead (MSR_PSTATE_CURRENT_LIMIT, &LocalMsrRegister, StdHeader);
ASSERT (((PSTATE_CURLIM_MSR *) &LocalMsrRegister)->PstateMaxVal >= StateNumber);
LibAmdMsrRead (MSR_PSTATE_CTL, &LocalMsrRegister, StdHeader);
((PSTATE_CTRL_MSR *) &LocalMsrRegister)->PstateCmd = (UINT64) StateNumber;
LibAmdMsrWrite (MSR_PSTATE_CTL, &LocalMsrRegister, StdHeader);
if (WaitForTransition) {
do {
LibAmdMsrRead (MSR_PSTATE_STS, &LocalMsrRegister, StdHeader);
} while (((PSTATE_STS_MSR *) &LocalMsrRegister)->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
F15GetTscRate (
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
OUT UINT32 *FrequencyInMHz,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT8 NumBoostStates;
UINT32 LocalPciRegister;
UINT64 LocalMsrRegister;
PCI_ADDR PciAddress;
PSTATE_CPU_FAMILY_SERVICES *FamilyServices;
LibAmdMsrRead (0xC0010015, &LocalMsrRegister, StdHeader);
if ((LocalMsrRegister & 0x01000000) != 0) {
FamilyServices = NULL;
GetFeatureServicesOfCurrentCore (&PstateFamilyServiceTable, (CONST VOID **)&FamilyServices, StdHeader);
ASSERT (FamilyServices != NULL);
OptionMultiSocketConfiguration.GetCurrPciAddr (&PciAddress, StdHeader);
PciAddress.Address.Function = FUNC_4;
PciAddress.Address.Register = CPB_CTRL_REG;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
NumBoostStates = (UINT8) ((F15_CPB_CTRL_REGISTER *) &LocalPciRegister)->NumBoostStates;
return (FamilyServices->GetPstateFrequency (FamilyServices, NumBoostStates, FrequencyInMHz, StdHeader));
} else {
return (FamilySpecificServices->GetCurrentNbFrequency (FamilySpecificServices, FrequencyInMHz, StdHeader));
}
}
/*---------------------------------------------------------------------------------------*/
/**
* 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
F15LaunchApCore (
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 LocalPciRegister;
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, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & HT_INIT_CTRL_REQ_DIS) != 0) {
LocalPciRegister &= ~HT_INIT_CTRL_REQ_DIS;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 1:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE1_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE1_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 2:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE2_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE2_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister,
StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 3:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE3_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE3_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 4:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE4_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE4_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 5:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE5_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE5_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 6:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE6_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE6_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 7:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE7_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE7_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 8:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE8_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE8_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
case 9:
PciAddress.Address.Register = CORE_CTRL;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((LocalPciRegister & CORE_CTRL_CORE9_EN) == 0) {
LocalPciRegister |= CORE_CTRL_CORE9_EN;
LibAmdPciWrite (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
LaunchFlag = TRUE;
} else {
LaunchFlag = FALSE;
}
break;
default:
break;
}
return (LaunchFlag);
}
/*---------------------------------------------------------------------------------------*/
/**
* Provide the features of the next HT link.
*
* @CpuServiceMethod{::F_GET_NEXT_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[in,out] Link Initially zero, each call returns the link number;
* caller passes it back unmodified each call.
* @param[in,out] LinkBase Initially the PCI bus, device, function=0, offset=0;
* Each call returns the HT Host Capability function and offset;
* Caller may use it to access registers, but must @b not modify it;
* Each new call passes the previous value as input.
* @param[out] HtHostFeats The link's features.
* @param[in] StdHeader Standard Head Pointer
*
* @retval TRUE Valid link and features found.
* @retval FALSE No more links.
*/
BOOLEAN
F15GetNextHtLinkFeatures (
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN OUT UINTN *Link,
IN OUT PCI_ADDR *LinkBase,
OUT HT_HOST_FEATS *HtHostFeats,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
PCI_ADDR PciAddress;
UINT32 RegValue;
UINT32 ExtendedFreq;
UINTN LinkOffset;
BOOLEAN Result;
ASSERT (FamilySpecificServices != NULL);
// No features present unless link is good and connected.
HtHostFeats->HtHostValue = 0;
Result = TRUE;
// Find next link.
if (LinkBase->Address.Register == 0) {
// Beginning iteration now.
LinkBase->Address.Register = HT_CAPABILITIES_POINTER;
LibAmdPciReadBits (*LinkBase, 7, 0, &RegValue, StdHeader);
} else {
// Get next link offset.
LibAmdPciReadBits (*LinkBase, 15, 8, &RegValue, StdHeader);
}
if (RegValue == 0) {
// Are we at the end? Check if we can move to another function.
if (LinkBase->Address.Function == 0) {
LinkBase->Address.Function = 4;
LinkBase->Address.Register = HT_CAPABILITIES_POINTER;
LibAmdPciReadBits (*LinkBase, 7, 0, &RegValue, StdHeader);
}
}
if (RegValue != 0) {
// Not at end, process the found link.
LinkBase->Address.Register = RegValue;
// Compute link number
*Link = (((LinkBase->Address.Function == 4) ? 4 : 0) + ((LinkBase->Address.Register - 0x80) >> 5));
// Handle pending link power off, check End of Chain, Xmit Off.
PciAddress = *LinkBase;
PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_CONTROL_REG_OFFSET;
LibAmdPciReadBits (PciAddress, 7, 6, &RegValue, StdHeader);
if (RegValue == 0) {
// 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. Must check the bit for sublink 0.
LinkOffset = (*Link > 3) ? ((*Link - 4) * 4) : (*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 {
if (*Link < 4) {
HtHostFeats->HtHostFeatures.Ganged = 1;
} else {
// If this is a sublink 1 but it will be ganged, clear all features.
HtHostFeats->HtHostValue = 0;
}
}
}
} else {
// end of links.
Result = FALSE;
}
return Result;
}
/*---------------------------------------------------------------------------------------*/
/**
* Checks to see if the HT phy register table entry should be applied
*
* @CpuServiceMethod{::F_NEXT_LINK_HAS_HTFPY_FEATS}.
*
* Find the next link which matches, if any.
* 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,out] HtHostCapability Initially the PCI bus, device, function=0, offset=0;
* Each call returns the HT Host Capability function and offset;
* Caller may use it to access registers, but must @b not modify it;
* Each new call passes the previous value as input.
* @param[in,out] Link Initially zero, each call returns the link number; caller passes it back unmodified each call.
* @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 No more links
*
*/
BOOLEAN
F15NextLinkHasHtPhyFeats (
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN OUT PCI_ADDR *HtHostCapability,
IN OUT 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;
UINT32 InternalLinks;
UINT32 Width;
PCI_ADDR PciAddress;
PCI_ADDR SubLink1Address;
HT_PHY_LINK_FEATS LinkType;
BOOLEAN IsReallyCheckingBoth;
BOOLEAN IsFound;
BOOLEAN Result;
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 | HTPHY_LINKTYPE_SL0_AND | HTPHY_LINKTYPE_SL1_AND)) == 0);
ASSERT (HtPhyLinkType->HtPhyLinkValue != 0);
Result = FALSE;
IsFound = FALSE;
while (!IsFound) {
*Frequency0 = 0;
*Frequency1 = 0;
IsReallyCheckingBoth = FALSE;
*MatchedSublink1 = FALSE;
LinkType.HtPhyLinkValue = 0;
// Find next link.
PciAddress = *HtHostCapability;
if (PciAddress.Address.Register == 0) {
// Beginning iteration now.
PciAddress.Address.Register = HT_CAPABILITIES_POINTER;
LibAmdPciReadBits (PciAddress, 7, 0, &RegValue, StdHeader);
} else {
// Get next link offset.
LibAmdPciReadBits (PciAddress, 15, 8, &RegValue, StdHeader);
}
if (RegValue != 0) {
HtHostCapability->Address.Register = RegValue;
// Compute link number of this sublink pair (so we don't need to account for function).
*Link = ((HtHostCapability->Address.Register - 0x80) >> 5);
// 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);
// Read IntLnkRoute from the Link Initialization Status register.
PciAddress = *HtHostCapability;
PciAddress.Address.Function = 0;
PciAddress.Address.Register = 0x1A0;
LibAmdPciReadBits (PciAddress, 23, 16, &InternalLinks, StdHeader);
// if ganged, don't read sublink 1, but use sublink 0 to check.
SubLink1Address = *HtHostCapability;
// Check ganged. Since we got called for sublink 0, sublink 1 is implemented also,
// but only access it if it is also unganged.
PciAddress = *HtHostCapability;
PciAddress.Address.Function = 0;
PciAddress.Address.Register = ((*Link * 4) + 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
// Handle pending link power off, check End of Chain, Xmit Off.
PciAddress = *HtHostCapability;
PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_CONTROL_REG_OFFSET;
LibAmdPciReadBits (PciAddress, 7, 6, &RegValue, StdHeader);
if (RegValue == 0) {
// Check coherency (HTHOST_LINK_TYPE_REG = 0x18)
PciAddress = *HtHostCapability;
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 = *HtHostCapability;
PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_EXTENDED_FREQ;
LibAmdPciRead (AccessWidth32, PciAddress, &ExtendedFreq, StdHeader);
PciAddress = *HtHostCapability;
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;
}
// Check internal / external
if ((InternalLinks & (1 << *Link)) == 0) {
// External
LinkType.HtPhyLinkFeatures.HtPhySL0External = 1;
} else {
// Internal
LinkType.HtPhyLinkFeatures.HtPhySL0Internal = 1;
}
} else {
LinkType.HtPhyLinkValue &= ~(HTPHY_LINKTYPE_SL0_ALL);
}
// Checks for Sublink 1
// Handle pending link power off, check End of Chain, Xmit Off.
// Also, if the links are ganged but the width is not 16 bits, treat it is an inactive lane.
PciAddress = SubLink1Address;
PciAddress.Address.Register = PciAddress.Address.Register + HT_LINK_CONTROL_REG_OFFSET;
LibAmdPciReadBits (PciAddress, 7, 6, &RegValue, StdHeader);
LibAmdPciReadBits (PciAddress, 31, 24, &Width, StdHeader);
if ((RegValue == 0) && (IsReallyCheckingBoth || (Width == 0x11))) {
// 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;
}
// Check internal / external. Note that we do really check sublink 1 regardless of ganging.
if ((InternalLinks & (1 << (*Link + 4))) == 0) {
// External
LinkType.HtPhyLinkFeatures.HtPhySL1External = 1;
} else {
// Internal
LinkType.HtPhyLinkFeatures.HtPhySL1Internal = 1;
}
} else {
LinkType.HtPhyLinkValue &= ~(HTPHY_LINKTYPE_SL1_ALL);
}
// Determine if the link matches the entry criteria.
// 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 (((HtPhyLinkType->HtPhyLinkValue & HTPHY_LINKTYPE_SL0_AND) == 0) &&
((HtPhyLinkType->HtPhyLinkValue & HTPHY_LINKTYPE_SL1_AND) == 0)) {
// Match if any feature matches (OR)
Result = (BOOLEAN) ((LinkType.HtPhyLinkValue & HtPhyLinkType->HtPhyLinkValue) != 0);
} else {
// Match if all features match (AND)
Result = (BOOLEAN) ((HtPhyLinkType->HtPhyLinkValue & ~(HTPHY_LINKTYPE_SL0_AND | HTPHY_LINKTYPE_SL1_AND)) ==
(LinkType.HtPhyLinkValue & HtPhyLinkType->HtPhyLinkValue));
}
if (Result) {
if (IsReallyCheckingBoth &&
(((LinkType.HtPhyLinkValue & HtPhyLinkType->HtPhyLinkValue) & (HTPHY_LINKTYPE_SL1_ALL)) != 0)) {
*MatchedSublink1 = TRUE;
}
IsFound = TRUE;
} else {
// Go to next link
}
} else {
// No more links
IsFound = TRUE;
}
}
return Result;
}
/*---------------------------------------------------------------------------------------*/
/**
* 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
F15SetHtPhyRegister (
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 > 0x3FF) || ((HtPhyEntry->Address >= 0xE) && (HtPhyEntry->Address <= 0x11))) {
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));
}
/*---------------------------------------------------------------------------------------*/
/**
* Applies an HT Phy write to a specified Phy register.
*
* @CpuServiceMethod{::F_SET_HT_PHY_REGISTER}.
*
* The caller is responsible for performing any read and modify steps.
* This function performs the necessary sequence of PCI reads, writes, and waits
* necessary to program an HT Phy register.
*
* @param[in] CapabilitySet The link's HT Host base address.
* @param[in] Link Zero based, node, link number (not package link).
* @param[in] Address The HT Phy register address
* @param[in] Data The data to write to the register
* @param[in] StdHeader Config handle for library and services
*
*/
VOID
STATIC
F15WriteOnlyHtPhyRegister (
IN PCI_ADDR CapabilitySet,
IN UINT32 Link,
IN UINT32 Address,
IN UINT32 Data,
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 ((Address > 0x3FF) || ((Address >= 0xE) && (Address <= 0x11))) {
PhyReg |= HTPHY_DIRECT_MAP;
}
PhyReg |= (Address);
// Get the current register contents and do the update requested by the table
PhyBase.AddressValue += 4;
LibAmdPciWrite (AccessWidth32, PhyBase, &Data, 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));
}
/*---------------------------------------------------------------------------------------*/
/**
* Get the value of an HT PHY register.
*
* Reading HT Phy registers is not generally useful, because they return the effective value,
* not the currently written value. So be warned, this function is dangerous if used to read
* a register that will be udpated subsequently elsewhere.
*
* This routine is useful for reading hardware status from the HT Phy that can be used to set
* other phy registers.
*
* @param[in] CapabilitySet The link's HT Host base address.
* @param[in] Link Zero based, node link number (not package link).
* @param[in] Address The HT Phy register address to read
* @param[in] StdHeader Config handle for library and services
*
* @return The register content (in most cases, the effective content not the pending content)
*
*/
UINT32
STATIC
F15GetHtPhyRegister (
IN PCI_ADDR CapabilitySet,
IN UINT32 Link,
IN UINT32 Address,
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 ((Address > 0x3FF) || ((Address >= 0xE) && (Address <= 0x11))) {
PhyReg |= HTPHY_DIRECT_MAP;
}
PhyReg |= 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
PhyBase.AddressValue += 4;
LibAmdPciRead (AccessWidth32, PhyBase, &Temp, StdHeader);
return Temp;
}
/*---------------------------------------------------------------------------------------*/
/**
* A Family Specific Workaround method, to override HT DLL Compensation.
*
* \@TableTypeFamSpecificInstances.
*
* The Link Product Information register can be fused to contain an HT PHY DLL Compensation Override table.
* Based on link frequency, a compensation override can be selected from the value.
* To accomodate individual link differences in the package, each link can also have a DLL process compensation
* value set. This value can apply an adjustment to the compensation value.
*
* @param[in] Data The table data value, for example to indicate which CPU and Platform types matched.
* @param[in] StdHeader Config params for library, services.
*/
VOID
F15HtPhyOverrideDllCompensation (
IN UINT32 Data,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 ProductLinkInfo;
UINT32 Link;
CPU_LOGICAL_ID CpuFamilyRevision;
PCI_ADDR StartingCapabilitySet;
PCI_ADDR CapabilitySet;
PCI_ADDR PciAddress;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
BOOLEAN MatchedSublink1;
HT_FREQUENCIES Freq0;
HT_FREQUENCIES Freq1;
UINTN Sublink;
HT_PHY_LINK_FEATS DesiredLinkFeats;
BOOLEAN IsEarlyRevProcessor;
BOOLEAN IsHardwareReportingComp;
UINTN LinkFrequency;
UINT32 Compensation;
UINT32 Adjustment;
BOOLEAN IsIncrementAdjust;
LINK_PHY_RECEIVER_PROCESS_FUSE_CONTROL LinkPhyReceiverProcessFuseControl;
LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL LinkPhyReceiverProcessDllControl;
OptionMultiSocketConfiguration.GetCurrPciAddr (&StartingCapabilitySet, StdHeader);
GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
GetCpuServicesFromLogicalId (&CpuFamilyRevision, (CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
// Check if the hardware reported any compensation values.
IsEarlyRevProcessor = (BOOLEAN) ((Data == 0) ? TRUE : FALSE);
PciAddress = StartingCapabilitySet;
PciAddress.Address.Function = FUNC_5;
PciAddress.Address.Register = 0x190;
LibAmdPciRead (AccessWidth32, PciAddress, &ProductLinkInfo, StdHeader);
IsHardwareReportingComp = (BOOLEAN) (ProductLinkInfo != 0);
if (!IsEarlyRevProcessor || IsHardwareReportingComp) {
// Process all the sublink 0's and then all the sublink 1's that are at HT3 frequency.
for (Sublink = 0; Sublink < 2; Sublink++) {
CapabilitySet = StartingCapabilitySet;
Link = 0;
DesiredLinkFeats.HtPhyLinkValue = ((Sublink == 0) ? HTPHY_LINKTYPE_SL0_HT3 : HTPHY_LINKTYPE_SL0_HT3);
while (FamilySpecificServices->NextLinkHasHtPhyFeats (
FamilySpecificServices,
&CapabilitySet,
&Link,
&DesiredLinkFeats,
&MatchedSublink1,
&Freq0,
&Freq1,
StdHeader)) {
// Look up compensation value. Remember that we matched links which are at HT3 frequency, so Freq[1,0]
// should safely be greater than or equal to 1.2 GHz.
if (Sublink == 0) {
LinkFrequency = Freq0 - HT_FREQUENCY_1200M;
} else {
LinkFrequency = (MatchedSublink1 ? Freq1 : Freq0) - HT_FREQUENCY_1200M;
}
// This assert would catch frequencies higher than we know how to support, or any table overrun bug.
ASSERT (LinkFrequency < (sizeof (HtPhyDllCompLookupTable) / sizeof (HT_PHY_DLL_COMP_LOOKUP_TABLE)));
// Since there are invalid entries in the table, for frequency enum skipped values, ensure we did not
// pick one of those entries. This should be impossible from real hardware.
ASSERT (HtPhyDllCompLookupTable[LinkFrequency].DefaultComp != 0xFFFFFFFFul);
if (IsHardwareReportingComp) {
LibAmdPciReadBits (
PciAddress,
HtPhyDllCompLookupTable[LinkFrequency].CtlIndexHiBit,
HtPhyDllCompLookupTable[LinkFrequency].CtlIndexLoBit,
&Compensation,
StdHeader);
} else {
Compensation = HtPhyDllCompLookupTable[LinkFrequency].DefaultComp;
}
// Apply any per PHY adjustment
LinkPhyReceiverProcessFuseControl.Value = F15GetHtPhyRegister (
CapabilitySet,
Link,
((Sublink == 0) ? HT_PHY_FUSE_PROC_DLL_PROCESS_COMP_RD_SL0 : HT_PHY_FUSE_PROC_DLL_PROCESS_COMP_RD_SL1),
StdHeader);
Adjustment = LinkPhyReceiverProcessFuseControl.Fields.DllProcessComp10;
IsIncrementAdjust = (BOOLEAN) ((LinkPhyReceiverProcessFuseControl.Fields.DllProcessComp2 == 0) ? TRUE : FALSE);
if (IsIncrementAdjust) {
Compensation = (((Compensation + Adjustment) > 0x000F) ? 0x000F : (Compensation + Adjustment));
} else {
// decrement adjustment
Compensation = ((Compensation < Adjustment) ? 0 : (Compensation - Adjustment));
}
// Update the DLL Compensation
LinkPhyReceiverProcessDllControl.Value = F15GetHtPhyRegister (
CapabilitySet,
Link,
HT_PHY_LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_RD,
StdHeader);
LinkPhyReceiverProcessDllControl.Fields.DllProcessFreqCtlOverride = 1;
LinkPhyReceiverProcessDllControl.Fields.DllProcessFreqCtlIndex2 = Compensation;
F15WriteOnlyHtPhyRegister (
CapabilitySet,
Link,
((Sublink == 0) ? HT_PHY_LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_SL0 : HT_PHY_LINK_PHY_RECEIVER_PROCESS_DLL_CONTROL_SL1),
LinkPhyReceiverProcessDllControl.Value,
StdHeader);
}
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Returns whether or not BIOS is responsible for configuring the NB COFVID.
*
* @CpuServiceMethod{::F_CPU_IS_NBCOF_INIT_NEEDED}.
*
* @param[in] FamilySpecificServices The current Family Specific Services.
* @param[in] PciAddress The northbridge to query by pci base address.
* @param[out] NbVidUpdateAll Do all NbVids need to be updated
* @param[in] StdHeader Header for library and services
*
* @retval TRUE Perform northbridge frequency and voltage config.
* @retval FALSE Do not configure them.
*/
BOOLEAN
F15CommonGetNbCofVidUpdate (
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN PCI_ADDR *PciAddress,
OUT BOOLEAN *NbVidUpdateAll,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
*NbVidUpdateAll = FALSE;
return FALSE;
}
/*---------------------------------------------------------------------------------------*/
/**
* Is the Northbridge PState feature enabled?
*
* @CpuServiceMethod{::F_IS_NB_PSTATE_ENABLED}.
*
* @param[in] FamilySpecificServices The current Family Specific Services.
* @param[in] PlatformConfig Platform profile/build option config structure.
* @param[in] StdHeader Handle of Header for calling lib functions and services.
*
* @retval TRUE The NB PState feature is enabled.
* @retval FALSE The NB PState feature is not enabled.
*/
BOOLEAN
F15IsNbPstateEnabled (
IN CPU_SPECIFIC_SERVICES *FamilySpecificServices,
IN PLATFORM_CONFIGURATION *PlatformConfig,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 LocalPciRegister;
PCI_ADDR PciAddress;
BOOLEAN PowerMode;
BOOLEAN SkipHwCfg;
SkipHwCfg = FALSE;
IDS_OPTION_HOOK (IDS_NBPSDIS_OVERRIDE, &SkipHwCfg, StdHeader);
// Defaults to Power Optimized Mode
PowerMode = TRUE;
// If system is optimized for performance, disable NB P-States
if (PlatformConfig->PlatformProfile.PlatformPowerPolicy == Performance) {
PowerMode = FALSE;
}
PciAddress.AddressValue = F15_NB_PSTATE_CTRL_PCI_ADDR;
LibAmdPciRead (AccessWidth32, PciAddress, &LocalPciRegister, StdHeader);
if ((((((F15_NB_PSTATE_CTRL_REGISTER *) &LocalPciRegister)->NbPstateMaxVal != 0) &&
(!IsNonCoherentHt1 (StdHeader))) || SkipHwCfg) && (PowerMode)) {
return TRUE;
}
return FALSE;
}