--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ Copyright (c) 2013 - 2014, ARM Ltd. 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
+#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
+}\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, //Fix me ConfigSpace\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, //Fix me ConfigSpace\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
+ EFI_STATUS Status;\r
+\r
+ Status = 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) //Fix me ConfigSpace\r
+ );\r
+ return Status;\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), //Fix me ConfigSpace\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, PciIoMemWrite },\r
+ { PciIoIoRead, PciIoIoWrite },\r
+ { PciIoPciRead, 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
+PciInstallDevice (\r
+ IN UINTN DeviceId,\r
+ IN PHYSICAL_ADDRESS MemoryStart,\r
+ IN UINT64 MemorySize,\r
+ IN UINTN ClassCode1,\r
+ IN UINTN ClassCode2,\r
+ IN UINTN ClassCode3\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+ EFI_PCI_IO_PRIVATE_DATA *Private;\r
+\r
+ // Configure USB host\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 = MemoryStart; // Get the USB capability register base\r
+ Private->Segment = 0; // Default to segment zero\r
+\r
+ // Calculate the total size of the USB controller (OHCI + EHCI).\r
+ Private->RootBridge.MemorySize = MemorySize; //CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));\r
+\r
+ // Create fake PCI config space: OHCI + EHCI\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
+ //\r
+ // Configure PCI config space: OHCI + EHCI\r
+ //\r
+ Private->ConfigSpace->Hdr.VendorId = 0x3530; //TODO: Define one\r
+ Private->ConfigSpace->Hdr.DeviceId = 0x3530; //TODO: Define one\r
+ Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1;\r
+ Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2;\r
+ Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3;\r
+ Private->ConfigSpace->Device.Bar[0] = MemoryStart;\r
+\r
+ Handle = NULL;\r
+\r
+ // Unique device path.\r
+ CopyMem (&Private->DevicePath, &PciIoDevicePathTemplate, sizeof (PciIoDevicePathTemplate));\r
+ Private->DevicePath.AcpiDevicePath.UID = 0;\r
+ Private->DevicePath.PciDevicePath.Device = DeviceId;\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
+EFI_STATUS\r
+PciEmulationEntryPoint (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = PciInstallDevice (0, FixedPcdGet32 (PcdSynopsysUsbOhciBaseAddress), SIZE_64KB, PCI_IF_OHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install OHCI device.\n"));\r
+ }\r
+\r
+ Status = PciInstallDevice (1, FixedPcdGet32 (PcdSynopsysUsbEhciBaseAddress), SIZE_64KB, PCI_IF_EHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install EHCI device.\n"));\r
+ }\r
+\r
+ return Status;\r
+}\r