diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f12/Proc/GNB/Nb/Feature/NbFuseTable.c')
-rwxr-xr-x | src/vendorcode/amd/agesa/f12/Proc/GNB/Nb/Feature/NbFuseTable.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f12/Proc/GNB/Nb/Feature/NbFuseTable.c b/src/vendorcode/amd/agesa/f12/Proc/GNB/Nb/Feature/NbFuseTable.c new file mode 100755 index 0000000000..37da8d2c8f --- /dev/null +++ b/src/vendorcode/amd/agesa/f12/Proc/GNB/Nb/Feature/NbFuseTable.c @@ -0,0 +1,432 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * Fuse table initialization + * + * + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: GNB + * @e \$Revision: 48452 $ @e \$Date: 2011-03-09 12:50:44 +0800 (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 "GnbCommonLib.h" +#include "GnbNbInitLibV1.h" +#include "OptionGnb.h" +#include "GnbRegistersLN.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 + *---------------------------------------------------------------------------------------- + */ +extern GNB_BUILD_OPTIONS GnbBuildOptions; + +/*---------------------------------------------------------------------------------------- + * 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, 0}, ///< Sclk DPM DID + {0, 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 + 0x40, ///< 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 + 0, ///< WRCK SMU clock Divisor + {0x24, 0x24, 0x24, 0x24} ///< Sclk VID +}; + + +/*----------------------------------------------------------------------------------------*/ +/** + * 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 + ); + + LoadDefaultFuses = TRUE; + if (GnbBuildOptions.GnbLoadRealFuseTable == 1) { + if (D18F3xA0.Field.CofVidProg == 1) { + IDS_HDT_CONSOLE (NB_MISC, " Processor Fused\n"); + NbFuseLoadFuseTableFromFcr (PpFuseArray, StdHeader); + if (PpFuseArray->PPlayTableRev != 0) { + LoadDefaultFuses = FALSE; + } else { + IDS_HDT_CONSOLE (NB_MISC, " PowerPlay Table Unfused\n"); + } + } else { + IDS_HDT_CONSOLE (NB_MISC, " Processor Unfuse\n"); + } + } else { + IDS_HDT_CONSOLE (NB_MISC, " Force default fuse table Unfuse\n"); + } + + 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 = GnbLocateHighestVidIndex (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"); +} |