/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT8 u8Device = 7; UINT16 u16VendorID = 0; UINT16 u16DeviceID = 0; u16VendorID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 0)); u16DeviceID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 2)); if ( u16VendorID != 0x8086 || u16DeviceID != 0x7113) return RETURN_ABORTED; if (PciRead8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80)) & 1) { mPmba = PciRead32 (PCI_LIB_ADDRESS (0, u8Device, 0, 0x40)); ASSERT (mPmba & PCI_BAR_IO); DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); mPmba &= ~PCI_BAR_IO; DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); } else { PciAndThenOr32 (PCI_LIB_ADDRESS (0,u8Device,0,0x40), (UINT32) ~0xfc0, mPmba); PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x04), 0x01); DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba)); } // // ACPI Timer enable is in Bus 0, Device ?, Function 3 // PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80), 0x01); return RETURN_SUCCESS; }
EFI_STATUS GetAllQncPmBase ( IN EFI_SMM_SYSTEM_TABLE2 *Smst ) /*++ Routine Description: Get QNC chipset LPC Power Management I/O Base at runtime. Arguments: Smst - The standard SMM system table. Returns: EFI_SUCCESS - Successfully init the device. Other - Error occured whening calling Dxe lib functions. --*/ { mAcpiSmm.QncPmBase = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_PM1BLK)) & B_QNC_LPC_PM1BLK_MASK; mAcpiSmm.QncGpe0Base = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_GPE0BLK)) & B_QNC_LPC_GPE0BLK_MASK; // // Quark does not support Changing Primary SoC IOBARs from what was // setup in SEC/PEI UEFI stages. // ASSERT (mAcpiSmm.QncPmBase == (UINT32) PcdGet16 (PcdPm1blkIoBaseAddress)); ASSERT (mAcpiSmm.QncGpe0Base == (UINT32) PcdGet16 (PcdGpe0blkIoBaseAddress)); return EFI_SUCCESS; }
/** Reads from a given location in the PCI configuration space. @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation. @param This Pointer to local data for the interface. @param Width The width of the access. Enumerated in bytes. See EFI_PEI_PCI_CFG_PPI_WIDTH above. @param Address The physical address of the access. The format of the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS. @param Buffer A pointer to the buffer of data. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER The invalid access width. **/ EFI_STATUS EFIAPI PciCfg2Read ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_PCI_CFG2_PPI *This, IN EFI_PEI_PCI_CFG_PPI_WIDTH Width, IN UINT64 Address, IN OUT VOID *Buffer ) { UINTN PciLibAddress; PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address); if (Width == EfiPeiPciCfgWidthUint8) { *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); } else if (Width == EfiPeiPciCfgWidthUint16) { if ((PciLibAddress & 0x01) == 0) { // // Aligned Pci address access // WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1); } } else if (Width == EfiPeiPciCfgWidthUint32) { if ((PciLibAddress & 0x03) == 0) { // // Aligned Pci address access // WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress)); } else if ((PciLibAddress & 0x01) == 0) { // // Unaligned Pci address access, break up the request into word by word. // WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress)); WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // *((UINT8 *) Buffer) = PciRead8 (PciLibAddress); *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1); *((UINT8 *) Buffer + 2) = PciRead8 (PciLibAddress + 2); *((UINT8 *) Buffer + 3) = PciRead8 (PciLibAddress + 3); } } else { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; }
/** This function scan PCI bus. @param VtdIndex VTd engine index @param Bus Pci bus @retval EFI_SUCCESS scan PCI bus successfully. **/ EFI_STATUS ScanPciBus ( IN UINTN VtdIndex, IN UINT8 Bus ) { UINT8 Device; UINT8 Function; UINT8 SecondaryBusNumber; UINT8 HeaderType; UINT8 BaseClass; UINT8 SubClass; UINT32 MaxFunction; UINT16 VendorID; UINT16 DeviceID; EFI_STATUS Status; // Scan the PCI bus for devices for (Device = 0; Device < PCI_MAX_DEVICE + 1; Device++) { HeaderType = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, 0, PCI_HEADER_TYPE_OFFSET)); MaxFunction = PCI_MAX_FUNC + 1; if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) { MaxFunction = 1; } for (Function = 0; Function < MaxFunction; Function++) { VendorID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_VENDOR_ID_OFFSET)); DeviceID = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_DEVICE_ID_OFFSET)); if (VendorID == 0xFFFF && DeviceID == 0xFFFF) { continue; } Status = RegisterPciDevice (VtdIndex, Bus, Device, Function, FALSE); if (EFI_ERROR (Status)) { return Status; } BaseClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2)); if (BaseClass == PCI_CLASS_BRIDGE) { SubClass = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1)); if (SubClass == PCI_CLASS_BRIDGE_P2P) { SecondaryBusNumber = PciRead8 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); DEBUG ((EFI_D_INFO," ScanPciBus: PCI bridge B%02x D%02x F%02x (SecondBus:%02x)\n", Bus, Device, Function, SecondaryBusNumber)); if (SecondaryBusNumber != 0) { ScanPciBus (VtdIndex, SecondaryBusNumber); } } } } } return EFI_SUCCESS; }
VOID GetQncName ( VOID ) { DEBUG ((EFI_D_INFO, "QNC Name: ")); switch (PciRead16 (PCI_LIB_ADDRESS (MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET))) { case QUARK_MC_DEVICE_ID: DEBUG ((EFI_D_INFO, "Quark")); break; case QUARK2_MC_DEVICE_ID: DEBUG ((EFI_D_INFO, "Quark2")); break; default: DEBUG ((EFI_D_INFO, "Unknown")); } // // Revision // switch (PciRead8 (PCI_LIB_ADDRESS (MC_BUS, MC_DEV, MC_FUN, PCI_REVISION_ID_OFFSET))) { case QNC_MC_REV_ID_A0: DEBUG ((EFI_D_INFO, " - A0 stepping\n")); break; default: DEBUG ((EFI_D_INFO, " - xx\n")); } return; }
/** Internal function to retrieve the ACPI I/O Port Base Address. Internal function to retrieve the ACPI I/O Port Base Address. @return The 16-bit ACPI I/O Port Base Address. **/ UINT16 InternalAcpiGetAcpiTimerIoPort ( VOID ) { UINT16 Port; Port = PcdGet16 (PcdAcpiIoPortBaseAddress); // // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then // read the PCI register for the ACPI BAR value in case the BAR has been programmed to a // value other than PcdAcpiIoPortBaseAddress // if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0x0000) { Port = PciRead16 (PCI_LIB_ADDRESS ( PcdGet8 (PcdAcpiIoPciBusNumber), PcdGet8 (PcdAcpiIoPciDeviceNumber), PcdGet8 (PcdAcpiIoPciFunctionNumber), PcdGet16 (PcdAcpiIoPciBarRegisterOffset) )); } return (Port & PcdGet16 (PcdAcpiIoPortBaseAddressMask)) + PcdGet16 (PcdAcpiPm1TmrOffset); }
ACPI_STATUS AcpiOsReadPciConfiguration ( ACPI_PCI_ID *PciId, UINT32 Register, UINT64 *Value, UINT32 Width) { UINT32 devfn = ((PciId->Device & 0x1f)<<3)|(PciId->Function & 0x07); switch (Width) { case 8: *(UINT8 *)Value = PciRead8(PciId->Bus,devfn,Register); break; case 16: *(UINT16 *)Value = PciRead16(PciId->Bus,devfn,Register); break; case 32: *(UINT32 *)Value = PciRead32(PciId->Bus,devfn,Register); break; default: dbgprintf("AcpiOsReadPciConfiguration unhandled value width: %u\n", Width); return AE_ERROR; } return (AE_OK); }
VOID AcpiPmControl ( UINTN SuspendType ) { UINT16 AcpiPmBaseAddress; UINT16 HostBridgeDevId; ASSERT (SuspendType < 6); AcpiPmBaseAddress = 0; HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); switch (HostBridgeDevId) { case INTEL_82441_DEVICE_ID: AcpiPmBaseAddress = PIIX4_PMBA_VALUE; break; case INTEL_Q35_MCH_DEVICE_ID: AcpiPmBaseAddress = ICH9_PMBASE_VALUE; break; default: ASSERT (FALSE); CpuDeadLoop (); } IoBitFieldWrite16 (AcpiPmBaseAddress + 4, 10, 13, (UINT16) SuspendType); IoOr16 (AcpiPmBaseAddress + 4, BIT13); CpuDeadLoop (); }
/** Internal function to read the current tick counter of ACPI. Dynamically compute the address of the ACPI tick counter based on the properties of the underlying platform, to avoid relying on global variables. @return The tick counter read. **/ UINT32 InternalAcpiGetTimerTick ( VOID ) { UINT16 HostBridgeDevId; UINTN Pmba; // // Query Host Bridge DID to determine platform type // HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); switch (HostBridgeDevId) { case INTEL_82441_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); break; case INTEL_Q35_MCH_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); break; default: DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, HostBridgeDevId)); ASSERT (FALSE); return 0; } // // Read PMBA to read and return the current ACPI timer value. // return IoRead32 ((PciRead32 (Pmba) & ~PMBA_RTE) + ACPI_TIMER_OFFSET); }
/** Reads a 16-bit PCI configuration register and saves the value in the S3 script to be replayed on S3 resume. Reads and returns the 16-bit PCI configuration register specified by Address. This function must guarantee that all PCI read and write operations are serialized. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). @param Address Address that encodes the PCI Bus, Device, Function and Register. @return The read value from the PCI configuration register. **/ UINT16 EFIAPI S3PciRead16 ( IN UINTN Address ) { return InternalSavePciWrite16ValueToBootScript (Address, PciRead16 (Address)); }
/** Performs a bitwise OR of a 16-bit PCI configuration register with a 16-bit value. Reads the 16-bit PCI configuration register specified by Address, performs a bitwise OR between the read result and the value specified by OrData, and writes the result to the 16-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). @param Address The address that encodes the PCI Bus, Device, Function and Register. @param OrData The value to OR with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI PciOr16 ( IN UINTN Address, IN UINT16 OrData ) { return PciWrite16 (Address, (UINT16) (PciRead16 (Address) | OrData)); }
/** Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value. Reads the 16-bit PCI configuration register specified by Address, performs a bitwise AND between the read result and the value specified by AndData, and writes the result to the 16-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). @param Address The address that encodes the PCI Bus, Device, Function and Register. @param AndData The value to AND with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI PciAnd16 ( IN UINTN Address, IN UINT16 AndData ) { return PciWrite16 (Address, (UINT16) (PciRead16 (Address) & AndData)); }
/* Helpers */ uint32_t PciDeviceRead(PciDevice_t *Device, uint32_t Register, uint32_t Length) { if (Length == 1) return (uint32_t)PciRead8(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register); else if (Length == 2) return (uint32_t)PciRead16(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register); else return PciRead32(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register); }
/** Reads a 16-bit PCI configuration register. Reads and returns the 16-bit PCI configuration register specified by Address. This function must guarantee that all PCI read and write operations are serialized. If any reserved bits in Address are set, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register. @return The 16-bit PCI configuration register specified by Address. **/ UINT16 EFIAPI PciSegmentRead16 ( IN UINT64 Address ) { ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); return PciRead16 (PCI_SEGMENT_TO_PCI_ADDRESS (Address)); }
/** Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value, followed a bitwise OR with another 16-bit value. Reads the 16-bit PCI configuration register specified by Address, performs a bitwise AND between the read result and the value specified by AndData, performs a bitwise OR between the result of the AND operation and the value specified by OrData, and writes the result to the 16-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). @param Address The address that encodes the PCI Bus, Device, Function and Register. @param AndData The value to AND with the PCI configuration register. @param OrData The value to OR with the result of the AND operation. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI PciAndThenOr16 ( IN UINTN Address, IN UINT16 AndData, IN UINT16 OrData ) { return PciWrite16 (Address, (UINT16) ((PciRead16 (Address) & AndData) | OrData)); }
/** Reads a bit field of a PCI configuration register. Reads the bit field in a 16-bit PCI configuration register. The bit field is specified by the StartBit and the EndBit. The value of the bit field is returned. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). @param Address The PCI configuration register to read. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..15. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..15. @return The value of the bit field read from the PCI configuration register. **/ UINT16 EFIAPI PciBitFieldRead16 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit ) { return BitFieldRead16 (PciRead16 (Address), StartBit, EndBit); }
/* PciDeviceRead * Reads a value of the given length from the given register * and this function takes care of the rest */ uint32_t PciDeviceRead(PciDevice_t *Device, size_t Register, size_t Length) { if (Length == 1) { return (uint32_t)PciRead8(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register); } else if (Length == 2) { return (uint32_t)PciRead16(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register); } else { return PciRead32(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register); } }
/** Perform Platform PEI initialization. @param FileHandle Handle of the file being invoked. @param PeiServices Describes the list of possible PEI Services. @return EFI_SUCCESS The PEIM initialized successfully. **/ EFI_STATUS EFIAPI InitializePlatform ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n")); DebugDumpCmos (); XenDetect (); if (QemuFwCfgS3Enabled ()) { DEBUG ((EFI_D_INFO, "S3 support was detected on QEMU\n")); mS3Supported = TRUE; Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE); ASSERT_EFI_ERROR (Status); } S3Verification (); BootModeInitialization (); AddressWidthInitialization (); MaxCpuCountInitialization (); PublishPeiMemory (); InitializeRamRegions (); if (mXen) { DEBUG ((EFI_D_INFO, "Xen was detected\n")); InitializeXen (); } // // Query Host Bridge DID // mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); if (mBootMode != BOOT_ON_S3_RESUME) { ReserveEmuVariableNvStore (); PeiFvInitialization (); MemMapInitialization (); NoexecDxeInitialization (); } MiscInitialization (); InstallFeatureControlCallback (); return EFI_SUCCESS; }
/** Check if it needs to re-initialize usb debug port hardware. During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check whether the usb debug port hardware configuration is changed. Such case can be triggerred by Pci bus resource allocation and so on. @param Handle Debug port handle. @retval TRUE The usb debug port hardware configuration is changed. @retval FALSE The usb debug port hardware configuration is not changed. **/ BOOLEAN EFIAPI NeedReinitializeHardware( IN USB_DEBUG_PORT_HANDLE *Handle ) { UINT16 PciCmd; UINT32 UsbDebugPortMemoryBase; UINT32 EhciMemoryBase; BOOLEAN Status; USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister; Status = FALSE; EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); if (EhciMemoryBase != Handle->EhciMemoryBase) { Handle->EhciMemoryBase = EhciMemoryBase; Status = TRUE; } UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle->DebugPortBarNumber * 4); if (UsbDebugPortMemoryBase != Handle->UsbDebugPortMemoryBase) { Handle->UsbDebugPortMemoryBase = UsbDebugPortMemoryBase; Status = TRUE; } // // Enable Ehci Memory Space Access // PciCmd = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET); if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) { PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER; PciWrite16(PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd); Status = TRUE; } // // If the owner and in_use bit is not set, it means system is doing cold/warm boot or EHCI host controller is reset by system software. // UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)(UINTN)(Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset); if ((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE)) != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_ENABLE | USB_DEBUG_PORT_IN_USE)) { Status = TRUE; } if (Handle->Initialized == USBDBG_RESET) { Status = TRUE; } else if (Handle->Initialized != USBDBG_INIT_DONE) { Status = TRUE; } return Status; }
/** The constructor function enables ACPI IO space. If ACPI I/O space not enabled, this function will enable it. It will always return RETURN_SUCCESS. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT16 HostBridgeDevId; UINTN Pmba; UINTN AcpiCtlReg; UINT8 AcpiEnBit; // // Query Host Bridge DID to determine platform type // HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); switch (HostBridgeDevId) { case INTEL_82441_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC); AcpiEnBit = PIIX4_PMREGMISC_PMIOSE; break; case INTEL_Q35_MCH_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL); AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN; break; default: DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, HostBridgeDevId)); ASSERT (FALSE); return RETURN_UNSUPPORTED; } // // Check to see if the Power Management Base Address is already enabled // if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) { // // If the Power Management Base Address is not programmed, // then program the Power Management Base Address from a PCD. // PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress)); // // Enable PMBA I/O port decodes // PciOr8 (AcpiCtlReg, AcpiEnBit); } return RETURN_SUCCESS; }
/** The constructor function caches the ACPI tick counter address, and, if necessary, enables ACPI IO space. @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. **/ RETURN_STATUS EFIAPI AcpiTimerLibConstructor ( VOID ) { UINT16 HostBridgeDevId; UINTN Pmba; UINTN PmRegMisc; // // Query Host Bridge DID to determine platform type // HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); switch (HostBridgeDevId) { case INTEL_82441_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40); PmRegMisc = POWER_MGMT_REGISTER_PIIX4 (0x80); break; case INTEL_Q35_MCH_DEVICE_ID: Pmba = POWER_MGMT_REGISTER_Q35 (0x40); PmRegMisc = POWER_MGMT_REGISTER_Q35 (0x80); break; default: DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", __FUNCTION__, HostBridgeDevId)); ASSERT (FALSE); return RETURN_UNSUPPORTED; } mAcpiTimerIoAddr = (PciRead32 (Pmba) & ~PMBA_RTE) + ACPI_TIMER_OFFSET; // // Check to see if the Power Management Base Address is already enabled // if ((PciRead8 (PmRegMisc) & PMIOSE) == 0) { // // If the Power Management Base Address is not programmed, // then program the Power Management Base Address from a PCD. // PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress)); // // Enable PMBA I/O port decodes in PMREGMISC // PciOr8 (PmRegMisc, PMIOSE); } return RETURN_SUCCESS; }
/** Reads a bit field in a 16-bit PCI configuration register, performs a bitwise AND, and writes the result back to the bit field in the 16-bit register. Reads the 16-bit PCI configuration register specified by Address, performs a bitwise AND between the read result and the value specified by AndData, and writes the result to the 16-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. Extra left bits in AndData are stripped. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Address The PCI configuration register to write. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..15. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..15. @param AndData The value to AND with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI PciBitFieldAnd16 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT16 AndData ) { return PciWrite16 ( Address, BitFieldAnd16 (PciRead16 (Address), StartBit, EndBit, AndData) ); }
/** Writes a bit field to a PCI configuration register. Writes Value to the bit field of the PCI configuration register. The bit field is specified by the StartBit and the EndBit. All other bits in the destination PCI configuration register are preserved. The new value of the 16-bit register is returned. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Address The PCI configuration register to write. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..15. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..15. @param Value The new value of the bit field. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI PciBitFieldWrite16 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT16 Value ) { return PciWrite16 ( Address, BitFieldWrite16 (PciRead16 (Address), StartBit, EndBit, Value) ); }
/** Perform Platform PEI initialization. @param FileHandle Handle of the file being invoked. @param PeiServices Describes the list of possible PEI Services. @return EFI_SUCCESS The PEIM initialized successfully. **/ EFI_STATUS EFIAPI InitializePlatform ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n")); DebugDumpCmos (); XenDetect (); if (QemuFwCfgS3Enabled ()) { DEBUG ((EFI_D_INFO, "S3 support was detected on QEMU\n")); mS3Supported = TRUE; } BootModeInitialization (); PublishPeiMemory (); InitializeRamRegions (); if (mXen) { DEBUG ((EFI_D_INFO, "Xen was detected\n")); InitializeXen (); } // // Query Host Bridge DID // mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); if (mBootMode != BOOT_ON_S3_RESUME) { ReserveEmuVariableNvStore (); PeiFvInitialization (); MemMapInitialization (); } MiscInitialization (); return EFI_SUCCESS; }
/** Perform USB erratas after MRC init. **/ VOID PlatformUsbErratasPostMrc ( VOID ) { UINT32 Index; UINT32 TempBar0Addr; UINT16 SaveCmdReg; UINT32 SaveBar0Reg; TempBar0Addr = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress); // // Apply EHCI controller erratas. // for (Index = 0; Index < IOH_MAX_EHCI_USB_CONTROLLERS; Index++, TempBar0Addr += IOH_USB_CONTROLLER_MMIO_RANGE) { if ((PciRead16 (IohEhciPciReg[Index] + R_IOH_USB_VENDOR_ID)) != V_IOH_USB_VENDOR_ID) { continue; // Device not enabled, skip. } // // Save current settings for PCI CMD/BAR0 registers // SaveCmdReg = PciRead16 (IohEhciPciReg[Index] + R_IOH_USB_COMMAND); SaveBar0Reg = PciRead32 (IohEhciPciReg[Index] + R_IOH_USB_MEMBAR); // // Temp. assign base address register, Enable Memory Space. // PciWrite32 ((IohEhciPciReg[Index] + R_IOH_USB_MEMBAR), TempBar0Addr); PciWrite16 (IohEhciPciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg | B_IOH_USB_COMMAND_MSE); // // Set packet buffer OUT/IN thresholds. // MmioAndThenOr32 ( TempBar0Addr + R_IOH_EHCI_INSNREG01, (UINT32) (~(B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_MASK | B_IOH_EHCI_INSNREG01_IN_THRESHOLD_MASK)), (UINT32) ((EHCI_OUT_THRESHOLD_VALUE << B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP) | (EHCI_IN_THRESHOLD_VALUE << B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP)) ); // // Restore settings for PCI CMD/BAR0 registers // PciWrite32 ((IohEhciPciReg[Index] + R_IOH_USB_MEMBAR), SaveBar0Reg); PciWrite16 (IohEhciPciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg); } // // Apply USB device controller erratas. // for (Index = 0; Index < IOH_MAX_USBDEVICE_USB_CONTROLLERS; Index++, TempBar0Addr += IOH_USB_CONTROLLER_MMIO_RANGE) { if ((PciRead16 (IohUsbDevicePciReg[Index] + R_IOH_USB_VENDOR_ID)) != V_IOH_USB_VENDOR_ID) { continue; // Device not enabled, skip. } // // Save current settings for PCI CMD/BAR0 registers // SaveCmdReg = PciRead16 (IohUsbDevicePciReg[Index] + R_IOH_USB_COMMAND); SaveBar0Reg = PciRead32 (IohUsbDevicePciReg[Index] + R_IOH_USB_MEMBAR); // // Temp. assign base address register, Enable Memory Space. // PciWrite32 ((IohUsbDevicePciReg[Index] + R_IOH_USB_MEMBAR), TempBar0Addr); PciWrite16 (IohUsbDevicePciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg | B_IOH_USB_COMMAND_MSE); // // Erratas for USB Device interrupt registers. // // // 1st Mask interrupts. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_D_INTR_MSK_UDC_REG, V_IOH_USBDEVICE_D_INTR_MSK_UDC_REG ); // // 2nd RW/1C of equivalent status bits. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_D_INTR_UDC_REG, V_IOH_USBDEVICE_D_INTR_MSK_UDC_REG ); // // 1st Mask end point interrupts. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG, V_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG ); // // 2nd RW/1C of equivalent end point status bits. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_EP_INTR_UDC_REG, V_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG ); // // Restore settings for PCI CMD/BAR0 registers // PciWrite32 ((IohUsbDevicePciReg[Index] + R_IOH_USB_MEMBAR), SaveBar0Reg); PciWrite16 (IohUsbDevicePciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg); } }
/* For each function we create a * pci_device and add it to the list */ void PciCheckFunction(list_t *Bridge, uint8_t Bus, uint8_t Device, uint8_t Function) { uint8_t SecondBus; PciNativeHeader_t *Pcs; PciDevice_t *PciDevice; /* Allocate */ Pcs = (PciNativeHeader_t*)kmalloc(sizeof(PciNativeHeader_t)); PciDevice = (PciDevice_t*)kmalloc(sizeof(PciDevice_t)); /* Get full information */ PciReadFunction(Pcs, Bus, Device, Function); /* Set information */ PciDevice->Header = Pcs; PciDevice->Bus = Bus; PciDevice->Device = Device; PciDevice->Function = Function; PciDevice->Children = NULL; /* Info * Ignore the spam of device_id 0x7a0 in VMWare*/ if (Pcs->DeviceId != 0x7a0) { #ifdef X86_PCI_DIAGNOSE printf(" * [%d:%d:%d][%d:%d:%d] Vendor 0x%x, Device 0x%x : %s\n", Pcs->Class, Pcs->Subclass, Pcs->Interface, Bus, Device, Function, Pcs->VendorId, Pcs->DeviceId, PciToString(Pcs->Class, Pcs->Subclass, Pcs->Interface)); #endif } /* Do some disabling, but NOT on the video or bridge */ if ((Pcs->Class != PCI_DEVICE_CLASS_BRIDGE) && (Pcs->Class != PCI_DEVICE_CLASS_VIDEO)) { /* Disable Device untill further notice */ uint16_t PciSettings = PciRead16(Bus, Device, Function, 0x04); PciWrite16(Bus, Device, Function, 0x04, PciSettings | X86_PCI_COMMAND_INTDISABLE); } /* Add to list */ if (Pcs->Class == PCI_DEVICE_CLASS_BRIDGE && Pcs->Subclass == PCI_DEVICE_SUBCLASS_PCI) { PciDevice->Type = X86_PCI_TYPE_BRIDGE; list_append(Bridge, list_create_node(X86_PCI_TYPE_BRIDGE, PciDevice)); } else { PciDevice->Type = X86_PCI_TYPE_DEVICE; list_append(Bridge, list_create_node(X86_PCI_TYPE_DEVICE, PciDevice)); } /* Is this a secondary (PCI) bus */ if ((Pcs->Class == PCI_DEVICE_CLASS_BRIDGE) && (Pcs->Subclass == PCI_DEVICE_SUBCLASS_PCI)) { /* Uh oh, this dude has children */ PciDevice->Children = list_create(LIST_SAFE); SecondBus = PciReadSecondaryBusNumber(Bus, Device, Function); PciCheckBus(PciDevice->Children, SecondBus); } }
/** Initialize usb debug port hardware. 1. reset ehci host controller. 2. set right port to debug port. 3. find a usb debug device is attached by getting debug device descriptor. 4. set address for the usb debug device. 5. configure the usb debug device to debug mode. @param Handle Debug port handle. @retval TRUE The usb debug port hardware configuration is changed. @retval FALSE The usb debug port hardware configuration is not changed. **/ RETURN_STATUS EFIAPI InitializeUsbDebugHardware ( IN USB_DEBUG_PORT_HANDLE *Handle ) { RETURN_STATUS Status; USB_DEBUG_PORT_REGISTER *UsbDebugPortRegister; USB_DEBUG_PORT_DESCRIPTOR UsbDebugPortDescriptor; UINT16 PciCmd; UINT32 *PortStatus; UINT32 *UsbCmd; UINT32 *UsbStatus; UINT32 *UsbHCSParam; UINT8 DebugPortNumber; UINT8 Length; UsbDebugPortRegister = (USB_DEBUG_PORT_REGISTER *)(UINTN)(Handle->UsbDebugPortMemoryBase + Handle->DebugPortOffset); PciCmd = PciRead16 (PcdGet32(PcdUsbEhciPciAddress) + PCI_COMMAND_OFFSET); UsbHCSParam = (UINT32 *)(UINTN)(Handle->EhciMemoryBase + 0x04); UsbCmd = (UINT32 *)(UINTN)(Handle->EhciMemoryBase + 0x20); UsbStatus = (UINT32 *)(UINTN)(Handle->EhciMemoryBase + 0x24); // // Check if the debug port is enabled and owned by myself. // if (((MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) & (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE)) != (USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE)) || (Handle->Initialized == USBDBG_RESET)) { DEBUG (( EFI_D_INFO, "UsbDbg: Need to reset the host controller. ControlStatus = %08x\n", MmioRead32((UINTN)&UsbDebugPortRegister->ControlStatus) )); // // If the host controller is halted, then reset and restart it. // if ((MmioRead32((UINTN)UsbStatus) & BIT12) != 0) { DEBUG ((EFI_D_INFO, "UsbDbg: Reset the host controller.\n")); // // reset the host controller. // MmioOr32((UINTN)UsbCmd, BIT1); // // ensure that the host controller is reset. // while ((MmioRead32((UINTN)UsbCmd) & BIT1) != 0); MmioOr32((UINTN)UsbCmd, BIT0); // ensure that the host controller is started (HALTED bit must be cleared) while ((MmioRead32((UINTN)UsbStatus) & BIT12) != 0); } // // First get the ownership of port 0. // MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_OWNER | USB_DEBUG_PORT_IN_USE); MicroSecondDelay (200000); } // // Find out which port is used as debug port. // DebugPortNumber = (UINT8)((MmioRead32((UINTN)UsbHCSParam) & 0x00F00000) >> 20); // // Should find a device is connected at debug port // PortStatus = (UINT32 *)(UINTN)(Handle->EhciMemoryBase + 0x64 + (DebugPortNumber - 1) * 4); if (!(MmioRead32((UINTN)PortStatus) & BIT0)) { Handle->Initialized = USBDBG_NO_DEV; return RETURN_NOT_FOUND; } if (Handle->Initialized != USBDBG_INIT_DONE || (MmioRead32 ((UINTN) &UsbDebugPortRegister->ControlStatus) & USB_DEBUG_PORT_ENABLE) == 0) { DEBUG ((EFI_D_INFO, "UsbDbg: Reset the debug port.\n")); // // Reset the debug port // MmioOr32((UINTN)PortStatus, BIT8); MicroSecondDelay (500000); MmioAnd32((UINTN)PortStatus, (UINT32)~BIT8); while (MmioRead32((UINTN)PortStatus) & BIT8); // // The port enabled bit should be set by HW. // if ((MmioRead32((UINTN)PortStatus) & BIT2) == 0) { Handle->Initialized = USBDBG_NO_DBG_CAB; return RETURN_DEVICE_ERROR; } // // Enable Usb Debug Port Capability // MmioOr32((UINTN)&UsbDebugPortRegister->ControlStatus, USB_DEBUG_PORT_ENABLE); // // initialize the data toggle used by bulk in/out endpoint. // Handle->BulkInToggle = 0; Handle->BulkOutToggle = 0; // // set usb debug device address as 0x7F. // Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mSetDebugAddress, 0x0, 0x0, NULL, NULL); if (RETURN_ERROR(Status)) { // // The device can not work well. // Handle->Initialized = USBDBG_NO_DBG_CAB; return Status; } // // Start to communicate with Usb Debug Device to see if the attached device is usb debug device or not. // Length = (UINT8)sizeof (USB_DEBUG_PORT_DESCRIPTOR); // // Get debug descriptor. // Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mGetDebugDescriptor, 0x7F, 0x0, (UINT8*)&UsbDebugPortDescriptor, &Length); if (RETURN_ERROR(Status)) { // // The device is not a usb debug device. // Handle->Initialized = USBDBG_NO_DBG_CAB; return Status; } if (Length != sizeof(USB_DEBUG_PORT_DESCRIPTOR)) { Handle->Initialized = USBDBG_NO_DBG_CAB; return RETURN_DEVICE_ERROR; } // // enable the usb debug feature. // Status = UsbDebugPortControlTransfer (UsbDebugPortRegister, &mSetDebugFeature, 0x7F, 0x0, NULL, NULL); if (RETURN_ERROR(Status)) { // // The device can not work well. // Handle->Initialized = USBDBG_NO_DBG_CAB; return Status; } Handle->Initialized = USBDBG_DBG_CAB; } // // Set initialized flag // Handle->Initialized = USBDBG_INIT_DONE; return RETURN_SUCCESS; }
EFIAPI PciHostBridgeGetRootBridges ( UINTN *Count ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; UINT64 ExtraRootBridges; PCI_ROOT_BRIDGE *Bridges; UINTN Initialized; UINTN LastRootBridgeNumber; UINTN RootBridgeNumber; *Count = 0; // // QEMU provides the number of extra root buses, shortening the exhaustive // search below. If there is no hint, the feature is missing. // Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridges) { ExtraRootBridges = 0; } else { QemuFwCfgSelectItem (FwCfgItem); QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges); if (ExtraRootBridges > PCI_MAX_BUS) { DEBUG ((EFI_D_ERROR, "%a: invalid count of extra root buses (%Lu) " "reported by QEMU\n", __FUNCTION__, ExtraRootBridges)); return NULL; } DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n", __FUNCTION__, ExtraRootBridges)); } // // Allocate the "main" root bridge, and any extra root bridges. // Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges); if (Bridges == NULL) { DEBUG ((EFI_D_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES)); return NULL; } Initialized = 0; // // The "main" root bus is always there. // LastRootBridgeNumber = 0; // // Scan all other root buses. If function 0 of any device on a bus returns a // VendorId register value different from all-bits-one, then that bus is // alive. // for (RootBridgeNumber = 1; RootBridgeNumber <= PCI_MAX_BUS && Initialized < ExtraRootBridges; ++RootBridgeNumber) { UINTN Device; for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) { if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0, PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) { break; } } if (Device <= PCI_MAX_DEVICE) { // // Found the next root bus. We can now install the *previous* one, // because now we know how big a bus number range *that* one has, for any // subordinate buses that might exist behind PCI bridges hanging off it. // Status = InitRootBridge ((UINT8)LastRootBridgeNumber, (UINT8)(RootBridgeNumber - 1), &Bridges[Initialized]); if (EFI_ERROR (Status)) { goto FreeBridges; } ++Initialized; LastRootBridgeNumber = RootBridgeNumber; } } // // Install the last root bus (which might be the only, ie. main, root bus, if // we've found no extra root buses). // Status = InitRootBridge ((UINT8)LastRootBridgeNumber, PCI_MAX_BUS, &Bridges[Initialized]); if (EFI_ERROR (Status)) { goto FreeBridges; } ++Initialized; *Count = Initialized; return Bridges; FreeBridges: while (Initialized > 0) { --Initialized; UninitRootBridge (&Bridges[Initialized]); } FreePool (Bridges); return NULL; }
/** Performs any early platform specific GPIO Controller manipulation. **/ VOID EFIAPI EarlyPlatformGpioCtrlerManipulation ( VOID ) { UINT32 IohGpioBase; UINT32 Data32; UINT32 Addr; UINT32 DevPcieAddr; UINT16 SaveCmdReg; UINT32 SaveBarReg; UINT16 PciVid; UINT16 PciDid; IohGpioBase = (UINT32) PcdGet64 (PcdIohGpioMmioBase); DevPcieAddr = PCI_LIB_ADDRESS ( PcdGet8 (PcdIohGpioBusNumber), PcdGet8 (PcdIohGpioDevNumber), PcdGet8 (PcdIohGpioFunctionNumber), 0 ); // // Do nothing if not a supported device. // PciVid = PciRead16 (DevPcieAddr + PCI_VENDOR_ID_OFFSET); PciDid = PciRead16 (DevPcieAddr + PCI_DEVICE_ID_OFFSET); if((PciVid != V_IOH_I2C_GPIO_VENDOR_ID) || (PciDid != V_IOH_I2C_GPIO_DEVICE_ID)) { return; } // // Save current settings for PCI CMD/BAR registers. // SaveCmdReg = PciRead16 (DevPcieAddr + PCI_COMMAND_OFFSET); SaveBarReg = PciRead32 (DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister)); // // Use predefined tempory memory resource. // PciWrite32 ( DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister), IohGpioBase); PciWrite8 ( DevPcieAddr + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); // // Gpio Controller Manipulation Tasks. // // // Reset Cypress Expander on Galileo Platform // Addr = IohGpioBase + GPIO_SWPORTA_DR; Data32 = *((volatile UINT32 *) (UINTN)(Addr)); Data32 |= BIT4; // Cypress Reset line controlled by GPIO<4> *((volatile UINT32 *) (UINTN)(Addr)) = Data32; Data32 = *((volatile UINT32 *) (UINTN)(Addr)); Data32 &= ~BIT4; // Cypress Reset line controlled by GPIO<4> *((volatile UINT32 *) (UINTN)(Addr)) = Data32; // // Restore settings for PCI CMD/BAR registers // PciWrite32 ((DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister)), SaveBarReg); PciWrite16 (DevPcieAddr + PCI_COMMAND_OFFSET, SaveCmdReg); }
/** Reads a range of PCI configuration registers into a caller supplied buffer. Reads the range of PCI configuration registers specified by StartAddress and Size into the buffer specified by Buffer. This function only allows the PCI configuration registers from a single PCI function to be read. Size is returned. When possible 32-bit PCI configuration read cycles are used to read from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit and 16-bit PCI configuration read cycles may be used at the beginning and the end of the range. If StartAddress > 0x0FFFFFFF, then ASSERT(). If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). If Size > 0 and Buffer is NULL, then ASSERT(). @param StartAddress The starting address that encodes the PCI Bus, Device, Function and Register. @param Size The size in bytes of the transfer. @param Buffer The pointer to a buffer receiving the data read. @return Size **/ UINTN EFIAPI PciReadBuffer ( IN UINTN StartAddress, IN UINTN Size, OUT VOID *Buffer ) { UINTN ReturnValue; ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0); ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); if (Size == 0) { return Size; } ASSERT (Buffer != NULL); // // Save Size for return // ReturnValue = Size; if ((StartAddress & BIT0) != 0) { // // Read a byte if StartAddress is byte aligned // *(volatile UINT8 *)Buffer = PciRead8 (StartAddress); StartAddress += sizeof (UINT8); Size -= sizeof (UINT8); Buffer = (UINT8*)Buffer + 1; } if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { // // Read a word if StartAddress is word aligned // WriteUnaligned16 (Buffer, PciRead16 (StartAddress)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } while (Size >= sizeof (UINT32)) { // // Read as many double words as possible // WriteUnaligned32 (Buffer, PciRead32 (StartAddress)); StartAddress += sizeof (UINT32); Size -= sizeof (UINT32); Buffer = (UINT32*)Buffer + 1; } if (Size >= sizeof (UINT16)) { // // Read the last remaining word if exist // WriteUnaligned16 (Buffer, PciRead16 (StartAddress)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } if (Size >= sizeof (UINT8)) { // // Read the last remaining byte if exist // *(volatile UINT8 *)Buffer = PciRead8 (StartAddress); } return ReturnValue; }