예제 #1
1
/**
  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 ();
}
예제 #2
0
/**
  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
}
예제 #3
0
// ------------------------------------------------------------------------------------------------
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);
}
예제 #4
0
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);
}
예제 #5
0
파일: PciIo.c 프로젝트: Fluray/MollenOS
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);
}
예제 #6
0
파일: PciLib.c 프로젝트: hsienchieh/uefilab
/**
  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);
}
예제 #7
0
파일: S3PciLib.c 프로젝트: etiago/vbox
/**
  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));
}
예제 #8
0
파일: PciLib.c 프로젝트: hsienchieh/uefilab
/**
  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);
}
예제 #9
0
파일: PciCfg2.c 프로젝트: bhanug/virtualbox
/**
  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;
}
예제 #10
0
파일: PciLib.c 프로젝트: hsienchieh/uefilab
/**
  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);
}
예제 #11
0
파일: PciSegmentLib.c 프로젝트: lersek/edk2
/**
  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);
}
예제 #12
0
파일: pciio.c 프로젝트: Fadekraft/MollenOS
/* 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);
	}
}
예제 #13
0
파일: Platform.c 프로젝트: OznOg/edk2
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
    );
}
예제 #14
0
파일: PciLib.c 프로젝트: hsienchieh/uefilab
/**
  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)
           );
}
예제 #15
0
파일: PciLib.c 프로젝트: hsienchieh/uefilab
/**
  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)
           );
}
예제 #16
0
/**
  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;
}
예제 #17
0
파일: Platform.c 프로젝트: OznOg/edk2
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 ();
  }
}
예제 #18
0
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;
}
예제 #19
0
/**
  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;
예제 #20
0
파일: PciLib.c 프로젝트: hsienchieh/uefilab
/**
  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;
}
예제 #21
0
/**
  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);
}
예제 #22
0
/* 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);
		}
	}
}
예제 #23
0
/** 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);
  }
}
예제 #24
0
/**
  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;
}