aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/cimx/rd890/nbPcieInitEarly.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode/amd/cimx/rd890/nbPcieInitEarly.c')
-rw-r--r--src/vendorcode/amd/cimx/rd890/nbPcieInitEarly.c720
1 files changed, 720 insertions, 0 deletions
diff --git a/src/vendorcode/amd/cimx/rd890/nbPcieInitEarly.c b/src/vendorcode/amd/cimx/rd890/nbPcieInitEarly.c
new file mode 100644
index 0000000000..6fdf2b120c
--- /dev/null
+++ b/src/vendorcode/amd/cimx/rd890/nbPcieInitEarly.c
@@ -0,0 +1,720 @@
+/**
+ * @file
+ *
+ * PCIe Early 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
+ *----------------------------------------------------------------------------------------
+ */
+
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * PCIE Init for all NB.
+ * Basic programming / EP training. After this call EP are fully operational.
+ *
+ *
+ *
+ * @param[in] ConfigPtr Northbridges configuration block pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+AmdPcieEarlyInit (
+ IN OUT AMD_NB_CONFIG_BLOCK *ConfigPtr
+ )
+{
+ AGESA_STATUS Status;
+
+ Status = LibNbApiCall (PcieEarlyInit, ConfigPtr);
+ return Status;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Northbridge PCIE Init.
+ * Basic programming / EP training. After this call EP are fully operational on particular NB.
+ *
+ *
+ *
+ * @param[in] NbConfigPtr Northbridge configuration structure pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieEarlyInit (
+ IN OUT AMD_NB_CONFIG *NbConfigPtr
+ )
+{
+ AGESA_STATUS Status;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (NbConfigPtr), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieEarlyInit Enter\n"));
+ Status = PcieLibInitValidateInput (NbConfigPtr);
+ if (Status == AGESA_FATAL) {
+ REPORT_EVENT (AGESA_FATAL, GENERAL_ERROR_BAD_CONFIGURATION, 0 , 0, 0, 0, NbConfigPtr);
+ CIMX_ASSERT (FALSE);
+ return Status;
+ }
+ Status = PciePreTrainingInit (NbConfigPtr);
+ Status = PcieInitPorts (NbConfigPtr);
+ Status = PcieAfterTrainingInit (NbConfigPtr);
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (NbConfigPtr), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieEarlyInit Exit [0x%x]\n", Status));
+ return Status;
+}
+
+
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Misc initialization prior port link training started
+ *
+ *
+ *
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PciePreTrainingInit (
+ IN OUT AMD_NB_CONFIG *pConfig
+ )
+{
+ PCIE_CONFIG *pPcieConfig;
+ CORE CoreId ;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PciePreTrainingInit Enter\n"));
+ pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig);
+ //Unhide all ports
+ PcieLibUnHidePorts (pConfig);
+ if (pPcieConfig->PcieMmioBaseAddress != 0 && pPcieConfig->PcieMmioSize != 0) {
+ PcieLibSetPcieMmioBase (pPcieConfig->PcieMmioBaseAddress, pPcieConfig->PcieMmioSize, pConfig);
+ }
+ for (CoreId = 0; CoreId <= MAX_CORE_ID; CoreId++) {
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " CoreId %d CoreSetting = 0x%x\n", CoreId, *((UINT32*)&pConfig->pPcieConfig->CoreSetting[CoreId])));
+ //if (pPcieConfig->CoreSetting[CoreId].CoreDisabled == OFF) {
+ //Configure cores
+ if (pPcieConfig->CoreSetting[CoreId].SkipConfiguration == OFF) {
+ PcieLibSetCoreConfiguration (CoreId, pConfig);
+ }
+ //Init core registers
+ PcieLibCommonCoreInit (CoreId, pConfig);
+ //}
+ }
+ PcieLibPreTrainingInit (pConfig);
+ for (CoreId = 0; CoreId <= MAX_CORE_ID; CoreId++) {
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " CoreId %d CoreSetting = 0x%x\n", CoreId, *((UINT32*)&pConfig->pPcieConfig->CoreSetting[CoreId])));
+ //Init CPL buffer allocation
+ //if (pPcieConfig->CoreSetting[CoreId].CoreDisabled == OFF && pPcieConfig->CoreSetting[CoreId].CplBufferAllocation == ON) {
+ if (pPcieConfig->CoreSetting[CoreId].CplBufferAllocation == ON) {
+ PcieLibCplBufferAllocation (CoreId, pConfig);
+ }
+ }
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PciePreTrainingInit Exit\n"));
+ return AGESA_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Misc initialization after port training complete
+ *
+ *
+ *
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieAfterTrainingInit (
+ IN AMD_NB_CONFIG *pConfig
+ )
+{
+ PCIE_CONFIG *pPcieConfig;
+ CORE CoreId;
+
+ pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig);
+ for (CoreId = 0; CoreId <= MAX_CORE_ID; CoreId++) {
+// if (pPcieConfig->CoreSetting[CoreId].CoreDisabled == OFF) {
+ //Configure cores
+ PcieLibCoreAfterTrainingInit (CoreId, pConfig);
+// }
+ }
+ //Hide all Ports
+ PcieLibHidePorts (pConfig);
+ return AGESA_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Train PCIE Ports
+ *
+ *
+ *
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieInitPorts (
+ IN OUT AMD_NB_CONFIG *pConfig
+ )
+{
+ AGESA_STATUS Status;
+ PCIE_CONFIG *pPcieConfig;
+
+ Status = AGESA_SUCCESS;
+ pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig);
+ if (pPcieConfig->DeviceInitMaskS1 != 0) {
+ Status = PcieInitSelectedPorts (pPcieConfig->DeviceInitMaskS1, pConfig);
+ }
+ if (pPcieConfig->DeviceInitMaskS2 != 0) {
+ Status = PcieInitSelectedPorts (pPcieConfig->DeviceInitMaskS2, pConfig);
+ }
+ return Status;
+}
+
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Train PCIE Ports selected for this stage
+ *
+ *
+ * @param[in] SelectedPortMask Bitmap of port ID selected for training.
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieInitSelectedPorts (
+ IN UINT16 SelectedPortMask,
+ IN OUT AMD_NB_CONFIG *pConfig
+ )
+{
+ AGESA_STATUS Status;
+ PCIE_CONFIG *pPcieConfig;
+ PORT PortId;
+ BOOLEAN RequestResetDelay;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieInitSelectedPorts (Ports = 0x%x) Enter\n", SelectedPortMask));
+ pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig);
+ Status = AGESA_SUCCESS;
+ RequestResetDelay = FALSE;
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " PortId %d PortConfiguration = 0x%x ExtPortConfiguration = 0x%x\n", PortId, *((UINT32*)&pPcieConfig->PortConfiguration[PortId]), *((UINT32*)&pPcieConfig->ExtPortConfiguration[PortId])));
+ if ((SelectedPortMask & (1 << PortId)) != 0) {
+ if (pPcieConfig->PortConfiguration[PortId].PortPresent == ON && PcieLibIsValidPortId (PortId, pConfig)) {
+ PCIE_LINK_MODE LinkMode;
+ //Deassert slot reset. Bring EP out of reset
+ Status = LibNbCallBack (PHCB_AmdPortResetDeassert, 1 << PortId, pConfig);
+ if (Status == AGESA_SUCCESS) {
+ //STALL (GET_BLOCK_CONFIG_PTR (pConfig), pPcieConfig->ResetToTrainingDelay * 1000, 0);
+ RequestResetDelay = TRUE;
+ }
+ //Init common registers
+ PcieLibCommonPortInit (PortId, pConfig);
+ //Check if we already have device failure to go to Gen2 before
+ if (PcieLibCheckGen2Disabled (PortId, pConfig)) {
+ pPcieConfig->PortConfiguration[PortId].PortLinkMode = PcieLinkModeGen1;
+ pPcieConfig->ExtPortConfiguration[PortId].PortDeemphasis = PcieTxDeemphasis6dB; // this is to workaround Gen2
+ }
+ //@todo Add handling for scratch register for PCIE Gen
+ switch (pPcieConfig->PortConfiguration[PortId].PortLinkMode) {
+ case PcieLinkModeGen2:
+ case PcieLinkModeGen2AdvertizeOnly:
+ case PcieLinkModeGen1:
+ LinkMode = pPcieConfig->PortConfiguration[PortId].PortLinkMode;
+ break;
+ default:
+ LinkMode = PcieLinkModeGen1;
+ }
+ PcieLibSetLinkMode (PortId, LinkMode, pConfig);
+ //Enable Compliance Mode
+ if (pPcieConfig->PortConfiguration[PortId].PortCompliance == ON) {
+ PcieLibSetLinkCompliance (PortId, pConfig);
+ }
+ } else {
+ //Port disabled
+ SelectedPortMask &= (~(1 << PortId));
+ }
+ }
+ }
+ if (RequestResetDelay) {
+ STALL (GET_BLOCK_CONFIG_PTR (pConfig), pPcieConfig->ResetToTrainingDelay * 1000, 0);
+ }
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ if ((SelectedPortMask & (1 << PortId)) != 0) {
+ //Release Port Training
+ PcieLibPortTrainingControl (PortId, PcieLinkTrainingRelease, pConfig);
+ }
+ }
+ STALL (GET_BLOCK_CONFIG_PTR (pConfig), pPcieConfig->TrainingToLinkTestDelay * 1000, 0);
+ Status = PcieCheckSelectedPorts (SelectedPortMask, pConfig);
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieInitSelectedPorts Exit\n"));
+ return Status;
+}
+
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Check link state on selected ports.
+ *
+ *
+ *
+ * @param[in] SelectedPortMask Bitmap of port ID selected for training.
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieCheckSelectedPorts (
+ IN UINT16 SelectedPortMask,
+ IN AMD_NB_CONFIG *pConfig
+ )
+{
+ AGESA_STATUS Status;
+ PCIE_CONFIG *pPcieConfig;
+ PORT PortId;
+ UINT16 PortMask;
+ UINT16 CurrentPortMask;
+ PCIE_LINK_STATUS PortsLinkStatus[MAX_PORT_ID + 1];
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieCheckSelectedPorts (Ports = 0x%x) Enter\n", SelectedPortMask));
+ Status = AGESA_SUCCESS;
+ pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig);
+ PortMask = SelectedPortMask;
+ // Clear up link state storage
+ LibAmdMemFill (PortsLinkStatus, 0, sizeof (PortsLinkStatus), (AMD_CONFIG_PARAMS *)&(pPcieConfig->sHeader));
+ // Initial check for link status on all ports
+ if (PortMask != 0) {
+ PcieGetPortsLinkStatus (PortMask, &PortsLinkStatus[0], pPcieConfig->ReceiverDetectionPooling, pConfig);
+ }
+ // Check if training on any ports in progress
+ PortMask = PcieFindPortsWithLinkStatus (&PortsLinkStatus[0], PcieLinkStatusTrainingInProgress);
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " #1 PortMask = 0x%x\n", PortMask));
+ if (PortMask != 0) {
+ // Try to recover ports in case of broken lane
+ if (PcieBrokenLaneWorkaround (PortMask, pConfig) != AGESA_UNSUPPORTED) {
+ // Update port status array
+ PortMask |= PcieFindPortsWithLinkStatus (&PortsLinkStatus[0], PcieLinkStatusConnected);
+ PcieGetPortsLinkStatus (PortMask, &PortsLinkStatus[0], pPcieConfig->ReceiverDetectionPooling, pConfig);
+ }
+ }
+ // Check if training on any ports still in progress
+ CurrentPortMask = PcieFindPortsWithLinkStatus (&PortsLinkStatus[0], PcieLinkStatusTrainingInProgress);
+ if (PortMask != CurrentPortMask) {
+ REPORT_EVENT (AGESA_WARNING, PCIE_ERROR_BROKEN_LINE, (PortMask^CurrentPortMask)&PortMask, 0, 0, 0, pConfig);
+ }
+ PortMask = CurrentPortMask;
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " #2 PortMask = 0x%x\n", PortMask));
+ if (PortMask != 0) {
+ // Try to recover port training by downgrading link speed to Gen1
+ if (PcieGen2Workaround (PortMask, pConfig) != AGESA_UNSUPPORTED) {
+ PortMask |= PcieFindPortsWithLinkStatus (&PortsLinkStatus[0], PcieLinkStatusConnected);
+ PcieGetPortsLinkStatus (PortMask, &PortsLinkStatus[0], pPcieConfig->ReceiverDetectionPooling, pConfig);
+ }
+ }
+ // Check if training on any ports still in progress
+ CurrentPortMask = PcieFindPortsWithLinkStatus (&PortsLinkStatus[0], PcieLinkStatusTrainingInProgress);
+ if (PortMask != CurrentPortMask) {
+ REPORT_EVENT (AGESA_WARNING, PCIE_ERROR_GEN2_FAIL, (PortMask^CurrentPortMask)&PortMask, 0, 0, 0, pConfig);
+ }
+ PortMask = CurrentPortMask;
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " #3 PortMask = 0x%x\n", PortMask));
+ if (PortMask != 0) {
+ REPORT_EVENT (AGESA_WARNING, PCIE_ERROR_TRAINING_FAIL, PortMask, 0, 0, 0, pConfig);
+ PcieMiscWorkaround (&PortsLinkStatus[0], pConfig);
+ }
+ //Get bitmap of successfully trained ports
+ PortMask = PcieFindPortsWithLinkStatus (&PortsLinkStatus[0], PcieLinkStatusConnected);
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), " #4 PortMask = 0x%x\n", PortMask));
+ if (PortMask != 0) {
+ // Check if VCO negotiation is completed
+ PcieCheckVco (PortMask, &PortsLinkStatus[0], pConfig);
+ }
+ CurrentPortMask = PcieFindPortsWithLinkStatus (&PortsLinkStatus[0], PcieLinkStatusConnected);
+ if (PortMask != CurrentPortMask) {
+ REPORT_EVENT (AGESA_WARNING, PCIE_ERROR_VCO_NEGOTIATON, (PortMask^CurrentPortMask)&PortMask, 0, 0, 0, pConfig);
+ }
+ PortMask = CurrentPortMask;
+ //Update status port status info
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ if ((SelectedPortMask & (1 << PortId)) != 0) {
+ PCI_ADDR Port;
+ Port = PcieLibGetPortPciAddress (PortId, pConfig);
+ if (PortsLinkStatus[PortId] == PcieLinkStatusInCompliance) {
+ pPcieConfig->PortConfiguration[PortId].PortCompliance = ON;
+ } else {
+ if (PortsLinkStatus[PortId] == PcieLinkStatusConnected) {
+ if (LibNbCallBack (PHCB_AmdPortTrainingCompleted, Port.AddressValue, pConfig) == AGESA_ERROR) {
+ PortsLinkStatus[PortId] = 0;
+ }
+ if (PortsLinkStatus[PortId] == PcieLinkStatusConnected &&
+ pPcieConfig->PcieConfiguration.DisableGfxWorkaround == OFF &&
+ PcieLibGetPortLinkInfo (PortId, pConfig).MaxLinkWidth >= PcieLinkWidth_x8 &&
+ PcieGfxWorkarounds (PortId, pConfig) != AGESA_SUCCESS) {
+ //CIMX_ASSERT (FALSE);
+ PortsLinkStatus[PortId] = 0;
+ }
+ if (PortsLinkStatus[PortId] == PcieLinkStatusConnected) {
+ pPcieConfig->PortConfiguration[PortId].PortDetected = ON;
+ PcieLibSetLinkWidth (PortId, pPcieConfig->ExtPortConfiguration[PortId].PortLinkWidth, pConfig);
+ }
+ }
+ if (pPcieConfig->PortConfiguration[PortId].PortDetected == OFF &&
+ pPcieConfig->PortConfiguration[PortId].PortHotplug == OFF) {
+ //Port training on Hold if Link in not connected and not in compliance
+ PcieLibPortTrainingControl (PortId, PcieLinkTrainingHold, pConfig);
+ }
+ }
+ if (pPcieConfig->PortConfiguration[PortId].PortDetected == OFF ||
+ pPcieConfig->PortConfiguration[PortId].PortHotplug == ON) {
+ // For all port without devices and hotplug ports
+ LibNbPciIndexRMW (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REG70, AccessWidth32, (UINT32)~BIT19, BIT19, pConfig);
+ }
+ LibNbPciIndexWrite (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REG01, AccessWidth32, (UINT32*)&pPcieConfig->PortConfiguration[PortId], pConfig);
+ LibNbPciWrite (Port.AddressValue | NB_PCIP_REG108, AccessWidth32, (UINT32*)&pPcieConfig->ExtPortConfiguration[PortId], pConfig);
+ }
+ }
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieCheckSelectedPorts Exit\n"));
+ return Status;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Workaround for broken TX line.
+ *
+ *
+ *
+ * @param[in] SelectedPortMask Bitmap of port ID selected for training.
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieBrokenLaneWorkaround (
+ IN UINT16 SelectedPortMask,
+ IN AMD_NB_CONFIG *pConfig
+ )
+{
+ AGESA_STATUS Status;
+ PORT PortId;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieBrokenLaneWorkaround Enter\n"));
+ Status = AGESA_UNSUPPORTED;
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ if ((SelectedPortMask & (1 << PortId)) != 0) {
+ LINK_INFO LinkInfo = PcieLibGetPortLinkInfo (PortId, pConfig);
+ if (LinkInfo.MaxLinkWidth > PcieLinkWidth_x1 && LinkInfo.LinkWidth < LinkInfo.MaxLinkWidth) {
+ PcieLibPowerOffPortLanes (PortId, LinkInfo.LinkWidth, pConfig);
+ if (PcieLibResetSlot (PortId, pConfig) == AGESA_SUCCESS) {
+ Status = AGESA_SUCCESS;
+ }
+ }
+ }
+ }
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieBrokenLaneWorkaround Exit\n"));
+ return Status;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Workaround for device violating Gen2 spec.
+ * Downgrade link speed to Gen1.
+ *
+ *
+ *
+ * @param[in] SelectedPortMask Bitmap of port ID selected for training.
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieGen2Workaround (
+ IN UINT16 SelectedPortMask,
+ IN AMD_NB_CONFIG *pConfig
+ )
+{
+ AGESA_STATUS Status;
+ PCIE_CONFIG *pPcieConfig;
+ PORT PortId;
+ BOOLEAN RequestPciReset;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieGen2Workaround Enter\n"));
+ pPcieConfig = GET_PCIE_CONFIG_PTR (pConfig);
+ RequestPciReset = FALSE;
+ Status = AGESA_UNSUPPORTED;
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ if ((SelectedPortMask & (1 << PortId)) != 0) {
+ if (pPcieConfig->PortConfiguration[PortId].PortLinkMode == PcieLinkModeGen2 ||
+ pPcieConfig->PortConfiguration[PortId].PortLinkMode == PcieLinkModeGen2AdvertizeOnly ||
+ pPcieConfig->ExtPortConfiguration[PortId].PortDeemphasis == PcieTxDeemphasis3p5dB) {
+ //Degrade link speed to Gen1
+ pPcieConfig->ExtPortConfiguration[PortId].PortDeemphasis = PcieTxDeemphasis6dB;
+ PcieLibSetLinkMode (PortId, PcieLinkModeGen1, pConfig);
+ PcieLibSetGen2Disabled (PortId, pConfig);
+ if (PcieLibResetSlot (PortId, pConfig) != AGESA_SUCCESS) {
+ //Slot reset logic not supported request PCI reset.
+ RequestPciReset = TRUE;
+ }
+ //Report back to caller that potential downgrade case is detected.
+ Status = AGESA_SUCCESS;
+ }
+ }
+ if (RequestPciReset) {
+ PcieLibRequestPciReset (pConfig);
+ }
+ }
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieGen2Workaround Enter\n"));
+ return Status;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Try to recover system by issuing system wide PCI reset.
+ *
+ *
+ *
+ * @param[in] PortsLinkStatus Array of link status for every Port
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieMiscWorkaround (
+ IN PCIE_LINK_STATUS *PortsLinkStatus,
+ IN AMD_NB_CONFIG *pConfig
+ )
+{
+ AGESA_STATUS Status;
+ PORT PortId;
+ UINT16 PortMask;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieMiscWorkaround Enter\n"));
+ Status = AGESA_UNSUPPORTED;
+ PortMask = PcieFindPortsWithLinkStatus (PortsLinkStatus, PcieLinkStatusTrainingInProgress);
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ if ((PortMask & (1 << PortId)) != 0) {
+ if (PcieLibRequestPciReset (pConfig)!= AGESA_SUCCESS) {
+ break;
+ }
+ PortMask = PcieFindPortsWithLinkStatus (PortsLinkStatus, PcieLinkStatusTrainingInProgress);
+ if (PortMask == 0) {
+ break;
+ }
+ }
+ }
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieMiscWorkaround Exit\n"));
+ return Status;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Check VCO negotiation complete.
+ * Routine will retry retrain device infinitely if VCO negotiation is failing.
+ *
+ *
+ * @param[in] SelectedPortMask Bitmap of port ID selected for training.
+ * @param[in] PortsLinkStatus Array of link status for every Port
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+AGESA_STATUS
+PcieCheckVco (
+ IN UINT16 SelectedPortMask,
+ IN PCIE_LINK_STATUS *PortsLinkStatus,
+ IN AMD_NB_CONFIG *pConfig
+ )
+{
+ AGESA_STATUS Status;
+ UINT16 VcoNegotiationInProgressPortMask;
+ PORT PortId;
+ UINT16 VcoStatus;
+ UINT32 LinkRetrainCount;
+ UINT32 VcoPoll;
+ UINT32 Value;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]VcoNegotiationInProgress Enter\n"));
+ Status = AGESA_SUCCESS;
+ VcoNegotiationInProgressPortMask = SelectedPortMask;
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ if (VcoNegotiationInProgressPortMask & (1 << PortId)) {
+ // For each port where VCO needs to be checked
+ PCI_ADDR Port;
+ Port = PcieLibGetPortPciAddress (PortId, pConfig);
+ PortsLinkStatus[PortId] = PcieLinkStatusVcoNegotiationInProgress;
+ for (LinkRetrainCount = 0; LinkRetrainCount < 10; LinkRetrainCount++) {
+ // Poll for 200 ms for VC0 negotioation completion
+ for (VcoPoll = 0; VcoPoll < 200; VcoPoll++) {
+ LibNbPciRead (Port.AddressValue | NB_PCIP_REG12A, AccessWidth16, &VcoStatus, pConfig);
+ if ((VcoStatus & BIT1) != 0) {
+ STALL (GET_BLOCK_CONFIG_PTR (pConfig), 1000, 0);
+ } else {
+ PortsLinkStatus[PortId] = PcieLinkStatusConnected;
+ break;
+ }
+ } //For each VcoPoll
+ if (PortsLinkStatus[PortId] == PcieLinkStatusVcoNegotiationInProgress) {
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_MISC), " Vco Not Completed. Retrain link on PortId %d\n", PortId));
+ LibNbPciIndexRead (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REGA2, AccessWidth32, &Value, pConfig);
+ Value = (Value & 0xfffffe80) | ((Value & 0x70) >> 4) | BIT8;
+ LibNbPciIndexWrite (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REGA2, AccessWidth32, &Value, pConfig);
+ } else {
+ break; //Vco negotiations complete
+ }
+ } //For each LinkRetrainCount
+ if (PortsLinkStatus[PortId] == PcieLinkStatusVcoNegotiationInProgress) {
+ PortsLinkStatus[PortId] = PcieLinkStatusNotConnected;
+ }
+ } // Vco negotiations required
+ } //For each port
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]VcoNegotiationInProgress Exit\n"));
+ return Status;
+}
+
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Get bit map of ports with particular link status
+ *
+ *
+ *
+ * @param[in] PortLinkStatus Pointer to array of link status for every Port
+ * @param[in] LinkStatus LinkStatus to search for.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+UINT16
+PcieFindPortsWithLinkStatus (
+ IN PCIE_LINK_STATUS *PortLinkStatus,
+ IN PCIE_LINK_STATUS LinkStatus
+ )
+{
+ UINT16 PortMask;
+ PORT PortId;
+
+ PortMask = 0;
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ if (PortLinkStatus[PortId] == LinkStatus) PortMask |= (1 << PortId);
+ }
+ return PortMask;
+}
+/*----------------------------------------------------------------------------------------*/
+/**
+ * Gather link state for selected ports.
+ *
+ *
+ * @param[in] SelectedPortMask Bitmap of port ID selected for training.
+ * @param[in] PortLinkStatus Pointer to array of link status for every Port
+ * @param[in] Pooling Time in MS to pool for link status change.
+ * @param[in] pConfig Northbridge configuration structure pointer.
+ *
+ */
+/*----------------------------------------------------------------------------------------*/
+PCIE_LINK_STATUS
+PcieGetPortsLinkStatus (
+ IN UINT16 SelectedPortMask,
+ IN OUT PCIE_LINK_STATUS *PortLinkStatus,
+ IN UINT32 Pooling,
+ IN AMD_NB_CONFIG *pConfig
+ )
+{
+ PCIE_LINK_STATUS Status;
+ PORT PortId;
+
+ CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_TRACE), "[NBPCIE]PcieGetPortsLinkStatus Enter\n"));
+ Status = PcieLinkStatusNotConnected;
+ Pooling *= 10;
+ while (Pooling-- != 0 && Status != PcieLinkStatusConnected) {
+ Status = PcieLinkStatusConnected; //Set up initial overall state as connected
+ for (PortId = MIN_PORT_ID; PortId <= MAX_PORT_ID; PortId++) {
+ //Work only on selected ports
+ if ((SelectedPortMask & (1 << PortId)) != 0) {
+ PCI_ADDR Port;
+ UINT32 LinkState;
+ Port = PcieLibGetPortPciAddress (PortId, pConfig); //Get PCI address of this port
+ //Get link state
+ LibNbPciIndexRead (Port.AddressValue | NB_BIF_INDEX, NB_BIFNBP_REGA5, AccessWidth32, &LinkState, pConfig);
+ LinkState &= 0x3F;
+ //CIMX_TRACE ((TRACE_DATA (GET_BLOCK_CONFIG_PTR (pConfig), CIMX_NBPCIE_MISC), " PortId %d LinkState = 0x%x \n", PortId, LinkState));
+ printk(BIOS_INFO, "[NBPCIE] PortId %02d LinkState = 0x%x \n", PortId, LinkState);
+ //Check if link in L0 state
+
+ if (LinkState == 0x10) {
+ PortLinkStatus[PortId] = PcieLinkStatusConnected;
+ } else {
+ Status = PcieLinkStatusNotConnected;
+ //Check if link in compliance mode
+ if (LinkState == 0x7) {
+ PortLinkStatus[PortId] = PcieLinkStatusInCompliance;
+ } else {
+ //Check if we passed receiver detection. It will indicate that device present.
+ if (LinkState > 0x4) {
+ PortLinkStatus[PortId] = PcieLinkStatusTrainingInProgress;
+ }
+ }
+ }
+ }
+ }
+ STALL (GET_BLOCK_CONFIG_PTR (pConfig), 100, 0);
+ }
+ return Status;
+}