blob: 9934159219a6d53fa1ae69a7770bd65c1de997df [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* Config Fch Gpp controller
*
* Init Gpp Controller features.
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: FCH
* @e \$Revision: 49753 $ @e \$Date: 2011-03-29 04:51:46 +0800 (Tue, 29 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.
****************************************************************************
*/
#include "FchPlatform.h"
#include "Ids.h"
#include "Filecode.h"
#define FILECODE PROC_FCH_PCIE_GPPENV_FILECODE
//
// Declaration of local functions
//
VOID FchGppRasInitialization (IN FCH_DATA_BLOCK* FchDataPtr);
VOID FchGppAerInitialization (IN FCH_DATA_BLOCK* FchDataPtr);
VOID PreInitGppLink (IN FCH_DATA_BLOCK* FchDataPtr);
UINT8 CheckGppLinkStatus (IN FCH_DATA_BLOCK* FchDataPtr);
VOID AfterGppLinkInit (IN FCH_DATA_BLOCK* FchDataPtr);
//
//-----------------------------------------------------------------------------------
// Early GPP initialization sequence:
//
// 1) Set port enable bit fields by current GPP link configuration mode
// 2) Deassert GPP reset and pull EP out of reset - Clear GPP_RESET (abcfg:0xC0[8] = 0)
// 3) Loop polling for the link status of all ports
// 4) Misc operations after link training:
// - (optional) Detect GFX device
// - Hide empty GPP configuration spaces (Disable empty GPP ports)
// - (optional) Power down unused GPP ports
// - (optional) Configure PCIE_P2P_Int_Map (abcfg:0xC4[7:0])
// 5) GPP init completed
//
//
// *) Gen2 vs Gen1
// Gen2 mode Gen1 mode
// ---------------------------------------------------------------
// STRAP_PHY_PLL_CLKF[6:0] 7'h32 7'h19
// STRAP_BIF_GEN2_EN 1 0
//
// PCIE_PHY_PLL clock locks @ 5GHz
//
//
/**
* FchInitEnvGpp - Config Gpp controller before PCI emulation
*
* - GppEarlyInit
*
* @param[in] FchDataPtr Fch configuration structure pointer.
*
*/
VOID
FchInitEnvGpp (
IN VOID *FchDataPtr
)
{
//
// GppEarlyInit
//
UINT8 FchGppMemWrImprove;
UINT8 FchGppLaneReversal;
UINT8 FchAlinkPhyPllPowerDown;
UINT32 AbValue;
FCH_DATA_BLOCK *LocalCfgPtr;
AMD_CONFIG_PARAMS *StdHeader;
LocalCfgPtr = (FCH_DATA_BLOCK *) FchDataPtr;
StdHeader = LocalCfgPtr->StdHeader;
FchGppMemWrImprove = LocalCfgPtr->Gpp.GppMemWrImprove;
FchGppLaneReversal = (UINT8) LocalCfgPtr->Gpp.GppLaneReversal;
FchAlinkPhyPllPowerDown = (UINT8) LocalCfgPtr->Ab.UmiPhyPllPowerDown;
OutPort80 (0x90, StdHeader);
//
// Configure NB-FCH link PCIE PHY PLL power down for L1
//
if ( FchAlinkPhyPllPowerDown == TRUE ) {
//
// Set PCIE_P_CNTL in Alink PCIEIND space
//
WriteAlink (FCH_AX_INDXC_REG30 | (UINT32) (AXINDC << 29), 0x40, StdHeader);
AbValue = ReadAlink (FCH_AX_DATAC_REG34 | (UINT32) (AXINDC << 29), StdHeader);
AbValue |= BIT12 + BIT3 + BIT0;
AbValue &= ~(BIT9 + BIT4);
WriteAlink (FCH_AX_DATAC_REG34 | (UINT32) (AXINDC << 29), AbValue, StdHeader);
RwAlink (FCH_AX_INDXC_REG02 | (UINT32) (AXINDC << 29), ~(BIT8), (BIT8), StdHeader);
RwAlink (FCH_AX_INDXC_REG02 | (UINT32) (AXINDC << 29), ~(BIT3), (BIT3), StdHeader);
}
//
// AXINDC_Reg 0xA4[18] = 0x1
//
WriteAlink (FCH_AX_INDXP_REG38 | (UINT32) (AXINDP << 29), 0xA4, StdHeader);
AbValue = ReadAlink (FCH_AX_DATAP_REG3C | (UINT32) (AXINDP << 29), StdHeader);
AbValue |= BIT18;
WriteAlink (FCH_AX_DATAP_REG3C | (UINT32) (AXINDP << 29), AbValue, StdHeader);
//
// Set ABCFG 0x031C[0] = 1 to enable lane reversal
//
AbValue = ReadAlink (FCH_ABCFG_REG31C | (UINT32) (ABCFG << 29), StdHeader);
if ( FchGppLaneReversal ) {
WriteAlink (FCH_ABCFG_REG31C | (UINT32) (ABCFG << 29), AbValue | BIT0, StdHeader);
} else {
WriteAlink (FCH_ABCFG_REG31C | (UINT32) (ABCFG << 29), AbValue | 0x00, StdHeader);
}
//
// Set abcfg:0x90[20] = 1 to enable GPP bridge multi-function
//
AbValue = ReadAlink (FCH_ABCFG_REG90 | (UINT32) (ABCFG << 29), StdHeader);
WriteAlink (FCH_ABCFG_REG90 | (UINT32) (ABCFG << 29), AbValue | BIT20, StdHeader);
//
// Initialize and configure GPP
//
if (LocalCfgPtr->Gpp.GppFunctionEnable) {
ProgramGppTogglePcieReset (LocalCfgPtr->Gpp.GppToggleReset, StdHeader);
FchGppAerInitialization (LocalCfgPtr);
FchGppRasInitialization (LocalCfgPtr);
//
// PreInit - Enable GPP link training
//
PreInitGppLink (LocalCfgPtr);
//
// GPP Upstream Memory Write Arbitration Enhancement ABCFG 0x54[26] = 1
// GPP Memory Write Max Payload Improvement RCINDC_Reg 0x10[12:10] = 0x4
//
if ( FchGppMemWrImprove == TRUE ) {
RwAlink (FCH_ABCFG_REG54 | (UINT32) (ABCFG << 29), ~BIT26, (BIT26), StdHeader);
RwAlink (FCH_RCINDXC_REG10 | (UINT32) (RCINDXC << 29), ~(BIT12 + BIT11 + BIT10), (BIT12), StdHeader);
}
if (CheckGppLinkStatus (LocalCfgPtr) && !LocalCfgPtr->Misc.S3Resume) {
//
// Toggle GPP reset (Note this affects all Hudson-2 GPP ports)
//
ProgramGppTogglePcieReset (LocalCfgPtr->Gpp.GppToggleReset, StdHeader);
}
//
// Misc operations after link training
//
AfterGppLinkInit (LocalCfgPtr);
}
FchGppDynamicPowerSaving (LocalCfgPtr);
OutPort80 (0x9F, StdHeader);
}
/**
* FchGppAerInitialization - Initializing AER
*
*
* @param[in] FchDataPtr
*
*/
VOID
FchGppAerInitialization (
IN FCH_DATA_BLOCK *FchDataPtr
)
{
AMD_CONFIG_PARAMS *StdHeader;
StdHeader = FchDataPtr->StdHeader;
if (FchDataPtr->Gpp.PcieAer) {
//
// GPP strap configuration
//
RwAlink (FCH_ABCFG_REG310 | (UINT32) (ABCFG << 29), ~(BIT7 + BIT4), BIT28 + BIT27 + BIT26 + BIT1, StdHeader);
RwAlink (FCH_ABCFG_REG314 | (UINT32) (ABCFG << 29), ~(UINT32) (0xfff << 15), 0, StdHeader);
//
// AB strap configuration
//
RwAlink (FCH_ABCFG_REGF0 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT15 + BIT14, StdHeader);
RwAlink (FCH_ABCFG_REGF4 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT3, StdHeader);
} else {
//
// Hard System Hang running MeatGrinder Test on multiple blocks
// GPP Error Reporting Configuration
RwAlink (FCH_ABCFG_REGF0 | (UINT32) (ABCFG << 29), ~(BIT1), 0, StdHeader);
}
}
/**
* FchGppRasInitialization - Initializing RAS
*
*
* @param[in] FchDataPtr
*
*/
VOID
FchGppRasInitialization (
IN FCH_DATA_BLOCK *FchDataPtr
)
{
if (FchDataPtr->Gpp.PcieRas) {
RwAlink (FCH_ABCFG_REGF4 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT0, FchDataPtr->StdHeader);
}
}
/**
* PreInitGppLink - Enable GPP link training.
*
*
*
* @param[in] FchDataPtr Fch configuration structure pointer.
*
*/
VOID
PreInitGppLink (
IN FCH_DATA_BLOCK *FchDataPtr
)
{
GPP_LINKMODE CfgMode;
UINT8 PortId;
UINT32 GppPortCfg;
UINT16 Tmp16Value;
FCH_GPP_PORT_CONFIG *PortCfg;
AMD_CONFIG_PARAMS *StdHeader;
UINT8 PortMask[5] = {
0x01,
0x00,
0x03,
0x07,
0x0F
};
//
// PCIE_GPP_ENABLE (abcfg:0xC0):
//
// GPP_LINK_CONFIG ([3:0]) PortA PortB PortC PortD Description
// ----------------------------------------------------------------------------------
// 0000 0-3 x4 Config
// 0001 N/A
// 0010 0-1 2-3 0 2:2 Config
// 0011 0-1 2 3 2:1:1 Config
// 0100 0 1 2 3 1:1:1:1 Config
//
// For A12 and above:
// ABCFG:0xC0[12] - Port A hold training (default 1)
// ABCFG:0xC0[13] - Port B hold training (default 1)
// ABCFG:0xC0[14] - Port C hold training (default 1)
// ABCFG:0xC0[15] - Port D hold training (default 1)
//
//
//
// Set port enable bit fields based on current GPP link configuration mode
//
CfgMode = FchDataPtr->Gpp.GppLinkConfig;
StdHeader = FchDataPtr->StdHeader;
ASSERT (CfgMode == PortA4 || CfgMode == PortA2B2 || CfgMode == PortA2B1C1 || CfgMode == PortA1B1C1D1);
GppPortCfg = (UINT32) PortMask[CfgMode];
//
// Mask out non-applicable ports according to the target link configuration mode
//
for ( PortId = 0; PortId < MAX_GPP_PORTS; PortId++ ) {
FchDataPtr->Gpp.PortCfg[PortId].PortPresent &= (UINT8 ) (GppPortCfg >> PortId) & BIT0;
}
//
// Deassert GPP reset and pull EP out of reset - Clear GPP_RESET (abcfg:0xC0[8] = 0)
//
Tmp16Value = (UINT16) (~GppPortCfg << 12);
GppPortCfg = (UINT32) (Tmp16Value + (GppPortCfg << 4) + CfgMode);
WriteAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), GppPortCfg, StdHeader);
GppPortCfg = ReadAlink (0xC0 | (UINT32) (RCINDXC << 29), StdHeader);
WriteAlink (0xC0 | (UINT32) (RCINDXC << 29), GppPortCfg | 0x400, StdHeader); /// Set STRAP_F0_MSI_EN
//
// A-Link L1 Entry Delay Shortening
// AXINDP_Reg 0xA0[7:4] = 0x3
// KR Does not need this portion of code.
RwAlink (FCH_AX_INDXP_REGA0, 0xFFFFFF0F, 0x30, StdHeader);
RwAlink (FCH_AX_INDXP_REGB1, 0xFFFFFFFF, BIT19, StdHeader);
RwAlink (FCH_AX_INDXP_REGB1, 0xFFFFFFFF, BIT28, StdHeader);
//
// GPP L1 Entry Delay Shortening
// RCINDP_Reg 0xA0[7:4] = 0x1 Enter L1 sooner after ACK'ing PM request.
// This is done to reduce number of NAK received with L1 enabled.
//
for ( PortId = 0; PortId < MAX_GPP_PORTS; PortId++ ) {
RwAlink (FCH_RCINDXP_REGA0 | PortId << 24, 0xFFFFFF0F, 0x10, StdHeader);
// Hard System Hang running MeatGrinder Test on multiple blocks
// GPP Error Reporting Configuration
RwAlink (FCH_RCINDXP_REG6A | PortId << 24, ~(BIT1), 0, StdHeader);
}
if (FchDataPtr->Misc.S3Resume) {
for ( PortId = 0; PortId < MAX_GPP_PORTS; PortId++ ) {
PortCfg = &FchDataPtr->Gpp.PortCfg[PortId];
if (PortCfg->PortHotPlug == TRUE) {
PortCfg->PortDetected = FALSE;
} else {
if (PortCfg->PortIsGen2 == 1) {
FchGppForceGen1 (FchDataPtr, (UINT8) (1 << PortId));
} else {
FchGppForceGen2 (FchDataPtr, (UINT8) (1 << PortId));
}
}
}
}
//
// Obtain original Gen2 strap value (LC_GEN2_EN_STRAP)
//
FchDataPtr->Gpp.GppGen2Strap = (UINT8) (ReadAlink (FCH_RCINDXP_REGA4 | 0 << 24, StdHeader) & BIT0);
}
/**
* CheckGppLinkStatus - loop polling the link status for each GPP port
*
*
* Return: ToggleStatus[3:0] = Port bitmap for those need to clear De-emphasis
*
* @param[in] FchDataPtr Fch configuration structure pointer.
*
*/
UINT8
CheckGppLinkStatus (
IN FCH_DATA_BLOCK *FchDataPtr
)
{
UINT32 PortId;
UINT8 PortScanMap;
UINT8 GppHwDowngrade;
FCH_GPP_PORT_CONFIG *PortCfg;
UINT8 FailedPorts;
PortScanMap = 0;
FailedPorts = 0;
//
// Obtain a list of ports to be checked
//
for ( PortId = 0; PortId < MAX_GPP_PORTS; PortId++ ) {
PortCfg = &FchDataPtr->Gpp.PortCfg[PortId];
if ( PortCfg->PortPresent == TRUE && PortCfg->PortDetected == FALSE ) {
PortScanMap |= 1 << PortId;
}
}
GppHwDowngrade = (UINT8)FchDataPtr->Gpp.GppHardwareDownGrade;
if (GppHwDowngrade != 0) {
//
// Skip polling and always assume this port to be present
//
PortScanMap &= ~(1 << (GppHwDowngrade - 1));
}
//
//GPP Gen2 Speed Change
// if ((GPP Gen2 == enabled) and (RCINDP_Reg 0xA4[0] == 0x1)) {
// PCIe_Cfg 0x88[3:0] = 0x2
// RCINDP_Reg 0xA2[13] = 0x0
// RCINDP_Reg 0xC0[15] = 0x0
// RCINDP_Reg 0xA4[29] = 0x1
// } else {
// PCIe_Cfg 0x88[3:0] = 0x1
// RCINDP_Reg 0xA4[0] = 0x0
// RCINDP_Reg 0xA2[13] = 0x1
// RCINDP_Reg 0xC0[15] = 0x0
// RCINDP_Reg 0xA4[29] = 0x1
// }
//
FchStall (5000, FchDataPtr->StdHeader);
if (FchDataPtr->Gpp.GppGen2 && FchDataPtr->Gpp.GppGen2Strap) {
FchGppForceGen2 (FchDataPtr, PortScanMap);
FailedPorts = GppPortPollingLtssm (FchDataPtr, PortScanMap, TRUE);
if (FailedPorts) {
FchGppForceGen1 (FchDataPtr, FailedPorts);
FailedPorts = GppPortPollingLtssm (FchDataPtr, FailedPorts, FALSE);
}
} else {
FchGppForceGen1 (FchDataPtr, PortScanMap);
FailedPorts = GppPortPollingLtssm (FchDataPtr, PortScanMap, FALSE);
}
return FailedPorts;
}
/**
* AfterGppLinkInit
* - Search for display device behind each GPP port
* - If the port is empty AND not hotplug-capable:
* * Turn off link training
* * (optional) Power down the port
* * Hide the configuration space (Turn off the port)
*
* @param[in] FchDataPtr Fch configuration structure pointer.
*
*/
VOID
AfterGppLinkInit (
IN FCH_DATA_BLOCK *FchDataPtr
)
{
UINT32 PortId;
FCH_GPP_PORT_CONFIG *PortCfg;
UINT32 RegBusNumber;
UINT32 AbValue;
UINT32 AbIndex;
UINT8 Value;
UINT8 FchGppGen2;
AMD_CONFIG_PARAMS *StdHeader;
StdHeader = FchDataPtr->StdHeader;
FchGppGen2 = FchDataPtr->Gpp.GppGen2;
FchDataPtr->Gpp.GppFoundGfxDev = 0;
AbValue = ReadAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), StdHeader);
//
// Link Bandwidth Notification Capability Enable
//RCINDC:0xC1[0] = 1
//
RwAlink (FCH_RCINDXC_REGC1, 0xFFFFFFFF, BIT0, StdHeader);
for ( PortId = 0; PortId < MAX_GPP_PORTS; PortId++ ) {
//
// Program requester ID for every port
//
AbIndex = FCH_RCINDXP_REG21 | (UINT32) (RCINDXP << 29) | (PortId << 24);
WriteAlink (AbIndex, (FCH_GPP_DEV << 3) + PortId, StdHeader);
//
// Link Bandwidth Notification Capability Enable
//PCIe Cfg 0x68[10] = 0
//PCIe Cfg 0x68[11] = 0
//
RwPci (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x68), AccessWidth16, ~(BIT10 + BIT11), 0, StdHeader);
PortCfg = &FchDataPtr->Gpp.PortCfg[PortId];
//
// Check if there is GFX device behind each GPP port
//
if ( PortCfg->PortDetected == TRUE ) {
RegBusNumber = (SBTEMP_BUS << 16) + (SBTEMP_BUS << 8);
WritePci (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x18), AccessWidth32, &RegBusNumber, StdHeader);
ReadPci (PCI_ADDRESS (SBTEMP_BUS, 0, 0, 0x0B), AccessWidth8, &Value, StdHeader);
if ( Value == 3 ) {
FchDataPtr->Gpp.GppFoundGfxDev |= (1 << PortId);
}
RegBusNumber = 0;
WritePci (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x18), AccessWidth32, &RegBusNumber, StdHeader);
} else if ( PortCfg->PortPresent == FALSE || PortCfg->PortHotPlug == FALSE ) {
//
// Mask off non-applicable ports
//
AbValue &= ~(1 << (PortId + 4));
}
if ( PortCfg->PortHotPlug == TRUE ) {
//
// Hot Plug: PCIe Native Support
// RCINDP_Reg 0x10[3] = 0x1
// PCIe_Cfg 0x5A[8] = 0x1
// PCIe_Cfg 0x6C[6] = 0x1
// RCINDP_Reg 0x20[19] = 0x0
//
RwAlink ((FCH_RCINDXP_REG10 | (UINT32) (RCINDXP << 29) | (PortId << 24)), 0xFFFFFFFF, BIT3, StdHeader);
RwPci (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x5b), AccessWidth8, 0xff, BIT0, StdHeader);
RwPci (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x6c), AccessWidth8, 0xff, BIT6, StdHeader);
RwAlink ((FCH_RCINDXP_REG20 | (UINT32) (RCINDXP << 29) | (PortId << 24)), ~BIT19, 0, StdHeader);
}
}
if ( FchDataPtr->Gpp.GppUnhidePorts == FALSE ) {
if ((AbValue & 0xF0) == 0) {
AbValue = BIT8; /// if all ports are empty set GPP_RESET
} else if ((AbValue & 0xE0) != 0 && (AbValue & 0x10) == 0) {
AbValue |= BIT4; /// PortA should always be visible whenever other ports are exist
}
//
// Update GPP_Portx_Enable (abcfg:0xC0[7:5])
//
WriteAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), AbValue, StdHeader);
}
//
// Common initialization for open GPP ports
//
for ( PortId = 0; PortId < MAX_GPP_PORTS; PortId++ ) {
ReadPci (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x80), AccessWidth8, &Value, StdHeader);
if (Value != 0xff) {
//
// Set pciCfg:PCIE_DEVICE_CNTL2[3:0] = 4'h6 (0x80[3:0])
//
Value &= 0xf0;
Value |= 0x06;
WritePci (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x80), AccessWidth8, &Value, StdHeader);
//
// Set PCIEIND_P:PCIE_RX_CNTL[RX_RCB_CPL_TIMEOUT_MODE] (0x70:[19]) = 1
//
AbIndex = FCH_RCINDXP_REG70 | (UINT32) (RCINDXP << 29) | (PortId << 24);
AbValue = ReadAlink (AbIndex, StdHeader) | BIT19;
WriteAlink (AbIndex, AbValue, StdHeader);
//
// Set PCIEIND_P:PCIE_TX_CNTL[TX_FLUSH_TLP_DIS] (0x20:[19]) = 0
//
AbIndex = FCH_RCINDXP_REG20 | (UINT32) (RCINDXP << 29) | (PortId << 24);
AbValue = ReadAlink (AbIndex, StdHeader) & ~BIT19;
WriteAlink (AbIndex, AbValue, StdHeader);
}
}
}