blob: 17ae4f746bef19f91839c656628c05ae345c8d61 [file] [log] [blame]
/**
* @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);
}
}
}