diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c index 381d7a9536..c05431ff30 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c @@ -399,24 +399,31 @@ XhcGetRootHubPortStatus ( // // According to XHCI 1.1 spec November 2017, - // bit 10~13 of the root port status register identifies the speed of the attached device. + // Section 7.2 xHCI Support Protocol Capability // - switch ((State & XHC_PORTSC_PS) >> 10) { - case 2: - PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; - break; + PortStatus->PortStatus = XhcCheckUsbPortSpeedUsedPsic (Xhc, ((State & XHC_PORTSC_PS) >> 10)); + if (PortStatus->PortStatus == 0) { + // + // According to XHCI 1.1 spec November 2017, + // bit 10~13 of the root port status register identifies the speed of the attached device. + // + switch ((State & XHC_PORTSC_PS) >> 10) { + case 2: + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + break; - case 3: - PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; - break; + case 3: + PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; + break; - case 4: - case 5: - PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED; - break; + case 4: + case 5: + PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED; + break; - default: - break; + default: + break; + } } // @@ -1826,6 +1833,8 @@ XhcCreateUsbHc ( Xhc->ExtCapRegBase = ExtCapReg << 2; Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY); Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG); + Xhc->Usb2SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB2); + Xhc->Usb3SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB3); DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength)); DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1)); @@ -1835,6 +1844,8 @@ XhcCreateUsbHc ( DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff)); DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset)); DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset)); + DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb2SupOffset 0x%x\n", Xhc->Usb2SupOffset)); + DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb3SupOffset 0x%x\n", Xhc->Usb3SupOffset)); // // Create AsyncRequest Polling Timer diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h index 5054d796b1..ca223bd20c 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h +++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h @@ -227,6 +227,8 @@ struct _USB_XHCI_INSTANCE { UINT32 ExtCapRegBase; UINT32 UsbLegSupOffset; UINT32 DebugCapSupOffset; + UINT32 Usb2SupOffset; + UINT32 Usb3SupOffset; UINT64 *DCBAA; VOID *DCBAAMap; UINT32 MaxSlotsEn; diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c index 80be3311d4..2b4a4b2444 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c @@ -575,6 +575,184 @@ XhcGetCapabilityAddr ( return 0xFFFFFFFF; } +/** + Calculate the offset of the xHCI Supported Protocol Capability. + + @param Xhc The XHCI Instance. + @param MajorVersion The USB Major Version in xHCI Support Protocol Capability Field + + @return The offset of xHCI Supported Protocol capability register. + +**/ +UINT32 +XhcGetSupportedProtocolCapabilityAddr ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 MajorVersion + ) +{ + UINT32 ExtCapOffset; + UINT8 NextExtCapReg; + UINT32 Data; + UINT32 NameString; + XHC_SUPPORTED_PROTOCOL_DW0 UsbSupportDw0; + + if (Xhc == NULL) { + return 0; + } + + ExtCapOffset = 0; + + do { + // + // Check if the extended capability register's capability id is USB Legacy Support. + // + Data = XhcReadExtCapReg (Xhc, ExtCapOffset); + UsbSupportDw0.Dword = Data; + if ((Data & 0xFF) == XHC_CAP_USB_SUPPORTED_PROTOCOL) { + if (UsbSupportDw0.Data.RevMajor == MajorVersion) { + NameString = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_NAME_STRING_OFFSET); + if (NameString == XHC_SUPPORTED_PROTOCOL_NAME_STRING_VALUE) { + // + // Ensure Name String field is xHCI supported protocols in xHCI Supported Protocol Capability Offset 04h + // + return ExtCapOffset; + } + } + } + + // + // If not, then traverse all of the ext capability registers till finding out it. + // + NextExtCapReg = (UINT8)((Data >> 8) & 0xFF); + ExtCapOffset += (NextExtCapReg << 2); + } while (NextExtCapReg != 0); + + return 0xFFFFFFFF; +} + +/** + Find PortSpeed value match Protocol Speed ID Value (PSIV). + + @param Xhc The XHCI Instance. + @param ExtCapOffset The USB Major Version in xHCI Support Protocol Capability Field + @param PortSpeed The Port Speed Field in USB PortSc register + + @return The Protocol Speed ID (PSI) from xHCI Supported Protocol capability register. + +**/ +UINT32 +XhciPsivGetPsid ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT32 ExtCapOffset, + IN UINT8 PortSpeed + ) +{ + XHC_SUPPORTED_PROTOCOL_DW2 PortId; + XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID Reg; + UINT32 Count; + + if ((Xhc == NULL) || (ExtCapOffset == 0xFFFFFFFF)) { + return 0; + } + + // + // According to XHCI 1.1 spec November 2017, + // Section 7.2 xHCI Supported Protocol Capability + // 1. Get the PSIC(Protocol Speed ID Count) value. + // 2. The PSID register boundary should be Base address + PSIC * 0x04 + // + PortId.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_DW2_OFFSET); + + for (Count = 0; Count < PortId.Data.Psic; Count++) { + Reg.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_PSI_OFFSET + (Count << 2)); + if (Reg.Data.Psiv == PortSpeed) { + return Reg.Dword; + } + } + + return 0; +} + +/** + Find PortSpeed value match case in XHCI Supported Protocol Capability + + @param Xhc The XHCI Instance. + @param PortSpeed The Port Speed Field in USB PortSc register + + @return The USB Port Speed. + +**/ +UINT16 +XhcCheckUsbPortSpeedUsedPsic ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 PortSpeed + ) +{ + XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID SpField; + UINT16 UsbSpeedIdMap; + + if (Xhc == NULL) { + return 0; + } + + SpField.Dword = 0; + UsbSpeedIdMap = 0; + + // + // Check xHCI Supported Protocol Capability, find the PSIV field to match + // PortSpeed definition when the Major Revision is 03h. + // + if (Xhc->Usb3SupOffset != 0xFFFFFFFF) { + SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb3SupOffset, PortSpeed); + if (SpField.Dword != 0) { + // + // Found the corresponding PORTSC value in PSIV field of USB3 offset. + // + UsbSpeedIdMap = USB_PORT_STAT_SUPER_SPEED; + } + } + + // + // Check xHCI Supported Protocol Capability, find the PSIV field to match + // PortSpeed definition when the Major Revision is 02h. + // + if ((UsbSpeedIdMap == 0) && (Xhc->Usb2SupOffset != 0xFFFFFFFF)) { + SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb2SupOffset, PortSpeed); + if (SpField.Dword != 0) { + // + // Found the corresponding PORTSC value in PSIV field of USB2 offset. + // + if (SpField.Data.Psie == 2) { + // + // According to XHCI 1.1 spec November 2017, + // Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition, + // PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 2 shall represent bit rate in Mb/s + // + if (SpField.Data.Psim == XHC_SUPPORTED_PROTOCOL_USB2_HIGH_SPEED_PSIM) { + // + // PSIM shows as default High-speed protocol, apply to High-speed mapping + // + UsbSpeedIdMap = USB_PORT_STAT_HIGH_SPEED; + } + } else if (SpField.Data.Psie == 1) { + // + // According to XHCI 1.1 spec November 2017, + // Section 7.2.1 the Protocol Speed ID Exponent (PSIE) field definition, + // PSIE value shall be applied to Protocol Speed ID Mantissa when calculating, value 1 shall represent bit rate in Kb/s + // + if (SpField.Data.Psim == XHC_SUPPORTED_PROTOCOL_USB2_LOW_SPEED_PSIM) { + // + // PSIM shows as default Low-speed protocol, apply to Low-speed mapping + // + UsbSpeedIdMap = USB_PORT_STAT_LOW_SPEED; + } + } + } + } + + return UsbSpeedIdMap; +} + /** Whether the XHCI host controller is halted. diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h index 4950eed272..5fe2ba4f0e 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h @@ -25,8 +25,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define USB_HUB_CLASS_CODE 0x09 #define USB_HUB_SUBCLASS_CODE 0x00 -#define XHC_CAP_USB_LEGACY 0x01 -#define XHC_CAP_USB_DEBUG 0x0A +#define XHC_CAP_USB_LEGACY 0x01 +#define XHC_CAP_USB_DEBUG 0x0A +#define XHC_CAP_USB_SUPPORTED_PROTOCOL 0x02 // ============================================// // XHCI register offset // @@ -74,6 +75,18 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define USBLEGSP_BIOS_SEMAPHORE BIT16 // HC BIOS Owned Semaphore #define USBLEGSP_OS_SEMAPHORE BIT24 // HC OS Owned Semaphore +// +// xHCI Supported Protocol Capability +// +#define XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB2 0x02 +#define XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB3 0x03 +#define XHC_SUPPORTED_PROTOCOL_NAME_STRING_OFFSET 0x04 +#define XHC_SUPPORTED_PROTOCOL_NAME_STRING_VALUE 0x20425355 +#define XHC_SUPPORTED_PROTOCOL_DW2_OFFSET 0x08 +#define XHC_SUPPORTED_PROTOCOL_PSI_OFFSET 0x10 +#define XHC_SUPPORTED_PROTOCOL_USB2_HIGH_SPEED_PSIM 480 +#define XHC_SUPPORTED_PROTOCOL_USB2_LOW_SPEED_PSIM 1500 + #pragma pack (1) typedef struct { UINT8 MaxSlots; // Number of Device Slots @@ -130,6 +143,52 @@ typedef union { HCCPARAMS Data; } XHC_HCCPARAMS; +// +// xHCI Supported Protocol Cabability +// +typedef struct { + UINT8 CapId; + UINT8 NextExtCapReg; + UINT8 RevMinor; + UINT8 RevMajor; +} SUPPORTED_PROTOCOL_DW0; + +typedef union { + UINT32 Dword; + SUPPORTED_PROTOCOL_DW0 Data; +} XHC_SUPPORTED_PROTOCOL_DW0; + +typedef struct { + UINT32 NameString; +} XHC_SUPPORTED_PROTOCOL_DW1; + +typedef struct { + UINT8 CompPortOffset; + UINT8 CompPortCount; + UINT16 ProtocolDef : 12; + UINT16 Psic : 4; +} SUPPORTED_PROTOCOL_DW2; + +typedef union { + UINT32 Dword; + SUPPORTED_PROTOCOL_DW2 Data; +} XHC_SUPPORTED_PROTOCOL_DW2; + +typedef struct { + UINT16 Psiv : 4; + UINT16 Psie : 2; + UINT16 Plt : 2; + UINT16 Pfd : 1; + UINT16 RsvdP : 5; + UINT16 Lp : 2; + UINT16 Psim; +} SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID; + +typedef union { + UINT32 Dword; + SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID Data; +} XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID; + #pragma pack () // @@ -546,4 +605,34 @@ XhcGetCapabilityAddr ( IN UINT8 CapId ); +/** + Calculate the offset of the xHCI Supported Protocol Capability. + + @param Xhc The XHCI Instance. + @param MajorVersion The USB Major Version in xHCI Support Protocol Capability Field + + @return The offset of xHCI Supported Protocol capability register. + +**/ +UINT32 +XhcGetSupportedProtocolCapabilityAddr ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 MajorVersion + ); + +/** + Find SpeedField value match with Port Speed ID value. + + @param Xhc The XHCI Instance. + @param Speed The Port Speed filed in USB PortSc register + + @return The USB Port Speed. + +**/ +UINT16 +XhcCheckUsbPortSpeedUsedPsic ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 Speed + ); + #endif