/** * @file * * PCIE Late Initialization * * * * @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" #include "amdSbLib.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 *---------------------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------------------- * P R O T O T Y P E S O F L O C A L F U N C T I O N S *---------------------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------------------- * E X P O R T E D F U N C T I O N S *---------------------------------------------------------------------------------------- */ /*----------------------------------------------------------------------------------------*/ /** * Amd PCIE Late Init for all NB. * * * @param[in] ConfigPtr Northbridges configuration block pointer. * */ AGESA_STATUS AmdPcieLateInit ( IN AMD_NB_CONFIG_BLOCK *ConfigPtr ) { AGESA_STATUS Status; Status = LibNbApiCall (PcieLateInit, ConfigPtr); return Status; } /*----------------------------------------------------------------------------------------*/ /** * Amd PCIE Late Init for all NB. * * * @param[in] ConfigPtr Northbridges configuration block pointer. * */ AGESA_STATUS AmdPcieLateInitWa ( IN AMD_NB_CONFIG_BLOCK *ConfigPtr ) { AGESA_STATUS Status; Status = LibNbApiCall (PcieLateInitWa, ConfigPtr); return Status; } /*----------------------------------------------------------------------------------------*/ /** * Amd PCIE Special Init for all NB. * * * @param[in] ConfigPtr Northbridges configuration block pointer. * */ AGESA_STATUS AmdPcieValidatePortState ( IN AMD_NB_CONFIG_BLOCK *ConfigPtr ) { AGESA_STATUS Status; Status = LibNbApiCall (PcieValidatePortState, ConfigPtr); return Status; } /*----------------------------------------------------------------------------------------*/ /** * Amd PCIE S3 Init fro all NB. * * * @param[in] ConfigPtr Northbridges configuration block pointer. * */ AGESA_STATUS AmdPcieS3Init ( IN AMD_NB_CONFIG_BLOCK *ConfigPtr ) { AGESA_STATUS Status; Status = LibNbApiCall (PcieLateInit, ConfigPtr); return Status; } /*----------------------------------------------------------------------------------------*/ /** * NB PCIE Late Init. * Extended programming. Enable power management and misc capability. * Prepare PCIE subsystem to boot to OS. * * * @param[in] NbConfigPtr Northbridge configuration structure pointer. * */ AGESA_STATUS PcieLateInit ( IN AMD_NB_CONFIG *NbConfigPtr ) { AGESA_STATUS Status; PcieLibUnHidePorts (NbConfigPtr); Status = PcieLateValidateConfiguration (NbConfigPtr); if (Status == AGESA_FATAL) { PcieLibHidePorts (NbConfigPtr); REPORT_EVENT (AGESA_FATAL, GENERAL_ERROR_BAD_CONFIGURATION, 0, 0, 0, 0, NbConfigPtr); CIMX_ASSERT (FALSE); return Status; } PcieLibLateInit (NbConfigPtr); Status = PcieLateInitPorts (NbConfigPtr); Status = PcieLateInitCores (NbConfigPtr); PcieLibHidePorts (NbConfigPtr); return Status; } /*----------------------------------------------------------------------------------------*/ /** * NB PCIE Late Init. * Extended programming. Enable power management and misc capability. * Prepare PCIE subsystem to boot to OS. * * * @param[in] NbConfigPtr Northbridge configuration structure pointer. * */ AGESA_STATUS PcieLateInitWa ( IN AMD_NB_CONFIG *NbConfigPtr ) { UINT32 Value; BOOLEAN SmuWa; LibNbPciIndexRead (NbConfigPtr->NbPciAddress.AddressValue | NB_MISC_INDEX, NB_MISC_REG4A, AccessWidth32, &Value, NbConfigPtr); SmuWa = ((Value & BIT21) != 0) ? TRUE : FALSE; if (SmuWa) { UINT32 SmuWaData; LibNbMcuControl (AssertReset, NbConfigPtr); SmuWaData = LibNbReadMcuRam (0xFE74, NbConfigPtr); SmuWaData &= 0x00ff; LibNbLoadMcuFirmwareBlock (0xFE74, 0x1, &SmuWaData, NbConfigPtr); LibNbMcuControl (DeAssertReset, NbConfigPtr); } return AGESA_SUCCESS; } /*----------------------------------------------------------------------------------------*/ /** * Late init PCIE Ports * * * * @param[in] NbConfigPtr Northbridge configuration structure pointer. * */ AGESA_STATUS PcieLateInitPorts ( IN AMD_NB_CONFIG *NbConfigPtr ) { AGESA_STATUS Status; PCIE_CONFIG *pPcieConfig; PORT PortId; BOOLEAN IsIommuEnabled; NB_INFO NbInfo; CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (NbConfigPtr), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieLateInitPorts Enter\n")); IsIommuEnabled = LibNbIsIommuEnabled (NbConfigPtr); NbInfo = LibNbGetRevisionInfo (NbConfigPtr); pPcieConfig = GET_PCIE_CONFIG_PTR (NbConfigPtr); Status = AGESA_SUCCESS; for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) { CORE CoreId; CoreId = PcieLibGetCoreId (PortId, NbConfigPtr); if (!PcieLibIsValidCoreId (CoreId, NbConfigPtr)) { PcieLibPowerOffPortLanes (PortId, PcieLinkWidth_x0, NbConfigPtr); } else if (PcieLibIsValidPortId (PortId, NbConfigPtr)) { PCIE_LINK_WIDTH LinkWidth; PCI_ADDR Port; LinkWidth = PcieLibGetLinkWidth (PortId, NbConfigPtr); CoreId = PcieLibGetCoreId (PortId, NbConfigPtr); Port = PcieLibGetPortPciAddress (PortId, NbConfigPtr); PcieLateCommonPortInit (PortId, NbConfigPtr); if (pPcieConfig->PortConfiguration[PortId].PortDetected == ON) { if (pPcieConfig->PortConfiguration[PortId].PortLinkMode == PcieLinkModeGen2SoftwareInitiated) { PcieInitiateSoftwareGen2 (PortId, NbConfigPtr); } PcieAsmpEnableOnPort (PortId, (UINT8)pPcieConfig->PortConfiguration[PortId].PortAspm, NbConfigPtr); } LibNbPciIndexRMW (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REG70 , AccessS3SaveWidth32, (UINT32)~BIT12, 0, NbConfigPtr); //PCIE should not ignore malformed packet error or ATS request if (pPcieConfig->PortConfiguration[PortId].PortCompliance == OFF && pPcieConfig->PortConfiguration[PortId].PortHotplug == OFF && pPcieConfig->CoreSetting[CoreId].PowerOffUnusedLanes == ON) { PcieLibPowerOffPortLanes (PortId, LinkWidth, NbConfigPtr); } } } CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (NbConfigPtr), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieLateInitPorts Exit\n")); return Status; } /*----------------------------------------------------------------------------------------*/ /** * Late init PCIE Cores. Core level feature/power management etc. * * * * @param[in] pConfig Northbridge configuration structure pointer. * */ AGESA_STATUS PcieLateInitCores ( IN AMD_NB_CONFIG *pConfig ) { AGESA_STATUS Status; PCIE_CONFIG *pPcieConfig; CORE CoreId; CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieLateInitCores Enter\n")); Status = AGESA_SUCCESS; pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); for (CoreId = 0; CoreId <= MAX_CORE_ID; CoreId++) { CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " Init CoreId [%d]\n", CoreId)); if (pPcieConfig->CoreSetting[CoreId].PowerOffPllInL1 == ON) { PcieLibEnablePllPowerOffInL1 (CoreId, pConfig); } if (pPcieConfig->CoreSetting[CoreId].PowerOffPll == ON) { PcieLibPowerOffPll (CoreId, pConfig); } PcieLibMiscLateCoreSetting (CoreId, pConfig); PcieLibManageTxClock (CoreId, pConfig); PcieLibManageLclkClock (CoreId, pConfig); } #ifndef VC1_SUPPORT_DISABLE if (NB_SBDFO == 0 && pPcieConfig->PcieConfiguration.NbSbVc1 == ON) { PcieNbSbSetupVc (pConfig); } #endif CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieLateInitCores Exit\n")); return Status; } /*----------------------------------------------------------------------------------------*/ /* * Set up NB-SB virtual channel for audio traffic * * * * @param[in] pConfig Northbridge configuration structure pointer. * */ VOID PcieNbSbSetupVc ( IN AMD_NB_CONFIG *pConfig ) { UINT32 VCStatus; PCI_ADDR Port; Port = PcieLibGetPortPciAddress (8, pConfig); if (PcieSbSetupVc (pConfig) == AGESA_SUCCESS) { LibNbPciRMW (Port.AddressValue | NB_PCIP_REG124, AccessS3SaveWidth8, 0x01, 0, pConfig); LibNbPciRMW (Port.AddressValue | NB_PCIP_REG130, AccessS3SaveWidth32, (UINT32)~(BIT24 + BIT25 + BIT26), 0xFE + BIT24, pConfig); LibNbPciRMW (Port.AddressValue | NB_PCIP_REG130, AccessS3SaveWidth32, 0xffffffff, BIT31, pConfig); do { STALL (GET_BLOCK_CONFIG_PTR (pConfig), 200, CIMX_S3_SAVE); LibNbPciRead (Port.AddressValue | NB_PCIP_REG134, AccessWidth32, &VCStatus, pConfig); } while (VCStatus & BIT17); PcieSbEnableVc (pConfig); } } /*----------------------------------------------------------------------------------------*/ /* * Late common Port Init * * * @param[in] PortId Port Id * @param[in] pConfig Northbridge configuration structure pointer. * */ AGESA_STATUS PcieLateCommonPortInit ( IN PORT PortId, IN AMD_NB_CONFIG *pConfig ) { AGESA_STATUS Status; Status = AGESA_SUCCESS; return Status; } /*----------------------------------------------------------------------------------------*/ /* * Initiate SW Gen2 switch * * * * @param[in] PortId Port Id. * @param[in] pConfig Northbridge configuration structure pointer. * */ VOID PcieInitiateSoftwareGen2 ( IN PORT PortId, IN AMD_NB_CONFIG *pConfig ) { UINT8 LinkSpeedCap; UINT8 PcieCapPtr; UINT8 SecondaryBus; UINT32 Value; UINT32 Counter; PCI_ADDR Ep; PCI_ADDR Port; CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieInitiateSoftwareGen2 PortId[%d] Enter\n", PortId)); Counter = 5000; Port = PcieLibGetPortPciAddress (PortId, pConfig); LibNbPciRead (Port.AddressValue | NB_PCIP_REG19, AccessWidth8, &SecondaryBus, pConfig); Ep.AddressValue = 0; Ep.Address.Bus = SecondaryBus; CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE] SecondaryBus = 0x%x \n", SecondaryBus)); PcieCapPtr = LibNbFindPciCapability (Ep.AddressValue, PCIE_CAP_ID, pConfig); LibNbPciRead (Ep.AddressValue | (PcieCapPtr + 0xC), AccessWidth8, &LinkSpeedCap, pConfig); CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE] PcieCapPtr = 0x%x \n", PcieCapPtr)); if ((LinkSpeedCap & 0xf) < 2) { return; } PcieLibSetLinkMode (PortId, PcieLinkModeGen2, pConfig); LibNbPciIndexRMW (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REGA4 , AccessS3SaveWidth32, (UINT32)~(BIT18), BIT18 , pConfig); do { STALL (GET_BLOCK_CONFIG_PTR (pConfig), 200, CIMX_S3_SAVE); LibNbPciIndexRead (Port.AddressValue | NB_PCIP_REGE0, NB_BIFNBP_REGA5, AccessWidth32, &Value, pConfig); } while ((UINT8)Value != 0x10 && Counter-- != 0); LibNbPciIndexRead (Port.AddressValue | NB_PCIP_REGE0, NB_BIFNBP_REGA4, AccessWidth32, &Value, pConfig); if ((Value & BIT24) != 0) { //Initiate link speed change LibNbPciIndexRMW (Port.AddressValue | NB_PCIP_REGE0, NB_BIFNBP_REGA4, AccessS3SaveWidth32, ((UINT32)~BIT7), BIT7, pConfig); } CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieInitiateSoftwareGen2 Exit\n")); } /*----------------------------------------------------------------------------------------*/ /** * Validate input parameters configuration for PCie Late Init call. * * * * @param[in] pConfig Northbridge configuration structure pointer. * */ AGESA_STATUS PcieLateValidateConfiguration ( IN AMD_NB_CONFIG *pConfig ) { PCIE_CONFIG *pPcieConfig; NB_INFO NbInfo; CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieLateValidateConfiguration Enter\n")); pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig); NbInfo = LibNbGetRevisionInfo (pConfig); if (pPcieConfig == NULL) { REPORT_EVENT (AGESA_FATAL, GENERAL_ERROR_BAD_CONFIGURATION, 0, 0, 0, 0, pConfig); CIMX_ASSERT (FALSE); return AGESA_FATAL; } if (pPcieConfig->sHeader.InitializerID != INITIALIZED_BY_INITIALIZER) { PcieLibInitializer (pConfig); } CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieLateValidateConfiguration Exit\n")); return AGESA_SUCCESS; } /*----------------------------------------------------------------------------------------*/ /** * PcieValidatePortState * Port disable or port visibility control * * * @param[in] NbConfigPtr Northbridge configuration structure pointer. * */ AGESA_STATUS PcieValidatePortState ( IN AMD_NB_CONFIG *NbConfigPtr ) { AGESA_STATUS Status; Status = AGESA_SUCCESS; PcieLibUnHidePorts (NbConfigPtr); PcieLibValidatePortStateInit (NbConfigPtr); PcieForcePortsVisibleOrDisable (NbConfigPtr); PcieLibHidePorts (NbConfigPtr); return Status; } /*----------------------------------------------------------------------------------------*/ /** * PciePortsVisibleOrDisable * Set ports always visible or disable based on input parameter * * * * @param[in] NbConfigPtr Northbridge configuration structure pointer. * */ VOID PcieForcePortsVisibleOrDisable ( IN AMD_NB_CONFIG *NbConfigPtr ) { PCIE_CONFIG *pPcieConfig; PORT PortId; PCI_ADDR Port; pPcieConfig = GET_PCIE_CONFIG_PTR (NbConfigPtr); for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) { if (PcieLibIsValidPortId (PortId, NbConfigPtr)) { Port = PcieLibGetPortPciAddress (PortId, NbConfigPtr); if (pPcieConfig->PortConfiguration[PortId].ForcePortDisable == ON ) { pPcieConfig->PortConfiguration[PortId].PortPresent = OFF; pPcieConfig->PortConfiguration[PortId].PortDetected = OFF; } if (pPcieConfig->PortConfiguration[PortId].PortAlwaysVisible == ON) { LibNbPciIndexRMW (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REG70, AccessWidth32, (UINT32)~BIT19, BIT19, NbConfigPtr); pPcieConfig->PortConfiguration[PortId].PortPresent = ON; pPcieConfig->PortConfiguration[PortId].PortDetected = ON; } LibNbPciIndexWrite (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REG01, AccessWidth32, (UINT32*)&pPcieConfig->PortConfiguration[PortId], NbConfigPtr); } } }