| |
| /** |
| * @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); |
| } |
| } |