2 Debug Port Library implementation based on usb3 debug port.
4 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "DebugCommunicationLibUsb3Internal.h"
18 // The global variable which can be used after memory is ready.
20 USB3_DEBUG_PORT_HANDLE mDebugCommunicationLibUsb3DebugPortHandle
;
22 UINT16 mString0Desc
[] = {
23 // String Descriptor Type + Length
24 ( USB_DESC_TYPE_STRING
<< 8 ) + STRING0_DESC_LEN
,
28 UINT16 mManufacturerStrDesc
[] = {
29 // String Descriptor Type + Length
30 ( USB_DESC_TYPE_STRING
<< 8 ) + MANU_DESC_LEN
,
31 'I', 'n', 't', 'e', 'l'
34 UINT16 mProductStrDesc
[] = {
35 // String Descriptor Type + Length
36 ( USB_DESC_TYPE_STRING
<< 8 ) + PRODUCT_DESC_LEN
,
37 'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
40 UINT16 mSerialNumberStrDesc
[] = {
41 // String Descriptor Type + Length
42 ( USB_DESC_TYPE_STRING
<< 8 ) + SERIAL_DESC_LEN
,
47 Sets bits as per the enabled bit positions in the mask.
49 @param[in, out] Register UINTN register
50 @param[in] BitMask 32-bit mask
54 IN OUT UINTN Register
,
60 RegisterValue
= MmioRead32 (Register
);
61 RegisterValue
|= (UINT32
)(BitMask
);
62 MmioWrite32 (Register
, RegisterValue
);
66 Clears bits as per the enabled bit positions in the mask.
68 @param[in, out] Register UINTN register
69 @param[in] BitMask 32-bit mask
73 IN OUT UINTN Register
,
79 RegisterValue
= MmioRead32 (Register
);
80 RegisterValue
&= ~BitMask
;
81 MmioWrite32 (Register
, RegisterValue
);
85 Write the data to the XHCI debug register.
87 @param Handle Debug port handle.
88 @param Offset The offset of the runtime register.
89 @param Data The data to write.
94 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
99 EFI_PHYSICAL_ADDRESS DebugCapabilityBase
;
101 DebugCapabilityBase
= Handle
->DebugCapabilityBase
;
102 MmioWrite32 ((UINTN
)(DebugCapabilityBase
+ Offset
), Data
);
108 Read XHCI debug register.
110 @param Handle Debug port handle.
111 @param Offset The offset of the runtime register.
113 @return The register content read
118 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
123 EFI_PHYSICAL_ADDRESS DebugCapabilityBase
;
125 DebugCapabilityBase
= Handle
->DebugCapabilityBase
;
126 Data
= MmioRead32 ((UINTN
)(DebugCapabilityBase
+ Offset
));
132 Set one bit of the runtime register while keeping other bits.
134 @param Handle Debug port handle.
135 @param Offset The offset of the runtime register.
136 @param Bit The bit mask of the register to set.
141 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
148 Data
= XhcReadDebugReg (Handle
, Offset
);
150 XhcWriteDebugReg (Handle
, Offset
, Data
);
154 Program and eanble XHCI MMIO base address.
156 @return XHCI MMIO base address.
160 ProgramXhciBaseAddress (
167 EFI_PHYSICAL_ADDRESS XhciMmioBase
;
169 Low
= PciRead32 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_BASE_ADDRESSREG_OFFSET
);
170 High
= PciRead32 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_BASE_ADDRESSREG_OFFSET
+ 4);
171 XhciMmioBase
= (EFI_PHYSICAL_ADDRESS
) (LShiftU64 ((UINT64
) High
, 32) | Low
);
172 XhciMmioBase
&= XHCI_BASE_ADDRESS_64_BIT_MASK
;
174 if ((XhciMmioBase
== 0) || (XhciMmioBase
== XHCI_BASE_ADDRESS_64_BIT_MASK
)) {
175 XhciMmioBase
= PcdGet64(PcdUsbXhciMemorySpaceBase
);
176 PciWrite32(PcdGet32(PcdUsbXhciPciAddress
) + PCI_BASE_ADDRESSREG_OFFSET
, XhciMmioBase
& 0xFFFFFFFF);
177 PciWrite32(PcdGet32(PcdUsbXhciPciAddress
) + PCI_BASE_ADDRESSREG_OFFSET
+ 4, (RShiftU64 (XhciMmioBase
, 32) & 0xFFFFFFFF));
180 PciCmd
= PciRead16 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_COMMAND_OFFSET
);
181 if (((PciCmd
& EFI_PCI_COMMAND_MEMORY_SPACE
) == 0) || ((PciCmd
& EFI_PCI_COMMAND_BUS_MASTER
) == 0)) {
182 PciCmd
|= EFI_PCI_COMMAND_MEMORY_SPACE
| EFI_PCI_COMMAND_BUS_MASTER
;
183 PciWrite16(PcdGet32(PcdUsbXhciPciAddress
) + PCI_COMMAND_OFFSET
, PciCmd
);
190 Update XHC MMIO base address when MMIO base address is changed.
192 @param Handle Debug port handle.
193 @param XhciMmioBase XHCI MMIO base address.
198 IN OUT USB3_DEBUG_PORT_HANDLE
*Handle
,
199 IN EFI_PHYSICAL_ADDRESS XhciMmioBase
202 if ((Handle
== NULL
) || (Handle
->XhciMmioBase
== XhciMmioBase
)) {
207 // Need fix Handle data according to new XHCI MMIO base address.
209 Handle
->XhciMmioBase
= XhciMmioBase
;
210 Handle
->DebugCapabilityBase
= XhciMmioBase
+ Handle
->DebugCapabilityOffset
;
211 Handle
->XhciOpRegister
= XhciMmioBase
+ MmioRead8 ((UINTN
)XhciMmioBase
);
215 Calculate the usb debug port bar address.
217 @param Handle Debug port handle.
219 @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.
220 @retval RETURN_SUCCESS Get bar and offset successfully.
225 CalculateUsbDebugPortMmioBase (
226 USB3_DEBUG_PORT_HANDLE
*Handle
236 EFI_PHYSICAL_ADDRESS CapabilityPointer
;
239 VendorId
= PciRead16 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_VENDOR_ID_OFFSET
);
240 DeviceId
= PciRead16 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_DEVICE_ID_OFFSET
);
242 if ((VendorId
== 0xFFFF) || (DeviceId
== 0xFFFF)) {
246 ProgInterface
= PciRead8 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_CLASSCODE_OFFSET
);
247 SubClassCode
= PciRead8 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_CLASSCODE_OFFSET
+ 1);
248 BaseCode
= PciRead8 (PcdGet32(PcdUsbXhciPciAddress
) + PCI_CLASSCODE_OFFSET
+ 2);
250 if ((ProgInterface
!= PCI_IF_XHCI
) || (SubClassCode
!= PCI_CLASS_SERIAL_USB
) || (BaseCode
!= PCI_CLASS_SERIAL
)) {
254 CapLength
= MmioRead8 ((UINTN
) Handle
->XhciMmioBase
);
257 // Get capability pointer from HCCPARAMS at offset 0x10
259 CapabilityPointer
= Handle
->XhciMmioBase
+ (MmioRead32 ((UINTN
)(Handle
->XhciMmioBase
+ XHC_HCCPARAMS_OFFSET
)) >> 16) * 4;
262 // Search XHCI debug capability
265 Capability
= MmioRead32 ((UINTN
)CapabilityPointer
);
267 if ((Capability
& XHC_CAPABILITY_ID_MASK
) == PCI_CAPABILITY_ID_DEBUG_PORT
) {
271 if ((((Capability
& XHC_NEXT_CAPABILITY_MASK
) >> 8) & XHC_CAPABILITY_ID_MASK
) == 0) {
273 // Reach the end of capability list, quit
277 CapabilityPointer
+= ((Capability
& XHC_NEXT_CAPABILITY_MASK
) >> 8) * 4;
278 Capability
= MmioRead32 ((UINTN
)CapabilityPointer
);
286 // USB3 debug capability is supported.
288 Handle
->DebugCapabilityBase
= CapabilityPointer
;
289 Handle
->DebugCapabilityOffset
= CapabilityPointer
- Handle
->XhciMmioBase
;
290 Handle
->XhciOpRegister
= Handle
->XhciMmioBase
+ CapLength
;
291 Handle
->Initialized
= USB3DBG_DBG_CAB
;
292 return RETURN_SUCCESS
;
295 Handle
->Initialized
= USB3DBG_NO_DBG_CAB
;
296 return RETURN_UNSUPPORTED
;
300 Check if it needs to re-initialize usb debug port hardware.
302 During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
303 whether the usb debug port hardware configuration is changed. Such case can be triggerred by
304 Pci bus resource allocation and so on.
306 @param Handle Debug port handle.
308 @retval TRUE The usb debug port hardware configuration is changed.
309 @retval FALSE The usb debug port hardware configuration is not changed.
314 NeedReinitializeHardware(
315 IN USB3_DEBUG_PORT_HANDLE
*Handle
319 volatile UINT32 Dcctrl
;
324 // If DCE bit, it means USB3 debug is not enabled.
326 Dcctrl
= XhcReadDebugReg (Handle
, XHC_DC_DCCTRL
);
327 if ((Dcctrl
& BIT0
) == 0) {
335 Create XHCI event ring.
337 @param Handle Debug port handle.
338 @param EventRing The created event ring.
343 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
344 OUT EVENT_RING
*EventRing
348 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
350 ASSERT (EventRing
!= NULL
);
353 // Allocate Event Ring
355 Buf
= AllocateAlignBuffer (sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
356 ASSERT (Buf
!= NULL
);
357 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
358 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
360 EventRing
->EventRingSeg0
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Buf
;
361 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
362 EventRing
->EventRingDequeue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) EventRing
->EventRingSeg0
;
363 EventRing
->EventRingEnqueue
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) EventRing
->EventRingSeg0
;
366 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
367 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
369 EventRing
->EventRingCCS
= 1;
372 // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
374 Buf
= AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
375 ASSERT (Buf
!= NULL
);
376 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
377 ZeroMem (Buf
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
379 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
380 EventRing
->ERSTBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) ERSTBase
;
383 // Fill Event Segment address
385 ERSTBase
->PtrLo
= XHC_LOW_32BIT (EventRing
->EventRingSeg0
);
386 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (EventRing
->EventRingSeg0
);
387 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
390 // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
395 XHC_LOW_32BIT((UINT64
)(UINTN
)EventRing
->EventRingDequeue
)
401 XHC_HIGH_32BIT((UINT64
)(UINTN
)EventRing
->EventRingDequeue
)
405 // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
410 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTBase
)
416 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTBase
)
420 // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
431 Create XHCI transfer ring.
433 @param Handle Debug port handle.
434 @param TrbNum The number of TRB in the ring.
435 @param TransferRing The created transfer ring.
440 IN USB3_DEBUG_PORT_HANDLE
*Handle
,
442 OUT TRANSFER_RING
*TransferRing
448 Buf
= AllocateAlignBuffer (sizeof (TRB_TEMPLATE
) * TrbNum
);
449 ASSERT (Buf
!= NULL
);
450 ASSERT (((UINTN
) Buf
& 0xF) == 0);
451 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
453 TransferRing
->RingSeg0
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Buf
;
454 TransferRing
->TrbNumber
= TrbNum
;
455 TransferRing
->RingEnqueue
= TransferRing
->RingSeg0
;
456 TransferRing
->RingDequeue
= TransferRing
->RingSeg0
;
457 TransferRing
->RingPCS
= 1;
459 // 4.9.2 Transfer Ring Management
460 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
461 // point to the first TRB in the ring.
463 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
464 EndTrb
->Type
= TRB_TYPE_LINK
;
465 EndTrb
->PtrLo
= XHC_LOW_32BIT (Buf
);
466 EndTrb
->PtrHi
= XHC_HIGH_32BIT (Buf
);
468 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
472 // Set Cycle bit as other TRB PCS init value
474 EndTrb
->CycleBit
= 0;
478 Create debug capability context for XHC debug device.
480 @param Handle Debug port handle.
482 @retval EFI_SUCCESS The bit successfully changed by host controller.
483 @retval EFI_TIMEOUT The time out occurred.
487 CreateDebugCapabilityContext (
488 IN USB3_DEBUG_PORT_HANDLE
*Handle
492 XHC_DC_CONTEXT
*DebugCapabilityContext
;
494 UINT8
*ManufacturerStrDesc
;
495 UINT8
*ProductStrDesc
;
496 UINT8
*SerialNumberStrDesc
;
499 // Allocate debug device context
501 Buf
= AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT
));
502 ASSERT (Buf
!= NULL
);
503 ASSERT (((UINTN
) Buf
& 0xF) == 0);
504 ZeroMem (Buf
, sizeof (XHC_DC_CONTEXT
));
506 DebugCapabilityContext
= (XHC_DC_CONTEXT
*)(UINTN
) Buf
;
507 Handle
->DebugCapabilityContext
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) DebugCapabilityContext
;
510 // Initialize DbcInfoContext.
512 DebugCapabilityContext
->DbcInfoContext
.String0Length
= STRING0_DESC_LEN
;
513 DebugCapabilityContext
->DbcInfoContext
.ManufacturerStrLength
= MANU_DESC_LEN
;
514 DebugCapabilityContext
->DbcInfoContext
.ProductStrLength
= PRODUCT_DESC_LEN
;
515 DebugCapabilityContext
->DbcInfoContext
.SerialNumberStrLength
= SERIAL_DESC_LEN
;
518 // Initialize EpOutContext.
520 DebugCapabilityContext
->EpOutContext
.CErr
= 0x3;
521 DebugCapabilityContext
->EpOutContext
.EPType
= ED_BULK_OUT
;
522 DebugCapabilityContext
->EpOutContext
.MaxPacketSize
= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
;
523 DebugCapabilityContext
->EpOutContext
.AverageTRBLength
= 0x1000;
526 // Initialize EpInContext.
528 DebugCapabilityContext
->EpInContext
.CErr
= 0x3;
529 DebugCapabilityContext
->EpInContext
.EPType
= ED_BULK_IN
;
530 DebugCapabilityContext
->EpInContext
.MaxPacketSize
= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
;
531 DebugCapabilityContext
->EpInContext
.AverageTRBLength
= 0x1000;
534 // Update string descriptor address
536 String0Desc
= (UINT8
*) AllocateAlignBuffer (STRING0_DESC_LEN
+ MANU_DESC_LEN
+ PRODUCT_DESC_LEN
+ SERIAL_DESC_LEN
);
537 ASSERT (String0Desc
!= NULL
);
538 ZeroMem (String0Desc
, STRING0_DESC_LEN
+ MANU_DESC_LEN
+ PRODUCT_DESC_LEN
+ SERIAL_DESC_LEN
);
539 CopyMem (String0Desc
, mString0Desc
, STRING0_DESC_LEN
);
540 DebugCapabilityContext
->DbcInfoContext
.String0DescAddress
= (UINT64
)(UINTN
)String0Desc
;
542 ManufacturerStrDesc
= String0Desc
+ STRING0_DESC_LEN
;
543 CopyMem (ManufacturerStrDesc
, mManufacturerStrDesc
, MANU_DESC_LEN
);
544 DebugCapabilityContext
->DbcInfoContext
.ManufacturerStrDescAddress
= (UINT64
)(UINTN
)ManufacturerStrDesc
;
546 ProductStrDesc
= ManufacturerStrDesc
+ MANU_DESC_LEN
;
547 CopyMem (ProductStrDesc
, mProductStrDesc
, PRODUCT_DESC_LEN
);
548 DebugCapabilityContext
->DbcInfoContext
.ProductStrDescAddress
= (UINT64
)(UINTN
)ProductStrDesc
;
550 SerialNumberStrDesc
= ProductStrDesc
+ PRODUCT_DESC_LEN
;
551 CopyMem (SerialNumberStrDesc
, mSerialNumberStrDesc
, SERIAL_DESC_LEN
);
552 DebugCapabilityContext
->DbcInfoContext
.SerialNumberStrDescAddress
= (UINT64
)(UINTN
)SerialNumberStrDesc
;
555 // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
557 ZeroMem (&Handle
->TransferRingIn
, sizeof (TRANSFER_RING
));
558 CreateTransferRing (Handle
, TR_RING_TRB_NUMBER
, &Handle
->TransferRingIn
);
559 DebugCapabilityContext
->EpInContext
.PtrLo
= XHC_LOW_32BIT (Handle
->TransferRingIn
.RingSeg0
) | BIT0
;
560 DebugCapabilityContext
->EpInContext
.PtrHi
= XHC_HIGH_32BIT (Handle
->TransferRingIn
.RingSeg0
);
563 // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
565 ZeroMem (&Handle
->TransferRingOut
, sizeof (TRANSFER_RING
));
566 CreateTransferRing (Handle
, TR_RING_TRB_NUMBER
, &Handle
->TransferRingOut
);
567 DebugCapabilityContext
->EpOutContext
.PtrLo
= XHC_LOW_32BIT (Handle
->TransferRingOut
.RingSeg0
) | BIT0
;
568 DebugCapabilityContext
->EpOutContext
.PtrHi
= XHC_HIGH_32BIT (Handle
->TransferRingOut
.RingSeg0
);
571 // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
576 XHC_LOW_32BIT((UINT64
)(UINTN
)DebugCapabilityContext
)
581 XHC_HIGH_32BIT((UINT64
)(UINTN
)DebugCapabilityContext
)
587 Check if debug device is running.
589 @param Handle Debug port handle.
593 XhcDetectDebugCapabilityReady (
594 IN USB3_DEBUG_PORT_HANDLE
*Handle
598 volatile UINT32 Dcctrl
;
601 if (Handle
->Initialized
== USB3DBG_DBG_CAB
) {
603 // As detection is slow in seconds, wait for longer timeout for the first time.
604 // If first initialization is failed, we will try to enable debug device in the
605 // Poll function invoked by timer.
607 TimeOut
= DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout
), XHC_POLL_DELAY
) + 1;
612 // Check if debug device is in configured state
614 Dcctrl
= XhcReadDebugReg (Handle
, XHC_DC_DCCTRL
);
615 if ((Dcctrl
& BIT0
) != 0) {
617 // Set the flag to indicate debug device is in configured state
619 Handle
->Ready
= TRUE
;
622 MicroSecondDelay (XHC_POLL_DELAY
);
624 } while (TimeOut
!= 0);
628 Initialize usb debug port hardware.
630 @param Handle Debug port handle.
632 @retval TRUE The usb debug port hardware configuration is changed.
633 @retval FALSE The usb debug port hardware configuration is not changed.
638 InitializeUsbDebugHardware (
639 IN USB3_DEBUG_PORT_HANDLE
*Handle
642 RETURN_STATUS Status
;
646 EFI_PHYSICAL_ADDRESS XhciOpRegister
;
648 XhciOpRegister
= Handle
->XhciOpRegister
;
649 TotalUsb3Port
= MmioRead32 (((UINTN
) Handle
->XhciMmioBase
+ XHC_HCSPARAMS1_OFFSET
)) >> 24;
651 if (Handle
->Initialized
== USB3DBG_NOT_ENABLED
) {
653 // If XHCI supports debug capability, hardware resource has been allocated,
654 // but it has not been enabled, try to enable again.
660 // Initialize for PEI phase when AllocatePages can work.
661 // Allocate data buffer with max packet size for data read and data poll.
662 // Allocate data buffer for data write.
664 Buffer
= AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
* 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
);
665 if (Buffer
== NULL
) {
667 // AllocatePages can not still work now, return fail and do not initialize now.
669 return RETURN_NOT_READY
;
673 // Reset port to get debug device discovered
675 for (Index
= 0; Index
< TotalUsb3Port
; Index
++) {
676 XhcSetR32Bit ((UINTN
)XhciOpRegister
+ XHC_PORTSC_OFFSET
+ Index
* 0x10, BIT4
);
677 MicroSecondDelay (10 * 1000);
681 // Construct the buffer for read, poll and write.
683 Handle
->UrbIn
.Data
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Buffer
;
684 Handle
->Data
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Buffer
+ XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
;
685 Handle
->UrbOut
.Data
= Handle
->UrbIn
.Data
+ XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
* 2;
688 // Initialize event ring
690 ZeroMem (&Handle
->EventRing
, sizeof (EVENT_RING
));
691 Status
= CreateEventRing (Handle
, &Handle
->EventRing
);
692 ASSERT_EFI_ERROR (Status
);
695 // Init IN and OUT endpoint context
697 Status
= CreateDebugCapabilityContext (Handle
);
698 ASSERT_EFI_ERROR (Status
);
701 // Init DCDDI1 and DCDDI2
706 (UINT32
)((XHCI_DEBUG_DEVICE_VENDOR_ID
<< 16) | XHCI_DEBUG_DEVICE_PROTOCOL
)
712 (UINT32
)((XHCI_DEBUG_DEVICE_REVISION
<< 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID
)
716 if ((Handle
->Initialized
== USB3DBG_NOT_ENABLED
) && (!Handle
->ChangePortPower
)) {
718 // If the first time detection is failed, turn port power off and on in order to
719 // reset port status this time, then try to check if debug device is ready again.
721 for (Index
= 0; Index
< TotalUsb3Port
; Index
++) {
722 XhcClearR32Bit ((UINTN
)XhciOpRegister
+ XHC_PORTSC_OFFSET
+ Index
* 0x10, BIT9
);
723 MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY
);
724 XhcSetR32Bit ((UINTN
)XhciOpRegister
+ XHC_PORTSC_OFFSET
+ Index
* 0x10, BIT9
);
725 MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY
);
726 Handle
->ChangePortPower
= TRUE
;
731 // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization
733 XhcSetDebugRegBit (Handle
, XHC_DC_DCCTRL
, BIT1
|BIT31
);
735 XhcDetectDebugCapabilityReady (Handle
);
737 Status
= RETURN_SUCCESS
;
738 if (!Handle
->Ready
) {
739 Handle
->Initialized
= USB3DBG_NOT_ENABLED
;
740 Status
= RETURN_NOT_READY
;
742 Handle
->Initialized
= USB3DBG_ENABLED
;
749 Read data from debug device and save the data in buffer.
751 Reads NumberOfBytes data bytes from a debug device into the buffer
752 specified by Buffer. The number of bytes actually read is returned.
753 If the return value is less than NumberOfBytes, then the rest operation failed.
754 If NumberOfBytes is zero, then return 0.
756 @param Handle Debug port handle.
757 @param Buffer Pointer to the data buffer to store the data read from the debug device.
758 @param NumberOfBytes Number of bytes which will be read.
759 @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
761 @retval 0 Read data failed, no data is to be read.
762 @retval >0 Actual number of bytes read from debug device.
767 DebugPortReadBuffer (
768 IN DEBUG_PORT_HANDLE Handle
,
770 IN UINTN NumberOfBytes
,
774 USB3_DEBUG_PORT_HANDLE
*UsbDebugPortHandle
;
775 RETURN_STATUS Status
;
779 if (NumberOfBytes
!= 1 || Buffer
== NULL
|| Timeout
!= 0) {
784 // If Handle is NULL, it means memory is ready for use.
785 // Use global variable to store handle value.
787 if (Handle
== NULL
) {
788 UsbDebugPortHandle
= &mDebugCommunicationLibUsb3DebugPortHandle
;
790 UsbDebugPortHandle
= (USB3_DEBUG_PORT_HANDLE
*)Handle
;
793 if (UsbDebugPortHandle
->Initialized
== USB3DBG_NO_DBG_CAB
) {
797 if (NeedReinitializeHardware(UsbDebugPortHandle
)) {
798 Status
= InitializeUsbDebugHardware (UsbDebugPortHandle
);
799 if (RETURN_ERROR(Status
)) {
804 Data
= (UINT8
*)(UINTN
)UsbDebugPortHandle
->Data
;
807 // Read data from buffer
809 if (UsbDebugPortHandle
->DataCount
< 1) {
814 for (Index
= 0; Index
< UsbDebugPortHandle
->DataCount
- 1; Index
++) {
815 if ((Index
+ 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
) {
818 Data
[Index
] = Data
[Index
+ 1];
820 UsbDebugPortHandle
->DataCount
= (UINT8
)(UsbDebugPortHandle
->DataCount
- 1);
826 Write data from buffer to debug device.
828 Writes NumberOfBytes data bytes from Buffer to the debug device.
829 The number of bytes actually written to the debug device is returned.
830 If the return value is less than NumberOfBytes, then the write operation failed.
831 If NumberOfBytes is zero, then return 0.
833 @param Handle Debug port handle.
834 @param Buffer Pointer to the data buffer to be written.
835 @param NumberOfBytes Number of bytes to written to the debug device.
837 @retval 0 NumberOfBytes is 0.
838 @retval >0 The number of bytes written to the debug device.
839 If this value is less than NumberOfBytes, then the read operation failed.
844 DebugPortWriteBuffer (
845 IN DEBUG_PORT_HANDLE Handle
,
847 IN UINTN NumberOfBytes
850 USB3_DEBUG_PORT_HANDLE
*UsbDebugPortHandle
;
851 RETURN_STATUS Status
;
854 EFI_PHYSICAL_ADDRESS XhciMmioBase
;
857 if (NumberOfBytes
== 0 || Buffer
== NULL
) {
865 // If Handle is NULL, it means memory is ready for use.
866 // Use global variable to store handle value.
868 if (Handle
== NULL
) {
869 UsbDebugPortHandle
= &mDebugCommunicationLibUsb3DebugPortHandle
;
871 UsbDebugPortHandle
= (USB3_DEBUG_PORT_HANDLE
*)Handle
;
874 if (UsbDebugPortHandle
->Initialized
== USB3DBG_NO_DBG_CAB
) {
879 // MMIO base address is possible to clear, set it if it is cleared. (XhciMemorySpaceClose in PchUsbCommon.c)
881 XhciMmioBase
= ProgramXhciBaseAddress ();
883 UpdateXhcResource (UsbDebugPortHandle
, XhciMmioBase
);
885 if (NeedReinitializeHardware(UsbDebugPortHandle
)) {
886 Status
= InitializeUsbDebugHardware (UsbDebugPortHandle
);
887 if (RETURN_ERROR(Status
)) {
893 // When host is trying to send data, write will be blocked.
894 // Poll to see if there is any data sent by host at first.
896 DebugPortPollBuffer (Handle
);
899 while ((Total
< NumberOfBytes
)) {
900 if (NumberOfBytes
- Total
> USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
) {
901 Sent
= USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
;
903 Sent
= (UINT8
)(NumberOfBytes
- Total
);
905 Status
= XhcDataTransfer (UsbDebugPortHandle
, EfiUsbDataOut
, Buffer
+ Total
, &Sent
, DATA_TRANSFER_WRITE_TIMEOUT
);
913 Polls a debug device to see if there is any data waiting to be read.
915 Polls a debug device to see if there is any data waiting to be read.
916 If there is data waiting to be read from the debug device, then TRUE is returned.
917 If there is no data waiting to be read from the debug device, then FALSE is returned.
919 @param Handle Debug port handle.
921 @retval TRUE Data is waiting to be read from the debug device.
922 @retval FALSE There is no data waiting to be read from the serial device.
927 DebugPortPollBuffer (
928 IN DEBUG_PORT_HANDLE Handle
931 USB3_DEBUG_PORT_HANDLE
*UsbDebugPortHandle
;
933 RETURN_STATUS Status
;
934 EFI_PHYSICAL_ADDRESS XhciMmioBase
;
937 // If Handle is NULL, it means memory is ready for use.
938 // Use global variable to store handle value.
940 if (Handle
== NULL
) {
941 UsbDebugPortHandle
= &mDebugCommunicationLibUsb3DebugPortHandle
;
943 UsbDebugPortHandle
= (USB3_DEBUG_PORT_HANDLE
*)Handle
;
946 if (UsbDebugPortHandle
->Initialized
== USB3DBG_NO_DBG_CAB
) {
950 XhciMmioBase
= ProgramXhciBaseAddress ();
951 UpdateXhcResource (UsbDebugPortHandle
, XhciMmioBase
);
953 if (NeedReinitializeHardware(UsbDebugPortHandle
)) {
954 Status
= InitializeUsbDebugHardware(UsbDebugPortHandle
);
955 if (RETURN_ERROR(Status
)) {
961 // If the data buffer is not empty, then return TRUE directly.
962 // Otherwise initialize a usb read transaction and read data to internal data buffer.
964 if (UsbDebugPortHandle
->DataCount
!= 0) {
969 // Read data as much as we can
971 Length
= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
;
972 XhcDataTransfer (Handle
, EfiUsbDataIn
, (VOID
*)(UINTN
)UsbDebugPortHandle
->Data
, &Length
, DATA_TRANSFER_POLL_TIMEOUT
);
974 if (Length
> XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE
) {
983 // Store data into internal buffer for use later
985 UsbDebugPortHandle
->DataCount
= (UINT8
) Length
;
990 Initialize the debug port.
992 If Function is not NULL, Debug Communication Libary will call this function
993 by passing in the Context to be the first parameter. If needed, Debug Communication
994 Library will create one debug port handle to be the second argument passing in
995 calling the Function, otherwise it will pass NULL to be the second argument of
998 If Function is NULL, and Context is not NULL, the Debug Communication Library could
999 a) Return the same handle as passed in (as Context parameter).
1000 b) Ignore the input Context parameter and create new hanlde to be returned.
1002 If parameter Function is NULL and Context is NULL, Debug Communication Library could
1003 created a new handle if needed and return it, otherwise it will return NULL.
1005 @param[in] Context Context needed by callback function; it was optional.
1006 @param[in] Function Continue function called by Debug Communication library;
1009 @return The debug port handle created by Debug Communication Library if Function
1015 DebugPortInitialize (
1017 IN DEBUG_PORT_CONTINUE Function
1020 RETURN_STATUS Status
;
1021 USB3_DEBUG_PORT_HANDLE Handle
;
1022 USB3_DEBUG_PORT_HANDLE
*UsbDebugPortHandle
;
1025 // Validate the PCD PcdDebugPortHandleBufferSize value
1027 ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize
) == sizeof (USB3_DEBUG_PORT_HANDLE
));
1029 if (Function
== NULL
&& Context
!= NULL
) {
1030 UsbDebugPortHandle
= (USB3_DEBUG_PORT_HANDLE
*)Context
;
1032 ZeroMem(&Handle
, sizeof (USB3_DEBUG_PORT_HANDLE
));
1033 UsbDebugPortHandle
= &Handle
;
1036 if (Function
== NULL
&& Context
!= NULL
) {
1037 return (DEBUG_PORT_HANDLE
*) Context
;
1041 // Read 64-bit MMIO base address
1043 UsbDebugPortHandle
->XhciMmioBase
= ProgramXhciBaseAddress ();
1045 Status
= CalculateUsbDebugPortMmioBase (UsbDebugPortHandle
);
1046 if (RETURN_ERROR (Status
)) {
1050 if (NeedReinitializeHardware(&Handle
)) {
1051 Status
= InitializeUsbDebugHardware (&Handle
);
1052 if (RETURN_ERROR(Status
)) {
1059 if (Function
!= NULL
) {
1060 Function (Context
, &Handle
);
1062 CopyMem(&mDebugCommunicationLibUsb3DebugPortHandle
, &Handle
, sizeof (USB3_DEBUG_PORT_HANDLE
));
1065 return (DEBUG_PORT_HANDLE
)(UINTN
)&mDebugCommunicationLibUsb3DebugPortHandle
;