/* $NoKeywords:$ */ /** * @file * * KB specific PCIe services * * * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: GNB * @e \$Revision: 87645 $ @e \$Date: 2013-02-06 13:08:17 -0600 (Wed, 06 Feb 2013) $ * */ /* ***************************************************************************** * * Copyright (c) 2008 - 2013, 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 "heapManager.h" #include "Gnb.h" #include "GnbPcie.h" #include "GnbSbLib.h" #include "GnbCommonLib.h" #include "GnbPcieInitLibV1.h" #include "GnbPcieInitLibV5.h" #include "GnbPcieConfig.h" #include "GnbPcieTrainingV2.h" #include "GnbNbInitLibV4.h" #include "GnbNbInitLibV1.h" #include "GnbNbInitLibV5.h" #include "PcieComplexDataKB.h" #include "PcieLibKB.h" #include "GnbRegistersKB.h" #include "GnbRegisterAccKB.h" #include "GnbF1Table.h" #include "Filecode.h" #define FILECODE PROC_GNB_MODULES_GNBINITKB_PCIELIBKB_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 *---------------------------------------------------------------------------------------- */ PCIE_LINK_SPEED_CAP PcieGetLinkSpeedCapKB ( IN UINT32 Flags, IN PCIe_ENGINE_CONFIG *Engine ); UINT32 GnbTimeStampKB ( IN AMD_CONFIG_PARAMS *StdHeader ); UINT8 PcieMaxPayloadKB ( IN PCIe_ENGINE_CONFIG *Engine ); /*----------------------------------------------------------------------------------------*/ /** * PLL powerdown * * * @param[in] Wrapper Pointer to Wrapper config descriptor * @param[in] Pcie Pointer to PICe configuration data area */ VOID PciePifPllConfigureKB ( IN PCIe_WRAPPER_CONFIG *Wrapper, IN PCIe_PLATFORM_CONFIG *Pcie ) { D0F0xE4_PIF_0012_STRUCT D0F0xE4_PIF_0012; IDS_HDT_CONSOLE (GNB_TRACE, "PciePifPllConfigureKB Enter\n"); D0F0xE4_PIF_0012.Value = PcieRegisterRead ( Wrapper, PIF_SPACE (Wrapper->WrapId, 0, D0F0xE4_PIF_0012_ADDRESS), Pcie ); D0F0xE4_PIF_0012.Field.PllRampUpTime = 0x0; if (Wrapper->Features.PowerOffUnusedPlls != 0) { D0F0xE4_PIF_0012.Field.PllPowerStateInOff = PifPowerStateOff; D0F0xE4_PIF_0012.Field.PllPowerStateInTxs2 = PifPowerStateOff; } else { D0F0xE4_PIF_0012.Field.PllPowerStateInOff = PifPowerStateL0; D0F0xE4_PIF_0012.Field.PllPowerStateInTxs2 = PifPowerStateL0; } if (Wrapper->Features.PllOffInL1 != 0) { D0F0xE4_PIF_0012.Field.TxPowerStateInTxs2 = PifPowerStateLS2; D0F0xE4_PIF_0012.Field.RxPowerStateInRxs2 = PifPowerStateLS2; } else { D0F0xE4_PIF_0012.Field.TxPowerStateInTxs2 = PifPowerStateL0; D0F0xE4_PIF_0012.Field.RxPowerStateInRxs2 = PifPowerStateL0; } PcieRegisterWrite ( Wrapper, PIF_SPACE (Wrapper->WrapId, 0, D0F0xE4_PIF_0012_ADDRESS), D0F0xE4_PIF_0012.Value, TRUE, Pcie ); PcieRegisterWrite ( Wrapper, PIF_SPACE (Wrapper->WrapId, 0, D0F0xE4_PIF_0012_ADDRESS + 1), D0F0xE4_PIF_0012.Value, TRUE, Pcie ); IDS_HDT_CONSOLE (GNB_TRACE, "PciePifPllConfigureKB Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Power down unused lanes and plls * * * @param[in] Wrapper Pointer to wrapper config descriptor * @param[in] Pcie Pointer to global PCIe configuration */ VOID PciePwrPowerDownUnusedLanesKB ( IN PCIe_WRAPPER_CONFIG *Wrapper, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 UnusedLanes; IDS_HDT_CONSOLE (GNB_TRACE, "PciePwrPowerDownUnusedLanesKB Enter\n"); if (Wrapper->Features.PowerOffUnusedLanes != 0) { UnusedLanes = PcieUtilGetWrapperLaneBitMap (LANE_TYPE_CORE_ALL, LANE_TYPE_PCIE_CORE_ALLOC_ACTIVE, Wrapper); PcieTopologyLaneControlV5 ( DisableLanes, UnusedLanes, Wrapper, Pcie ); } IDS_HDT_CONSOLE (GNB_TRACE, "PciePwrPowerDownUnusedLanesKB Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * Request boot up voltage * * * * @param[in] LinkCap Global GEN capability * @param[in] Pcie Pointer to PCIe configuration data area */ VOID PcieSetVoltageKB ( IN PCIE_LINK_SPEED_CAP LinkCap, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT8 TargetVid; UINT8 MinVidIndex; UINT8 PP_FUSE_ARRAY_V2_fld32[5]; UINT8 Index; PP_F1_ARRAY_V2 *PpF1Array; UINT32 Millivolt; UINT32 D0F0xBC_xC0104007; UINT32 D0F0xBC_xC0104008; UINT32 D0F0xBC_xC010407C; UINT32 D0F0xBC_xC0107064; IDS_HDT_CONSOLE (GNB_TRACE, "PcieSetVoltageKB Enter\n"); PpF1Array = GnbLocateHeapBuffer (AMD_PP_F1_TABLE_HANDLE, GnbLibGetHeader (Pcie)); if (PpF1Array == NULL) { GnbRegisterReadKB (GnbGetHandle (GnbLibGetHeader (Pcie)), 0x4, 0xC0104007, &D0F0xBC_xC0104007, 0, GnbLibGetHeader (Pcie)); GnbRegisterReadKB (GnbGetHandle (GnbLibGetHeader (Pcie)), 0x4, 0xC0104008, &D0F0xBC_xC0104008, 0, GnbLibGetHeader (Pcie)); GnbRegisterReadKB (GnbGetHandle (GnbLibGetHeader (Pcie)), 0x4, 0xC010407C, &D0F0xBC_xC010407C, 0, GnbLibGetHeader (Pcie)); GnbRegisterReadKB (GnbGetHandle (GnbLibGetHeader (Pcie)), 0x4, 0xC0107064, &D0F0xBC_xC0107064, 0, GnbLibGetHeader (Pcie)); PP_FUSE_ARRAY_V2_fld32[0] = (UINT8) ((D0F0xBC_xC0104007 >> 5) & 0xFF); PP_FUSE_ARRAY_V2_fld32[1] = (UINT8) ((D0F0xBC_xC0104008 >> 5) & 0xFF); PP_FUSE_ARRAY_V2_fld32[2] = (UINT8) ((D0F0xBC_xC0104008 >> 13) & 0xFF); PP_FUSE_ARRAY_V2_fld32[3] = (UINT8) ((D0F0xBC_xC0104008 >> 21) & 0xFF); PP_FUSE_ARRAY_V2_fld32[4] = (UINT8) ((D0F0xBC_xC010407C >> 20) & 0xFF); Index = (UINT8) ((D0F0xBC_xC0107064 >> 11) & 7); } else { PP_FUSE_ARRAY_V2_fld32[0] = PpF1Array->PP_FUSE_ARRAY_V2_fld32[0]; PP_FUSE_ARRAY_V2_fld32[1] = PpF1Array->PP_FUSE_ARRAY_V2_fld32[1]; PP_FUSE_ARRAY_V2_fld32[2] = PpF1Array->PP_FUSE_ARRAY_V2_fld32[2]; PP_FUSE_ARRAY_V2_fld32[3] = PpF1Array->PP_FUSE_ARRAY_V2_fld32[3]; PP_FUSE_ARRAY_V2_fld32[4] = PpF1Array->PP_FUSE_ARRAY_V2_fld32[4]; Index = PpF1Array->PcieGen2Vid; } if (LinkCap > PcieGen1) { ASSERT (PP_FUSE_ARRAY_V2_fld32[Index] != 0); TargetVid = PP_FUSE_ARRAY_V2_fld32[Index]; } else { MinVidIndex = 0; for (Index = 0; Index < 5; Index++) { if (PP_FUSE_ARRAY_V2_fld32[Index] > PP_FUSE_ARRAY_V2_fld32[MinVidIndex]) { MinVidIndex = (UINT8) Index; } } ASSERT (PP_FUSE_ARRAY_V2_fld32[MinVidIndex] != 0); TargetVid = PP_FUSE_ARRAY_V2_fld32[MinVidIndex]; } IDS_HDT_CONSOLE (PCIE_MISC, " Set Voltage for Gen %d, Vid code %d\n", LinkCap, TargetVid); Millivolt = GnbTranslateVidCodeToMillivoltV5 (TargetVid, GnbLibGetHeader (Pcie)) * 4 / 100; GnbRegisterWriteKB (GnbGetHandle (GnbLibGetHeader (Pcie)), TYPE_SMU_MSG, SMC_MSG_VDDNB_REQUEST, &Millivolt, 0, GnbLibGetHeader (Pcie)); IDS_HDT_CONSOLE (GNB_TRACE, "PcieSetVoltageKB Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * PLL power up latency * * * @param[in] Wrapper Pointer to Wrapper config descriptor * @param[in] Pcie Pointer to PICe configuration data area * @retval Pll wake up latency in us */ UINT8 PciePifGetPllPowerUpLatencyKB ( IN PCIe_WRAPPER_CONFIG *Wrapper, IN PCIe_PLATFORM_CONFIG *Pcie ) { return 35; } /*----------------------------------------------------------------------------------------*/ /** * Get max link speed capability supported by this port * * * * @param[in] Flags See Flags PCIE_PORT_GEN_CAP_BOOT / PCIE_PORT_GEN_CAP_MAX * @param[in] Engine Pointer to engine config descriptor * @retval PcieGen1/PcieGen2 Max supported link gen capability */ PCIE_LINK_SPEED_CAP PcieGetLinkSpeedCapKB ( IN UINT32 Flags, IN PCIe_ENGINE_CONFIG *Engine ) { PCIE_LINK_SPEED_CAP LinkSpeedCapability; PCIe_WRAPPER_CONFIG *Wrapper; PCIe_PLATFORM_CONFIG *Pcie; Wrapper = PcieConfigGetParentWrapper (Engine); Pcie = PcieConfigGetPlatform (Wrapper); LinkSpeedCapability = PcieGen2; if (Engine->Type.Port.PortData.LinkSpeedCapability == PcieGenMaxSupported) { Engine->Type.Port.PortData.LinkSpeedCapability = (UINT8) LinkSpeedCapability; } if (Pcie->PsppPolicy == PsppPowerSaving) { LinkSpeedCapability = PcieGen1; } if (Engine->Type.Port.PortData.LinkSpeedCapability < LinkSpeedCapability) { LinkSpeedCapability = Engine->Type.Port.PortData.LinkSpeedCapability; } if ((Flags & PCIE_PORT_GEN_CAP_BOOT) != 0) { if (( Pcie->PsppPolicy == PsppBalanceLow || Engine->Type.Port.PortData.MiscControls.LinkSafeMode == PcieGen1) && !PcieConfigIsSbPcieEngine (Engine)) { LinkSpeedCapability = PcieGen1; } } return LinkSpeedCapability; } /*----------------------------------------------------------------------------------------*/ /** * Family specific time stamp function * * * @param[in] StdHeader Standard configuration header * @retval Count */ UINT32 GnbTimeStampKB ( IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 TimeStamp; TimeStamp = 0; GnbLibPciIndirectRead ( MAKE_SBDFO (0, 0, 0, 0, 0xE0), 0x13080F0, AccessWidth32, &TimeStamp, StdHeader ); IDS_HDT_CONSOLE (GNB_TRACE, "GnbTsKb: %08x\n", TimeStamp); return TimeStamp; } /*----------------------------------------------------------------------------------------*/ /** * Limit MaxPayload to 256 for x1 ports * * * * @param[in] Engine Pointer to engine config descriptor * @retval MaxPayload MaxPayloadSupport */ UINT8 PcieMaxPayloadKB ( IN PCIe_ENGINE_CONFIG *Engine ) { UINT8 MaxPayload; MaxPayload = MAX_PAYLOAD_512; if (Engine->EngineData.StartLane == Engine->EngineData.EndLane) { MaxPayload = MAX_PAYLOAD_256; } IDS_HDT_CONSOLE (GNB_TRACE, "PcieMaxPayloadKB Exit with MaxPayload = %d for StartLane = %d and EndLane = %d\n", MaxPayload, Engine->EngineData.StartLane, Engine->EngineData.EndLane); return MaxPayload; } /*----------------------------------------------------------------------------------------*/ /** * Select master PLL * * * * @param[in] Wrapper Pointer to wrapper config descriptor * @param[out] ConfigChanged Pointer to boolean indicator that configuration was changed * @param[in] Pcie Pointer to global PCIe configuration */ VOID PcieTopologySelectMasterPllKB ( IN PCIe_WRAPPER_CONFIG *Wrapper, OUT BOOLEAN *ConfigChanged, IN PCIe_PLATFORM_CONFIG *Pcie ) { PCIe_ENGINE_CONFIG *EngineList; UINT16 MasterLane; UINT16 MasterHotplugLane; UINT16 EngineMasterLane; D0F0xE4_WRAP_8013_STRUCT D0F0xE4_WRAP_8013; D0F0xE4_WRAP_8013_STRUCT D0F0xE4_WRAP_8013_BASE; IDS_HDT_CONSOLE (GNB_TRACE, "PcieTopologySelectMasterPll Enter\n"); MasterLane = 0xFFFF; MasterHotplugLane = 0xFFFF; EngineList = PcieConfigGetChildEngine (Wrapper); while (EngineList != NULL) { if (PcieConfigIsEngineAllocated (EngineList) && EngineList->Type.Port.PortData.PortPresent != PortDisabled && PcieConfigIsPcieEngine (EngineList)) { EngineMasterLane = PcieConfigGetPcieEngineMasterLane (EngineList); if (EngineList->Type.Port.PortData.LinkHotplug != HotplugDisabled) { MasterHotplugLane = (EngineMasterLane < MasterHotplugLane) ? EngineMasterLane : MasterHotplugLane; } else { MasterLane = (EngineMasterLane < MasterLane) ? EngineMasterLane : MasterLane; if (PcieConfigIsSbPcieEngine (EngineList)) { break; } } } EngineList = PcieLibGetNextDescriptor (EngineList); } if (MasterLane == 0xffff) { if (MasterHotplugLane != 0xffff) { MasterLane = MasterHotplugLane; } else { MasterLane = 0x0; } } D0F0xE4_WRAP_8013.Value = PcieRegisterRead ( Wrapper, WRAP_SPACE (Wrapper->WrapId, D0F0xE4_WRAP_8013_ADDRESS), Pcie ); D0F0xE4_WRAP_8013_BASE.Value = D0F0xE4_WRAP_8013.Value; if (MasterLane <= 3 ) { Wrapper->MasterPll = GNB_PCIE_MASTERPLL_A; } else { Wrapper->MasterPll = GNB_PCIE_MASTERPLL_B; } IDS_OPTION_HOOK (IDS_GNB_PCIE_MASTERPLL_SELECTION, &(Wrapper->MasterPll), GnbLibGetHeader (Pcie)); if (Wrapper->MasterPll == GNB_PCIE_MASTERPLL_A) { D0F0xE4_WRAP_8013.Field.MasterPciePllA = 0x1; D0F0xE4_WRAP_8013.Field.MasterPciePllB = 0x0; } else { D0F0xE4_WRAP_8013.Field.MasterPciePllA = 0x0; D0F0xE4_WRAP_8013.Field.MasterPciePllB = 0x1; } if (ConfigChanged != NULL) { *ConfigChanged = (D0F0xE4_WRAP_8013.Value == D0F0xE4_WRAP_8013_BASE.Value) ? FALSE : TRUE; } PcieRegisterWrite ( Wrapper, WRAP_SPACE (Wrapper->WrapId, D0F0xE4_WRAP_8013_ADDRESS), D0F0xE4_WRAP_8013.Value, FALSE, Pcie ); IDS_HDT_CONSOLE (GNB_TRACE, "PcieTopologySelectMasterPll Exit\n"); }