/* $NoKeywords:$ */ /** * @file * * Various PCI service routines. * * * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: GNB * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $ * */ /* ***************************************************************************** * * Copyright 2008 - 2012 ADVANCED MICRO DEVICES, INC. All Rights Reserved. * * AMD is granting you permission to use this software (the Materials) * pursuant to the terms and conditions of your Software License Agreement * with AMD. This header does *NOT* give you permission to use the Materials * or any rights under AMD's intellectual property. Your use of any portion * of these Materials shall constitute your acceptance of those terms and * conditions. If you do not agree to the terms and conditions of the Software * License Agreement, please do not use any portion of these Materials. * * CONFIDENTIALITY: The Materials and all other information, identified as * confidential and provided to you by AMD shall be kept confidential in * accordance with the terms and conditions of the Software License Agreement. * * LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION * PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE, * OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE. * IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS * INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE, * GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER * RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE * EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, * THE ABOVE LIMITATION MAY NOT APPLY TO YOU. * * AMD does not assume any responsibility for any errors which may appear in * the Materials or any other related information provided to you by AMD, or * result from use of the Materials or any related information. * * You agree that you will not reverse engineer or decompile the Materials. * * NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any * further information, software, technical information, know-how, or show-how * available to you. Additionally, AMD retains the right to modify the * Materials at any time, without notice, and is not obligated to provide such * modified Materials to you. * * U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with * "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is * subject to the restrictions as set forth in FAR 52.227-14 and * DFAR252.227-7013, et seq., or its successor. Use of the Materials by the * Government constitutes acknowledgement of AMD's proprietary rights in them. * * EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any * direct product thereof will be exported directly or indirectly, into any * country prohibited by the United States Export Administration Act and the * regulations thereunder, without the required authorization from the U.S. * government nor will be used for any purpose prohibited by the same. * *************************************************************************** * */ #include "AGESA.h" #include "amdlib.h" #include "Gnb.h" #include "GnbLibPciAcc.h" #include "GnbLibPci.h" #include "GnbLib.h" #include "Filecode.h" #define FILECODE PROC_GNB_MODULES_GNBCOMMONLIB_GNBLIBPCI_FILECODE /*----------------------------------------------------------------------------------------*/ /* * Check if device present * * * * @param[in] Address PCI address (as described in PCI_ADDR) * @param[in] StdHeader Standard configuration header * @retval TRUE Device is present * @retval FALSE Device is not present */ BOOLEAN GnbLibPciIsDevicePresent ( IN UINT32 Address, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 DeviceId; GnbLibPciRead (Address, AccessWidth32, &DeviceId, StdHeader); if (DeviceId == 0xffffffff) { return FALSE; } else { return TRUE; } } /*----------------------------------------------------------------------------------------*/ /* * Check if device is bridge * * * * @param[in] Address PCI address (as described in PCI_ADDR) * @param[in] StdHeader Standard configuration header * @retval TRUE Device is a bridge * @retval FALSE Device is not a bridge */ BOOLEAN GnbLibPciIsBridgeDevice ( IN UINT32 Address, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT8 Header; GnbLibPciRead (Address | 0xe, AccessWidth8, &Header, StdHeader); if ((Header & 0x7f) == 1) { return TRUE; } else { return FALSE; } } /*----------------------------------------------------------------------------------------*/ /* * Check if device is multifunction * * * * @param[in] Address PCI address (as described in PCI_ADDR) * @param[in] StdHeader Standard configuration header * @retval TRUE Device is a multifunction device. * @retval FALSE Device is a single function device. * */ BOOLEAN GnbLibPciIsMultiFunctionDevice ( IN UINT32 Address, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT8 Header; GnbLibPciRead (Address | 0xe, AccessWidth8, &Header, StdHeader); if ((Header & 0x80) != 0) { return TRUE; } else { return FALSE; } } /*----------------------------------------------------------------------------------------*/ /* * Check if device is PCIe device * * * * @param[in] Address PCI address (as described in PCI_ADDR) * @param[in] StdHeader Standard configuration header * @retval TRUE Device is a PCIe device * @retval FALSE Device is not a PCIe device * */ BOOLEAN GnbLibPciIsPcieDevice ( IN UINT32 Address, IN AMD_CONFIG_PARAMS *StdHeader ) { if (GnbLibFindPciCapability (Address, PCIE_CAP_ID, StdHeader) != 0 ) { return TRUE; } else { return FALSE; } } /*----------------------------------------------------------------------------------------*/ /* * Find PCI capability pointer * * * * @param[in] Address PCI address (as described in PCI_ADDR) * @param[in] CapabilityId PCI capability ID * @param[in] StdHeader Standard configuration header * @retval Register address of capability pointer * */ UINT8 GnbLibFindPciCapability ( IN UINT32 Address, IN UINT8 CapabilityId, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT8 CapabilityPtr; UINT8 CurrentCapabilityId; CapabilityPtr = 0x34; if (!GnbLibPciIsDevicePresent (Address, StdHeader)) { return 0; } while (CapabilityPtr != 0) { GnbLibPciRead (Address | CapabilityPtr, AccessWidth8 , &CapabilityPtr, StdHeader); if (CapabilityPtr != 0) { GnbLibPciRead (Address | CapabilityPtr , AccessWidth8 , &CurrentCapabilityId, StdHeader); if (CurrentCapabilityId == CapabilityId) { break; } CapabilityPtr++; } } return CapabilityPtr; } /*----------------------------------------------------------------------------------------*/ /* * Find PCIe extended capability pointer * * * * @param[in] Address PCI address (as described in PCI_ADDR) * @param[in] ExtendedCapabilityId Extended PCIe capability ID * @param[in] StdHeader Standard configuration header * @retval Register address of extended capability pointer * */ #if 0 /* Not used */ UINT16 GnbLibFindPcieExtendedCapability ( IN UINT32 Address, IN UINT16 ExtendedCapabilityId, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT16 CapabilityPtr; UINT32 ExtendedCapabilityIdBlock; if (GnbLibPciIsPcieDevice (Address, StdHeader)) { GnbLibPciRead (Address | 0x100 , AccessWidth32 , &ExtendedCapabilityIdBlock, StdHeader); if ((ExtendedCapabilityIdBlock != 0) && ((UINT16)ExtendedCapabilityIdBlock != 0xffff)) { do { CapabilityPtr = (UINT16) ((ExtendedCapabilityIdBlock >> 20) & 0xfff); if ((UINT16)ExtendedCapabilityIdBlock == ExtendedCapabilityId) { return CapabilityPtr; } GnbLibPciRead (Address | CapabilityPtr , AccessWidth32 , &ExtendedCapabilityIdBlock, StdHeader); } while (((ExtendedCapabilityIdBlock >> 20) & 0xfff) != 0); } } return 0; } #endif /*----------------------------------------------------------------------------------------*/ /* * Scan range of device on PCI bus. * * * * @param[in] Start Start address to start scan from * @param[in] End End address of scan * @param[in] ScanData Supporting data * */ /*----------------------------------------------------------------------------------------*/ VOID GnbLibPciScan ( IN PCI_ADDR Start, IN PCI_ADDR End, IN GNB_PCI_SCAN_DATA *ScanData ) { UINTN Bus; UINTN Device; UINTN LastDevice; UINTN Function; UINTN LastFunction; PCI_ADDR PciDevice; SCAN_STATUS Status; for (Bus = Start.Address.Bus; Bus <= End.Address.Bus; Bus++) { Device = (Bus == Start.Address.Bus) ? Start.Address.Device : 0x00; LastDevice = (Bus == End.Address.Bus) ? End.Address.Device : 0x1F; for ( ; Device <= LastDevice; Device++) { if ((Bus == Start.Address.Bus) && (Device == Start.Address.Device)) { Function = Start.Address.Function; } else { Function = 0x0; } PciDevice.AddressValue = MAKE_SBDFO (0, Bus, Device, Function, 0); if (!GnbLibPciIsDevicePresent (PciDevice.AddressValue, ScanData->StdHeader)) { continue; } if (GnbLibPciIsMultiFunctionDevice (PciDevice.AddressValue, ScanData->StdHeader)) { if ((Bus == End.Address.Bus) && (Device == End.Address.Device)) { LastFunction = Start.Address.Function; } else { LastFunction = 0x7; } } else { LastFunction = 0x0; } for ( ; Function <= LastFunction; Function++) { PciDevice.AddressValue = MAKE_SBDFO (0, Bus, Device, Function, 0); if (GnbLibPciIsDevicePresent (PciDevice.AddressValue, ScanData->StdHeader)) { Status = ScanData->GnbScanCallback (PciDevice, ScanData); if ((Status & SCAN_SKIP_FUNCTIONS) != 0) { Function = LastFunction + 1; } if ((Status & SCAN_SKIP_DEVICES) != 0) { Device = LastDevice + 1; } if ((Status & SCAN_SKIP_BUSES) != 0) { Bus = End.Address.Bus + 1; } } } } } } /*----------------------------------------------------------------------------------------*/ /** * Scan all subordinate buses * * * @param[in] Bridge PCI bridge address * @param[in,out] ScanData Scan configuration data * */ VOID GnbLibPciScanSecondaryBus ( IN PCI_ADDR Bridge, IN OUT GNB_PCI_SCAN_DATA *ScanData ) { PCI_ADDR StartRange; PCI_ADDR EndRange; UINT8 SecondaryBus; GnbLibPciRead (Bridge.AddressValue | 0x19, AccessWidth8, &SecondaryBus, ScanData->StdHeader); if (SecondaryBus != 0) { StartRange.AddressValue = MAKE_SBDFO (0, SecondaryBus, 0, 0, 0); EndRange.AddressValue = MAKE_SBDFO (0, SecondaryBus, 0x1f, 0x7, 0); GnbLibPciScan (StartRange, EndRange, ScanData); } } /*----------------------------------------------------------------------------------------*/ /** * Get PCIe device type * * * * @param[in] Device PCI address of device. * @param[in] StdHeader Northbridge configuration structure pointer. * * @retval PCIE_DEVICE_TYPE */ /*----------------------------------------------------------------------------------------*/ PCIE_DEVICE_TYPE GnbLibGetPcieDeviceType ( IN PCI_ADDR Device, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT8 PcieCapPtr; UINT8 Value; PcieCapPtr = GnbLibFindPciCapability (Device.AddressValue, PCIE_CAP_ID, StdHeader); if (PcieCapPtr != 0) { GnbLibPciRead (Device.AddressValue | (PcieCapPtr + 0x2) , AccessWidth8, &Value, StdHeader); return Value >> 4; } return PcieNotPcieDevice; } /*----------------------------------------------------------------------------------------*/ /** * Save config space area * * * * @param[in] Address PCI address of device. * @param[in] StartRegisterAddress Start register address. * @param[in] EndRegisterAddress End register address. * @param[in] Width Acess width. * @param[in] StdHeader Standard header. * */ /*----------------------------------------------------------------------------------------*/ VOID GnbLibS3SaveConfigSpace ( IN UINT32 Address, IN UINT16 StartRegisterAddress, IN UINT16 EndRegisterAddress, IN ACCESS_WIDTH Width, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT16 Index; UINT16 Delta; UINT16 Length; Length = (StartRegisterAddress < EndRegisterAddress) ? (EndRegisterAddress - StartRegisterAddress) : (StartRegisterAddress - EndRegisterAddress); Delta = LibAmdAccessWidth (Width); for (Index = 0; Index <= Length; Index = Index + Delta) { GnbLibPciRMW ( Address | ((StartRegisterAddress < EndRegisterAddress) ? (StartRegisterAddress + Index) : (StartRegisterAddress - Index)), Width, 0xffffffff, 0x0, StdHeader ); } }