/** @file ;****************************************************************************** ;* Copyright (c) 2017 - 2020, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** **/ #include #include #include #include #include #include #include #include #include #include #include #include "PchDdtUsbPei.h" /** Helper function for gathering of xHCI controller features and infromation @param[in] XhciPciBase xHCI PCI config space address @param[out] HcInfo xHCI controller information structure **/ STATIC VOID GetXhciControllerInfo ( IN UINT64 XhciPciBase, OUT USB_CONTROLLER_INFO *HcInfo ) { UINT16 ControllerDid; ZeroMem (HcInfo, sizeof (USB_CONTROLLER_INFO)); // Check device DID from given PCI config space ControllerDid = PciSegmentRead16 (XhciPciBase + PCI_DEVICE_ID_OFFSET); HcInfo->DeviceId = ControllerDid; switch (HcInfo->DeviceId) { case V_XHCI_DID_CNP_LP: case V_XHCI_DID_CNP_H: HcInfo->OnSouth = TRUE; HcInfo->IpVersion = V16_0; break; case V_XHCI_DID_CPU_V17_0_1: HcInfo->IpVersion = V17_0; HcInfo->OnSouth = FALSE; break; case V_XHCI_DID_PCH_V17_1_1: HcInfo->OnSouth = TRUE; HcInfo->IpVersion = V17_1; break; case V_XHCI_DID_PCH_V17_1_2: case V_XHCI_DID_PCH_V17_1_3: HcInfo->OnSouth = TRUE; HcInfo->IpVersion = V17_1; break; } if ((HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_2) || (HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_3)) { HcInfo->UsbLtrHigh = V_XHCI_LTR_HIT_2; HcInfo->UsbLtrMid = V_XHCI_LTR_MIT_2; HcInfo->UsbLtrLow = V_XHCI_LTR_LIT_2; } else { HcInfo->UsbLtrHigh = V_XHCI_LTR_HIT_1; HcInfo->UsbLtrMid = V_XHCI_LTR_MIT_1; HcInfo->UsbLtrLow = V_XHCI_LTR_LIT_1; } DEBUG ((DEBUG_INFO, "xHCI Controller DID: 0x%4X\n", ControllerDid)); DEBUG ((DEBUG_INFO, "Params:\n UsbIpVersion: 0x%2X, Device: 0x%4X\n", HcInfo->IpVersion, HcInfo->DeviceId)); } /** Program and enable XHCI Memory Space @param[in] XhciPciBase XHCI PCI Base Address @param[in] XhciMmioBase Memory base address of XHCI Controller **/ VOID DdtXhciMemorySpaceOpen ( IN UINT64 XhciPciBase, IN UINT32 XhciMmioBase ) { // // Assign memory resources // PciSegmentWrite32 (XhciPciBase + R_XHCI_CFG_BAR0, XhciMmioBase); PciSegmentWrite32 (XhciPciBase + R_XHCI_CFG_BAR0 + 4, 0); PciSegmentOr16 ( XhciPciBase + PCI_COMMAND_OFFSET, (UINT16) (EFI_PCI_COMMAND_MEMORY_SPACE) ); } /* Helper function to return supported number of USB2 ports reported by Host Controller @param[in] XhciMmioBase Memory BAR of the xHCI controller */ STATIC UINT32 GetUsb2PortCount ( IN UINTN XhciMmioBase ) { return ((MmioRead32 (XhciMmioBase + R_XHCI_MEM_XECP_SUPP_USB2_2) & B_XHCI_MEM_XECP_SUPP_USBX_2_CPC) >> N_XHCI_MEM_XECP_SUPP_USBX_2_CPC); } /* Helper function to return supported number of USB3 ports reported by Host Controller @param[in] XhciMmioBase Memory BAR of the xHCI controller */ STATIC UINT32 GetUsb3PortCount ( IN UINTN XhciMmioBase ) { return ((MmioRead32 (XhciMmioBase + R_XHCI_MEM_XECP_SUPP_USB3_2) & B_XHCI_MEM_XECP_SUPP_USBX_2_CPC) >> N_XHCI_MEM_XECP_SUPP_USBX_2_CPC); } /** Performs basic configuration of USB3 (xHCI) controller. @param[in] HcInfo xHCI controller information structure @param[in] XhciPciBase xHCI PCI config space address @param[in] XhciMmioBase Memory base address of xHCI Controller @retval None **/ VOID DdtXhciHcInit ( IN USB_CONTROLLER_INFO *HcInfo, IN UINT64 XhciPciBase, IN UINT32 XhciMmioBase ) { UINT32 Data32; UINT32 Data32Or; UINT32 Data32And; UINT32 HsPortCount; UINT32 SsPortCount; UINT32 XhciUsb3Pdo; UINT32 XhciUsb3PortsMask; DEBUG ((DEBUG_INFO, "XhciHcInit XhciMmio Base = 0x%x\n", XhciMmioBase)); HsPortCount = GetUsb2PortCount (XhciMmioBase); SsPortCount = GetUsb3PortCount (XhciMmioBase); DEBUG ((DEBUG_INFO, "Number of supported Super Speed Ports = %d\n", SsPortCount)); DEBUG ((DEBUG_INFO, "Number of supported High Speed Ports = %d\n", HsPortCount)); // // XHCC1 - XHC System Bus Configuration 1 // Address Offset: 0x40 // Value: [21:19] 110b, [18] 1b, [8] 1b // Writes to this registers needs to be performed per bytes to avoid touching bit 31 // Bit 31 is used to lock RW/L bits and can be writen once. // PciSegmentOr8 ( XhciPciBase + R_XHCI_CFG_XHCC1 + 1, (UINT32) (BIT0) ); PciSegmentOr8 ( XhciPciBase + R_XHCI_CFG_XHCC1 + 2, (UINT32) (BIT5 | BIT4 | BIT2) ); // // DBGDEV_CTRL_REG1 - Debug Device Control Register 1 // Address Offset: 0x8754 // Value: [9] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_DBGDEV_CTRL_REG1), (UINT32) (BIT9) ); // // XHCC2 - XHC System Bus Configuration 2 // Address Offset: 0x44 // Value: [24:22] 001b, [21] 1b, [20:14] 1111111b, [10] 1b, [9:8] 10b, [7:6] 10b, [5:3] 001b, [2:0] 000b // Additionally for IP V17.0 and V17.1 [22] 1b [0] 1b // Additionally for IP V17.0 only [25:23] 111b [2:1] 11b // Data32Or = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16 | BIT15 | BIT14 | BIT10 | BIT9 | BIT7 | BIT3); if ((HcInfo->IpVersion == V17_0) || (HcInfo->IpVersion == V17_1)) { Data32Or |= (BIT22 | BIT0); } if (HcInfo->IpVersion == V17_0) { Data32Or |= (BIT25 | BIT24 | BIT23 | BIT2 | BIT1); } PciSegmentOr32 ( XhciPciBase + R_XHCI_CFG_XHCC2, Data32Or ); // // PMCTRL2 - Power Management Control 2 // Address Offset: 0x8468 // Value: [5] 1b, [0] 1b // This bits must be set before setting USB_SRAM_PG_EN (bit27) in XHCLKGTEN // This setting doesn't apply to CNP-LP Ax steppings // if (!((HcInfo->DeviceId == V_XHCI_DID_CNP_LP) && (PchStepping () < PCH_B0))) { MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_PMCTRL2), (UINT32) (BIT5 | BIT0) ); } // // XHCLKGTEN - Clock Gating // Address Offset: 0x50 // Value: 0x0FDF6D3F // Additionally for devices with IDs 0x38ED or 0x3DED // [17:16] 11b, [6] 0b // Data32 = 0x0FDF6D3F; if ((HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_2) || (HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_3)) { Data32 |= (BIT17 | BIT16); Data32 &= (UINT32)~(BIT6); } PciSegmentWrite32 ( (XhciPciBase + R_XHCI_CFG_XHCLKGTEN), Data32 ); // // MSI_NEXT - Next Item Pointer // Address Offset: 0x81 // Value: [7:0] 90h // PciSegmentWrite8 ( (XhciPciBase + R_XHCI_CFG_MSI_NEXT), 0x90 ); // // PCE - Power Control Enables // Address Offset: 0xA2 // Value: [5] 1b, [3] 1b, [2] 1b, [1] 1b // PciSegmentOr16 ( (XhciPciBase + R_XHCI_CFG_PCE), (UINT16) (BIT5 | BIT3 | BIT2 | BIT1) ); // // HSCFG2 - High Speed Configuration 2 // Address Offset: 0xA4 // [15:13] 000b // [12:11] 11b // PciSegmentAndThenOr32 ( (XhciPciBase + R_XHCI_CFG_HSCFG2), (UINT32) ~(BIT15 | BIT14 | BIT13), (UINT32) (BIT12 | BIT11) ); // // SSCFG1 - SuperSpeed Configuration 1 // Address Offset: 0xA8 // Value: [17] 1b, [14] 1b // PciSegmentOr32 ( (XhciPciBase + R_XHCI_CFG_SSCFG1), (UINT32) (BIT17 | BIT14) ); // // XHCC3 - XHC System Bus Configuration 3 // Address Offset: 0xFC // Value: [4] 1b // PciSegmentOr32 ( (XhciPciBase + R_XHCI_CFG_XHCC3), (UINT32) (BIT4) ); if (HcInfo->IpVersion == V16_0) { // // HCIVERSION - Host Controller Interface Version Number // Address Offset: 0x02 // Set [15:0] = 0110h // Only for IP V16.0 // //[-start-200420-IB17800060-modify]// //RC 1181.1 define change. //if HcInfo->IpVersion > V18_0 , V_XHCI_MEM_HCIVERSION_0120 //if HcInfo->IpVersion <= V18_0 , V_XHCI_MEM_HCIVERSION_0110 //MmioAndThenOr32 ( // (XhciMmioBase + R_XHCI_MEM_CAPLENGTH), // (UINT32) B_XHCI_MEM_HCIVERSION, // (UINT32) (V_XHCI_MEM_HCIVERSION << N_XHCI_MEM_HCIVERSION) // ); MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_CAPLENGTH), (UINT32) B_XHCI_MEM_HCIVERSION, (UINT32) (V_XHCI_MEM_HCIVERSION_0110 << N_XHCI_MEM_HCIVERSION) ); //[-end-200420-IB17800060-modify]// } // // HCSPARAMS3 - Structural Parameters 3 // Address Offset: 0x0C // Value: [31:16] = A0h, [7:0] = 0Ah // For CNP-LP A0 [31:16] = 0x0200 // Data32Or = 0x00A0000A; if ((HcInfo->DeviceId == V_XHCI_DID_CNP_LP) && (PchStepping () == PCH_A0)) { Data32Or = (0x0200 << N_XHCI_MEM_HCSPARAMS3_U2DEL) | (Data32Or & B_XHCI_MEM_HCSPARAMS3_U1DEL); } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_HCSPARAMS3), B_XHCI_MEM_HCSPARAMS3, Data32Or ); // // HCCPARAMS1 - Capability Parameters 1 // Address Offset: 0x10 // Value: [11] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HCCPARAMS1), (UINT32) (BIT11) ); // // HCCPARAMS2 - Capability Parameters 2 // Address Offset: 0x1C // Value: [6] 1b, [4] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HCCPARAMS2), (UINT32) (BIT6 | BIT4) ); // // XECP_CMDM_CTRL_REG1 - Command Manager Control 1 // Address Offset: 0x818C // Value: [20] 0b, [16] 1b, [8] 0b // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_XECP_CMDM_CTRL_REG1), (UINT32)~(BIT20 | BIT8), (UINT32) (BIT16) ); // // HOST_CTRL_ODMA_REG - Host Control ODMA Register // Address Offset: 0x8098 // Value: [2:1] 00b // MmioAnd32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_ODMA_REG), (UINT32)~(BIT2 | BIT1) ); // // PMCTRL - Power Management Control // Address Offset: 0x80A4 // Value: [30] 1b, [27] 1b, [24] 1b, [16] 1b, [15:8] 50h, [3] 1b, [2] 1b // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_PMCTRL), (UINT32) ~(B_XHCI_MEM_PMCTRL_SSU3LFPS_DET), (UINT32) (BIT30 | BIT27 | BIT24 | (0x50 << N_XHCI_MEM_PMCTRL_SSU3LPFS_DET) | BIT3 | BIT2) ); // // AUX_CTRL_REG3 - Aux PM Control 3 Register // Address Offset: 0x81C8 // Value: [6] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_AUX_CTRL_REG3), (UINT32) (BIT6) ); // // SSPE - Super Speed Port Enables // Address Offset: 0x80B8 // Value: [30] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_SSPE), (UINT32) (BIT30) ); // // AUX_CTRL_REG1 - AUX Power Management Control // Address Offset: 0x80E0 // Value: [16] 0b, [6] 1b // For CNP Ax steppings [16] 1b // Data32Or = (UINT32) (BIT6); if (((HcInfo->DeviceId == V_XHCI_DID_CNP_LP) || (HcInfo->DeviceId == V_XHCI_DID_CNP_H)) && (PchStepping () < PCH_B0)) { Data32Or |= BIT16; } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_AUX_CTRL_REG1), (UINT32) ~(BIT16), Data32Or ); // // HOST_CTRL_SCH_REG - Host Control Scheduler // Address Offset: 0x8094 // Value: [23] 1b, [22] 1b, [6] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_SCH_REG), (UINT32) (BIT23 | BIT22 | BIT6) ); // // HOST_CTRL_PORT_LINK_REG - SuperSpeed Port Link Control // Address Offset: 0x80EC // Value: [17] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_PORT_LINK_REG), (UINT32) (BIT17) ); // // USB2_LINK_MGR_CTRL_REG1 - USB2 Port Link Control 1, 2, 3, 4 // Address Offset: 0x80F0 // [127:96] is mapped to DW4 at offset 80FCh-80FFh [25] 1b // [31:0] is mapped to DW1 at offset 80F0h-80F3h [20] 0b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_USB2_LINK_MGR_CTRL_REG1_DW4), (UINT32) (BIT25) ); MmioAnd32 ( (XhciMmioBase + R_XHCI_MEM_USB2_LINK_MGR_CTRL_REG1_DW1), (UINT32) ~(BIT20) ); if (((HcInfo->DeviceId == V_XHCI_DID_CNP_LP) && (PchStepping () >= PCH_B0)) || (HcInfo->DeviceId == V_XHCI_DID_CNP_H)) { MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_USB2_LINK_MGR_CTRL_REG1_DW1), (UINT32) (BIT22) ); } // // HOST_CTRL_BW_CTRL_REG - Host Controller Bandwith Control Register // Address Offset: 0x8100 // Value: [21] 1b [20] 1b // Program only for IP V16.0 or for devices with IDs: // 0x8A13, 0x34ED or 0x38ED // if ((HcInfo->IpVersion == V16_0) || (HcInfo->DeviceId == V_XHCI_DID_CPU_V17_0_1) || (HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_1) || (HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_2)) { MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_BW_CTRL_REG), (UINT32) (BIT20 | BIT21) ); } // // HOST_IF_CTRL_REG - Host Controller Interface Control Register // Address Offset: 0x8108 // Value: [30] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_IF_CTRL_REG), (UINT32) (BIT30) ); // // HOST_CTRL_TRM_REG2 - Host Controller Transfer Manager Control 2 // Address Offset: 0x8110 // Value: [20] 1b, [11] 1b, [2] 0b, // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_TRM_REG2), (UINT32)~(BIT2), (UINT32) (BIT20 | BIT11) ); // // HOST_CTRL_BW_MAX_REG - MAX BW Control Reg 4 // Address Offset: 0x8128 // Value: V16_0 [47:36] - 0xFFF for CNP A0, 0x528 (default) for rest // Value: [23:12] 0x753 // if (HcInfo->OnSouth) { if (((HcInfo->DeviceId == V_XHCI_DID_CNP_LP) || (HcInfo->DeviceId == V_XHCI_DID_CNP_H)) && (PchStepping () == PCH_A0)) { MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_BW_MAX_REG + 4), (UINT32) (0xFFF << 4) ); } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_BW_MAX_REG), (UINT32)~(B_XHCI_MEM_HOST_CTRL_BW_MAX_REG_MAX_HS_BW), (UINT32) (0x753 << N_XHCI_MEM_HOST_CTRL_BW_MAX_REG_MAX_HS_BW) ); } // // AUX_CTRL_REG2 - Aux PM Control Register 2 // Address Offset: 0x8154 // Value: [21] 0b, [13] 1b // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_AUX_CTRL_REG2), (UINT32) ~(BIT21), (UINT32) (BIT13) ); // // xHCI Aux Clock Control Register // Address Offset: 0x816C // [11:8] 0h // [19] 1b, [18] 1b, [17] 1b, [16] 1b, [14] 1b, [5] 1b, [4] 1b, [3] 1b, [2] 1b // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_AUXCLKCTL), (UINT32) ~(BIT11 | BIT10 | BIT9 | BIT8), (UINT32) (BIT19 | BIT18 | BIT17 | BIT16 | BIT14 | BIT5 | BIT4 | BIT3 | BIT2) ); // // HOST_IF_PWR_CTRL_REG0 - Power Scheduler Control 0 // Address Offset: 0x8140 // Value: [31:24] 0xFF, [23:12] 0x00F, [11:0] 0x03C // MmioWrite32 ( (XhciMmioBase + R_XHCI_MEM_HOST_IF_PWR_CTRL_REG0), 0xFF00F03C ); // // HOST_IF_PWR_CTRL_REG1 - Power Scheduler Control 1 // Address Offset: 0x8144 // Value: [24] 1b // Applies only to devices with IDs 0x38ED or 0x3DED // if ((HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_2) || (HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_3)) { MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_IF_PWR_CTRL_REG1), (UINT32) (BIT24) ); } // // USBLPM - USB LPM Parameters // Address Offset: 0x8170 // Value: [16] 0b // MmioAnd32 ( (XhciMmioBase + R_XHCI_MEM_USBLPM), (UINT32)~(BIT16) ); // // xHC Latency Tolerance Parameters - LTV Control // Address Offset: 0x8174 // Value: [30] 1b // [24] 1b // [11:0] 0xC0A (for xHCI in PCH) // Data32And = (UINT32)~(0); Data32Or = (BIT30 | BIT24); if (HcInfo->OnSouth) { Data32And = (UINT32)~(0xFFF); Data32Or |= 0xC0A; } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_XLTP_LTV1), Data32And, Data32Or ); // // xHC Latency Tolerance Parameters - High Idle Time Control // Address Offset: 0x817C // // For devices with IDs 0x38ED or 0x3DED // Value - 0x00050001 // else // Value - 0x033200A3 // MmioWrite32 ( (XhciMmioBase + R_XHCI_MEM_LTVHIT), HcInfo->UsbLtrHigh ); // // xHC Latency Tolerance Parameters - Medium Idle Time Control // Address Offset: 0x8180 // // For devices with IDs 0x38ED or 0x3DED // Value - 0x00050001 // else // Value - 0x00CB0028 // MmioWrite32 ( (XhciMmioBase + R_XHCI_MEM_LTVMIT), HcInfo->UsbLtrMid ); // // xHC Latency Tolerance Parameters - Low Idle Time Control // Address Offset: 0x8184 // // For devices with IDs 0x38ED or 0x3DED // Value - 0x00050001 // else // Value - 0x00CB001E // MmioWrite32 ( (XhciMmioBase + R_XHCI_MEM_LTVLIT), HcInfo->UsbLtrLow ); // // Host Controller Misc Reg // Address Offset: 0x80B0 // Value: [23] 1b, [18:16] 000b // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_MISC_REG), (UINT32)~(BIT18| BIT17 | BIT16), (UINT32) (BIT23) ); // // Host Controller Misc Reg 2 // Address Offset: 0x80B4 // Value: [28] 1b, [7] 1b, [2] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_MISC_REG_2), (UINT32) (BIT28 | BIT7 | BIT2) ); // // HOST_BW_OV_HS_REG - High Speed TT Bandwidth Overhead // Address Offset: 0x80C8 // Value: For IP V16.0 or V17.1 [23:12] 0Ah // [11:0] 0h // // Data32And = (UINT32)~(B_XHCI_MEM_HOST_BW_OV_HS_REG_OVHD_HSTTBW); Data32Or = 0; if ((HcInfo->IpVersion == V16_0) || (HcInfo->IpVersion == V17_1)) { Data32And &= (UINT32)~(B_XHCI_MEM_HOST_BW_OV_HS_REG_OVHD_HSBW); Data32Or = (0xA << N_XHCI_MEM_HOST_BW_OV_HS_REG_OVHD_HSBW); } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_BW_OV_HS_REG), Data32And, Data32Or ); // // THROTT - XHCI Throttle Control // Address Offset: 0x819C // Value: [20] 1b, [14] 1b, [13] 1b, [12] 1b, [11:8] 0x3, [7:4] 0x7, [3:0] 0xD // For IP V16.0 [16] 1b // Data32Or = (UINT32) (BIT20 | BIT14 | BIT13 | BIT12 | BIT9 | BIT8 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT0); if (HcInfo->IpVersion == V16_0) { Data32Or |= (BIT16); } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_THROTT), (UINT32) ~(BIT11 | BIT10 | BIT7 | BIT1), Data32Or ); // // THROTT2 - XHCI Throttle Control2 // Address Offset: 0x81B4 // Value: [31:0] 0h // MmioWrite32 ( (XhciMmioBase + R_XHCI_MEM_THROTT2), 0x0 ); // // D0I2CTRL - D0I2 Control Register // Address Offset: 0x81BC // Value: [31] 1b, [29:26] 4h, [25:22] 4h, [20:16] 4h, [15:4] 20h // For USB IP V16.0 or device with ID 0x8A13 // [3] 1b // Data32Or = (UINT32) (BIT31 | BIT28 | BIT24 | BIT18 | (0x20 << N_XHCI_MEM_D0I2CTRL_MSI_IDLE_THRESHOLD)); if ((HcInfo->IpVersion == V16_0) || (HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_1) || (HcInfo->IsCpuStepA0)) { Data32Or |= BIT3; } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_D0I2CTRL), (UINT32)~(0x3FDFFFF0), Data32Or ); // // D0i2SchAlarmCtrl - D0i2 Scheduler Alarm Control Register // Address Offset: 0x81C0 // Value: [28:16] 0Fh, [12:0] 05h // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_D0I2SCH_ALARM_CTRL), (UINT32)~(0x1FFF1FFF), (UINT32) (BIT19 | BIT18 | BIT17 | BIT16 | BIT2 | BIT0) ); // // USB2PMCTRL - USB2 Power Management Control // Address Offset: 0x81C4 // Value: [11] 1b, [8] 1b, [3:2] 10b, [1:0] 10b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_USB2PMCTRL), (UINT32) (BIT11 | BIT8 | BIT3 | BIT1) ); // // TRBPRFCTRLREG1 - TRB Prefetch Control Register 1 // Address Offset: 0x81D0 // Value: [23] 1b, [2] 1b // For CNP-LP Ax steppings [25] 1b else [25] 0b // For CNP-H or CNP-LP Bx or newer [0] 1b // Data32Or = (UINT32) (BIT23 | BIT2); Data32And = (UINT32)~(0); if (((HcInfo->DeviceId == V_XHCI_DID_CNP_LP) && (PchStepping () >= PCH_B0)) || (HcInfo->DeviceId == V_XHCI_DID_CNP_H)) { Data32And &= (UINT32)~(BIT25); } if ((HcInfo->DeviceId == V_XHCI_DID_CNP_H) || (PchStepping () >= PCH_B0)) { Data32Or |= BIT0; } MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_TRBPRFCTRLREG1), Data32And, Data32Or ); // // TRBPRFCACHEINVREG - TRB Prefetch Cache Invalidation Register 1 // Address Offset: 0x81D8 // Value: [23:17] 7Fh, // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_TRBPRFCACHEINVREG), (0x7F << N_XHCI_MEM_TRBPRFCACHEINVREG_EN_TRB_FLUSH) ); // // HOST_CTRL_SUS_LINK_PORT_REG // Address Offset: 0x81F8 // Value: [8:7] 1h // MmioAndThenOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_SUS_LINK_PORT_REG), (UINT32) ~(BIT8 | BIT7), (UINT32) (BIT7) ); if ((HcInfo->IpVersion == V17_0) || (HcInfo->IpVersion == V17_1)) { // // PMREQ Control Register // Address Offset: 0x83D0 // Value: [15] 1b // Applies only to IP V17.0 and V17.1 // Additionally for device with ID 0x34ED // [12] 1b // Data32Or = (UINT32) (BIT15); if (HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_1) { Data32Or |= BIT12; } MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_PMREQ_CTRL_REG), Data32Or ); if ((HcInfo->DeviceId == V_XHCI_DID_PCH_V17_1_1) || ((HcInfo->DeviceId == V_XHCI_DID_CPU_V17_0_1) && (HcInfo->IsCpuStepA0))) { // // Enhanced Clock Gate Control Policy Reguster // Address Offset: 0x83D8 // Applies only to devices with IDs 0x8A13 or 0x34ED // Values: [3:2] 11b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_ENH_CLK_GATE_CTRL), (UINT32) (BIT3 | BIT2) ); } } // // DBCCTL - DBC Control // Address Offset: 0x8760 // Values: [6:2] 1Fh [0] 1b // MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_DBC_DBCCTL), (UINT32) ((0x1F << N_XHCI_MEM_DBC_DBCCTL_DISC_RXD_CNT) | BIT0) ); // // HOST_CTRL_SSP_LINK_REG2 // Address Offset: 0x8E68 // Value: [24:23] 3h for CNP Ax else 0h // [4] 1b for CNP Ax else 0b // if (((HcInfo->DeviceId == V_XHCI_DID_CNP_LP) || (HcInfo->DeviceId == V_XHCI_DID_CNP_H)) && (PchStepping () < PCH_B0)) { MmioOr32 ( (XhciMmioBase + R_XHCI_MEM_HOST_CTRL_SSP_LINK_REG2), (UINT32) (BIT24 | BIT23 | BIT4) ); } // // HOST_CTRL_SSP_LFPS_REG2 // Address Offset: 0x8E74 // Value: [22:18] 3h // MmioAndThenOr32 ( XhciMmioBase + R_XHCI_MEM_HOST_CTRL_SSP_LFPS_REG2, (UINT32) ~(0x7C0000), (UINT32) (BIT19 | BIT18) ); // // HOST_CTRL_SSP_LFPS_REG3 // Address Offset: 0x8E78 // Value: [4:0] 3h // MmioAndThenOr32 ( XhciMmioBase + R_XHCI_MEM_HOST_CTRL_SSP_LFPS_REG3, (UINT32) ~(0x1F), (UINT32) (BIT1 | BIT0) ); // // HOST_CTRL_SSP_CONFIG_REG1 // Address Offset: 0x8E80 // Value: [29] 1b // MmioOr32 ( XhciMmioBase + R_XHCI_MEM_HOST_CTRL_SSP_CONFIG_REG1, (UINT32) (BIT29) ); // // HOST_CTRL_USB3_RECAL // Address Offset: 0x8E84 // Value: // For IP V16.0 [30:28] = 111b, [19:18] = 10b // For IP V17.0 [31] = 0b // if ((HcInfo->IpVersion == V16_0) || (HcInfo->IpVersion == V17_0)) { switch (HcInfo->IpVersion) { case V16_0: Data32And = (UINT32)~(BIT18); Data32Or = (UINT32) (BIT30 | BIT29 | BIT28 | BIT19); break; case V17_0: Data32And = (UINT32)~(BIT31); Data32Or = 0; break; default: Data32And = (UINT32)~(0); Data32Or = 0; break; } MmioAndThenOr32 ( XhciMmioBase + R_XHCI_MEM_HOST_CTRL_USB3_RECAL, Data32And, Data32Or ); } // // Set 1 to enable Super Speed Ports terminations on enabled ports only (PDO = 0) // Required for Deep S3 // XhciUsb3PortsMask = (UINT32)((1 << SsPortCount) - 1); XhciUsb3Pdo = MmioRead32 (XhciMmioBase + R_PCH_XHCI_MEM_USB3PDO) & XhciUsb3PortsMask; Data32 = (~XhciUsb3Pdo) & XhciUsb3PortsMask; MmioAndThenOr32 ( XhciMmioBase + R_XHCI_MEM_SSPE, (UINT32)~(XhciUsb3PortsMask), Data32 ); // // SSIC related programming // MmioOr32( XhciMmioBase + R_XHCI_MEM_SSIC_CONF_REG2_PORT_1, (UINT32) (B_XHCI_MEM_SSIC_CONF_REG2_PORT_UNUSED | B_XHCI_MEM_SSIC_CONF_REG2_PROG_DONE) ); MmioOr32( XhciMmioBase + R_XHCI_MEM_SSIC_CONF_REG2_PORT_2, (UINT32) (B_XHCI_MEM_SSIC_CONF_REG2_PORT_UNUSED | B_XHCI_MEM_SSIC_CONF_REG2_PROG_DONE) ); } STATIC BOOLEAN IsS3Wakeup ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_CPU_IO_PPI *CpuIo ) { UINT16 Pm1Sts; UINT16 Pm1Cnt; // // Read the ACPI registers // Pm1Sts = CpuIo->IoRead16 (PeiServices, CpuIo, PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress) + R_ACPI_IO_PM1_STS); Pm1Cnt = CpuIo->IoRead16 (PeiServices, CpuIo, PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress) + R_ACPI_IO_PM1_CNT); // // No power failure while S3_Resume, and only enter S3 boot mode once after OS standby. // if ((Pm1Sts & B_ACPI_IO_PM1_STS_WAK) != 0 && (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) == V_ACPI_IO_PM1_CNT_S3) { return TRUE; } return FALSE; } /** Clear and disable XHCI Memory Space @param[in] XhciPciBase XHCI PCI Base Address **/ STATIC VOID DdtXhciMemorySpaceClose ( IN UINT64 XhciPciBase ) { // // Clear memory resources // PciSegmentAnd16 ( XhciPciBase + PCI_COMMAND_OFFSET, (UINT16) ~(EFI_PCI_COMMAND_MEMORY_SPACE) ); PciSegmentWrite32 ((XhciPciBase + R_XHCI_CFG_BAR0), 0); PciSegmentWrite32 ((XhciPciBase + R_XHCI_CFG_BAR0 + 4), 0); } /** Returns USB3 PortSC register address base offset in xHCI MMIO space which can be later used for iteration through all USB3 PortSC registers @param[in] XhciMmioBase Memory BAR of the xHCI controller @retval UINT32 Calculated PortSC register offset **/ STATIC UINT32 GetUsb3PortScBase ( IN UINT32 XhciMmioBase ) { UINT32 Usb2PortCount; Usb2PortCount = GetUsb2PortCount (XhciMmioBase); return (R_XHCI_MEM_PORTSC_START_OFFSET + (Usb2PortCount * S_XHCI_MEM_PORTSC_PORT_SPACING)); } /** Function for checking if one of the USB3 ports is used for debug purposes @param[in] XhciMmioBase Memory BAR of the xHCI controller @param[out] RetDebugEnable Debug 0 indexed port number if found, otherwise 0xFF returned @retval BOOLEAN TRUE if debug port found on one of the ports **/ STATIC BOOLEAN GetDebugPortIndex ( IN UINT32 XhciMmioBase, OUT UINT32 *RetDebugPortSsIndex ) { UINT32 DebugPortSsIndex; UINT32 SsPortCount; UINT32 HsPortCount; UINT32 DebugPort; UINT32 CapabilityPointer; UINT32 Capability; BOOLEAN DebugEnable; HsPortCount = GetUsb2PortCount (XhciMmioBase); SsPortCount = GetUsb3PortCount (XhciMmioBase); // // Get debug enable status in order to skip some XHCI init which // may break XHCI debug // CapabilityPointer = (UINT32) (XhciMmioBase + (MmioRead32 (XhciMmioBase + R_XHCI_MEM_HCCPARAMS1) >> 16) * 4); DebugEnable = FALSE; DebugPortSsIndex = 0xFF; Capability = MmioRead32 (CapabilityPointer); DEBUG ((DEBUG_INFO, "XHCI Capability Pointer = 0x%x\n", CapabilityPointer)); while (TRUE) { if ((Capability & B_XHCI_MEM_CAPABILITY_ID) == V_XHCI_MEM_DBC_DCID) { // // Check DCR bit in DCCTRL register (Debug Capability Base + 20h), if set, debug device is running // if ((MmioRead32 (CapabilityPointer + R_XHCI_MEM_DBC_DCCTRL) & B_XHCI_MEM_DBC_DCCTRL_DCR) != 0) { DebugEnable = TRUE; // // Get debug port number [24:31] in DCST register which starts from 1 // DebugPort = (MmioRead32 (CapabilityPointer + R_XHCI_MEM_DBC_DCST) >> N_XHCI_MEM_DBC_DCST_DBG_PORT_NUMBER); // // Veryfing if debug port number falls within Super Speed port boundaries // if (DebugPort > HsPortCount) { if (DebugPort - HsPortCount < SsPortCount) { // // Translate to 0-based super speed port numbering // DebugPortSsIndex = DebugPort - HsPortCount - 1; DEBUG ((DEBUG_INFO, "DebugPortSsIndex = ?%d\n", DebugPortSsIndex)); break; } } } } if ((((Capability & B_XHCI_MEM_CAPABILITY_NEXT_CAP_PTR) >> N_XHCI_MEM_CAPABILITY_NEXT_CAP_PTR) & B_XHCI_MEM_CAPABILITY_ID) == 0) { // // Reached the end of list, quit // break; } CapabilityPointer += ((Capability & B_XHCI_MEM_CAPABILITY_NEXT_CAP_PTR) >> N_XHCI_MEM_CAPABILITY_NEXT_CAP_PTR) * 4; Capability = MmioRead32 (CapabilityPointer); } *RetDebugPortSsIndex = DebugPortSsIndex; return DebugEnable; } /* Helper function to initiate reset on USB3 ports @param[in] XhciMmioBase Memory BAR of the xHCI controller */ STATIC VOID XhciInitiatePortReset ( IN UINT32 XhciMmioBase ) { BOOLEAN DebugEnable; UINT32 PortSCxUsb3Base; UINT32 DebugPortSsIndex; UINT32 UsbPort; UINT32 SsPortCount; // // Perform WPR on USB3 port except for the port has DBC enabled. // // // Get debug enable status in order to skip some XHCI init which // may break XHCI debug // DebugEnable = FALSE; PortSCxUsb3Base = GetUsb3PortScBase (XhciMmioBase); SsPortCount = GetUsb3PortCount (XhciMmioBase); // // Perform WPR on USB3 port except for the port has DBC enabled. // DebugEnable = GetDebugPortIndex (XhciMmioBase, &DebugPortSsIndex); // // Initiate warm reset to all USB3 ports except for the USB3 port which has Dbc enabled // for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) { if ((DebugEnable) && (UsbPort == DebugPortSsIndex)) { continue; } MmioAndThenOr32 ( XhciMmioBase + (PortSCxUsb3Base + (UsbPort * S_XHCI_MEM_PORTSC_PORT_SPACING)), (UINT32) ~ (B_XHCI_MEM_PORTSCXUSB3_PED), B_XHCI_MEM_PORTSCXUSB3_WPR ); } } /** Configures PCH xHCI device @param[in] SiPolicy The SI Policy PPI instance @param[in] TempMemBaseAddr Temporary Memory Base Address for PCI devices to be used to initialize MMIO registers. @retval EFI_SUCCESS The function completed successfully @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver **/ EFI_STATUS EFIAPI DdtConfigureXhci ( IN UINT32 TempMemBaseAddr, IN BOOLEAN IsS3BootMode ) { USB_CONTROLLER_INFO HcInfo; UINT32 XhciMmioBase; UINT64 XhciPciBase; DEBUG ((DEBUG_INFO, "DdtConfigureXhci() - Start\n")); XhciMmioBase = TempMemBaseAddr; XhciPciBase = PCI_SEGMENT_LIB_ADDRESS ( DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_XHCI, PCI_FUNCTION_NUMBER_PCH_XHCI, 0 ); GetXhciControllerInfo (XhciPciBase, &HcInfo); /// /// Assign memory resources /// DdtXhciMemorySpaceOpen ( XhciPciBase, XhciMmioBase ); MmioOr32 ( XhciMmioBase + R_XHCI_MEM_HOST_CTRL_PORT_LINK_REG, (UINT32) (BIT0) ); DdtXhciHcInit ( &HcInfo, XhciPciBase, XhciMmioBase ); // // Initiate USB ports reset after Host Controller initialization is done // if (!(IsS3BootMode)) { XhciInitiatePortReset (XhciMmioBase); } /// /// Clear memory resources /// DdtXhciMemorySpaceClose ( XhciPciBase ); DEBUG ((DEBUG_INFO, "DdtConfigureXhci() - End\n")); return EFI_SUCCESS; } EFI_STATUS EFIAPI PchDdtUsbPeiEntryPoint ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; BOOLEAN IsS3BootMode; IsS3BootMode = IsS3Wakeup (PeiServices, (**PeiServices).CpuIo); // // Configure PCH xHCI // Status = DdtConfigureXhci (PcdGet32 (PcdSiliconInitTempMemBaseAddr), IsS3BootMode); ASSERT_EFI_ERROR (Status); return Status; }