/* $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"); }