/** Probe a bar is existed or not. @param[in] Address PCI address for the BAR. @param[out] OriginalValue The original bar value returned. @param[out] Value The probed bar value returned. **/ STATIC VOID PcatPciRootBridgeBarExisted ( IN UINT64 Address, OUT UINT32 *OriginalValue, OUT UINT32 *Value ) { UINTN PciAddress; PciAddress = (UINTN)Address; // // Preserve the original value // *OriginalValue = PciRead32 (PciAddress); // // Disable timer interrupt while the BAR is probed // DisableInterrupts (); PciWrite32 (PciAddress, 0xFFFFFFFF); *Value = PciRead32 (PciAddress); PciWrite32 (PciAddress, *OriginalValue); // // Enable interrupt // EnableInterrupts (); }
/** Configure RootPort for downstream PCIe NAND devices. @param[in] RpBase - PCIe configuration space address of this RootPort @param[in] BusNumber - Bus number @param[in] MemoryBase - Memory base address @param[in] MemoryLength - Memory size **/ VOID ConfigureRootPortForPcieNand ( IN UINTN RpBase, IN UINTN BusNumber, IN UINT32 MemoryBase, IN UINT32 MemoryLength ) { UINT32 MemoryLimit; DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n", BusNumber, MemoryBase, MemoryLength)); if (MemoryLength == 0) { MemoryLimit = MemoryBase; } else { MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M } /// /// Configue PCIE configuration space for RootPort /// PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers }
// ------------------------------------------------------------------------------------------------ static void PciReadBar(uint32 id, uint32 index, uint32 *address, uint32 *mask) { uint32 reg = PCI_CONFIG_BAR0 + index * sizeof(uint32); // Get address *address = PciRead32(id, reg); // Find out size of the bar PciWrite32(id, reg, 0xffffffff); *mask = PciRead32(id, reg); // Restore adddress PciWrite32(id, reg, *address); }
ACPI_STATUS AcpiOsWritePciConfiguration ( ACPI_PCI_ID *PciId, UINT32 Register, UINT64 Value, UINT32 Width) { UINT32 devfn = ((PciId->Device & 0x1f)<<3)|(PciId->Function & 0x07); switch (Width) { case 8: PciWrite8(PciId->Bus,devfn,Register,Value); break; case 16: PciWrite16(PciId->Bus,devfn,Register,Value); break; case 32: PciWrite32(PciId->Bus,devfn,Register,Value); break; default: dbgprintf("AcpiOsReadPciConfiguration unhandled value width: %u\n", Width); return AE_ERROR; } return (AE_OK); }
void PciDeviceWrite(PciDevice_t *Device, uint32_t Register, uint32_t Value, uint32_t Length) { if (Length == 1) PciWrite8(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register, (uint8_t)(Value & 0xFF)); else if (Length == 2) PciWrite16(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register, (uint16_t)(Value & 0xFFFFF)); else PciWrite32(Device->PciBus, Device->Bus, Device->Device, Device->Function, Register, Value); }
/** Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value. Reads the 32-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 32-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 32-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. **/ UINT32 EFIAPI PciOr32 ( IN UINTN Address, IN UINT32 OrData ) { return PciWrite32 (Address, PciRead32 (Address) | OrData); }
/** Writes a 32-bit PCI configuration register and saves the value in the S3 script to be replayed on S3 resume. Writes the 32-bit PCI configuration register specified by Address with the value specified by Value. Value 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 32-bit boundary, then ASSERT(). @param Address Address that encodes the PCI Bus, Device, Function and Register. @param Value The value to write. @return The value written to the PCI configuration register. **/ UINT32 EFIAPI S3PciWrite32 ( IN UINTN Address, IN UINT32 Value ) { return InternalSavePciWrite32ValueToBootScript (Address, PciWrite32 (Address, Value)); }
/** Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value. Reads the 32-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 32-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 32-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. **/ UINT32 EFIAPI PciAnd32 ( IN UINTN Address, IN UINT32 AndData ) { return PciWrite32 (Address, PciRead32 (Address) & AndData); }
/** Write to 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 PciCfg2Write ( 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) { PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); } else if (Width == EfiPeiPciCfgWidthUint16) { if ((PciLibAddress & 0x01) == 0) { // // Aligned Pci address access // PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1)); } } else if (Width == EfiPeiPciCfgWidthUint32) { if ((PciLibAddress & 0x03) == 0) { // // Aligned Pci address access // PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer)); } else if ((PciLibAddress & 0x01) == 0) { // // Unaligned Pci address access, break up the request into word by word. // PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer)); PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1)); } else { // // Unaligned Pci address access, break up the request into byte by byte. // PciWrite8 (PciLibAddress, *((UINT8 *) Buffer)); PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1)); PciWrite8 (PciLibAddress + 2, *((UINT8 *) Buffer + 2)); PciWrite8 (PciLibAddress + 3, *((UINT8 *) Buffer + 3)); } } else { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; }
/** Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value, followed a bitwise OR with another 32-bit value. Reads the 32-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 32-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 32-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. **/ UINT32 EFIAPI PciAndThenOr32 ( IN UINTN Address, IN UINT32 AndData, IN UINT32 OrData ) { return PciWrite32 (Address, (PciRead32 (Address) & AndData) | OrData); }
/** Writes a 32-bit PCI configuration register. Writes the 32-bit PCI configuration register specified by Address with the value specified by Value. Value is returned. 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 32-bit boundary, then ASSERT(). @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register. @param Value The value to write. @return The parameter of Value. **/ UINT32 EFIAPI PciSegmentWrite32 ( IN UINT64 Address, IN UINT32 Value ) { ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); return PciWrite32 (PCI_SEGMENT_TO_PCI_ADDRESS (Address), Value); }
/* PciDeviceWrite * Writes a value of the given length to the given register * and this function takes care of the rest */ void PciDeviceWrite(PciDevice_t *Device, size_t Register, uint32_t Value, size_t Length) { if (Length == 1) { PciWrite8(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register, (uint8_t)(Value & 0xFF)); } else if (Length == 2) { PciWrite16(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register, (uint16_t)(Value & 0xFFFFF)); } else { PciWrite32(Device->BusIo, Device->Bus, Device->Slot, Device->Function, Register, Value); } }
VOID PciExBarInitialization ( VOID ) { union { UINT64 Uint64; UINT32 Uint32[2]; } PciExBarBase; // // We only support the 256MB size for the MMCONFIG area: // 256 buses * 32 devices * 8 functions * 4096 bytes config space. // // The masks used below enforce the Q35 requirements that the MMCONFIG area // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB. // // Note that (b) also ensures that the minimum address width we have // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice // for DXE's page tables to cover the MMCONFIG area. // PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress); ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0); ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0); // // Clear the PCIEXBAREN bit first, before programming the high register. // PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0); // // Program the high register. Then program the low register, setting the // MMCONFIG area size and enabling decoding at once. // PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]); PciWrite32 ( DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN ); }
/** Reads a bit field in a 32-bit PCI configuration register, performs a bitwise AND, and writes the result back to the bit field in the 32-bit register. Reads the 32-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 32-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 32-bit boundary, then ASSERT(). If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, 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..31. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..31. @param AndData The value to AND with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT32 EFIAPI PciBitFieldAnd32 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT32 AndData ) { return PciWrite32 ( Address, BitFieldAnd32 (PciRead32 (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 32-bit register is returned. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 32-bit boundary, then ASSERT(). If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, 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..31. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..31. @param Value The new value of the bit field. @return The value written back to the PCI configuration register. **/ UINT32 EFIAPI PciBitFieldWrite32 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT32 Value ) { return PciWrite32 ( Address, BitFieldWrite32 (PciRead32 (Address), StartBit, EndBit, Value) ); }
/** 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 IntelQNCAcpiTimerLibConstructor ( VOID ) { if ((PciRead32 (PCI_LIB_ADDRESS (LPC_PCI_BUS, LPC_PCI_DEV, LPC_PCI_FUNC, R_LPC_PM1BLK)) & BIT31) == 0) { // // If ACPI I/O space is not enabled, program ACPI I/O base address and enable it. // PciWrite32 (PCI_LIB_ADDRESS (LPC_PCI_BUS, LPC_PCI_DEV, LPC_PCI_FUNC, R_LPC_PM1BLK), BIT31 | PcdGet16 (PcdPm1blkIoBaseAddress)); } return RETURN_SUCCESS; }
VOID MiscInitialization ( VOID ) { UINTN PmCmd; UINTN Pmba; UINTN AcpiCtlReg; UINT8 AcpiEnBit; // // Disable A20 Mask // IoOr8 (0x92, BIT1); // // Build the CPU HOB with guest RAM size dependent address width and 16-bits // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during // S3 resume as well, so we build it unconditionally.) // BuildCpuHob (mPhysMemAddressWidth, 16); // // Determine platform type and save Host Bridge DID to PCD // switch (mHostBridgeDevId) { case INTEL_82441_DEVICE_ID: PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET); 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: PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET); 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__, mHostBridgeDevId)); ASSERT (FALSE); return; } PcdSet16 (PcdOvmfHostBridgePciDevId, mHostBridgeDevId); // // If the appropriate IOspace enable bit is set, assume the ACPI PMBA // has been configured (e.g., by Xen) and skip the setup here. // This matches the logic in AcpiTimerLibConstructor (). // if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) { // // The PEI phase should be exited with fully accessibe ACPI PM IO space: // 1. set PMBA // PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress)); // // 2. set PCICMD/IOSE // PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE); // // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN) // PciOr8 (AcpiCtlReg, AcpiEnBit); } if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { // // Set Root Complex Register Block BAR // PciWrite32 ( POWER_MGMT_REGISTER_Q35 (ICH9_RCBA), ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN ); // // Set PCI Express Register Range Base Address // PciExBarInitialization (); } }
EFI_STATUS IgdPmHook ( IN EFI_HANDLE ImageHandle, IN DXE_VLV_PLATFORM_POLICY_PROTOCOL *DxePlatformSaPolicy ) { EFI_EVENT mConOutEvent; VOID *gConOutNotifyReg; EFI_STATUS Status; EFI_PHYSICAL_ADDRESS MemBaseAddress; UINT32 LoGTBaseAddress; UINT32 HiGTBaseAddress; GTTMMADR = 0; Status = EFI_SUCCESS; // // If device 0:2:0 (Internal Graphics Device, or GT) is enabled, then Program GTTMMADR, // if (PciRead16(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_VID)) != 0xFFFF) { ASSERT (gDS!=NULL); // // Enable Bus Master, I/O and Memory access on 0:2:0 // PciOr8(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_CMD), (BIT2 | BIT1 | BIT0)); // // Means Allocate 4MB for GTTMADDR // MemBaseAddress = 0x0ffffffff; Status = gDS->AllocateMemorySpace ( EfiGcdAllocateMaxAddressSearchBottomUp, EfiGcdMemoryTypeMemoryMappedIo, GTT_MEM_ALIGN, GTTMMADR_SIZE_4MB, &MemBaseAddress, ImageHandle, NULL ); ASSERT_EFI_ERROR (Status); // // Program GT PM Settings if GTTMMADR allocation is Successful // GTTMMADR = (UINTN) MemBaseAddress; LoGTBaseAddress = (UINT32) (MemBaseAddress & 0xFFFFFFFF); HiGTBaseAddress = (UINT32) RShiftU64 ((MemBaseAddress & 0xFFFFFFFF00000000), 32); PciWrite32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR), LoGTBaseAddress); PciWrite32 (PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR+4), HiGTBaseAddress); S3PciRead32(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_GTTMMADR)); S3MmioRead32(IGD_R_GTTMMADR + 4); S3PciRead8(PCI_LIB_ADDRESS(0, IGD_DEV, 0, IGD_R_CMD)); // // Do POST GT PM Init Steps after VBIOS Initialization in DoPostPmInitCallBack // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, (EFI_EVENT_NOTIFY)PostPmInitCallBack, NULL, &mConOutEvent ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } Status = gBS->RegisterProtocolNotify ( &gEfiGraphicsOutputProtocolGuid, mConOutEvent, &gConOutNotifyReg ); MmioWrite64 (IGD_R_GTTMMADR, 0); // // Free allocated resources // gDS->FreeMemorySpace ( MemBaseAddress, GTTMMADR_SIZE_4MB ); } return EFI_SUCCESS; }
/** Initialize the debug port. If Function is not NULL, Debug Communication Libary will call this function by passing in the Context to be the first parameter. If needed, Debug Communication Library will create one debug port handle to be the second argument passing in calling the Function, otherwise it will pass NULL to be the second argument of Function. If Function is NULL, and Context is not NULL, the Debug Communication Library could a) Return the same handle as passed in (as Context parameter). b) Ignore the input Context parameter and create new hanlde to be returned. If parameter Function is NULL and Context is NULL, Debug Communication Library could created a new handle if needed and return it, otherwise it will return NULL. @param[in] Context Context needed by callback function; it was optional. @param[in] Function Continue function called by Debug Communication library; it was optional. @return The debug port handle created by Debug Communication Library if Function is not NULL. **/ DEBUG_PORT_HANDLE EFIAPI DebugPortInitialize ( IN VOID *Context, IN DEBUG_PORT_CONTINUE Function ) { RETURN_STATUS Status; USB_DEBUG_PORT_HANDLE Handle; USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle; UINT64 TimerStartValue; UINT64 TimerEndValue; // // Validate the PCD PcdDebugPortHandleBufferSize value // ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB_DEBUG_PORT_HANDLE)); if (Function == NULL && Context != NULL) { UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Context; } else { ZeroMem(&Handle, sizeof (USB_DEBUG_PORT_HANDLE)); UsbDebugPortHandle = &Handle; } UsbDebugPortHandle->TimerFrequency = GetPerformanceCounterProperties ( &TimerStartValue, &TimerEndValue ); DEBUG ((EFI_D_INFO, "USB Debug Port: TimerFrequency = 0x%lx\n", UsbDebugPortHandle->TimerFrequency)); DEBUG ((EFI_D_INFO, "USB Debug Port: TimerStartValue = 0x%lx\n", TimerStartValue)); DEBUG ((EFI_D_INFO, "USB Debug Port: TimerEndValue = 0x%lx\n", TimerEndValue)); if (TimerEndValue < TimerStartValue) { UsbDebugPortHandle->TimerCountDown = TRUE; UsbDebugPortHandle->TimerCycle = TimerStartValue - TimerEndValue; } else { UsbDebugPortHandle->TimerCountDown = FALSE; UsbDebugPortHandle->TimerCycle = TimerEndValue - TimerStartValue; } if (Function == NULL && Context != NULL) { return (DEBUG_PORT_HANDLE *) Context; } Status = CalculateUsbDebugPortBar(&Handle.DebugPortOffset, &Handle.DebugPortBarNumber); if (RETURN_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbDbg: the pci device pointed by PcdUsbEhciPciAddress is not EHCI host controller or does not support debug port capability!\n")); goto Exit; } Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); if (Handle.EhciMemoryBase == 0) { // // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero // PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, PcdGet32(PcdUsbEhciMemorySpaceBase)); Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); } Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4); if (Handle.UsbDebugPortMemoryBase == 0) { // // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero // PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4, PcdGet32(PcdUsbDebugPortMemorySpaceBase)); Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4); } Handle.Initialized = USBDBG_RESET; if (NeedReinitializeHardware(&Handle)) { DEBUG ((EFI_D_ERROR, "UsbDbg: Start EHCI debug port initialization!\n")); Status = InitializeUsbDebugHardware (&Handle); if (RETURN_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "UsbDbg: Failed, please check if USB debug cable is plugged into EHCI debug port correctly!\n")); goto Exit; } } Exit: if (Function != NULL) { Function (Context, &Handle); } else { CopyMem(&mUsbDebugPortHandle, &Handle, sizeof (USB_DEBUG_PORT_HANDLE)); } return (DEBUG_PORT_HANDLE)(UINTN)&mUsbDebugPortHandle;
/** Copies the data in a caller supplied buffer to a specified range of PCI configuration space. Writes the range of PCI configuration registers specified by StartAddress and Size from the buffer specified by Buffer. This function only allows the PCI configuration registers from a single PCI function to be written. Size is returned. When possible 32-bit PCI configuration write cycles are used to write from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit and 16-bit PCI configuration write 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 containing the data to write. @return Size written to StartAddress. **/ UINTN EFIAPI PciWriteBuffer ( IN UINTN StartAddress, IN UINTN Size, IN VOID *Buffer ) { UINTN ReturnValue; ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0); ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); if (Size == 0) { return 0; } ASSERT (Buffer != NULL); // // Save Size for return // ReturnValue = Size; if ((StartAddress & BIT0) != 0) { // // Write a byte if StartAddress is byte aligned // PciWrite8 (StartAddress, *(UINT8*)Buffer); StartAddress += sizeof (UINT8); Size -= sizeof (UINT8); Buffer = (UINT8*)Buffer + 1; } if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { // // Write a word if StartAddress is word aligned // PciWrite16 (StartAddress, ReadUnaligned16 (Buffer)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } while (Size >= sizeof (UINT32)) { // // Write as many double words as possible // PciWrite32 (StartAddress, ReadUnaligned32 (Buffer)); StartAddress += sizeof (UINT32); Size -= sizeof (UINT32); Buffer = (UINT32*)Buffer + 1; } if (Size >= sizeof (UINT16)) { // // Write the last remaining word if exist // PciWrite16 (StartAddress, ReadUnaligned16 (Buffer)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } if (Size >= sizeof (UINT8)) { // // Write the last remaining byte if exist // PciWrite8 (StartAddress, *(UINT8*)Buffer); } return ReturnValue; }
/** 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); }
/* Read IO Areas */ void PciReadBars(PciBus_t *Bus, MCoreDevice_t *Device, uint32_t HeaderType) { /* Sanity */ int Count = (HeaderType & 0x1) == 0x1 ? 2 : 6; int i; /* Iterate */ for (i = 0; i < Count; i++) { /* Vars */ uint32_t Offset = 0x10 + (i << 2); uint32_t Space32, Size32, Mask32; uint64_t Space64, Size64, Mask64; /* Calc initial mask */ Mask32 = (HeaderType & 0x1) == 0x1 ? ~0x7FF : 0xFFFFFFFF; /* Read */ Space32 = PciRead32(Bus, Device->Bus, Device->Device, Device->Function, Offset); PciWrite32(Bus, Device->Bus, Device->Device, Device->Function, Offset, Space32 | Mask32); Size32 = PciRead32(Bus, Device->Bus, Device->Device, Device->Function, Offset); PciWrite32(Bus, Device->Bus, Device->Device, Device->Function, Offset, Space32); /* Sanity */ if (Size32 == 0xFFFFFFFF) Size32 = 0; if (Space32 == 0xFFFFFFFF) Space32 = 0; /* Io? */ if (Space32 & 0x1) { /* Modify mask */ Mask64 = 0xFFFC; Size64 = Size32; Space64 = Space32 & 0xFFFC; /* Correct the size */ Size64 = PciValidateBarSize(Space64, Size64, Mask64); /* Sanity */ if (Space64 != 0 && Size64 != 0) Device->IoSpaces[i] = IoSpaceCreate(DEVICE_IO_SPACE_IO, (Addr_t)Space64, (size_t)Size64); } /* Memory, 64 bit or 32 bit? */ else if (Space32 & 0x4) { /* 64 Bit */ Space64 = Space32 & 0xFFFFFFF0; Size64 = Size32 & 0xFFFFFFF0; Mask64 = 0xFFFFFFFFFFFFFFF0; /* Calculate new offset */ i++; Offset = 0x10 + (i << 2); /* Read */ Space32 = PciRead32(Bus, Device->Bus, Device->Device, Device->Function, Offset); PciWrite32(Bus, Device->Bus, Device->Device, Device->Function, Offset, 0xFFFFFFFF); Size32 = PciRead32(Bus, Device->Bus, Device->Device, Device->Function, Offset); PciWrite32(Bus, Device->Bus, Device->Device, Device->Function, Offset, Space32); /* Add */ Space64 |= ((uint64_t)Space32 << 32); Size64 |= ((uint64_t)Size32 << 32); /* Sanity */ if (sizeof(Addr_t) < 8 && Space64 > SIZE_MAX) { LogFatal("PCIE", "Found 64 bit device with 64 bit address, can't use it in 32 bit mode"); return; } /* Correct the size */ Size64 = PciValidateBarSize(Space64, Size64, Mask64); /* Create */ if (Space64 != 0 && Size64 != 0) Device->IoSpaces[i] = IoSpaceCreate(DEVICE_IO_SPACE_IO, (Addr_t)Space64, (size_t)Size64); } else { /* Set mask */ Space64 = Space32 & 0xFFFFFFF0; Size64 = Size32 & 0xFFFFFFF0; Mask64 = 0xFFFFFFF0; /* Correct the size */ Size64 = PciValidateBarSize(Space64, Size64, Mask64); /* Create */ if (Space64 != 0 && Size64 != 0) Device->IoSpaces[i] = IoSpaceCreate(DEVICE_IO_SPACE_IO, (Addr_t)Space64, (size_t)Size64); } } }
/** 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); } }
/** The user code starts with this function. @param FileHandle Handle of the file being invoked. @param PeiServices Describes the list of possible PEI Services. @retval EFI_SUCCESS The driver is successfully initialized. @retval Others Can't initialize the driver. **/ EFI_STATUS EFIAPI InitializeSdMmcHcPeim ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_BOOT_MODE BootMode; EFI_STATUS Status; UINT16 Bus; UINT16 Device; UINT16 Function; UINT32 Size; UINT64 MmioSize; UINT8 SubClass; UINT8 BaseClass; UINT8 SlotInfo; UINT8 SlotNum; UINT8 FirstBar; UINT8 Index; UINT8 Slot; UINT32 BarAddr; SD_MMC_HC_PEI_PRIVATE_DATA *Private; // // Shadow this PEIM to run from memory // if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { return EFI_SUCCESS; } Status = PeiServicesGetBootMode (&BootMode); /// /// We do not expose this in S3 boot path, because it is only for recovery. /// if (BootMode == BOOT_ON_S3_RESUME) { return EFI_SUCCESS; } Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA)); if (Private == NULL) { DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n")); return EFI_OUT_OF_RESOURCES; } Private->Signature = SD_MMC_HC_PEI_SIGNATURE; Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi; Private->PpiList = mPpiList; Private->PpiList.Ppi = &Private->SdMmcHostControllerPpi; BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase); for (Bus = 0; Bus < 256; Bus++) { for (Device = 0; Device < 32; Device++) { for (Function = 0; Function < 8; Function++) { SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A)); BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B)); if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) { // // Get the SD/MMC Pci host controller's Slot Info. // SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET)); FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar; SlotNum = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1; ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS); for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) { // // Get the SD/MMC Pci host controller's MMIO region size. // PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE)); PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF); Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot)); switch (Size & 0x07) { case 0x0: // // Memory space: anywhere in 32 bit address space // MmioSize = (~(Size & 0xFFFFFFF0)) + 1; break; case 0x4: // // Memory space: anywhere in 64 bit address space // MmioSize = Size & 0xFFFFFFF0; PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF); Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4)); // // Fix the length to support some spefic 64 bit BAR // Size |= ((UINT32)(-1) << HighBitSet32 (Size)); // // Calculate the size of 64bit bar // MmioSize |= LShiftU64 ((UINT64) Size, 32); MmioSize = (~(MmioSize)) + 1; // // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR. // PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0); break; default: // // Unknown BAR type // ASSERT (FALSE); continue; }; // // Assign resource to the SdMmc Pci host controller's MMIO BAR. // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register. // PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr); PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE)); // // Record the allocated Mmio base address. // Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++; Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr; BarAddr += (UINT32)MmioSize; } Private->TotalSdMmcHcs++; ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS); } } } } /// /// Install SdMmc Host Controller PPI /// Status = PeiServicesInstallPpi (&Private->PpiList); ASSERT_EFI_ERROR (Status); return Status; }