| /** |
| * @file |
| * |
| * PCIe silicon specific functions library. |
| * |
| * |
| * |
| * @xrefitem bom "File Content Label" "Release Content" |
| * @e project: CIMx-NB |
| * @e sub-project: |
| * @e \$Revision:$ @e \$Date:$ |
| * |
| */ |
| /***************************************************************************** |
| * |
| * Copyright (C) 2012 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. |
| * |
| * |
| ***************************************************************************/ |
| /*---------------------------------------------------------------------------------------- |
| * M O D U L E S U S E D |
| *---------------------------------------------------------------------------------------- |
| */ |
| |
| #include "NbPlatform.h" |
| #include "amdDebugOutLib.h" |
| |
| /*---------------------------------------------------------------------------------------- |
| * D E F I N I T I O N S A N D M A C R O S |
| *---------------------------------------------------------------------------------------- |
| */ |
| |
| |
| /*---------------------------------------------------------------------------------------- |
| * T Y P E D E F S A N D S T R U C T U R E S |
| *---------------------------------------------------------------------------------------- |
| */ |
| |
| |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Misc Initialization in late init |
| * |
| * |
| * |
| * @param[in] pConfig Northbridge configuration structure pointer. |
| * |
| */ |
| |
| VOID |
| PcieLibLateInit ( |
| IN AMD_NB_CONFIG *pConfig |
| ) |
| { |
| CORE CoreId; |
| PORT PortId; |
| PCIE_CONFIG *pPcieConfig; |
| PCI_ADDR ClkPciAddress; |
| |
| pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); |
| ClkPciAddress = pConfig->NbPciAddress; |
| ClkPciAddress.Address.Function = 1; |
| //Restore general setting in scratch |
| LibNbEnableClkConfig (pConfig); |
| LibNbPciRead (ClkPciAddress.AddressValue | NB_CLK_REG78, AccessWidth32, &pPcieConfig->PcieConfiguration, pConfig); |
| LibNbDisableClkConfig (pConfig); |
| // Restore Core setting from scratch |
| for (CoreId = 0; CoreId <= MAX_CORE_ID; CoreId++) { |
| // if (PcieLibIsCoreAccessible (CoreId, pConfig) && pPcieConfig->CoreSetting[CoreId].CoreDisabled != ON ) { |
| UINT32 CoreAddress; |
| CoreAddress = PcieLibGetCoreAddress (CoreId, pConfig); |
| LibNbPciIndexRead ( |
| pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, |
| NB_BIFNB_REG01 | CoreAddress, |
| AccessWidth32, |
| (UINT32*)&pPcieConfig->CoreSetting[CoreId], |
| pConfig |
| ); |
| // } else { |
| // pPcieConfig->CoreSetting[CoreId].CoreDisabled = ON; |
| // } |
| // CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Recover Core Setting CoreId %d Setting %x Enter\n", CoreId, (UINT32)(pPcieConfig->CoreSetting[CoreId]))); |
| } |
| // Restore port Setting from scratch |
| for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) { |
| if (PcieLibIsValidPortId (PortId, pConfig)) { |
| PCI_ADDR Port; |
| Port = PcieLibGetPortPciAddress (PortId, pConfig); |
| //Reload port configuration from scratch register |
| LibNbPciIndexRead ( |
| Port.AddressValue | NB_BIF_INDEX, |
| NB_BIFNBP_REG01, |
| AccessWidth32, |
| (UINT32*)&pPcieConfig->PortConfiguration[PortId], |
| pConfig |
| ); |
| LibNbPciRead (Port.AddressValue | NB_PCIP_REG108, AccessWidth32, (UINT32*)&pPcieConfig->ExtPortConfiguration[PortId], pConfig); |
| // CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Recover Port setting PortId %d Setting %x Enter\n", PortId, (UINT32)(pPcieConfig->PortConfiguration[PortId]))); |
| } else { |
| *((UINT32*)&pPcieConfig->ExtPortConfiguration[PortId]) = 0; |
| *((UINT32*)&pPcieConfig->PortConfiguration[PortId]) = 0; |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Misc Initialization in validate port state |
| * |
| * |
| * |
| * @param[in] pConfig Northbridge configuration structure pointer. |
| * |
| */ |
| |
| VOID |
| PcieLibValidatePortStateInit ( |
| IN AMD_NB_CONFIG *pConfig |
| ) |
| { |
| CORE CoreId; |
| PORT PortId; |
| UINT32 PortAlwaysVisible; |
| UINT32 ForcePortDisable; |
| PCIE_CONFIG *pPcieConfig; |
| PCI_ADDR ClkPciAddress; |
| |
| pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); |
| ClkPciAddress = pConfig->NbPciAddress; |
| ClkPciAddress.Address.Function = 1; |
| //Restore general setting in scratch |
| LibNbEnableClkConfig (pConfig); |
| LibNbPciRead (ClkPciAddress.AddressValue | NB_CLK_REG78, AccessWidth32, &pPcieConfig->PcieConfiguration, pConfig); |
| LibNbDisableClkConfig (pConfig); |
| // Restore Core setting from scratch |
| for (CoreId = 0; CoreId <= MAX_CORE_ID; CoreId++) { |
| // if (PcieLibIsCoreAccessible (CoreId, pConfig) && pPcieConfig->CoreSetting[CoreId].CoreDisabled != ON ) { |
| UINT32 CoreAddress; |
| CoreAddress = PcieLibGetCoreAddress (CoreId, pConfig); |
| LibNbPciIndexRead ( |
| pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, |
| NB_BIFNB_REG01 | CoreAddress, |
| AccessWidth32, |
| (UINT32*)&pPcieConfig->CoreSetting[CoreId], |
| pConfig |
| ); |
| // } else { |
| // pPcieConfig->CoreSetting[CoreId].CoreDisabled = ON; |
| // } |
| // CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Recover Core Setting CoreId %d Setting %x Enter\n", CoreId, (UINT32)(pPcieConfig->CoreSetting[CoreId]))); |
| } |
| // Restore port Setting from scratch |
| for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) { |
| if (PcieLibIsValidPortId (PortId, pConfig)) { |
| PCI_ADDR Port; |
| Port = PcieLibGetPortPciAddress (PortId, pConfig); |
| PortAlwaysVisible = pPcieConfig->PortConfiguration[PortId].PortAlwaysVisible; |
| ForcePortDisable = pPcieConfig->PortConfiguration[PortId].ForcePortDisable; |
| //Reload port configuration from scratch register |
| LibNbPciIndexRead ( |
| Port.AddressValue | NB_BIF_INDEX, |
| NB_BIFNBP_REG01, |
| AccessWidth32, |
| (UINT32*)&pPcieConfig->PortConfiguration[PortId], |
| pConfig |
| ); |
| pPcieConfig->PortConfiguration[PortId].PortAlwaysVisible = PortAlwaysVisible; |
| pPcieConfig->PortConfiguration[PortId].ForcePortDisable = ForcePortDisable; |
| LibNbPciRead (Port.AddressValue | NB_PCIP_REG108, AccessWidth32, (UINT32*)&pPcieConfig->ExtPortConfiguration[PortId], pConfig); |
| // CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Recover Port setting PortId %d Setting %x Enter\n", PortId, (UINT32)(pPcieConfig->PortConfiguration[PortId]))); |
| } else { |
| *((UINT32*)&pPcieConfig->ExtPortConfiguration[PortId]) = 0; |
| *((UINT32*)&pPcieConfig->PortConfiguration[PortId]) = 0; |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Enable LCLK clock gating or shutdown LCLK clock banch if possible |
| * |
| * |
| * |
| * @param[in] CoreId PCI Express Core ID |
| * @param[in] pConfig Northbridge configuration structure pointer. |
| * |
| */ |
| VOID |
| PcieLibManageLclkClock ( |
| IN CORE CoreId, |
| IN AMD_NB_CONFIG *pConfig |
| ) |
| { |
| UINT32 Value; |
| UINT32 Mask; |
| PCI_ADDR ClkPciAddress; |
| UINT32 CoreAddress; |
| PCIE_CONFIG *pPcieConfig; |
| |
| CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieLibManageLclkClock [CoreId %d] Enter \n", CoreId)); |
| pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); |
| CoreAddress = PcieLibGetCoreAddress (CoreId, pConfig); |
| ClkPciAddress = pConfig->NbPciAddress; |
| ClkPciAddress.Address.Function = 1; |
| LibNbEnableClkConfig (pConfig); |
| |
| if (pPcieConfig->CoreSetting[CoreId].LclkClockGating == ON) { |
| ClkPciAddress.Address.Register = NB_CLK_REGE8; |
| Value = 0; |
| Mask = 0; |
| switch (CoreAddress) { |
| case GPP1_CORE: |
| ClkPciAddress.Address.Register = NB_CLK_REG94; |
| Mask = BIT16; |
| break; |
| case GPP2_CORE: |
| Value = BIT28; |
| break; |
| case GPP3a_CORE: |
| Value = BIT31; |
| break; |
| case GPP3b_CORE: |
| Value = BIT25; |
| break; |
| case SB_CORE: |
| ClkPciAddress.Address.Register = NB_CLK_REG94; |
| Mask = BIT24; |
| break; |
| default: |
| CIMX_ASSERT (FALSE); |
| } |
| LibNbPciRMW (ClkPciAddress.AddressValue, AccessS3SaveWidth32, ~Mask, Value, pConfig); |
| } |
| if (pPcieConfig->CoreSetting[CoreId].LclkClockOff == ON) { |
| UINT8 ActiveCoreMap; |
| ActiveCoreMap = PcieLibGetActiveCoreMap (pConfig); |
| if ((ActiveCoreMap & (1 << CoreId)) == 0) { |
| //Core not active we can shutdown LCLK permanantly |
| CORE_INFO *pCoreInfo; |
| CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Shutdown LCKL clock\n")); |
| pCoreInfo = PcieLibGetCoreInfo (CoreId, pConfig); |
| ClkPciAddress.Address.Register = NB_CLK_REGE0; |
| pPcieConfig->CoreSetting[CoreId].CoreDisableStatus = ON; |
| // We have to setup Index for BIFNB to point out to SB core. After this point core registers no longer accesasable |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, 0x00 | SB_CORE, AccessS3SaveWidth32, 0xffffffff, 0x00, pConfig); |
| LibNbPciRMW (ClkPciAddress.AddressValue, AccessS3SaveWidth32, 0xffffffff, 1 << pCoreInfo->LclkOffOffset, pConfig); |
| |
| Value = 0; |
| if (CoreAddress == GPP1_CORE) { |
| if ((ActiveCoreMap & 0xb) == 0 && !LibNbIsIommuEnabled (pConfig)) { |
| // Can shutdown master core |
| Value = 1 << pCoreInfo->LclkPermOffOffset; |
| } |
| } else { |
| Value = 1 << pCoreInfo->LclkPermOffOffset; |
| } |
| if (Value != 0) { |
| NbIommuDisconnectPcieCore (CoreId, pConfig); |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_MISC_INDEX, NB_MISC_REG27, AccessS3SaveWidth32, 0xffffffff, Value, pConfig); |
| |
| } |
| } |
| } |
| LibNbDisableClkConfig (pConfig); |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Power Off Pll for unused lanes. |
| * |
| * |
| * |
| * @param[in] CoreId PCI Express Core ID |
| * @param[in] pConfig Northbridge configuration structure pointer. |
| */ |
| VOID |
| PcieLibPowerOffPll ( |
| IN CORE CoreId, |
| IN AMD_NB_CONFIG *pConfig |
| ) |
| { |
| PCIE_CONFIG *pPcieConfig; |
| UINT32 CoreAddress; |
| UINT32 PowerOfPllValue; |
| UINT32 PadsMap; |
| //UINT32 TxClockOffValue; |
| UINT32 PowerOfPllRegister; |
| |
| pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); |
| CoreAddress = PcieLibGetCoreAddress (CoreId, pConfig); |
| PowerOfPllValue = 0; |
| PadsMap = 0; |
| //TxClockOffValue = 0; |
| PowerOfPllRegister = NB_MISC_REG23; |
| |
| LibNbPciIndexRead (pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, NB_BIFNB_REG65 | CoreAddress, AccessS3SaveWidth32, &PadsMap, pConfig); |
| if (CoreAddress == GPP1_CORE || CoreAddress == GPP2_CORE) { |
| if ((PadsMap & 0xf0) == 0xf0) { |
| //Power Off PLL1 |
| PowerOfPllValue |= (BIT1 | BIT3); |
| if ((PadsMap & 0x0f) == 0x0f && pPcieConfig->CoreConfiguration[CoreId] != GFX_CONFIG_AABB) { |
| //Power Off PLL0 |
| PowerOfPllValue |= (BIT0 | BIT2); |
| } |
| } |
| if (CoreAddress == GPP2_CORE) { |
| PowerOfPllValue <<= 8; |
| //TxClockOffValue = BIT1; |
| } else { |
| //TxClockOffValue = BIT0; |
| } |
| if ((UINT16)PadsMap != 0xffff) { |
| //TxClockOffValue = 0; //Do not disable TX clock in case any line is ON |
| } |
| } |
| if (CoreAddress == GPP3a_CORE ) { |
| if ((UINT16)PadsMap == 0x3F3F) { |
| PowerOfPllValue = BIT18 | BIT16; |
| //TxClockOffValue = BIT2; |
| } |
| } |
| if (CoreAddress == GPP3b_CORE ) { |
| PowerOfPllRegister = NB_MISC_REG2E; |
| if ((UINT16)PadsMap == 0x0F0F) { |
| PowerOfPllValue = BIT8 | BIT6; |
| //TxClockOffValue = BIT3; |
| } |
| } |
| //Power Off Pll |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_MISC_INDEX, PowerOfPllRegister , AccessS3SaveWidth32, 0xffffffff, PowerOfPllValue, pConfig); |
| CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Power off PLL CoreId %d, Value 0x%x\n", CoreId, PowerOfPllValue)); |
| //Turn off TXCLK |
| //LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_MISC_INDEX, NB_MISC_REG07, AccessS3SaveWidth32, 0xffffffff, TxClockOffValue, pConfig); |
| } |
| |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Enable TX clock gating or shutdown TX clock if possible |
| * |
| * |
| * |
| * @param[in] CoreId PCI Express Core ID |
| * @param[in] pConfig Northbridge configuration structure pointer. * |
| */ |
| VOID |
| PcieLibManageTxClock ( |
| IN CORE CoreId, |
| IN AMD_NB_CONFIG *pConfig |
| ) |
| { |
| PCIE_CONFIG *pPcieConfig; |
| UINT32 CoreAddress; |
| UINT32 Value; |
| pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); |
| CoreAddress = PcieLibGetCoreAddress (CoreId, pConfig); |
| if (pPcieConfig->CoreSetting[CoreId].TxClockGating == ON) { |
| switch (CoreAddress) { |
| case GPP1_CORE: |
| Value = BIT4; |
| break; |
| case GPP2_CORE: |
| Value = BIT5; |
| break; |
| case GPP3a_CORE: |
| Value = BIT6; |
| break; |
| case GPP3b_CORE: |
| Value = BIT24; |
| break; |
| case SB_CORE: |
| Value = BIT7; |
| break; |
| default: |
| Value = 0; |
| CIMX_ASSERT (FALSE); |
| } |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_MISC_INDEX, NB_MISC_REG07, AccessS3SaveWidth32, 0xffffffff, Value, pConfig); |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, NB_BIFNB_REG40 | CoreAddress, AccessS3SaveWidth32, (UINT32)~BIT6, BIT6, pConfig); |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, NB_BIFNB_REG11 | CoreAddress, AccessS3SaveWidth32, 0xfffffff0, 0x0C, pConfig); |
| } |
| if (pPcieConfig->CoreSetting[CoreId].TxClockOff == ON) { |
| UINT8 ActiveCoreMap; |
| ActiveCoreMap = PcieLibGetActiveCoreMap (pConfig); |
| if ((ActiveCoreMap & (1 << CoreId)) == 0) { |
| //Core not active we can shutdown TX clk permanantly |
| CORE_INFO *pCoreInfo; |
| CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Shutdown TX clock\n")); |
| pPcieConfig->CoreSetting[CoreId].CoreDisableStatus = ON; |
| pCoreInfo = PcieLibGetCoreInfo (CoreId, pConfig); |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_MISC_INDEX, NB_MISC_REG07, AccessS3SaveWidth32, 0xffffffff, 1 << pCoreInfo->TxOffOffset, pConfig); |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Enable Pll Power Down in L1. |
| * |
| * |
| * |
| * @param[in] CoreId PCI Express Core ID |
| * @param[in] pConfig Northbridge configuration structure pointer. * |
| */ |
| VOID |
| PcieLibEnablePllPowerOffInL1 ( |
| IN CORE CoreId, |
| IN AMD_NB_CONFIG *pConfig |
| ) |
| { |
| PCIE_CONFIG *pPcieConfig; |
| UINT32 Value; |
| UINT32 CoreAddress; |
| PORT PortId; |
| pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); |
| if (pPcieConfig->CoreSetting[CoreId].DetectPowerOffPllInL1 == ON && !PciePllOffComatibilityTest (CoreId, pConfig)) { |
| return; |
| } |
| for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) { |
| if (PcieLibIsValidPortId (PortId, pConfig) && PcieLibGetCoreId (PortId, pConfig) == CoreId) { |
| if (pPcieConfig->PortConfiguration[PortId].PortHotplug != OFF) { |
| // set up max exit latency requirment for hotplug ports |
| PCI_ADDR Port; |
| Port = PcieLibGetPortPciAddress (PortId, pConfig); |
| LibNbPciIndexRMW (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REGC1 , AccessS3SaveWidth32, 0xffffffff, 0xf, pConfig); |
| } |
| } |
| } |
| CoreAddress = PcieLibGetCoreAddress (CoreId, pConfig); |
| Value = BIT8; |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, NB_BIFNB_REG40 | CoreAddress, AccessS3SaveWidth32, (UINT32)~(BIT9 + BIT4), BIT3 + BIT0 + BIT12, pConfig); |
| if (CoreAddress == GPP3b_CORE || CoreAddress == GPP3a_CORE || CoreAddress == SB_CORE) { |
| Value |= BIT3; |
| } |
| LibNbPciIndexRMW (pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, NB_BIFNB_REG02 | CoreAddress, AccessS3SaveWidth32, 0xffffffff, Value, pConfig); |
| } |
| |
| /*----------------------------------------------------------------------------------------*/ |
| /** |
| * Misc. core setting. |
| * |
| * |
| * |
| * @param[in] CoreId PCI Express- Core ID |
| * @param[in] pConfig Northbridge configuration structure pointer. |
| */ |
| VOID |
| PcieLibMiscLateCoreSetting ( |
| IN CORE CoreId, |
| IN AMD_NB_CONFIG *pConfig |
| ) |
| { |
| //Lock |
| LibNbPciIndexRMW ( |
| pConfig->NbPciAddress.AddressValue | NB_BIF_INDEX, |
| NB_BIFNB_REG10 | PcieLibGetCoreAddress (CoreId, pConfig), |
| AccessS3SaveWidth32, |
| 0xffffffff, |
| BIT0, |
| pConfig |
| ); |
| } |