3 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
4 Copyright (c) 2013 - 2014, ARM Ltd. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PciEmulation.h"
18 #define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44
21 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
22 PCI_DEVICE_PATH PciDevicePath
;
23 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
24 } EFI_PCI_IO_DEVICE_PATH
;
28 EFI_PCI_IO_DEVICE_PATH DevicePath
;
29 EFI_PCI_IO_PROTOCOL PciIoProtocol
;
30 PCI_TYPE00
*ConfigSpace
;
31 PCI_ROOT_BRIDGE RootBridge
;
33 } EFI_PCI_IO_PRIVATE_DATA
;
35 #define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o')
36 #define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
38 EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate
=
41 { ACPI_DEVICE_PATH
, ACPI_DP
, { sizeof (ACPI_HID_DEVICE_PATH
), 0 } },
42 EISA_PNP_ID(0x0A03), // HID
46 { HARDWARE_DEVICE_PATH
, HW_PCI_DP
, { sizeof (PCI_DEVICE_PATH
), 0 } },
50 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0} }
64 IN EFI_PCI_IO_PROTOCOL
*This
,
65 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
75 return EFI_UNSUPPORTED
;
80 IN EFI_PCI_IO_PROTOCOL
*This
,
81 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
91 return EFI_UNSUPPORTED
;
96 IN EFI_PCI_IO_PROTOCOL
*This
,
97 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
104 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This
);
106 return PciRootBridgeIoMemRead (&Private
->RootBridge
.Io
,
107 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
108 Private
->ConfigSpace
->Device
.Bar
[BarIndex
] + Offset
, //Fix me ConfigSpace
116 IN EFI_PCI_IO_PROTOCOL
*This
,
117 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
124 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This
);
126 return PciRootBridgeIoMemWrite (&Private
->RootBridge
.Io
,
127 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
128 Private
->ConfigSpace
->Device
.Bar
[BarIndex
] + Offset
, //Fix me ConfigSpace
136 IN EFI_PCI_IO_PROTOCOL
*This
,
137 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
145 return EFI_UNSUPPORTED
;
150 IN EFI_PCI_IO_PROTOCOL
*This
,
151 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
159 return EFI_UNSUPPORTED
;
163 Enable a PCI driver to read PCI controller registers in PCI configuration space.
165 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
166 @param[in] Width Signifies the width of the memory operations.
167 @param[in] Offset The offset within the PCI configuration space for
169 @param[in] Count The number of PCI configuration operations to
170 perform. Bytes moved is Width size * Count,
173 @param[in out] Buffer The destination buffer to store the results.
175 @retval EFI_SUCCESS The data was read from the PCI controller.
176 @retval EFI_INVALID_PARAMETER "Width" is invalid.
177 @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
182 IN EFI_PCI_IO_PROTOCOL
*This
,
183 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
189 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This
);
192 if ((Width
< 0) || (Width
>= EfiPciIoWidthMaximum
) || (Buffer
== NULL
)) {
193 return EFI_INVALID_PARAMETER
;
196 Status
= PciRootBridgeIoMemRW (
197 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
)Width
,
202 (PTR
)(UINTN
)(((UINT8
*)Private
->ConfigSpace
) + Offset
) //Fix me ConfigSpace
209 Enable a PCI driver to write PCI controller registers in PCI configuration space.
211 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
212 @param[in] Width Signifies the width of the memory operations.
213 @param[in] Offset The offset within the PCI configuration space for
215 @param[in] Count The number of PCI configuration operations to
216 perform. Bytes moved is Width size * Count,
219 @param[in out] Buffer The source buffer to write data from.
221 @retval EFI_SUCCESS The data was read from the PCI controller.
222 @retval EFI_INVALID_PARAMETER "Width" is invalid.
223 @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
228 IN EFI_PCI_IO_PROTOCOL
*This
,
229 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
235 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This
);
237 if ((Width
< 0) || (Width
>= EfiPciIoWidthMaximum
) || (Buffer
== NULL
)) {
238 return EFI_INVALID_PARAMETER
;
241 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
244 (PTR
)(UINTN
)(((UINT8
*)Private
->ConfigSpace
) + Offset
), //Fix me ConfigSpace
252 IN EFI_PCI_IO_PROTOCOL
*This
,
253 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
254 IN UINT8 DestBarIndex
,
255 IN UINT64 DestOffset
,
256 IN UINT8 SrcBarIndex
,
262 return EFI_UNSUPPORTED
;
267 IN EFI_PCI_IO_PROTOCOL
*This
,
268 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation
,
269 IN VOID
*HostAddress
,
270 IN OUT UINTN
*NumberOfBytes
,
271 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
275 DMA_MAP_OPERATION DmaOperation
;
277 if (Operation
== EfiPciIoOperationBusMasterRead
) {
278 DmaOperation
= MapOperationBusMasterRead
;
279 } else if (Operation
== EfiPciIoOperationBusMasterWrite
) {
280 DmaOperation
= MapOperationBusMasterWrite
;
281 } else if (Operation
== EfiPciIoOperationBusMasterCommonBuffer
) {
282 DmaOperation
= MapOperationBusMasterCommonBuffer
;
284 return EFI_INVALID_PARAMETER
;
286 return DmaMap (DmaOperation
, HostAddress
, NumberOfBytes
, DeviceAddress
, Mapping
);
291 IN EFI_PCI_IO_PROTOCOL
*This
,
295 return DmaUnmap (Mapping
);
299 Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
302 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
303 @param[in] Type This parameter is not used and must be ignored.
304 @param[in] MemoryType The type of memory to allocate, EfiBootServicesData or
305 EfiRuntimeServicesData.
306 @param[in] Pages The number of pages to allocate.
307 @param[out] HostAddress A pointer to store the base system memory address of
309 @param[in] Attributes The requested bit mask of attributes for the allocated
310 range. Only the attributes,
311 EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and
312 EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with this
313 function. If any other bits are set, then EFI_UNSUPPORTED
314 is returned. This function ignores this bit mask.
316 @retval EFI_SUCCESS The requested memory pages were allocated.
317 @retval EFI_INVALID_PARAMETER HostAddress is NULL.
318 @retval EFI_INVALID_PARAMETER MemoryType is invalid.
319 @retval EFI_UNSUPPORTED Attributes is unsupported.
320 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
324 PciIoAllocateBuffer (
325 IN EFI_PCI_IO_PROTOCOL
*This
,
326 IN EFI_ALLOCATE_TYPE Type
,
327 IN EFI_MEMORY_TYPE MemoryType
,
329 OUT VOID
**HostAddress
,
334 (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE
|
335 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
))) {
336 return EFI_UNSUPPORTED
;
339 return DmaAllocateBuffer (MemoryType
, Pages
, HostAddress
);
345 IN EFI_PCI_IO_PROTOCOL
*This
,
350 return DmaFreeBuffer (Pages
, HostAddress
);
356 IN EFI_PCI_IO_PROTOCOL
*This
363 Retrieves this PCI controller's current PCI bus number, device number, and function number.
365 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
366 @param[out] SegmentNumber The PCI controller's current PCI segment number.
367 @param[out] BusNumber The PCI controller's current PCI bus number.
368 @param[out] DeviceNumber The PCI controller's current PCI device number.
369 @param[out] FunctionNumber The PCI controller’s current PCI function number.
371 @retval EFI_SUCCESS The PCI controller location was returned.
372 @retval EFI_INVALID_PARAMETER At least one out of the four output parameters is
377 IN EFI_PCI_IO_PROTOCOL
*This
,
378 OUT UINTN
*SegmentNumber
,
379 OUT UINTN
*BusNumber
,
380 OUT UINTN
*DeviceNumber
,
381 OUT UINTN
*FunctionNumber
384 EFI_PCI_IO_PRIVATE_DATA
*Private
= EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This
);
386 if ((SegmentNumber
== NULL
) || (BusNumber
== NULL
) ||
387 (DeviceNumber
== NULL
) || (FunctionNumber
== NULL
) ) {
388 return EFI_INVALID_PARAMETER
;
391 *SegmentNumber
= Private
->Segment
;
400 Performs an operation on the attributes that this PCI controller supports.
402 The operations include getting the set of supported attributes, retrieving
403 the current attributes, setting the current attributes, enabling attributes,
404 and disabling attributes.
406 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
407 @param[in] Operation The operation to perform on the attributes for this
409 @param[in] Attributes The mask of attributes that are used for Set,
410 Enable and Disable operations.
411 @param[out] Result A pointer to the result mask of attributes that are
412 returned for the Get and Supported operations. This
413 is an optional parameter that may be NULL for the
414 Set, Enable, and Disable operations.
416 @retval EFI_SUCCESS The operation on the PCI controller's
417 attributes was completed. If the operation
418 was Get or Supported, then the attribute mask
419 is returned in Result.
420 @retval EFI_INVALID_PARAMETER Operation is greater than or equal to
421 EfiPciIoAttributeOperationMaximum.
422 @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL.
423 @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL.
428 IN EFI_PCI_IO_PROTOCOL
*This
,
429 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
,
430 IN UINT64 Attributes
,
431 OUT UINT64
*Result OPTIONAL
435 case EfiPciIoAttributeOperationGet
:
436 case EfiPciIoAttributeOperationSupported
:
437 if (Result
== NULL
) {
438 return EFI_INVALID_PARAMETER
;
441 // We are not a real PCI device so just say things we kind of do
443 *Result
= EFI_PCI_DEVICE_ENABLE
;
446 case EfiPciIoAttributeOperationSet
:
447 case EfiPciIoAttributeOperationEnable
:
448 case EfiPciIoAttributeOperationDisable
:
449 if (Attributes
& (~EFI_PCI_DEVICE_ENABLE
)) {
450 return EFI_UNSUPPORTED
;
452 // Since we are not a real PCI device no enable/set or disable operations exist.
456 return EFI_INVALID_PARAMETER
;
462 PciIoGetBarAttributes (
463 IN EFI_PCI_IO_PROTOCOL
*This
,
465 OUT UINT64
*Supports
, OPTIONAL
466 OUT VOID
**Resources OPTIONAL
470 return EFI_UNSUPPORTED
;
474 PciIoSetBarAttributes (
475 IN EFI_PCI_IO_PROTOCOL
*This
,
476 IN UINT64 Attributes
,
478 IN OUT UINT64
*Offset
,
479 IN OUT UINT64
*Length
483 return EFI_UNSUPPORTED
;
486 EFI_PCI_IO_PROTOCOL PciIoTemplate
=
490 { PciIoMemRead
, PciIoMemWrite
},
491 { PciIoIoRead
, PciIoIoWrite
},
492 { PciIoPciRead
, PciIoPciWrite
},
501 PciIoGetBarAttributes
,
502 PciIoSetBarAttributes
,
510 IN PHYSICAL_ADDRESS MemoryStart
,
511 IN UINT64 MemorySize
,
519 EFI_PCI_IO_PRIVATE_DATA
*Private
;
521 // Configure USB host
524 // Create a private structure
525 Private
= AllocatePool (sizeof (EFI_PCI_IO_PRIVATE_DATA
));
526 if (Private
== NULL
) {
527 Status
= EFI_OUT_OF_RESOURCES
;
531 Private
->Signature
= EFI_PCI_IO_PRIVATE_DATA_SIGNATURE
; // Fill in signature
532 Private
->RootBridge
.Signature
= PCI_ROOT_BRIDGE_SIGNATURE
; // Fake Root Bridge structure needs a signature too
533 Private
->RootBridge
.MemoryStart
= MemoryStart
; // Get the USB capability register base
534 Private
->Segment
= 0; // Default to segment zero
536 // Calculate the total size of the USB controller (OHCI + EHCI).
537 Private
->RootBridge
.MemorySize
= MemorySize
; //CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));
539 // Create fake PCI config space: OHCI + EHCI
540 Private
->ConfigSpace
= AllocateZeroPool (sizeof (PCI_TYPE00
));
541 if (Private
->ConfigSpace
== NULL
) {
542 Status
= EFI_OUT_OF_RESOURCES
;
548 // Configure PCI config space: OHCI + EHCI
550 Private
->ConfigSpace
->Hdr
.VendorId
= 0xFFFF; // Invalid vendor Id as it is not an actual device.
551 Private
->ConfigSpace
->Hdr
.DeviceId
= 0x0000; // Not relevant as the vendor id is not valid.
552 Private
->ConfigSpace
->Hdr
.ClassCode
[0] = ClassCode1
;
553 Private
->ConfigSpace
->Hdr
.ClassCode
[1] = ClassCode2
;
554 Private
->ConfigSpace
->Hdr
.ClassCode
[2] = ClassCode3
;
555 Private
->ConfigSpace
->Device
.Bar
[0] = MemoryStart
;
559 // Unique device path.
560 CopyMem (&Private
->DevicePath
, &PciIoDevicePathTemplate
, sizeof (PciIoDevicePathTemplate
));
561 Private
->DevicePath
.AcpiDevicePath
.UID
= 1; // Use '1' to differentiate from PLDA root complex
562 Private
->DevicePath
.PciDevicePath
.Device
= DeviceId
;
564 // Copy protocol structure
565 CopyMem (&Private
->PciIoProtocol
, &PciIoTemplate
, sizeof (PciIoTemplate
));
567 Status
= gBS
->InstallMultipleProtocolInterfaces (&Handle
,
568 &gEfiPciIoProtocolGuid
, &Private
->PciIoProtocol
,
569 &gEfiDevicePathProtocolGuid
, &Private
->DevicePath
,
571 if (EFI_ERROR (Status
)) {
572 DEBUG ((EFI_D_ERROR
, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces () failed.\n"));
579 PciEmulationEntryPoint (
585 Status
= PciInstallDevice (0, FixedPcdGet32 (PcdSynopsysUsbOhciBaseAddress
), SIZE_64KB
, PCI_IF_OHCI
, PCI_CLASS_SERIAL_USB
, PCI_CLASS_SERIAL
);
586 if (EFI_ERROR (Status
)) {
587 DEBUG ((EFI_D_ERROR
, "PciEmulation: failed to install OHCI device.\n"));
590 Status
= PciInstallDevice (1, FixedPcdGet32 (PcdSynopsysUsbEhciBaseAddress
), SIZE_64KB
, PCI_IF_EHCI
, PCI_CLASS_SERIAL_USB
, PCI_CLASS_SERIAL
);
591 if (EFI_ERROR (Status
)) {
592 DEBUG ((EFI_D_ERROR
, "PciEmulation: failed to install EHCI device.\n"));