blob: 0ae550789f148c9ffb64c9d3b2d70a76f9a3f33d [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* Fuse table initialization
*
*
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: GNB
* @e \$Revision: 48498 $ @e \$Date: 2011-03-09 12:44:53 -0700 (Wed, 09 Mar 2011) $
*
*/
/*
*****************************************************************************
*
* 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 "heapManager.h"
#include "Gnb.h"
#include "GnbFuseTable.h"
#include GNB_MODULE_DEFINITIONS (GnbCommonLib)
#include "GnbRegistersON.h"
#include "NbSmuLib.h"
#include "NbConfigData.h"
#include "NbFuseTable.h"
#include "NbFamilyServices.h"
#include "GfxLib.h"
#include "Filecode.h"
#define FILECODE PROC_GNB_NB_FEATURE_NBFUSETABLE_FILECODE
/*----------------------------------------------------------------------------------------
* D E F I N I T I O N S A N D M A C R O S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* 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
*----------------------------------------------------------------------------------------
*/
VOID
NbFuseLoadDefaultFuseTable (
OUT PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
);
VOID
NbFuseLoadFuseTableFromFcr (
OUT PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
);
VOID
NbFuseDebugDump (
IN PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
);
VOID
NbFuseAdjustFuseTableToCurrentMainPllVco (
IN OUT PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
);
PP_FUSE_ARRAY DefaultPpFuseArray = {
0, ///< PP table revision
{1, 0, 0, 0, 0, 0}, ///< Valid DPM states
{0x40, 0, 0, 0, 0}, ///< Sclk DPM DID
{0, 0, 0, 0, 0}, ///< Sclk DPM VID
{0, 0, 0, 0, 0}, ///< Sclk DPM Cac
{1, 0, 0, 0, 0, 0}, ///< State policy flags
{2, 0, 0, 0, 0, 0}, ///< State policy label
{0x40, 0, 0, 0}, ///< VCLK DID
{0x40, 0, 0, 0}, ///< DCLK DID
0, ///< Thermal SCLK
{0, 0, 0, 0, 0, 0}, ///< Vclk/Dclk selector
{0, 0, 0, 0}, ///< Valid Lclk DPM states
{0, 0, 0, 0}, ///< Lclk DPM DID
{0, 0, 0, 0}, ///< Lclk DPM VID
{0, 0, 0, 0}, ///< Displclk DID
3, ///< Pcie Gen 2 VID
0x10 ///< Main PLL id for 3200 VCO
};
/*----------------------------------------------------------------------------------------*/
/**
* Fuse Table Init
*
*
*
* @param[in] StdHeader Pointer to Standard configuration
* @retval AGESA_STATUS
*/
AGESA_STATUS
NbFuseTableFeature (
IN AMD_CONFIG_PARAMS *StdHeader
)
{
PP_FUSE_ARRAY *PpFuseArray;
D18F3xA0_STRUCT D18F3xA0;
BOOLEAN LoadDefaultFuses;
IDS_HDT_CONSOLE (GNB_TRACE, "NbFuseTableFeature Enter\n");
PpFuseArray = (PP_FUSE_ARRAY *) GnbAllocateHeapBuffer (AMD_PP_FUSE_TABLE_HANDLE, sizeof (PP_FUSE_ARRAY), StdHeader);
ASSERT (PpFuseArray != NULL);
if (PpFuseArray == NULL) {
IDS_HDT_CONSOLE (GNB_TRACE, " ERROR!!! Heap Allocation\n");
return AGESA_ERROR;
}
LibAmdMemFill (PpFuseArray, 0x00, sizeof (PP_FUSE_ARRAY), StdHeader);
GnbLibPciRead (
MAKE_SBDFO ( 0, 0, 0x18, 3, D18F3xA0_ADDRESS),
AccessWidth32,
&D18F3xA0.Value,
StdHeader
);
#ifndef GNB_FORCE_DEFAULT_FUSE
LoadDefaultFuses = FALSE;
if (D18F3xA0.Field.CofVidProg == 1) {
IDS_HDT_CONSOLE (NB_MISC, " Processor Fused\n");
NbFuseLoadFuseTableFromFcr (PpFuseArray, StdHeader);
if (PpFuseArray->PPlayTableRev == 0) {
IDS_HDT_CONSOLE (NB_MISC, " PowerPlay Table Unfused\n");
LoadDefaultFuses = TRUE;
}
} else {
IDS_HDT_CONSOLE (NB_MISC, " Processor Unfuse\n");
LoadDefaultFuses = TRUE;
}
#else
LoadDefaultFuses = TRUE;
#endif
if (LoadDefaultFuses) {
IDS_HDT_CONSOLE (NB_MISC, " Load default fuses\n");
NbFuseLoadDefaultFuseTable (PpFuseArray, StdHeader);
}
NbFmFuseAdjustFuseTablePatch (PpFuseArray, StdHeader);
NbFuseAdjustFuseTableToCurrentMainPllVco (PpFuseArray, StdHeader);
IDS_OPTION_CALLOUT (IDS_CALLOUT_GNB_PPFUSE_OVERRIDE, PpFuseArray, StdHeader);
GNB_DEBUG_CODE (
NbFuseDebugDump (PpFuseArray, StdHeader)
);
IDS_HDT_CONSOLE (GNB_TRACE, "NbFuseTableFeature Exit\n");
return AGESA_SUCCESS;
}
/*----------------------------------------------------------------------------------------*/
/**
* Load Fuse Table From FCRs
*
*
* @param[out] PpFuseArray Pointer to save fuse table
* @param[in] StdHeader Pointer to Standard configuration
* @retval AGESA_STATUS
*/
VOID
NbFuseLoadFuseTableFromFcr (
OUT PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
FUSE_TABLE *FuseTable;
UINTN RegisterIndex;
FuseTable = NbFmGetFuseTranslationTable ();
for (RegisterIndex = 0; RegisterIndex < FuseTable->FuseTableLength; RegisterIndex++ ) {
UINTN FieldIndex;
UINTN FuseRegisterTableLength;
UINT32 FuseValue;
FuseRegisterTableLength = FuseTable->FuseTable[RegisterIndex].FuseRegisterTableLength;
FuseValue = NbSmuReadEfuse (
FuseTable->FuseTable[RegisterIndex].Register,
StdHeader
);
for (FieldIndex = 0; FieldIndex < FuseRegisterTableLength; FieldIndex++) {
FUSE_REGISTER_ENTRY RegisterEntry;
UINT8 *FuseArrayPtr;
UINT32 FuseArrauValue;
RegisterEntry = FuseTable->FuseTable[RegisterIndex].FuseRegisterTable[FieldIndex];
FuseArrayPtr = (UINT8*) PpFuseArray + RegisterEntry.FuseOffset;
FuseArrauValue = (FuseValue >> RegisterEntry.FieldOffset) & ((1 << RegisterEntry.FieldWidth) - 1);
if (RegisterEntry.FieldWidth > 16) {
*((UINT32 *) FuseArrayPtr) = FuseArrauValue;
} else if (RegisterEntry.FieldWidth > 8) {
*((UINT16 *) FuseArrayPtr) = (UINT16) FuseArrauValue;
} else {
*((UINT8 *) FuseArrayPtr) = (UINT8) FuseArrauValue;
}
}
}
}
/*----------------------------------------------------------------------------------------*/
/**
* Load Default Fuse Table
*
*
* @param[out] PpFuseArray Pointer to save fuse table
* @param[in] StdHeader Pointer to Standard configuration
* @retval AGESA_STATUS
*/
VOID
NbFuseLoadDefaultFuseTable (
OUT PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
D18F3x15C_STRUCT D18F3x15C;
UINT8 MaxVidIndex;
LibAmdMemCopy (PpFuseArray, &DefaultPpFuseArray, sizeof (PP_FUSE_ARRAY), StdHeader);
GnbLibPciRead (
MAKE_SBDFO ( 0, 0, 0x18, 3, D18F3x15C_ADDRESS),
AccessWidth32,
&D18F3x15C.Value,
StdHeader
);
if (D18F3x15C.Value == 0) {
D18F3x15C.Value = 0x24242424;
GnbLibPciWrite (
MAKE_SBDFO ( 0, 0, 0x18, 3, D18F3x15C_ADDRESS),
AccessWidth32,
&D18F3x15C.Value,
StdHeader
);
}
MaxVidIndex = GfxLibMaxVidIndex (StdHeader);
PpFuseArray->SclkDpmVid[0] = MaxVidIndex;
PpFuseArray->PcieGen2Vid = MaxVidIndex;
}
/*----------------------------------------------------------------------------------------*/
/**
* Adjust DIDs to current main PLL VCO
*
* Main PLL VCO can be changed for debug perpouses
*
* @param[in,out] PpFuseArray Pointer to save fuse table
* @param[in] StdHeader Pointer to Standard configuration
*/
VOID
NbFuseAdjustFuseTableToCurrentMainPllVco (
IN OUT PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 EffectiveMainPllFreq10KHz;
UINT32 FusedMainPllFreq10KHz;
UINT32 TempVco;
UINTN Index;
EffectiveMainPllFreq10KHz = GfxLibGetMainPllFreq (StdHeader) * 100;
FusedMainPllFreq10KHz = (PpFuseArray->MainPllId + 0x10) * 100 * 100;
if (FusedMainPllFreq10KHz != EffectiveMainPllFreq10KHz) {
IDS_HDT_CONSOLE (NB_MISC, " WARNING! Adjusting fuse table for reprogrammed VCO\n");
IDS_HDT_CONSOLE (NB_MISC, " Actual main Freq %d \n", EffectiveMainPllFreq10KHz);
IDS_HDT_CONSOLE (NB_MISC, " Fused main Freq %d \n", FusedMainPllFreq10KHz);
for (Index = 0; Index < 5; Index++) {
if (PpFuseArray->SclkDpmDid[Index] != 0) {
TempVco = GfxLibCalculateClk (PpFuseArray->SclkDpmDid[Index], FusedMainPllFreq10KHz);
PpFuseArray->SclkDpmDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
}
}
for (Index = 0; Index < 4; Index++) {
if (PpFuseArray->VclkDid[Index] != 0) {
TempVco = GfxLibCalculateClk (PpFuseArray->VclkDid[Index], FusedMainPllFreq10KHz);
PpFuseArray->VclkDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
}
if (PpFuseArray->DclkDid[Index] != 0) {
TempVco = GfxLibCalculateClk (PpFuseArray->DclkDid[Index], FusedMainPllFreq10KHz);
PpFuseArray->DclkDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
}
if (PpFuseArray->LclkDpmDid[Index] != 0) {
TempVco = GfxLibCalculateClk (PpFuseArray->LclkDpmDid[Index], FusedMainPllFreq10KHz);
PpFuseArray->LclkDpmDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
}
if (PpFuseArray->DisplclkDid[Index] != 0) {
TempVco = GfxLibCalculateClk (PpFuseArray->DisplclkDid[Index], FusedMainPllFreq10KHz);
PpFuseArray->DisplclkDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
}
}
if (PpFuseArray->SclkThermDid != 0) {
TempVco = GfxLibCalculateClk (PpFuseArray->SclkThermDid , FusedMainPllFreq10KHz);
PpFuseArray->SclkThermDid = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
}
}
}
/*----------------------------------------------------------------------------------------*/
/**
* Debug dump fuse table
*
*
* @param[out] PpFuseArray Pointer to save fuse table
* @param[in] StdHeader Pointer to Standard configuration
*/
VOID
NbFuseDebugDump (
IN PP_FUSE_ARRAY *PpFuseArray,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINTN Index;
UINT32 EffectiveMainPllFreq10KHz;
EffectiveMainPllFreq10KHz = GfxLibGetMainPllFreq (StdHeader) * 100;
IDS_HDT_CONSOLE (NB_MISC, "<------------ GNB FUSE TABLE------------>\n");
for (Index = 0; Index < 4; Index++) {
if (PpFuseArray->LclkDpmValid[Index] != 0) {
IDS_HDT_CONSOLE (
NB_MISC,
" LCLK DID[%d] - 0x%02x (%dMHz)\n",
Index,
PpFuseArray->LclkDpmDid[Index],
GfxLibCalculateClk (PpFuseArray->LclkDpmDid[Index], EffectiveMainPllFreq10KHz) / 100);
IDS_HDT_CONSOLE (NB_MISC, " LCLK VID[%d] - 0x02%x\n", Index, PpFuseArray->LclkDpmVid[Index]);
}
}
for (Index = 0; Index < 4; Index++) {
IDS_HDT_CONSOLE (
NB_MISC,
" VCLK DID[%d] - 0x%02x (%dMHz)\n",
Index,
PpFuseArray->VclkDid[Index],
(PpFuseArray->VclkDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->VclkDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
);
IDS_HDT_CONSOLE (
NB_MISC,
" DCLK DID[%d] - 0x%02x (%dMHz)\n",
Index,
PpFuseArray->DclkDid[Index],
(PpFuseArray->DclkDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->DclkDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
);
}
for (Index = 0; Index < 4; Index++) {
IDS_HDT_CONSOLE (
NB_MISC,
" DISPCLK DID[%d] - 0x%02x (%dMHz)\n",
Index,
PpFuseArray->DisplclkDid[Index],
(PpFuseArray->DisplclkDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->DisplclkDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
);
}
for (Index = 0; Index < 6; Index++) {
IDS_HDT_CONSOLE (
NB_MISC,
" SCLK DID[%d] - 0x%02x (%dMHz)\n",
Index,
PpFuseArray->SclkDpmDid[Index],
(PpFuseArray->SclkDpmDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->SclkDpmDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
);
IDS_HDT_CONSOLE (
NB_MISC,
" SCLK TDP[%d] - 0x%x \n",
Index,
PpFuseArray->SclkDpmTdpLimit[Index]
);
IDS_HDT_CONSOLE (NB_MISC, " SCLK VID[%d] - 0x%02x\n", Index, PpFuseArray->SclkDpmVid[Index]);
}
for (Index = 0; Index < 6; Index++) {
IDS_HDT_CONSOLE (NB_MISC, " State #%d\n", Index);
IDS_HDT_CONSOLE (NB_MISC, " Policy Label - 0x%x\n", PpFuseArray->PolicyLabel[Index]);
IDS_HDT_CONSOLE (NB_MISC, " Policy Flag - 0x%x\n", PpFuseArray->PolicyFlags[Index]);
IDS_HDT_CONSOLE (NB_MISC, " Valid SCLK - 0x%x\n", PpFuseArray->SclkDpmValid[Index]);
IDS_HDT_CONSOLE (NB_MISC, " Vclk/Dclk Index - 0x%x\n", PpFuseArray->VclkDclkSel[Index]);
}
IDS_HDT_CONSOLE (NB_MISC, " GEN2 VID - 0x%x\n", PpFuseArray->PcieGen2Vid);
IDS_HDT_CONSOLE (NB_MISC, " Main PLL Id - 0x%x\n", PpFuseArray->MainPllId);
IDS_HDT_CONSOLE (NB_MISC, " GpuBoostCap - %x\n", PpFuseArray->GpuBoostCap);
IDS_HDT_CONSOLE (NB_MISC, " SclkDpmBoostMargin - %x\n", PpFuseArray->SclkDpmBoostMargin);
IDS_HDT_CONSOLE (NB_MISC, " SclkDpmThrottleMargin - %x\n", PpFuseArray->SclkDpmThrottleMargin);
IDS_HDT_CONSOLE (NB_MISC, " SclkDpmTdpLimitPG - %x\n", PpFuseArray->SclkDpmTdpLimitPG);
IDS_HDT_CONSOLE (
NB_MISC, " SclkThermDid - %x(%dMHz)\n",
PpFuseArray->SclkThermDid,
(PpFuseArray->SclkThermDid != 0) ? (GfxLibCalculateClk (PpFuseArray->SclkThermDid, EffectiveMainPllFreq10KHz) / 100) : 0
);
IDS_HDT_CONSOLE (NB_MISC, "<------------ GNB FUSE END-------------->\n");
}