]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Omap35xxPkg/PciEmulation/PciEmulation.c
Moving OMAP 3530 code out of BeagleBoard package into its own package
[mirror_edk2.git] / Omap35xxPkg / PciEmulation / PciEmulation.c
diff --git a/Omap35xxPkg/PciEmulation/PciEmulation.c b/Omap35xxPkg/PciEmulation/PciEmulation.c
new file mode 100644 (file)
index 0000000..fa44570
--- /dev/null
@@ -0,0 +1,578 @@
+/** @file
+
+  Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+  
+  All rights reserved. This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciEmulation.h"
+#include <Omap3530/Omap3530.h>
+
+EFI_CPU_ARCH_PROTOCOL      *gCpu;
+EMBEDDED_EXTERNAL_DEVICE   *gTPS65950;
+
+#define HOST_CONTROLLER_OPERATION_REG_SIZE  0x44
+
+typedef struct {
+  ACPI_HID_DEVICE_PATH      AcpiDevicePath;
+  PCI_DEVICE_PATH           PciDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  EndDevicePath;
+} EFI_PCI_IO_DEVICE_PATH;
+
+typedef struct {
+  UINT32                  Signature;
+  EFI_PCI_IO_DEVICE_PATH  DevicePath;
+  EFI_PCI_IO_PROTOCOL     PciIoProtocol;
+  PCI_TYPE00              *ConfigSpace;
+  PCI_ROOT_BRIDGE         RootBridge;
+  UINTN                   Segment;
+} EFI_PCI_IO_PRIVATE_DATA;
+
+#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE     SIGNATURE_32('p', 'c', 'i', 'o')
+#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a)  CR(a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
+
+EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = 
+{
+  {
+    { ACPI_DEVICE_PATH, ACPI_DP, sizeof (ACPI_HID_DEVICE_PATH), 0},
+    EISA_PNP_ID(0x0A03),  // HID
+    0                     // UID
+  },
+  {
+    { HARDWARE_DEVICE_PATH, HW_PCI_DP, sizeof (PCI_DEVICE_PATH), 0},
+    0,
+    0
+  },
+  { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
+};
+
+STATIC
+VOID
+ConfigureUSBHost (
+  VOID
+  )
+{
+  EFI_STATUS Status;
+  UINT8      Data = 0;
+
+  // Take USB host out of force-standby mode
+  MmioWrite32(UHH_SYSCONFIG, UHH_SYSCONFIG_MIDLEMODE_NO_STANDBY
+                             | UHH_SYSCONFIG_CLOCKACTIVITY_ON
+                             | UHH_SYSCONFIG_SIDLEMODE_NO_STANDBY
+                             | UHH_SYSCONFIG_ENAWAKEUP_ENABLE    
+                             | UHH_SYSCONFIG_AUTOIDLE_ALWAYS_RUN);
+  MmioWrite32(UHH_HOSTCONFIG, UHH_HOSTCONFIG_P3_CONNECT_STATUS_DISCONNECT
+                              | UHH_HOSTCONFIG_P2_CONNECT_STATUS_DISCONNECT
+                              | UHH_HOSTCONFIG_P1_CONNECT_STATUS_DISCONNECT
+                              | UHH_HOSTCONFIG_ENA_INCR_ALIGN_DISABLE      
+                              | UHH_HOSTCONFIG_ENA_INCR16_ENABLE           
+                              | UHH_HOSTCONFIG_ENA_INCR8_ENABLE            
+                              | UHH_HOSTCONFIG_ENA_INCR4_ENABLE            
+                              | UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN_ON    
+                              | UHH_HOSTCONFIG_P1_ULPI_BYPASS_ULPI_MODE);
+
+  // USB reset (GPIO 147 - Port 5 pin 19) output high
+  MmioAnd32(GPIO5_BASE + GPIO_OE, ~BIT19);
+  MmioWrite32(GPIO5_BASE + GPIO_SETDATAOUT, BIT19);
+
+  // Get the Power IC protocol.
+  Status = gBS->LocateProtocol(&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
+  ASSERT_EFI_ERROR(Status);
+
+  //Enable power to the USB host.
+  Status = gTPS65950->Read(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+
+  //LEDAON & LEDAPWM control the power to the USB host so enable those bits.
+  Data |= (LEDAON | LEDAPWM);
+
+  Status = gTPS65950->Write(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+}
+
+EFI_STATUS
+PciIoPollMem (
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN  UINT8                        BarIndex,
+  IN  UINT64                       Offset,
+  IN  UINT64                       Mask,
+  IN  UINT64                       Value,
+  IN  UINT64                       Delay,
+  OUT UINT64                       *Result
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+PciIoPollIo (
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN  UINT8                        BarIndex,
+  IN  UINT64                       Offset,
+  IN  UINT64                       Mask,
+  IN  UINT64                       Value,
+  IN  UINT64                       Delay,
+  OUT UINT64                       *Result
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+PciIoMemRead (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT8                        BarIndex,
+  IN     UINT64                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+
+  return PciRootBridgeIoMemRead (&Private->RootBridge.Io, 
+                                (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+                                Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
+                                Count,
+                                Buffer
+                                );
+}
+
+EFI_STATUS
+PciIoMemWrite (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT8                        BarIndex,
+  IN     UINT64                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+
+  return PciRootBridgeIoMemWrite (&Private->RootBridge.Io, 
+                                 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
+                                 Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
+                                 Count,
+                                 Buffer
+                                 );
+}
+
+EFI_STATUS
+PciIoIoRead (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT8                        BarIndex,
+  IN     UINT64                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+PciIoIoWrite (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT8                        BarIndex,
+  IN     UINT64                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+PciIoPciRead (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT32                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+
+  return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, 
+                               Count, 
+                               TRUE, 
+                               (PTR)(UINTN)Buffer, 
+                               TRUE, 
+                               (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)
+                              );
+}
+
+EFI_STATUS
+PciIoPciWrite (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT32                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+
+  return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, 
+                               Count, 
+                               TRUE, 
+                               (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset), 
+                               TRUE, 
+                               (PTR)(UINTN)Buffer
+                               );
+}
+
+EFI_STATUS
+PciIoCopyMem (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINT8                        DestBarIndex,
+  IN     UINT64                       DestOffset,
+  IN     UINT8                        SrcBarIndex,
+  IN     UINT64                       SrcOffset,
+  IN     UINTN                        Count
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+PciIoMap (
+  IN EFI_PCI_IO_PROTOCOL                *This,
+  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
+  IN     VOID                           *HostAddress,
+  IN OUT UINTN                          *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
+  OUT    VOID                           **Mapping
+  )
+{
+  MAP_INFO_INSTANCE     *Map;
+  EFI_STATUS            Status;
+
+  if ( HostAddress == NULL || NumberOfBytes == NULL || 
+       DeviceAddress == NULL || Mapping == NULL ) {
+    
+    return EFI_INVALID_PARAMETER;
+  }
+  
+
+  if (Operation >= EfiPciOperationMaximum) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DeviceAddress = ConvertToPhysicalAddress (HostAddress);
+
+  // Data cache flush (HostAddress, NumberOfBytes);
+
+  // Remember range so we can flush on the other side
+  Status = gBS->AllocatePool (EfiBootServicesData, sizeof (PCI_DMA_MAP), (VOID **) &Map);
+  if (EFI_ERROR(Status)) {
+    return  EFI_OUT_OF_RESOURCES;
+  }
+  
+  *Mapping = Map;
+
+  Map->HostAddress   = (UINTN)HostAddress;
+  Map->DeviceAddress = *DeviceAddress;
+  Map->NumberOfBytes = *NumberOfBytes;
+  Map->Operation     = Operation;
+
+  // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate
+  gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);
+  
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PciIoUnmap (
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  VOID                         *Mapping
+  )
+{
+  PCI_DMA_MAP *Map;
+  
+  if (Mapping == NULL) {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  
+  Map = (PCI_DMA_MAP *)Mapping;
+  if (Map->Operation == EfiPciOperationBusMasterWrite) {
+    //
+    // Make sure we read buffer from uncached memory and not the cache
+    //
+    gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);
+  } 
+  
+  FreePool (Map);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PciIoAllocateBuffer (
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  EFI_ALLOCATE_TYPE            Type,
+  IN  EFI_MEMORY_TYPE              MemoryType,
+  IN  UINTN                        Pages,
+  OUT VOID                         **HostAddress,
+  IN  UINT64                       Attributes
+  )
+{
+  if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (HostAddress == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
+  //
+  // We used uncached memory to keep coherency
+  //
+  if (MemoryType == EfiBootServicesData) {
+    *HostAddress = UncachedAllocatePages (Pages);
+  } else if (MemoryType != EfiRuntimeServicesData) {
+    *HostAddress = UncachedAllocateRuntimePages (Pages);
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PciIoFreeBuffer (
+  IN EFI_PCI_IO_PROTOCOL           *This,
+  IN  UINTN                        Pages,
+  IN  VOID                         *HostAddress
+  )
+{
+  if (HostAddress == NULL) {
+     return EFI_INVALID_PARAMETER;
+  } 
+  
+  UncachedFreePages (HostAddress, Pages);
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+PciIoFlush (
+  IN EFI_PCI_IO_PROTOCOL  *This
+  )
+{
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PciIoGetLocation (
+  IN EFI_PCI_IO_PROTOCOL          *This,
+  OUT UINTN                       *SegmentNumber,
+  OUT UINTN                       *BusNumber,
+  OUT UINTN                       *DeviceNumber,
+  OUT UINTN                       *FunctionNumber
+  )
+{
+  EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+
+  if (SegmentNumber != NULL) {
+    *SegmentNumber = Private->Segment;
+  }
+
+  if (BusNumber != NULL) {
+    *BusNumber = 0xff;
+  }
+
+  if (DeviceNumber != NULL) {
+    *DeviceNumber = 0;
+  }
+
+  if (FunctionNumber != NULL) {
+    *FunctionNumber = 0;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PciIoAttributes (
+  IN EFI_PCI_IO_PROTOCOL                       *This,
+  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
+  IN  UINT64                                   Attributes,
+  OUT UINT64                                   *Result OPTIONAL
+  )
+{
+  switch (Operation) {
+  case EfiPciIoAttributeOperationGet:
+  case EfiPciIoAttributeOperationSupported:
+    if (Result == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    // We are not a real PCI device so just say things we kind of do
+    *Result = EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_DEVICE_ENABLE;
+    break;
+
+  case EfiPciIoAttributeOperationSet:
+  case EfiPciIoAttributeOperationEnable:
+  case EfiPciIoAttributeOperationDisable:
+    // Since we are not a real PCI device no enable/set or disable operations exist.
+    return EFI_SUCCESS;
+    
+  default:
+  ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  };
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PciIoGetBarAttributes (
+  IN EFI_PCI_IO_PROTOCOL             *This,
+  IN  UINT8                          BarIndex,
+  OUT UINT64                         *Supports, OPTIONAL
+  OUT VOID                           **Resources OPTIONAL
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+PciIoSetBarAttributes (
+  IN EFI_PCI_IO_PROTOCOL              *This,
+  IN     UINT64                       Attributes,
+  IN     UINT8                        BarIndex,
+  IN OUT UINT64                       *Offset,
+  IN OUT UINT64                       *Length
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+EFI_PCI_IO_PROTOCOL PciIoTemplate = 
+{
+  PciIoPollMem,
+  PciIoPollIo,
+  PciIoMemRead,
+  PciIoMemWrite,
+  PciIoIoRead,
+  PciIoIoWrite,
+  PciIoPciRead,
+  PciIoPciWrite,
+  PciIoCopyMem,
+  PciIoMap,
+  PciIoUnmap,
+  PciIoAllocateBuffer,
+  PciIoFreeBuffer,
+  PciIoFlush,
+  PciIoGetLocation,
+  PciIoAttributes,
+  PciIoGetBarAttributes,
+  PciIoSetBarAttributes,
+  0,
+  0
+};
+
+EFI_STATUS
+EFIAPI
+PciEmulationEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS              Status;
+  EFI_HANDLE              Handle;
+  EFI_PCI_IO_PRIVATE_DATA *Private;
+  UINT8                   CapabilityLength;
+  UINT8                   PhysicalPorts;
+  UINTN                   Count;
+
+  // Get the Cpu protocol for later use
+  Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
+  ASSERT_EFI_ERROR(Status);
+
+  //Configure USB host for OMAP3530.
+  ConfigureUSBHost();
+
+  // Create a private structure
+  Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
+  if (Private == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    return Status;
+  }
+  
+  Private->Signature              = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE;  // Fill in signature
+  Private->RootBridge.Signature   = PCI_ROOT_BRIDGE_SIGNATURE;          // Fake Root Bridge structure needs a signature too
+  Private->RootBridge.MemoryStart = USB_EHCI_HCCAPBASE;                 // Get the USB capability register base
+  Private->Segment                = 0;                                  // Default to segment zero
+
+  // Find out the capability register length and number of physical ports.
+  CapabilityLength = MmioRead8(Private->RootBridge.MemoryStart);
+  PhysicalPorts    = (MmioRead32(Private->RootBridge.MemoryStart + 0x4)) & 0x0000000F;
+
+  // Calculate the total size of the USB registers.
+  Private->RootBridge.MemorySize = CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));
+
+  // Enable Port Power bit in Port status and control registers in EHCI register space.
+  // Port Power Control (PPC) bit in the HCSPARAMS register is already set which indicates
+  // host controller implementation includes port power control.
+  for (Count = 0; Count < PhysicalPorts; Count++) {
+    MmioOr32((Private->RootBridge.MemoryStart + CapabilityLength + HOST_CONTROLLER_OPERATION_REG_SIZE + 4*Count), 0x00001000);
+  }
+
+  // Create fake PCI config space.
+  Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
+  if (Private->ConfigSpace == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    FreePool(Private);
+    return Status;
+  }
+
+  // Configure PCI config space
+  Private->ConfigSpace->Hdr.VendorId = 0x3530;
+  Private->ConfigSpace->Hdr.DeviceId = 0x3530;
+  Private->ConfigSpace->Hdr.ClassCode[0] = 0x20;
+  Private->ConfigSpace->Hdr.ClassCode[1] = 0x03;
+  Private->ConfigSpace->Hdr.ClassCode[2] = 0x0C;
+  Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
+
+  Handle = NULL;
+
+  // Unique device path.
+  CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
+  Private->DevicePath.AcpiDevicePath.UID = 0;
+  
+  // Copy protocol structure
+  CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
+
+  Status = gBS->InstallMultipleProtocolInterfaces(&Handle,
+                                                  &gEfiPciIoProtocolGuid,       &Private->PciIoProtocol,
+                                                  &gEfiDevicePathProtocolGuid,  &Private->DevicePath,
+                                                  NULL);
+  if (EFI_ERROR(Status)) {
+    DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n"));
+  }
+
+  return Status;
+}
+