/* $NoKeywords:$ */ /** * @file * * NB services * * * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: GNB * @e \$Revision: 64352 $ @e \$Date: 2012-01-19 03:54:04 -0600 (Thu, 19 Jan 2012) $ * */ /* ***************************************************************************** * * Copyright (c) 2008 - 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 "AGESA.h" #include "Ids.h" #include "amdlib.h" #include "S3SaveState.h" #include "Gnb.h" #include "GnbPcieConfig.h" #include "GnbCommonLib.h" #include "GnbPcieInitLibV1.h" #include "GnbNbInitLibV4.h" #include "GnbRegistersTN.h" #include "heapManager.h" #include "GnbFamServices.h" #include "Filecode.h" #define FILECODE PROC_GNB_MODULES_GNBNBINITLIBV4_GNBNBINITLIBV4_FILECODE /*---------------------------------------------------------------------------------------- * D E F I N I T I O N S A N D M A C R O S *---------------------------------------------------------------------------------------- */ #define SMC_RAM_START_ADDR 0x10000ul /*---------------------------------------------------------------------------------------- * T Y P E D E F S A N D S T R U C T U R E S *---------------------------------------------------------------------------------------- */ typedef struct { GNB_PCI_SCAN_DATA ScanData; GNB_TOPOLOGY_INFO *TopologyInfo; } GNB_TOPOLOGY_INFO_DATA; /*---------------------------------------------------------------------------------------- * 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 *---------------------------------------------------------------------------------------- */ VOID GnbSmuServiceRequestV4S3Script ( IN AMD_CONFIG_PARAMS *StdHeader, IN UINT16 ContextLength, IN VOID *Context ); /*----------------------------------------------------------------------------------------*/ /** * Check a PCIE device to see if it supports phantom functions * * @param[in] Device Device pci address * @param[in] StdHeader Standard configuration header * @return TRUE Current device supports phantom functions */ STATIC BOOLEAN GnbCheckPhantomFuncSupport ( IN PCI_ADDR Device, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT8 PcieCapPtr; UINT32 Value; Value = 0; PcieCapPtr = GnbLibFindPciCapability (Device.AddressValue, PCIE_CAP_ID, StdHeader); if (PcieCapPtr != 0) { GnbLibPciRead (Device.AddressValue | (PcieCapPtr + 4), AccessWidth32, &Value, StdHeader); } return ((Value & (BIT3 | BIT4)) != 0) ? TRUE : FALSE; } /*----------------------------------------------------------------------------------------*/ /** * Evaluate device * * * * @param[in] Device PCI Address * @param[in,out] ScanData Scan configuration data * @retval Scan Status */ SCAN_STATUS STATIC GnbTopologyInfoScanCallback ( IN PCI_ADDR Device, IN OUT GNB_PCI_SCAN_DATA *ScanData ) { SCAN_STATUS ScanStatus; GNB_TOPOLOGY_INFO_DATA *GnbTopologyInfo; PCIE_DEVICE_TYPE DeviceType; ScanStatus = SCAN_SUCCESS; IDS_HDT_CONSOLE (GNB_TRACE, " GnbIommuInfoScanCallback for Device = %d:%d:%d\n", Device.Address.Bus, Device.Address.Device, Device.Address.Function ); GnbTopologyInfo = (GNB_TOPOLOGY_INFO_DATA *)ScanData; ScanStatus = SCAN_SUCCESS; DeviceType = GnbLibGetPcieDeviceType (Device, ScanData->StdHeader); switch (DeviceType) { case PcieDeviceRootComplex: case PcieDeviceDownstreamPort: GnbLibPciScanSecondaryBus (Device, &GnbTopologyInfo->ScanData); break; case PcieDeviceUpstreamPort: GnbLibPciScanSecondaryBus (Device, &GnbTopologyInfo->ScanData); ScanStatus = SCAN_SKIP_FUNCTIONS | SCAN_SKIP_DEVICES | SCAN_SKIP_BUSES; break; case PcieDevicePcieToPcix: GnbTopologyInfo->TopologyInfo->PcieToPciexBridge = TRUE; ScanStatus = SCAN_SKIP_FUNCTIONS | SCAN_SKIP_DEVICES | SCAN_SKIP_BUSES; break; case PcieDeviceEndPoint: case PcieDeviceLegacyEndPoint: if (GnbCheckPhantomFuncSupport (Device, ScanData->StdHeader)) { GnbTopologyInfo->TopologyInfo->PhantomFunction = TRUE; } ScanStatus = SCAN_SKIP_DEVICES | SCAN_SKIP_BUSES; break; default: break; } return ScanStatus; } /*----------------------------------------------------------------------------------------*/ /** * Get IOMMU topology info * * * * @param[in] StartPciAddress Start PCI address * @param[in] EndPciAddress End PCI address * @param[in] TopologyInfo Topology info structure * @param[in] StdHeader Standard Configuration Header */ AGESA_STATUS GnbGetTopologyInfoV4 ( IN PCI_ADDR StartPciAddress, IN PCI_ADDR EndPciAddress, OUT GNB_TOPOLOGY_INFO *TopologyInfo, IN AMD_CONFIG_PARAMS *StdHeader ) { GNB_TOPOLOGY_INFO_DATA GnbTopologyInfo; IDS_HDT_CONSOLE (GNB_TRACE, "GnbGetTopologyInfoV4 Enter\n"); GnbTopologyInfo.ScanData.GnbScanCallback = GnbTopologyInfoScanCallback; GnbTopologyInfo.ScanData.StdHeader = StdHeader; GnbTopologyInfo.TopologyInfo = TopologyInfo; GnbLibPciScan (StartPciAddress, EndPciAddress, &GnbTopologyInfo.ScanData); IDS_HDT_CONSOLE (GNB_TRACE, "GnbGetTopologyInfoV4 Exit\n"); return AGESA_SUCCESS; } /*----------------------------------------------------------------------------------------*/ /** * SMU service request * * * @param[in] GnbPciAddress GNB PCI address * @param[in] RequestId Request ID * @param[in] AccessFlags See GNB_ACCESS_FLAGS_* definitions * @param[in] StdHeader Standard configuration header */ VOID GnbSmuServiceRequestV4 ( IN PCI_ADDR GnbPciAddress, IN UINT8 RequestId, IN UINT32 AccessFlags, IN AMD_CONFIG_PARAMS *StdHeader ) { D0F0xBC_xE0003004_STRUCT D0F0xBC_xE0003004; D0F0xBC_xE0003000_STRUCT D0F0xBC_xE0003000; IDS_HDT_CONSOLE (GNB_TRACE, "GnbSmuServiceRequestV4 Enter\n"); IDS_HDT_CONSOLE (NB_MISC, " Service Request %d\n", RequestId); if ((AccessFlags & GNB_REG_ACC_FLAG_S3SAVE) != 0) { SMU_MSG_CONTEXT SmuMsgContext; SmuMsgContext.GnbPciAddress.AddressValue = GnbPciAddress.AddressValue; SmuMsgContext.RequestId = RequestId; S3_SAVE_DISPATCH (StdHeader, GnbSmuServiceRequestV4S3Script_ID, sizeof (SmuMsgContext), &SmuMsgContext); } do { GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0003004_ADDRESS, AccessWidth32, &D0F0xBC_xE0003004.Value, StdHeader); } while (D0F0xBC_xE0003004.Field.IntDone == 0x0); GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0003000_ADDRESS, AccessWidth32, &D0F0xBC_xE0003000.Value, StdHeader); D0F0xBC_xE0003000.Field.IntToggle = ~D0F0xBC_xE0003000.Field.IntToggle; D0F0xBC_xE0003000.Field.ServiceIndex = RequestId; GnbLibPciIndirectWrite (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0003000_ADDRESS, AccessWidth32, &D0F0xBC_xE0003000.Value, StdHeader); do { GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0003004_ADDRESS, AccessWidth32, &D0F0xBC_xE0003004.Value, StdHeader); } while (D0F0xBC_xE0003004.Field.IntAck == 0x0); do { GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0003004_ADDRESS, AccessWidth32, &D0F0xBC_xE0003004.Value, StdHeader); } while (D0F0xBC_xE0003004.Field.IntDone == 0x0); IDS_HDT_CONSOLE (GNB_TRACE, "GnbSmuServiceRequestV4 Exit\n"); } /*----------------------------------------------------------------------------------------*/ /** * SMU service request for S3 script * * * @param[in] StdHeader Standard configuration header * @param[in] ContextLength Context length * @param[in] Context Pointer to Context */ VOID GnbSmuServiceRequestV4S3Script ( IN AMD_CONFIG_PARAMS *StdHeader, IN UINT16 ContextLength, IN VOID *Context ) { SMU_MSG_CONTEXT *SmuMsgContext; SmuMsgContext = (SMU_MSG_CONTEXT *) Context; GnbSmuServiceRequestV4 (SmuMsgContext->GnbPciAddress, SmuMsgContext->RequestId, 0, StdHeader); } /*----------------------------------------------------------------------------------------*/ /** * SMU firmware download * * * @param[in] GnbPciAddress GNB Pci Address * @param[in] Firmware Pointer tp firmware * @param[in] StdHeader Standard configuration header */ AGESA_STATUS GnbSmuFirmwareLoadV4 ( IN PCI_ADDR GnbPciAddress, IN FIRMWARE_HEADER_V4 *Firmware, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 Index; D0F0xBC_xE00030A4_STRUCT D0F0xBC_xE00030A4; D0F0xBC_xE0000004_STRUCT D0F0xBC_xE0000004; D0F0xBC_xE0003088_STRUCT D0F0xBC_xE0003088; ex1005_STRUCT ex1005 ; D0F0xBC_x1F380_STRUCT D0F0xBC_x1F380; IDS_HDT_CONSOLE (GNB_TRACE, "GnbSmuFirmwareLoadV4 Enter\n"); IDS_HDT_CONSOLE (NB_MISC, " Firmware version 0x%x\n", Firmware->Version); // Step 2, 10, make sure Rom firmware sequance is done do { GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0000004_ADDRESS, AccessWidth32, &D0F0xBC_xE0000004.Value, StdHeader); } while (D0F0xBC_xE0000004.Field.boot_seq_done == 0); // Step 1, check if firmware running in protected mode GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE00030A4_ADDRESS, AccessWidth32, &D0F0xBC_xE00030A4.Value, StdHeader); if (D0F0xBC_xE00030A4.Field.SmuProtectedMode == 0) { // Step3, Clear firmware interrupt flags GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_x1F380_ADDRESS, AccessWidth32, 0x0, 0x0, StdHeader ); } //Step 4, 11, Assert LM32 reset GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, 0x80000000 , AccessWidth32, (UINT32) ~(0x1 ), 1 << 0 , StdHeader ); // Step5, 12, Load firmware for (Index = 0; Index < (Firmware->FirmwareLength + Firmware->HeaderLength); Index++) { GnbLibPciIndirectWrite (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, SMC_RAM_START_ADDR + (Index * 4), AccessWidth32, &((UINT32 *) Firmware)[Index], StdHeader); } if (D0F0xBC_xE00030A4.Field.SmuProtectedMode == 0) { //Step 6, Write jmp to RAM firmware GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, 0x0, AccessWidth32, 0x0, 0xE0000000 + ((SMC_RAM_START_ADDR + Firmware->HeaderLength * 4) >> 2), StdHeader ); } else { //Step 13, Clear autentification done GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0003088_ADDRESS, AccessWidth32, 0x0, 0x0, StdHeader ); } // Step 7, 14 Enable LM32 clock GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, 0x80000004 , AccessWidth32, (UINT32) ~(0x1 ), 0 << 0 , StdHeader ); //Step 8, 15, Deassert LM32 reset GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, 0x80000000 , AccessWidth32, (UINT32) ~(0x1 ), 0 << 0 , StdHeader ); if (D0F0xBC_xE00030A4.Field.SmuProtectedMode == 1) { IDS_HDT_CONSOLE (NB_MISC, " Protected mode: poll init autehtication vector\n"); // Step 16, Wait for rom firmware init autehtication vector do { GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, 0x80010000 , AccessWidth32, &ex1005.Value, StdHeader); } while (ex1005.Value != 0x400); // Call Authentication service GnbSmuServiceRequestV4 (GnbPciAddress, SMC_MSG_FIRMWARE_AUTH, 0, StdHeader); IDS_HDT_CONSOLE (NB_MISC, " Protected mode: poll init autehtication done\n"); // Wait for autehtication done do { GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_xE0003088_ADDRESS, AccessWidth32, &D0F0xBC_xE0003088.Value, StdHeader); } while (D0F0xBC_xE0003088.Field.SmuAuthDone == 0x0); //Step 17, Check Authentication results if (D0F0xBC_xE0003088.Field.SmuAuthPass == 0) { IDS_HDT_CONSOLE (NB_MISC, " ERROR!!!Autehtication fail!!!\n"); ASSERT (FALSE); return AGESA_FATAL; } // Step 18, Clear firmware interrupt enable flag GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_x1F380_ADDRESS, AccessWidth32, 0x0, 0x0, StdHeader ); //Step 19, Assert LM32 reset GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, 0x80000000 , AccessWidth32, (UINT32) ~(0x1 ), 1 << 0 , StdHeader ); //Step 20, Deassert LM32 reset GnbLibPciIndirectRMW ( GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, 0x80000000 , AccessWidth32, (UINT32) ~(0x1 ), 0 << 0 , StdHeader ); } //Step 9, 21 Wait firmware to initialize do { GnbLibPciIndirectRead (GnbPciAddress.AddressValue | D0F0xB8_ADDRESS, D0F0xBC_x1F380_ADDRESS, AccessWidth32, &D0F0xBC_x1F380.Value, StdHeader); } while (D0F0xBC_x1F380.Field.InterruptsEnabled == 0); IDS_HDT_CONSOLE (GNB_TRACE, "GnbSmuFirmwareLoadV4 Exit\n"); return AGESA_SUCCESS; } /*----------------------------------------------------------------------------------------*/ /** * Get IOMMU PCI address * * * @param[in] GnbHandle GNB handle * @param[in] StdHeader Standard configuration header */ PCI_ADDR GnbGetIommuPciAddressV4 ( IN GNB_HANDLE *GnbHandle, IN AMD_CONFIG_PARAMS *StdHeader ) { PCI_ADDR GnbIommuPciAddress; GnbIommuPciAddress = GnbGetHostPciAddress (GnbHandle); GnbIommuPciAddress.Address.Function = 0x2; return GnbIommuPciAddress; } /*----------------------------------------------------------------------------------------*/ /** * UnitID Clumping * * * @param[in] GnbHandle GNB handle * @param[in] StdHeader Standard configuration header */ VOID GnbClumpUnitIdV4 ( IN GNB_HANDLE *GnbHandle, IN AMD_CONFIG_PARAMS *StdHeader ) { PCIe_ENGINE_CONFIG *EngineList; UINT32 Value; Value = 0; EngineList = (PCIe_ENGINE_CONFIG *) PcieConfigGetChild (DESCRIPTOR_PCIE_ENGINE, &GnbHandle->Header); while (EngineList != NULL) { if (EngineList->Type.Port.NumberOfUnitId != 0) { if (!PcieConfigIsActivePcieEngine (EngineList)) { Value |= (((1 << EngineList->Type.Port.NumberOfUnitId) - 1) << EngineList->Type.Port.UnitId); } else { if (EngineList->Type.Port.NumberOfUnitId > 1) { Value |= (((1 << (EngineList->Type.Port.NumberOfUnitId - 1)) - 1) << (EngineList->Type.Port.UnitId + 1)); } } } EngineList = (PCIe_ENGINE_CONFIG *) PcieConfigGetNextTopologyDescriptor (EngineList, DESCRIPTOR_TERMINATE_GNB); } // Set GNB GnbLibPciIndirectRMW ( GnbHandle->Address.AddressValue | D0F0x94_ADDRESS, D0F0x98_x3A_ADDRESS | (1 << D0F0x94_OrbIndWrEn_OFFSET), AccessS3SaveWidth32, (UINT32) ~Value, Value, StdHeader ); //Set UNB GnbLibPciRMW ( MAKE_SBDFO (0, 0, GnbHandle->NodeId + 0x18, 0, D18F0x110_ADDRESS + GnbHandle->LinkId * 4), AccessS3SaveWidth32, (UINT32) ~Value, Value, StdHeader ); } /*----------------------------------------------------------------------------------------*/ /** * Config GNB to prevent LPC deadlock scenario * * * @param[in] GnbHandle GNB handle * @param[in] StdHeader Standard configuration header */ VOID GnbLpcDmaDeadlockPreventionV4 ( IN GNB_HANDLE *GnbHandle, IN AMD_CONFIG_PARAMS *StdHeader ) { PCIe_PLATFORM_CONFIG *Pcie; PCIe_ENGINE_CONFIG *EngineList; Pcie = (PCIe_PLATFORM_CONFIG *) PcieConfigGetParent (DESCRIPTOR_PLATFORM, &GnbHandle->Header); EngineList = (PCIe_ENGINE_CONFIG *) PcieConfigGetChild (DESCRIPTOR_ALL_ENGINES, &GnbHandle->Header); while (EngineList != NULL) { if (PcieConfigIsPcieEngine (EngineList) && PcieConfigIsSbPcieEngine (EngineList)) { PcieRegisterRMW ( PcieConfigGetParentWrapper (EngineList), CORE_SPACE (EngineList->Type.Port.CoreId, D0F0xE4_CORE_0010_ADDRESS), D0F0xE4_CORE_0010_UmiNpMemWrite_MASK, 1 << D0F0xE4_CORE_0010_UmiNpMemWrite_OFFSET, TRUE, Pcie ); //Enable special NP memory write protocol in ORB GnbLibPciIndirectRMW ( GnbHandle->Address.AddressValue | D0F0x94_ADDRESS, D0F0x98_x06_ADDRESS | (1 << D0F0x94_OrbIndWrEn_OFFSET), AccessS3SaveWidth32, 0xFFFFFFFF, 1 << D0F0x98_x06_UmiNpMemWrEn_OFFSET, StdHeader ); break; } EngineList = (PCIe_ENGINE_CONFIG *) PcieConfigGetNextTopologyDescriptor (EngineList, DESCRIPTOR_TERMINATE_GNB); } } /*----------------------------------------------------------------------------------------*/ /** * Enable IOMMU base address. (MMIO space ) * * * * @param[in] StdHeader Standard Configuration Header * @retval AGESA_SUCCESS * @retval AGESA_ERROR */ AGESA_STATUS GnbEnableIommuMmioV4 ( IN GNB_HANDLE *GnbHandle, IN AMD_CONFIG_PARAMS *StdHeader ) { AGESA_STATUS Status; UINT16 CapabilityOffset; UINT64 BaseAddress; UINT32 Value; PCI_ADDR GnbIommuPciAddress; Status = AGESA_SUCCESS; IDS_HDT_CONSOLE (GNB_TRACE, "GnbEnableIommuMmio Enter\n"); if (GnbFmCheckIommuPresent (GnbHandle, StdHeader)) { GnbIommuPciAddress = GnbGetIommuPciAddressV4 (GnbHandle, StdHeader); CapabilityOffset = GnbLibFindPciCapability (GnbIommuPciAddress.AddressValue, IOMMU_CAP_ID, StdHeader); GnbLibPciRead (GnbIommuPciAddress.AddressValue | (CapabilityOffset + 0x4), AccessWidth32, &Value, StdHeader); BaseAddress = (UINT64) Value << 32; GnbLibPciRead (GnbIommuPciAddress.AddressValue | (CapabilityOffset + 0x8), AccessWidth32, &Value, StdHeader); BaseAddress |= Value; if ((BaseAddress & 0xfffffffffffffffe) != 0x0) { IDS_HDT_CONSOLE (GNB_TRACE, " Enable IOMMU MMIO at address %x for Socket %d Silicon %d\n", BaseAddress, GnbGetSocketId (GnbHandle) , GnbGetSiliconId (GnbHandle)); GnbLibPciRMW (GnbIommuPciAddress.AddressValue | (CapabilityOffset + 0x8), AccessS3SaveWidth32, 0xFFFFFFFF, 0x0, StdHeader); GnbLibPciRMW (GnbIommuPciAddress.AddressValue | (CapabilityOffset + 0x4), AccessS3SaveWidth32, 0xFFFFFFFE, 0x1, StdHeader); } else { ASSERT (FALSE); Status = AGESA_ERROR; } } IDS_HDT_CONSOLE (GNB_TRACE, "GnbEnableIommuMmio Exit\n"); return Status; }