/** * @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++ ) { if (!(reg32Value & (1 << portId))) pConfig->PORTCONFIG[portId].PortCfg.PortPresent = false; else if (!pConfig->PORTCONFIG[portId].PortCfg.PortPresent) reg32Value &= ~(1 << portId); } // // 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); } }