From ee39ea7e7edf9699f1bae1b2708ad6816f054817 Mon Sep 17 00:00:00 2001 From: efdesign98 Date: Thu, 16 Jun 2011 16:39:30 -0700 Subject: Add AMD SB900 CIMx code This code is added to support the AMD SB900 southbridge. Change-Id: I7dc5e13a53ffd479dcea4e05e8c8631096e2ba91 Signed-off-by: Frank Vibrans Signed-off-by: efdesign98 Reviewed-on: http://review.coreboot.org/41 Tested-by: build bot (Jenkins) Reviewed-by: Marc Jones --- src/vendorcode/amd/cimx/sb900/Gpp.c | 1109 +++++++++++++++++++++++++++++++++++ 1 file changed, 1109 insertions(+) create mode 100755 src/vendorcode/amd/cimx/sb900/Gpp.c (limited to 'src/vendorcode/amd/cimx/sb900/Gpp.c') diff --git a/src/vendorcode/amd/cimx/sb900/Gpp.c b/src/vendorcode/amd/cimx/sb900/Gpp.c new file mode 100755 index 0000000000..b87bd87032 --- /dev/null +++ b/src/vendorcode/amd/cimx/sb900/Gpp.c @@ -0,0 +1,1109 @@ + +/** + * @file + * + * Config Southbridge GPP controller + * + * Init GPP features. + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: CIMx-SB + * @e sub-project + * @e \$Revision:$ @e \$Date:$ + * + */ +/* +***************************************************************************** +* +* 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 "SbPlatform.h" +#include "cbtypes.h" +#include "AmdSbLib.h" + +/** + * PCIE_CAP_ID - PCIe Cap ID + * + */ +#define PCIE_CAP_ID 0x10 + +// +// Declaration of local functions +// +UINT8 +sbFindPciCap ( + IN UINT32 pciAddress, + IN UINT8 targetCapId + ); + +VOID +sbGppSetAspm ( + IN UINT32 pciAddress, + IN UINT8 LxState + ); + +VOID +sbGppSetEPAspm ( + IN UINT32 pciAddress, + IN UINT8 LxState + ); + +VOID +sbGppValidateAspm ( + IN UINT32 pciAddress, + IN UINT8 *LxState + ); + +VOID +sbGppForceGen2 ( + IN AMDSBCFG *pConfig, + IN CONST UINT8 ActivePorts + ); + +VOID +sbGppForceGen1 ( + IN AMDSBCFG *pConfig, + IN CONST UINT8 ActivePorts + ); + +VOID +PreInitGppLink ( + IN AMDSBCFG* pConfig + ); + +UINT8 +GppPortPollingLtssm ( + IN AMDSBCFG* pConfig, + IN UINT8 ActivePorts, + IN BOOLEAN IsGen2 + ); + +UINT8 +CheckGppLinkStatus ( + IN AMDSBCFG* pConfig + ); + +VOID +AfterGppLinkInit ( + IN AMDSBCFG* pConfig + ); + +VOID +sbGppDynamicPowerSaving ( + IN AMDSBCFG* pConfig + ); + +VOID +sbGppAerInitialization ( + IN AMDSBCFG* pConfig + ); + +VOID +sbGppRasInitialization ( + IN AMDSBCFG* pConfig + ); + +// +// Declaration of external functions +// + + +/** + * sbFindPciCap - Find PCI Cap + * + * + * @param[in] pciAddress PCI Address. + * @param[in] targetCapId Target Cap ID. + * + */ +UINT8 +sbFindPciCap ( + IN UINT32 pciAddress, + IN UINT8 targetCapId + ) +{ + UINT8 NextCapPtr; + UINT8 CapId; + + NextCapPtr = 0x34; + while (NextCapPtr != 0) { + ReadPCI (pciAddress + NextCapPtr, AccWidthUint8, &NextCapPtr); + if (NextCapPtr == 0xff) { + return 0; + } + if (NextCapPtr != 0) { + ReadPCI (pciAddress + NextCapPtr, AccWidthUint8, &CapId); + if (CapId == targetCapId) { + break; + } else { + NextCapPtr++; + } + } + } + return NextCapPtr; +} + +/** + * sbGppSetAspm - Set GPP ASPM + * + * + * @param[in] pciAddress PCI Address. + * @param[in] LxState Lane State. + * + */ +VOID +sbGppSetAspm ( + IN UINT32 pciAddress, + IN UINT8 LxState + ) +{ + UINT8 pcieCapOffset; + UINT8 value8; + + pcieCapOffset = sbFindPciCap (pciAddress, PCIE_CAP_ID); + if (pcieCapOffset) { + // Read link capabilities register (0x0C[11:10] - ASPM support) + ReadPCI (pciAddress + pcieCapOffset + 0x0D, AccWidthUint8, &value8); + if (value8 & BIT2) { + value8 = (value8 >> 2) & (BIT1 + BIT0); + // Set ASPM state in link control register + RWPCI (pciAddress + pcieCapOffset + 0x10, AccWidthUint8, 0xffffffff, LxState & value8); + } + } +} + +/** + * sbGppSetEPAspm - Set EP GPP ASPM + * + * + * @param[in] pciAddress PCI Address. + * @param[in] LxState Lane State. + * + */ +VOID +sbGppSetEPAspm ( + IN UINT32 pciAddress, + IN UINT8 LxState + ) +{ + UINT8 value8; + UINT8 maxFuncs; + UINT32 devBDF; + + maxFuncs = 1; + ReadPCI (pciAddress + 0x0E, AccWidthUint8, &value8); + + if (value8 & BIT7) { + maxFuncs = 8; // multi-function device + } + while (maxFuncs != 0) { + devBDF = pciAddress + (UINT32) ((maxFuncs - 1) << 16); + sbGppSetAspm (devBDF, LxState); + maxFuncs--; + } +} + +/** + * sbGppValidateAspm - Validate endpoint support for GPP ASPM + * + * + * @param[in] pciAddress PCI Address. + * @param[in] LxState Lane State. + * + */ +VOID +sbGppValidateAspm ( + IN UINT32 pciAddress, + IN UINT8 *LxState + ) +{ + UINT8 pcieCapOffset; + UINT8 value8; + UINT8 maxFuncs; + UINT32 devBDF; + + maxFuncs = 1; + ReadPCI (pciAddress + 0x0E, AccWidthUint8, &value8); + + if (value8 & BIT7) { + maxFuncs = 8; // multi-function device + } + while (maxFuncs != 0) { + devBDF = pciAddress + (UINT32) ((maxFuncs - 1) << 16); + pcieCapOffset = sbFindPciCap (devBDF, PCIE_CAP_ID); + if (pcieCapOffset) { + // Read link capabilities register (0x0C[11:10] - ASPM support) + ReadPCI (devBDF + pcieCapOffset + 0x0D, AccWidthUint8, &value8); + if (value8 & BIT2) { + value8 = (value8 >> 2) & (BIT1 + BIT0); + // Set ASPM state as what's endpoint support + *LxState &= value8; + } + } + maxFuncs--; + } +} + + +/** + * sbGppForceGen2 - Set GPP to Gen2 + * + * + * @param[in] pConfig Southbridge configuration structure pointer. + * @param[in] ActivePorts Activate Ports. + * + */ +VOID +sbGppForceGen2 ( + IN AMDSBCFG *pConfig, + IN CONST UINT8 ActivePorts + ) +{ + UINT32 portId; + + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + if (ActivePorts & (1 << portId)) { + rwAlink (SB_RCINDXP_REGA4 | portId << 24, 0xFFFFFFFF, BIT29 + BIT0); + rwAlink ((SB_ABCFG_REG340 + portId * 4) | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT21); + rwAlink (SB_RCINDXP_REGA2 | portId << 24, ~BIT13, 0); + rwAlink (SB_RCINDXP_REGC0 | portId << 24, ~BIT15, 0); + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x88), AccWidthUint8, 0xf0, 0x02); + + (&pConfig->PORTCONFIG[portId].PortCfg)->PortIsGen2 = 2; + } + } +} + +/** + * sbGppForceGen1 - Set GPP to Gen1 + * + * + * @param[in] pConfig Southbridge configuration structure pointer. + * @param[in] ActivePorts Activate Ports. + * + */ +VOID +sbGppForceGen1 ( + IN AMDSBCFG *pConfig, + IN CONST UINT8 ActivePorts + ) +{ + UINT32 portId; + + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + if (ActivePorts & (1 << portId) && pConfig->GppHardwareDowngrade != portId + 1) { + rwAlink ((SB_ABCFG_REG340 + portId * 4) | (UINT32) (ABCFG << 29), ~BIT21, 0); + rwAlink (SB_RCINDXP_REGA4 | portId << 24, ~BIT0, BIT29); + rwAlink (SB_RCINDXP_REGA2 | portId << 24, 0xFFFFFFFF, BIT13); + rwAlink (SB_RCINDXP_REGC0 | portId << 24, ~BIT15, 0); + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x88), AccWidthUint8, 0xf0, 0x01); + + (&pConfig->PORTCONFIG[portId].PortCfg)->PortIsGen2 = 1; + } + } +} + + +/** + * PreInitGppLink - Enable GPP link training. + * + * + * + * @param[in] pConfig Southbridge configuration structure pointer. + * + */ +VOID +PreInitGppLink ( + IN AMDSBCFG* pConfig + ) +{ + UINT8 portMask[5] = { + 0x01, + 0x00, + 0x03, + 0x07, + 0x0F + }; + UINT8 cfgMode; + UINT8 portId; + UINT32 reg32Value; + UINT16 tmp16Value; + +// 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 = (UINT8) pConfig->GppLinkConfig; + if ( cfgMode > GPP_CFGMODE_X1111 || cfgMode == 1 ) { + cfgMode = GPP_CFGMODE_X4000; + pConfig->GppLinkConfig = GPP_CFGMODE_X4000; + } + reg32Value = (UINT32) portMask[cfgMode]; + + // Mask out non-applicable ports according to the target link configuration mode + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + pConfig->PORTCONFIG[portId].PortCfg.PortPresent &= (reg32Value >> portId) & BIT0; + } + + // + // Deassert GPP reset and pull EP out of reset - Clear GPP_RESET (abcfg:0xC0[8] = 0) + // + tmp16Value = (UINT16) (~reg32Value << 12); + reg32Value = (UINT32) (tmp16Value + (reg32Value << 4) + cfgMode); + writeAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29), reg32Value); + + reg32Value = readAlink (0xC0 | (UINT32) (RCINDXC << 29)); + writeAlink (0xC0 | (UINT32) (RCINDXC << 29), reg32Value | 0x400); // Set STRAP_F0_MSI_EN + + // A-Link L1 Entry Delay Shortening + // AXINDP_Reg 0xA0[7:4] = 0x3 + rwAlink (SB_AX_INDXP_REGA0, 0xFFFFFF0F, 0x30); + rwAlink (SB_AX_INDXP_REGB1, 0xFFFFFFFF, BIT19); + rwAlink (SB_AX_INDXP_REGB1, 0xFFFFFFFF, BIT28); + + // RPR5.22 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. + // ENH254401: Program L0S/L1 activity timer to enable L0S/L1 on GPP + // RCINDP_Reg 0xA0[11:8] = 0x9 + // RCINDP_Reg 0xA0[15:12] = 0x6 + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + rwAlink (SB_RCINDXP_REGA0 | portId << 24, 0xFFFF000F, 0x6910); + //OBS220313: Hard System Hang running MeatGrinder Test on multiple blocks + //RPR 5.13 GPP Error Reporting Configuration + rwAlink (SB_RCINDXP_REG6A | portId << 24, ~(BIT1), 0); + } + + if (pConfig->S3Resume) { + SBGPPPORTCONFIG *portCfg; + + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + portCfg = &pConfig->PORTCONFIG[portId].PortCfg; + if (portCfg->PortHotPlug == TRUE) { + portCfg->PortDetected = FALSE; + } else { + if (portCfg->PortIsGen2 == 1) { + sbGppForceGen1 (pConfig, (UINT8) (1 << portId)); + } else { + sbGppForceGen2 (pConfig, (UINT8) (1 << portId)); + } + } + } + } + + // Obtain original Gen2 strap value (LC_GEN2_EN_STRAP) + pConfig->GppGen2Strap = (UINT8) (readAlink (SB_RCINDXP_REGA4 | 0 << 24) & BIT0); +} + + +/** + * GppPortPollingLtssm - Loop polling the LTSSM for each GPP port marked in PortMap + * + * + * Return: FailedPortMap = A bitmap of ports which failed to train + * + * @param[in] pConfig Southbridge configuration structure pointer. + * @param[in] ActivePorts A bitmap of ports which should be polled + * @param[in] IsGen2 TRUE if the polling is in Gen2 mode + * + */ +UINT8 +GppPortPollingLtssm ( + IN AMDSBCFG* pConfig, + IN UINT8 ActivePorts, + IN BOOLEAN IsGen2 + ) +{ + UINT32 retryCounter; + UINT8 PortId; + UINT8 FailedPorts; + SBGPPPORTCONFIG *portCfg; + UINT32 abIndex; + UINT32 Data32; + UINT8 EmptyPorts; + + FailedPorts = 0; + retryCounter = MAX_LT_POLLINGS; + EmptyPorts = ActivePorts; + + while (retryCounter-- && ActivePorts) { + for (PortId = 0; PortId < MAX_GPP_PORTS; PortId++) { + if (ActivePorts & (1 << PortId)) { + portCfg = &pConfig->PORTCONFIG[PortId].PortCfg; + abIndex = SB_RCINDXP_REGA5 | (UINT32) (RCINDXP << 29) | (PortId << 24); + Data32 = readAlink (abIndex) & 0x3F3F3F3F; + + if ((UINT8) (Data32) > 0x04) { + EmptyPorts &= ~(1 << PortId); + } + + if ((UINT8) (Data32) == 0x10) { + ActivePorts &= ~(1 << PortId); + portCfg->PortDetected = TRUE; + break; + } + if (IsGen2) { + UINT8 i; + + for (i = 0; i < 4; i++) { + if ((UINT8) (Data32) == 0x29 || (UINT8) (Data32) == 0x2A ) { + ActivePorts &= ~(1 << PortId); + FailedPorts |= (1 << PortId); + break; + } + Data32 >>= 8; + } + } + } + } + if (EmptyPorts && retryCounter < (MAX_LT_POLLINGS - 200)) { + ActivePorts &= ~EmptyPorts; + } + SbStall (1000); + } + FailedPorts |= ActivePorts; + return FailedPorts; +} + + +/** + * 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] pConfig Southbridge configuration structure pointer. + * + */ +UINT8 +CheckGppLinkStatus ( + IN AMDSBCFG* pConfig + ) +{ + UINT32 portId; + UINT8 portScanMap; + UINT8 GppHwDowngrade; + SBGPPPORTCONFIG *portCfg; + UINT8 FailedPorts; + + + portScanMap = 0; + FailedPorts = 0; + + // Obtain a list of ports to be checked + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + portCfg = &pConfig->PORTCONFIG[portId].PortCfg; + if ( portCfg->PortPresent == TRUE && portCfg->PortDetected == FALSE ) { + portScanMap |= 1 << portId; + } + } + GppHwDowngrade = (UINT8)pConfig->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 + // } + SbStall (5000); + if (pConfig->GppGen2 && pConfig->GppGen2Strap) { + sbGppForceGen2 (pConfig, portScanMap); + FailedPorts = GppPortPollingLtssm (pConfig, portScanMap, TRUE); + + if (FailedPorts) { + sbGppForceGen1 (pConfig, FailedPorts); + FailedPorts = GppPortPollingLtssm (pConfig, FailedPorts, FALSE); + } + } else { + sbGppForceGen1 (pConfig, portScanMap); + FailedPorts = GppPortPollingLtssm (pConfig, 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] pConfig Southbridge configuration structure pointer. + * + */ +VOID +AfterGppLinkInit ( + IN AMDSBCFG* pConfig + ) +{ + UINT32 portId; + SBGPPPORTCONFIG *portCfg; + UINT32 regBusNumber; + UINT32 abValue; + UINT32 abIndex; + UINT8 bValue; + UINT8 cimGppGen2; + + cimGppGen2 = pConfig->GppGen2; +#if SB_CIMx_PARAMETER == 0 + cimGppGen2 = cimGppGen2Default; +#endif + + pConfig->GppFoundGfxDev = 0; + abValue = readAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29)); + //RPR 5.9 Link Bandwidth Notification Capability Enable + //RCINDC:0xC1[0] = 1 + rwAlink (SB_RCINDXC_REGC1, 0xFFFFFFFF, BIT0); + + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + // Program requester ID for every port + abIndex = SB_RCINDXP_REG21 | (UINT32) (RCINDXP << 29) | (portId << 24); + writeAlink (abIndex, (SB_GPP_DEV << 3) + portId); + + //RPR 5.9 Link Bandwidth Notification Capability Enable + //PCIe Cfg 0x68[10] = 0 + //PCIe Cfg 0x68[11] = 0 + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x68), AccWidthUint16, ~(BIT10 + BIT11), 0); + + portCfg = &pConfig->PORTCONFIG[portId].PortCfg; + // 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), AccWidthUint32, ®BusNumber); + // *** Stall (); + ReadPCI (PCI_ADDRESS (SBTEMP_BUS, 0, 0, 0x0B), AccWidthUint8, &bValue); + if ( bValue == 3 ) { + pConfig->GppFoundGfxDev |= (1 << portId); + } + regBusNumber = 0; + WritePCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x18), AccWidthUint32, ®BusNumber); + } else if ( portCfg->PortPresent == FALSE || portCfg->PortHotPlug == FALSE ) { + // Mask off non-applicable ports + abValue &= ~(1 << (portId + 4)); + } + + if ( portCfg->PortHotPlug == TRUE ) { + // RPR5.12 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 ((SB_RCINDXP_REG10 | (UINT32) (RCINDXP << 29) | (portId << 24)), 0xFFFFFFFF, BIT3); + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x5b), AccWidthUint8, 0xff, BIT0); + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x6c), AccWidthUint8, 0xff, BIT6); + rwAlink ((SB_RCINDXP_REG20 | (UINT32) (RCINDXP << 29) | (portId << 24)), ~BIT19, 0); + } + } + if ( pConfig->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 (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29), abValue); + } + + // + // Common initialization for open GPP ports + // + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + ReadPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x80), AccWidthUint8, &bValue); + if (bValue != 0xff) { + // Set pciCfg:PCIE_DEVICE_CNTL2[3:0] = 4'h6 (0x80[3:0]) + bValue &= 0xf0; + bValue |= 0x06; + WritePCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x80), AccWidthUint8, &bValue); + + // Set PCIEIND_P:PCIE_RX_CNTL[RX_RCB_CPL_TIMEOUT_MODE] (0x70:[19]) = 1 + abIndex = SB_RCINDXP_REG70 | (UINT32) (RCINDXP << 29) | (portId << 24); + abValue = readAlink (abIndex) | BIT19; + writeAlink (abIndex, abValue); + + // Set PCIEIND_P:PCIE_TX_CNTL[TX_FLUSH_TLP_DIS] (0x20:[19]) = 0 + abIndex = SB_RCINDXP_REG20 | (UINT32) (RCINDXP << 29) | (portId << 24); + abValue = readAlink (abIndex) & ~BIT19; + writeAlink (abIndex, abValue); + + // Set Immediate Ack PM_Active_State_Request_L1 (0xA0:[23]) = 0 + abIndex = SB_RCINDXP_REGA0 | (UINT32) (RCINDXP << 29) | (portId << 24); + abValue = readAlink (abIndex) & ~BIT23; + if ( pConfig->L1ImmediateAck == 0) { + abValue |= BIT23; + } + writeAlink (abIndex, abValue); + } + } +} + + +/** + * sbPcieGppLateInit - Late PCIE initialization for Hudson-2 GPP component + * + * + * @param[in] pConfig Southbridge configuration structure pointer. + * + */ +VOID +sbPcieGppLateInit ( + IN AMDSBCFG* pConfig + ) +{ + UINT8 portId; + UINT8 busNum; + UINT8 aspmValue; + UINT8 PortaspmValue; + UINT8 reg8Value; + UINT8 cimGppPhyPllPowerDown; + SBGPPPORTCONFIG *portCfg; + UINT32 reg32Value; + + // Disable hidden register decode and serial number capability + reg32Value = readAlink (SB_ABCFG_REG330 | (UINT32) (ABCFG << 29)); + writeAlink (SB_ABCFG_REG330 | (UINT32) (ABCFG << 29), reg32Value & ~(BIT26 + BIT10)); + + if (readAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29)) & BIT8) { + return; + } + + // + // Configure ASPM + // + // writeAlink (0xC0 | (UINT32) (RCINDXC << 29), 0x400); // Set STRAP_F0_MSI_EN + aspmValue = (UINT8)pConfig->GppPortAspm; + cimGppPhyPllPowerDown = (UINT8) pConfig->GppPhyPllPowerDown; +#if SB_CIMx_PARAMETER == 0 + aspmValue = cimGppPortAspmDefault; + cimGppPhyPllPowerDown = cimGppPhyPllPowerDownDefault; +#endif + + reg8Value = 0x01; + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + // write pci_reg3d with 0x01 to fix yellow mark for GPP bridge under Vista + // when native PCIE is enabled but MSI is not available + // SB02029: Hudson-2 BIF/GPP allowing strap STRAP_BIF_INTERRUPT_PIN_SB controlled by AB reg + portCfg = &pConfig->PORTCONFIG[portId].PortCfg; + if (portCfg->PortHotPlug) { + RWPCI (PCI_ADDRESS (0, 21, portId, 0x04), AccWidthUint8, 0xFE, 0x00); //clear IO enable to fix possible hotplug hang + } + WritePCI (PCI_ADDRESS (0, 21, portId, 0x3d), AccWidthUint8, ®8Value); + ReadPCI (PCI_ADDRESS (0, 21, portId, 0x19), AccWidthUint8, &busNum); + if (busNum != 0xFF) { + ReadPCI (PCI_ADDRESS (busNum, 0, 0, 0x00), AccWidthUint32, ®32Value); + if (reg32Value != 0xffffffff) { + PortaspmValue = aspmValue; + // Vlidate if EP support ASPM + sbGppValidateAspm (PCI_ADDRESS (busNum, 0, 0, 0), &PortaspmValue); + // Set ASPM on EP side + sbGppSetEPAspm (PCI_ADDRESS (busNum, 0, 0, 0), PortaspmValue); + // Set ASPM on port side + sbGppSetAspm (PCI_ADDRESS (0, 21, portId, 0), PortaspmValue); + } + } + rwAlink ((SB_RCINDXP_REG02 | (UINT32) (RCINDXP << 29) | (portId << 24) ), ~(BIT15), (BIT15)); + } + rwAlink ((SB_RCINDXC_REG02 | (UINT32) (RCINDXC << 29)), ~(BIT0), (BIT0)); + + // + // Configure Lock HWInit registers + // + reg32Value = readAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29)); + if (reg32Value & 0xF0) { + reg32Value = readAlink (SB_RCINDXC_REG10 | (UINT32) (RCINDXC << 29)); + writeAlink (SB_RCINDXC_REG10 | (UINT32) (RCINDXC << 29), reg32Value | BIT0); // Set HWINIT_WR_LOCK + + if ( cimGppPhyPllPowerDown == TRUE ) { + // + // RPR 5.4 Power Saving Feature for GPP Lanes + // + UINT32 abValue; + + // Set PCIE_P_CNTL in Alink PCIEIND space + abValue = readAlink (RC_INDXC_REG40 | (UINT32) (RCINDXC << 29)); + abValue |= BIT12 + BIT3 + BIT0; + abValue &= ~(BIT9 + BIT4); + writeAlink (RC_INDXC_REG40 | (UINT32) (RCINDXC << 29), abValue); + rwAlink (SB_RCINDXC_REG02, ~(BIT8), (BIT8)); + rwAlink (SB_RCINDXC_REG02, ~(BIT3), (BIT3)); + } + } + + // Restore strap0 via override + if (pConfig->PcieAER) { + rwAlink (SB_ABCFG_REG310 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT7); + rwAlink (RC_INDXC_REGC0, 0xFFFFFFFF, BIT9); + } +} + + +/** + * sbGppDynamicPowerSaving - RPR 5.19 GPP Dynamic Power Saving + * + * + * @param[in] pConfig + * + */ +VOID +sbGppDynamicPowerSaving ( + IN AMDSBCFG* pConfig + ) +{ + SBGPPPORTCONFIG *portCfg; + UINT8 cimGppLaneReversal; + UINT8 cimAlinkPhyPllPowerDown; + UINT8 cimGppPhyPllPowerDown; + UINT32 Data32; + UINT32 HoldData32; + UINT32 abValue; + + if (!pConfig->GppDynamicPowerSaving || pConfig->sdbEnable) { + return; + } + + cimAlinkPhyPllPowerDown = (UINT8) pConfig->AlinkPhyPllPowerDown; + cimGppLaneReversal = (UINT8) pConfig->GppLaneReversal; + cimGppPhyPllPowerDown = (UINT8) pConfig->GppPhyPllPowerDown; +#if SB_CIMx_PARAMETER == 0 + cimGppLaneReversal = cimGppLaneReversalDefault; + cimAlinkPhyPllPowerDown = cimAlinkPhyPllPowerDownDefault; + cimGppPhyPllPowerDown = cimGppPhyPllPowerDownDefault; +#endif + if (pConfig->GppHardwareDowngrade) { + portCfg = &pConfig->PORTCONFIG[pConfig->GppHardwareDowngrade - 1].PortCfg; + portCfg->PortDetected = TRUE; + } + + Data32 = 0; + HoldData32 = 0; + switch ( pConfig->GppLinkConfig ) { + case GPP_CFGMODE_X4000: + portCfg = &pConfig->PORTCONFIG[0].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= 0x0f0f; + HoldData32 |= 0x1000; + } + break; + case GPP_CFGMODE_X2200: + portCfg = &pConfig->PORTCONFIG[0].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0c0c:0x0303; + HoldData32 |= 0x1000; + } + portCfg = &pConfig->PORTCONFIG[1].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0303:0x0c0c; + HoldData32 |= 0x2000; + } + break; + case GPP_CFGMODE_X2110: + portCfg = &pConfig->PORTCONFIG[0].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0c0c:0x0303; + HoldData32 |= 0x1000; + } + portCfg = &pConfig->PORTCONFIG[1].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0202:0x0404; + HoldData32 |= 0x2000; + } + portCfg = &pConfig->PORTCONFIG[2].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0101:0x0808; + HoldData32 |= 0x4000; + } + break; + case GPP_CFGMODE_X1111: + portCfg = &pConfig->PORTCONFIG[0].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0808:0x0101; + HoldData32 |= 0x1000; + } + portCfg = &pConfig->PORTCONFIG[1].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0404:0x0202; + HoldData32 |= 0x2000; + } + portCfg = &pConfig->PORTCONFIG[2].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0202:0x0404; + HoldData32 |= 0x4000; + } + portCfg = &pConfig->PORTCONFIG[3].PortCfg; + if ( portCfg->PortDetected == FALSE ) { + Data32 |= ( cimGppLaneReversal )? 0x0101:0x0808; + HoldData32 |= 0x8000; + } + break; + default: + break; + } + + // RPR 5.11 Power Saving With GPP Disable + // ABCFG 0xC0[8] = 0x0 + // ABCFG 0xC0[15:12] = 0xF + // Enable "Power Saving Feature for A-Link Express Lanes" + // Enable "Power Saving Feature for GPP Lanes" + // ABCFG 0x90[19] = 1 + // ABCFG 0x90[6] = 1 + // RCINDC_Reg 0x65 [27:0] = 0xFFFFFFF + // ABCFG 0xC0[7:4] = 0x0 + if ( cimAlinkPhyPllPowerDown && cimGppPhyPllPowerDown ) { + abValue = readAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29)); + writeAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29), (( abValue | HoldData32 ) & (~ BIT8 ))); + rwAlink (SB_AX_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12)); + rwAlink ((SB_ABCFG_REG90 | (UINT32) (ABCFG << 29)), 0xFFFFFFFF, (BIT6 + BIT19)); + rwAlink (RC_INDXC_REG65, 0xFFFFFFFF, ((Data32 & 0x0F) == 0x0F) ? Data32 | 0x0CFF0000 : Data32); + rwAlink (RC_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12)); + } +} + + +/** + * sbGppAerInitialization - Initializing AER + * + * + * @param[in] pConfig + * + */ +VOID +sbGppAerInitialization ( + IN AMDSBCFG* pConfig + ) +{ + UINT8 PortId; + UINT32 ValueDd; + + if (pConfig->PcieAER) { + // GPP strap configuration + rwAlink (SB_ABCFG_REG310 | (UINT32) (ABCFG << 29), ~(BIT7 + BIT4), BIT28 + BIT27 + BIT26 + BIT1); + rwAlink (SB_ABCFG_REG314 | (UINT32) (ABCFG << 29), ~(UINT32) (0xfff << 15), 0); + + for (PortId = 0; PortId < MAX_GPP_PORTS; PortId++) { + ReadPCI (PCI_ADDRESS (0, GPP_DEV_NUM, PortId, 0x00), AccWidthUint32, &ValueDd); + if (ValueDd != 0xffffffff) { + rwAlink ((SB_RCINDXP_REG6A | (UINT32) (RCINDXP << 29) | (PortId << 24)), ~BIT1, 0); + rwAlink ((SB_RCINDXP_REG70 | (UINT32) (RCINDXP << 29) | (PortId << 24)), 0xFFFFE000, 0); + } + } + + rwAlink (SB_RCINDXC_REG10, ~(BIT18 + BIT21 + BIT22), 0); + + // AB strap configuration + rwAlink (SB_ABCFG_REGF0 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT15 + BIT14); + rwAlink (SB_ABCFG_REGF4 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT3); + + // Enable GPP function0 error reporting + rwAlink (SB_ABCFG_REG310 | (UINT32) (ABCFG << 29), ~BIT7, BIT7); + rwAlink (SB_RCINDXC_REGC0, ~BIT9, BIT9); + } else { + //OBS220313: Hard System Hang running MeatGrinder Test on multiple blocks + //RPR 5.13 GPP Error Reporting Configuration + rwAlink (SB_ABCFG_REGF0 | (UINT32) (ABCFG << 29), ~(BIT1), 0); + //rwAlink (SB_ABCFG_REG310 | (UINT32) (ABCFG << 29), ~BIT7, 0); + //rwAlink (SB_RCINDXC_REGC0, ~BIT8, 0); + } + //RPR 5.13 GPP Error Reporting Configuration + rwAlink (SB_ABCFG_REGB8 | (UINT32) (ABCFG << 29), ~(BIT8 + BIT24 + BIT25 + BIT26 + BIT28), BIT8 + BIT24 + BIT26 + BIT28); +} + +/** + * sbGppRasInitialization - Initializing RAS + * + * + * @param[in] pConfig + * + */ +VOID +sbGppRasInitialization ( + IN AMDSBCFG* pConfig + ) +{ + if (pConfig->PcieRAS) { + rwAlink (SB_ABCFG_REGF4 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT0); + } +} + + +// +//----------------------------------------------------------------------------------- +// Early Hudson-2 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 +// +// + +/** + * GPP early programming and link training. On exit all populated EPs should be fully operational. + * + * + * + * @param[in] pConfig Southbridge configuration structure pointer. + * + */ +VOID +sbPcieGppEarlyInit ( + IN AMDSBCFG* pConfig + ) +{ + UINT32 reg32Value; + UINT8 cimNbSbGen2; + UINT8 cimGppMemWrImprove; + UINT8 cimGppLaneReversal; + UINT8 cimAlinkPhyPllPowerDown; + UINT32 abValue; + + cimNbSbGen2 = pConfig->NbSbGen2; + cimGppMemWrImprove = pConfig->GppMemWrImprove; + cimGppLaneReversal = (UINT8) pConfig->GppLaneReversal; + cimAlinkPhyPllPowerDown = (UINT8) pConfig->AlinkPhyPllPowerDown; +#if SB_CIMx_PARAMETER == 0 + cimNbSbGen2 = cimNbSbGen2Default; + cimGppMemWrImprove = cimGppMemWrImproveDefault; + cimGppLaneReversal = cimGppLaneReversalDefault; + cimAlinkPhyPllPowerDown = cimAlinkPhyPllPowerDownDefault; +#endif + + outPort80 (0x90); + // + // Configure NB-SB link PCIE PHY PLL power down for L1 + // + if ( cimAlinkPhyPllPowerDown == TRUE ) { + // Set PCIE_P_CNTL in Alink PCIEIND space + writeAlink (SB_AX_INDXC_REG30 | (UINT32) (AXINDC << 29), 0x40); + abValue = readAlink (SB_AX_DATAC_REG34 | (UINT32) (AXINDC << 29)); + abValue |= BIT12 + BIT3 + BIT0; + abValue &= ~(BIT9 + BIT4); + writeAlink (SB_AX_DATAC_REG34 | (UINT32) (AXINDC << 29), abValue); + rwAlink (SB_AX_INDXC_REG02 | (UINT32) (AXINDC << 29), ~(BIT8), (BIT8)); + rwAlink (SB_AX_INDXC_REG02 | (UINT32) (AXINDC << 29), ~(BIT3), (BIT3)); + } + + // AXINDC_Reg 0xA4[18] = 0x1 + writeAlink (SB_AX_INDXP_REG38 | (UINT32) (AXINDP << 29), 0xA4); + abValue = readAlink (SB_AX_DATAP_REG3C | (UINT32) (AXINDP << 29)); + abValue |= BIT18; + writeAlink (SB_AX_DATAP_REG3C | (UINT32) (AXINDP << 29), abValue); + + + // + // Set ABCFG 0x031C[0] = 1 to enable lane reversal + // + reg32Value = readAlink (SB_ABCFG_REG31C | (UINT32) (ABCFG << 29)); + if ( cimGppLaneReversal ) { + writeAlink (SB_ABCFG_REG31C | (UINT32) (ABCFG << 29), reg32Value | BIT0); + } else { + writeAlink (SB_ABCFG_REG31C | (UINT32) (ABCFG << 29), reg32Value | 0x00); + } + // + // Set abcfg:0x90[20] = 1 to enable GPP bridge multi-function + // + reg32Value = readAlink (SB_ABCFG_REG90 | (UINT32) (ABCFG << 29)); + writeAlink (SB_ABCFG_REG90 | (UINT32) (ABCFG << 29), reg32Value | BIT20); + + + // + // Initialize and configure GPP + // + if (pConfig->GppFunctionEnable) { + sbGppTogglePcieReset (pConfig); + + // PreInit - Enable GPP link training + PreInitGppLink (pConfig); + + // + // GPP Upstream Memory Write Arbitration Enhancement ABCFG 0x54[26] = 1 + // GPP Memory Write Max Payload Improvement RCINDC_Reg 0x10[12:10] = 0x4 + // + if ( cimGppMemWrImprove == TRUE ) { + rwAlink (SB_ABCFG_REG54 | (UINT32) (ABCFG << 29), ~BIT26, (BIT26)); + rwAlink (SB_RCINDXC_REG10 | (UINT32) (RCINDXC << 29), ~(BIT12 + BIT11 + BIT10), (BIT12)); + } + + if (CheckGppLinkStatus (pConfig) && !pConfig->S3Resume) { + // Toggle GPP reset (Note this affects all Hudson-2 GPP ports) + sbGppTogglePcieReset (pConfig); + } + + // Misc operations after link training + AfterGppLinkInit (pConfig); + + + sbGppAerInitialization (pConfig); + sbGppRasInitialization (pConfig); + } + sbGppDynamicPowerSaving (pConfig); + outPort80 (0x9F); +} + -- cgit v1.2.3