* [Patch 2/3] [edk2-platforms] Platform/Intel/DebugFeaturePkg: Add USB3DebugPort related modules.
2019-05-29 0:47 [Patch 0/3] [edk2-platforms] Add DebugFeaturePkg to keep debug related modules Dong, Eric
2019-05-29 0:47 ` [Patch 1/3] [edk2-platforms] Platform/Intel/DebugFeaturePkg: Add DebugFeaturePkg Dong, Eric
@ 2019-05-29 0:47 ` Dong, Eric
2019-05-29 0:47 ` [Patch 3/3] [edk2-platforms] Platform/Intel/DebugFeaturePkg/AcpiDebug: Change AcpiDebug module location Dong, Eric
2019-05-29 6:49 ` [edk2-devel] [Patch 0/3] [edk2-platforms] Add DebugFeaturePkg to keep debug related modules Liming Gao
3 siblings, 0 replies; 5+ messages in thread
From: Dong, Eric @ 2019-05-29 0:47 UTC (permalink / raw)
To: devel; +Cc: Liming Gao
https://bugzilla.tianocore.org/show_bug.cgi?id=1553
Add USB3DebugPort related modules, include Usb3DebugPortLib and
Usb3DebugPortParameterLib. Usb3DebugPortParameterLib will be consumed
by Usb3DebugPortLib.
Interfaces export by Us3DebugPortLib includes:
Usb3DebugPortParameterLib
Usb3DebugPortWrite
Usb3DebugPortPoll
Interfaces export by Usb3DebugPortParameterLib includes:
GetUsb3DebugPortController
SetUsb3DebugPortController
Signed-off-by: Eric Dong <eric.dong@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
---
.../Intel/DebugFeaturePkg/DebugFeaturePkg.dec | 36 +-
.../Intel/DebugFeaturePkg/DebugFeaturePkg.dsc | 62 ++
.../Include/Library/Usb3DebugPortLib.h | 76 ++
.../Library/Usb3DebugPortParameterLib.h | 56 ++
.../Library/Usb3DebugPortLib/MiscServices.c | 385 ++++++++
.../Usb3DebugPortDataTransfer.c | 892 ++++++++++++++++++
.../Usb3DebugPortInitialize.c | 726 ++++++++++++++
.../Usb3DebugPortLib/Usb3DebugPortLibDxe.c | 454 +++++++++
.../Usb3DebugPortLib/Usb3DebugPortLibDxe.inf | 55 ++
.../Usb3DebugPortLibDxeIoMmu.c | 828 ++++++++++++++++
.../Usb3DebugPortLibDxeIoMmu.inf | 63 ++
.../Usb3DebugPortLibInternal.h | 887 +++++++++++++++++
.../Usb3DebugPortLib/Usb3DebugPortLibNull.c | 103 ++
.../Usb3DebugPortLib/Usb3DebugPortLibNull.inf | 28 +
.../Usb3DebugPortLib/Usb3DebugPortLibPei.c | 236 +++++
.../Usb3DebugPortLib/Usb3DebugPortLibPei.inf | 48 +
.../Usb3DebugPortLibPeiIoMmu.c | 440 +++++++++
.../Usb3DebugPortLibPeiIoMmu.inf | 51 +
.../Usb3DebugPortParameterLibPcd.c | 58 ++
.../Usb3DebugPortParameterLibPcd.inf | 31 +
20 files changed, 5514 insertions(+), 1 deletion(-)
create mode 100644 Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortLib.h
create mode 100644 Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortParameterLib.h
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/MiscServices.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortDataTransfer.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortInitialize.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.inf
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.inf
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibInternal.h
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.inf
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.inf
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.inf
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.c
create mode 100644 Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.inf
diff --git a/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dec b/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dec
index 839684183a..63a6ed03b7 100644
--- a/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dec
+++ b/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dec
@@ -16,4 +16,38 @@
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = DebugFeaturePkg
PACKAGE_GUID = 58B6F2BB-A94F-4EB9-89DA-2F06ED59CE39
- PACKAGE_VERSION = 0.1
\ No newline at end of file
+ PACKAGE_VERSION = 0.1
+
+[Includes]
+ Include
+
+[LibraryClasses]
+ ## @libraryclass Provide capability to get/set USB3 debug port parameter.
+ Usb3DebugPortParameterLib|Include/Library/Usb3DebugPortParameterLib.h
+
+[Guids]
+ gEfiUsb3DebugPortTokenSpaceGuid = { 0x87e7378b, 0xc59d, 0x4a16, { 0xa4, 0x21, 0x2c, 0xdb, 0x78, 0x26, 0xb1, 0xca } }
+
+[PcdsFeatureFlag]
+ ## This PCD specifies whether StatusCode is reported via USB3 Serial port.
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdStatusCodeUseUsb3Serial|TRUE|BOOLEAN|0x10000003
+
+[PcdsFixedAtBuild]
+ ## These PCD specify XHCI controller Bus/Device/Function, which are used to enable
+ # XHCI debug device.
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsbSerialXhciBus|0x00|UINT8|0x00000016
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsbSerialXhciDev|0x14|UINT8|0x00000017
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsbSerialXhciFunc|0x00|UINT8|0x00000018
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciDefaultBaseAddress|0xFEA10000|UINT32|0x00000019
+
+ ## This PCD specifies the wait timeout value in microsecond if USB debug cable is detected but host not connected.
+ # Default timeout value is 2000000 microseconds.
+ # If user does not want system stall for long time, it can be set to small value.
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciHostWaitTimeout|2000000|UINT64|0x00000020
+
+ ## This PCD sepcifies the start index in CMOS, it will occupy 1 bytes space.
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsb3DebugPortBusIndex|0x59|UINT8|0x10000024
+ ## This PCD sepcifies the start index in CMOS, it will occupy 1 bytes space.
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsb3DebugPortDeviceIndex|0x5A|UINT8|0x10000025
+ ## This PCD sepcifies the start index in CMOS, it will occupy 1 bytes space.
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsb3DebugPortFunctionIndex|0x5B|UINT8|0x10000026
\ No newline at end of file
diff --git a/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dsc b/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dsc
index 351d6583d5..aeca73a8c8 100644
--- a/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dsc
+++ b/Platform/Intel/DebugFeaturePkg/DebugFeaturePkg.dsc
@@ -22,3 +22,65 @@
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
SKUID_IDENTIFIER = DEFAULT
+[LibraryClasses]
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+
+[LibraryClasses.common.PEIM]
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+ #Usb3DebugPortLib|DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.inf
+
+[LibraryClasses.IA32.PEIM, LibraryClasses.X64.PEIM]
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+
+[LibraryClasses.common.DXE_SMM_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+# into firmware volume images. This section is just a list of modules to compile from
+# source into UEFI-compliant binaries.
+# It is the FDF file that contains information on combining binary files into firmware
+# volume images, whose concept is beyond UEFI and is described in PI specification.
+# Binary modules do not need to be listed in this section, as they should be
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+# Logo (Logo.bmp), and etc.
+# There may also be modules listed in this section that are not required in the FDF file,
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+# generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+
+[Components]
+ DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.inf
+ DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.inf
+ DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.inf
+ DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.inf
+ DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.inf
+ DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.inf
diff --git a/Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortLib.h b/Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortLib.h
new file mode 100644
index 0000000000..61adf654d2
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortLib.h
@@ -0,0 +1,76 @@
+/** @file
+ This library class provides common USB3 debug port functions.
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __USB3_DEBUG_PORT_LIB__
+#define __USB3_DEBUG_PORT_LIB__
+
+/**
+ Initialize the USB3 debug port hardware.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+ If the serial device was successfully initialized, then return RETURN_SUCCESS.
+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+ @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+Usb3DebugPortInitialize (
+ VOID
+ );
+
+/**
+ Write data from buffer to USB3 debug port.
+
+ Writes NumberOfBytes data bytes from Buffer to the serial device.
+ The number of bytes actually written to the serial device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If Buffer is NULL, then ASSERT().
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the serial device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+Usb3DebugPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ );
+
+
+/**
+ Read data from USB3 debug port and save the datas in buffer.
+
+ Reads NumberOfBytes data bytes from a serial device into the buffer
+ specified by Buffer. The number of bytes actua
+/**
+ Polls a USB3 debug port to see if there is any data waiting to be read.
+
+ Polls a serial device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the serial device, then TRUE is returned.
+ If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+ @retval TRUE Data is waiting to be read from the serial device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+Usb3DebugPortPoll (
+ VOID
+ );
+
+#endif
diff --git a/Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortParameterLib.h b/Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortParameterLib.h
new file mode 100644
index 0000000000..167c607e9f
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Include/Library/Usb3DebugPortParameterLib.h
@@ -0,0 +1,56 @@
+/** @file
+ This library class provides capability to get/set usb3 debug port parameter.
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __USB3_DEBUG_PORT_PARAMETER_LIB__
+#define __USB3_DEBUG_PORT_PARAMETER_LIB__
+
+typedef struct {
+ UINT8 Function;
+ UINT8 Device;
+ UINT8 Bus;
+} PCI_ADDRESS;
+
+typedef union {
+ UINT32 Controller;
+ PCI_ADDRESS PciAddress;
+} USB3_DEBUG_PORT_CONTROLLER;
+
+/**
+ Returns the USB debug port controller.
+ bit: 0~ 7: Function
+ bit: 8~15: Device
+ bit: 16~24: Bus
+
+ @return Controller information of USB debug port.
+
+**/
+UINT32
+EFIAPI
+GetUsb3DebugPortController (
+ VOID
+ );
+
+/**
+ Sets the USB debug port controller.
+ bit: 0~ 7: Function
+ bit: 8~15: Device
+ bit: 16~24: Bus
+
+ @param[in] Controller information of USB debug port value to be set.
+
+ @retval TRUE The controller of USB debug port was sucessfully set.
+ @retval FALSE The controller of USB debug port could not be set.
+
+**/
+BOOLEAN
+EFIAPI
+SetUsb3DebugPortController (
+ UINT32 Controller
+ );
+
+#endif
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/MiscServices.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/MiscServices.c
new file mode 100644
index 0000000000..cb29a880e6
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/MiscServices.c
@@ -0,0 +1,385 @@
+/** @file
+ Miscellaneous services internal to USB debug port implementation.
+
+ Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Usb3DebugPortLibInternal.h"
+
+/**
+ Verifies if the bit positions specified by a mask are set in a register.
+
+ @param[in, out] Register UNITN register
+ @param[in] BitMask 32-bit mask
+
+ @return BOOLEAN - TRUE if all bits specified by the mask are enabled.
+ - FALSE even if one of the bits specified by the mask
+ is not enabled.
+**/
+BOOLEAN
+XhcIsBitSet(
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ )
+{
+ if ((MmioRead32 (Register) & (BitMask)) != 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Sets bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcSetR32Bit(
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ )
+{
+ UINT32 RegisterValue;
+
+ RegisterValue = MmioRead32 (Register);
+ RegisterValue |= (UINT32)(BitMask);
+ MmioWrite32 (Register, RegisterValue);
+}
+
+/**
+ Clears bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcClrR32Bit(
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ )
+{
+ UINT32 RegisterValue;
+
+ RegisterValue = MmioRead32 (Register);
+ RegisterValue &= (UINT32)(~(BitMask));
+ MmioWrite32 (Register, RegisterValue);
+}
+
+/**
+ Initialize the USB debug port hardware.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+ If the serial device was successfully initialized, then return RETURN_SUCCESS.
+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+ @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
+**/
+RETURN_STATUS
+EFIAPI
+Usb3DebugPortInitialize (
+ VOID
+ )
+{
+ USB3Initialize ();
+ return RETURN_SUCCESS;
+}
+
+/**
+ Write data from buffer to USB debug port.
+
+ Writes NumberOfBytes data bytes from Buffer to the serial device.
+ The number of bytes actually written to the serial device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If Buffer is NULL, then ASSERT().
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the serial device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+**/
+UINTN
+EFIAPI
+Usb3DebugPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ Usb3DbgOut (Buffer, &NumberOfBytes);
+ return NumberOfBytes;
+}
+
+/**
+ Read data from USB debug port and save the datas in buffer.
+
+ Reads NumberOfBytes data bytes from a serial device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If Buffer is NULL, then ASSERT().
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to store the data read from the serial device.
+ @param NumberOfBytes Number of bytes which will be read.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from serial device.
+**/
+UINTN
+EFIAPI
+Usb3DebugPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ Usb3DbgIn (Buffer, &NumberOfBytes);
+ return NumberOfBytes;
+}
+
+/**
+ Polls a USB debug port to see if there is any data waiting to be read.
+
+ Polls a serial device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the serial device, then TRUE is returned.
+ If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+ @retval TRUE Data is waiting to be read from the serial device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+**/
+BOOLEAN
+EFIAPI
+Usb3DebugPortPoll (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Write the data to the XHCI debug register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDebugReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ DebugCapabilityBase = Xhc->DebugCapabilityBase;
+
+ MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);
+
+ return;
+}
+
+/**
+ Read XHCI debug register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the debug register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadDebugReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ DebugCapabilityBase = Xhc->DebugCapabilityBase;
+
+ Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));
+
+ return Data;
+}
+
+/**
+ Set one bit of the debug register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetDebugRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadDebugReg (Xhc, Offset);
+ Data |= Bit;
+ XhcWriteDebugReg (Xhc, Offset, Data);
+}
+
+/**
+ Clear one bit of the debug register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcClearDebugRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadDebugReg (Xhc, Offset);
+ Data &= ~Bit;
+ XhcWriteDebugReg (Xhc, Offset, Data);
+}
+
+/**
+ Write the data to the XHCI MMIO register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteMmioReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_PHYSICAL_ADDRESS MmioBase;
+
+ MmioBase = Xhc->XhcMmioBase;
+ MmioWrite32 ((UINTN)(MmioBase + Offset), Data);
+
+ return;
+}
+
+/**
+ Read XHCI MMIO register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadMmioReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_PHYSICAL_ADDRESS MmioBase;
+
+ MmioBase = Xhc->XhcMmioBase;
+
+ Data = MmioRead32 ((UINTN)(MmioBase + Offset));
+
+ return Data;
+}
+
+/**
+ Set one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetMmioRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadMmioReg (Xhc, Offset);
+ Data |= Bit;
+ XhcWriteMmioReg (Xhc, Offset, Data);
+}
+
+/**
+ Clear one bit of the operational register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the runtime register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcClearMmioRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadMmioReg (Xhc, Offset);
+ Data &= ~Bit;
+ XhcWriteMmioReg (Xhc, Offset, Data);
+}
+
+/**
+ Wait the operation register's bit as specified by Bit
+ to be set (or clear).
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the operational register.
+ @param Bit The bit of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+XhcWaitMmioRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ )
+{
+ UINT32 Index;
+ UINTN Loop;
+
+ Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;
+
+ for (Index = 0; Index < Loop; Index++) {
+ if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {
+ return EFI_SUCCESS;
+ }
+
+ MicroSecondDelay (XHC_POLL_DELAY);
+ }
+
+ return EFI_TIMEOUT;
+}
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortDataTransfer.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortDataTransfer.c
new file mode 100644
index 0000000000..53478a49b8
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortDataTransfer.c
@@ -0,0 +1,892 @@
+/** @file
+ Usb3 Debug Port library instance
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <PiPei.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/Usb3DebugPortParameterLib.h>
+#include "Usb3DebugPortLibInternal.h"
+
+EFI_SMRAM_DESCRIPTOR mSmramCheckRanges[MAX_SMRAM_RANGE];
+UINTN mSmramCheckRangeCount = 0;
+BOOLEAN mUsb3InSmm = FALSE;
+UINT64 mUsb3MmioSize = 0;
+
+/**
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI Instance.
+ @param TrsRing The transfer ring to sync.
+
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncTrsRing (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN TRANSFER_RING *TrsRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *TrsTrb;
+
+ ASSERT (TrsRing != NULL);
+
+ //
+ // Calculate the latest RingEnqueue and RingPCS
+ //
+ TrsTrb = (TRB_TEMPLATE *)(UINTN) TrsRing->RingEnqueue;
+
+ ASSERT (TrsTrb != NULL);
+
+ for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
+ if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
+ break;
+ }
+ TrsTrb++;
+ if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
+ ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
+ //
+ // set cycle bit in Link TRB as normal
+ //
+ ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
+ //
+ // Toggle PCS maintained by software
+ //
+ TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
+ TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
+ }
+ }
+ ASSERT (Index != TrsRing->TrbNumber);
+
+ if ((EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb != TrsRing->RingEnqueue) {
+ TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb;
+ }
+
+ //
+ // Clear the Trb context for enqueue, but reserve the PCS bit
+ //
+ TrsTrb->Parameter1 = 0;
+ TrsTrb->Parameter2 = 0;
+ TrsTrb->Status = 0;
+ TrsTrb->RsvdZ1 = 0;
+ TrsTrb->Type = 0;
+ TrsTrb->Control = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.
+
+ @param Xhc The XHCI Instance.
+ @param EvtRing The event ring to sync.
+
+ @retval EFI_SUCCESS The event ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncEventRing (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN EVENT_RING *EvtRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *EvtTrb1;
+
+ ASSERT (EvtRing != NULL);
+
+ //
+ // Calculate the EventRingEnqueue and EventRingCCS.
+ // Note: only support single Segment
+ //
+ EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
+
+ for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
+ if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
+ break;
+ }
+
+ EvtTrb1++;
+
+ if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingSeg0;
+ EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
+ }
+ }
+
+ if (Index < EvtRing->TrbNumber) {
+ EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if there is a new generated event.
+
+ @param Xhc The XHCI Instance.
+ @param EvtRing The event ring to check.
+ @param NewEvtTrb The new event TRB found.
+
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.
+ @retval EFI_NOT_READY The event ring has no new event.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcCheckNewEvent (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN EVENT_RING *EvtRing,
+ OUT TRB_TEMPLATE **NewEvtTrb
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (EvtRing != NULL);
+
+ *NewEvtTrb = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;
+
+ if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
+ return EFI_NOT_READY;
+ }
+
+ Status = EFI_SUCCESS;
+
+ EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
+ //
+ // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
+ //
+ if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
+ }
+
+ return Status;
+}
+
+/**
+ Check if the Trb is a transaction of the URB.
+
+ @param Trb The TRB to be checked
+ @param Urb The transfer ring to be checked.
+
+ @retval TRUE It is a transaction of the URB.
+ @retval FALSE It is not any transaction of the URB.
+
+**/
+BOOLEAN
+IsTransferRingTrb (
+ IN TRB_TEMPLATE *Trb,
+ IN URB *Urb
+ )
+{
+ TRB_TEMPLATE *CheckedTrb;
+ TRANSFER_RING *Ring;
+ UINTN Index;
+
+ Ring = (TRANSFER_RING *)(UINTN) Urb->Ring;
+ CheckedTrb = (TRB_TEMPLATE *)(UINTN) Ring->RingSeg0;
+
+ ASSERT (Ring->TrbNumber == CMD_RING_TRB_NUMBER || Ring->TrbNumber == TR_RING_TRB_NUMBER);
+
+ for (Index = 0; Index < Ring->TrbNumber; Index++) {
+ if (Trb == CheckedTrb) {
+ return TRUE;
+ }
+ CheckedTrb++;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check the URB's execution result and update the URB's
+ result accordingly.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The URB to check result.
+
+ @return Whether the result of URB transfer is finialized.
+
+**/
+EFI_STATUS
+XhcCheckUrbResult (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ EVT_TRB_TRANSFER *EvtTrb;
+ TRB_TEMPLATE *TRBPtr;
+ UINTN Index;
+ UINT8 TRBType;
+ EFI_STATUS Status;
+ URB *CheckedUrb;
+ UINT64 XhcDequeue;
+ UINT32 High;
+ UINT32 Low;
+
+ ASSERT ((Xhc != NULL) && (Urb != NULL));
+
+ Status = EFI_SUCCESS;
+
+ if (Urb->Finished) {
+ goto EXIT;
+ }
+
+ EvtTrb = NULL;
+
+ //
+ // Traverse the event ring to find out all new events from the previous check.
+ //
+ XhcSyncEventRing (Xhc, &Xhc->EventRing);
+
+ for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
+ Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
+ if (Status == EFI_NOT_READY) {
+ //
+ // All new events are handled, return directly.
+ //
+ goto EXIT;
+ }
+ //
+ // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
+ //
+ if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
+ continue;
+ }
+
+ TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
+
+ //
+ // Update the status of Urb according to the finished event regardless of whether
+ // the urb is current checked one or in the XHCI's async transfer list.
+ // This way is used to avoid that those completed async transfer events don't get
+ // handled in time and are flushed by newer coming events.
+ //
+ if (IsTransferRingTrb (TRBPtr, Urb)) {
+ CheckedUrb = Urb;
+ } else {
+ continue;
+ }
+ switch (EvtTrb->Completecode) {
+ case TRB_COMPLETION_STALL_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_STALL;
+ CheckedUrb->Finished = TRUE;
+ break;
+
+ case TRB_COMPLETION_BABBLE_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
+ CheckedUrb->Finished = TRUE;
+ break;
+
+ case TRB_COMPLETION_DATA_BUFFER_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
+ CheckedUrb->Finished = TRUE;
+ break;
+
+ case TRB_COMPLETION_USB_TRANSACTION_ERROR:
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Finished = TRUE;
+ break;
+
+ case TRB_COMPLETION_SHORT_PACKET:
+ case TRB_COMPLETION_SUCCESS:
+ if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
+ }
+
+ TRBType = (UINT8) (TRBPtr->Type);
+ if ((TRBType == TRB_TYPE_DATA_STAGE) ||
+ (TRBType == TRB_TYPE_NORMAL) ||
+ (TRBType == TRB_TYPE_ISOCH)) {
+ CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Length);
+ }
+
+ break;
+
+ default:
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Finished = TRUE;
+ break;
+ }
+
+ //
+ // Only check first and end Trb event address
+ //
+
+ if ((EFI_PHYSICAL_ADDRESS)(UINTN) TRBPtr == CheckedUrb->TrbStart) {
+ CheckedUrb->StartDone = TRUE;
+ }
+
+ if ((EFI_PHYSICAL_ADDRESS)(UINTN) TRBPtr == CheckedUrb->TrbEnd) {
+ CheckedUrb->EndDone = TRUE;
+ }
+
+ if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
+ CheckedUrb->Finished = TRUE;
+ }
+
+ }
+
+EXIT:
+ //
+ // Advance event ring to last available entry
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ Low = XhcReadDebugReg (Xhc, XHC_DC_DCERDP);
+ High = XhcReadDebugReg (Xhc, XHC_DC_DCERDP + 4);
+ XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
+
+ if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Xhc->EventRing.EventRingDequeue & (~0x0F))) {
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcWriteDebugReg (Xhc, XHC_DC_DCERDP, XHC_LOW_32BIT (Xhc->EventRing.EventRingDequeue));
+ XhcWriteDebugReg (Xhc, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Xhc->EventRing.EventRingDequeue));
+ }
+
+ return Status;
+}
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The pointer to URB.
+
+ @retval EFI_SUCCESS Successfully ring the door bell.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcRingDoorBell (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ UINT32 Dcdb;
+
+ //
+ // 7.6.8.2 DCDB Register
+ //
+ if (Urb->Direction == EfiUsbDataIn) {
+ Dcdb = 0x100;
+ } else {
+ Dcdb = 0x0;
+ }
+
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCDB,
+ Dcdb
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Xhc The XHCI Instance.
+ @param Urb The URB to execute.
+ @param Timeout The time to wait before abort, in millisecond.
+
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
+ @return EFI_TIMEOUT The transfer failed due to time out.
+ @return EFI_SUCCESS The transfer finished OK.
+
+**/
+EFI_STATUS
+XhcExecTransfer (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN URB *Urb,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Loop;
+ TRB_TEMPLATE *Trb;
+ TRANSFER_RING *Ring;
+ TRB_TEMPLATE *TrbStart;
+ TRB_TEMPLATE *TrbEnd;
+
+ Status = EFI_SUCCESS;
+
+ Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;
+ if (Timeout == 0) {
+ Loop = 0xFFFFFFFF;
+ }
+ XhcRingDoorBell (Xhc, Urb);
+ //
+ // DSCT BIT0: Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
+ //
+
+ for (Index = 0; Index < Loop; Index++) {
+ Status = XhcCheckUrbResult (Xhc, Urb);
+ if (Urb->Finished) {
+ break;
+ }
+ MicroSecondDelay (XHC_POLL_DELAY);
+ }
+ if (Index == Loop) {
+ Urb->Result = EFI_USB_ERR_TIMEOUT;
+ }
+
+ //
+ // If URB transfer is error, restore transfer ring to original value before URB transfer
+ // This will make the current transfer TRB is always at the latest unused one in transfer ring.
+ // Without this code, when there is read TRB from target, but host does not write anything, this TRB (A)
+ // will be still here, next read TRB (B) will be put next to TRB (A), when host write then, the TRB (A)
+ // will be used to contain data, not TRB(B), this will cause Finished flag will not be set and return error in this function.
+ //
+ Ring = (TRANSFER_RING *)(UINTN) Urb->Ring;
+ if (Urb->Result != EFI_USB_NOERROR) {
+ Ring->RingEnqueue = Urb->TrbStart;
+ //
+ // Clear CCS flag for next use
+ //
+ TrbStart = (TRB_TEMPLATE *)(UINTN) Urb->TrbStart;
+ TrbEnd = (TRB_TEMPLATE *)(UINTN) Urb->TrbEnd;
+ for (Trb = TrbStart; Trb <= TrbEnd; Trb++) {
+ Trb->CycleBit = ((~Ring->RingPCS) & BIT0);
+ }
+ }
+ return Status;
+}
+
+/**
+ Create a transfer TRB.
+
+ @param Xhc The XHCI Instance
+ @param Urb The urb used to construct the transfer TRB.
+
+ @return Created TRB or NULL
+
+**/
+EFI_STATUS
+XhcCreateTransferTrb (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN URB *Urb
+ )
+{
+ TRANSFER_RING *EPRing;
+ TRB *TrbStart;
+ UINT32 TotalLen;
+ UINT32 Len;
+ UINT32 TrbNum;
+
+ Urb->Finished = FALSE;
+ Urb->StartDone = FALSE;
+ Urb->EndDone = FALSE;
+ Urb->Completed = 0;
+ Urb->Result = EFI_USB_NOERROR;
+
+ if (Urb->Direction == EfiUsbDataIn) {
+ EPRing = &Xhc->TransferRingIn;
+ } else {
+ EPRing = &Xhc->TransferRingOut;
+ }
+
+ Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN) EPRing;
+ //
+ // Construct the TRB for ED_BULK_OUT and ED_BULK_IN
+ //
+ XhcSyncTrsRing (Xhc, EPRing);
+
+ Urb->TrbStart = EPRing->RingEnqueue;
+
+ TotalLen = 0;
+ Len = 0;
+ TrbNum = 0;
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+
+ while (TotalLen < Urb->DataLen) {
+ if ((TotalLen + 0x10000) >= Urb->DataLen) {
+ Len = Urb->DataLen - TotalLen;
+ } else {
+ Len = 0x10000;
+ }
+ TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
+ TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT(Urb->Data + TotalLen);
+ TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT(Urb->Data + TotalLen);
+ TrbStart->TrbNormal.Length = Len;
+ TrbStart->TrbNormal.TDSize = 0;
+ TrbStart->TrbNormal.IntTarget = 0;
+ TrbStart->TrbNormal.ISP = 1;
+ TrbStart->TrbNormal.IOC = 1;
+ TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
+
+ //
+ // Update the cycle bit
+ //
+ TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
+
+ XhcSyncTrsRing (Xhc, EPRing);
+ TrbNum++;
+ TotalLen += Len;
+ }
+
+ Urb->TrbNum = TrbNum;
+
+ //
+ // Update to the last TRB
+ //
+ Urb->TrbEnd = (EFI_PHYSICAL_ADDRESS)(UINTN) TrbStart;
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new URB for a new transaction.
+
+ @param Xhc The XHCI Instance
+ @param Direction The direction of data flow.
+ @param Data The user data to transfer
+ @param DataLen The length of data buffer
+
+ @return Created URB or NULL
+
+**/
+URB*
+XhcCreateUrb (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN VOID *Data,
+ IN UINTN DataLen
+ )
+{
+ EFI_STATUS Status;
+ URB *Urb;
+ EFI_PHYSICAL_ADDRESS DataAddress;
+
+ Urb = &Xhc->Urb;
+ ASSERT (Urb->Data != 0);
+ DataAddress = Urb->Data;
+ ZeroMem (Urb, sizeof (URB));
+
+ Urb->Signature = USB3_DEBUG_PORT_INSTANCE_SIGNATURE;
+ Urb->Direction = Direction;
+ Urb->Data = DataAddress;
+
+ ZeroMem ((VOID*)(UINTN) Urb->Data, DataLen);
+ CopyMem ((VOID*)(UINTN) Urb->Data, Data, DataLen);
+
+ Urb->DataLen = (UINT32) DataLen;
+ Status = XhcCreateTransferTrb (Xhc, Urb);
+ ASSERT_EFI_ERROR (Status);
+
+ return Urb;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param Xhc The instance of debug device.
+ @param Direction The direction of data transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param Timeout Indicates the maximum time, in millisecond, which
+ the transfer is allowed to complete.
+ @param TransferResult Transfer result.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDataTransfer (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *TransferResult
+ )
+{
+ URB *Urb;
+ EFI_STATUS Status;
+
+ //
+ // Validate the parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) ||
+ (Data == NULL) || (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ Urb = XhcCreateUrb (Xhc, Direction, Data, *DataLength);
+
+ if (Urb == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = XhcExecTransfer (Xhc, Urb, Timeout);
+
+ *TransferResult = Urb->Result;
+ *DataLength = Urb->Completed;
+
+ if (*TransferResult == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ON_EXIT:
+
+ return Status;
+}
+
+/**
+ Check whether the MMIO Bar is within any of the SMRAM ranges.
+
+ @param[in] XhcMmioBase The address of the MMIO to be checked.
+
+ @retval TURE The XHCI MMIO is in SMRAM ranges.
+ @retval FALSE The XHCI MMIO is out of SMRAM ranges.
+**/
+BOOLEAN
+EFIAPI
+Usb3DebugIsAddressInSmram (
+ IN EFI_PHYSICAL_ADDRESS XhcMmioBase
+ )
+{
+ UINTN Index;
+
+ if (mSmramCheckRangeCount == 0) {
+ //
+ // When we invoke this function, we are already in SMM mode,
+ // but SmmAccess->GetCapabilities failed which kept mSmramCheckRanges as 0.
+ //
+ return TRUE;
+ }
+
+ for (Index = 0; Index < mSmramCheckRangeCount; Index ++) {
+ if (((XhcMmioBase >= mSmramCheckRanges[Index].CpuStart) && (XhcMmioBase < mSmramCheckRanges[Index].CpuStart + mSmramCheckRanges[Index].PhysicalSize)) ||
+ ((mSmramCheckRanges[Index].CpuStart >= XhcMmioBase) && (mSmramCheckRanges[Index].CpuStart < XhcMmioBase + mUsb3MmioSize))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Transfer data via XHC controller.
+
+ @param Data Data buffer.
+ @param Length Data length.
+ @param Direction Transfer direction.
+
+**/
+VOID
+Usb3DebugPortDataTransfer (
+ UINT8 *Data,
+ UINTN *Length,
+ EFI_USB_DATA_DIRECTION Direction
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+ UINT16 Command;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT32 TransferResult;
+ UINT32 Dcctrl;
+ EFI_PHYSICAL_ADDRESS UsbBase;
+ UINTN BytesToSend;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+ EFI_STATUS Status;
+ USB3_DEBUG_PORT_INSTANCE UsbDbgInstance;
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+
+ //
+ // MMIO base address is possible to clear, set it if it is cleared. (XhciMemorySpaceClose in PchUsbCommon.c)
+ //
+ XhcMmioBase = GetXhciBaseAddress ();
+ Command = GetXhciPciCommand ();
+
+ if ((XhcMmioBase == 0) || (XhcMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
+ //
+ // XHCI device MMIO base is cleared by someone, set it again
+ //
+ UsbBase = PcdGet32 (PcdXhciDefaultBaseAddress);
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)UsbBase);
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0x0);
+ UsbBase = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET)) & XHCI_BASE_ADDRESS_32_BIT_MASK;
+ if (UsbBase == 0 || UsbBase == XHCI_BASE_ADDRESS_32_BIT_MASK) {
+ return;
+ }
+ }
+
+ //
+ // Check if XHC debug MMIO range is in SMRAM
+ //
+ if ((mUsb3InSmm) && (Usb3DebugIsAddressInSmram (XhcMmioBase))) {
+ return;
+ }
+
+ //
+ // Save and set Command Register
+ //
+ if (((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((Command & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
+ PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
+ PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ }
+
+ Instance = GetUsb3DebugPortInstance ();
+
+ if (Instance != NULL) {
+ if (!Instance->DebugSupport) {
+ //
+ // Debug device is not supported by XHCI, return
+ //
+ goto Done;
+ }
+ }
+
+ if ((Instance != NULL) && (Instance->Ready)) {
+ //
+ // Debug device is broken suddently (e.g. Windows OS), return
+ //
+ Dcctrl = XhcReadDebugReg (Instance, XHC_DC_DCCTRL);
+ if ((Dcctrl & BIT0) == 0) {
+ goto Done;
+ }
+ }
+
+ if ((Instance != NULL) && (!Instance->Ready)) {
+ //
+ // Debug host does not connect with target
+ //
+ goto Done;
+ }
+
+ if (Instance == NULL) {
+ ZeroMem (&UsbDbgInstance, sizeof (USB3_DEBUG_PORT_INSTANCE));
+ DiscoverUsb3DebugPort (&UsbDbgInstance);
+ if (UsbDbgInstance.DebugSupport) {
+ if (!IsAllocatePagesReady ()) {
+ //
+ // AllocatePages can not work, return
+ //
+ goto Done;
+ }
+ }
+ Status = USB3InitializeReal ();
+ if (EFI_ERROR (Status)) {
+ //
+ // Debug device is failed to initialize
+ //
+ goto Done;
+ }
+
+ //
+ // Update instance
+ //
+ Instance = GetUsb3DebugPortInstance ();
+
+ if (Instance == NULL) {
+ //
+ // Debug device instance is failed to create
+ //
+ goto Done;
+ }
+
+ if ((!Instance->Ready) || (!Instance->DebugSupport)) {
+ //
+ // Debug host does not connect at first or is not supported
+ //
+ goto Done;
+ }
+ }
+
+ BytesToSend = 0;
+ while (*Length > 0) {
+ BytesToSend = ((*Length) > XHC_DEBUG_PORT_DATA_LENGTH) ? XHC_DEBUG_PORT_DATA_LENGTH : *Length;
+ XhcDataTransfer (
+ Instance,
+ Direction,
+ Data,
+ &BytesToSend,
+ DATA_TRANSFER_TIME_OUT,
+ &TransferResult
+ );
+ if (TransferResult != EFI_USB_NOERROR) {
+ break;
+ }
+ *Length -= BytesToSend;
+ Data += BytesToSend;
+ }
+
+Done:
+ //
+ // Restore Command Register
+ //
+ PciWrite16(PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
+
+}
+
+/**
+ Receive data over the USB3 debug cable.
+
+ @param[out] Data Pointer to data
+ @param[in, out] Length Pointer to data length
+
+**/
+RETURN_STATUS
+Usb3DbgIn (
+ OUT UINT8 *Data,
+ IN OUT UINTN *Length
+ )
+{
+ Usb3DebugPortDataTransfer (Data, Length, EfiUsbDataIn);
+ return EFI_SUCCESS;
+}
+
+/**
+ Send data over the USB3 debug cable.
+
+ @param[out] Data Pointer to data
+ @param[in, out] Length Pointer to data length
+
+**/
+VOID
+Usb3DbgOut (
+ OUT UINT8 *Data,
+ IN OUT UINTN *Length
+ )
+{
+ Usb3DebugPortDataTransfer (Data, Length, EfiUsbDataOut);
+}
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortInitialize.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortInitialize.c
new file mode 100644
index 0000000000..dbdae59253
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortInitialize.c
@@ -0,0 +1,726 @@
+/** @file
+ Usb3 Debug Port initialization
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <PiPei.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/HobLib.h>
+#include <Library/Usb3DebugPortParameterLib.h>
+#include "Usb3DebugPortLibInternal.h"
+
+UINT16 mString0Desc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + STRING0_DESC_LEN,
+ 0x0409
+};
+
+UINT16 mManufacturerStrDesc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + MANU_DESC_LEN,
+ 'I', 'n', 't', 'e', 'l'
+};
+
+//USB 3.0 Debug Cable
+UINT16 mProductStrDesc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + PRODUCT_DESC_LEN,
+ 'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
+};
+
+UINT16 mSerialNumberStrDesc[] = {
+ // String Descriptor Type + Length
+ ( USB_DESC_TYPE_STRING << 8 ) + SERIAL_DESC_LEN,
+ '1'
+};
+
+XHC_DC_CONTEXT DebugCapabilityContextTemplate = {
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ STRING0_DESC_LEN,
+ MANU_DESC_LEN,
+ PRODUCT_DESC_LEN,
+ SERIAL_DESC_LEN,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ 0, // EPState
+ 0, // RsvdZ1
+ 0, // Mult
+ 0, // MaxPStreams
+ 0, // LSA
+ 0, // Interval
+ 0, // RsvdZ2
+ 0, // RsvdZ3
+ 3, // CERR
+ ED_BULK_OUT, // EPType
+ 0, // RsvdZ4
+ 0, // HID
+ 0, // MaxBurstSize
+ 1024, // MaxPacketSize
+ 0, // PtrLo
+ 0, // PtrHi
+ 0x1000, // AverageTRBLength
+ 0, // MaxESITPayload
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3, //CERR
+ ED_BULK_IN,
+ 0,
+ 0,
+ 0,
+ 1024, //MaxPacketSize
+ 0,
+ 0,
+ 0x1000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }
+};
+
+/**
+ Return command register value in XHCI controller.
+
+**/
+UINT16
+GetXhciPciCommand (
+ VOID
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 Command;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+ Command = PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ return Command;
+}
+
+/**
+ Discover the USB3 debug device.
+
+ @param[in] Instance Pointer to USB3 debug port object instance.
+
+ @retval RETURN_SUCCESS The USB3 debug device was found.
+ @retval RETURN_DEVICE_ERROR The USB3 debug device was not found.
+
+**/
+RETURN_STATUS
+DiscoverUsb3DebugPort(
+ IN USB3_DEBUG_PORT_INSTANCE *Instance
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 Command;
+ EFI_PHYSICAL_ADDRESS UsbBase;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+ EFI_PHYSICAL_ADDRESS CapabilityPointer;
+ UINT32 Capability;
+ BOOLEAN Flag;
+ UINT8 CapLength;
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+ if ((PciRead8(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2)) != PCI_CLASS_SERIAL) ||
+ (PciRead8(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1)) != PCI_CLASS_SERIAL_USB) ||
+ (PciRead8(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_CLASSCODE_OFFSET)) != 0x30)) {
+ //
+ // The device is not XHCI controller
+ //
+ return RETURN_NOT_FOUND;
+ }
+
+ //
+ // USBBASE is at 10-13h, i.e. the first BAR, clear the low bits which is not part of base address
+ //
+ UsbBase = GetXhciBaseAddress ();
+
+ //
+ // Set XHCI MMIO base address if necessary
+ //
+ if ((UsbBase == 0) || (UsbBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
+ UsbBase = PcdGet32 (PcdXhciDefaultBaseAddress);
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)UsbBase);
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0x0);
+ UsbBase = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET)) & XHCI_BASE_ADDRESS_32_BIT_MASK;
+ if (UsbBase == 0 || UsbBase == XHCI_BASE_ADDRESS_32_BIT_MASK) {
+ return RETURN_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Set MSE and BME bit - enable the address space
+ //
+ Command = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
+ PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
+ PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ }
+
+ CapLength = MmioRead8 ((UINTN) UsbBase);
+
+ //
+ // Get capability pointer from HCCPARAMS at offset 0x10
+ //
+ CapabilityPointer = UsbBase + (MmioRead32 ((UINTN)(UsbBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
+
+ //
+ // Search XHCI debug capability
+ //
+ Flag = FALSE;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ while (TRUE) {
+ if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
+ Flag = TRUE;
+ break;
+ }
+ if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
+ //
+ // Reach the end of capability list, quit
+ //
+ break;
+ }
+ CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ }
+
+ Instance->Signature = USB3_DEBUG_PORT_INSTANCE_SIGNATURE;
+
+ if (Flag) {
+ Instance->DebugSupport = TRUE;
+ Instance->DebugCapabilityBase = CapabilityPointer;
+ Instance->DebugCapabilityOffset = CapabilityPointer - UsbBase;
+
+ Instance->XhciOpRegister = UsbBase + CapLength;
+ Instance->XhcMmioBase = UsbBase;
+
+ Instance->PciBusNumber = Bus;
+ Instance->PciDeviceNumber = Device;
+ Instance->PciFunctionNumber = Function;
+ }
+
+ //
+ // Restore Command Register
+ //
+ PciWrite16(PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Create XHCI event ring.
+
+ @param Xhc The XHCI Instance.
+ @param EventRing The created event ring.
+
+**/
+EFI_STATUS
+CreateEventRing (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ OUT EVENT_RING *EventRing
+ )
+{
+ VOID *Buf;
+ EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
+
+ ASSERT (EventRing != NULL);
+
+ //
+ // Allocate Event Ring
+ //
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+
+ EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
+ EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
+ EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
+ EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
+
+ //
+ // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
+ // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
+ //
+ EventRing->EventRingCCS = 1;
+
+ //
+ // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
+ //
+ Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+
+ ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
+ EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;
+
+ //
+ // Fill Event Segment address
+ //
+ ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
+ ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
+ ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
+
+ //
+ // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCERDP,
+ XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
+ );
+
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCERDP + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
+ );
+
+ //
+ // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCERSTBA,
+ XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)
+ );
+
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCERSTBA + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)
+ );
+
+ //
+ // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCERSTSZ,
+ ERST_NUMBER
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Create XHCI transfer ring.
+
+ @param Xhc The XHCI Instance.
+ @param TrbNum The number of TRB in the ring.
+ @param TransferRing The created transfer ring.
+
+**/
+VOID
+CreateTransferRing (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 TrbNum,
+ OUT TRANSFER_RING *TransferRing
+ )
+{
+ VOID *Buf;
+ LINK_TRB *EndTrb;
+
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0xF) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
+
+ TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
+ TransferRing->TrbNumber = TrbNum;
+ TransferRing->RingEnqueue = TransferRing->RingSeg0;
+ TransferRing->RingDequeue = TransferRing->RingSeg0;
+ TransferRing->RingPCS = 1;
+ //
+ // 4.9.2 Transfer Ring Management
+ // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
+ // point to the first TRB in the ring.
+ //
+ EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
+ EndTrb->Type = TRB_TYPE_LINK;
+ EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
+ EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
+ //
+ // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
+ //
+ EndTrb->TC = 1;
+ //
+ // Set Cycle bit as other TRB PCS init value
+ //
+ EndTrb->CycleBit = 0;
+}
+
+/**
+ Create debug capability context for XHC debug device.
+
+ @param Xhc The XHCI Instance.
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+CreateDebugCapabilityContext (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc
+ )
+{
+ VOID *Buf;
+ XHC_DC_CONTEXT *DebugCapabilityContext;
+ UINT8 *String0Desc;
+ UINT8 *ManufacturerStrDesc;
+ UINT8 *ProductStrDesc;
+ UINT8 *SerialNumberStrDesc;
+
+ //
+ // Allocate debug device context
+ //
+ Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN) Buf & 0xF) == 0);
+ ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
+
+ DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;
+ Xhc->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;
+
+ CopyMem (DebugCapabilityContext, &DebugCapabilityContextTemplate, sizeof (XHC_DC_CONTEXT));
+
+ //
+ // Update string descriptor address
+ //
+ String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
+ ASSERT (String0Desc != NULL);
+ ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
+ CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
+
+ ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
+ CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
+
+ ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
+ CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
+
+ SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
+ CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
+
+ //
+ // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
+ //
+ ZeroMem (&Xhc->TransferRingIn, sizeof (TRANSFER_RING));
+ CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, &Xhc->TransferRingIn);
+
+ //
+ // Can not set BIT0, otherwise there is no transfer ring detected.
+ //
+ DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Xhc->TransferRingIn.RingSeg0) | BIT0;
+ DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Xhc->TransferRingIn.RingSeg0);
+
+ //
+ // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
+ //
+ ZeroMem (&Xhc->TransferRingOut, sizeof (TRANSFER_RING));
+ CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, &Xhc->TransferRingOut);
+
+ //
+ // Can not set BIT0, otherwise there is no transfer ring detected.
+ //
+ DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Xhc->TransferRingOut.RingSeg0) | BIT0;
+ DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Xhc->TransferRingOut.RingSeg0);
+
+ //
+ // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
+ //
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCCP,
+ XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)
+ );
+ XhcWriteDebugReg (
+ Xhc,
+ XHC_DC_DCCP + 4,
+ XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the USB3 debug Device hardware.
+
+ @param[in] Instance Pointer to USB3 debug port object instance.
+
+ @retval RETURN_SUCCESS The USB3 debug device was initialized successfully.
+ @retval !RETURN_SUCCESS Error.
+
+**/
+RETURN_STATUS
+InitializeUsb3DebugPort (
+ IN USB3_DEBUG_PORT_INSTANCE *Instance
+ )
+{
+ RETURN_STATUS Status;
+ UINT64 XhciOpRegister;
+ volatile UINT32 Dcctrl;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 Command;
+ EFI_BOOT_MODE BootMode;
+ UINT64 TimeOut;
+ CHAR8 *TestString;
+ UINTN Length;
+ UINT32 TransferResult;
+
+ Bus = Instance->PciBusNumber;
+ Device = Instance->PciDeviceNumber;
+ Function = Instance->PciFunctionNumber;
+
+ Command = GetXhciPciCommand ();
+
+ //
+ // Save and set Command Register
+ //
+ if (((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((Command & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
+ PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER);
+ PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ }
+
+ //
+ // Clear DCE bit and LSE bit in DCCTRL
+ //
+ if ((XhcReadDebugReg (Instance, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) {
+ XhcClearDebugRegBit (Instance, XHC_DC_DCCTRL, BIT1|BIT31);
+ }
+
+ XhciOpRegister = Instance->XhciOpRegister;
+
+ //
+ // Get current Boot Mode
+ //
+ BootMode = GetBootModeHob ();
+
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ if (!XhcIsBitSet((UINTN)(XhciOpRegister + XHC_USBSTS_OFFSET), XHC_USBSTS_HALT)) {
+ XhcClrR32Bit((UINTN) XhciOpRegister + XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);
+ while (!XhcIsBitSet((UINTN)(XhciOpRegister + XHC_USBSTS_OFFSET), XHC_USBSTS_HALT)) {
+ MicroSecondDelay (10);
+ }
+ }
+
+ //
+ // Reset host controller
+ //
+ XhcSetR32Bit((UINTN)XhciOpRegister + XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);
+
+ //
+ // Ensure that the host controller is reset (RESET bit must be cleared after reset)
+ //
+ while (XhcIsBitSet((UINTN)XhciOpRegister + XHC_USBCMD_OFFSET, XHC_USBCMD_RESET)) {
+ MicroSecondDelay (10);
+ }
+ }
+
+ //
+ // Initialize event ring
+ //
+ ZeroMem (&Instance->EventRing, sizeof (EVENT_RING));
+ Status = CreateEventRing (Instance, &Instance->EventRing);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init IN and OUT endpoint context
+ //
+ Status = CreateDebugCapabilityContext (Instance);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init data buffer used to transfer
+ //
+ Instance->Urb.Data = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAlignBuffer (XHC_DEBUG_PORT_DATA_LENGTH);
+
+ //
+ // Init DCDDI1 and DCDDI2
+ //
+ XhcWriteDebugReg (
+ Instance,
+ XHC_DC_DCDDI1,
+ (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
+ );
+
+ XhcWriteDebugReg (
+ Instance,
+ XHC_DC_DCDDI2,
+ (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
+ );
+
+ //
+ // Set DCE bit and LSE bit to "1" in DCCTRL
+ //
+ XhcSetDebugRegBit (Instance, XHC_DC_DCCTRL, BIT1|BIT31);
+
+ TimeOut = DivU64x32 (PcdGet64 (PcdXhciHostWaitTimeout), XHC_POLL_DELAY) + 1;
+ while (TimeOut != 0) {
+ //
+ // Check if debug device is in configured state
+ //
+ Dcctrl = XhcReadDebugReg (Instance, XHC_DC_DCCTRL);
+ if ((Dcctrl & BIT0) != 0) {
+ //
+ // Set the flag to indicate debug device is ready
+ //
+ Instance->Ready = TRUE;
+ break;
+ }
+ MicroSecondDelay (XHC_POLL_DELAY);
+ TimeOut--;
+ }
+
+ if (!Instance->Ready) {
+ XhcClearDebugRegBit (Instance, XHC_DC_DCCTRL, BIT1|BIT31);
+ } else {
+ TestString = "Usb 3.0 Debug Message Start\n";
+ Length = AsciiStrLen (TestString);
+ XhcDataTransfer (
+ Instance,
+ EfiUsbDataOut,
+ TestString,
+ &Length,
+ 0,
+ &TransferResult
+ );
+ }
+
+ //
+ // Restore Command Register
+ //
+ PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update XHC hardware address when MMIO base is changed.
+
+ @param Instance The XHCI Instance.
+ @param XhcMmioBase XHCI MMIO base address.
+
+**/
+VOID
+FixUsb3InstanceResource (
+ IN OUT USB3_DEBUG_PORT_INSTANCE *Instance,
+ IN EFI_PHYSICAL_ADDRESS XhcMmioBase
+ )
+{
+ if ((Instance == NULL) || (Instance->XhcMmioBase == XhcMmioBase)) {
+ return;
+ }
+
+ //
+ // Need fix Instance data according to PCI resource
+ //
+ Instance->XhcMmioBase = XhcMmioBase;
+ Instance->DebugCapabilityBase = XhcMmioBase + Instance->DebugCapabilityOffset;
+ Instance->XhciOpRegister = XhcMmioBase + MmioRead8 ((UINTN)XhcMmioBase);
+}
+
+/**
+ Save USB3 instance address.
+
+ @param[in] Instance The XHCI Instance.
+
+**/
+VOID
+SaveUsb3InstanceAddress (
+ IN USB3_DEBUG_PORT_INSTANCE *Instance
+ )
+{
+ UINT16 Command;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+
+ Command = GetXhciPciCommand ();
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+
+ //
+ // Set Command Register
+ //
+ if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
+ PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
+ PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ }
+
+ //
+ // After debug device is finished to enumerate, use DCDDI2 register to store instance address
+ //
+ XhcWriteDebugReg (
+ Instance,
+ XHC_DC_DCDDI2,
+ (UINT32)(UINTN)Instance
+ );
+
+ //
+ // Restore Command Register
+ //
+ PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
+}
+
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.c
new file mode 100644
index 0000000000..8c3dd999db
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.c
@@ -0,0 +1,454 @@
+/** @file
+ Usb3 Debug Port library instance
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <PiDxe.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/Usb3DebugPortParameterLib.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/SmmAccess2.h>
+#include "Usb3DebugPortLibInternal.h"
+
+extern EFI_SMRAM_DESCRIPTOR mSmramCheckRanges[MAX_SMRAM_RANGE];
+extern UINTN mSmramCheckRangeCount;
+extern BOOLEAN mUsb3InSmm;
+extern UINT64 mUsb3MmioSize;
+extern BOOLEAN mUsb3GetCapSuccess;
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+USB3_DEBUG_PORT_CONTROLLER mUsb3DebugPort;
+USB3_DEBUG_PORT_INSTANCE *mUsb3Instance = NULL;
+
+/**
+ Return XHCI MMIO base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetXhciBaseAddress (
+ VOID
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT32 Low;
+ UINT32 High;
+
+ if (mUsb3DebugPort.Controller == 0) {
+ mUsb3DebugPort.Controller = GetUsb3DebugPortController();
+ }
+
+ Bus = mUsb3DebugPort.PciAddress.Bus;
+ Device = mUsb3DebugPort.PciAddress.Device;
+ Function = mUsb3DebugPort.PciAddress.Function;
+
+ Low = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
+ High = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
+ Address = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
+ //
+ // Mask other parts which are not part of base address
+ //
+ Address &= XHCI_BASE_ADDRESS_64_BIT_MASK;
+ return Address;
+}
+
+/**
+ Return XHCI debug instance address.
+
+**/
+USB3_DEBUG_PORT_INSTANCE *
+GetUsb3DebugPortInstance (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+ UINT64 CapabilityPointer;
+ UINT32 Capability;
+ BOOLEAN Flag;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 Command;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+
+ Instance = NULL;
+
+ XhcMmioBase = GetXhciBaseAddress ();
+
+ if ((XhcMmioBase == 0) || (XhcMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
+ return NULL;
+ }
+
+ if (mUsb3Instance != NULL) {
+ FixUsb3InstanceResource (mUsb3Instance, XhcMmioBase);
+ return mUsb3Instance;
+ }
+
+ Command = GetXhciPciCommand ();
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+
+ //
+ // Set Command Register
+ //
+ if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
+ PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
+ PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ }
+
+ //
+ // Calculate capability offset from HCCPARAMS [16:31], in 32-bit words
+ //
+ CapabilityPointer = XhcMmioBase + (MmioRead32 ((UINTN)(XhcMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
+
+ //
+ // Search XHCI debug capability
+ //
+ Flag = FALSE;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ while (TRUE) {
+ if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
+ Flag = TRUE;
+ break;
+ }
+ if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
+ //
+ // Reach the end of list, quit
+ //
+ break;
+ }
+ CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ }
+
+ if (Flag) {
+ Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN) MmioRead32 ((UINTN) (CapabilityPointer + XHC_DC_DCDDI2));
+
+ if (Instance != NULL) {
+ FixUsb3InstanceResource (Instance, XhcMmioBase);
+ }
+ }
+
+ //
+ // Restore Command Register
+ //
+ PciWrite16(PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
+
+ return Instance;
+}
+
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The USB3 debug port was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3Initialize (
+ VOID
+ )
+{
+ //
+ // Leave it empty, we assume PEI phase already do initialization
+ //
+ return RETURN_SUCCESS;
+}
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3InitializeReal (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE UsbDbg;
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+
+ if ((gST == NULL) || (gBS == NULL)) {
+ //
+ // gST and gBS have not been initialized yet
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &mUsb3Instance);
+ if (!EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // It is first time to run DXE instance, copy Instance from Hob to ACPINvs
+ // NOTE: Hob is not ready at this time, so copy it from XHCI register.
+ //
+ Instance = GetUsb3DebugPortInstance ();
+ if (Instance == NULL) {
+ //
+ // Initialize USB debug
+ //
+ SetMem (&UsbDbg, sizeof(UsbDbg), 0);
+ DiscoverUsb3DebugPort (&UsbDbg);
+ if (UsbDbg.DebugSupport) {
+ InitializeUsb3DebugPort (&UsbDbg);
+ }
+ Instance = &UsbDbg;
+ }
+ Address = SIZE_4GB;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (USB3_DEBUG_PORT_INSTANCE)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (
+ (VOID *)(UINTN)Address,
+ Instance,
+ sizeof (USB3_DEBUG_PORT_INSTANCE)
+ );
+ mUsb3Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN)Address;
+
+ Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, mUsb3Instance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mUsb3Instance->DebugSupport) {
+ SaveUsb3InstanceAddress (mUsb3Instance);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Calculate the size of XHCI MMIO space.
+
+ @retval TURE The XHCI MMIO is in SMRAM ranges.
+ @retval FALSE The XHCI MMIO is out of SMRAM ranges.
+**/
+UINT64
+CalculateMmioSize (
+ VOID
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT32 Value;
+ UINT32 Mask;
+ UINT64 MmioSize;
+ UINT16 Command;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+
+ Mask = 0xFFFFFFF0;
+ MmioSize = 0;
+
+ XhcMmioBase = GetXhciBaseAddress ();
+
+ //
+ // Disable MSE
+ //
+ Command = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command & ~(EFI_PCI_COMMAND_MEMORY_SPACE));
+
+ //
+ // Get Mmio Size
+ //
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), 0xFFFFFFFF);
+ Value = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
+
+ switch (Value & 0x07) {
+ case 0x0:
+ //
+ // Memory space: anywhere in 32 bit address space
+ //
+ MmioSize = (~(Value & Mask)) + 1;
+ break;
+ case 0x4:
+ //
+ // Memory space: anywhere in 64 bit address space
+ //
+ MmioSize = Value & Mask;
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);
+ Value = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
+ //
+ // Fix the length to support some spefic 64 bit BAR
+ //
+ Value |= ((UINT32)(-1) << HighBitSet32 (Value));
+ //
+ // Calculate the size of 64bit bar
+ //
+ MmioSize |= LShiftU64 ((UINT64) Value, 32);
+ MmioSize = (~(MmioSize)) + 1;
+ break;
+ default:
+ //
+ // Unknown BAR type
+ //
+ MmioSize = (~(Value & Mask)) + 1;
+ break;
+ };
+
+
+ //
+ // Restore MMIO address
+ //
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)XhcMmioBase);
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), (UINT32) (XhcMmioBase >> 32));
+
+ PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ return MmioSize;
+}
+
+/**
+ The constructor function initialize USB3 debug port.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+Usb3DebugPortLibDxeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_SMM_BASE2_PROTOCOL *SmmBase;
+ EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
+ UINTN Size;
+ EFI_STATUS Status;
+
+ //
+ // Do real initialization here, because we need copy data from Hob to ACPINvs.
+ // We must do it in constructor because it depends on UefiBootServicesTableLib.
+ //
+ if (FeaturePcdGet (PcdStatusCodeUseUsb3Serial)) {
+ USB3InitializeReal ();
+ }
+
+ mUsb3MmioSize = CalculateMmioSize ();
+
+ if (gBS != NULL) {
+ SmmBase = NULL;
+ Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&SmmBase);
+ if (!EFI_ERROR (Status)) {
+ SmmBase->InSmm(SmmBase, &mUsb3InSmm);
+ }
+
+ if (mUsb3InSmm) {
+ //
+ // Get SMRAM information
+ //
+ SmmAccess = NULL;
+ Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (mSmramCheckRanges);
+
+ Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramCheckRanges);
+ if (!EFI_ERROR (Status)) {
+ mSmramCheckRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+
+ Buf = NULL;
+
+ if (gBS != NULL) {
+ Address = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *)(UINTN)Address;
+ }
+ }
+
+ return Buf;
+}
+
+/**
+ Check whether AllocatePages in permanent memory is ready.
+
+ @retval TRUE AllocatePages in permanent memory is ready.
+ @retval FALSE AllocatePages in permanent memory is not ready.
+
+**/
+BOOLEAN
+IsAllocatePagesReady (
+ VOID
+ )
+{
+ if (gBS != NULL) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.inf b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.inf
new file mode 100644
index 0000000000..1d4b05779c
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxe.inf
@@ -0,0 +1,55 @@
+## @file
+# Usb3 debug port library.
+#
+# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Usb3DebugPortLibDxe
+ FILE_GUID = 08A575C4-D962-4ca5-8855-D3B4AE93A141
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Usb3DebugPortLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = Usb3DebugPortLibDxeConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Usb3DebugPortLibDxe.c
+ Usb3DebugPortDataTransfer.c
+ Usb3DebugPortInitialize.c
+ MiscServices.c
+ Usb3DebugPortLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ DebugFeaturePkg/DebugFeaturePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiLib
+ HobLib
+ Usb3DebugPortParameterLib
+
+[Protocols]
+ gEfiSmmAccess2ProtocolGuid ## CONSUMES
+ gEfiSmmBase2ProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciDefaultBaseAddress ## SOMETIMES_CONSUMES
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciHostWaitTimeout ## CONSUMES
+
+[FeaturePcd]
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdStatusCodeUseUsb3Serial ## CONSUMES
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.c
new file mode 100644
index 0000000000..97c3f88113
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.c
@@ -0,0 +1,828 @@
+/** @file
+ Usb3 Debug Port library instance
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <PiDxe.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PciLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/Usb3DebugPortParameterLib.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/IoMmu.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include "Usb3DebugPortLibInternal.h"
+
+extern EFI_SMRAM_DESCRIPTOR mSmramCheckRanges[MAX_SMRAM_RANGE];
+extern UINTN mSmramCheckRangeCount;
+extern BOOLEAN mUsb3InSmm;
+extern UINT64 mUsb3MmioSize;
+extern BOOLEAN mUsb3GetCapSuccess;
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+USB3_DEBUG_PORT_CONTROLLER mUsb3DebugPort;
+USB3_DEBUG_PORT_INSTANCE *mUsb3Instance = NULL;
+EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
+
+/**
+ Creates a named event that can be signaled.
+
+ This function creates an event using NotifyTpl, NoifyFunction.
+ If Name is NULL, then ASSERT().
+ If NotifyTpl is not a legal TPL value, then ASSERT().
+ If NotifyFunction is NULL, then ASSERT().
+
+ @param Name Supplies the GUID name of the event.
+ @param NotifyTpl Supplies the task priority level of the event notifications.
+ @param NotifyFunction Supplies the function to notify when the event is signaled.
+ @param Event A pointer to the event created.
+
+ @retval EFI_SUCCESS A named event was created.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
+
+**/
+EFI_STATUS
+EFIAPI
+Usb3NamedEventListen (
+ IN CONST EFI_GUID *Name,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction,
+ IN EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ VOID *RegistrationLocal;
+
+ ASSERT (Name != NULL);
+ ASSERT (NotifyFunction != NULL);
+ ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
+
+ //
+ // Create event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NotifyTpl,
+ NotifyFunction,
+ NULL,
+ Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for an installation of protocol interface
+ //
+ Status = gBS->RegisterProtocolNotify (
+ (EFI_GUID *) Name,
+ *Event,
+ &RegistrationLocal
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ USB3 map one DMA buffer.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Address DMA buffer address to be mapped.
+ @param NumberOfBytes Number of bytes to be mapped.
+
+**/
+VOID
+Usb3MapOneDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfBytes
+ )
+{
+ EFI_STATUS Status;
+ VOID *HostAddress;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ VOID *Mapping;
+
+ HostAddress = (VOID *) (UINTN) Address;
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ HostAddress,
+ &NumberOfBytes,
+ &DeviceAddress,
+ &Mapping
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
+}
+
+/**
+ USB3 map DMA buffers.
+
+ @param Instance Pointer to USB3 debug port instance.
+ @param PciIo Pointer to PciIo for USB3 debug port.
+
+**/
+VOID
+Usb3MapDmaBuffers (
+ IN USB3_DEBUG_PORT_INSTANCE *Instance,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->Urb.Data,
+ XHC_DEBUG_PORT_DATA_LENGTH
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingIn.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingOut.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.EventRingSeg0,
+ sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.ERSTBase,
+ sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->DebugCapabilityContext,
+ sizeof (XHC_DC_CONTEXT)
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ ((XHC_DC_CONTEXT *) (UINTN) Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
+ STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
+ );
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3DxeSmmReadyToLockNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ASSERT (mUsb3Instance != NULL);
+
+ //
+ // For the case that the USB3 debug port instance and DMA buffers are
+ // from PEI HOB with IOMMU enabled.
+ // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
+ // by SMM environment.
+ //
+ InitializeUsb3DebugPort (mUsb3Instance);
+
+ SaveUsb3InstanceAddress (mUsb3Instance);
+
+ gBS->CloseEvent (Event);
+}
+
+/**
+ USB3 get IOMMU protocol.
+
+ @return Pointer to IOMMU protocol.
+
+**/
+EDKII_IOMMU_PROTOCOL *
+Usb3GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PROTOCOL *IoMmu;
+
+ IoMmu = NULL;
+ Status = gBS->LocateProtocol (
+ &gEdkiiIoMmuProtocolGuid,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3PciIoNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN PciIoHandleCount;
+ EFI_HANDLE *PciIoHandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN PciSegment;
+ UINTN PciBusNumber;
+ UINTN PciDeviceNumber;
+ UINTN PciFunctionNumber;
+ EFI_EVENT SmmReadyToLockEvent;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &PciIoHandleCount,
+ &PciIoHandleBuffer
+ );
+ if (!EFI_ERROR (Status) &&
+ (PciIoHandleBuffer != NULL) &&
+ (PciIoHandleCount != 0)) {
+ for (Index = 0; Index < PciIoHandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ PciIoHandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
+ ASSERT_EFI_ERROR (Status);
+ if ((PciBusNumber == mUsb3DebugPort.PciAddress.Bus) &&
+ (PciDeviceNumber == mUsb3DebugPort.PciAddress.Device) &&
+ (PciFunctionNumber == mUsb3DebugPort.PciAddress.Function)) {
+ //
+ // Found the PciIo for USB3 debug port.
+ //
+ ASSERT (mUsb3Instance != NULL);
+ if (Usb3GetIoMmu () != NULL) {
+ Usb3MapDmaBuffers (mUsb3Instance, PciIo);
+
+ if (mUsb3Instance->FromHob) {
+ mUsb3PciIo = PciIo;
+ Usb3NamedEventListen (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_NOTIFY,
+ Usb3DxeSmmReadyToLockNotify,
+ &SmmReadyToLockEvent
+ );
+ }
+ }
+ gBS->CloseEvent (Event);
+ break;
+ }
+ }
+
+ gBS->FreePool (PciIoHandleBuffer);
+ }
+}
+
+/**
+ Return XHCI MMIO base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetXhciBaseAddress (
+ VOID
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT32 Low;
+ UINT32 High;
+
+ if (mUsb3DebugPort.Controller == 0) {
+ mUsb3DebugPort.Controller = GetUsb3DebugPortController();
+ }
+
+ Bus = mUsb3DebugPort.PciAddress.Bus;
+ Device = mUsb3DebugPort.PciAddress.Device;
+ Function = mUsb3DebugPort.PciAddress.Function;
+
+ Low = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
+ High = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
+ Address = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
+ //
+ // Mask other parts which are not part of base address
+ //
+ Address &= XHCI_BASE_ADDRESS_64_BIT_MASK;
+ return Address;
+}
+
+/**
+ Return XHCI debug instance address.
+
+**/
+USB3_DEBUG_PORT_INSTANCE *
+GetUsb3DebugPortInstance (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+ UINT64 CapabilityPointer;
+ UINT32 Capability;
+ BOOLEAN Flag;
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 Command;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+
+ Instance = NULL;
+
+ XhcMmioBase = GetXhciBaseAddress ();
+
+ if ((XhcMmioBase == 0) || (XhcMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
+ return NULL;
+ }
+
+ if (mUsb3Instance != NULL) {
+ FixUsb3InstanceResource (mUsb3Instance, XhcMmioBase);
+ return mUsb3Instance;
+ }
+
+ Command = GetXhciPciCommand ();
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+
+ //
+ // Set Command Register
+ //
+ if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) {
+ PciWrite16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
+ PciRead16(PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ }
+
+ //
+ // Calculate capability offset from HCCPARAMS [16:31], in 32-bit words
+ //
+ CapabilityPointer = XhcMmioBase + (MmioRead32 ((UINTN)(XhcMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
+
+ //
+ // Search XHCI debug capability
+ //
+ Flag = FALSE;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ while (TRUE) {
+ if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
+ Flag = TRUE;
+ break;
+ }
+ if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
+ //
+ // Reach the end of list, quit
+ //
+ break;
+ }
+ CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ }
+
+ if (Flag) {
+ Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN) MmioRead32 ((UINTN) (CapabilityPointer + XHC_DC_DCDDI2));
+
+ if (Instance != NULL) {
+ FixUsb3InstanceResource (Instance, XhcMmioBase);
+ }
+ }
+
+ //
+ // Restore Command Register
+ //
+ PciWrite16(PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command);
+
+ return Instance;
+}
+
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The USB3 debug port was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3Initialize (
+ VOID
+ )
+{
+ //
+ // Leave it empty, we assume PEI phase already do initialization
+ //
+ return RETURN_SUCCESS;
+}
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3InitializeReal (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE UsbDbg;
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ if ((gST == NULL) || (gBS == NULL)) {
+ //
+ // gST and gBS have not been initialized yet
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &mUsb3Instance);
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // It is first time to run DXE instance, copy Instance from Hob to ACPINvs
+ // NOTE: Hob is not ready at this time, so copy it from XHCI register.
+ //
+ Instance = GetUsb3DebugPortInstance ();
+ if (Instance == NULL) {
+ //
+ // Initialize USB debug
+ //
+ SetMem (&UsbDbg, sizeof(UsbDbg), 0);
+ DiscoverUsb3DebugPort (&UsbDbg);
+ if (UsbDbg.DebugSupport) {
+ InitializeUsb3DebugPort (&UsbDbg);
+ }
+ Instance = &UsbDbg;
+ }
+ Address = SIZE_4GB;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (USB3_DEBUG_PORT_INSTANCE)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (
+ (VOID *)(UINTN)Address,
+ Instance,
+ sizeof (USB3_DEBUG_PORT_INSTANCE)
+ );
+ mUsb3Instance = (USB3_DEBUG_PORT_INSTANCE *)(UINTN)Address;
+
+ Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, mUsb3Instance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mUsb3Instance->DebugSupport) {
+ SaveUsb3InstanceAddress (mUsb3Instance);
+ }
+
+Done:
+ if ((mUsb3Instance != NULL) && mUsb3Instance->Ready && (mUsb3Instance->PciIoEvent == 0)) {
+ Status = Usb3NamedEventListen (
+ &gEfiPciIoProtocolGuid,
+ TPL_NOTIFY,
+ Usb3PciIoNotify,
+ &Event
+ );
+ if (!EFI_ERROR (Status)) {
+ mUsb3Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS) (UINTN) Event;
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Calculate the size of XHCI MMIO space.
+
+ @retval TURE The XHCI MMIO is in SMRAM ranges.
+ @retval FALSE The XHCI MMIO is out of SMRAM ranges.
+**/
+UINT64
+CalculateMmioSize (
+ VOID
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT32 Value;
+ UINT32 Mask;
+ UINT64 MmioSize;
+ UINT16 Command;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+
+ Mask = 0xFFFFFFF0;
+ MmioSize = 0;
+
+ XhcMmioBase = GetXhciBaseAddress ();
+
+ //
+ // Disable MSE
+ //
+ Command = PciRead16 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_COMMAND_OFFSET));
+ PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command & ~(EFI_PCI_COMMAND_MEMORY_SPACE));
+
+ //
+ // Get Mmio Size
+ //
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), 0xFFFFFFFF);
+ Value = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
+
+ switch (Value & 0x07) {
+ case 0x0:
+ //
+ // Memory space: anywhere in 32 bit address space
+ //
+ MmioSize = (~(Value & Mask)) + 1;
+ break;
+ case 0x4:
+ //
+ // Memory space: anywhere in 64 bit address space
+ //
+ MmioSize = Value & Mask;
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);
+ Value = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
+ //
+ // Fix the length to support some spefic 64 bit BAR
+ //
+ Value |= ((UINT32)(-1) << HighBitSet32 (Value));
+ //
+ // Calculate the size of 64bit bar
+ //
+ MmioSize |= LShiftU64 ((UINT64) Value, 32);
+ MmioSize = (~(MmioSize)) + 1;
+ break;
+ default:
+ //
+ // Unknown BAR type
+ //
+ MmioSize = (~(Value & Mask)) + 1;
+ break;
+ };
+
+
+ //
+ // Restore MMIO address
+ //
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET), (UINT32)XhcMmioBase);
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), (UINT32) (XhcMmioBase >> 32));
+
+ PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), Command | EFI_PCI_COMMAND_MEMORY_SPACE);
+
+ return MmioSize;
+}
+
+/**
+ The constructor function initialize USB3 debug port.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+Usb3DebugPortLibDxeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_SMM_BASE2_PROTOCOL *SmmBase;
+ EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
+ UINTN Size;
+ EFI_STATUS Status;
+
+ //
+ // Do real initialization here, because we need copy data from Hob to ACPINvs.
+ // We must do it in constructor because it depends on UefiBootServicesTableLib.
+ //
+ if (FeaturePcdGet (PcdStatusCodeUseUsb3Serial)) {
+ USB3InitializeReal ();
+ }
+
+ mUsb3MmioSize = CalculateMmioSize ();
+
+ if (gBS != NULL) {
+ SmmBase = NULL;
+ Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&SmmBase);
+ if (!EFI_ERROR (Status)) {
+ SmmBase->InSmm(SmmBase, &mUsb3InSmm);
+ }
+
+ if (mUsb3InSmm) {
+ //
+ // Get SMRAM information
+ //
+ SmmAccess = NULL;
+ Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (mSmramCheckRanges);
+
+ Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramCheckRanges);
+ if (!EFI_ERROR (Status)) {
+ mSmramCheckRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+Usb3DebugPortLibDxeDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ if ((mUsb3Instance != NULL) && (mUsb3Instance->PciIoEvent != 0)) {
+ //
+ // Close the event created.
+ //
+ gBS->CloseEvent ((EFI_EVENT) (UINTN) mUsb3Instance->PciIoEvent);
+ mUsb3Instance->PciIoEvent = 0;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Pages The number of pages to allocate.
+ @param Address A pointer to store the base system memory address of the
+ allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+Usb3AllocateDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Pages,
+ OUT VOID **Address
+ )
+{
+ EFI_STATUS Status;
+
+ *Address = NULL;
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ Pages,
+ Address,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) *Address,
+ EFI_PAGES_TO_SIZE (Pages)
+ );
+ }
+ return Status;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+
+ Buf = NULL;
+
+ if (gBS != NULL) {
+ if (mUsb3PciIo != NULL) {
+ Usb3AllocateDmaBuffer (
+ mUsb3PciIo,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Buf
+ );
+ } else {
+ Address = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *)(UINTN)Address;
+ }
+ }
+ }
+
+ return Buf;
+}
+
+/**
+ Check whether AllocatePages in permanent memory is ready.
+
+ @retval TRUE AllocatePages in permanent memory is ready.
+ @retval FALSE AllocatePages in permanent memory is not ready.
+
+**/
+BOOLEAN
+IsAllocatePagesReady (
+ VOID
+ )
+{
+ if (gBS != NULL) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.inf b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.inf
new file mode 100644
index 0000000000..7e84d26864
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibDxeIoMmu.inf
@@ -0,0 +1,63 @@
+## @file
+# Usb3 debug port library.
+#
+# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Usb3DebugPortLibDxeIoMmu
+ FILE_GUID = BC48A65D-5E5E-4512-8ACC-90E79E2D80C2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Usb3DebugPortLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = Usb3DebugPortLibDxeConstructor
+ DESTRUCTOR = Usb3DebugPortLibDxeDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Usb3DebugPortLibDxeIoMmu.c
+ Usb3DebugPortDataTransfer.c
+ Usb3DebugPortInitialize.c
+ MiscServices.c
+ Usb3DebugPortLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ DebugFeaturePkg/DebugFeaturePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiLib
+ HobLib
+ Usb3DebugPortParameterLib
+
+[Protocols]
+ gEfiSmmAccess2ProtocolGuid ## CONSUMES
+ gEfiSmmBase2ProtocolGuid ## CONSUMES
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEfiPciIoProtocolGuid
+ gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ gEfiDxeSmmReadyToLockProtocolGuid
+
+[Pcd]
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciDefaultBaseAddress ## SOMETIMES_CONSUMES
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciHostWaitTimeout ## CONSUMES
+
+[FeaturePcd]
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdStatusCodeUseUsb3Serial ## CONSUMES
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibInternal.h b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibInternal.h
new file mode 100644
index 0000000000..3641cc1d52
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibInternal.h
@@ -0,0 +1,887 @@
+/** @file
+ This library class provides common Usb debug port functions.
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __USB3_DEBUG_PORT_LIB_INTERNAL__
+#define __USB3_DEBUG_PORT_LIB_INTERNAL__
+
+#include <Uefi.h>
+#include <IndustryStandard/Usb.h>
+#include <Library/IoLib.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+
+//
+// USB Debug GUID value
+//
+#define USB3_DBG_GUID \
+ { \
+ 0xb2a56f4d, 0x9177, 0x4fc8, { 0xa6, 0x77, 0xdd, 0x96, 0x3e, 0xb4, 0xcb, 0x1b } \
+ }
+
+//
+// Define the maximum of SMRAM ranges
+//
+#define MAX_SMRAM_RANGE 8
+
+#define XHCI_DEBUG_DEVICE_VENDOR_ID 0x8086
+#define XHCI_DEBUG_DEVICE_PRODUCT_ID 0x1234
+#define XHCI_DEBUG_DEVICE_PROTOCOL 0xFF
+#define XHCI_DEBUG_DEVICE_REVISION 0x00
+
+#define XHCI_BASE_ADDRESS_64_BIT_MASK 0xFFFFFFFFFFFF0000ULL
+#define XHCI_BASE_ADDRESS_32_BIT_MASK 0xFFFF0000
+
+#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A
+#define XHC_HCCPARAMS_OFFSET 0x10
+#define XHC_CAPABILITY_ID_MASK 0xFF
+#define XHC_NEXT_CAPABILITY_MASK 0xFF00
+
+#define XHC_USBCMD_OFFSET 0x0 // USB Command Register Offset
+#define XHC_USBSTS_OFFSET 0x4 // USB Status Register Offset
+
+#define XHC_USBCMD_RUN BIT0 // Run/Stop
+#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
+
+#define XHC_USBSTS_HALT BIT0
+
+//
+// Transfer the data of 8 bytes each time
+//
+#define XHC_DEBUG_PORT_DATA_LENGTH 8
+
+//
+// Indicate the timeout when data is transferred. 0 means infinite timeout.
+//
+#define DATA_TRANSFER_TIME_OUT 0
+
+//
+// USB debug device string descritpor (header size + unicode string length)
+//
+#define STRING0_DESC_LEN 4
+#define MANU_DESC_LEN 12
+#define PRODUCT_DESC_LEN 40
+#define SERIAL_DESC_LEN 4
+
+//
+// Debug Capability Register Offset
+//
+#define XHC_DC_DCID 0x0
+#define XHC_DC_DCDB 0x4
+#define XHC_DC_DCERSTSZ 0x8
+#define XHC_DC_DCERSTBA 0x10
+#define XHC_DC_DCERDP 0x18
+#define XHC_DC_DCCTRL 0x20
+#define XHC_DC_DCST 0x24
+#define XHC_DC_DCPORTSC 0x28
+#define XHC_DC_DCCP 0x30
+#define XHC_DC_DCDDI1 0x38
+#define XHC_DC_DCDDI2 0x3C
+
+#define TRB_TYPE_LINK 6
+
+#define ERST_NUMBER 0x01
+#define TR_RING_TRB_NUMBER 0x100
+#define EVENT_RING_TRB_NUMBER 0x200
+#define CMD_RING_TRB_NUMBER 0x100
+
+#define ED_BULK_OUT 2
+#define ED_BULK_IN 6
+
+#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))
+#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF))
+#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+#define XHC_REG_BIT_IS_SET(Xhc, Offset, Bit) \
+ (XHC_BIT_IS_SET(XhcReadMmioReg ((Xhc), (Offset)), (Bit)))
+
+//
+// Endpoint Type (EP Type).
+//
+#define ED_NOT_VALID 0
+#define ED_ISOCH_OUT 1
+#define ED_BULK_OUT 2
+#define ED_INTERRUPT_OUT 3
+#define ED_CONTROL_BIDIR 4
+#define ED_ISOCH_IN 5
+#define ED_BULK_IN 6
+#define ED_INTERRUPT_IN 7
+
+//
+// 6.4.5 TRB Completion Codes
+//
+#define TRB_COMPLETION_INVALID 0
+#define TRB_COMPLETION_SUCCESS 1
+#define TRB_COMPLETION_DATA_BUFFER_ERROR 2
+#define TRB_COMPLETION_BABBLE_ERROR 3
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4
+#define TRB_COMPLETION_TRB_ERROR 5
+#define TRB_COMPLETION_STALL_ERROR 6
+#define TRB_COMPLETION_SHORT_PACKET 13
+
+//
+// 6.4.6 TRB Types
+//
+#define TRB_TYPE_NORMAL 1
+#define TRB_TYPE_SETUP_STAGE 2
+#define TRB_TYPE_DATA_STAGE 3
+#define TRB_TYPE_STATUS_STAGE 4
+#define TRB_TYPE_ISOCH 5
+#define TRB_TYPE_LINK 6
+#define TRB_TYPE_EVENT_DATA 7
+#define TRB_TYPE_NO_OP 8
+#define TRB_TYPE_EN_SLOT 9
+#define TRB_TYPE_DIS_SLOT 10
+#define TRB_TYPE_ADDRESS_DEV 11
+#define TRB_TYPE_CON_ENDPOINT 12
+#define TRB_TYPE_EVALU_CONTXT 13
+#define TRB_TYPE_RESET_ENDPOINT 14
+#define TRB_TYPE_STOP_ENDPOINT 15
+#define TRB_TYPE_SET_TR_DEQUE 16
+#define TRB_TYPE_RESET_DEV 17
+#define TRB_TYPE_GET_PORT_BANW 21
+#define TRB_TYPE_FORCE_HEADER 22
+#define TRB_TYPE_NO_OP_COMMAND 23
+#define TRB_TYPE_TRANS_EVENT 32
+#define TRB_TYPE_COMMAND_COMPLT_EVENT 33
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34
+#define TRB_TYPE_HOST_CONTROLLER_EVENT 37
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38
+#define TRB_TYPE_MFINDEX_WRAP_EVENT 39
+
+//
+// Convert millisecond to microsecond.
+//
+#define XHC_1_MILLISECOND (1000)
+#define XHC_POLL_DELAY (1000)
+#define XHC_GENERIC_TIMEOUT (10 * 1000)
+
+#define EFI_USB_SPEED_FULL 0x0000 ///< 12 Mb/s, USB 1.1 OHCI and UHCI HC.
+#define EFI_USB_SPEED_LOW 0x0001 ///< 1 Mb/s, USB 1.1 OHCI and UHCI HC.
+#define EFI_USB_SPEED_HIGH 0x0002 ///< 480 Mb/s, USB 2.0 EHCI HC.
+#define EFI_USB_SPEED_SUPER 0x0003 ///< 4.8 Gb/s, USB 3.0 XHCI HC.
+
+//
+// Transfer types, used in URB to identify the transfer type
+//
+#define XHC_CTRL_TRANSFER 0x01
+#define XHC_BULK_TRANSFER 0x02
+#define XHC_INT_TRANSFER_SYNC 0x04
+#define XHC_INT_TRANSFER_ASYNC 0x08
+#define XHC_INT_ONLY_TRANSFER_ASYNC 0x10
+
+//
+// USB Transfer Results
+//
+#define EFI_USB_NOERROR 0x00
+#define EFI_USB_ERR_NOTEXECUTE 0x01
+#define EFI_USB_ERR_STALL 0x02
+#define EFI_USB_ERR_BUFFER 0x04
+#define EFI_USB_ERR_BABBLE 0x08
+#define EFI_USB_ERR_NAK 0x10
+#define EFI_USB_ERR_CRC 0x20
+#define EFI_USB_ERR_TIMEOUT 0x40
+#define EFI_USB_ERR_BITSTUFF 0x80
+#define EFI_USB_ERR_SYSTEM 0x100
+
+#define USB3_DEBUG_PORT_INSTANCE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P')
+
+#pragma pack(1)
+
+//
+// 7.6.9 OUT/IN EP Context: 64 bytes
+// 7.6.9.2 When used by the DbC it is always a 64 byte data structure
+//
+typedef struct _ENDPOINT_CONTEXT_64 {
+ UINT32 EPState:3;
+ UINT32 RsvdZ1:5;
+ UINT32 Mult:2; // set to 0
+ UINT32 MaxPStreams:5; // set to 0
+ UINT32 LSA:1; // set to 0
+ UINT32 Interval:8; // set to 0
+ UINT32 RsvdZ2:8;
+
+ UINT32 RsvdZ3:1;
+ UINT32 CErr:2;
+ UINT32 EPType:3;
+ UINT32 RsvdZ4:1;
+ UINT32 HID:1; // set to 0
+ UINT32 MaxBurstSize:8;
+ UINT32 MaxPacketSize:16;
+
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 AverageTRBLength:16;
+ UINT32 MaxESITPayload:16; // set to 0
+
+ UINT32 RsvdZ5; // Reserved
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+ UINT32 RsvdZ15;
+} ENDPOINT_CONTEXT_64;
+
+//
+// 6.4.1.1 Normal TRB: 16 bytes
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer
+// Rings, and to define the Data stage information for Control Transfer Rings.
+//
+typedef struct _TRANSFER_TRB_NORMAL {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:17;
+ UINT32 TDSize:5;
+ UINT32 IntTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 ENT:1;
+ UINT32 ISP:1;
+ UINT32 NS:1;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 IDT:1;
+ UINT32 RsvdZ1:2;
+ UINT32 BEI:1;
+ UINT32 Type:6;
+ UINT32 RsvdZ2:16;
+} TRANSFER_TRB_NORMAL;
+
+//
+// 6.4.2.1 Transfer Event TRB: 16 bytes
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1
+// for more information on the use and operation of Transfer Events.
+//
+typedef struct _EVT_TRB_TRANSFER {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length:24;
+ UINT32 Completecode:8;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:1;
+ UINT32 ED:1;
+ UINT32 RsvdZ2:7;
+ UINT32 Type:6;
+ UINT32 EndpointId:5;
+ UINT32 RsvdZ3:3;
+ UINT32 SlotId:8;
+} EVT_TRB_TRANSFER;
+
+//
+// 6.4.4.1 Link TRB: 16 bytes
+// A Link TRB provides support for non-contiguous TRB Rings.
+//
+typedef struct _LINK_TRB {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1:22;
+ UINT32 InterTarget:10;
+
+ UINT32 CycleBit:1;
+ UINT32 TC:1;
+ UINT32 RsvdZ2:2;
+ UINT32 CH:1;
+ UINT32 IOC:1;
+ UINT32 RsvdZ3:4;
+ UINT32 Type:6;
+ UINT32 RsvdZ4:16;
+} LINK_TRB;
+
+//
+// TRB Template: 16 bytes
+//
+typedef struct _TRB_TEMPLATE {
+ UINT32 Parameter1;
+
+ UINT32 Parameter2;
+
+ UINT32 Status;
+
+ UINT32 CycleBit:1;
+ UINT32 RsvdZ1:9;
+ UINT32 Type:6;
+ UINT32 Control:16;
+} TRB_TEMPLATE;
+
+//
+// Refer to XHCI 6.5 Event Ring Segment Table: 16 bytes
+//
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {
+ UINT32 PtrLo;
+ UINT32 PtrHi;
+ UINT32 RingTrbSize:16;
+ UINT32 RsvdZ1:16;
+ UINT32 RsvdZ2;
+} EVENT_RING_SEG_TABLE_ENTRY;
+
+//
+// Size: 40 bytes
+//
+typedef struct _EVENT_RING {
+ EFI_PHYSICAL_ADDRESS ERSTBase;
+ EFI_PHYSICAL_ADDRESS EventRingSeg0;
+ UINT32 TrbNumber;
+ EFI_PHYSICAL_ADDRESS EventRingEnqueue;
+ EFI_PHYSICAL_ADDRESS EventRingDequeue;
+ UINT32 EventRingCCS;
+} EVENT_RING;
+
+// Size: 32 bytes
+typedef struct _TRANSFER_RING {
+ EFI_PHYSICAL_ADDRESS RingSeg0;
+ UINT32 TrbNumber;
+ EFI_PHYSICAL_ADDRESS RingEnqueue;
+ EFI_PHYSICAL_ADDRESS RingDequeue;
+ UINT32 RingPCS;
+} TRANSFER_RING;
+
+//
+// Size: 64 bytes
+//
+typedef struct _DBC_INFO_CONTEXT {
+ UINT64 String0DescAddress;
+ UINT64 ManufacturerStrDescAddress;
+ UINT64 ProductStrDescAddress;
+ UINT64 SerialNumberStrDescAddress;
+ UINT64 String0Length:8;
+ UINT64 ManufacturerStrLength:8;
+ UINT64 ProductStrLength:8;
+ UINT64 SerialNumberStrLength:8;
+ UINT64 RsvdZ1:32;
+ UINT64 RsvdZ2;
+ UINT64 RsvdZ3;
+ UINT64 RsvdZ4;
+} DBC_INFO_CONTEXT;
+
+//
+// Debug Capability Context Data Structure: 192 bytes
+//
+typedef struct _XHC_DC_CONTEXT {
+ DBC_INFO_CONTEXT DbcInfoContext;
+ ENDPOINT_CONTEXT_64 EpOutContext;
+ ENDPOINT_CONTEXT_64 EpInContext;
+} XHC_DC_CONTEXT;
+
+//
+// Size: 16 bytes
+//
+typedef union _TRB {
+ TRB_TEMPLATE TrbTemplate;
+ TRANSFER_TRB_NORMAL TrbNormal;
+} TRB;
+
+///
+/// USB data transfer direction
+///
+typedef enum {
+ EfiUsbDataIn,
+ EfiUsbDataOut,
+ EfiUsbNoData
+} EFI_USB_DATA_DIRECTION;
+
+//
+// URB (Usb Request Block) contains information for all kinds of
+// usb requests.
+//
+typedef struct _URB {
+ UINT32 Signature;
+ //
+ // Transfer data
+ //
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT32 DataLen;
+ //
+ // Execute result
+ //
+ UINT32 Result;
+ //
+ // Completed data length
+ //
+ UINT32 Completed;
+ //
+ // Tranfer Ring info
+ //
+ EFI_PHYSICAL_ADDRESS Ring;
+ EFI_PHYSICAL_ADDRESS TrbStart;
+ EFI_PHYSICAL_ADDRESS TrbEnd;
+ UINT32 TrbNum;
+ BOOLEAN StartDone;
+ BOOLEAN EndDone;
+ BOOLEAN Finished;
+ EFI_USB_DATA_DIRECTION Direction;
+} URB;
+
+//
+// Size: 90 bytes
+//
+typedef struct _USB3_DEBUG_PORT_INSTANCE {
+ UINT32 Signature;
+
+ UINT8 PciBusNumber;
+ UINT8 PciDeviceNumber;
+ UINT8 PciFunctionNumber;
+
+ //
+ // The flag indicates debug capability is supported
+ //
+ BOOLEAN DebugSupport;
+
+ //
+ // The flag indicates debug device is ready
+ //
+ BOOLEAN Ready;
+
+ //
+ // The flag indicates the instance is from HOB
+ //
+ BOOLEAN FromHob;
+
+ //
+ // PciIo protocol event
+ //
+ EFI_PHYSICAL_ADDRESS PciIoEvent;
+
+ //
+ // XHCI MMIO Base address
+ //
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+
+ //
+ // XHCI OP RegisterBase address
+ //
+ EFI_PHYSICAL_ADDRESS XhciOpRegister;
+
+ //
+ // XHCI Debug Register Base Address
+ //
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ //
+ // XHCI Debug Capability offset
+ //
+ UINT64 DebugCapabilityOffset;
+
+ //
+ // XHCI Debug Context Address
+ //
+ EFI_PHYSICAL_ADDRESS DebugCapabilityContext;
+
+ //
+ // Transfer Ring
+ //
+ TRANSFER_RING TransferRingOut;
+ TRANSFER_RING TransferRingIn;
+
+ //
+ // EventRing
+ //
+ EVENT_RING EventRing;
+
+ //
+ // URB
+ //
+ URB Urb;
+} USB3_DEBUG_PORT_INSTANCE;
+
+#pragma pack()
+
+/**
+ Clear one bit of the debug register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcClearDebugRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Clear one bit of the MMIO register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the MMIO register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcClearMmioRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Read XHCI debug register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the debug register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadDebugReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Read XHCI MMIO register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the MMIO register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadMmioReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset
+ );
+
+/**
+ Set one bit of the debug register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetDebugRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Set one bit of the MMIO register while keeping other bits.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the MMIO register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetMmioRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Wait the MMIO register's bit as specified by Bit
+ to be set (or clear).
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the MMIO register.
+ @param Bit The bit of the register to wait for.
+ @param WaitToSet Wait the bit to set or clear.
+ @param Timeout The time to wait before abort (in millisecond, ms).
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+XhcWaitMmioRegBit (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Bit,
+ IN BOOLEAN WaitToSet,
+ IN UINT32 Timeout
+ );
+
+/**
+ Write the data to the debug register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the debug register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDebugReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Write the data to the MMIO register.
+
+ @param Xhc The XHCI Instance.
+ @param Offset The offset of the MMIO register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteMmioReg (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Discover the USB3 debug device.
+
+ @param[in] Instance Pointer to USB3 debug port object instance.
+
+ @retval RETURN_SUCCESS The USB3 debug device was found.
+ @retval RETURN_DEVICE_ERROR The USB3 debug device was not found.
+
+**/
+RETURN_STATUS
+DiscoverUsb3DebugPort(
+ IN USB3_DEBUG_PORT_INSTANCE *Instance
+ );
+
+/**
+ Initialize the USB3 debug Device hardware.
+
+ @param[in] Instance Pointer to USB3 debug port object instance.
+
+ @retval RETURN_SUCCESS The USB3 debug device was initialized successfully.
+ @retval !RETURN_SUCCESS Error.
+
+**/
+RETURN_STATUS
+InitializeUsb3DebugPort (
+ IN USB3_DEBUG_PORT_INSTANCE *Instance
+ );
+
+/**
+ Return XHCI MMIO base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetXhciBaseAddress (
+ VOID
+ );
+
+/**
+ Return XHCI debug instance address.
+
+**/
+USB3_DEBUG_PORT_INSTANCE *
+GetUsb3DebugPortInstance (
+ VOID
+ );
+
+/**
+ Send data over the USB3 debug cable.
+
+ @param[out] Data Pointer to data
+ @param[in, out] Length Pointer to data length
+
+**/
+VOID
+Usb3DbgOut (
+ OUT UINT8 *Data,
+ IN OUT UINTN *Length
+ );
+
+/**
+ Receive data over the USB3 debug cable.
+
+ @param[out] Data Pointer to data
+ @param[in, out] Length Pointer to data length
+
+**/
+RETURN_STATUS
+Usb3DbgIn (
+ OUT UINT8 *Data,
+ IN OUT UINTN *Length
+ );
+
+/**
+ Verifies if the bit positions specified by a mask are set in a register.
+
+ @param[in, out] Register UNITN register
+ @param[in] BitMask 32-bit mask
+
+ @return BOOLEAN - TRUE if all bits specified by the mask are enabled.
+ - FALSE even if one of the bits specified by the mask
+ is not enabled.
+**/
+BOOLEAN
+XhcIsBitSet(
+ UINTN Register,
+ UINT32 BitMask
+ );
+
+/**
+ Sets bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcSetR32Bit(
+ UINTN Register,
+ UINT32 BitMask
+ );
+
+/**
+ Clears bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcClrR32Bit(
+ UINTN Register,
+ UINT32 BitMask
+ );
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3Initialize (
+ VOID
+ );
+
+/**
+ Return command register value in XHCI controller.
+
+**/
+UINT16
+GetXhciPciCommand (
+ VOID
+ );
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ );
+
+/**
+ Check whether AllocatePages in permanent memory is ready.
+
+ @retval TRUE AllocatePages in permanent memory is ready.
+ @retval FALSE AllocatePages in permanent memory is not ready.
+
+**/
+BOOLEAN
+IsAllocatePagesReady (
+ VOID
+ );
+
+/**
+ The real function to initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3InitializeReal (
+ VOID
+ );
+
+/**
+ Update XHC hardware address when MMIO base is changed.
+
+ @param Instance The XHCI Instance.
+ @param XhcMmioBase XHCI MMIO base address.
+
+**/
+VOID
+FixUsb3InstanceResource (
+ IN OUT USB3_DEBUG_PORT_INSTANCE *Instance,
+ IN EFI_PHYSICAL_ADDRESS XhcMmioBase
+ );
+
+/**
+ Save USB3 instance address.
+
+ @param[in] Instance The XHCI Instance.
+
+**/
+VOID
+SaveUsb3InstanceAddress (
+ IN USB3_DEBUG_PORT_INSTANCE *Instance
+ );
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param Xhc The instance of debug device.
+ @param Direction The direction of data transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The lenght of the data buffer.
+ @param Timeout Indicates the maximum time, in millisecond, which
+ the transfer is allowed to complete.
+ @param TransferResult Transfer result.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDataTransfer (
+ IN USB3_DEBUG_PORT_INSTANCE *Xhc,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *TransferResult
+ );
+
+#endif //__SERIAL_PORT_LIB_USB__
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.c
new file mode 100644
index 0000000000..319cebecbb
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.c
@@ -0,0 +1,103 @@
+/** @file
+ Usb Debug Port library NULL instance
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+/**
+ Initialize the USB3 debug port hardware.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+ If the serial device was successfully initialized, then return RETURN_SUCCESS.
+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+ @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+Usb3DebugPortInitialize (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ Write data from buffer to USB3 debug port.
+
+ Writes NumberOfBytes data bytes from Buffer to the serial device.
+ The number of bytes actually written to the serial device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If Buffer is NULL, then ASSERT().
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the serial device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+Usb3DebugPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ return 0;
+}
+
+
+/**
+ Read data from USB3 debug port and save the datas in buffer.
+
+ Reads NumberOfBytes data bytes from a serial device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If Buffer is NULL, then ASSERT().
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to store the data read from the serial device.
+ @param NumberOfBytes Number of bytes which will be read.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from serial device.
+
+**/
+UINTN
+EFIAPI
+Usb3DebugPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ return 0;
+}
+
+/**
+ Polls a USB3 debug port to see if there is any data waiting to be read.
+
+ Polls a serial device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the serial device, then TRUE is returned.
+ If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+ @retval TRUE Data is waiting to be read from the serial device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+Usb3DebugPortPoll (
+ VOID
+ )
+{
+ return FALSE;
+}
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.inf b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.inf
new file mode 100644
index 0000000000..f632150c26
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibNull.inf
@@ -0,0 +1,28 @@
+## @file
+# Usb3 debug port library.
+#
+# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = USB3DebugPortLibNull
+ FILE_GUID = 3E895F08-0A69-42a2-AF4A-3E9EFAA40361
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Usb3DebugPortLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Usb3DebugPortLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.c
new file mode 100644
index 0000000000..a1e0bdbf6d
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.c
@@ -0,0 +1,236 @@
+/** @file
+ Usb Debug Port library instance
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <PiPei.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/Usb3DebugPortParameterLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Ppi/MemoryDiscovered.h>
+#include "Usb3DebugPortLibInternal.h"
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+/**
+ Return XHCI MMIO base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetXhciBaseAddress (
+ VOID
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT32 Low;
+ UINT32 High;
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+ Low = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
+ High = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
+ Address = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
+
+ //
+ // Mask other parts which are not part of base address
+ //
+ Address &= XHCI_BASE_ADDRESS_64_BIT_MASK;
+ return Address;
+}
+
+/**
+ Return XHCI debug instance address.
+
+**/
+USB3_DEBUG_PORT_INSTANCE *
+GetUsb3DebugPortInstance (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+
+ Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
+ if (Hob.Raw == NULL) {
+ return NULL;
+ }
+ Instance = GET_GUID_HOB_DATA (Hob.Guid);
+
+ //
+ // Update XHCI MMIO base address
+ //
+ XhcMmioBase = GetXhciBaseAddress ();
+
+ FixUsb3InstanceResource (Instance, XhcMmioBase);
+
+ return Instance;
+}
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3Initialize (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3InitializeReal (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE UsbDbg;
+ VOID *DataPtr;
+ EFI_PEI_HOB_POINTERS Hob;
+
+ //
+ // USB Initilization has to be done only once. So this function should just return when
+ // it is called more than once.
+ //
+ Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
+ if (Hob.Raw != NULL) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // Initialize USB debug for PEI at the first time
+ //
+ SetMem (&UsbDbg, sizeof(UsbDbg), 0);
+ UsbDbg.FromHob = TRUE;
+ DiscoverUsb3DebugPort (&UsbDbg);
+ if (UsbDbg.DebugSupport) {
+ InitializeUsb3DebugPort (&UsbDbg);
+ }
+
+ //
+ // Save Instance into HOB
+ //
+ DataPtr = BuildGuidDataHob (
+ &gUsb3DbgGuid,
+ (VOID*) &UsbDbg,
+ sizeof (UsbDbg)
+ );
+
+ if (UsbDbg.DebugSupport) {
+ SaveUsb3InstanceAddress ((USB3_DEBUG_PORT_INSTANCE *) DataPtr);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS Address;
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_STATUS Status;
+ VOID *MemoryDiscoveredPpi;
+
+ Buf = NULL;
+ PeiServices = GetPeiServicesTablePointer ();
+
+ //
+ // Make sure the allocated memory is physical memory.
+ //
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &MemoryDiscoveredPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = (*PeiServices)->AllocatePages (
+ PeiServices,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *)(UINTN) Address;
+ }
+ }
+ return Buf;
+}
+
+/**
+ Check whether AllocatePages in permanent memory is ready.
+
+ @retval TRUE AllocatePages in permanent memory is ready.
+ @retval FALSE AllocatePages in permanent memory is not ready.
+
+**/
+BOOLEAN
+IsAllocatePagesReady (
+ VOID
+ )
+{
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_STATUS Status;
+ VOID *MemoryDiscoveredPpi;
+
+ PeiServices = GetPeiServicesTablePointer ();
+
+ //
+ // Make sure the allocated memory is physical memory.
+ //
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &MemoryDiscoveredPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.inf b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.inf
new file mode 100644
index 0000000000..bc65c06f72
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPei.inf
@@ -0,0 +1,48 @@
+## @file
+# Usb3 debug port library.
+#
+# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = USB3DebugPortLibPei
+ FILE_GUID = 62C974F0-D0E0-4963-B93A-22FBCEB69AB4
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Usb3DebugPortLib|PEIM PEI_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Usb3DebugPortLibPei.c
+ Usb3DebugPortDataTransfer.c
+ Usb3DebugPortInitialize.c
+ MiscServices.c
+ Usb3DebugPortLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ DebugFeaturePkg/DebugFeaturePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ HobLib
+ Usb3DebugPortParameterLib
+ PeiServicesTablePointerLib
+
+[Ppis]
+ gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
+
+[Pcd]
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciDefaultBaseAddress ## SOMETIMES_CONSUMES
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciHostWaitTimeout ## CONSUMES
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.c
new file mode 100644
index 0000000000..68543c8562
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.c
@@ -0,0 +1,440 @@
+/** @file
+ Usb Debug Port library instance
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+
+#include <PiPei.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/Usb3DebugPortParameterLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Ppi/IoMmu.h>
+#include "Usb3DebugPortLibInternal.h"
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+/**
+ USB3 IOMMU PPI notify.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+Usb3IoMmuPpiNotify (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+ //
+ // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI.
+ //
+ InitializeUsb3DebugPort (Instance);
+
+ SaveUsb3InstanceAddress (Instance);
+
+ return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiIoMmuPpiGuid,
+ Usb3IoMmuPpiNotify
+};
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+ *Mapping = NULL;
+
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiRuntimeServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = IoMmu->Map (
+ IoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *HostAddress = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->Unmap (IoMmu, *Mapping);
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *Mapping = NULL;
+ *HostAddress = NULL;
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ USB3 get IOMMU PPI.
+
+ @return Pointer to IOMMU PPI.
+
+**/
+EDKII_IOMMU_PPI *
+Usb3GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+ CONST EFI_PEI_SERVICES **PeiServices;
+
+ PeiServices = GetPeiServicesTablePointer ();
+
+ IoMmu = NULL;
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Return XHCI MMIO base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetXhciBaseAddress (
+ VOID
+ )
+{
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT32 Low;
+ UINT32 High;
+
+ UsbDebugPort.Controller = GetUsb3DebugPortController();
+ Bus = UsbDebugPort.PciAddress.Bus;
+ Device = UsbDebugPort.PciAddress.Device;
+ Function = UsbDebugPort.PciAddress.Function;
+ Low = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET));
+ High = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
+ Address = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
+
+ //
+ // Mask other parts which are not part of base address
+ //
+ Address &= XHCI_BASE_ADDRESS_64_BIT_MASK;
+ return Address;
+}
+
+/**
+ Return XHCI debug instance address.
+
+**/
+USB3_DEBUG_PORT_INSTANCE *
+GetUsb3DebugPortInstance (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_INSTANCE *Instance;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS XhcMmioBase;
+
+ Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
+ if (Hob.Raw == NULL) {
+ return NULL;
+ }
+ Instance = GET_GUID_HOB_DATA (Hob.Guid);
+
+ //
+ // Update XHCI MMIO base address
+ //
+ XhcMmioBase = GetXhciBaseAddress ();
+
+ FixUsb3InstanceResource (Instance, XhcMmioBase);
+
+ return Instance;
+}
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3Initialize (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3InitializeReal (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ USB3_DEBUG_PORT_INSTANCE UsbDbg;
+ VOID *DataPtr;
+ EFI_PEI_HOB_POINTERS Hob;
+ CONST EFI_PEI_SERVICES **PeiServices;
+
+ PeiServices = GetPeiServicesTablePointer ();
+
+ //
+ // USB Initilization has to be done only once. So this function should just return when
+ // it is called more than once.
+ //
+ Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
+ if (Hob.Raw != NULL) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // Initialize USB debug for PEI at the first time
+ //
+ SetMem (&UsbDbg, sizeof(UsbDbg), 0);
+ UsbDbg.FromHob = TRUE;
+ DiscoverUsb3DebugPort (&UsbDbg);
+ if (UsbDbg.DebugSupport) {
+ InitializeUsb3DebugPort (&UsbDbg);
+ }
+
+ if (UsbDbg.Ready && (Usb3GetIoMmu () == NULL)) {
+ Status = (*PeiServices)->NotifyPpi (PeiServices, &mUsb3IoMmuPpiNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Save Instance into HOB
+ //
+ DataPtr = BuildGuidDataHob (
+ &gUsb3DbgGuid,
+ (VOID*) &UsbDbg,
+ sizeof (UsbDbg)
+ );
+
+ if (UsbDbg.DebugSupport) {
+ SaveUsb3InstanceAddress ((USB3_DEBUG_PORT_INSTANCE *) DataPtr);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS Address;
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_STATUS Status;
+ VOID *MemoryDiscoveredPpi;
+ EDKII_IOMMU_PPI *IoMmu;
+ VOID *HostAddress;
+ VOID *Mapping;
+
+ Buf = NULL;
+ PeiServices = GetPeiServicesTablePointer ();
+
+ //
+ // Make sure the allocated memory is physical memory.
+ //
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &MemoryDiscoveredPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ IoMmu = Usb3GetIoMmu ();
+ if (IoMmu != NULL) {
+ Status = IoMmuAllocateBuffer (
+ IoMmu,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &HostAddress,
+ &Address,
+ &Mapping
+ );
+ if (!EFI_ERROR (Status)) {
+ ASSERT (Address == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
+ Buf = (VOID *)(UINTN) Address;
+ }
+ } else {
+ Status = (*PeiServices)->AllocatePages (
+ PeiServices,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *)(UINTN) Address;
+ }
+ }
+ }
+ return Buf;
+}
+
+/**
+ Check whether AllocatePages in permanent memory is ready.
+
+ @retval TRUE AllocatePages in permanent memory is ready.
+ @retval FALSE AllocatePages in permanent memory is not ready.
+
+**/
+BOOLEAN
+IsAllocatePagesReady (
+ VOID
+ )
+{
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_STATUS Status;
+ VOID *MemoryDiscoveredPpi;
+ EDKII_IOMMU_PPI *IoMmu;
+ VOID *HostAddress;
+
+ PeiServices = GetPeiServicesTablePointer ();
+
+ //
+ // Make sure the allocated memory is physical memory.
+ //
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &MemoryDiscoveredPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiRuntimeServicesData,
+ 1,
+ &HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // DMA protection has been enabled,
+ // but DMA buffer could not be allocated yet.
+ //
+ return FALSE;
+ }
+ IoMmu->FreeBuffer (
+ IoMmu,
+ 1,
+ HostAddress
+ );
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.inf b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.inf
new file mode 100644
index 0000000000..c351aa0234
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortLib/Usb3DebugPortLibPeiIoMmu.inf
@@ -0,0 +1,51 @@
+## @file
+# Usb3 debug port library.
+#
+# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = USB3DebugPortLibPeiIoMmu
+ FILE_GUID = C973C5E8-A0D8-4FEE-A0F0-7DA6C3C72451
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Usb3DebugPortLib|PEIM PEI_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Usb3DebugPortLibPeiIoMmu.c
+ Usb3DebugPortDataTransfer.c
+ Usb3DebugPortInitialize.c
+ MiscServices.c
+ Usb3DebugPortLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ DebugFeaturePkg/DebugFeaturePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ HobLib
+ Usb3DebugPortParameterLib
+ PeiServicesTablePointerLib
+
+[Ppis]
+ gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciDefaultBaseAddress ## SOMETIMES_CONSUMES
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdXhciHostWaitTimeout ## CONSUMES
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.c b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.c
new file mode 100644
index 0000000000..747c5dccc9
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.c
@@ -0,0 +1,58 @@
+/** @file
+ USB3 debug Port Parameter library instance based on PCD.
+
+ Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/Usb3DebugPortParameterLib.h>
+
+/**
+ Returns the USB3 debug port controller.
+ bit: 0~ 7: Function
+ bit: 8~15: Device
+ bit: 16~24: Bus
+
+ @return Controller information of USB debug port.
+
+**/
+UINT32
+EFIAPI
+GetUsb3DebugPortController (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_CONTROLLER UsbDebugPort;
+
+ UsbDebugPort.Controller = 0;
+ UsbDebugPort.PciAddress.Bus = PcdGet8(PcdUsbSerialXhciBus);
+ UsbDebugPort.PciAddress.Device = PcdGet8(PcdUsbSerialXhciDev);
+ UsbDebugPort.PciAddress.Function = PcdGet8(PcdUsbSerialXhciFunc);
+
+ return UsbDebugPort.Controller;
+}
+
+/**
+ Sets the USB debug port controller.
+ bit: 0~ 7: Function
+ bit: 8~15: Device
+ bit: 16~24: Bus
+
+ @param[in] Controller information of USB debug port value to be set.
+
+ @retval TRUE The controller of USB debug port was sucessfully set.
+ @retval FALSE The controller of USB debug port could not be set.
+
+**/
+BOOLEAN
+EFIAPI
+SetUsb3DebugPortController (
+ UINT32 Controller
+ )
+{
+ return FALSE;
+}
diff --git a/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.inf b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.inf
new file mode 100644
index 0000000000..48fdd4800c
--- /dev/null
+++ b/Platform/Intel/DebugFeaturePkg/Library/Usb3DebugPortParameterLibPcd/Usb3DebugPortParameterLibPcd.inf
@@ -0,0 +1,31 @@
+## @file
+# USB3 debug Port Parameter library instance based on PCD.
+#
+# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Usb3DebugPortParameterLibPcd
+ FILE_GUID = 4990A700-4002-4d08-8E00-622720032662
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Usb3DebugPortParameterLib
+
+[Sources]
+ Usb3DebugPortParameterLibPcd.c
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ DebugFeaturePkg/DebugFeaturePkg.dec
+
+[Pcd]
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsbSerialXhciBus ## CONSUMES
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsbSerialXhciDev ## CONSUMES
+ gEfiUsb3DebugPortTokenSpaceGuid.PcdUsbSerialXhciFunc ## CONSUMES
--
2.21.0.windows.1
^ permalink raw reply related [flat|nested] 5+ messages in thread