diff options
author | Frank Vibrans <frank.vibrans@amd.com> | 2011-02-14 18:30:54 +0000 |
---|---|---|
committer | Marc Jones <marc.jones@amd.com> | 2011-02-14 18:30:54 +0000 |
commit | 2b4c831b4d16b55a7abdea20bce82cccd168232c (patch) | |
tree | 95a35c737d16119f1dfa9c1c9d7700710d8a04f7 /src/vendorcode/amd/cimx/sb800/Gpp.c | |
parent | 74ad66cdc143e04f976ba21e538e02b20362d7e6 (diff) | |
download | coreboot-2b4c831b4d16b55a7abdea20bce82cccd168232c.tar.xz |
Add AMD Agesa and AMD CIMx SB800 code. Patch 1 of 8.
This code currently generates many warnings that are functionally benign. These are being addressed, but the wheels of bureaucracy turn slowly. This drop supports AMD cpu families 10h and 14h. Only Family 14h is used as an example in this set of patches. Other cpu families are supported by the infrastructure, but their specific support is not included herein. This patch is functionally independent of the other patches in this set.
Signed-off-by: Frank Vibrans <frank.vibrans@amd.com>
Acked-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Acked-by: Marc Jones <marcj303@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@6344 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
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); + } +} |