3 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PciEmulation.h"
16 #include <Omap3530/Omap3530.h>
18 EFI_CPU_ARCH_PROTOCOL
*gCpu
;
19 EMBEDDED_EXTERNAL_DEVICE
*gTPS65950
;
21 #define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44
24 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
25 PCI_DEVICE_PATH PciDevicePath
;
26 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
27 } EFI_PCI_IO_DEVICE_PATH
;
31 EFI_PCI_IO_DEVICE_PATH DevicePath
;
32 EFI_PCI_IO_PROTOCOL PciIoProtocol
;
33 PCI_TYPE00
*ConfigSpace
;
34 PCI_ROOT_BRIDGE RootBridge
;
36 } EFI_PCI_IO_PRIVATE_DATA
;
38 #define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o')
39 #define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
41 EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate
=
44 { ACPI_DEVICE_PATH
, ACPI_DP
, sizeof (ACPI_HID_DEVICE_PATH
), 0},
45 EISA_PNP_ID(0x0A03), // HID
49 { HARDWARE_DEVICE_PATH
, HW_PCI_DP
, sizeof (PCI_DEVICE_PATH
), 0},
53 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0}
66 // Take USB host out of force-standby mode
67 MmioWrite32 (UHH_SYSCONFIG
, UHH_SYSCONFIG_MIDLEMODE_NO_STANDBY
68 | UHH_SYSCONFIG_CLOCKACTIVITY_ON
69 | UHH_SYSCONFIG_SIDLEMODE_NO_STANDBY
70 | UHH_SYSCONFIG_ENAWAKEUP_ENABLE
71 | UHH_SYSCONFIG_AUTOIDLE_ALWAYS_RUN
);
72 MmioWrite32 (UHH_HOSTCONFIG
, UHH_HOSTCONFIG_P3_CONNECT_STATUS_DISCONNECT
73 | UHH_HOSTCONFIG_P2_CONNECT_STATUS_DISCONNECT
74 | UHH_HOSTCONFIG_P1_CONNECT_STATUS_DISCONNECT
75 | UHH_HOSTCONFIG_ENA_INCR_ALIGN_DISABLE
76 | UHH_HOSTCONFIG_ENA_INCR16_ENABLE
77 | UHH_HOSTCONFIG_ENA_INCR8_ENABLE
78 | UHH_HOSTCONFIG_ENA_INCR4_ENABLE
79 | UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN_ON
80 | UHH_HOSTCONFIG_P1_ULPI_BYPASS_ULPI_MODE
);
82 // USB reset (GPIO 147 - Port 5 pin 19) output high
83 MmioAnd32(GPIO5_BASE
+ GPIO_OE
, ~BIT19
);
84 MmioWrite32 (GPIO5_BASE
+ GPIO_SETDATAOUT
, BIT19
);
86 // Get the Power IC protocol.
87 Status
= gBS
->LocateProtocol(&gEmbeddedExternalDeviceProtocolGuid
, NULL
, (VOID
**)&gTPS65950
);
88 ASSERT_EFI_ERROR(Status
);
90 //Enable power to the USB host.
91 Status
= gTPS65950
->Read(gTPS65950
, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3
, LEDEN
), 1, &Data
);
92 ASSERT_EFI_ERROR(Status
);
94 //LEDAON & LEDAPWM control the power to the USB host so enable those bits.
95 Data
|= (LEDAON
| LEDAPWM
);
97 Status
= gTPS65950
->Write(gTPS65950
, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3
, LEDEN
), 1, &Data
);
98 ASSERT_EFI_ERROR(Status
);
100 // Get the Power IC protocol.
101 Status
= gBS
->LocateProtocol(&gEmbeddedExternalDeviceProtocolGuid
, NULL
, (VOID
**)&gTPS65950
);
102 ASSERT_EFI_ERROR(Status
);
104 //Enable power to the USB host.
105 Status
= gTPS65950
->Read(gTPS65950
, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3
, LEDEN
), 1, &Data
);
106 ASSERT_EFI_ERROR(Status
);
108 //LEDAON & LEDAPWM control the power to the USB host so enable those bits.
109 Data
|= (LEDAON
| LEDAPWM
);
111 Status
= gTPS65950
->Write(gTPS65950
, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3
, LEDEN
), 1, &Data
);
112 ASSERT_EFI_ERROR(Status
);
114 // USB reset (GPIO 147 - Port 5 pin 19) output low
115 MmioAnd32 (GPIO5_BASE
+ GPIO_OE
, ~BIT19
);
116 MmioWrite32 (GPIO5_BASE
+ GPIO_CLEARDATAOUT
, BIT19
);
118 // Turn on functional & interface clocks to the USBHOST power domain
119 MmioOr32 (CM_FCLKEN_USBHOST
, CM_FCLKEN_USBHOST_EN_USBHOST2_ENABLE
| CM_FCLKEN_USBHOST_EN_USBHOST1_ENABLE
);
120 MmioOr32 (CM_ICLKEN_USBHOST
, CM_ICLKEN_USBHOST_EN_USBHOST_ENABLE
);
121 // Wait for clock to become active
122 while (0 == (MmioRead32 (CM_CLKSTST_USBHOST
) & 1));
126 // Take USB host out of force-standby mode
127 MmioWrite32 (UHH_SYSCONFIG
, UHH_SYSCONFIG_MIDLEMODE_NO_STANDBY
128 | UHH_SYSCONFIG_CLOCKACTIVITY_ON
129 | UHH_SYSCONFIG_ENAWAKEUP_ENABLE
130 | UHH_SYSCONFIG_SOFTRESET
132 while ((MmioRead32 (UHH_SYSSTATUS
) & UHH_SYSSTATUS_RESETDONE
) != UHH_SYSSTATUS_RESETDONE
);
134 MmioWrite32 (UHH_SYSCONFIG
, UHH_SYSCONFIG_CLOCKACTIVITY_ON
135 | UHH_SYSCONFIG_SIDLEMODE_NO_STANDBY
136 | UHH_SYSCONFIG_ENAWAKEUP_ENABLE
140 MmioWrite32 (UHH_HOSTCONFIG
, UHH_HOSTCONFIG_ENA_INCR16_ENABLE
141 | UHH_HOSTCONFIG_ENA_INCR8_ENABLE
142 | UHH_HOSTCONFIG_ENA_INCR4_ENABLE
145 // USB reset output high
146 MmioWrite32 (GPIO5_BASE
+ GPIO_SETDATAOUT
, BIT19
);
153 IN EFI_PCI_IO_PROTOCOL
*This
,
154 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
164 return EFI_UNSUPPORTED
;
169 IN EFI_PCI_IO_PROTOCOL
*This
,
170 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
180 return EFI_UNSUPPORTED
;
185 IN EFI_PCI_IO_PROTOCOL
*This
,
186 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
193 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This
);
195 return PciRootBridgeIoMemRead (&Private
->RootBridge
.Io
,
196 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
197 Private
->ConfigSpace
->Device
.Bar
[BarIndex
] + Offset
,
205 IN EFI_PCI_IO_PROTOCOL
*This
,
206 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
213 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This
);
215 return PciRootBridgeIoMemWrite (&Private
->RootBridge
.Io
,
216 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
217 Private
->ConfigSpace
->Device
.Bar
[BarIndex
] + Offset
,
225 IN EFI_PCI_IO_PROTOCOL
*This
,
226 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
234 return EFI_UNSUPPORTED
;
239 IN EFI_PCI_IO_PROTOCOL
*This
,
240 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
248 return EFI_UNSUPPORTED
;
253 IN EFI_PCI_IO_PROTOCOL
*This
,
254 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
260 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This
);
262 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
)Width
,
267 (PTR
)(UINTN
)(((UINT8
*)Private
->ConfigSpace
) + Offset
)
273 IN EFI_PCI_IO_PROTOCOL
*This
,
274 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
280 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This
);
282 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
285 (PTR
)(UINTN
)(((UINT8
*)Private
->ConfigSpace
) + Offset
),
293 IN EFI_PCI_IO_PROTOCOL
*This
,
294 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
295 IN UINT8 DestBarIndex
,
296 IN UINT64 DestOffset
,
297 IN UINT8 SrcBarIndex
,
303 return EFI_UNSUPPORTED
;
308 IN EFI_PCI_IO_PROTOCOL
*This
,
309 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation
,
310 IN VOID
*HostAddress
,
311 IN OUT UINTN
*NumberOfBytes
,
312 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
316 MAP_INFO_INSTANCE
*Map
;
319 if ( HostAddress
== NULL
|| NumberOfBytes
== NULL
||
320 DeviceAddress
== NULL
|| Mapping
== NULL
) {
322 return EFI_INVALID_PARAMETER
;
326 if (Operation
>= EfiPciOperationMaximum
) {
327 return EFI_INVALID_PARAMETER
;
330 *DeviceAddress
= ConvertToPhysicalAddress (HostAddress
);
332 // Data cache flush (HostAddress, NumberOfBytes);
334 // Remember range so we can flush on the other side
335 Status
= gBS
->AllocatePool (EfiBootServicesData
, sizeof (PCI_DMA_MAP
), (VOID
**) &Map
);
336 if (EFI_ERROR(Status
)) {
337 return EFI_OUT_OF_RESOURCES
;
342 Map
->HostAddress
= (UINTN
)HostAddress
;
343 Map
->DeviceAddress
= *DeviceAddress
;
344 Map
->NumberOfBytes
= *NumberOfBytes
;
345 Map
->Operation
= Operation
;
347 // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate
348 gCpu
->FlushDataCache (gCpu
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
, *NumberOfBytes
, EfiCpuFlushTypeWriteBackInvalidate
);
355 IN EFI_PCI_IO_PROTOCOL
*This
,
361 if (Mapping
== NULL
) {
363 return EFI_INVALID_PARAMETER
;
366 Map
= (PCI_DMA_MAP
*)Mapping
;
367 if (Map
->Operation
== EfiPciOperationBusMasterWrite
) {
369 // Make sure we read buffer from uncached memory and not the cache
371 gCpu
->FlushDataCache (gCpu
, Map
->HostAddress
, Map
->NumberOfBytes
, EfiCpuFlushTypeInvalidate
);
380 PciIoAllocateBuffer (
381 IN EFI_PCI_IO_PROTOCOL
*This
,
382 IN EFI_ALLOCATE_TYPE Type
,
383 IN EFI_MEMORY_TYPE MemoryType
,
385 OUT VOID
**HostAddress
,
389 if (Attributes
& EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER
) {
390 return EFI_UNSUPPORTED
;
393 if (HostAddress
== NULL
) {
394 return EFI_INVALID_PARAMETER
;
398 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
400 // We used uncached memory to keep coherency
402 if (MemoryType
== EfiBootServicesData
) {
403 *HostAddress
= UncachedAllocatePages (Pages
);
404 } else if (MemoryType
!= EfiRuntimeServicesData
) {
405 *HostAddress
= UncachedAllocateRuntimePages (Pages
);
407 return EFI_INVALID_PARAMETER
;
415 IN EFI_PCI_IO_PROTOCOL
*This
,
420 if (HostAddress
== NULL
) {
421 return EFI_INVALID_PARAMETER
;
424 UncachedFreePages (HostAddress
, Pages
);
431 IN EFI_PCI_IO_PROTOCOL
*This
439 IN EFI_PCI_IO_PROTOCOL
*This
,
440 OUT UINTN
*SegmentNumber
,
441 OUT UINTN
*BusNumber
,
442 OUT UINTN
*DeviceNumber
,
443 OUT UINTN
*FunctionNumber
446 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This
);
448 if (SegmentNumber
!= NULL
) {
449 *SegmentNumber
= Private
->Segment
;
452 if (BusNumber
!= NULL
) {
456 if (DeviceNumber
!= NULL
) {
460 if (FunctionNumber
!= NULL
) {
469 IN EFI_PCI_IO_PROTOCOL
*This
,
470 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
,
471 IN UINT64 Attributes
,
472 OUT UINT64
*Result OPTIONAL
476 case EfiPciIoAttributeOperationGet
:
477 case EfiPciIoAttributeOperationSupported
:
478 if (Result
== NULL
) {
479 return EFI_INVALID_PARAMETER
;
481 // We are not a real PCI device so just say things we kind of do
482 *Result
= EFI_PCI_IO_ATTRIBUTE_MEMORY
| EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
| EFI_PCI_DEVICE_ENABLE
;
485 case EfiPciIoAttributeOperationSet
:
486 case EfiPciIoAttributeOperationEnable
:
487 case EfiPciIoAttributeOperationDisable
:
488 // Since we are not a real PCI device no enable/set or disable operations exist.
493 return EFI_INVALID_PARAMETER
;
499 PciIoGetBarAttributes (
500 IN EFI_PCI_IO_PROTOCOL
*This
,
502 OUT UINT64
*Supports
, OPTIONAL
503 OUT VOID
**Resources OPTIONAL
507 return EFI_UNSUPPORTED
;
511 PciIoSetBarAttributes (
512 IN EFI_PCI_IO_PROTOCOL
*This
,
513 IN UINT64 Attributes
,
515 IN OUT UINT64
*Offset
,
516 IN OUT UINT64
*Length
520 return EFI_UNSUPPORTED
;
523 EFI_PCI_IO_PROTOCOL PciIoTemplate
=
541 PciIoGetBarAttributes
,
542 PciIoSetBarAttributes
,
549 PciEmulationEntryPoint (
550 IN EFI_HANDLE ImageHandle
,
551 IN EFI_SYSTEM_TABLE
*SystemTable
556 EFI_PCI_IO_PRIVATE_DATA
*Private
;
557 UINT8 CapabilityLength
;
561 // Get the Cpu protocol for later use
562 Status
= gBS
->LocateProtocol(&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**)&gCpu
);
563 ASSERT_EFI_ERROR(Status
);
565 //Configure USB host for OMAP3530.
568 // Create a private structure
569 Private
= AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA
));
570 if (Private
== NULL
) {
571 Status
= EFI_OUT_OF_RESOURCES
;
575 Private
->Signature
= EFI_PCI_IO_PRIVATE_DATA_SIGNATURE
; // Fill in signature
576 Private
->RootBridge
.Signature
= PCI_ROOT_BRIDGE_SIGNATURE
; // Fake Root Bridge structure needs a signature too
577 Private
->RootBridge
.MemoryStart
= USB_EHCI_HCCAPBASE
; // Get the USB capability register base
578 Private
->Segment
= 0; // Default to segment zero
580 // Find out the capability register length and number of physical ports.
581 CapabilityLength
= MmioRead8(Private
->RootBridge
.MemoryStart
);
582 PhysicalPorts
= (MmioRead32 (Private
->RootBridge
.MemoryStart
+ 0x4)) & 0x0000000F;
584 // Calculate the total size of the USB registers.
585 Private
->RootBridge
.MemorySize
= CapabilityLength
+ (HOST_CONTROLLER_OPERATION_REG_SIZE
+ ((4 * PhysicalPorts
) - 1));
587 // Enable Port Power bit in Port status and control registers in EHCI register space.
588 // Port Power Control (PPC) bit in the HCSPARAMS register is already set which indicates
589 // host controller implementation includes port power control.
590 for (Count
= 0; Count
< PhysicalPorts
; Count
++) {
591 MmioOr32 ((Private
->RootBridge
.MemoryStart
+ CapabilityLength
+ HOST_CONTROLLER_OPERATION_REG_SIZE
+ 4*Count
), 0x00001000);
594 // Create fake PCI config space.
595 Private
->ConfigSpace
= AllocateZeroPool(sizeof(PCI_TYPE00
));
596 if (Private
->ConfigSpace
== NULL
) {
597 Status
= EFI_OUT_OF_RESOURCES
;
602 // Configure PCI config space
603 Private
->ConfigSpace
->Hdr
.VendorId
= 0x3530;
604 Private
->ConfigSpace
->Hdr
.DeviceId
= 0x3530;
605 Private
->ConfigSpace
->Hdr
.ClassCode
[0] = 0x20;
606 Private
->ConfigSpace
->Hdr
.ClassCode
[1] = 0x03;
607 Private
->ConfigSpace
->Hdr
.ClassCode
[2] = 0x0C;
608 Private
->ConfigSpace
->Device
.Bar
[0] = Private
->RootBridge
.MemoryStart
;
612 // Unique device path.
613 CopyMem(&Private
->DevicePath
, &PciIoDevicePathTemplate
, sizeof(PciIoDevicePathTemplate
));
614 Private
->DevicePath
.AcpiDevicePath
.UID
= 0;
616 // Copy protocol structure
617 CopyMem(&Private
->PciIoProtocol
, &PciIoTemplate
, sizeof(PciIoTemplate
));
619 Status
= gBS
->InstallMultipleProtocolInterfaces(&Handle
,
620 &gEfiPciIoProtocolGuid
, &Private
->PciIoProtocol
,
621 &gEfiDevicePathProtocolGuid
, &Private
->DevicePath
,
623 if (EFI_ERROR(Status
)) {
624 DEBUG((EFI_D_ERROR
, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n"));