--- /dev/null
+/** @file\r
+ Debug Port Library implementation based on usb3 debug port.\r
+\r
+ Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DebugCommunicationLibUsb3Internal.h"\r
+\r
+//\r
+// The global variable which can be used after memory is ready.\r
+//\r
+USB3_DEBUG_PORT_HANDLE mDebugCommunicationLibUsb3DebugPortHandle;\r
+\r
+UINT16 mString0Desc[] = {\r
+ // String Descriptor Type + Length\r
+ ( USB_DESC_TYPE_STRING << 8 ) + STRING0_DESC_LEN,\r
+ 0x0409\r
+};\r
+\r
+UINT16 mManufacturerStrDesc[] = {\r
+ // String Descriptor Type + Length\r
+ ( USB_DESC_TYPE_STRING << 8 ) + MANU_DESC_LEN,\r
+ 'I', 'n', 't', 'e', 'l'\r
+};\r
+\r
+UINT16 mProductStrDesc[] = {\r
+ // String Descriptor Type + Length\r
+ ( USB_DESC_TYPE_STRING << 8 ) + PRODUCT_DESC_LEN,\r
+ 'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'\r
+};\r
+\r
+UINT16 mSerialNumberStrDesc[] = {\r
+ // String Descriptor Type + Length\r
+ ( USB_DESC_TYPE_STRING << 8 ) + SERIAL_DESC_LEN,\r
+ '1'\r
+};\r
+\r
+/**\r
+ Sets bits as per the enabled bit positions in the mask.\r
+\r
+ @param[in, out] Register UINTN register\r
+ @param[in] BitMask 32-bit mask\r
+**/\r
+VOID\r
+XhcSetR32Bit(\r
+ IN OUT UINTN Register, \r
+ IN UINT32 BitMask\r
+ )\r
+{\r
+ UINT32 RegisterValue;\r
+\r
+ RegisterValue = MmioRead32 (Register);\r
+ RegisterValue |= (UINT32)(BitMask);\r
+ MmioWrite32 (Register, RegisterValue);\r
+}\r
+\r
+/**\r
+ Clears bits as per the enabled bit positions in the mask.\r
+\r
+ @param[in, out] Register UINTN register\r
+ @param[in] BitMask 32-bit mask\r
+**/\r
+VOID\r
+XhcClearR32Bit(\r
+ IN OUT UINTN Register, \r
+ IN UINT32 BitMask\r
+ )\r
+{\r
+ UINT32 RegisterValue;\r
+\r
+ RegisterValue = MmioRead32 (Register);\r
+ RegisterValue &= ~BitMask;\r
+ MmioWrite32 (Register, RegisterValue);\r
+}\r
+\r
+/**\r
+ Write the data to the XHCI debug register.\r
+\r
+ @param Handle Debug port handle.\r
+ @param Offset The offset of the runtime register.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteDebugReg (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;\r
+ \r
+ DebugCapabilityBase = Handle->DebugCapabilityBase;\r
+ MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);\r
+ \r
+ return;\r
+}\r
+\r
+/**\r
+ Read XHCI debug register.\r
+\r
+ @param Handle Debug port handle.\r
+ @param Offset The offset of the runtime register.\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadDebugReg (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;\r
+ \r
+ DebugCapabilityBase = Handle->DebugCapabilityBase;\r
+ Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));\r
+\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Set one bit of the runtime register while keeping other bits.\r
+\r
+ @param Handle Debug port handle.\r
+ @param Offset The offset of the runtime register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcSetDebugRegBit (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = XhcReadDebugReg (Handle, Offset);\r
+ Data |= Bit;\r
+ XhcWriteDebugReg (Handle, Offset, Data);\r
+}\r
+\r
+/**\r
+ Program and eanble XHCI MMIO base address.\r
+\r
+ @return XHCI MMIO base address.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+ProgramXhciBaseAddress (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 PciCmd;\r
+ UINT32 Low;\r
+ UINT32 High;\r
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
+ \r
+ Low = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);\r
+ High = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);\r
+ XhciMmioBase = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);\r
+ XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;\r
+\r
+ if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {\r
+ XhciMmioBase = PcdGet64(PcdUsbXhciMemorySpaceBase);\r
+ PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);\r
+ PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));\r
+ }\r
+\r
+ PciCmd = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);\r
+ if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {\r
+ PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;\r
+ PciWrite16(PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);\r
+ }\r
+\r
+ return XhciMmioBase;\r
+}\r
+\r
+/**\r
+ Check if the timer is timeout.\r
+ \r
+ @param[in] UsbDebugPortHandle Pointer to USB Debug port handle\r
+ @param[in] Timer The start timer from the begin.\r
+ @param[in] TimeoutTicker Ticker number need time out.\r
+\r
+ @return TRUE Timer time out occurs.\r
+ @retval FALSE Timer does not time out.\r
+\r
+**/\r
+BOOLEAN\r
+IsTimerTimeout (\r
+ IN USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle,\r
+ IN UINT64 Timer,\r
+ IN UINT64 TimeoutTicker\r
+ )\r
+{\r
+ UINT64 CurrentTimer;\r
+ UINT64 Delta;\r
+\r
+ CurrentTimer = GetPerformanceCounter ();\r
+\r
+ if (UsbDebugPortHandle->TimerCountDown) {\r
+ //\r
+ // The timer counter counts down. Check for roll over condition.\r
+ //\r
+ if (CurrentTimer < Timer) {\r
+ Delta = Timer - CurrentTimer;\r
+ } else {\r
+ //\r
+ // Handle one roll-over. \r
+ //\r
+ Delta = UsbDebugPortHandle->TimerCycle - (CurrentTimer - Timer);\r
+ }\r
+ } else {\r
+ //\r
+ // The timer counter counts up. Check for roll over condition.\r
+ //\r
+ if (CurrentTimer > Timer) {\r
+ Delta = CurrentTimer - Timer;\r
+ } else {\r
+ //\r
+ // Handle one roll-over. \r
+ //\r
+ Delta = UsbDebugPortHandle->TimerCycle - (Timer - CurrentTimer);\r
+ }\r
+ }\r
+ \r
+ return (BOOLEAN) (Delta >= TimeoutTicker);\r
+}\r
+\r
+/**\r
+ Update XHC MMIO base address when MMIO base address is changed.\r
+\r
+ @param Handle Debug port handle.\r
+ @param XhciMmioBase XHCI MMIO base address.\r
+\r
+**/\r
+VOID\r
+UpdateXhcResource (\r
+ IN OUT USB3_DEBUG_PORT_HANDLE *Handle,\r
+ IN EFI_PHYSICAL_ADDRESS XhciMmioBase\r
+ )\r
+{\r
+ if ((Handle == NULL) || (Handle->XhciMmioBase == XhciMmioBase)) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Need fix Handle data according to new XHCI MMIO base address.\r
+ //\r
+ Handle->XhciMmioBase = XhciMmioBase;\r
+ Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;\r
+ Handle->XhciOpRegister = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);\r
+}\r
+\r
+/**\r
+ Calculate the usb debug port bar address.\r
+\r
+ @param Handle Debug port handle.\r
+\r
+ @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.\r
+ @retval RETURN_SUCCESS Get bar and offset successfully.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+CalculateUsbDebugPortMmioBase (\r
+ USB3_DEBUG_PORT_HANDLE *Handle\r
+ )\r
+{\r
+ UINT16 VendorId;\r
+ UINT16 DeviceId;\r
+ UINT8 ProgInterface;\r
+ UINT8 SubClassCode;\r
+ UINT8 BaseCode;\r
+ BOOLEAN Flag;\r
+ UINT32 Capability;\r
+ EFI_PHYSICAL_ADDRESS CapabilityPointer;\r
+ UINT8 CapLength;\r
+\r
+ VendorId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);\r
+ DeviceId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);\r
+ \r
+ if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {\r
+ goto Done;\r
+ }\r
+\r
+ ProgInterface = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);\r
+ SubClassCode = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);\r
+ BaseCode = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);\r
+ \r
+ if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {\r
+ goto Done;\r
+ }\r
+\r
+ CapLength = MmioRead8 ((UINTN) Handle->XhciMmioBase);\r
+\r
+ //\r
+ // Get capability pointer from HCCPARAMS at offset 0x10\r
+ //\r
+ CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;\r
+ \r
+ //\r
+ // Search XHCI debug capability\r
+ //\r
+ Flag = FALSE;\r
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);\r
+ while (TRUE) {\r
+ if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {\r
+ Flag = TRUE;\r
+ break;\r
+ }\r
+ if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {\r
+ //\r
+ // Reach the end of capability list, quit\r
+ //\r
+ break;\r
+ }\r
+ CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;\r
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);\r
+ }\r
+\r
+ if (!Flag) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // USB3 debug capability is supported.\r
+ //\r
+ Handle->DebugCapabilityBase = CapabilityPointer;\r
+ Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;\r
+ Handle->XhciOpRegister = Handle->XhciMmioBase + CapLength;\r
+ Handle->Initialized = USB3DBG_DBG_CAB;\r
+ return RETURN_SUCCESS;\r
+\r
+Done:\r
+ Handle->Initialized = USB3DBG_NO_DBG_CAB;\r
+ return RETURN_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Check if it needs to re-initialize usb debug port hardware.\r
+\r
+ During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check\r
+ whether the usb debug port hardware configuration is changed. Such case can be triggerred by\r
+ Pci bus resource allocation and so on.\r
+\r
+ @param Handle Debug port handle.\r
+\r
+ @retval TRUE The usb debug port hardware configuration is changed.\r
+ @retval FALSE The usb debug port hardware configuration is not changed.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+NeedReinitializeHardware(\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle\r
+ )\r
+{\r
+ BOOLEAN Result;\r
+ volatile UINT32 Dcctrl;\r
+\r
+ Result = FALSE;\r
+\r
+ //\r
+ // If DCE bit, it means USB3 debug is not enabled.\r
+ //\r
+ Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);\r
+ if ((Dcctrl & BIT0) == 0) {\r
+ Result = TRUE;\r
+ }\r
+\r
+ return Result;\r
+}\r
+\r
+/**\r
+ Create XHCI event ring.\r
+\r
+ @param Handle Debug port handle.\r
+ @param EventRing The created event ring.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateEventRing (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle,\r
+ OUT EVENT_RING *EventRing\r
+ )\r
+{\r
+ VOID *Buf;\r
+ EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
+\r
+ ASSERT (EventRing != NULL);\r
+ \r
+ //\r
+ // Allocate Event Ring\r
+ //\r
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
+ ASSERT (Buf != NULL);\r
+ ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
+\r
+ EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;\r
+ EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
+ EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;\r
+ EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;\r
+ \r
+ //\r
+ // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
+ // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
+ //\r
+ EventRing->EventRingCCS = 1;\r
+\r
+ //\r
+ // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table\r
+ //\r
+ Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
+ ASSERT (Buf != NULL);\r
+ ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+ ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
+\r
+ ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
+ EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;\r
+\r
+ //\r
+ // Fill Event Segment address\r
+ //\r
+ ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);\r
+ ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);\r
+ ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
+\r
+ //\r
+ // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)\r
+ //\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCERDP,\r
+ XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)\r
+ );\r
+\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCERDP + 4,\r
+ XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)\r
+ );\r
+\r
+ //\r
+ // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)\r
+ //\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCERSTBA,\r
+ XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)\r
+ );\r
+\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCERSTBA + 4,\r
+ XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)\r
+ );\r
+\r
+ //\r
+ // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)\r
+ //\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCERSTSZ,\r
+ ERST_NUMBER\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create XHCI transfer ring.\r
+\r
+ @param Handle Debug port handle.\r
+ @param TrbNum The number of TRB in the ring.\r
+ @param TransferRing The created transfer ring.\r
+\r
+**/\r
+VOID\r
+CreateTransferRing (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle,\r
+ IN UINT32 TrbNum,\r
+ OUT TRANSFER_RING *TransferRing\r
+ )\r
+{\r
+ VOID *Buf;\r
+ LINK_TRB *EndTrb;\r
+ \r
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);\r
+ ASSERT (Buf != NULL);\r
+ ASSERT (((UINTN) Buf & 0xF) == 0);\r
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
+\r
+ TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;\r
+ TransferRing->TrbNumber = TrbNum;\r
+ TransferRing->RingEnqueue = TransferRing->RingSeg0;\r
+ TransferRing->RingDequeue = TransferRing->RingSeg0;\r
+ TransferRing->RingPCS = 1;\r
+ //\r
+ // 4.9.2 Transfer Ring Management\r
+ // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
+ // point to the first TRB in the ring.\r
+ //\r
+ EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
+ EndTrb->Type = TRB_TYPE_LINK;\r
+ EndTrb->PtrLo = XHC_LOW_32BIT (Buf);\r
+ EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);\r
+ //\r
+ // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
+ //\r
+ EndTrb->TC = 1;\r
+ //\r
+ // Set Cycle bit as other TRB PCS init value\r
+ //\r
+ EndTrb->CycleBit = 0;\r
+}\r
+\r
+/**\r
+ Create debug capability context for XHC debug device.\r
+\r
+ @param Handle Debug port handle.\r
+\r
+ @retval EFI_SUCCESS The bit successfully changed by host controller.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateDebugCapabilityContext (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle\r
+ )\r
+{\r
+ VOID *Buf;\r
+ XHC_DC_CONTEXT *DebugCapabilityContext;\r
+ UINT8 *String0Desc;\r
+ UINT8 *ManufacturerStrDesc;\r
+ UINT8 *ProductStrDesc;\r
+ UINT8 *SerialNumberStrDesc;\r
+ \r
+ //\r
+ // Allocate debug device context\r
+ //\r
+ Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));\r
+ ASSERT (Buf != NULL);\r
+ ASSERT (((UINTN) Buf & 0xF) == 0);\r
+ ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));\r
+ \r
+ DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;\r
+ Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;\r
+ \r
+ //\r
+ // Initialize DbcInfoContext.\r
+ //\r
+ DebugCapabilityContext->DbcInfoContext.String0Length = STRING0_DESC_LEN;\r
+ DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;\r
+ DebugCapabilityContext->DbcInfoContext.ProductStrLength = PRODUCT_DESC_LEN;\r
+ DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;\r
+\r
+ //\r
+ // Initialize EpOutContext.\r
+ //\r
+ DebugCapabilityContext->EpOutContext.CErr = 0x3;\r
+ DebugCapabilityContext->EpOutContext.EPType = ED_BULK_OUT;\r
+ DebugCapabilityContext->EpOutContext.MaxPacketSize = 0x400;\r
+ DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;\r
+ \r
+ //\r
+ // Initialize EpInContext.\r
+ //\r
+ DebugCapabilityContext->EpInContext.CErr = 0x3;\r
+ DebugCapabilityContext->EpInContext.EPType = ED_BULK_IN;\r
+ DebugCapabilityContext->EpInContext.MaxPacketSize = 0x400;\r
+ DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;\r
+ \r
+ //\r
+ // Update string descriptor address\r
+ //\r
+ String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);\r
+ ASSERT (String0Desc != NULL);\r
+ ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);\r
+ CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);\r
+ DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;\r
+ \r
+ ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;\r
+ CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);\r
+ DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;\r
+ \r
+ ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;\r
+ CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);\r
+ DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;\r
+ \r
+ SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;\r
+ CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);\r
+ DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;\r
+ \r
+ //\r
+ // Allocate and initialize the Transfer Ring for the Input Endpoint Context.\r
+ //\r
+ ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));\r
+ CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);\r
+ DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;\r
+ DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);\r
+\r
+ //\r
+ // Allocate and initialize the Transfer Ring for the Output Endpoint Context.\r
+ //\r
+ ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));\r
+ CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);\r
+ DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;\r
+ DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);\r
+\r
+ //\r
+ // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)\r
+ //\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCCP,\r
+ XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)\r
+ );\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCCP + 4,\r
+ XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check if debug device is running.\r
+\r
+ @param Handle Debug port handle.\r
+\r
+**/\r
+VOID\r
+XhcDetectDebugCapabilityReady (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle\r
+ )\r
+{\r
+ UINT64 TimeOut;\r
+ volatile UINT32 Dcctrl;\r
+\r
+ TimeOut = 1;\r
+ if (Handle->Initialized == USB3DBG_DBG_CAB) {\r
+ //\r
+ // As detection is slow in seconds, wait for longer timeout for the first time.\r
+ // If first initialization is failed, we will try to enable debug device in the\r
+ // Poll function invoked by timer.\r
+ //\r
+ TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;\r
+ }\r
+\r
+ do {\r
+ //\r
+ // Check if debug device is in configured state\r
+ //\r
+ Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);\r
+ if ((Dcctrl & BIT0) != 0) {\r
+ //\r
+ // Set the flag to indicate debug device is in configured state\r
+ //\r
+ Handle->Ready = TRUE;\r
+ break;\r
+ }\r
+ MicroSecondDelay (XHC_POLL_DELAY);\r
+ TimeOut--;\r
+ } while (TimeOut != 0);\r
+}\r
+\r
+/**\r
+ Initialize usb debug port hardware.\r
+\r
+ @param Handle Debug port handle.\r
+\r
+ @retval TRUE The usb debug port hardware configuration is changed.\r
+ @retval FALSE The usb debug port hardware configuration is not changed.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+InitializeUsbDebugHardware (\r
+ IN USB3_DEBUG_PORT_HANDLE *Handle\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT8 *Buffer;\r
+ UINTN Index;\r
+ UINT8 TotalUsb3Port;\r
+ EFI_PHYSICAL_ADDRESS XhciOpRegister;\r
+\r
+ XhciOpRegister = Handle->XhciOpRegister;\r
+ TotalUsb3Port = MmioRead32 (((UINTN) Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;\r
+\r
+ if (Handle->Initialized == USB3DBG_NOT_ENABLED) {\r
+ //\r
+ // If XHCI supports debug capability, hardware resource has been allocated, \r
+ // but it has not been enabled, try to enable again.\r
+ //\r
+ goto Enable;\r
+ }\r
+\r
+ //\r
+ // Initialize for PEI phase when AllocatePages can work\r
+ //\r
+ Buffer = AllocateAlignBuffer (XHC_DEBUG_PORT_DATA_LENGTH);\r
+ if (Buffer == NULL) {\r
+ //\r
+ // AllocatePages can not still work now, return fail and do not initialize now.\r
+ //\r
+ return RETURN_NOT_READY;\r
+ }\r
+\r
+ //\r
+ // Reset port to get debug device discovered\r
+ // \r
+ for (Index = 0; Index < TotalUsb3Port; Index++) {\r
+ XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);\r
+ MicroSecondDelay (10 * 1000);\r
+ }\r
+\r
+ //\r
+ // Construct the buffer for URB in and URB out\r
+ //\r
+ Handle->UrbIn.Data = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer;\r
+ Handle->UrbOut.Data = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer + XHC_DEBUG_PORT_DATA_LENGTH;\r
+ \r
+ //\r
+ // Initialize event ring\r
+ //\r
+ ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));\r
+ Status = CreateEventRing (Handle, &Handle->EventRing);\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ //\r
+ // Init IN and OUT endpoint context\r
+ //\r
+ Status = CreateDebugCapabilityContext (Handle);\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ //\r
+ // Init DCDDI1 and DCDDI2\r
+ //\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCDDI1,\r
+ (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)\r
+ ); \r
+\r
+ XhcWriteDebugReg (\r
+ Handle,\r
+ XHC_DC_DCDDI2,\r
+ (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)\r
+ );\r
+\r
+Enable:\r
+ if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {\r
+ //\r
+ // If the first time detection is failed, turn port power off and on in order to \r
+ // reset port status this time, then try to check if debug device is ready again.\r
+ //\r
+ for (Index = 0; Index < TotalUsb3Port; Index++) {\r
+ XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);\r
+ MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);\r
+ XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);\r
+ MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);\r
+ Handle->ChangePortPower = TRUE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization\r
+ //\r
+ XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);\r
+ \r
+ XhcDetectDebugCapabilityReady (Handle);\r
+ \r
+ Status = RETURN_SUCCESS;\r
+ if (!Handle->Ready) {\r
+ Handle->Initialized = USB3DBG_NOT_ENABLED;\r
+ Status = RETURN_NOT_READY;\r
+ } else {\r
+ Handle->Initialized = USB3DBG_ENABLED;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read data from debug device and save the data in buffer.\r
+\r
+ Reads NumberOfBytes data bytes from a debug device into the buffer\r
+ specified by Buffer. The number of bytes actually read is returned.\r
+ If the return value is less than NumberOfBytes, then the rest operation failed.\r
+ If NumberOfBytes is zero, then return 0.\r
+\r
+ @param Handle Debug port handle.\r
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.\r
+ @param NumberOfBytes Number of bytes which will be read.\r
+ @param Timeout Timeout value for reading from debug device. It unit is Microsecond.\r
+\r
+ @retval 0 Read data failed, no data is to be read.\r
+ @retval >0 Actual number of bytes read from debug device.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+DebugPortReadBuffer (\r
+ IN DEBUG_PORT_HANDLE Handle,\r
+ IN UINT8 *Buffer,\r
+ IN UINTN NumberOfBytes,\r
+ IN UINTN Timeout\r
+ )\r
+{\r
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
+ RETURN_STATUS Status;\r
+ UINTN Received;\r
+ UINTN Total;\r
+ UINTN Remaining;\r
+ UINT8 Index;\r
+ UINTN Length;\r
+ UINT64 Begin;\r
+ UINT64 TimeoutTicker;\r
+ UINT64 TimerRound;\r
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
+\r
+ if (NumberOfBytes == 0 || Buffer == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ Received = 0;\r
+ Total = 0;\r
+ Remaining = 0;\r
+\r
+ //\r
+ // If Handle is NULL, it means memory is ready for use.\r
+ // Use global variable to store handle value.\r
+ //\r
+ if (Handle == NULL) {\r
+ UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
+ } else {\r
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
+ }\r
+ \r
+ if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
+ return 0;\r
+ }\r
+ \r
+ XhciMmioBase = ProgramXhciBaseAddress ();\r
+ UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
+ \r
+ if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
+ Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
+ if (RETURN_ERROR(Status)) {\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ //\r
+ // First read data from buffer, then read debug port hw to get received data.\r
+ //\r
+ if (UsbDebugPortHandle->DataCount > 0) {\r
+ if (NumberOfBytes <= UsbDebugPortHandle->DataCount) {\r
+ Total = NumberOfBytes;\r
+ } else {\r
+ Total = UsbDebugPortHandle->DataCount;\r
+ }\r
+\r
+ for (Index = 0; Index < Total; Index++) {\r
+ Buffer[Index] = UsbDebugPortHandle->Data[Index];\r
+ }\r
+\r
+ for (Index = 0; Index < UsbDebugPortHandle->DataCount - Total; Index++) {\r
+ if (Total + Index >= 8) {\r
+ return 0;\r
+ }\r
+ UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Total + Index];\r
+ }\r
+ UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - (UINT8)Total);\r
+ }\r
+\r
+ //\r
+ // If Timeout is equal to 0, then it means it should always wait until all data required are received.\r
+ //\r
+ Begin = 0;\r
+ TimeoutTicker = 0; \r
+ TimerRound = 0;\r
+ if (Timeout != 0) {\r
+ Begin = GetPerformanceCounter ();\r
+ TimeoutTicker = DivU64x32 (\r
+ MultU64x64 (\r
+ UsbDebugPortHandle->TimerFrequency,\r
+ Timeout\r
+ ),\r
+ 1000000u\r
+ );\r
+ TimerRound = DivU64x64Remainder (\r
+ TimeoutTicker,\r
+ DivU64x32 (UsbDebugPortHandle->TimerCycle, 2),\r
+ &TimeoutTicker\r
+ );\r
+ }\r
+\r
+ //\r
+ // Read remaining data by executing one or more usb debug transfer transactions at usb debug port hw.\r
+ //\r
+ while (Total < NumberOfBytes) {\r
+ if (Timeout != 0) {\r
+ if (TimerRound == 0) {\r
+ if (IsTimerTimeout (UsbDebugPortHandle, Begin, TimeoutTicker)) {\r
+ //\r
+ // If time out occurs.\r
+ //\r
+ return 0;\r
+ }\r
+ } else {\r
+ if (IsTimerTimeout (UsbDebugPortHandle, Begin, DivU64x32 (UsbDebugPortHandle->TimerCycle, 2))) {\r
+ TimerRound --;\r
+ }\r
+ }\r
+ }\r
+ Remaining = NumberOfBytes - Total;\r
+ if (Remaining >= USB3_DEBUG_PORT_MAX_PACKET_SIZE) {\r
+ Received = USB3_DEBUG_PORT_MAX_PACKET_SIZE;\r
+ Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, Buffer + Total, &Received, DATA_TRANSFER_READ_TIMEOUT);\r
+ } else {\r
+ Received = USB3_DEBUG_PORT_MAX_PACKET_SIZE;\r
+ Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, &UsbDebugPortHandle->Data[0], &Received, DATA_TRANSFER_READ_TIMEOUT);\r
+ UsbDebugPortHandle->DataCount = (UINT8) Received;\r
+\r
+ if (Remaining <= Received) {\r
+ //\r
+ // The data received are more than required\r
+ //\r
+ Length = (UINT8)Remaining;\r
+ } else {\r
+ //\r
+ // The data received are less than the remaining bytes\r
+ //\r
+ Length = (UINT8)Received;\r
+ }\r
+\r
+ //\r
+ // Copy required data from the data buffer to user buffer.\r
+ //\r
+ for (Index = 0; Index < Length; Index++) {\r
+ (Buffer + Total)[Index] = UsbDebugPortHandle->Data[Index];\r
+ UsbDebugPortHandle->DataCount--;\r
+ }\r
+\r
+ //\r
+ // reorder the data buffer to make available data arranged from the beginning of the data buffer.\r
+ //\r
+ for (Index = 0; Index < Received - Length; Index++) {\r
+ if (Length + Index >= 8) {\r
+ return 0;\r
+ }\r
+ UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Length + Index];\r
+ }\r
+ //\r
+ // fixup the real required length of data.\r
+ //\r
+ Received = Length;\r
+ }\r
+ Total += Received;\r
+ }\r
+ return Total;\r
+}\r
+\r
+/**\r
+ Write data from buffer to debug device.\r
+\r
+ Writes NumberOfBytes data bytes from Buffer to the debug device.\r
+ The number of bytes actually written to the debug device is returned.\r
+ If the return value is less than NumberOfBytes, then the write operation failed.\r
+ If NumberOfBytes is zero, then return 0.\r
+\r
+ @param Handle Debug port handle.\r
+ @param Buffer Pointer to the data buffer to be written.\r
+ @param NumberOfBytes Number of bytes to written to the debug device.\r
+\r
+ @retval 0 NumberOfBytes is 0.\r
+ @retval >0 The number of bytes written to the debug device.\r
+ If this value is less than NumberOfBytes, then the read operation failed.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+DebugPortWriteBuffer (\r
+ IN DEBUG_PORT_HANDLE Handle,\r
+ IN UINT8 *Buffer,\r
+ IN UINTN NumberOfBytes\r
+ )\r
+{\r
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
+ RETURN_STATUS Status;\r
+ UINTN Sent;\r
+ UINTN Total;\r
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
+ UINTN Index;\r
+\r
+ if (NumberOfBytes == 0 || Buffer == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ Sent = 0;\r
+ Total = 0;\r
+\r
+ //\r
+ // If Handle is NULL, it means memory is ready for use.\r
+ // Use global variable to store handle value.\r
+ //\r
+ if (Handle == NULL) {\r
+ UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
+ } else {\r
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
+ }\r
+ \r
+ if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // MMIO base address is possible to clear, set it if it is cleared. (XhciMemorySpaceClose in PchUsbCommon.c)\r
+ //\r
+ XhciMmioBase = ProgramXhciBaseAddress ();\r
+\r
+ UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
+\r
+ if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
+ Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
+ if (RETURN_ERROR(Status)) {\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ //\r
+ // When host is trying to send data, write will be blocked.\r
+ // Poll to see if there is any data sent by host at first.\r
+ //\r
+ DebugPortPollBuffer (Handle);\r
+\r
+ Index = 0;\r
+ while ((Total < NumberOfBytes)) {\r
+ if (NumberOfBytes - Total > USB3_DEBUG_PORT_MAX_PACKET_SIZE) {\r
+ Sent = USB3_DEBUG_PORT_MAX_PACKET_SIZE;\r
+ } else {\r
+ Sent = (UINT8)(NumberOfBytes - Total);\r
+ }\r
+ Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);\r
+ Total += Sent;\r
+ }\r
+ \r
+ return Total;\r
+}\r
+\r
+/**\r
+ Polls a debug device to see if there is any data waiting to be read.\r
+\r
+ Polls a debug device to see if there is any data waiting to be read.\r
+ If there is data waiting to be read from the debug device, then TRUE is returned.\r
+ If there is no data waiting to be read from the debug device, then FALSE is returned.\r
+\r
+ @param Handle Debug port handle.\r
+\r
+ @retval TRUE Data is waiting to be read from the debug device.\r
+ @retval FALSE There is no data waiting to be read from the serial device.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DebugPortPollBuffer (\r
+ IN DEBUG_PORT_HANDLE Handle\r
+ )\r
+{\r
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
+ UINTN Length;\r
+ RETURN_STATUS Status;\r
+ UINT8 Buffer[XHC_DEBUG_PORT_DATA_LENGTH];\r
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;\r
+\r
+ //\r
+ // If Handle is NULL, it means memory is ready for use.\r
+ // Use global variable to store handle value.\r
+ //\r
+ if (Handle == NULL) {\r
+ UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
+ } else {\r
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
+ }\r
+\r
+ if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
+ return 0;\r
+ }\r
+\r
+ XhciMmioBase = ProgramXhciBaseAddress ();\r
+ UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
+ \r
+ if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
+ Status = InitializeUsbDebugHardware(UsbDebugPortHandle);\r
+ if (RETURN_ERROR(Status)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // If the data buffer is not empty, then return TRUE directly.\r
+ // Otherwise initialize a usb read transaction and read data to internal data buffer.\r
+ //\r
+ if (UsbDebugPortHandle->DataCount != 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // Read most 8-bytes data\r
+ //\r
+ Length = XHC_DEBUG_PORT_DATA_LENGTH;\r
+ XhcDataTransfer (Handle, EfiUsbDataIn, Buffer, &Length, DATA_TRANSFER_POLL_TIMEOUT);\r
+\r
+ if (Length > 8) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (Length == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Store data into internal buffer for use later\r
+ //\r
+ CopyMem (UsbDebugPortHandle->Data, Buffer, Length);\r
+ UsbDebugPortHandle->DataCount = (UINT8) Length;\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Initialize the debug port.\r
+\r
+ If Function is not NULL, Debug Communication Libary will call this function\r
+ by passing in the Context to be the first parameter. If needed, Debug Communication\r
+ Library will create one debug port handle to be the second argument passing in\r
+ calling the Function, otherwise it will pass NULL to be the second argument of\r
+ Function.\r
+\r
+ If Function is NULL, and Context is not NULL, the Debug Communication Library could\r
+ a) Return the same handle as passed in (as Context parameter).\r
+ b) Ignore the input Context parameter and create new hanlde to be returned.\r
+\r
+ If parameter Function is NULL and Context is NULL, Debug Communication Library could\r
+ created a new handle if needed and return it, otherwise it will return NULL.\r
+\r
+ @param[in] Context Context needed by callback function; it was optional.\r
+ @param[in] Function Continue function called by Debug Communication library;\r
+ it was optional.\r
+\r
+ @return The debug port handle created by Debug Communication Library if Function\r
+ is not NULL.\r
+\r
+**/\r
+DEBUG_PORT_HANDLE\r
+EFIAPI\r
+DebugPortInitialize (\r
+ IN VOID *Context,\r
+ IN DEBUG_PORT_CONTINUE Function\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ USB3_DEBUG_PORT_HANDLE Handle;\r
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;\r
+ UINT64 TimerStartValue;\r
+ UINT64 TimerEndValue;\r
+\r
+ //\r
+ // Validate the PCD PcdDebugPortHandleBufferSize value \r
+ //\r
+ ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));\r
+\r
+ if (Function == NULL && Context != NULL) {\r
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Context;\r
+ } else {\r
+ ZeroMem(&Handle, sizeof (USB3_DEBUG_PORT_HANDLE));\r
+ UsbDebugPortHandle = &Handle;\r
+ }\r
+\r
+ UsbDebugPortHandle->TimerFrequency = GetPerformanceCounterProperties (\r
+ &TimerStartValue,\r
+ &TimerEndValue\r
+ );\r
+\r
+ if (TimerEndValue < TimerStartValue) {\r
+ UsbDebugPortHandle->TimerCountDown = TRUE;\r
+ UsbDebugPortHandle->TimerCycle = TimerStartValue - TimerEndValue;\r
+ } else {\r
+ UsbDebugPortHandle->TimerCountDown = FALSE;\r
+ UsbDebugPortHandle->TimerCycle = TimerEndValue - TimerStartValue;\r
+ } \r
+\r
+ if (Function == NULL && Context != NULL) {\r
+ return (DEBUG_PORT_HANDLE *) Context;\r
+ }\r
+ \r
+ //\r
+ // Read 64-bit MMIO base address\r
+ //\r
+ UsbDebugPortHandle->XhciMmioBase = ProgramXhciBaseAddress ();\r
+\r
+ Status = CalculateUsbDebugPortMmioBase (UsbDebugPortHandle);\r
+ if (RETURN_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ if (NeedReinitializeHardware(&Handle)) {\r
+ Status = InitializeUsbDebugHardware (&Handle);\r
+ if (RETURN_ERROR(Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+Exit:\r
+\r
+ if (Function != NULL) {\r
+ Function (Context, &Handle);\r
+ } else {\r
+ CopyMem(&mDebugCommunicationLibUsb3DebugPortHandle, &Handle, sizeof (USB3_DEBUG_PORT_HANDLE));\r
+ }\r
+\r
+ return (DEBUG_PORT_HANDLE)(UINTN)&mDebugCommunicationLibUsb3DebugPortHandle;\r
+}\r