/* $NoKeywords:$ */ /** * @file * * PCIe early post initialization. * * * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: GNB * @e \$Revision: 64732 $ @e \$Date: 2012-01-30 02:16:26 -0600 (Mon, 30 Jan 2012) $ * */ /* ***************************************************************************** * * Copyright (c) 2008 - 2012, 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 "Ids.h" #include "amdlib.h" #include "Gnb.h" #include "OptionGnb.h" #include "GnbCommonLib.h" #include "GnbPcieConfig.h" #include "GnbTable.h" #include "GnbNbInitLibV4.h" #include "GnbSmuFirmwareTN.h" #include "GnbRegisterAccTN.h" #include "GnbRegistersTN.h" #include "GfxLibTN.h" #include "GnbCacWeightsTN.h" #include "cpuFamilyTranslation.h" #include "GnbHandleLib.h" #include "GnbBapmCoeffCalcTN.h" #include "GnbInitTN.h" #include "Filecode.h" #define FILECODE PROC_GNB_MODULES_GNBINITTN_GNBEARLYINITTN_FILECODE /*---------------------------------------------------------------------------------------- * D E F I N I T I O N S A N D M A C R O S *---------------------------------------------------------------------------------------- */ extern GNB_TABLE ROMDATA GnbEarlyInitTableTN []; extern GNB_TABLE ROMDATA GnbEarlierInitTableBeforeSmuTN []; extern GNB_TABLE ROMDATA GnbEarlierInitTableAfterSmuTN []; extern GNB_BUILD_OPTIONS GnbBuildOptions; extern BUILD_OPT_CFG UserOptions; /*---------------------------------------------------------------------------------------- * 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 *---------------------------------------------------------------------------------------- */ AGESA_STATUS GnbEarlyInterfaceTN ( IN AMD_CONFIG_PARAMS *StdHeader ); AGESA_STATUS GnbEarlierInterfaceTN ( IN AMD_CONFIG_PARAMS *StdHeader ); /*----------------------------------------------------------------------------------------*/ /** * Gnb TN Decrease all of the SMU VIDs by 4 (+25mV) * * * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbAdjustSmuVidBeforeSmuTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_xE0001008_STRUCT D0F0xBC_xE0001008; IDS_HDT_CONSOLE (GNB_TRACE, "GnbAdjustSmuVidBeforeSmuTN Enter\n"); GnbRegisterReadTN (D0F0xBC_xE0001008_TYPE, D0F0xBC_xE0001008_ADDRESS, &D0F0xBC_xE0001008, 0, StdHeader); D0F0xBC_xE0001008.Field.SClkVid3 -= 4; D0F0xBC_xE0001008.Field.SClkVid2 -= 4; D0F0xBC_xE0001008.Field.SClkVid1 -= 4; D0F0xBC_xE0001008.Field.SClkVid0 -= 4; GnbRegisterWriteTN (D0F0xBC_xE0001008_TYPE, D0F0xBC_xE0001008_ADDRESS, &D0F0xBC_xE0001008, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbAdjustSmuVidBeforeSmuTN Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Gnb TN Decrease all of the SMU VIDs by 4 (+25mV) * * * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbAdjustSmuVidAfterSmuTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_x1F88C_STRUCT D0F0xBC_x1F88C; D0F0xBC_x1F8DC_STRUCT D0F0xBC_x1F8DC; D0F0xBC_x1F8E0_STRUCT D0F0xBC_x1F8E0; D0F0xBC_x1F8E4_STRUCT D0F0xBC_x1F8E4; D0F0xBC_x1F8E8_STRUCT D0F0xBC_x1F8E8; D0F0xBC_x1F400_STRUCT D0F0xBC_x1F400; IDS_HDT_CONSOLE (GNB_TRACE, "GnbAdjustSmuVidAfterSmuTN Enter\n"); //Adjust SMU VIDs GnbRegisterReadTN (D0F0xBC_x1F88C_TYPE, D0F0xBC_x1F88C_ADDRESS, &D0F0xBC_x1F88C, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F8DC_TYPE, D0F0xBC_x1F8DC_ADDRESS, &D0F0xBC_x1F8DC, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F8E0_TYPE, D0F0xBC_x1F8E0_ADDRESS, &D0F0xBC_x1F8E0, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F8E4_TYPE, D0F0xBC_x1F8E4_ADDRESS, &D0F0xBC_x1F8E4, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F8E8_TYPE, D0F0xBC_x1F8E8_ADDRESS, &D0F0xBC_x1F8E8, 0, StdHeader); D0F0xBC_x1F88C.Field.NbVid_3 -= 4; D0F0xBC_x1F88C.Field.NbVid_2 -= 4; D0F0xBC_x1F88C.Field.NbVid_1 -= 4; D0F0xBC_x1F88C.Field.NbVid_0 -= 4; D0F0xBC_x1F8DC.Field.SClkVid3 -= 4; D0F0xBC_x1F8DC.Field.SClkVid2 -= 4; D0F0xBC_x1F8DC.Field.SClkVid1 -= 4; D0F0xBC_x1F8DC.Field.SClkVid0 -= 4; D0F0xBC_x1F8E0.Field.BapmSclkVid_2 -= 4; D0F0xBC_x1F8E0.Field.BapmSclkVid_1 -= 4; D0F0xBC_x1F8E0.Field.BapmSclkVid_0 -= 4; D0F0xBC_x1F8E4.Field.BapmNbVid_1 -= 4; D0F0xBC_x1F8E4.Field.BapmNbVid_0 -= 4; D0F0xBC_x1F8E4.Field.BapmSclkVid_3 -= 4; D0F0xBC_x1F8E8.Field.BapmNbVid_3 -= 4; D0F0xBC_x1F8E8.Field.BapmNbVid_2 -= 4; GnbRegisterWriteTN (D0F0xBC_x1F88C_TYPE, D0F0xBC_x1F88C_ADDRESS, &D0F0xBC_x1F88C, 0, StdHeader); GnbRegisterWriteTN (D0F0xBC_x1F8DC_TYPE, D0F0xBC_x1F8DC_ADDRESS, &D0F0xBC_x1F8DC, 0, StdHeader); GnbRegisterWriteTN (D0F0xBC_x1F8E0_TYPE, D0F0xBC_x1F8E0_ADDRESS, &D0F0xBC_x1F8E0, 0, StdHeader); GnbRegisterWriteTN (D0F0xBC_x1F8E4_TYPE, D0F0xBC_x1F8E4_ADDRESS, &D0F0xBC_x1F8E4, 0, StdHeader); GnbRegisterWriteTN (D0F0xBC_x1F8E8_TYPE, D0F0xBC_x1F8E8_ADDRESS, &D0F0xBC_x1F8E8, 0, StdHeader); //D0F0xBC_x1F400[SviLoadLineOffsetVddNB]=01b (-25mV) GnbRegisterReadTN (D0F0xBC_x1F400_TYPE, D0F0xBC_x1F400_ADDRESS, &D0F0xBC_x1F400, 0, StdHeader); D0F0xBC_x1F400.Field.SviLoadLineOffsetVddNB = 1; GnbRegisterWriteTN (D0F0xBC_x1F400_TYPE, D0F0xBC_x1F400_ADDRESS, &D0F0xBC_x1F400, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbAdjustSmuVidAfterSmuTN Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Gnb SMU LHTC support * * Part of BAPM enablement. * When BAPM is disabled in battery mode firmware will enable LHTC. * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbBapmLhtcInitTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_x1F638_STRUCT D0F0xBC_x1F638; D0F0xBC_x1F428_STRUCT D0F0xBC_x1F428; D0F0xBC_x1F86C_STRUCT D0F0xBC_x1F86C; D0F0xBC_x1F628_STRUCT D0F0xBC_x1F628; D0F0xBC_xE0104188_STRUCT D0F0xBC_xE0104188; IDS_HDT_CONSOLE (GNB_TRACE, "GnbBapmLhtcInitTN Enter\n"); GnbRegisterReadTN (D0F0xBC_x1F638_TYPE, D0F0xBC_x1F638_ADDRESS, &D0F0xBC_x1F638, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F428_TYPE, D0F0xBC_x1F428_ADDRESS, &D0F0xBC_x1F428, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_xE0104188_TYPE, D0F0xBC_xE0104188_ADDRESS, &D0F0xBC_xE0104188, 0, StdHeader); //1. Set HTC period to 10 in PM_TIMERS_2 register //Still need to keep PM_CONFIG.Enable_HTC_Limit to 0 D0F0xBC_x1F428.Field.field_4 = 0; GnbRegisterWriteTN (D0F0xBC_x1F428_TYPE, D0F0xBC_x1F428_ADDRESS, &D0F0xBC_x1F428, 0, StdHeader); D0F0xBC_x1F638.Field.HtcPeriod = 10; GnbRegisterWriteTN (D0F0xBC_x1F638_TYPE, D0F0xBC_x1F638_ADDRESS, &D0F0xBC_x1F638, 0, StdHeader); //2. Read BapmLhtcCap fuse GnbRegisterReadTN (D0F0xBC_x1F86C_TYPE, D0F0xBC_x1F86C_ADDRESS, &D0F0xBC_x1F86C, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F628_TYPE, D0F0xBC_x1F628_ADDRESS, &D0F0xBC_x1F628, 0, StdHeader); if (D0F0xBC_x1F86C.Field.BapmLhtcCap == 0) { D0F0xBC_x1F628.Field.HtcActivePstateLimit = 0; } else { D0F0xBC_x1F628.Field.HtcActivePstateLimit = D0F0xBC_xE0104188.Field.LhtcPstateLimit; } GnbRegisterWriteTN (D0F0xBC_x1F628_TYPE, D0F0xBC_x1F628_ADDRESS, &D0F0xBC_x1F628, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbBapmLhtcInitTN Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Measured temperature with BAPM * * * * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbBapmMeasuredTempTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_x1F428_STRUCT D0F0xBC_x1F428; D0F0xBC_xE0104188_STRUCT D0F0xBC_xE0104188; D0F0xBC_x1F844_STRUCT D0F0xBC_x1F844; D0F0xBC_x1F848_STRUCT D0F0xBC_x1F848; D0F0xBC_x1F84C_STRUCT D0F0xBC_x1F84C; IDS_HDT_CONSOLE (GNB_TRACE, "GnbBapmMeasuredTempTN Enter\n"); GnbRegisterReadTN (D0F0xBC_xE0104188_TYPE, D0F0xBC_xE0104188_ADDRESS, &D0F0xBC_xE0104188, 0, StdHeader); //Measured temperature with BAPM GnbRegisterReadTN (D0F0xBC_x1F428_TYPE, D0F0xBC_x1F428_ADDRESS, &D0F0xBC_x1F428, 0, StdHeader); D0F0xBC_x1F428.Field.line180 = 0; if (D0F0xBC_xE0104188.Field.BapmMeasuredTemp == 1) { D0F0xBC_x1F844.Value = 0x38B; GnbRegisterWriteTN (D0F0xBC_x1F844_TYPE, D0F0xBC_x1F844_ADDRESS, &D0F0xBC_x1F844, 0, StdHeader); D0F0xBC_x1F848.Value = 0x38D; GnbRegisterWriteTN (D0F0xBC_x1F848_TYPE, D0F0xBC_x1F848_ADDRESS, &D0F0xBC_x1F848, 0, StdHeader); D0F0xBC_x1F84C.Value = 0x389; GnbRegisterWriteTN (D0F0xBC_x1F84C_TYPE, D0F0xBC_x1F84C_ADDRESS, &D0F0xBC_x1F84C, 0, StdHeader); D0F0xBC_x1F428.Field.line180 = 1; } GnbRegisterWriteTN (D0F0xBC_x1F428_TYPE, D0F0xBC_x1F428_ADDRESS, &D0F0xBC_x1F428, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbBapmMeasuredTempTN Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Gnb SMU LHTC Enable * * Part of BAPM enablement. * When BAPM is disabled in battery mode firmware will enable LHTC. * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbLhtcEnableTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_x1F428_STRUCT D0F0xBC_x1F428; IDS_HDT_CONSOLE (GNB_TRACE, "GnbLhtcEnableTN Enter\n"); GnbRegisterReadTN (D0F0xBC_x1F428_TYPE, D0F0xBC_x1F428_ADDRESS, &D0F0xBC_x1F428, 0, StdHeader); D0F0xBC_x1F428.Field.field_4 = 1; GnbRegisterWriteTN (D0F0xBC_x1F428_TYPE, D0F0xBC_x1F428_ADDRESS, &D0F0xBC_x1F428, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbLhtcEnableTN Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Gnb TN Update BAPMTI_TjOffset * * * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbTjOffsetUpdateTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_x1F870_STRUCT D0F0xBC_x1F870; CPU_LOGICAL_ID LogicalId; GNB_HANDLE *GnbHandle; D0F0xBC_xE0104040_STRUCT D0F0xBC_xE0104040; D0F0xBC_x1F85C_STRUCT D0F0xBC_x1F85C; ex1075_STRUCT ex1075 ; UINT32 TimerPeriod; IDS_HDT_CONSOLE (GNB_TRACE, "GnbTjOffsetUpdateTN Enter\n"); TimerPeriod = D0F0xBC_x1F468_TimerPeriod_Value; GnbRegisterReadTN (D0F0xBC_x1F85C_TYPE, D0F0xBC_x1F85C_ADDRESS, &D0F0xBC_x1F85C, 0, StdHeader); GnbRegisterReadTN (TYPE_D0F0xBC , 0xe010413c , &ex1075, 0, StdHeader); // Determine desired AgingRate: // PM_FUSES4.TdpAgeRate * Fuse[BAPMTI_Ts] (encoded in us) // Re-encode TdpAgeRate with 1ms BAPM interval D0F0xBC_x1F85C.Field.TdpAgeRate = (D0F0xBC_x1F85C.Field.TdpAgeRate * ex1075.Field.ex1075_0 ) / (TimerPeriod / 100); GnbRegisterWriteTN (D0F0xBC_x1F85C_TYPE, D0F0xBC_x1F85C_ADDRESS, &D0F0xBC_x1F85C, 0, StdHeader); GnbHandle = GnbGetHandle (StdHeader); ASSERT (GnbHandle != NULL); GetLogicalIdOfSocket (GnbGetSocketId (GnbHandle), &LogicalId, StdHeader); if ((LogicalId.Revision & 0x0000000000000100ull ) != 0x0000000000000100ull ) { IDS_HDT_CONSOLE (GNB_TRACE, "CPU Rev = %x, Skip GnbTjOffsetUpdateTN\n", LogicalId.Revision); return; } GnbRegisterReadTN (D0F0xBC_xE0104040_TYPE, D0F0xBC_xE0104040_ADDRESS, &D0F0xBC_xE0104040, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F870_TYPE, D0F0xBC_x1F870_ADDRESS, &D0F0xBC_x1F870, 0, StdHeader); //9900h=FS1r2/FP2 Devastator //9903h=FS1r2/FP2 Devastator Lite //9990h=FS1r2/FP2 Scrapper //9901h=FM2 Devastator //9904h=FM2 Devastator Lite //9991h=FM2 Scrapper if ((D0F0xBC_xE0104040.Field.DeviceID == 0x9900) || (D0F0xBC_xE0104040.Field.DeviceID == 0x9903)) { D0F0xBC_x1F870.Field.BAPMTI_TjOffset_0 = 0x26; D0F0xBC_x1F870.Field.BAPMTI_TjOffset_1 = 0x26; D0F0xBC_x1F870.Field.BAPMTI_TjOffset_2 = 0x26; } else if (D0F0xBC_xE0104040.Field.DeviceID == 0x9990) { D0F0xBC_x1F870.Field.BAPMTI_TjOffset_0 = 0x2E; D0F0xBC_x1F870.Field.BAPMTI_TjOffset_1 = 0x2E; D0F0xBC_x1F870.Field.BAPMTI_TjOffset_2 = 0x2E; } else { IDS_HDT_CONSOLE (GNB_TRACE, "GnbTjOffsetUpdateTN Skip DID- %x\n", D0F0xBC_xE0104040.Field.DeviceID); } GnbRegisterWriteTN (D0F0xBC_x1F870_TYPE, D0F0xBC_x1F870_ADDRESS, &D0F0xBC_x1F870, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbTjOffsetUpdateTN Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * GPU CAC enablement and weights programming * * * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbCacEnablement ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_x1F464_STRUCT D0F0xBC_x1F464; ex1071_STRUCT ex1071 ; ex1072_STRUCT ex1072 ; PCI_ADDR PciAddress; UINT8 Index; ex1073_STRUCT ex1073 ; D18F5x160_STRUCT D18F5x160; DOUBLE UnbCac; GMMx898_STRUCT GMMx898; GnbRegisterReadTN (TYPE_D0F0xBC , 0x1f920 , &ex1072, 0, StdHeader); ex1072.Field.ex1072_2 = 0x29; GnbRegisterWriteTN (TYPE_D0F0xBC , 0x1f920 , &ex1072, 0, StdHeader); //UNB_CAC_VALUE.UNB_CAC = 2.3734E-04 * FNBPS0 (in MHz) * 2^GPU_CAC_AVRG_CNTL.WEIGHT_PREC GnbRegisterReadTN (D18F5x160_TYPE, D18F5x160_ADDRESS, &D18F5x160.Value, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "NBP0 10khz %x (%d)\n", GfxLibGetNclkTN ((UINT8) D18F5x160.Field.NbFid, (UINT8) D18F5x160.Field.NbDid), GfxLibGetNclkTN ((UINT8) D18F5x160.Field.NbFid, (UINT8) D18F5x160.Field.NbDid)); UnbCac = 0.00000204831536 * (1 << ex1072.Field.ex1072_0 ) * GfxLibGetNclkTN ((UINT8) D18F5x160.Field.NbFid, (UINT8) D18F5x160.Field.NbDid); ex1073.Field.ex1073_0 = (UINT32) GnbFpLibDoubleToInt32 (UnbCac); IDS_HDT_CONSOLE (GNB_TRACE, "UnbCac %x (%d)\n", ex1073.Field.ex1073_0 , ex1073.Field.ex1073_0 ); GnbRegisterWriteTN (TYPE_D0F0xBC , 0x1f91c , &ex1073.Value, 0, StdHeader); GnbRegisterReadTN (TYPE_D0F0xBC , 0x1f160 , &ex1071, 0, StdHeader); ex1071.Field.ex1071_0 = 0x1; ex1071.Field.ex1071_3 = 0x4; ex1071.Field.ex1071_4 = 0x25; GnbRegisterWriteTN (TYPE_D0F0xBC , 0x1f160 , &ex1071, 0, StdHeader); GnbRegisterReadTN (GMMx898_TYPE, GMMx898_ADDRESS, &GMMx898, 0, StdHeader); GMMx898.Field.Threshold = 0x31; GnbRegisterWriteTN (GMMx898_TYPE, GMMx898_ADDRESS, &GMMx898, 0, StdHeader); // Set CAC/TDP interval GnbRegisterReadTN (D0F0xBC_x1F464_TYPE, D0F0xBC_x1F464_ADDRESS, &D0F0xBC_x1F464, 0, StdHeader); D0F0xBC_x1F464.Field.TdpCntl = 1; GnbRegisterWriteTN (D0F0xBC_x1F464_TYPE, D0F0xBC_x1F464_ADDRESS, &D0F0xBC_x1F464, 0, StdHeader); // Program GPU CAC weights for (Index = 0; Index < (sizeof (CacWeightsTN) / sizeof (CacWeightsTN[0])); Index++) { GnbRegisterWriteTN (TYPE_D0F0xBC , (0x1f9a0 + (Index * 4)), &CacWeightsTN[Index], 0, StdHeader); } // Call BIOS service SMC_MSG_CONFIG_TDP_CNTL PciAddress.AddressValue = MAKE_SBDFO (0, 0, 0, 0, 0); GnbSmuServiceRequestV4 ( PciAddress, SMC_MSG_CONFIG_TDP_CNTL, 0, StdHeader ); } /*----------------------------------------------------------------------------------------*/ /** * Decode power of CPU out of Watt * * * * @param[in] Encode PwrCpu encode * @param[in] StdHeader Standard Configuration Header * @retval mWatt */ STATIC INT32 CpuPowerDecode ( IN UINT8 Encode, IN AMD_CONFIG_PARAMS *StdHeader ) { INT32 Power; ex1002_STRUCT ex1002 ; GnbRegisterReadTN (TYPE_D0F0xBC , 0x1f850 , &ex1002, 0, StdHeader); //TdpWatt = TdpWattEncode / 1024 //PwrCpu / TdpWatt = Encode //PwrCpu = Encode * TdpWattEncode / 1024 Power = (INT32) ((Encode * ex1002.Field.ex1002_0 *1000) / 1024); return Power; } /*----------------------------------------------------------------------------------------*/ /** * Encode the offset of power of CPU * * * * @param[in] NewPower New power of mWatt * @param[in] OrgPower Original power of mWatt * @param[in] StdHeader Standard Configuration Header * @retval Encode */ STATIC UINT8 CpuPowerOffsetEncode ( IN INT32 NewPower, IN INT32 OrgPower, IN AMD_CONFIG_PARAMS *StdHeader ) { INT8 PowerOffsetEncode; INT32 PowerOffset; ex1002_STRUCT ex1002 ; BOOLEAN Postive; GnbRegisterReadTN (TYPE_D0F0xBC , 0x1f850 , &ex1002, 0, StdHeader); if (NewPower > OrgPower) { PowerOffset = NewPower - OrgPower; Postive = TRUE; } else { PowerOffset = OrgPower - NewPower; Postive = FALSE; } IDS_HDT_CONSOLE (GNB_TRACE, "Cpu New Pwr %x (%d)\n", NewPower, NewPower); IDS_HDT_CONSOLE (GNB_TRACE, "Cpu org Pwr %x (%d)\n", OrgPower, OrgPower); IDS_HDT_CONSOLE (GNB_TRACE, "Tdp2Watt %x, (%d)\n", ex1002.Field.ex1002_0 , ex1002.Field.ex1002_0 ); //Ceil of (mWatt *1024 / TdpWattEncode) / 1000 = Encode in watt PowerOffset = (((PowerOffset * 1024) / ex1002.Field.ex1002_0 ) + 500) / 1000; if (Postive) { PowerOffsetEncode = (INT8) PowerOffset; } else { PowerOffsetEncode = 0 - (INT8) PowerOffset; } IDS_HDT_CONSOLE (GNB_TRACE, "PowerOffsetEncode %x\n", PowerOffsetEncode); return (UINT8) PowerOffsetEncode; } /*----------------------------------------------------------------------------------------*/ /** * Decode power of GPU out of Watt * * * * @param[in] Encode PwrGpu encode * @param[in] StdHeader Standard Configuration Header * @retval mWatt */ STATIC INT16 GpuPowerDecode ( IN UINT16 Encode, IN AMD_CONFIG_PARAMS *StdHeader ) { INT16 Power; Power = (INT16) Encode; return Power; } /*----------------------------------------------------------------------------------------*/ /** * Decode Max Tj * * * * @param[in] Encode Tj encode * @retval 100 x Tj */ STATIC INT16 TjMaxDecode ( IN UINT8 Encode ) { INT16 TjMax; TjMax = (INT16) Encode; return (TjMax * 100); } /*----------------------------------------------------------------------------------------*/ /** * for BAPMTI_TjOffset decoding * * * * @param[in] Encode Tj encode * @retval 100 x Tjoffset */ STATIC INT16 TjOffsetDecode ( IN UINT8 Encode ) { UINT16 Number; UINT8 Floating; BOOLEAN Postive; UINT8 TjOffsetEncode; TjOffsetEncode = Encode; Postive = TRUE; if (Encode == 0) { return 0; } if ((TjOffsetEncode & 0x80) != 0) { Postive = FALSE; TjOffsetEncode = (UINT8) (~(Encode - 1)); } Number = ((TjOffsetEncode >> 2) & 0x1F) * 100; Floating = (TjOffsetEncode & 0x3); if (Floating == 1) { Number += 25; } else if (Floating == 2) { Number += 50; } else if (Floating == 3) { Number += 75; } else { } if (Postive) { return (INT16) Number; } else { return (INT16) (0 - Number); } } /*----------------------------------------------------------------------------------------*/ /** * Trinity SMU supports a software-writeable TjOffset (called swTjOffset) that can be programmed to * account for underspec thermal solutions. * There is a mechanism for customers to adjust TjOffset (via BAPM_PARAMETERS3.TjOffset) * for under-performing thermal solutions. * BIOS will adjust NomPow/MidPow/MaxPow based on this software-programmable TjOffset (called swTjOffset). * SMU firmware will add this value to Fuse[TjOffset] for all TE's during BAPM calculations. * * Tj stands for junction temperature of the processor. However, here is a general description of * our software-programmable TjOffset for BAPM (Birdirectional Application Power Management): * "swTjOffset is an adjustable offset for BAPM thermal calculations to account for changes in * junction temperature, TjOffset. For further details, see Thermal Guide." * * @param[in] StdHeader Standard configuration header */ STATIC VOID GnbSoftwareTjOffsetTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_x1F860_STRUCT D0F0xBC_x1F860; D0F0xBC_x1F864_STRUCT D0F0xBC_x1F864; ex999_STRUCT ex999 ; D0F0xBC_x1F870_STRUCT D0F0xBC_x1F870; ex1000_STRUCT ex1000 ; ex1001_STRUCT ex1001 ; ex996_STRUCT ex996; ex997_STRUCT ex997 ; D0F0xBC_x1F6B4_STRUCT D0F0xBC_x1F6B4; ex998_STRUCT ex998 ; INT8 SwTjOffset; INT16 Delta_T_org; INT16 Delta_T_new; INT32 Cpu_New_Pwr; INT32 Gpu_New_Pwr; SwTjOffset = (INT8) UserOptions.CfgGnbSwTjOffset; IDS_HDT_CONSOLE (GNB_TRACE, "GnbSoftwareTjOffsetTN Enter\n"); IDS_OPTION_HOOK (IDS_GNB_PMM_SWTJOFFSET, &SwTjOffset, StdHeader); if (SwTjOffset == 0) { return; } IDS_HDT_CONSOLE (GNB_TRACE, "User Input Tj Offset %x\n", SwTjOffset); GnbRegisterReadTN (D0F0xBC_x1F860_TYPE, D0F0xBC_x1F860_ADDRESS, &D0F0xBC_x1F860, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F864_TYPE, D0F0xBC_x1F864_ADDRESS, &D0F0xBC_x1F864, 0, StdHeader); GnbRegisterReadTN (TYPE_D0F0xBC , 0x1f868 , &ex999, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_x1F870_TYPE, D0F0xBC_x1F870_ADDRESS, &D0F0xBC_x1F870, 0, StdHeader); GnbRegisterReadTN (TYPE_D0F0xBC , 0x1f898 , &ex1000, 0, StdHeader); GnbRegisterReadTN (TYPE_D0F0xBC , 0x1f8c0 , &ex1001, 0, StdHeader); //Tjoffset_new = Tjoffset_org + SwTjOffset //Delta_T_org = T_die - Tjoffset_org - 45 //Delta_T_new = T_die - Tjoffset_new - 45 // = T_die - (Tjoffset_org + SwTjOffset) - 45 // = T_die - Tjoffset_org - SwTjOffset - 45 //Pwr_new = Pwr_org * (Delta_T_new/Delta_T_org) // = Pwr_org * (T_org - TjOffset) / T_org //Cpu0 Delta_T_org = TjMaxDecode ((UINT8) D0F0xBC_x1F860.Field.BAPMTI_TjMax_0) - TjOffsetDecode ((UINT8) D0F0xBC_x1F870.Field.BAPMTI_TjOffset_0) - 4500; Delta_T_new = TjMaxDecode ((UINT8) D0F0xBC_x1F860.Field.BAPMTI_TjMax_0) - TjOffsetDecode ((UINT8) D0F0xBC_x1F870.Field.BAPMTI_TjOffset_0) - (SwTjOffset * 100) - 4500; IDS_HDT_CONSOLE (GNB_TRACE, "Cpu0 Delta T org %x (%d)\n", Delta_T_org, Delta_T_org); IDS_HDT_CONSOLE (GNB_TRACE, "Cpu0 Delta T New %x (%d)\n", Delta_T_new, Delta_T_new); Cpu_New_Pwr = (CpuPowerDecode ((UINT8) ex999.Field.ex999_3 , StdHeader) * Delta_T_new) / Delta_T_org; ex996.Field.ex996_2 = CpuPowerOffsetEncode (Cpu_New_Pwr, CpuPowerDecode ((UINT8) ex999.Field.ex999_3 , StdHeader), StdHeader); Cpu_New_Pwr = (CpuPowerDecode ((UINT8) ex999.Field.ex999_2 , StdHeader) * Delta_T_new) / Delta_T_org; ex996.Field.ex996_3 = CpuPowerOffsetEncode (Cpu_New_Pwr, CpuPowerDecode ((UINT8) ex999.Field.ex999_2 , StdHeader), StdHeader); Cpu_New_Pwr = (CpuPowerDecode ((UINT8) ex1001.Field.ex1001_2 , StdHeader) * Delta_T_new) / Delta_T_org; ex998.Field.ex998_2 = CpuPowerOffsetEncode (Cpu_New_Pwr, CpuPowerDecode ((UINT8) ex1001.Field.ex1001_2 , StdHeader), StdHeader); //Cpu1 Delta_T_org = TjMaxDecode ((UINT8) D0F0xBC_x1F860.Field.BAPMTI_TjMax_1) - TjOffsetDecode ((UINT8) D0F0xBC_x1F870.Field.BAPMTI_TjOffset_1) - 4500; Delta_T_new = TjMaxDecode ((UINT8) D0F0xBC_x1F860.Field.BAPMTI_TjMax_1) - TjOffsetDecode ((UINT8) D0F0xBC_x1F870.Field.BAPMTI_TjOffset_1) - (SwTjOffset * 100) - 4500; IDS_HDT_CONSOLE (GNB_TRACE, "Cpu1 Delta T org %x (%d)\n", Delta_T_org, Delta_T_org); IDS_HDT_CONSOLE (GNB_TRACE, "Cpu1 Delta T New %x (%d)\n", Delta_T_new, Delta_T_new); Cpu_New_Pwr = (CpuPowerDecode ((UINT8) ex999.Field.ex999_1 , StdHeader) * Delta_T_new) / Delta_T_org; ex996.Field.ex996_0 = CpuPowerOffsetEncode (Cpu_New_Pwr, CpuPowerDecode ((UINT8) ex999.Field.ex999_1, StdHeader), StdHeader); Cpu_New_Pwr = (CpuPowerDecode ((UINT8) ex999.Field.ex999_0 , StdHeader) * Delta_T_new) / Delta_T_org; ex996.Field.ex996_1 = CpuPowerOffsetEncode (Cpu_New_Pwr, CpuPowerDecode ((UINT8) ex999.Field.ex999_0 , StdHeader), StdHeader); Cpu_New_Pwr = (CpuPowerDecode ((UINT8) ex1001.Field.ex1001_1 , StdHeader) * Delta_T_new) / Delta_T_org; ex998.Field.ex998_1 = CpuPowerOffsetEncode (Cpu_New_Pwr, CpuPowerDecode ((UINT8) ex1001.Field.ex1001_1 , StdHeader), StdHeader); //GPU Delta_T_org = TjMaxDecode ((UINT8) D0F0xBC_x1F864.Field.BAPMTI_GpuTjMax) - TjOffsetDecode ((UINT8) D0F0xBC_x1F870.Field.BAPMTI_TjOffset_2) - 4500; Delta_T_new = TjMaxDecode ((UINT8) D0F0xBC_x1F864.Field.BAPMTI_GpuTjMax) - TjOffsetDecode ((UINT8) D0F0xBC_x1F870.Field.BAPMTI_TjOffset_2) - (SwTjOffset * 100) - 4500; IDS_HDT_CONSOLE (GNB_TRACE, "Gpu Delta T org %x (%d)\n", Delta_T_org, Delta_T_org); IDS_HDT_CONSOLE (GNB_TRACE, "Gpu Delta T New %x (%d)\n", Delta_T_new, Delta_T_new); Gpu_New_Pwr = (GpuPowerDecode ((UINT16) ex1000.Field.ex1000_1 , StdHeader) * Delta_T_new) / Delta_T_org; ex997.Field.ex997_0 = (UINT16) (Gpu_New_Pwr - GpuPowerDecode ((UINT16) ex1000.Field.ex1000_1 , StdHeader)); Gpu_New_Pwr = (GpuPowerDecode ((UINT16) ex1000.Field.ex1000_0 , StdHeader) * Delta_T_new) / Delta_T_org; ex997.Field.ex997_1 = (UINT16) (Gpu_New_Pwr - GpuPowerDecode ((UINT16) ex1000.Field.ex1000_0 , StdHeader)); Gpu_New_Pwr = (GpuPowerDecode ((UINT16) ex1001.Field.ex1001_0 , StdHeader) * Delta_T_new) / Delta_T_org; ex998.Field.ex998_0 = (UINT16) (Gpu_New_Pwr - GpuPowerDecode ((UINT16) ex1001.Field.ex1001_0 , StdHeader)); //SwTjOffset D0F0xBC_x1F6B4.Field.TjOffset = SwTjOffset; GnbRegisterWriteTN (TYPE_D0F0xBC , 0x1f6ac , &ex996, 0, StdHeader); GnbRegisterWriteTN (TYPE_D0F0xBC , 0x1f6b0 , &ex997, 0, StdHeader); GnbRegisterWriteTN (D0F0xBC_x1F6B4_TYPE, D0F0xBC_x1F6B4_ADDRESS, &D0F0xBC_x1F6B4, 0, StdHeader); GnbRegisterWriteTN (TYPE_D0F0xBC , 0x1F6B8 , &ex998, 0, StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbSoftwareTjOffsetTN Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Init TDC * * * * @param[in] StdHeader Standard configuration header * @retval AGESA_STATUS */ STATIC VOID GnbInitTdc ( IN AMD_CONFIG_PARAMS *StdHeader ) { AMD_EARLY_PARAMS *EarlyParams; D0F0xBC_x1F62C_STRUCT D0F0xBC_x1F62C; D0F0xBC_x1F840_STRUCT D0F0xBC_x1F840; EarlyParams = (AMD_EARLY_PARAMS *) StdHeader; D0F0xBC_x1F62C.Field.Idd = EarlyParams->PlatformConfig.VrmProperties[CoreVrm].CurrentLimit / 10; D0F0xBC_x1F62C.Field.Iddnb = EarlyParams->PlatformConfig.VrmProperties[NbVrm].CurrentLimit / 10; GnbRegisterWriteTN (D0F0xBC_x1F62C_TYPE, D0F0xBC_x1F62C_ADDRESS, &D0F0xBC_x1F62C, 0, StdHeader); D0F0xBC_x1F840.Field.IddspikeOCP = EarlyParams->PlatformConfig.VrmProperties[CoreVrm].SviOcpLevel / 10; D0F0xBC_x1F840.Field.IddNbspikeOCP = EarlyParams->PlatformConfig.VrmProperties[NbVrm].SviOcpLevel / 10; GnbRegisterWriteTN (D0F0xBC_x1F840_TYPE, D0F0xBC_x1F840_ADDRESS, &D0F0xBC_x1F840, 0, StdHeader); } /*----------------------------------------------------------------------------------------*/ /** * PCIe Early Post Init * * * * @param[in] StdHeader Standard configuration header * @retval AGESA_STATUS */ AGESA_STATUS GnbEarlyInterfaceTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { AGESA_STATUS Status; GNB_HANDLE *GnbHandle; UINT32 Property; D0F0xBC_xE0104188_STRUCT D0F0xBC_xE0104188; Status = AGESA_SUCCESS; IDS_HDT_CONSOLE (GNB_TRACE, "GnbEarlyInterfaceTN Enter\n"); Property = TABLE_PROPERTY_DEAFULT; //Check fuse to support BAPM disabled. GnbRegisterReadTN (D0F0xBC_xE0104188_TYPE, D0F0xBC_xE0104188_ADDRESS, &D0F0xBC_xE0104188, 0, StdHeader); if (D0F0xBC_xE0104188.Field.BapmDisable == 0) { Property |= GnbBuildOptions.CfgBapmSupport ? TABLE_PROPERTY_BAPM : 0; } IDS_OPTION_HOOK (IDS_GNB_PROPERTY, &Property, StdHeader); // SMU LHTC support init GnbBapmLhtcInitTN (StdHeader); if ((Property & TABLE_PROPERTY_BAPM) == TABLE_PROPERTY_BAPM) { GnbTjOffsetUpdateTN (StdHeader); GnbSoftwareTjOffsetTN (StdHeader); GnbBapmCalculateCoeffsTN (StdHeader); GnbCacEnablement (StdHeader); GnbBapmMeasuredTempTN (StdHeader); } else { // If BAPM is disabled (either through fusing or CBS option), AGESA should enable LHTC algorithm. // Right now, LHTC is only enabled in the "DisableBAPM()" firmware routine, so unless Driver specifically calls this message, // LHTC will never be enabled if BAPM is disabled from the start. GnbLhtcEnableTN (StdHeader); } GnbInitTdc (StdHeader); GnbHandle = GnbGetHandle (StdHeader); ASSERT (GnbHandle != NULL); Status = GnbProcessTable ( GnbHandle, GnbEarlyInitTableTN, Property, 0, StdHeader ); IDS_HDT_CONSOLE (GNB_TRACE, "GnbEarlyInterfaceTN Exit [0x%x]\n", Status); return Status; } /*----------------------------------------------------------------------------------------*/ /** * PCIe Early Post Init * * * * @param[in] StdHeader Standard configuration header * @retval AGESA_STATUS */ AGESA_STATUS GnbEarlierInterfaceTN ( IN AMD_CONFIG_PARAMS *StdHeader ) { AGESA_STATUS Status; GNB_HANDLE *GnbHandle; D0F0xBC_xE0107060_STRUCT D0F0xBC_xE0107060; D0F0xBC_xE0001008_STRUCT D0F0xBC_xE0001008; Status = AGESA_SUCCESS; IDS_HDT_CONSOLE (GNB_TRACE, "GnbEarlierInterfaceTN Enter\n"); GnbAdjustSmuVidBeforeSmuTN (StdHeader); GnbHandle = GnbGetHandle (StdHeader); ASSERT (GnbHandle != NULL); GnbRegisterReadTN (D0F0xBC_xE0107060_TYPE, D0F0xBC_xE0107060_ADDRESS, &D0F0xBC_xE0107060, 0, StdHeader); GnbRegisterReadTN (D0F0xBC_xE0001008_TYPE, D0F0xBC_xE0001008_ADDRESS, &D0F0xBC_xE0001008, 0, StdHeader); GfxRequestVoltageTN ((UINT8) D0F0xBC_xE0001008.Field.SClkVid1, StdHeader); GfxRequestSclkTN ((UINT8) D0F0xBC_xE0107060.Field.SClkDpmDid1, StdHeader); Status = GnbProcessTable ( GnbHandle, GnbEarlierInitTableBeforeSmuTN, 0, 0, StdHeader ); GnbSmuFirmwareLoadV4 (GnbHandle->Address, (FIRMWARE_HEADER_V4*) &FirmwareTN[0], StdHeader); Status = GnbProcessTable ( GnbHandle, GnbEarlierInitTableAfterSmuTN, 0, 0, StdHeader ); GnbAdjustSmuVidAfterSmuTN (StdHeader); IDS_HDT_CONSOLE (GNB_TRACE, "GnbEarlierInterfaceTN Exit [0x%x]\n", Status); return Status; }