-/** @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;
-
-#if 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);
-#else
- // 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);
-
- // USB reset (GPIO 147 - Port 5 pin 19) output low
- MmioAnd32 (GPIO5_BASE + GPIO_OE, ~BIT19);
- MmioWrite32 (GPIO5_BASE + GPIO_CLEARDATAOUT, BIT19);
-
- // Turn on functional & interface clocks to the USBHOST power domain
- MmioOr32 (CM_FCLKEN_USBHOST, CM_FCLKEN_USBHOST_EN_USBHOST2_ENABLE | CM_FCLKEN_USBHOST_EN_USBHOST1_ENABLE);
- MmioOr32 (CM_ICLKEN_USBHOST, CM_ICLKEN_USBHOST_EN_USBHOST_ENABLE);
- // Wait for clock to become active
- while (0 == (MmioRead32 (CM_CLKSTST_USBHOST) & 1));
-
-
-
- // Take USB host out of force-standby mode
- MmioWrite32 (UHH_SYSCONFIG, UHH_SYSCONFIG_MIDLEMODE_NO_STANDBY
- | UHH_SYSCONFIG_CLOCKACTIVITY_ON
- | UHH_SYSCONFIG_ENAWAKEUP_ENABLE
- | UHH_SYSCONFIG_SOFTRESET
- );
- while ((MmioRead32 (UHH_SYSSTATUS) & UHH_SYSSTATUS_RESETDONE) != UHH_SYSSTATUS_RESETDONE);
-
- MmioWrite32 (UHH_SYSCONFIG, UHH_SYSCONFIG_CLOCKACTIVITY_ON
- | UHH_SYSCONFIG_SIDLEMODE_NO_STANDBY
- | UHH_SYSCONFIG_ENAWAKEUP_ENABLE
- );
-
-
- MmioWrite32 (UHH_HOSTCONFIG, UHH_HOSTCONFIG_ENA_INCR16_ENABLE
- | UHH_HOSTCONFIG_ENA_INCR8_ENABLE
- | UHH_HOSTCONFIG_ENA_INCR4_ENABLE
- );
-
- // USB reset output high
- MmioWrite32 (GPIO5_BASE + GPIO_SETDATAOUT, BIT19);
-
-#endif
-}
-
-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;
-}
-
+/** @file\r
+\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ \r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PciEmulation.h"\r
+\r
+EMBEDDED_EXTERNAL_DEVICE *gTPS65950;\r
+\r
+#define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44\r
+\r
+typedef struct {\r
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;\r
+ PCI_DEVICE_PATH PciDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
+} EFI_PCI_IO_DEVICE_PATH;\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ EFI_PCI_IO_DEVICE_PATH DevicePath;\r
+ EFI_PCI_IO_PROTOCOL PciIoProtocol;\r
+ PCI_TYPE00 *ConfigSpace;\r
+ PCI_ROOT_BRIDGE RootBridge;\r
+ UINTN Segment;\r
+} EFI_PCI_IO_PRIVATE_DATA;\r
+\r
+#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o')\r
+#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)\r
+\r
+EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = \r
+{\r
+ {\r
+ { ACPI_DEVICE_PATH, ACPI_DP, sizeof (ACPI_HID_DEVICE_PATH), 0},\r
+ EISA_PNP_ID(0x0A03), // HID\r
+ 0 // UID\r
+ },\r
+ {\r
+ { HARDWARE_DEVICE_PATH, HW_PCI_DP, sizeof (PCI_DEVICE_PATH), 0},\r
+ 0,\r
+ 0\r
+ },\r
+ { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}\r
+};\r
+\r
+STATIC\r
+VOID\r
+ConfigureUSBHost (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Data = 0;\r
+\r
+ // Take USB host out of force-standby mode\r
+ MmioWrite32 (UHH_SYSCONFIG, UHH_SYSCONFIG_MIDLEMODE_NO_STANDBY\r
+ | UHH_SYSCONFIG_CLOCKACTIVITY_ON\r
+ | UHH_SYSCONFIG_SIDLEMODE_NO_STANDBY\r
+ | UHH_SYSCONFIG_ENAWAKEUP_ENABLE\r
+ | UHH_SYSCONFIG_AUTOIDLE_ALWAYS_RUN);\r
+ MmioWrite32 (UHH_HOSTCONFIG, UHH_HOSTCONFIG_P3_CONNECT_STATUS_DISCONNECT\r
+ | UHH_HOSTCONFIG_P2_CONNECT_STATUS_DISCONNECT\r
+ | UHH_HOSTCONFIG_P1_CONNECT_STATUS_DISCONNECT\r
+ | UHH_HOSTCONFIG_ENA_INCR_ALIGN_DISABLE\r
+ | UHH_HOSTCONFIG_ENA_INCR16_ENABLE\r
+ | UHH_HOSTCONFIG_ENA_INCR8_ENABLE\r
+ | UHH_HOSTCONFIG_ENA_INCR4_ENABLE\r
+ | UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN_ON\r
+ | UHH_HOSTCONFIG_P1_ULPI_BYPASS_ULPI_MODE);\r
+\r
+ // USB reset (GPIO 147 - Port 5 pin 19) output high\r
+ MmioAnd32 (GPIO5_BASE + GPIO_OE, ~BIT19);\r
+ MmioWrite32 (GPIO5_BASE + GPIO_SETDATAOUT, BIT19);\r
+\r
+ // Get the Power IC protocol\r
+ Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);\r
+ ASSERT_EFI_ERROR (Status); \r
+\r
+ // Power the USB PHY\r
+ Data = VAUX_DEV_GRP_P1;\r
+ Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VAUX2_DEV_GRP), 1, &Data);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ Data = VAUX_DEDICATED_18V;\r
+ Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VAUX2_DEDICATED), 1, &Data);\r
+ ASSERT_EFI_ERROR (Status); \r
+\r
+ // Enable power to the USB hub\r
+ Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // LEDAON controls the power to the USB host, PWM is disabled\r
+ Data &= ~LEDAPWM;\r
+ Data |= LEDAON;\r
+\r
+ Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+PciIoPollMem (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINT64 Mask,\r
+ IN UINT64 Value,\r
+ IN UINT64 Delay,\r
+ OUT UINT64 *Result\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoPollIo (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINT64 Mask,\r
+ IN UINT64 Value,\r
+ IN UINT64 Delay,\r
+ OUT UINT64 *Result\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoMemRead (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);\r
+\r
+ return PciRootBridgeIoMemRead (&Private->RootBridge.Io, \r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Private->ConfigSpace->Device.Bar[BarIndex] + Offset,\r
+ Count,\r
+ Buffer\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+PciIoMemWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);\r
+\r
+ return PciRootBridgeIoMemWrite (&Private->RootBridge.Io, \r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Private->ConfigSpace->Device.Bar[BarIndex] + Offset,\r
+ Count,\r
+ Buffer\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+PciIoIoRead (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoIoWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoPciRead (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);\r
+\r
+ return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, \r
+ Count, \r
+ TRUE, \r
+ (PTR)(UINTN)Buffer, \r
+ TRUE, \r
+ (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+PciIoPciWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);\r
+\r
+ return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, \r
+ Count, \r
+ TRUE, \r
+ (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset), \r
+ TRUE, \r
+ (PTR)(UINTN)Buffer\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+PciIoCopyMem (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 DestBarIndex,\r
+ IN UINT64 DestOffset,\r
+ IN UINT8 SrcBarIndex,\r
+ IN UINT64 SrcOffset,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoMap (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ DMA_MAP_OPERATION DmaOperation;\r
+\r
+ if (Operation == EfiPciIoOperationBusMasterRead) {\r
+ DmaOperation = MapOperationBusMasterRead;\r
+ } else if (Operation == EfiPciIoOperationBusMasterWrite) {\r
+ DmaOperation = MapOperationBusMasterWrite;\r
+ } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
+ DmaOperation = MapOperationBusMasterCommonBuffer;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);\r
+}\r
+\r
+EFI_STATUS\r
+PciIoUnmap (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ return DmaUnmap (Mapping);\r
+}\r
+\r
+EFI_STATUS\r
+PciIoAllocateBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {\r
+ // Check this\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return DmaAllocateBuffer (MemoryType, Pages, HostAddress);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+PciIoFreeBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress\r
+ )\r
+{\r
+ return DmaFreeBuffer (Pages, HostAddress);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+PciIoFlush (\r
+ IN EFI_PCI_IO_PROTOCOL *This\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoGetLocation (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ OUT UINTN *SegmentNumber,\r
+ OUT UINTN *BusNumber,\r
+ OUT UINTN *DeviceNumber,\r
+ OUT UINTN *FunctionNumber\r
+ )\r
+{\r
+ EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);\r
+\r
+ if (SegmentNumber != NULL) {\r
+ *SegmentNumber = Private->Segment;\r
+ }\r
+\r
+ if (BusNumber != NULL) {\r
+ *BusNumber = 0xff;\r
+ }\r
+\r
+ if (DeviceNumber != NULL) {\r
+ *DeviceNumber = 0;\r
+ }\r
+\r
+ if (FunctionNumber != NULL) {\r
+ *FunctionNumber = 0;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoAttributes (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,\r
+ IN UINT64 Attributes,\r
+ OUT UINT64 *Result OPTIONAL\r
+ )\r
+{\r
+ switch (Operation) {\r
+ case EfiPciIoAttributeOperationGet:\r
+ case EfiPciIoAttributeOperationSupported:\r
+ if (Result == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ // We are not a real PCI device so just say things we kind of do\r
+ *Result = EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_DEVICE_ENABLE;\r
+ break;\r
+\r
+ case EfiPciIoAttributeOperationSet:\r
+ case EfiPciIoAttributeOperationEnable:\r
+ case EfiPciIoAttributeOperationDisable:\r
+ // Since we are not a real PCI device no enable/set or disable operations exist.\r
+ return EFI_SUCCESS;\r
+ \r
+ default:\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ };\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoGetBarAttributes (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN UINT8 BarIndex,\r
+ OUT UINT64 *Supports, OPTIONAL\r
+ OUT VOID **Resources OPTIONAL\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+PciIoSetBarAttributes (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN UINT64 Attributes,\r
+ IN UINT8 BarIndex,\r
+ IN OUT UINT64 *Offset,\r
+ IN OUT UINT64 *Length\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_PCI_IO_PROTOCOL PciIoTemplate = \r
+{\r
+ PciIoPollMem,\r
+ PciIoPollIo,\r
+ PciIoMemRead,\r
+ PciIoMemWrite,\r
+ PciIoIoRead,\r
+ PciIoIoWrite,\r
+ PciIoPciRead,\r
+ PciIoPciWrite,\r
+ PciIoCopyMem,\r
+ PciIoMap,\r
+ PciIoUnmap,\r
+ PciIoAllocateBuffer,\r
+ PciIoFreeBuffer,\r
+ PciIoFlush,\r
+ PciIoGetLocation,\r
+ PciIoAttributes,\r
+ PciIoGetBarAttributes,\r
+ PciIoSetBarAttributes,\r
+ 0,\r
+ 0\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PciEmulationEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+ EFI_PCI_IO_PRIVATE_DATA *Private;\r
+ UINT8 CapabilityLength;\r
+ UINT8 PhysicalPorts;\r
+ UINTN Count;\r
+\r
+\r
+ //Configure USB host for OMAP3530.\r
+ ConfigureUSBHost();\r
+\r
+ // Create a private structure\r
+ Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ return Status;\r
+ }\r
+ \r
+ Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature\r
+ Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too\r
+ Private->RootBridge.MemoryStart = USB_EHCI_HCCAPBASE; // Get the USB capability register base\r
+ Private->Segment = 0; // Default to segment zero\r
+\r
+ // Find out the capability register length and number of physical ports.\r
+ CapabilityLength = MmioRead8(Private->RootBridge.MemoryStart);\r
+ PhysicalPorts = (MmioRead32 (Private->RootBridge.MemoryStart + 0x4)) & 0x0000000F;\r
+\r
+ // Calculate the total size of the USB registers.\r
+ Private->RootBridge.MemorySize = CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));\r
+\r
+ // Enable Port Power bit in Port status and control registers in EHCI register space.\r
+ // Port Power Control (PPC) bit in the HCSPARAMS register is already set which indicates\r
+ // host controller implementation includes port power control.\r
+ for (Count = 0; Count < PhysicalPorts; Count++) {\r
+ MmioOr32 ((Private->RootBridge.MemoryStart + CapabilityLength + HOST_CONTROLLER_OPERATION_REG_SIZE + 4*Count), 0x00001000);\r
+ }\r
+\r
+ // Create fake PCI config space.\r
+ Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));\r
+ if (Private->ConfigSpace == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ FreePool(Private);\r
+ return Status;\r
+ }\r
+\r
+ // Configure PCI config space\r
+ Private->ConfigSpace->Hdr.VendorId = 0x3530;\r
+ Private->ConfigSpace->Hdr.DeviceId = 0x3530;\r
+ Private->ConfigSpace->Hdr.ClassCode[0] = 0x20;\r
+ Private->ConfigSpace->Hdr.ClassCode[1] = 0x03;\r
+ Private->ConfigSpace->Hdr.ClassCode[2] = 0x0C;\r
+ Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;\r
+\r
+ Handle = NULL;\r
+\r
+ // Unique device path.\r
+ CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));\r
+ Private->DevicePath.AcpiDevicePath.UID = 0;\r
+ \r
+ // Copy protocol structure\r
+ CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces(&Handle,\r
+ &gEfiPciIoProtocolGuid, &Private->PciIoProtocol,\r
+ &gEfiDevicePathProtocolGuid, &Private->DevicePath,\r
+ NULL);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n"));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r