3 The XHCI register operation routines.
5 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Read 1-byte width XHCI capability register.
15 @param Xhc The XHCI Instance.
16 @param Offset The offset of the 1-byte width capability register.
18 @return The register content read.
19 @retval If err, return 0xFF.
24 IN USB_XHCI_INSTANCE
*Xhc
,
31 Status
= Xhc
->PciIo
->Mem
.Read (
40 if (EFI_ERROR (Status
)) {
41 DEBUG ((DEBUG_ERROR
, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status
, Offset
));
49 Read 4-bytes width XHCI capability register.
51 @param Xhc The XHCI Instance.
52 @param Offset The offset of the 4-bytes width capability register.
54 @return The register content read.
55 @retval If err, return 0xFFFFFFFF.
60 IN USB_XHCI_INSTANCE
*Xhc
,
67 Status
= Xhc
->PciIo
->Mem
.Read (
76 if (EFI_ERROR (Status
)) {
77 DEBUG ((DEBUG_ERROR
, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status
, Offset
));
85 Read 4-bytes width XHCI Operational register.
87 @param Xhc The XHCI Instance.
88 @param Offset The offset of the 4-bytes width operational register.
90 @return The register content read.
91 @retval If err, return 0xFFFFFFFF.
96 IN USB_XHCI_INSTANCE
*Xhc
,
103 ASSERT (Xhc
->CapLength
!= 0);
105 Status
= Xhc
->PciIo
->Mem
.Read (
109 Xhc
->CapLength
+ Offset
,
114 if (EFI_ERROR (Status
)) {
115 DEBUG ((DEBUG_ERROR
, "XhcReadOpReg: Pci Io Read error - %r at %d\n", Status
, Offset
));
123 Write the data to the 4-bytes width XHCI operational register.
125 @param Xhc The XHCI Instance.
126 @param Offset The offset of the 4-bytes width operational register.
127 @param Data The data to write.
132 IN USB_XHCI_INSTANCE
*Xhc
,
139 ASSERT (Xhc
->CapLength
!= 0);
141 Status
= Xhc
->PciIo
->Mem
.Write (
145 Xhc
->CapLength
+ Offset
,
150 if (EFI_ERROR (Status
)) {
151 DEBUG ((DEBUG_ERROR
, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
156 Write the data to the XHCI door bell register.
158 @param Xhc The XHCI Instance.
159 @param Offset The offset of the door bell register.
160 @param Data The data to write.
164 XhcWriteDoorBellReg (
165 IN USB_XHCI_INSTANCE
*Xhc
,
172 ASSERT (Xhc
->DBOff
!= 0);
174 Status
= Xhc
->PciIo
->Mem
.Write (
183 if (EFI_ERROR (Status
)) {
184 DEBUG ((DEBUG_ERROR
, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
189 Read XHCI runtime register.
191 @param Xhc The XHCI Instance.
192 @param Offset The offset of the runtime register.
194 @return The register content read
199 IN USB_XHCI_INSTANCE
*Xhc
,
206 ASSERT (Xhc
->RTSOff
!= 0);
208 Status
= Xhc
->PciIo
->Mem
.Read (
212 Xhc
->RTSOff
+ Offset
,
217 if (EFI_ERROR (Status
)) {
218 DEBUG ((DEBUG_ERROR
, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status
, Offset
));
226 Write the data to the XHCI runtime register.
228 @param Xhc The XHCI Instance.
229 @param Offset The offset of the runtime register.
230 @param Data The data to write.
235 IN USB_XHCI_INSTANCE
*Xhc
,
242 ASSERT (Xhc
->RTSOff
!= 0);
244 Status
= Xhc
->PciIo
->Mem
.Write (
248 Xhc
->RTSOff
+ Offset
,
253 if (EFI_ERROR (Status
)) {
254 DEBUG ((DEBUG_ERROR
, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
259 Read XHCI extended capability register.
261 @param Xhc The XHCI Instance.
262 @param Offset The offset of the extended capability register.
264 @return The register content read
269 IN USB_XHCI_INSTANCE
*Xhc
,
276 ASSERT (Xhc
->ExtCapRegBase
!= 0);
278 Status
= Xhc
->PciIo
->Mem
.Read (
282 Xhc
->ExtCapRegBase
+ Offset
,
287 if (EFI_ERROR (Status
)) {
288 DEBUG ((DEBUG_ERROR
, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status
, Offset
));
296 Write the data to the XHCI extended capability register.
298 @param Xhc The XHCI Instance.
299 @param Offset The offset of the extended capability register.
300 @param Data The data to write.
305 IN USB_XHCI_INSTANCE
*Xhc
,
312 ASSERT (Xhc
->ExtCapRegBase
!= 0);
314 Status
= Xhc
->PciIo
->Mem
.Write (
318 Xhc
->ExtCapRegBase
+ Offset
,
323 if (EFI_ERROR (Status
)) {
324 DEBUG ((DEBUG_ERROR
, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status
, Offset
));
329 Set one bit of the runtime register while keeping other bits.
331 @param Xhc The XHCI Instance.
332 @param Offset The offset of the runtime register.
333 @param Bit The bit mask of the register to set.
337 XhcSetRuntimeRegBit (
338 IN USB_XHCI_INSTANCE
*Xhc
,
345 Data
= XhcReadRuntimeReg (Xhc
, Offset
);
347 XhcWriteRuntimeReg (Xhc
, Offset
, Data
);
351 Clear one bit of the runtime register while keeping other bits.
353 @param Xhc The XHCI Instance.
354 @param Offset The offset of the runtime register.
355 @param Bit The bit mask of the register to set.
359 XhcClearRuntimeRegBit (
360 IN USB_XHCI_INSTANCE
*Xhc
,
367 Data
= XhcReadRuntimeReg (Xhc
, Offset
);
369 XhcWriteRuntimeReg (Xhc
, Offset
, Data
);
373 Set one bit of the operational register while keeping other bits.
375 @param Xhc The XHCI Instance.
376 @param Offset The offset of the operational register.
377 @param Bit The bit mask of the register to set.
382 IN USB_XHCI_INSTANCE
*Xhc
,
389 Data
= XhcReadOpReg (Xhc
, Offset
);
391 XhcWriteOpReg (Xhc
, Offset
, Data
);
395 Clear one bit of the operational register while keeping other bits.
397 @param Xhc The XHCI Instance.
398 @param Offset The offset of the operational register.
399 @param Bit The bit mask of the register to clear.
404 IN USB_XHCI_INSTANCE
*Xhc
,
411 Data
= XhcReadOpReg (Xhc
, Offset
);
413 XhcWriteOpReg (Xhc
, Offset
, Data
);
417 Wait the operation register's bit as specified by Bit
418 to become set (or clear).
420 @param Xhc The XHCI Instance.
421 @param Offset The offset of the operation register.
422 @param Bit The bit of the register to wait for.
423 @param WaitToSet Wait the bit to set or clear.
424 @param Timeout The time to wait before abort (in millisecond, ms).
426 @retval EFI_SUCCESS The bit successfully changed by host controller.
427 @retval EFI_TIMEOUT The time out occurred.
428 @retval EFI_OUT_OF_RESOURCES Memory for the timer event could not be allocated.
433 IN USB_XHCI_INSTANCE
*Xhc
,
436 IN BOOLEAN WaitToSet
,
441 EFI_EVENT TimeoutEvent
;
449 Status
= gBS
->CreateEvent (
457 if (EFI_ERROR (Status
)) {
461 Status
= gBS
->SetTimer (
464 EFI_TIMER_PERIOD_MILLISECONDS (Timeout
)
467 if (EFI_ERROR (Status
)) {
472 if (XHC_REG_BIT_IS_SET (Xhc
, Offset
, Bit
) == WaitToSet
) {
473 Status
= EFI_SUCCESS
;
477 gBS
->Stall (XHC_1_MICROSECOND
);
478 } while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
)));
480 Status
= EFI_TIMEOUT
;
483 if (TimeoutEvent
!= NULL
) {
484 gBS
->CloseEvent (TimeoutEvent
);
493 @param Xhc The XHCI Instance.
497 XhcSetBiosOwnership (
498 IN USB_XHCI_INSTANCE
*Xhc
503 if (Xhc
->UsbLegSupOffset
== 0xFFFFFFFF) {
507 DEBUG ((DEBUG_INFO
, "XhcSetBiosOwnership: called to set BIOS ownership\n"));
509 Buffer
= XhcReadExtCapReg (Xhc
, Xhc
->UsbLegSupOffset
);
510 Buffer
= ((Buffer
& (~USBLEGSP_OS_SEMAPHORE
)) | USBLEGSP_BIOS_SEMAPHORE
);
511 XhcWriteExtCapReg (Xhc
, Xhc
->UsbLegSupOffset
, Buffer
);
517 @param Xhc The XHCI Instance.
521 XhcClearBiosOwnership (
522 IN USB_XHCI_INSTANCE
*Xhc
527 if (Xhc
->UsbLegSupOffset
== 0xFFFFFFFF) {
531 DEBUG ((DEBUG_INFO
, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));
533 Buffer
= XhcReadExtCapReg (Xhc
, Xhc
->UsbLegSupOffset
);
534 Buffer
= ((Buffer
& (~USBLEGSP_BIOS_SEMAPHORE
)) | USBLEGSP_OS_SEMAPHORE
);
535 XhcWriteExtCapReg (Xhc
, Xhc
->UsbLegSupOffset
, Buffer
);
539 Calculate the offset of the XHCI capability.
541 @param Xhc The XHCI Instance.
542 @param CapId The XHCI Capability ID.
544 @return The offset of XHCI legacy support capability register.
548 XhcGetCapabilityAddr (
549 IN USB_XHCI_INSTANCE
*Xhc
,
561 // Check if the extended capability register's capability id is USB Legacy Support.
563 Data
= XhcReadExtCapReg (Xhc
, ExtCapOffset
);
564 if ((Data
& 0xFF) == CapId
) {
569 // If not, then traverse all of the ext capability registers till finding out it.
571 NextExtCapReg
= (UINT8
)((Data
>> 8) & 0xFF);
572 ExtCapOffset
+= (NextExtCapReg
<< 2);
573 } while (NextExtCapReg
!= 0);
579 Calculate the offset of the xHCI Supported Protocol Capability.
581 @param Xhc The XHCI Instance.
582 @param MajorVersion The USB Major Version in xHCI Support Protocol Capability Field
584 @return The offset of xHCI Supported Protocol capability register.
588 XhcGetSupportedProtocolCapabilityAddr (
589 IN USB_XHCI_INSTANCE
*Xhc
,
590 IN UINT8 MajorVersion
597 XHC_SUPPORTED_PROTOCOL_DW0 UsbSupportDw0
;
607 // Check if the extended capability register's capability id is USB Legacy Support.
609 Data
= XhcReadExtCapReg (Xhc
, ExtCapOffset
);
610 UsbSupportDw0
.Dword
= Data
;
611 if ((Data
& 0xFF) == XHC_CAP_USB_SUPPORTED_PROTOCOL
) {
612 if (UsbSupportDw0
.Data
.RevMajor
== MajorVersion
) {
613 NameString
= XhcReadExtCapReg (Xhc
, ExtCapOffset
+ XHC_SUPPORTED_PROTOCOL_NAME_STRING_OFFSET
);
614 if (NameString
== XHC_SUPPORTED_PROTOCOL_NAME_STRING_VALUE
) {
616 // Ensure Name String field is xHCI supported protocols in xHCI Supported Protocol Capability Offset 04h
624 // If not, then traverse all of the ext capability registers till finding out it.
626 NextExtCapReg
= (UINT8
)((Data
>> 8) & 0xFF);
627 ExtCapOffset
+= (NextExtCapReg
<< 2);
628 } while (NextExtCapReg
!= 0);
634 Find PortSpeed value match Protocol Speed ID Value (PSIV).
636 @param Xhc The XHCI Instance.
637 @param ExtCapOffset The USB Major Version in xHCI Support Protocol Capability Field
638 @param PortSpeed The Port Speed Field in USB PortSc register
639 @param PortNumber The Port Number (0-indexed)
641 @return The Protocol Speed ID (PSI) from xHCI Supported Protocol capability register.
646 IN USB_XHCI_INSTANCE
*Xhc
,
647 IN UINT32 ExtCapOffset
,
652 XHC_SUPPORTED_PROTOCOL_DW2 PortId
;
653 XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID Reg
;
658 if ((Xhc
== NULL
) || (ExtCapOffset
== 0xFFFFFFFF)) {
663 // According to XHCI 1.1 spec November 2017,
664 // Section 7.2 xHCI Supported Protocol Capability
665 // 1. Get the PSIC(Protocol Speed ID Count) value.
666 // 2. The PSID register boundary should be Base address + PSIC * 0x04
668 PortId
.Dword
= XhcReadExtCapReg (Xhc
, ExtCapOffset
+ XHC_SUPPORTED_PROTOCOL_DW2_OFFSET
);
671 // According to XHCI 1.1 spec November 2017, valid values
672 // for CompPortOffset are 1 to CompPortCount - 1.
674 // PortNumber is zero-indexed, so subtract 1.
676 if ((PortId
.Data
.CompPortOffset
== 0) || (PortId
.Data
.CompPortCount
== 0)) {
680 MinPortIndex
= PortId
.Data
.CompPortOffset
- 1;
681 MaxPortIndex
= MinPortIndex
+ PortId
.Data
.CompPortCount
- 1;
683 if ((PortNumber
< MinPortIndex
) || (PortNumber
> MaxPortIndex
)) {
687 for (Count
= 0; Count
< PortId
.Data
.Psic
; Count
++) {
688 Reg
.Dword
= XhcReadExtCapReg (Xhc
, ExtCapOffset
+ XHC_SUPPORTED_PROTOCOL_PSI_OFFSET
+ (Count
<< 2));
689 if (Reg
.Data
.Psiv
== PortSpeed
) {
698 Find PortSpeed value match case in XHCI Supported Protocol Capability
700 @param Xhc The XHCI Instance.
701 @param PortSpeed The Port Speed Field in USB PortSc register
702 @param PortNumber The Port Number (0-indexed)
704 @return The USB Port Speed.
708 XhcCheckUsbPortSpeedUsedPsic (
709 IN USB_XHCI_INSTANCE
*Xhc
,
714 XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID SpField
;
715 UINT16 UsbSpeedIdMap
;
725 // Check xHCI Supported Protocol Capability, find the PSIV field to match
726 // PortSpeed definition when the Major Revision is 03h.
728 if (Xhc
->Usb3SupOffset
!= 0xFFFFFFFF) {
729 SpField
.Dword
= XhciPsivGetPsid (Xhc
, Xhc
->Usb3SupOffset
, PortSpeed
, PortNumber
);
730 if (SpField
.Dword
!= 0) {
732 // Found the corresponding PORTSC value in PSIV field of USB3 offset.
734 UsbSpeedIdMap
= USB_PORT_STAT_SUPER_SPEED
;
739 // Check xHCI Supported Protocol Capability, find the PSIV field to match
740 // PortSpeed definition when the Major Revision is 02h.
742 if ((UsbSpeedIdMap
== 0) && (Xhc
->Usb2SupOffset
!= 0xFFFFFFFF)) {
743 SpField
.Dword
= XhciPsivGetPsid (Xhc
, Xhc
->Usb2SupOffset
, PortSpeed
, PortNumber
);
744 if (SpField
.Dword
!= 0) {
746 // Found the corresponding PORTSC value in PSIV field of USB2 offset.
748 if (SpField
.Data
.Psie
== 2) {
750 // According to XHCI 1.1 spec November 2017,
751 // Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition,
752 // PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 2 shall represent bit rate in Mb/s
754 if (SpField
.Data
.Psim
== XHC_SUPPORTED_PROTOCOL_USB2_HIGH_SPEED_PSIM
) {
756 // PSIM shows as default High-speed protocol, apply to High-speed mapping
758 UsbSpeedIdMap
= USB_PORT_STAT_HIGH_SPEED
;
760 } else if (SpField
.Data
.Psie
== 1) {
762 // According to XHCI 1.1 spec November 2017,
763 // Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition,
764 // PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 1 shall represent bit rate in Kb/s
766 if (SpField
.Data
.Psim
== XHC_SUPPORTED_PROTOCOL_USB2_LOW_SPEED_PSIM
) {
768 // PSIM shows as default Low-speed protocol, apply to Low-speed mapping
770 UsbSpeedIdMap
= USB_PORT_STAT_LOW_SPEED
;
776 return UsbSpeedIdMap
;
780 Whether the XHCI host controller is halted.
782 @param Xhc The XHCI Instance.
784 @retval TRUE The controller is halted.
785 @retval FALSE It isn't halted.
790 IN USB_XHCI_INSTANCE
*Xhc
793 return XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
);
797 Whether system error occurred.
799 @param Xhc The XHCI Instance.
801 @retval TRUE System error happened.
802 @retval FALSE No system error.
807 IN USB_XHCI_INSTANCE
*Xhc
810 return XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HSE
);
814 Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.
816 The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).
817 This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
819 @param Xhc The XHCI Instance.
824 IN USB_XHCI_INSTANCE
*Xhc
828 EFI_PCI_IO_PROTOCOL
*PciIo
;
832 Status
= PciIo
->Pci
.Read (
836 sizeof (XhciCmd
) / sizeof (UINT16
),
839 if (!EFI_ERROR (Status
)) {
840 if ((XhciCmd
& EFI_PCI_COMMAND_SERR
) != 0) {
841 XhcSetOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_HSEE
);
847 Reset the XHCI host controller.
849 @param Xhc The XHCI Instance.
850 @param Timeout Time to wait before abort (in millisecond, ms).
852 @retval EFI_SUCCESS The XHCI host controller is reset.
853 @return Others Failed to reset the XHCI before Timeout.
858 IN USB_XHCI_INSTANCE
*Xhc
,
864 Status
= EFI_SUCCESS
;
866 DEBUG ((DEBUG_INFO
, "XhcResetHC!\n"));
868 // Host can only be reset when it is halt. If not so, halt it
870 if (!XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
)) {
871 Status
= XhcHaltHC (Xhc
, Timeout
);
873 if (EFI_ERROR (Status
)) {
878 if ((Xhc
->DebugCapSupOffset
== 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc
, Xhc
->DebugCapSupOffset
) & 0xFF) != XHC_CAP_USB_DEBUG
) ||
879 ((XhcReadExtCapReg (Xhc
, Xhc
->DebugCapSupOffset
+ XHC_DC_DCCTRL
) & BIT0
) == 0))
881 XhcSetOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RESET
);
883 // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.
884 // Otherwise there may have the timeout case happened.
885 // The below is a workaround to solve such problem.
887 gBS
->Stall (XHC_1_MILLISECOND
);
888 Status
= XhcWaitOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RESET
, FALSE
, Timeout
);
890 if (!EFI_ERROR (Status
)) {
892 // The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.
893 // Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.
903 Halt the XHCI host controller.
905 @param Xhc The XHCI Instance.
906 @param Timeout Time to wait before abort (in millisecond, ms).
908 @return EFI_SUCCESS The XHCI host controller is halt.
909 @return EFI_TIMEOUT Failed to halt the XHCI before Timeout.
914 IN USB_XHCI_INSTANCE
*Xhc
,
920 XhcClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RUN
);
921 Status
= XhcWaitOpRegBit (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
, TRUE
, Timeout
);
926 Set the XHCI host controller to run.
928 @param Xhc The XHCI Instance.
929 @param Timeout Time to wait before abort (in millisecond, ms).
931 @return EFI_SUCCESS The XHCI host controller is running.
932 @return EFI_TIMEOUT Failed to set the XHCI to run before Timeout.
937 IN USB_XHCI_INSTANCE
*Xhc
,
943 XhcSetOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_RUN
);
944 Status
= XhcWaitOpRegBit (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
, FALSE
, Timeout
);