diff options
Diffstat (limited to 'src/vendorcode/amd/cimx/sb800/Gpp.c')
-rw-r--r-- | src/vendorcode/amd/cimx/sb800/Gpp.c | 897 |
1 files changed, 897 insertions, 0 deletions
diff --git a/src/vendorcode/amd/cimx/sb800/Gpp.c b/src/vendorcode/amd/cimx/sb800/Gpp.c new file mode 100644 index 0000000000..72cb1cdcc3 --- /dev/null +++ b/src/vendorcode/amd/cimx/sb800/Gpp.c @@ -0,0 +1,897 @@ + +/** + * @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" + +/** + * PCIE_CAP_ID - PCIe Cap ID + * + */ +#define PCIE_CAP_ID 0x10 + +// +// Declaration of local functions +// + +/** + * PreInitGppLink - Enable GPP link training. + * + * @param[in] pConfig Southbridge configuration structure pointer. + * + */ + VOID PreInitGppLink (IN AMDSBCFG* pConfig); + UINT8 CheckGppLinkStatus (IN AMDSBCFG* pConfig); + VOID AfterGppLinkInit (IN AMDSBCFG* pConfig); + VOID sbGppForceGen2 (IN UINT32 portId ); + VOID sbGppForceGen1 (IN UINT32 portId ); + VOID sbGppDisableUnusedPadMap (IN AMDSBCFG* pConfig ); + VOID sbGppSetAspm (IN UINT32 pciAddress, IN UINT8 LxState); + UINT8 sbFindPciCap (IN UINT32 pciAddress, IN UINT8 targetCapId); + +// +// Declaration of external functions +// + +// +//----------------------------------------------------------------------------------- +// Early SB800 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 + ) +{ + UINT8 TogglePort; + UINT8 portNum; + UINT32 reg32Value; + UINT8 retryCount; + UINT8 cimGppMemWrImprove; + UINT8 cimGppLaneReversal; + UINT8 cimAlinkPhyPllPowerDown; + + cimGppMemWrImprove = pConfig->GppMemWrImprove; + cimGppLaneReversal = (UINT8) pConfig->GppLaneReversal; + cimAlinkPhyPllPowerDown = (UINT8) pConfig->AlinkPhyPllPowerDown; +#if SB_CIMx_PARAMETER == 0 + cimGppMemWrImprove = cimGppMemWrImproveDefault; + cimGppLaneReversal = cimGppLaneReversalDefault; + cimAlinkPhyPllPowerDown = cimAlinkPhyPllPowerDownDefault; +#endif + +// +// Configure NB-SB link PCIE PHY PLL power down for L1 +// + if ( cimAlinkPhyPllPowerDown == TRUE ) { + UINT32 abValue; + // 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)); + } + +// +// Set ABCFG 0x031C[0] = 1 enable the lane reversal support. +// + 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) { + // 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 ( pConfig->S3Resume ) { + for ( portNum = 0; portNum < MAX_GPP_PORTS; portNum++ ) { + reg32Value = readAlink ((SB_ABCFG_REG340 + portNum * 4) | (UINT32) (ABCFG << 29)); + writeAlink ((SB_ABCFG_REG340 + portNum * 4) | (UINT32) (ABCFG << 29), reg32Value & ~BIT21); + } + } + // + // a) Loop polling regA5 -> LcState (timeout ~100ms); + // b) if (LcState[5:0] == 0x10), training successful, go to g); + // c) if any of (LcState[13:8], [21:16], [29:24]) == 0x29 or 0x2A: + // d) Clear De-emphasis bit for relevant ports; + // e) Toggle GPP reset signal (via OEM callback); + // f) go back to a); + // g) exit; + // + for (retryCount = 0; retryCount < MAX_GPP_RESETS; retryCount++) { + // Polling each GPP port for link status + TogglePort = CheckGppLinkStatus (pConfig); + + if (TogglePort == 0) { + break; + } else { + // Check failure port and clear STRAP_BIF_DE_EMPHASIS_SEL_x_GPP bit (abcfg:0x34[0, 4, 8, C][21]=0) + for ( portNum = 0; portNum < MAX_GPP_PORTS; portNum++ ) { + if (TogglePort & (1 << portNum)) { + reg32Value = readAlink ((SB_ABCFG_REG340 + portNum * 4) | (UINT32) (ABCFG << 29)); + writeAlink ((SB_ABCFG_REG340 + portNum * 4) | (UINT32) (ABCFG << 29), reg32Value & ~BIT21); + } + sbGppForceGen1 (portNum); + } + + // Toggle GPP reset (Note this affects all SB800 GPP ports) + CallBackToOEM (CB_SBGPP_RESET_ASSERT, (UINT32)TogglePort, pConfig); + SbStall (500); + CallBackToOEM (CB_SBGPP_RESET_DEASSERT, (UINT32)TogglePort, pConfig); + } + }; + + // Misc operations after link training + AfterGppLinkInit (pConfig); + } else { + +// 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 + + rwAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29), ~BIT8, (BIT4 + BIT5 + BIT6 + BIT7)); + rwAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, (BIT12 + BIT13 + BIT14 + BIT15)); + rwAlink (SB_AX_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12)); + rwAlink (RC_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12)); + rwAlink ((SB_ABCFG_REG90 | (UINT32) (ABCFG << 29)), 0xFFFFFFFF, (BIT6 + BIT19)); + rwAlink (RC_INDXC_REG65, 0xFFFFFFFF, 0x0fffffff); + rwAlink ((SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29)), ~(BIT4 + BIT5 + BIT6 + BIT7), 0); + } + sbGppDisableUnusedPadMap ( pConfig ); +} + +/** + * 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. + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + rwAlink (SB_RCINDXP_REGA0 | portId << 24, 0xFFFFFF0F, 0x10); + } +} + +/** + * 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 retryCounter; + UINT32 portId; + UINT32 abIndex; + UINT32 Data32; + UINT8 portScanMap; + UINT8 portScanMap2; + UINT8 ToggleStatus; + UINT16 i; + SBGPPPORTCONFIG *portCfg; + + + portScanMap = 0; + retryCounter = MAX_TRAINING_RETRY; + ToggleStatus = 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; + } + } + portScanMap2 = portScanMap; + + // + // After training is enabled, Check LCSTATE for each port, if LCSTATE<= 4, then keep + // polling for up to 40ms. If LCSTATE still <= 4, then assume the port to be empty. + // + i = 400; + while ( --i && portScanMap2) { + for (portId = 0; portId < MAX_GPP_PORTS; portId++) { + portCfg = &pConfig->PORTCONFIG[portId].PortCfg; + if (((portCfg->PortHotPlug == FALSE) || ((portCfg->PortHotPlug == TRUE) && (pConfig->S3Resume == FALSE)) ) && (portScanMap2 & (1 << portId))) { + // + // Get port link state (reading LC_CURRENT_STATE of PCIEIND_P) + // + abIndex = SB_RCINDXP_REGA5 | (UINT32) (RCINDXP << 29) | (portId << 24); + Data32 = readAlink (abIndex) & 0x3F; + if ((UINT8) (Data32) > 4) { + portScanMap2 &= ~(1 << portId); // This port is not empty + break; + } + SbStall (100); // Delay 100us + } + } + } + portScanMap &= ~portScanMap2; // Mark remaining ports as empty + + + while ( --retryCounter && portScanMap ) { + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + portCfg = &pConfig->PORTCONFIG[portId].PortCfg; + if (( portCfg->PortHotPlug == TRUE ) && ( pConfig->S3Resume )) { + continue; + } + if ( portCfg->PortPresent == TRUE && portCfg->PortDetected == FALSE ) { + // + // Get port link state (reading LC_CURRENT_STATE of PCIEIND_P) + // + SbStall (1000); // Delay 400us + abIndex = SB_RCINDXP_REGA5 | (UINT32) (RCINDXP << 29) | (portId << 24); + Data32 = readAlink (abIndex) & 0x3F3F3F3F; + + if ( (UINT8) (Data32) == 0x10 ) { + portCfg->PortDetected = TRUE; + portScanMap &= ~(1 << portId); + } else { + for (i = 0; i < 4; i++) { + // + // Compliance mode (0x7), downgrade from Gen2 to Gen1 (*A12) + // + if ((UINT8) (Data32) == 0x29 || (UINT8) (Data32) == 0x2A || (UINT8) (Data32) == 0x7 ) { + ToggleStatus |= (1 << portId); // A11 only: need to toggle GPP reset + portScanMap &= ~(1 << portId); + } + Data32 >>= 8; + } + } + } + } + } + return ToggleStatus; +} + + +/** + * 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; + UINT32 i; + UINT32 Data32; + UINT8 bValue; + UINT8 cimGppGen2; + + cimGppGen2 = pConfig->GppGen2; +#if SB_CIMx_PARAMETER == 0 + cimGppGen2 = cimGppGen2Default; +#endif + + bValue = GPP_EFUSE_LOCATION; + getEfuseStatus (&bValue); + if ( (bValue & GPP_GEN2_EFUSE_BIT) != 0 ) { + cimGppGen2 = FALSE; + } else { + pConfig->CoreGen2Enable = TRUE; // Output for platform use + } + +//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 +// } + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + portCfg = &pConfig->PORTCONFIG[portId].PortCfg; + abValue = readAlink (SB_RCINDXP_REGA4 | portId << 24) & BIT0; + if (( cimGppGen2 == TRUE ) && (abValue == BIT0) && (portCfg->PortDetected == TRUE)) { + portCfg->PortIsGen2 = TRUE; // Output for platform use + sbGppForceGen2 (portId); + //_asm {jmp $}; + SbStall (400); // Delay 400us + i = 500; + Data32 = 0; + while ( --i ) { + abIndex = SB_RCINDXP_REGA5 | (UINT32) (RCINDXP << 29) | (portId << 24); + Data32 = readAlink (abIndex) & 0x3F; + if ((UINT8) (Data32) == 0x10) { + break; + } + SbStall (400); // Delay 100us + } + if (!( (UINT8) (Data32) == 0x10 )) { + if (pConfig->GppCompliance == FALSE) { + portCfg->PortIsGen2 = FALSE; // Revert to default; output for platform use + sbGppForceGen1 (portId); + } + } + } else { + if (pConfig->GppCompliance == FALSE) { + sbGppForceGen1 (portId); + } + } +//RPR 5.9 Link Bandwidth Notification Capability Enable +//RCINDC 0xC1[0] = 1 +//PCIe Cfg 0x68[10] = 0 +//PCIe Cfg 0x68[11] = 0 + + rwAlink (SB_RCINDXC_REGC1, 0xFFFFFFFF, BIT0); + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x68), AccWidthUint16, ~(BIT10 + BIT11), 0); + } + +// Status = AGESA_SUCCESS; + pConfig->GppFoundGfxDev = 0; + abValue = readAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29)); + + for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) { + 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); + } + + // Mask off non-applicable ports + else if ( portCfg->PortPresent == FALSE ) { + abValue &= ~(1 << (portId + 4)); + } + // Mask off empty port if the port is not hotplug-capable + else if ( portCfg->PortHotPlug == FALSE ) { + abValue &= ~(1 << (portId + 4)); + } + // Clear STRAP_BIF_DE_EMPHASIS_SEL_x_GPP bit (abcfg:0x34[0, 4, 8, C][21]=0) to make hotplug working + if ( portCfg->PortHotPlug == TRUE ) { + rwAlink ((SB_ABCFG_REG340 + portId * 4) | (UINT32) (ABCFG << 29), ~BIT21, 0); + +// 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); + + } + } +} + + +/** + * sbPcieGppLateInit - Late PCIE initialization for SB800 GPP component + * + * + * @param[in] pConfig Southbridge configuration structure pointer. + * + */ +VOID +sbPcieGppLateInit ( + IN AMDSBCFG* pConfig + ) +{ + UINT32 reg32Value; + UINT8 portId; + UINT8 busNum; + UINT8 aspmValue; + UINT8 reg8Value; + UINT8 cimGppPhyPllPowerDown; + + reg8Value = 0x01; +// +// 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 + + 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: SB800 BIF/GPP allowing strap STRAP_BIF_INTERRUPT_PIN_SB controlled by AB reg + 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) { + // Set ASPM on EP side + sbGppSetAspm (PCI_ADDRESS (busNum, 0, 0, 0), aspmValue & 0x3); + // Set ASPM on port side + sbGppSetAspm (PCI_ADDRESS (0, 21, portId, 0), aspmValue & 0x3); + } + } + aspmValue = aspmValue >> 2; + } + +// +// 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); + } + } + +// +// Configure Lock HWInit registers +// + reg32Value = readAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29)); +// +// 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)); +} + +/** + * sbGppSetAspm - Set SPP ASPM + * + * + * @param[in] pciAddress PCI Address. + * @param[in] LxState Lane State. + * + */ +VOID +sbGppSetAspm ( + 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 in link control register + RWPCI (devBDF + pcieCapOffset + 0x10, AccWidthUint8, 0xffffffff, LxState & value8); + } + } + maxFuncs--; + } +} + +/** + * 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; +} + +/** + * sbGppForceGen2 - Set SPP to GENII + * + * + * @param[in] portId + * + */ +VOID +sbGppForceGen2 ( + IN UINT32 portId + ) +{ + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x88), AccWidthUint8, 0xf0, 0x02); + rwAlink (SB_RCINDXP_REGA2 | portId << 24, ~BIT13, 0); + rwAlink (SB_RCINDXP_REGC0 | portId << 24, ~BIT15, 0); + rwAlink (SB_RCINDXP_REGA4 | portId << 24, 0xFFFFFFFF, BIT29); +} + +/** + * sbGppForceGen1 - Set SPP to GENI + * + * + * @param[in] portId + * + */ +VOID +sbGppForceGen1 ( + IN UINT32 portId + ) +{ + RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x88), AccWidthUint8, 0xf0, 0x01); + rwAlink (SB_RCINDXP_REGA4 | portId << 24, ~BIT0, 0); + rwAlink (SB_RCINDXP_REGA2 | portId << 24, 0xFFFFFFFF, BIT13); + rwAlink (SB_RCINDXP_REGC0 | portId << 24, ~BIT15, 0); + rwAlink (SB_RCINDXP_REGA4 | portId << 24, 0xFFFFFFFF, BIT29); +} + +/** + * sbGppDisableUnusedPadMap - Return GPP Pad Map + * + * + * @param[in] pConfig + * + */ +VOID +sbGppDisableUnusedPadMap ( + IN AMDSBCFG* pConfig + ) +{ + UINT32 Data32; + UINT32 HoldData32; + SBGPPPORTCONFIG *portCfg; + UINT8 cimGppLaneReversal; + UINT8 cimAlinkPhyPllPowerDown; + UINT8 cimGppPhyPllPowerDown; + + cimAlinkPhyPllPowerDown = (UINT8) pConfig->AlinkPhyPllPowerDown; + cimGppLaneReversal = (UINT8) pConfig->GppLaneReversal; + cimGppPhyPllPowerDown = (UINT8) pConfig->GppPhyPllPowerDown; +#if SB_CIMx_PARAMETER == 0 + cimGppLaneReversal = cimGppLaneReversalDefault; + cimAlinkPhyPllPowerDown = cimAlinkPhyPllPowerDownDefault; + cimGppPhyPllPowerDown = cimGppPhyPllPowerDownDefault; +#endif + + 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 ( (Data32 & 0xf) == 0xf ) Data32 |= 0x0cff0000; + if ( cimAlinkPhyPllPowerDown && cimGppPhyPllPowerDown ) { + rwAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29), ~BIT8, 0); + rwAlink (SB_ABCFG_REGC0 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, HoldData32); + rwAlink (SB_AX_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12)); + rwAlink (RC_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12)); + rwAlink ((SB_ABCFG_REG90 | (UINT32) (ABCFG << 29)), 0xFFFFFFFF, (BIT6 + BIT19)); + rwAlink (RC_INDXC_REG65, 0xFFFFFFFF, Data32); + } +} |