summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c')
-rw-r--r--ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c3032
1 files changed, 3032 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c b/ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c
new file mode 100644
index 0000000..e53d783
--- /dev/null
+++ b/ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c
@@ -0,0 +1,3032 @@
+/** @file
+ Initializes PCH USB Controllers.
+
+@copyright
+ Copyright (c) 2009 - 2013 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#include "PchUsbCommon.h"
+#include "Token.h"
+
+const USB_CONTROLLER EhciControllersMap[PchEhciControllerMax] = {
+ {
+ PCI_DEVICE_NUMBER_PCH_USB,
+ PCI_FUNCTION_NUMBER_PCH_EHCI
+ },
+ {
+ PCI_DEVICE_NUMBER_PCH_USB_EXT,
+ PCI_FUNCTION_NUMBER_PCH_EHCI2
+ }
+};
+
+UINTN PCH_H_PORTSCxUSB2[] = {
+ R_PCH_XHCI_PORTSC01USB2,
+ R_PCH_XHCI_PORTSC02USB2,
+ R_PCH_XHCI_PORTSC03USB2,
+ R_PCH_XHCI_PORTSC04USB2,
+ R_PCH_XHCI_PORTSC05USB2,
+ R_PCH_XHCI_PORTSC06USB2,
+ R_PCH_XHCI_PORTSC07USB2,
+ R_PCH_XHCI_PORTSC08USB2,
+ R_PCH_XHCI_PORTSC09USB2,
+ R_PCH_H_XHCI_PORTSC10USB2,
+ R_PCH_H_XHCI_PORTSC11USB2,
+ R_PCH_H_XHCI_PORTSC12USB2,
+ R_PCH_H_XHCI_PORTSC13USB2,
+ R_PCH_H_XHCI_PORTSC14USB2,
+ R_PCH_H_XHCI_PORTSC15USB2
+};
+
+UINTN PCH_LP_PORTSCxUSB2[] = {
+ R_PCH_XHCI_PORTSC01USB2,
+ R_PCH_XHCI_PORTSC02USB2,
+ R_PCH_XHCI_PORTSC03USB2,
+ R_PCH_XHCI_PORTSC04USB2,
+ R_PCH_XHCI_PORTSC05USB2,
+ R_PCH_XHCI_PORTSC06USB2,
+ R_PCH_XHCI_PORTSC07USB2,
+ R_PCH_XHCI_PORTSC08USB2,
+ R_PCH_XHCI_PORTSC09USB2
+};
+
+UINTN PCH_H_PORTSCxUSB3[] = {
+ R_PCH_H_XHCI_PORTSC1USB3,
+ R_PCH_H_XHCI_PORTSC2USB3,
+ R_PCH_H_XHCI_PORTSC3USB3,
+ R_PCH_H_XHCI_PORTSC4USB3,
+ R_PCH_H_XHCI_PORTSC5USB3,
+ R_PCH_H_XHCI_PORTSC6USB3
+};
+
+UINTN PCH_LP_PORTSCxUSB3[] = {
+ R_PCH_LP_XHCI_PORTSC1USB3,
+ R_PCH_LP_XHCI_PORTSC2USB3,
+ R_PCH_LP_XHCI_PORTSC3USB3,
+ R_PCH_LP_XHCI_PORTSC4USB3
+};
+
+///
+/// Table: USB2 Pins Mapping between XHCI/EHCI Port
+/// -------------------------------------------
+/// | USB2 Pin | EHCI Port | XHCI Port |
+/// |--------------+----------------+-----------|
+/// | USB[P,N][0] | EHCI 1 Port 0 | Port 0 |
+/// | USB[P,N][1] | EHCI 1 Port 1 | Port 1 |
+/// | USB[P,N][2] | EHCI 1 Port 2 | Port 2 |
+/// | USB[P,N][3] | EHCI 1 Port 3 | Port 3 |
+/// | USB[P,N][4] | EHCI 1 Port 4 | Port 8 |
+/// | USB[P,N][5] | EHCI 1 Port 5 | Port 9 |
+/// | USB[P,N][6] | EHCI 1 Port 6 | Port 12 |
+/// | USB[P,N][7] | EHCI 1 Port 7 | Port 13 |
+/// | USB[P,N][8] | EHCI 2 Port 8 | Port 4 |
+/// | USB[P,N][9] | EHCI 2 Port 9 | Port 5 |
+/// | USB[P,N][10] | EHCI 2 Port 10 | Port 6 |
+/// | USB[P,N][11] | EHCI 2 Port 11 | Port 7 |
+/// | USB[P,N][12] | EHCI 2 Port 12 | Port 10 |
+/// | USB[P,N][13] | EHCI 2 Port 13 | Port 11 |
+/// -------------------------------------------
+///
+const UINT32 XhciUsb2InternalPortNumberLookUpTable[] = {
+ 0,1,2,3,8,9,12,13,4,5,6,7,10,11,12,13
+};
+
+/**
+ Configures PCH USB controller
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] EhciMmioBase Memory base address of EHCI Controller
+ @param[in] XhciMmioBase Memory base address of XHCI Controller
+ @param[in] BusNumber PCI Bus Number of the PCH device
+ @param[in] RootComplexBar RootComplexBar value of this PCH device
+ @param[out] FuncDisableReg Function Disable Register
+ @param[in] Revision The policy revision used for backward compatible check
+
+ @retval EFI_INVALID_PARAMETER The parameter of PchPlatformPolicy is invalid
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+EFIAPI
+CommonUsbInit (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINT32 EhciMmioBase,
+ IN UINT32 XhciMmioBase,
+ IN UINT8 BusNumber,
+ IN UINT32 RootComplexBar,
+ OUT UINT32 *FuncDisableReg,
+ IN UINT8 Revision
+ )
+{
+ UINTN PciD31F0RegBase;
+ UINTN XhciPciMmBase;
+ UINTN Ehci1PciMmBase;
+ UINTN Ehci2PciMmBase;
+ UINT16 LpcDeviceId;
+ UINT16 PmBase;
+ UINT16 RegData16 =0;
+ PCH_SERIES PchSeries;
+
+ DEBUG ((EFI_D_INFO, "CommonUsbInit() - Start\n"));
+
+ PchSeries = GetPchSeries();
+ PciD31F0RegBase = MmPciAddress (
+ 0,
+ BusNumber,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ 0
+ );
+ XhciPciMmBase = MmPciAddress (
+ 0,
+ BusNumber,
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI,
+ 0
+ );
+ Ehci1PciMmBase = MmPciAddress (
+ 0,
+ BusNumber,
+ EhciControllersMap[PchEhci1].Device,
+ EhciControllersMap[PchEhci1].Function,
+ 0
+ );
+ Ehci2PciMmBase = 0;
+ if (PchSeries == PchH) {
+ Ehci2PciMmBase = MmPciAddress (
+ 0,
+ BusNumber,
+ EhciControllersMap[PchEhci2].Device,
+ EhciControllersMap[PchEhci2].Function,
+ 0
+ );
+ }
+
+ PmBase = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_ACPI_BASE) & B_PCH_LPC_ACPI_BASE_BAR;
+ LpcDeviceId = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_DEVICE_ID);
+ ///
+ /// Check to disable USB Controllers
+ ///
+ if (UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_DISABLE) {
+ *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_EHCI1;
+ }
+
+ if (PchSeries == PchH) {
+ if (UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_DISABLE) {
+ *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_EHCI2;
+ }
+ }
+
+ if (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) {
+ ///
+ /// PCH BIOS Spec Rev 0.5.0, section 13.2.3 Hiding/Disabling xHCI Controller
+ /// In some instances, the System BIOS may choose to "hide" the xHCI controller. When
+ /// the xHCI device is hidden, all high speed shareable ports should be routed to the EHCI
+ /// controller to avoid the situation where USB ports are not functioning. To hide a host
+ /// controller, the BIOS must program the Function Disable register (RCBA + 3418h). See
+ /// the PCH EDS for a description of the register.
+ ///
+ *FuncDisableReg |= B_PCH_RCRB_FUNC_DIS_XHCI;
+ }
+
+ ///
+ /// Init USB Host Controllers
+ ///
+ CommonEhciHcsInit (
+ UsbConfig,
+ EhciMmioBase,
+ BusNumber,
+ Revision,
+ LpcDeviceId,
+ RootComplexBar
+ );
+
+ ///
+ /// Assign memory resources
+ ///
+ XhciMemorySpaceOpen (
+ UsbConfig,
+ XhciMmioBase,
+ XhciPciMmBase
+ );
+
+ CommonXhciHcInit (
+ UsbConfig,
+ XhciMmioBase,
+ Revision,
+ LpcDeviceId,
+ XhciPciMmBase
+ );
+
+ ///
+ /// Init Port Switching Flow
+ ///
+ PerformXhciEhciPortSwitchingFlow (
+ UsbConfig,
+ XhciMmioBase,
+ Revision,
+ LpcDeviceId,
+ XhciPciMmBase,
+ PciD31F0RegBase
+ );
+ ///
+ /// Setup USB Over-Current Mapping.
+ ///
+ EhciOverCurrentMapping (
+ UsbConfig,
+ Ehci1PciMmBase,
+ Ehci2PciMmBase
+ );
+
+ XhciOverCurrentMapping (
+ UsbConfig,
+ XhciPciMmBase
+ );
+
+ //
+ // Tune the USB 2.0 high-speed signals quality.
+ //
+ Usb2PortLengthProgramming (
+ UsbConfig,
+ LpcDeviceId,
+ RootComplexBar
+ );
+
+ ///
+ /// Support USB Per-Port Disable Control Override feature
+ ///
+#if defined OEM_USB_PER_PORT_DISABLE_SUPPORT && OEM_USB_PER_PORT_DISABLE_SUPPORT == 0
+ if (UsbConfig->UsbPerPortCtl == PCH_DEVICE_ENABLE) {
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 12.2 Disabling USB Ports
+ /// The PCH USB Port Disable Override Register (D26/29:F0 + 64h) can be locked by setting
+ /// the Write Enable bit of the PCH USB Per-Port Register Write Control Register,
+ /// PMBASE + 3Ch[1].
+ ///
+ /// Open the Per-Port Disable Control Override
+ ///
+ RegData16 = IoRead16 ((UINTN) ((UINT64) (PmBase + R_PCH_UPRWC)));
+ RegData16 |= B_PCH_UPRWC_WR_EN;
+ IoWrite16 ((UINTN) ((UINT64) (PmBase + R_PCH_UPRWC)), RegData16);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_IO_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (PmBase + R_PCH_UPRWC),
+ 1,
+ &RegData16
+ );
+#endif
+
+ EhciPortDisableOverride (
+ UsbConfig,
+ Ehci1PciMmBase,
+ Ehci2PciMmBase
+ );
+
+ XhciPortDisableOverride (
+ UsbConfig,
+ XhciPciMmBase,
+ Revision
+ );
+
+ ///
+ /// Close the Per-Port Disable Control Override
+ ///
+ RegData16 &= (~B_PCH_UPRWC_WR_EN);
+ IoWrite16 ((UINTN) ((UINT64) (PmBase + R_PCH_UPRWC)), RegData16);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_IO_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (PmBase + R_PCH_UPRWC),
+ 1,
+ &RegData16
+ );
+#endif
+ }
+#endif
+ ///
+ /// Support USBR feature
+ ///
+ if (UsbConfig->Ehci1Usbr == PCH_DEVICE_ENABLE &&
+ UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_ENABLE) {
+ EhciUsbrEnable (Ehci1PciMmBase);
+ }
+ if (PchSeries == PchH) {
+ if (UsbConfig->Ehci2Usbr == PCH_DEVICE_ENABLE && UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_ENABLE) {
+ EhciUsbrEnable (Ehci2PciMmBase);
+ }
+ }
+ ///
+ /// Clear memory resources
+ ///
+ XhciMemorySpaceClose (
+ UsbConfig,
+ XhciMmioBase,
+ XhciPciMmBase
+ );
+
+ DEBUG ((EFI_D_INFO, "CommonUsbInit() - End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Performs basic configuration of PCH EHCI controller.
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] EhciMmioBase Memory base address of EHCI Controller
+ @param[in] BusNumber PCI Bus Number of the PCH device
+ @param[in] Revision The policy revision used for backward compatible check
+ @param[in] LpcDeviceId The device ID of LPC
+ @param[in] RootComplexBar RootComplexBar value of this PCH device
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+EFIAPI
+CommonEhciHcsInit (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINT32 EhciMmioBase,
+ IN UINT8 BusNumber,
+ IN UINT8 Revision,
+ IN UINT16 LpcDeviceId,
+ IN UINT32 RootComplexBar
+ )
+{
+ UINTN EhciPciMmBase;
+ UINT8 Index;
+ UINT16 PciCmd;
+ BOOLEAN SkipRst;
+ UINT32 DwordReg;
+ UINT8 NumberOfPorts;
+ EFI_STATUS Status;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ PCH_SERIES PchSeries;
+#ifndef AMI_OVERRIDE_EHCI_MMIOBASE
+ UINT32 TempMmioBase = EhciMmioBase;
+#endif
+
+ PchSeries = GetPchSeries();
+
+ for (Index = 0; Index < GetPchEhciMaxControllerNum (); Index++) {
+ EhciPciMmBase = MmPciAddress (
+ 0,
+ BusNumber,
+ EhciControllersMap[Index].Device,
+ EhciControllersMap[Index].Function,
+ 0
+ );
+
+#ifndef AMI_OVERRIDE_EHCI_MMIOBASE
+ if (EhciMmioBase != TempMmioBase)
+ EhciMmioBase = TempMmioBase;
+#endif
+ ///
+ /// Set EHCI structural parameter
+ ///
+ if (UsbConfig->Usb20Settings[Index].Enable == PCH_DEVICE_DISABLE) {
+ MmioWrite32 (EhciPciMmBase + R_PCH_EHCI_MEM_BASE, 0);
+ MmioWrite16 (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER, 0);
+ } else {
+ PciCmd = 0;
+ ///
+ /// Shared EHCI/XHCI ports w/a.
+ /// This step is required when some of the ports are routed to EHCI
+ /// and other ports are routed XHCI at the same time.
+ ///
+ /// Clear D26/D29:F0 + 78h [1:0]
+ ///
+ if (UsbConfig->Usb30Settings.ManualMode == PCH_DEVICE_ENABLE) {
+ MmioAnd16 (
+ (EhciPciMmBase + 0x78),
+ (UINT16) ~(BIT1 | BIT0));
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support DeepSx and RapidStart resume from G3 state, all resume well registers
+ /// need to be saved into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (EhciPciMmBase + 0x78),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + 0x78)
+ );
+#endif
+ }
+ ///
+ /// For some cases, like usb debug mode, the Ehci memory resource will have been assigned and
+ /// enabled here. If so, then set SkipRst flag to skip the steps that are for Ehci memory
+ /// resource clear and host controller reset
+ ///
+ if ((MmioRead32 (EhciPciMmBase + R_PCH_EHCI_MEM_BASE) == 0) &&
+ !(MmioRead16 (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER) & B_PCH_EHCI_COMMAND_MSE)) {
+ MmioWrite32 ((EhciPciMmBase + R_PCH_EHCI_MEM_BASE), EhciMmioBase);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciPciMmBase + R_PCH_EHCI_MEM_BASE),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + R_PCH_EHCI_MEM_BASE)
+ );
+#endif
+ ///
+ /// Clear SkipRst flag
+ ///
+ SkipRst = FALSE;
+ } else {
+ ///
+ /// Use the memory address of Ehci controller that has been assigned before initialization
+ /// to do the programming.
+ ///
+ EhciMmioBase = MmioRead32 (EhciPciMmBase + R_PCH_EHCI_MEM_BASE);
+ ///
+ /// Save Pci command register
+ ///
+ PciCmd = MmioRead16 (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER);
+ ///
+ /// Set SkipRst flag
+ ///
+ SkipRst = TRUE;
+ }
+
+ MmioOr16 (
+ (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER),
+ (UINT16) (B_PCH_EHCI_COMMAND_MSE | B_PCH_EHCI_COMMAND_BME)
+ );
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER)
+ );
+#endif
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 12.10
+ /// Additional Programming Requirements during USB Initialization
+ ///
+ /// Step 1
+ /// Program D29/D26:MEM_BASE + 20h [1] = 1b,
+ /// This should be done before FS/LS initialitiation and also after S4/S5
+ ///
+ /// For some cases, like usb debug mode, we will skip this step, in case something will be destroyed
+ /// after doing host controller reset
+ ///
+ if (!SkipRst) {
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Reset the EHCI when running in PEI phase where USB precondition feature is enabled
+ /// or in DXE phase where USB precondition feature is disabled
+ /// If the precondition is enabled and running in DXE phase, EHCI has reset done already
+ ///
+ if (USB_RUN_IN_PEI || (!USB_PRECONDITION_POLICY_SUPPORT (UsbConfig))) {
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ MmioOr16 ((EhciMmioBase + R_PCH_EHCI_USB2CMD), B_PCH_EHCI_USB2CMD_HCRESET);
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ }
+ ///
+ /// Step 2
+ /// Configure number of controller and port:
+ ///
+ /// Step 2.a
+ /// Set D26/D29:F0:80h [0] = 1b
+ ///
+ MmioOr16 ((EhciPciMmBase + R_PCH_EHCI_ACCESS_CNTL), (UINT16) V_PCH_EHCI_ACCESS_CNTL_ENABLE);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (EhciPciMmBase + R_PCH_EHCI_ACCESS_CNTL),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + R_PCH_EHCI_ACCESS_CNTL)
+ );
+#endif
+ ///
+ /// Step 2.b
+ /// Set both EHCI's N_CC bit, D26 & D29 MEM_BASE + offset 04h [15:12], to 0000b
+ ///
+ MmioBitFieldWrite32 (
+ (EhciMmioBase + R_PCH_EHCI_HCSPARAMS),
+ N_PCH_EHCI_HCSPARAMS_N_CC,
+ (N_PCH_EHCI_HCSPARAMS_N_CC + 3),
+ 0
+ );
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciMmioBase + R_PCH_EHCI_HCSPARAMS),
+ 1,
+ (VOID *) (UINTN) (EhciMmioBase + R_PCH_EHCI_HCSPARAMS)
+ );
+#endif
+ ///
+ /// Step 2.c
+ /// Set both EHCI's N_PORTS bit, D26 & D29 MEM_BASE + offset 04h [3:0], to 2h
+ ///
+ NumberOfPorts = 2;
+ if (Index == PchEhci1) {
+ if (UsbConfig->Ehci1Usbr == PCH_DEVICE_ENABLE) {
+ NumberOfPorts = NumberOfPorts + 1;
+ }
+ } else {
+ if (PchSeries == PchH) {
+ if (Index == PchEhci2) {
+ if (UsbConfig->Ehci2Usbr == PCH_DEVICE_ENABLE) {
+ NumberOfPorts = NumberOfPorts + 1;
+ }
+ }
+ }
+ }
+ MmioBitFieldWrite32 (
+ (EhciMmioBase + R_PCH_EHCI_HCSPARAMS),
+ N_PCH_EHCI_HCSPARAMS_N_PORTS,
+ (N_PCH_EHCI_HCSPARAMS_N_PORTS + 3),
+ NumberOfPorts
+ );
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciMmioBase + R_PCH_EHCI_HCSPARAMS),
+ 1,
+ (VOID *) (UINTN) (EhciMmioBase + R_PCH_EHCI_HCSPARAMS)
+ );
+#endif
+ ///
+ /// Step 2.d
+ /// Clear D26/D29:F0:80h [0] to 0b
+ ///
+ MmioAnd16 ((EhciPciMmBase + R_PCH_EHCI_ACCESS_CNTL), (UINT16) (~V_PCH_EHCI_ACCESS_CNTL_ENABLE));
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (EhciPciMmBase + R_PCH_EHCI_ACCESS_CNTL),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + R_PCH_EHCI_ACCESS_CNTL)
+ );
+#endif
+ ///
+ /// Step 3
+ /// Program D29/D26:F0 + 78h[2] = 1b.
+ ///
+ DwordReg = MmioRead32 (EhciPciMmBase + 0x78);
+ DwordReg |= (UINT32) (BIT2);
+ MmioWrite32 (
+ (UINTN) (EhciPciMmBase + 0x78),
+ DwordReg
+ );
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciPciMmBase + 0x78),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + 0x78)
+ );
+#endif
+ ///
+ /// Step 4
+ /// Program D29/D26:F0 + 7Ch[14,7] = 1b
+ ///
+ MmioOr32 (EhciPciMmBase + 0x7C, (UINT32) BIT14 | BIT7);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciPciMmBase + 0x7C),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + 0x7C)
+ );
+#endif
+ ///
+ /// Step 5
+ /// Program D29/D26:F0 + 8Ch[11:8] = 0100b
+ /// Step 6
+ /// Program D29/D26:F0 + 8Ch[26,17] = 0b, 1b
+ ///
+ DwordReg = MmioRead32 (EhciPciMmBase + 0x8C);
+ DwordReg |= (UINT32) (BIT17 | BIT10);
+ DwordReg &= (UINT32)~(BIT26 | BIT11 | BIT9 | BIT8);
+ MmioWrite32 (
+ (UINTN) (EhciPciMmBase + 0x8C),
+ DwordReg
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciPciMmBase + 0x8C),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + 0x8C)
+ );
+
+ if (SkipRst) {
+ ///
+ /// Restore Pci command register
+ ///
+ MmioWrite16 ((EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER), PciCmd);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER)
+ );
+#endif
+ } else {
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// If precondition is enabled, execute USB precondition function by each phase call
+ ///
+ if (USB_PRECONDITION_POLICY_SUPPORT (UsbConfig)) {
+ EHCI_PRECONDITION (EhciControllersMap[Index].Device, EhciMmioBase);
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Clear memory resource and command register after initialization
+ ///
+ MmioAnd16 (
+ (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER),
+ (UINT16)~(B_PCH_EHCI_COMMAND_MSE | B_PCH_EHCI_COMMAND_BME)
+ );
+ MmioWrite32 ((EhciPciMmBase + R_PCH_EHCI_MEM_BASE), 0);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + R_PCH_EHCI_COMMAND_REGISTER)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciPciMmBase + R_PCH_EHCI_MEM_BASE),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + R_PCH_EHCI_MEM_BASE)
+ );
+#endif
+ }
+ }
+ }
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Execute the code if running in PEI phase when USB precondition feature is enabled
+ /// or in DXE phase when USB precondition feature disabled
+ /// If the precondition is enabled and running in DXE phase,
+ /// the code has already run once in PEI but the save S3 script need to run again in DXE phase
+ /// but only run if and only if both EHCI is not disabled
+ ///
+ if ((USB_RUN_IN_PEI || (!USB_PRECONDITION_POLICY_SUPPORT (UsbConfig))) ||
+ ((USB_RUN_IN_DXE) && ((UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_ENABLE) ||
+ ((UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_ENABLE) && (PchSeries == PchH)))))
+ {
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// PCH BIOS Spec Rev 0.5.5 Section 12.10
+ /// Additional Programming Requirements during USB Initialization
+ /// Step 7
+ /// IOBP Programming:
+ /// a) Set IOBP register 0xE5007F04 to 00004481h.
+ /// b) Set IOBP register 0xE500400F[0] + (PortNumber * 0x100) = 0b.
+ /// c) Set IOBP register 0xE5007F14[20:19] to 11b.
+ /// d) Set IOBP register 0xE5007F02[23:22] to 00b for LPT-LP
+ ///
+ /// Set IOBP register 0xE5007F04[14:13] to 10b.
+ ///
+ Data32And = 0;
+ Data32Or = 0x00004481;
+ Status = ProgramIobp (
+ RootComplexBar,
+ 0xE5007F04,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM (
+ RootComplexBar,
+ 0xE5007F04,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ for (Index = 0; Index < GetPchUsbMaxPhysicalPortNum (); Index++) {
+ ///
+ /// Set IOBP register 0xE500400F[0] + (PortNumber * 0x100) = 0b.
+ ///
+ Data32And = (UINT32)~(BIT0);
+ Data32Or = (UINT32) (0);
+ Status = ProgramIobp (
+ RootComplexBar,
+ 0xE500400F + ((Index + 1) * 0x100),
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM (
+ RootComplexBar,
+ 0xE500400F + ((Index + 1) * 0x100),
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ ///
+ /// Set IOBP register 0xE5007F14[20:19] to 11b.
+ ///
+ Data32And = (UINT32)~(0);
+ Data32Or = (UINT32) (BIT20 | BIT19);
+ Status = ProgramIobp (
+ RootComplexBar,
+ 0xE5007F14,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM (
+ RootComplexBar,
+ 0xE5007F14,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// Set IOBP register 0xE5007F02[23:22] to 00b for LPT-LP
+ ///
+ if (PchSeries == PchLp) {
+ Data32And = (UINT32)~(BIT23 | BIT22);
+ Data32Or = (UINT32) (0);
+ Status = ProgramIobp (
+ RootComplexBar,
+ 0xE5007F02,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM (
+ RootComplexBar,
+ 0xE5007F02,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ return EFI_SUCCESS;
+}
+
+/**
+ Performs basic configuration of PCH USB3 (xHCI) controller.
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] XhciMmioBase Memory base address of xHCI Controller
+ @param[in] Revision The policy revision used for backward compatible check
+ @param[in] LpcDeviceId The device ID of LPC
+ @param[in] XhciPciMmBase XHCI PCI Base Address
+
+ @retval None
+**/
+VOID
+CommonXhciHcInit (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINT32 XhciMmioBase,
+ IN UINT8 Revision,
+ IN UINT16 LpcDeviceId,
+ IN UINTN XhciPciMmBase
+ )
+{
+ UINT32 Data32Or;
+ UINT32 Data32And;
+ UINT8 PchSteppingValue;
+ PCH_SERIES PchSeries;
+
+ Data32Or = 0;
+ Data32And = 0;
+ PchSeries = GetPchSeries();
+ PchSteppingValue = PchStepping();
+ ///
+ /// Check if XHCI disabled, Exit function.
+ ///
+ if (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) {
+ return;
+ }
+ ///
+ /// PCH BIOS Spec Rev 0.5.5, Section 13.2.1 xHCI controller setup
+ ///
+ if (PchSeries == PchH) {
+ ///
+ /// For LPT-H Only:
+ /// USB3 ports always start at offset 16 (accounting for 15 USB2 ports) regardless of the number of USB2 ports
+ /// the XHCI spec allows there to be a gap between the highest numbered USB2 port and the lowest numbered USB3 port).
+ /// So the Maxports value is dependent entirely on the number of USB3 ports, and not upon the number of USB2 ports.
+ /// So the appropriate BIOS workaround is to look at the number of USB3 ports in the FUS register - config offset E0h.
+ /// (since there are SKUs with fewer than 6 port).
+ /// * If number of SS ports = 6, maxports = 21 (15h)
+ /// * If number of SS ports = 4, maxports = 19 (13h)
+ /// * If number of SS ports = 2, maxports = 17 (11h)
+ /// * If number of SS ports = 0, maxports = 15 (0Fh)
+ ///
+ switch (MmioRead32 (XhciPciMmBase + R_PCH_XHCI_FUS) & B_PCH_XHCI_FUS_SSPRTCNT) {
+ case V_PCH_XHCI_FUS_SSPRTCNT_11B:
+ // Number of SS ports is 0, Set xHCIBAR + 04h[31:24] = 0Fh
+ Data32Or = 0x0F000000;
+ break;
+
+ case V_PCH_XHCI_FUS_SSPRTCNT_10B:
+ // Number of SS ports is 2, Set xHCIBAR + 04h[31:24] = 11h
+ Data32Or = 0x11000000;
+ break;
+
+ case V_PCH_XHCI_FUS_SSPRTCNT_01B:
+ // Number of SS ports is 4, Set xHCIBAR + 04h[31:24] = 13h
+ Data32Or = 0x13000000;
+ break;
+
+ case V_PCH_XHCI_FUS_SSPRTCNT_00B:
+ default:
+ // Number of SS ports is 6, Set xHCIBAR + 04h[31:24] = 15h
+ Data32Or = 0x15000000;
+ break;
+ }
+ MmioAndThenOr32 (
+ (XhciMmioBase + R_PCH_XHCI_HCSPARAMS1),
+ (UINT32) 0x00FFFFFF,
+ (UINT32) Data32Or
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + R_PCH_XHCI_HCSPARAMS1),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + R_PCH_XHCI_HCSPARAMS1)
+ );
+ }
+ ///
+ /// Set xHCIBAR + 0Ch[7:0] = 0Ah and [31:16] = 200h
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + R_PCH_XHCI_HCSPARAMS3),
+ (UINT32) 0x0000FF00,
+ (UINT32) 0x0200000A
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + R_PCH_XHCI_HCSPARAMS3),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + R_PCH_XHCI_HCSPARAMS3)
+ );
+ ///
+ /// Set xHCIBAR + 10h[10,9,5] to 1b, 1b, 0b
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + R_PCH_XHCI_HCCPARAMS),
+ (UINT32)~(BIT5),
+ (UINT32) (BIT10 | BIT9)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + R_PCH_XHCI_HCCPARAMS),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + R_PCH_XHCI_HCCPARAMS)
+ );
+ if (PchSeries == PchH) {
+ ///
+ /// For LPT-H, Set xHCIBAR + 8008h[19] to 0b
+ ///
+ MmioAnd32 (
+ (XhciMmioBase + 0x8008),
+ (UINT32)~(BIT19)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8008),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8008)
+ );
+ }
+
+ if (PchSeries == PchLp) {
+ ///
+ /// Set xHCIBAR + 8058h[16,8] to 1b, 0b
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8058),
+ (UINT32)~(BIT8),
+ (UINT32) (BIT16)
+ );
+ } else if (PchSeries == PchH) {
+ ///
+ /// Set xHCIBAR + 8058h[20,16,8] to 1b, 1b, 0b
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8058),
+ (UINT32)~(BIT8),
+ (UINT32) (BIT20 | BIT16)
+ );
+ }
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8058),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8058)
+ );
+ ///
+ /// Set xHCIBAR + 8060h[25, 18] to 1b, 1b
+ ///
+ MmioOr32 (
+ (XhciMmioBase + 0x8060),
+ (UINT32) (BIT25 | BIT18)
+ );
+
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8060),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8060)
+ );
+ ///
+ /// Set xHCIBAR + 8090h[14,8] to 1b, 1b
+ ///
+ MmioOr32 (XhciMmioBase + 0x8090, (UINT32) (BIT14 | BIT8));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8090),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8090)
+ );
+ ///
+ /// Set xHCIBAR + 8094h[23, 21, 14] to 1b, 1b, 1b
+ ///
+ MmioOr32 (XhciMmioBase + 0x8094, (UINT32) (BIT23 | BIT21 | BIT14));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8094),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8094)
+ );
+ ///
+ /// Set xHCIBAR + 80E0h[16, 6] to 0b, 1b
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x80E0),
+ (UINT32)~(BIT16),
+ (UINT32) (BIT6)
+ );
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x80E0),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x80E0)
+ );
+#endif // SUS_WELL_RESTORE
+ ///
+ /// Set xHCIBAR + 80ECh[14:12] to 00h
+ /// Set xHCIBAR + 80ECh[11:9] to 06h
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x80EC),
+ (UINT32)~(BIT14 | BIT13 | BIT12 | BIT9),
+ (UINT32) (BIT11 | BIT10)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x80EC),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x80EC)
+ );
+ ///
+ /// Set xHCIBAR + 80F0h[20] to 0b
+ ///
+ MmioAnd32 (
+ (XhciMmioBase + 0x80F0),
+ (UINT32)~(BIT20)
+ );
+#ifdef SUS_WELL_RESTORE
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x80F0),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x80F0)
+ );
+#endif // SUS_WELL_RESTORE
+ ///
+ /// For LPT-LP, Set xHCIBAR + 80FCh[25] to 1b (Note: In document it is written as bit 121 of 80F0h.)
+ ///
+ if (PchSeries == PchLp) {
+ MmioOr32 (XhciMmioBase + 0x80FC, (UINT32) (BIT25));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x80FC),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x80FC)
+ );
+ }
+ if (PchSeries == PchLp) {
+ ///
+ /// Set xHCIBAR + 8110h[20,11, 8, 2] to 1b, 1b, 0b, 0b
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8110),
+ (UINT32)~(BIT2 | BIT8),
+ (UINT32) (BIT20 | BIT11)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8110),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8110)
+ );
+ } else if (PchSeries == PchH) {
+ ///
+ /// Set xHCIBAR + 8110h[20,11,2] to 1b, 1b, 0b
+ ///
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8110),
+ (UINT32)~(BIT2),
+ (UINT32) (BIT20 | BIT11)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8110),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8110)
+ );
+ }
+ ///
+ /// For LPT-H , Set xHCIBAR + 8140h[31:0] to FF03C132h
+ /// For LPT-LP, Set xHCIBAR + 8140h[31:0] to FF00F03Ch
+ ///
+ if (PchSeries == PchH) {
+ Data32And = (UINT32)~(0xFFFFFFFF);
+ Data32Or = (UINT32) (0xFF03C132);
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8140),
+ Data32And,
+ Data32Or
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8140),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8140)
+ );
+ }
+ if (PchSeries == PchLp) {
+ Data32And = (UINT32)~(0xFFFFFFFF);
+ Data32Or = (UINT32) (0xFF00F03C);
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8140),
+ Data32And,
+ Data32Or
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8140),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8140)
+ );
+ }
+
+ ///
+ /// For LPT-LP Set xHCIBAR + 8154h[21, 13] to 0b, 1b
+ /// For LPT-H Set xHCIBAR + 8154h[21, 13] to 0b, 0b
+ ///
+ if (PchSeries == PchH) {
+ Data32And = BIT21 | BIT13;
+ Data32Or = 0;
+ } else if (PchSeries == PchLp) {
+ Data32And = BIT21;
+ Data32Or = BIT13;
+ }
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8154),
+ (UINT32)~(Data32And),
+ (UINT32) (Data32Or)
+ );
+ ///
+ /// Clear xHCIBAR + 8154h[3] to 0b
+ ///
+ MmioAnd32 (
+ (XhciMmioBase + 0x8154),
+ (UINT32)~(BIT3)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8154),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8154)
+ );
+
+ ///
+ /// For LPT-LP, Set xHCIBAR + 8164h[0,1] to 1b
+ ///
+ if (PchSeries == PchLp) {
+ MmioOr32 (XhciMmioBase + 0x8164, (UINT32) (BIT1 | BIT0));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8164),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8164)
+ );
+ }
+
+ ///
+ /// For LPT-LP, Set xHCIBAR + 8174h = 0x01400C0A
+ ///
+ if (PchSeries == PchLp) {
+ MmioWrite32 (XhciMmioBase + 0x8174, 0x01400c0a);
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8174),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8174)
+ );
+ }
+ ///
+ /// For LPT-LP, Set xHCIBAR + 817Ch[31:0] to 033200A3h
+ ///
+ if (PchSeries == PchLp) {
+ Data32And = (UINT32)~(0xFFFFFFFF);
+ Data32Or = (UINT32) (0x033200A3);
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x817C),
+ Data32And,
+ Data32Or
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x817C),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x817C)
+ );
+ }
+ ///
+ /// For LPT-LP, Set xHCIBAR + 8180h[31:0] to 00CB0028h
+ ///
+ if (PchSeries == PchLp) {
+ Data32And = (UINT32)~(0xFFFFFFFF);
+ Data32Or = (UINT32) (0x00CB0028);
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8180),
+ Data32And,
+ Data32Or
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8180),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8180)
+ );
+ }
+ ///
+ /// For LPT-LP, Set xHCIBAR + 8184h[31:0] to 0064001Eh
+ ///
+ if (PchSeries == PchLp) {
+ Data32And = (UINT32)~(0xFFFFFFFF);
+ Data32Or = (UINT32) (0x0064001E);
+ MmioAndThenOr32 (
+ (XhciMmioBase + 0x8184),
+ Data32And,
+ Data32Or
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8184),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8184)
+ );
+ }
+
+ ///
+ /// Set D20:F0:44h[15,14,10,0] to 1b
+ /// Note: Only update D20:F0:44h by word since D20:F0:44h[31] is write-once bit
+ ///
+ MmioOr16 (XhciPciMmBase + 0x44, (UINT16) (BIT15 | BIT14 | BIT10 | BIT0));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (XhciPciMmBase + 0x44),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + 0x44)
+ );
+
+ ///
+ /// Set D20:F0:44h[19:16] to 1111b
+ /// Note: Update D20:F0:44h by byte to 46h since D20:F0:44h[31] is write-once bit
+ ///
+ MmioOr8 (XhciPciMmBase + 0x46, (UINT8) (BIT3 | BIT2 | BIT1 | BIT0));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (XhciPciMmBase + 0x46),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + 0x46)
+ );
+
+ ///
+ /// LPT-LP >= B0: BIOS must set XhciMmioBase + 0x8188[26, 24] to 1b, 1b
+ /// LPT-H >= C0: BIOS must set XhciMmioBase + 0x8188[ 24] to 1b
+ ///
+ if(((PchSeries == PchLp) && (PchSteppingValue >= LptLpB0))) {
+ MmioOr32 (XhciMmioBase + 0x8188, (UINT32) (BIT26 | BIT24));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8188),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8188)
+ );
+ } else if(((PchSeries == PchH) && (PchSteppingValue >= LptHC0))){
+ MmioOr32 (XhciMmioBase + 0x8188, (UINT32) (BIT24));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciMmioBase + 0x8188),
+ 1,
+ (VOID *) (UINTN) (XhciMmioBase + 0x8188)
+ );
+ }
+}
+
+/**
+ Initialization XHCI Clock Gating registers
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy
+ @param[in] RootComplexBar RootComplexBar value of this PCH device
+
+ @retval None
+**/
+VOID
+ConfigureXhciClockGating (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+ )
+{
+ UINT32 XhccCfg;
+ UINTN XhciPciMmBase;
+ UINT8 Data8;
+ UINT16 Data16;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ EFI_STATUS Status;
+ PCH_SERIES PchSeries;
+ PchSeries = GetPchSeries();
+ XhciPciMmBase = MmPciAddress (
+ 0,
+ PchPlatformPolicy->BusNumber,
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI,
+ 0
+ );
+ ///
+ /// Set IOBP register 0xE5004001[7:6] to 11b
+ ///
+ Data32And = (UINT32)~(0);
+ Data32Or = (UINT32) (BIT7 | BIT6);
+ Status = ProgramIobp (
+ RootComplexBar,
+ 0xE5004001,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM (
+ RootComplexBar,
+ 0xE5004001,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// For LPT-H : Set D20:F0:40h[21,20,18,17,8] to 1b
+ /// For LPT-LP:
+ /// Set D20:F0:40h[18,17,8] to 1b.
+ /// Set D20:F0:40h[21,20,19] to 000b to disable XHCI Idle L1.
+ /// Set D20:F0:40h[21,20,19] to 110b to enable XHCI Idle L1.
+ /// Note for LPT-LP Ax stepping,
+ /// USB3 hot plug will fail after 1 hot plug removal.
+ /// BIOS implement a Setup Option to disable XHCI Idle L1 as workaround.
+ /// Option should default to enable XHCI Idle L1 to allow PCH PM testing.
+ /// User need to put the system to G3 when changing from Enable to Disable state.
+ ///
+ XhccCfg = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_XHCC1);
+ XhccCfg &= (UINT32) ~(B_PCH_XHCI_XHCC1_URD);
+ if (PchSeries == PchH) {
+ XhccCfg |= (UINT32) (BIT21 | BIT20 | BIT18 | BIT17 | BIT8);
+ } else if (PchSeries == PchLp) {
+ XhccCfg |= (UINT32) (BIT18 | BIT17 | BIT8);
+ if (PchPlatformPolicy->UsbConfig->Usb30Settings.XhciIdleL1 == PCH_DEVICE_DISABLE) {
+ XhccCfg &= (UINT32)~(BIT21 | BIT20 | BIT19);
+ } else {
+ XhccCfg |= (UINT32) (BIT21 | BIT20);
+ XhccCfg &= (UINT32)~(BIT19);
+ }
+ }
+ Data16 = (UINT16)XhccCfg;
+ Data8 = (UINT8)(XhccCfg >> 16);
+ MmioWrite16 (XhciPciMmBase + R_PCH_XHCI_XHCC1, Data16);
+ MmioWrite8 (XhciPciMmBase + R_PCH_XHCI_XHCC1 + 2, Data8);
+ ///
+ /// Set D20:F0:44h[9, 7, 3] to 1b
+ ///
+ MmioOr16 (XhciPciMmBase + 0x44, (UINT16) (BIT9 | BIT7 | BIT3));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (XhciPciMmBase + 0x44),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + 0x44)
+ );
+
+ ///
+ /// For LPT-LP, Set D20:F0:A0h[18] to 1b
+ /// For LPT-H, Set D20:F0:A0h[6] to 1b
+ ///
+ if (PchSeries == PchH) {
+ Data32Or = BIT6;
+ } else if (PchSeries == PchLp) {
+ Data32Or = BIT18;
+ }
+ MmioOr32 (XhciPciMmBase + 0xA0, (UINT32) Data32Or);
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + 0xA0),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + 0xA0)
+ );
+ ///
+ /// Set D20:F0:A4h[13] to 0b
+ ///
+ MmioAnd32 (XhciPciMmBase + 0xA4, (UINT32)~(BIT13));
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + 0xA4),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + 0xA4)
+ );
+}
+
+/**
+ Performs basic configuration of PCH USB3 (xHCI) controller.
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] XhciMmioBase Memory base address of XHCI Controller
+ @param[in] Revision The policy revision used for backward compatible check
+ @param[in] LpcDeviceId The device ID of LPC
+ @param[in] XhciPciMmBase XHCI PCI Base Address
+ @param[in] PciD31F0RegBase LPC PCI Base Address
+
+ @retval None
+**/
+VOID
+PerformXhciEhciPortSwitchingFlow (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINT32 XhciMmioBase,
+ IN UINT8 Revision,
+ IN UINT16 LpcDeviceId,
+ IN UINTN XhciPciMmBase,
+ IN UINTN PciD31F0RegBase
+ )
+{
+ UINT32 UsbPort;
+ UINTN PortResetTimeout;
+ UINTN HsPortCount;
+ UINTN HsUsbrPortCount;
+ UINTN SsPortCount;
+ UINT32 PortMask;
+ UINT8 UsbPortRouting;
+ PCH_SERIES PchSeries;
+ UINTN *PORTSCxUSB2Ptr;
+ UINTN *PORTSCxUSB3Ptr;
+ UINT32 Data32;
+
+ PchSeries = GetPchSeries();
+ PORTSCxUSB2Ptr = NULL;
+ PORTSCxUSB3Ptr = NULL;
+ switch (PchSeries) {
+ case PchLp:
+ PORTSCxUSB2Ptr = &PCH_LP_PORTSCxUSB2[0];
+ PORTSCxUSB3Ptr = &PCH_LP_PORTSCxUSB3[0];
+ break;
+
+ case PchH:
+ PORTSCxUSB2Ptr = &PCH_H_PORTSCxUSB2[0];
+ PORTSCxUSB3Ptr = &PCH_H_PORTSCxUSB3[0];
+ break;
+
+ default:
+ break;
+ }
+ ///
+ /// Check if XHCI disabled, Exit function.
+ ///
+ if (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) {
+ return;
+ }
+ ///
+ /// Retrieves information about number of implemented xHCI ports and sets
+ /// appropriate port mask registers
+ /// Get the xHCI port number and program xHCI Port Routing Mask register
+ ///
+ GetXhciPortCountAndSetPortRoutingMask (
+ XhciPciMmBase,
+ &HsPortCount,
+ &HsUsbrPortCount,
+ &SsPortCount
+ );
+ ///
+ /// Workaround for USB2PR / USB3PR value not surviving warm reset.
+ ///
+ /// Check if Warm Reset
+ ///
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ if (USB_RUN_IN_PEI || (!USB_PRECONDITION_POLICY_SUPPORT (UsbConfig))) {
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ if (MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2) & B_PCH_LPC_GEN_PMCON_MEM_SR) {
+ ///
+ /// Restore USB Port Routing registers if OS HC Switch driver has been executed
+ ///
+ if (MmioRead32 (PciD31F0RegBase + 0xAC) & BIT16) {
+ ///
+ /// Program D20:F0:D8h[5:0] to the value of xHCI D20:F0:DCh[5:0]
+ ///
+ PortMask = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB3PRM) & (UINT32) B_PCH_XHCI_USB3PR_USB3SSENM;
+
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB3PR,
+ (UINT32)~B_PCH_XHCI_USB3PR_USB3SSEN,
+ PortMask
+ );
+ ///
+ /// Step 3
+ /// Program D20:F0:D0h[14:0] to the value of xHCI D20:F0:D4h[14:0]
+ ///
+ PortMask = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB2PRM) & (UINT32) B_PCH_XHCI_USB2PR_USB2HCSELM;
+
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB2PR,
+ (UINT32)~B_PCH_XHCI_USB2PR_USB2HCSEL,
+ PortMask
+ );
+ }
+ }
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Only clear this bit after DXE phase has finished using it.
+ /// because if we clear it too early in PEI phase
+ /// then we cannot determine if OS HC Switch driver has been executed in DXE phase.
+ ///
+ if (USB_RUN_IN_DXE || (!USB_PRECONDITION_POLICY_SUPPORT (UsbConfig))) {
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Clear B0:D31:F0 ACh[16] to indicate finish using this bit and begin of BIOS phase of USB port routing
+ ///
+ MmioAnd32 (PciD31F0RegBase + 0xAC, (UINT32) ~BIT16);
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Do nothing for this case
+ ///
+ UsbPortRouting = USB_PR_CASE_0;
+
+ if ((UsbConfig->Usb30Settings.PreBootSupport == PCH_DEVICE_DISABLE) ||
+ ((UsbConfig->Usb30Settings.PreBootSupport == PCH_DEVICE_ENABLE) &&
+ (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_AUTO))) {
+ ///
+ /// PCH BIOS Spec Rev 0.5.0
+ /// When the BIOS does not have xHCI pre-boot software available:
+ /// Section 13.1.1.2 xHCI Enabled mode
+ /// BIOS should route the Ports to the EHCI controller and prior to OS boot
+ /// it should route the ports to the xHCI controller.
+ /// Section 13.1.1.3 xHCI Auto mode
+ /// BIOS should route the Ports to the EHCI controller
+ ///
+ /// When the BIOS has xHCI pre-boot software available:
+ /// Section 13.1.2.3 xHCI Auto mode
+ /// BIOS should route the Ports to the EHCI controller
+ ///
+ /// For above cases, BIOS should follow Section 13.2.5 to route the
+ /// USB Ports to EHCI Controller.
+ ///
+ UsbPortRouting = USB_PR_CASE_1;
+ }
+
+ if ((UsbConfig->Usb30Settings.PreBootSupport == PCH_DEVICE_ENABLE) &&
+ (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_ON)) {
+ ///
+ /// PCH BIOS Spec Rev 0.5.0
+ /// When the BIOS has xHCI pre-boot software available:
+ /// Section 13.1.2.2 xHCI Enabled mode
+ /// BIOS should route the Ports to the xHCI controller
+ ///
+ /// For the above case, BIOS should follow Section 13.2.6 to route the
+ /// USB Ports to xHCI Controller.
+ ///
+ UsbPortRouting = USB_PR_CASE_2;
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Execute if runnin in PEI phase or USB precondition feature is not enabled
+ /// If the precondition is enabled and running in DXE phase, the workaround is done already
+ ///
+ if (USB_RUN_IN_PEI || (!USB_PRECONDITION_POLICY_SUPPORT (UsbConfig))) {
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ if (MmioRead16(PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2) & B_PCH_LPC_GEN_PMCON_MEM_SR) {
+ ///
+ /// Step 3
+ /// Initiate warm reset to all USB3 ports
+ ///
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB3Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB3_PED),
+ B_PCH_XHCI_PORTSCXUSB3_WPR
+ );
+ }
+ ///
+ /// 3.c. Poll for warm reset bit at steps #a to be cleared or timeout at 100ms
+ ///
+ PortResetTimeout = 0;
+ do {
+ Data32 = 0;
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ Data32 |= MmioRead32 (XhciMmioBase + PORTSCxUSB3Ptr[UsbPort]);
+ }
+ PchPmTimerStall (TEN_MS_TIMEOUT);
+ PortResetTimeout++;
+ } while ((Data32 & B_PCH_XHCI_PORTSCXUSB3_PR) &&
+ (PortResetTimeout < PORT_RESET_TIMEOUT));
+ }
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ }
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Execute if runnin in PEI phase or USB precondition feature is not enabled
+ /// If the precondition is enabled and running in DXE phase, the workaround is done already
+ ///
+ if (USB_RUN_IN_PEI || (!USB_PRECONDITION_POLICY_SUPPORT (UsbConfig))) {
+#endif // USB_PRECONDITION_ENABLE_FLAG
+ if ((SsPortCount != 0) &&
+ (UsbPortRouting == USB_PR_CASE_1) &&
+ ((MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB2PR) != 0) ||
+ (MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB3PR) != 0))) {
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 13.2.5 Routing of switchable USB Ports to
+ /// EHCI Controller
+ /// Step 1
+ /// Retrieve information about the number of implemented xHCI ports and set appropriate
+ /// port mask registers
+ /// Done in GetXhciPortCountAndSetPortRoutingMask()
+ /// Step 2
+ /// Based on available number of ports (from step 1) initiate port reset to enabled ports
+ /// where USB 2.0 device is connected
+ ///
+ /// 2.a. For Port #1, if xHCIBAR + 480h [0] is sets then
+ /// 2.b. Issue port reset by sets xHCIBAR + 480h [4] to 1b
+ /// 2.f. Repeat steps #a to #e for all the USB2.0 ports.
+ ///
+ for (UsbPort = 0; UsbPort < HsPortCount; UsbPort++) {
+ if (MmioRead32 (XhciMmioBase + PORTSCxUSB2Ptr[UsbPort]) & B_PCH_XHCI_PORTSCXUSB2_CCS) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB2Ptr[UsbPort],
+ (UINT32)~(B_PCH_XHCI_PORTSCXUSB2_PED),
+ B_PCH_XHCI_PORTSCXUSB2_PR
+ );
+ }
+ }
+ ///
+ /// 2.c. Poll for port reset bit at steps #b to be cleared or timeout at 100ms
+ ///
+ PortResetTimeout = 0;
+ do {
+ Data32 = 0;
+ for (UsbPort = 0; UsbPort < HsPortCount; UsbPort++) {
+ Data32 |= MmioRead32 (XhciMmioBase + PORTSCxUSB2Ptr[UsbPort]);
+ }
+ PchPmTimerStall (TEN_MS_TIMEOUT);
+ PortResetTimeout++;
+ } while ((Data32 & B_PCH_XHCI_PORTSCXUSB2_PR) &&
+ (PortResetTimeout < PORT_RESET_TIMEOUT));
+ ///
+ /// 2.d. Program D20:F0:D0h[14:0] to 0
+ ///
+ MmioAnd32 (
+ XhciPciMmBase + R_PCH_XHCI_USB2PR,
+ (UINT32)~B_PCH_XHCI_USB2PR_USB2HCSEL
+ );
+ ///
+ /// 2.e. Clear all the port's status by program xHCIBAR + 480h [23:17] to 1111111b
+ ///
+ for (UsbPort = 0; UsbPort < HsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB2Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB2_PED),
+ B_PCH_XHCI_PORTSCXUSB2_CEC |
+ B_PCH_XHCI_PORTSCXUSB2_PLC |
+ B_PCH_XHCI_PORTSCXUSB2_PRC |
+ B_PCH_XHCI_PORTSCXUSB2_OCC |
+ B_PCH_XHCI_PORTSCXUSB2_WRC |
+ B_PCH_XHCI_PORTSCXUSB2_PEC |
+ B_PCH_XHCI_PORTSCXUSB2_CSC
+ );
+ }
+ if (HsUsbrPortCount > 0) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB2Ptr[HsPortCount],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB2_PED),
+ B_PCH_XHCI_PORTSCXUSB2_CEC |
+ B_PCH_XHCI_PORTSCXUSB2_PLC |
+ B_PCH_XHCI_PORTSCXUSB2_PRC |
+ B_PCH_XHCI_PORTSCXUSB2_OCC |
+ B_PCH_XHCI_PORTSCXUSB2_WRC |
+ B_PCH_XHCI_PORTSCXUSB2_PEC |
+ B_PCH_XHCI_PORTSCXUSB2_CSC
+ );
+ }
+ ///
+ /// Step 3
+ /// Initiate warm reset to all USB 3.0 ports
+ ///
+ /// 3.a. For Port #1, sets xHCIBAR + 570h [31]
+ /// 3.e. Repeat steps #a to #e for all the USB3.0 ports.
+ ///
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB3Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB3_PED),
+ B_PCH_XHCI_PORTSCXUSB3_WPR
+ );
+ }
+ ///
+ /// 3.b. Program D20:F0:D8h[5:0] to 0h.
+ ///
+ MmioAnd32 (
+ XhciPciMmBase + R_PCH_XHCI_USB3PR,
+ (UINT32)~B_PCH_XHCI_USB3PR_USB3SSEN
+ );
+ ///
+ /// 3.c. Poll for warm reset bit at steps #a to be cleared or timeout at 100ms
+ ///
+ PortResetTimeout = 0;
+ do {
+ Data32 = 0;
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ Data32 |= MmioRead32 (XhciMmioBase + PORTSCxUSB3Ptr[UsbPort]);
+ }
+ PchPmTimerStall (TEN_MS_TIMEOUT);
+ PortResetTimeout++;
+ } while ((Data32 & B_PCH_XHCI_PORTSCXUSB3_PR) &&
+ (PortResetTimeout < PORT_RESET_TIMEOUT));
+ ///
+ /// 3.d. Clear all the port's status by program xHCIBAR + 570h [23:17] to 1111111b.
+ ///
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB3Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB3_PED),
+ B_PCH_XHCI_PORTSCXUSB3_CEC |
+ B_PCH_XHCI_PORTSCXUSB3_PLC |
+ B_PCH_XHCI_PORTSCXUSB3_PRC |
+ B_PCH_XHCI_PORTSCXUSB3_OCC |
+ B_PCH_XHCI_PORTSCXUSB3_WRC |
+ B_PCH_XHCI_PORTSCXUSB3_PEC |
+ B_PCH_XHCI_PORTSCXUSB3_CSC
+ );
+ }
+ ///
+ /// Step 4
+ /// Set the Run bit of xHCI controller, xHCIBAR +80h[0] to 1b
+ ///
+ MmioOr32 (
+ XhciMmioBase + R_PCH_XHCI_USBCMD,
+ B_PCH_XHCI_USBCMD_RS
+ );
+ ///
+ /// Step 5
+ /// Then clear the Run bit of xHCI controller, xHCIBAR +80h[0] to 0b
+ ///
+ MmioAnd32 (
+ XhciMmioBase + R_PCH_XHCI_USBCMD,
+ (UINT32)~B_PCH_XHCI_USBCMD_RS
+ );
+ } else if ((SsPortCount != 0) && (UsbPortRouting == USB_PR_CASE_2)) {
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 13.2.6 Routing of switchable USB Ports to
+ /// xHCI Controller
+ /// Step 1
+ /// Retrieve information about the number of implemented xHCI ports and set appropriate
+ /// port mask registers
+ /// Done in GetXhciPortCountAndSetPortRoutingMask()
+ /// Step 2
+ /// Program D20:F0:D8h[5:0] to the value of xHCI D20:F0:DCh[5:0]
+ ///
+ PortMask = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB3PRM) & (UINT32) B_PCH_XHCI_USB3PR_USB3SSENM;
+
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB3PR,
+ (UINT32)~B_PCH_XHCI_USB3PR_USB3SSEN,
+ PortMask
+ );
+ ///
+ /// Step 3
+ /// Program D20:F0:D0h[14:0] to the value of xHCI D20:F0:D4h[14:0]
+ ///
+ PortMask = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB2PRM) & (UINT32) B_PCH_XHCI_USB2PR_USB2HCSELM;
+
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB2PR,
+ (UINT32)~B_PCH_XHCI_USB2PR_USB2HCSEL,
+ PortMask
+ );
+ } else if (SsPortCount != 0) {
+ //
+ // Check if Warm Reset
+ //
+ if (MmioRead16(PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_2) & B_PCH_LPC_GEN_PMCON_MEM_SR) {
+ ///
+ /// Step 3
+ /// Initiate warm reset to all USB3 ports
+ ///
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB3Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB3_PED),
+ B_PCH_XHCI_PORTSCXUSB3_WPR
+ );
+ }
+ ///
+ /// 3.c. Poll for warm reset bit at steps #a to be cleared or timeout at 100ms
+ ///
+ PortResetTimeout = 0;
+ do {
+ Data32 = 0;
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ Data32 |= MmioRead32 (XhciMmioBase + PORTSCxUSB3Ptr[UsbPort]);
+ }
+ PchPmTimerStall (TEN_MS_TIMEOUT);
+ PortResetTimeout++;
+ } while ((Data32 & B_PCH_XHCI_PORTSCXUSB3_PR) &&
+ (PortResetTimeout < PORT_RESET_TIMEOUT));
+ }
+ }
+ if (UsbConfig->Usb30Settings.ManualMode == PCH_DEVICE_ENABLE) {
+ ///
+ /// Using the similar method as
+ /// PCH BIOS Spec Rev 0.5.0 Section 13.2.5 Routing of switchable USB Ports to
+ /// EHCI Controller
+ /// Step 1
+ /// Retrieve information about the number of implemented xHCI ports and set appropriate
+ /// port mask registers
+ /// Done in GetXhciPortCountAndSetPortRoutingMask()
+ /// Step 2
+ /// Based on available number of ports (from step 1) initiate port reset to enabled ports
+ /// where USB 2.0 device is connected
+ ///
+ /// 2.a. For Port #1, if xHCIBAR + 480h [0] is sets then
+ /// 2.b. Issue port reset by sets xHCIBAR + 480h [4] to 1b
+ /// 2.f. Repeat steps #a to #e for all the USB2.0 ports.
+ ///
+ for (UsbPort = 0; UsbPort < HsPortCount; UsbPort++) {
+ if (MmioRead32 (XhciMmioBase + PORTSCxUSB2Ptr[UsbPort]) & B_PCH_XHCI_PORTSCXUSB2_CCS) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB2Ptr[UsbPort],
+ (UINT32)~(B_PCH_XHCI_PORTSCXUSB2_PED),
+ B_PCH_XHCI_PORTSCXUSB2_PR
+ );
+ }
+ }
+ ///
+ /// 2.c. Poll for port reset bit at steps #b to be cleared or timeout at 100ms
+ ///
+ PortResetTimeout = 0;
+ do {
+ Data32 = 0;
+ for (UsbPort = 0; UsbPort < HsPortCount; UsbPort++) {
+ Data32 |= MmioRead32 (XhciMmioBase + PORTSCxUSB2Ptr[UsbPort]);
+ }
+ PchPmTimerStall (TEN_MS_TIMEOUT);
+ PortResetTimeout++;
+ } while ((Data32 & B_PCH_XHCI_PORTSCXUSB2_PR) &&
+ (PortResetTimeout < PORT_RESET_TIMEOUT));
+ ///
+ /// 2.d. Program D20:F0:D0h[14:0] manually
+ ///
+ PortMask = 0;
+ for (UsbPort = 0; UsbPort < HsPortCount; UsbPort++) {
+ if (UsbConfig->Usb30Settings.ManualModeUsb20PerPinRoute[UsbPort]==1) { // 0: EHCI; 1 :XHCI;
+ PortMask |= 1 << UsbPort;
+ }
+ }
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB2PR,
+ (UINT32)~B_PCH_XHCI_USB2PR_USB2HCSEL,
+ PortMask
+ );
+ ///
+ /// 2.e. Clear all the port's status by program xHCIBAR + 480h [23:17] to 1111111b
+ ///
+ for (UsbPort = 0; UsbPort < HsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB2Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB2_PED),
+ B_PCH_XHCI_PORTSCXUSB2_CEC |
+ B_PCH_XHCI_PORTSCXUSB2_PLC |
+ B_PCH_XHCI_PORTSCXUSB2_PRC |
+ B_PCH_XHCI_PORTSCXUSB2_OCC |
+ B_PCH_XHCI_PORTSCXUSB2_WRC |
+ B_PCH_XHCI_PORTSCXUSB2_PEC |
+ B_PCH_XHCI_PORTSCXUSB2_CSC
+ );
+ }
+ if (HsUsbrPortCount > 0) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB2Ptr[HsPortCount],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB2_PED),
+ B_PCH_XHCI_PORTSCXUSB2_CEC |
+ B_PCH_XHCI_PORTSCXUSB2_PLC |
+ B_PCH_XHCI_PORTSCXUSB2_PRC |
+ B_PCH_XHCI_PORTSCXUSB2_OCC |
+ B_PCH_XHCI_PORTSCXUSB2_WRC |
+ B_PCH_XHCI_PORTSCXUSB2_PEC |
+ B_PCH_XHCI_PORTSCXUSB2_CSC
+ );
+ }
+ ///
+ /// Step 3
+ /// Initiate warm reset to all USB 3.0 ports
+ ///
+ /// 3.a. For Port #1, sets xHCIBAR + 570h [31]
+ /// 3.e. Repeat steps #a to #e for all the USB3.0 ports.
+ ///
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB3Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB3_PED),
+ B_PCH_XHCI_PORTSCXUSB3_WPR
+ );
+ }
+ ///
+ /// 3.b. Program D20:F0:D8h[5:0] manually.
+ ///
+ PortMask = 0;
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ if (UsbConfig->Usb30Settings.ManualModeUsb30PerPinEnable[UsbPort]==1) { // 0: Disable; 1:Enable;
+ PortMask |= 1 << UsbPort;
+ }
+ }
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB3PR,
+ (UINT32)~B_PCH_XHCI_USB3PR_USB3SSEN,
+ PortMask
+ );
+ ///
+ /// 3.c. Poll for warm reset bit at steps #a to be cleared or timeout at 100ms
+ ///
+ PortResetTimeout = 0;
+ do {
+ Data32 = 0;
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ Data32 |= MmioRead32 (XhciMmioBase + PORTSCxUSB3Ptr[UsbPort]);
+ }
+ PchPmTimerStall (TEN_MS_TIMEOUT);
+ PortResetTimeout++;
+ } while ((Data32 & B_PCH_XHCI_PORTSCXUSB3_PR) &&
+ (PortResetTimeout < PORT_RESET_TIMEOUT));
+ ///
+ /// 3.d. Clear all the port's status by program xHCIBAR + 570h [23:17] to 1111111b.
+ ///
+ for (UsbPort = 0; UsbPort < SsPortCount; UsbPort++) {
+ MmioAndThenOr32 (
+ XhciMmioBase + PORTSCxUSB3Ptr[UsbPort],
+ (UINT32)~ (B_PCH_XHCI_PORTSCXUSB3_PED),
+ B_PCH_XHCI_PORTSCXUSB3_CEC |
+ B_PCH_XHCI_PORTSCXUSB3_PLC |
+ B_PCH_XHCI_PORTSCXUSB3_PRC |
+ B_PCH_XHCI_PORTSCXUSB3_OCC |
+ B_PCH_XHCI_PORTSCXUSB3_WRC |
+ B_PCH_XHCI_PORTSCXUSB3_PEC |
+ B_PCH_XHCI_PORTSCXUSB3_CSC
+ );
+ }
+ ///
+ /// Step 4
+ /// Set the Run bit of xHCI controller, xHCIBAR + 80h[0] to 1b
+ ///
+ MmioOr32 (
+ XhciMmioBase + R_PCH_XHCI_USBCMD,
+ (UINT32) B_PCH_XHCI_USBCMD_RS
+ );
+ ///
+ /// Step 5
+ /// Then clear the Run bit of xHCI controller, xHCIBAR + 80h[0] to 0b
+ ///
+ MmioAnd32 (
+ XhciMmioBase + R_PCH_XHCI_USBCMD,
+ (UINT32) ~B_PCH_XHCI_USBCMD_RS
+ );
+ }
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, XHCI USB3 PR resume well registers
+ /// get save into S3 Script table only when not running in Auto/Smart Auto mode.
+ ///
+ if (((UsbConfig->Usb30Settings.ManualMode == PCH_DEVICE_ENABLE)) ||
+ ((UsbConfig->Usb30Settings.PreBootSupport == PCH_DEVICE_ENABLE) &&
+ (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_ON))) {
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB3PR),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB3PR)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB2PR),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB2PR)
+ );
+ }
+#endif
+
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ ///
+ /// Check if XHCI disabled or auto even no preboot support, exit function directly
+ ///
+ if ((UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) ||
+ (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_AUTO) ||
+ (UsbConfig->Usb30Settings.PreBootSupport == PCH_DEVICE_DISABLE)
+ ) {
+ return;
+ }
+ ///
+ /// If precondition is enabled, execute USB precondition function by each phase call
+ ///
+ if (USB_PRECONDITION_POLICY_SUPPORT (UsbConfig)) {
+ XHCI_PRECONDITION (
+ (UINT8) ((XhciPciMmBase >> 20) &0xFF),
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI,
+ XhciMmioBase,
+ PORTSCxUSB2Ptr,
+ HsPortCount,
+ PORTSCxUSB3Ptr,
+ SsPortCount
+ );
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+}
+
+/**
+ Retrieves information about number of implemented xHCI ports
+ and sets appropriate port mask registers.
+
+ @param[in] XhciPciMmBase XHCI PCI Base Address
+ @param[out] HsPortCount Count of High Speed Ports
+ @param[out] HsUsbrPortCount Count of USBr Port
+ @param[out] SsPortCount Count of Super Speed Ports
+
+ @retval None
+**/
+VOID
+GetXhciPortCountAndSetPortRoutingMask (
+ IN UINTN XhciPciMmBase,
+ OUT UINTN *HsPortCount,
+ OUT UINTN *HsUsbrPortCount,
+ OUT UINTN *SsPortCount
+ )
+{
+ UINT32 HsPortEnableMask;
+ UINT32 SsPortEnableMask;
+ PCH_SERIES PchSeries;
+
+ HsPortEnableMask = 0;
+ SsPortEnableMask = 0;
+ PchSeries = GetPchSeries();
+ ///
+ /// PCH BIOS Spec Rev 0.5.0
+ /// Section 13.2.5 Routing of switchable USB Ports to EHCI Controller
+ /// Section 13.2.6 Routing of switchable USB Ports to xHCI Controller
+ ///
+ if (PchSeries == PchH) {
+ ///
+ /// Step 1.a Check xHCI D20:F0:E0h[2:1] to get HS Port Count.
+ ///
+ switch (MmioRead32 (XhciPciMmBase + R_PCH_XHCI_FUS) & B_PCH_XHCI_FUS_HSPRTCNT) {
+ case V_PCH_XHCI_FUS_HSPRTCNT_11B:
+ ///
+ /// If the value is 11b: Set xHCI D20:F0:D4h[13:0] to 00FFh. Number of HS ports is 8.
+ ///
+ *HsPortCount = V_PCH_H_XHCI_FUS_HSPRTCNT_11B_CNT;
+ HsPortEnableMask = V_PCH_H_XHCI_FUS_HSPRTCNT_11B_MASK;
+ break;
+
+ case V_PCH_XHCI_FUS_HSPRTCNT_10B:
+ ///
+ /// If the value is 10b: Set xHCI D20:F0:D4h[13:0] to 0FFFh. Number of HS ports is 10.
+ /// It is work around. Bit 6 and 7 have to be set to 1 to enable USB2 ports.
+ ///
+ *HsPortCount = V_PCH_H_XHCI_FUS_HSPRTCNT_10B_CNT;
+ HsPortEnableMask = V_PCH_H_XHCI_FUS_HSPRTCNT_10B_MASK;
+ break;
+
+ case V_PCH_XHCI_FUS_HSPRTCNT_01B:
+ ///
+ /// If the value is 01b: Set xHCI D20:F0:D4h[13:0] to 3FFFh. Number of HS ports is 12.
+ /// It is work around. Bit 6 and 7 have to be set to 1 to enable USB2 ports.
+ ///
+ *HsPortCount = V_PCH_H_XHCI_FUS_HSPRTCNT_01B_CNT;
+ HsPortEnableMask = V_PCH_H_XHCI_FUS_HSPRTCNT_01B_MASK;
+ break;
+
+ case V_PCH_XHCI_FUS_HSPRTCNT_00B:
+ ///
+ /// If the value is 00b: Set xHCI D20:F0:D4h[13:0] to 3FFFh. Number of HS ports is 14
+ ///
+ default:
+ *HsPortCount = V_PCH_H_XHCI_FUS_HSPRTCNT_00B_CNT;
+ HsPortEnableMask = V_PCH_H_XHCI_FUS_HSPRTCNT_00B_MASK;
+ break;
+ }
+ ///
+ /// Step 1.b Check xHCI D20:F0:E0h[4:3] to get SS Port Count.
+ ///
+ switch (MmioRead32 (XhciPciMmBase + R_PCH_XHCI_FUS) & B_PCH_XHCI_FUS_SSPRTCNT) {
+ case V_PCH_XHCI_FUS_SSPRTCNT_11B:
+ ///
+ /// If the value is 11b: Set xHCI D20:F0:DCh[5:0] to 000000b. Number of SS ports is 0.
+ ///
+ *SsPortCount = V_PCH_H_XHCI_FUS_SSPRTCNT_11B_CNT;
+ SsPortEnableMask = V_PCH_H_XHCI_FUS_SSPRTCNT_11B_MASK;
+ break;
+
+ case V_PCH_XHCI_FUS_SSPRTCNT_10B:
+ ///
+ /// If the value is 10b: Set xHCI D20:F0:DCh[5:0] to 000011b. Number of SS ports is 2.
+ ///
+ *SsPortCount = V_PCH_H_XHCI_FUS_SSPRTCNT_10B_CNT;
+ SsPortEnableMask = V_PCH_H_XHCI_FUS_SSPRTCNT_10B_MASK;
+ break;
+
+ case V_PCH_XHCI_FUS_SSPRTCNT_01B:
+ ///
+ /// If the value is 01b: Set xHCI D20:F0:DCh[5:0] to 001111b. Number of SS ports is 4.
+ ///
+ *SsPortCount = V_PCH_H_XHCI_FUS_SSPRTCNT_01B_CNT;
+ SsPortEnableMask = V_PCH_H_XHCI_FUS_SSPRTCNT_01B_MASK;
+ break;
+
+ case V_PCH_XHCI_FUS_SSPRTCNT_00B:
+ ///
+ /// If the value is 00b: Set xHCI D20:F0:DCh[5:0] to 111111b. Number of SS ports is 6.
+ ///
+ default:
+ *SsPortCount = V_PCH_H_XHCI_FUS_SSPRTCNT_00B_CNT;
+ SsPortEnableMask = V_PCH_H_XHCI_FUS_SSPRTCNT_00B_MASK;
+ break;
+ }
+ ///
+ /// Step 1.c Check xHCI D20:F0:E0h[5] to know if USBr is enabled.
+ /// @todo Need more comments to understand this
+ ///
+ switch (MmioRead32 (XhciPciMmBase + R_PCH_XHCI_FUS) & B_PCH_XHCI_FUS_USBR) {
+ case V_PCH_XHCI_FUS_USBR_EN:
+ ///
+ /// If 0b: Set xHCI D20:F0:D4[14] to 1b. USBr port is enabled.
+ ///
+ *HsUsbrPortCount = 1;
+ HsPortEnableMask |= BIT14;
+ break;
+
+ case V_PCH_XHCI_FUS_USBR_DIS:
+ ///
+ /// If 1b: Set xHCI D20:F0:D4[14] to 0b. USBr port is disabled.
+ ///
+ *HsUsbrPortCount = 0;
+ HsPortEnableMask &= (~BIT14);
+ break;
+ }
+ } else if (PchSeries == PchLp) {
+ ///
+ /// Step 1.a LPT-LP has a fixed number of 8 HS ports. Set xHCI D20:F0:D4h[13:0] to 00FFh.
+ ///
+ *HsPortCount = V_PCH_LP_XHCI_FIXED_HSPRTCNT;
+ HsPortEnableMask = V_PCH_LP_XHCI_FIXED_HSPRTCNT_MASK;
+ ///
+ /// Step 1.b LPT-LP has a fixed number of 4 SS ports. Set xHCI D20:F0:DCh[3:0] to 0Fh.
+ ///
+ *SsPortCount = V_PCH_LP_XHCI_FIXED_SSPRTCNT;
+ SsPortEnableMask = V_PCH_LP_XHCI_FIXED_SSPRTCNT_MASK;
+ ///
+ /// Step 1.c Check xHCI D20:F0:E0h[5] to know if USBr is enabled.
+ /// @todo Need more comments to understand this
+ ///
+ switch (MmioRead32 (XhciPciMmBase + R_PCH_XHCI_FUS) & B_PCH_XHCI_FUS_USBR) {
+ case V_PCH_XHCI_FUS_USBR_EN:
+ ///
+ /// If 0b: Set xHCI D20:F0:D4[8] to 1b. USBr port is enabled.
+ ///
+ *HsUsbrPortCount = 1;
+ HsPortEnableMask |= BIT8;
+ break;
+
+ case V_PCH_XHCI_FUS_USBR_DIS:
+ ///
+ /// If 1b: Set xHCI D20:F0:D4[8] to 0b. USBr port is disabled.
+ ///
+ *HsUsbrPortCount = 0;
+ HsPortEnableMask &= (~BIT8);
+ break;
+ }
+ }
+
+ //Routing the USB ports 12, 8, and 5 to EHCI to avoid OC detection when wakening up from S3
+
+ #ifdef UPSERVER_SUPPORT
+ HsPortEnableMask &=~(BIT12|BIT8|BIT5);
+ #endif
+
+ ///
+ /// Set xHCI USB2 Port Routing Mask register (D20:F0:D4h[14:0])
+ /// per HS Port Enable Mask value
+ ///
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB2PRM,
+ ~ (UINT32) B_PCH_XHCI_USB2PR_USB2HCSELM,
+ HsPortEnableMask
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB2PRM),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB2PRM)
+ );
+ ///
+ /// Set xHCI USB3 Port Routing Mask register (D20:F0:DCh[5:0])
+ /// per SS Port Enable Mask value
+ ///
+ MmioAndThenOr32 (
+ XhciPciMmBase + R_PCH_XHCI_USB3PRM,
+ ~ (UINT32) B_PCH_XHCI_USB3PR_USB3SSENM,
+ SsPortEnableMask
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB3PRM),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB3PRM)
+ );
+}
+
+/**
+ Setup XHCI Over-Current Mapping
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] XhciPciMmBase XHCI PCI Base Address
+
+ @retval None
+**/
+VOID
+XhciOverCurrentMapping (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINTN XhciPciMmBase
+ )
+{
+ ///
+ /// BIOS responsibility on Overcurrent protection.
+ /// ----------------------------------------------
+ /// There are 8 total overcurrent pins
+ /// which can be map to 14 USB2 ports and 6 USB3 ports.
+ /// On a given physical connector,
+ /// one OC pin is shared between the USB2 (HS) pins and USB3 (SS) pins.
+ /// USB2 (HS) pins are programmable to be owned by either XHCI or EHCI.
+ /// OC pins are associated to the current owner.
+ /// USB2 (HS) ports 1-8 use OC pins 1-4, ports 9-14 use OC pins 4-8
+ /// USB3 (SS) ports has the flexibility in pairing with any of the OC pins.
+ /// It is ok to map multiple ports to a single pin.
+ /// It is not ok to map a single ports to a multiple pins.
+ /// All USB ports routed out of the package must have Overcurrent protection.
+ /// USB Ports not routed out from the package should not be assigned OC pins.
+ ///
+ UINT32 Index;
+ UINT32 CurrentIndex;
+ UINT32 XhciHsOcm1;
+ UINT32 XhciHsOcm2;
+ UINT32 XhciSsOcm1;
+ UINT32 XhciSsOcm2;
+ PCH_SERIES PchSeries;
+
+ PchSeries = GetPchSeries();
+ ///
+ /// Check if XHCI disabled, Exit function.
+ ///
+ if (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) {
+ return;
+ }
+ ///
+ /// Find the corresponding register and set the bits
+ ///
+ XhciHsOcm1 = 0;
+ XhciHsOcm2 = 0;
+ XhciSsOcm1 = 0;
+ XhciSsOcm2 = 0;
+
+ for (Index = 0; Index < GetPchUsbMaxPhysicalPortNum (); Index++) {
+ if (UsbConfig->Usb20OverCurrentPins[Index] == PchUsbOverCurrentPinSkip) {
+ ///
+ /// No OC pin assigned, skip this port
+ ///
+ } else {
+ if (Index < 8) {
+ ///
+ /// Port 0-7: OC0 - OC3
+ ///
+ if (UsbConfig->Usb20OverCurrentPins[Index] > PchUsbOverCurrentPin3) {
+ ASSERT (FALSE);
+ continue;
+ }
+
+ CurrentIndex = UsbConfig->Usb20OverCurrentPins[Index] * 8 + Index;
+ XhciHsOcm1 |= (UINT32) (BIT0 << CurrentIndex);
+ } else {
+ ///
+ /// Port 8-13: OC4 - OC7
+ ///
+ if ((UsbConfig->Usb20OverCurrentPins[Index] < PchUsbOverCurrentPin4) ||
+ (UsbConfig->Usb20OverCurrentPins[Index] > PchUsbOverCurrentPin7)) {
+ ASSERT (FALSE);
+ continue;
+ }
+
+ CurrentIndex = (UsbConfig->Usb20OverCurrentPins[Index] - 4) * 8 + (Index - 8);
+ XhciHsOcm2 |= (UINT32) (BIT0 << CurrentIndex);
+ }
+ }
+ }
+
+ for (Index = 0; Index < GetPchXhciMaxUsb3PortNum (); Index++) {
+ if (UsbConfig->Usb30OverCurrentPins[Index] == PchUsbOverCurrentPinSkip) {
+ ///
+ /// No OC pin assigned, skip this port
+ ///
+ } else {
+ ///
+ /// Port 0-5: OC0 - OC7
+ ///
+ if (UsbConfig->Usb30OverCurrentPins[Index] < PchUsbOverCurrentPin4) {
+ CurrentIndex = UsbConfig->Usb30OverCurrentPins[Index] * 8 + Index;
+ XhciSsOcm1 |= (UINT32) (BIT0 << CurrentIndex);
+ } else {
+ CurrentIndex = (UsbConfig->Usb30OverCurrentPins[Index] - 4) * 8 + Index;
+ XhciSsOcm2 |= (UINT32) (BIT0 << CurrentIndex);
+ }
+ }
+ }
+ ///
+ /// OCM registers are in the suspend well.
+ ///
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_U2OCM1, XhciHsOcm1);
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_U3OCM1, XhciSsOcm1);
+ if (PchSeries == PchH) {
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_U2OCM2, XhciHsOcm2);
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_U3OCM2, XhciSsOcm2);
+ }
+
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_U2OCM1),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_U2OCM1)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_U3OCM1),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_U3OCM1)
+ );
+ if (PchSeries == PchH) {
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_U2OCM2),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_U2OCM2)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_U3OCM2),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_U3OCM2)
+ );
+ }
+#endif // SUS_WELL_RESTORE
+}
+
+/**
+ Setup EHCI Over-Current Mapping
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] Ehci1PciMmBase EHCI 1 PCI Base Address
+ @param[in] Ehci2PciMmBase EHCI 2 PCI Base Address
+
+ @retval None
+**/
+VOID
+EhciOverCurrentMapping (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINTN Ehci1PciMmBase,
+ IN UINTN Ehci2PciMmBase
+ )
+{
+ UINT32 Index;
+ UINT32 CurrentIndex;
+ UINT32 Ehci1Ocm;
+ UINT32 Ehci2Ocm;
+ PCH_SERIES PchSeries;
+
+ Ehci1Ocm = 0;
+ Ehci2Ocm = 0;
+ PchSeries = GetPchSeries();
+
+ for (Index = 0; Index < GetPchUsbMaxPhysicalPortNum (); Index++) {
+ if (UsbConfig->Usb20OverCurrentPins[Index] == PchUsbOverCurrentPinSkip) {
+ ///
+ /// No OC pin assigned, skip this port
+ ///
+ } else {
+ if (Index < 8) {
+ ///
+ /// Port 0~7 -> OC0~3
+ ///
+ if (UsbConfig->Usb20OverCurrentPins[Index] > PchUsbOverCurrentPin3) {
+ ASSERT (FALSE);
+ continue;
+ }
+
+ CurrentIndex = UsbConfig->Usb20OverCurrentPins[Index] * 8 + Index;
+ Ehci1Ocm |= (UINT32) (BIT0 << CurrentIndex);
+ } else {
+ if (PchSeries == PchH) {
+ ///
+ /// Port 8~13 -> OC4~7
+ ///
+ if ((UsbConfig->Usb20OverCurrentPins[Index] < PchUsbOverCurrentPin4) ||
+ (UsbConfig->Usb20OverCurrentPins[Index] > PchUsbOverCurrentPin7)) {
+ ASSERT (FALSE);
+ continue;
+ }
+ CurrentIndex = (UsbConfig->Usb20OverCurrentPins[Index] - 4) * 8 + (Index - 8);
+ Ehci2Ocm |= (UINT32) (BIT0 << CurrentIndex);
+ }
+ }
+ }
+ }
+ ///
+ /// EHCI1OCM and EHCI2OCM are in the suspend well.
+ ///
+ if (UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_ENABLE) {
+ MmioWrite32 (Ehci1PciMmBase + R_PCH_EHCI_OCMAP, Ehci1Ocm);
+ }
+
+ if (PchSeries == PchH) {
+ if (UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_ENABLE) {
+ MmioWrite32 (Ehci2PciMmBase + R_PCH_EHCI_OCMAP, Ehci2Ocm);
+ }
+ }
+
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ if (UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_ENABLE) {
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (Ehci1PciMmBase + R_PCH_EHCI_OCMAP),
+ 1,
+ (VOID *) (UINTN) (Ehci1PciMmBase + R_PCH_EHCI_OCMAP)
+ );
+ }
+
+ if (PchSeries == PchH) {
+ if (UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_ENABLE) {
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (Ehci2PciMmBase + R_PCH_EHCI_OCMAP),
+ 1,
+ (VOID *) (UINTN) (Ehci2PciMmBase + R_PCH_EHCI_OCMAP)
+ );
+ }
+ }
+#endif
+}
+
+/**
+ Program Ehci Port Disable Override
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] Ehci1PciMmBase EHCI 1 PCI Base Address
+ @param[in] Ehci2PciMmBase EHCI 2 PCI Base Address
+
+ @retval None
+**/
+VOID
+EhciPortDisableOverride (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINTN Ehci1PciMmBase,
+ IN UINTN Ehci2PciMmBase
+ )
+{
+ UINT32 Index;
+ PCH_SERIES PchSeries;
+
+ PchSeries = GetPchSeries();
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 12.2 Disabling USB Ports
+ /// System BIOS may choose to disable individual USB ports to save power or for security
+ /// purposes. Each of the USB ports has a corresponding bit within the PCH USB Port
+ /// Disable Override Register (D26/29:F0 + 64h). The PCH USB Port Disable Override
+ /// Register can be locked by setting the Write Enable bit of the PCH USB Per-Port Register
+ /// Write Control Register, PMBASE + 3Ch[1]. Refer to the PCH EDS for more details on
+ /// these registers.
+ ///
+ for (Index = 0; Index < GetPchUsbMaxPhysicalPortNum (); Index++) {
+ if ((Index < 8) && (UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_ENABLE)) {
+ ///
+ /// EHCI1 PDO for Port 0 to 7
+ ///
+ if (UsbConfig->PortSettings[Index].Enable == PCH_DEVICE_DISABLE) {
+ MmioOr8 (Ehci1PciMmBase + R_PCH_EHCI_PDO, (UINT8) (B_PCH_EHCI_PDO_DIS_PORT0 << Index));
+ } else {
+ MmioAnd8 (Ehci1PciMmBase + R_PCH_EHCI_PDO, (UINT8) ~(B_PCH_EHCI_PDO_DIS_PORT0 << Index));
+ }
+ }
+ if (PchSeries == PchH) {
+ if ((Index < 14) && (UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_ENABLE)) {
+ ///
+ /// EHCI2 PDO for Port 8 to 13
+ ///
+ if (UsbConfig->PortSettings[Index].Enable == PCH_DEVICE_DISABLE) {
+ MmioOr8 (Ehci2PciMmBase + R_PCH_EHCI_PDO, (UINT8) (B_PCH_EHCI_PDO_DIS_PORT0 << (Index - 8)));
+ } else {
+ MmioAnd8 (Ehci2PciMmBase + R_PCH_EHCI_PDO, (UINT8) ~(B_PCH_EHCI_PDO_DIS_PORT0 << (Index - 8)));
+ }
+ }
+ }
+ }
+
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ if (UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_ENABLE) {
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (Ehci1PciMmBase + R_PCH_EHCI_PDO),
+ 1,
+ (VOID *) (UINTN) (Ehci1PciMmBase + R_PCH_EHCI_PDO)
+ );
+ }
+
+ if (PchSeries == PchH) {
+ if (UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_ENABLE) {
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (Ehci2PciMmBase + R_PCH_EHCI_PDO),
+ 1,
+ (VOID *) (UINTN) (Ehci2PciMmBase + R_PCH_EHCI_PDO)
+ );
+ }
+ }
+#endif // SUS_WELL_RESTORE
+}
+
+/**
+ Program Xhci Port Disable Override
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] XhciPciMmBase XHCI PCI Base Address
+ @param[in] Revision Platform policy revision
+
+ @retval None
+**/
+VOID
+XhciPortDisableOverride (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINTN XhciPciMmBase,
+ IN UINT8 Revision
+ )
+{
+ UINT32 Index;
+ UINT32 XhciUsb2Pdo;
+ UINT32 XhciUsb3Pdo;
+ UINT32 XhciIndex;
+ PCH_SERIES PchSeries;
+
+ PchSeries = GetPchSeries();
+ ///
+ /// Check if XHCI disabled, Exit function.
+ ///
+ if (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) {
+ return;
+ }
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 13.2.2 Port Disable Override
+ /// In LynxPoint PCH, Port disable override on xHCI ports is implemented by mapping the
+ /// appropriate ports to the EHCI controller and then setting the port disable override in
+ /// the EHCI function. Please refer to section 12.2.
+ /// Please note that there is a corresponding disable bit on D20:F0:E4h[14:0] for USB 2.0
+ /// ports and D20:F0:E8h[5:0] for USB 3.0 ports. BIOS needs to program them accordingly.
+ ///
+ /// XHCI PDO for HS
+ ///
+ XhciUsb2Pdo = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB2PDO) & B_PCH_XHCI_USB2PDO_MASK;
+ for (Index = 0; Index < GetPchUsbMaxPhysicalPortNum (); Index++) {
+ XhciIndex = Index;
+ if (PchSeries == PchH) {
+ ///
+ /// Translate physical pins to internal ports numbering
+ ///
+ XhciIndex = XhciUsb2InternalPortNumberLookUpTable[Index];
+ }
+ if (UsbConfig->PortSettings[Index].Enable == PCH_DEVICE_DISABLE) {
+ XhciUsb2Pdo |= (UINT32) (B_PCH_XHCI_USB2PDO_DIS_PORT0 << XhciIndex);
+ } else {
+ XhciUsb2Pdo &= (UINT32)~(B_PCH_XHCI_USB2PDO_DIS_PORT0 << XhciIndex);
+ }
+ }
+ ///
+ /// XHCI PDO for SS
+ ///
+ XhciUsb3Pdo = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_USB3PDO) & B_PCH_XHCI_USB3PDO_MASK;
+ for (Index = 0; Index < GetPchXhciMaxUsb3PortNum (); Index++) {
+
+ if (USB3PORT_SETTING_POLICY_SUPPORT(Revision)){
+ if (UsbConfig->Port30Settings[Index].Enable == PCH_DEVICE_DISABLE) {
+ XhciUsb3Pdo |= (UINT32) (B_PCH_XHCI_USB3PDO_DIS_PORT0 << Index);
+ } else {
+ XhciUsb3Pdo &= (UINT32)~(B_PCH_XHCI_USB3PDO_DIS_PORT0 << Index);
+ }
+ } else {
+ if (UsbConfig->PortSettings[Index].Enable == PCH_DEVICE_DISABLE) {
+ XhciUsb3Pdo |= (UINT32) (B_PCH_XHCI_USB3PDO_DIS_PORT0 << Index);
+ } else {
+ XhciUsb3Pdo &= (UINT32)~(B_PCH_XHCI_USB3PDO_DIS_PORT0 << Index);
+ }
+ }
+ }
+ ///
+ /// USB2PDO and USB3PDO are Write-Once registers and bits in them are in the SUS Well.
+ ///
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_USB2PDO, XhciUsb2Pdo);
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_USB3PDO, XhciUsb3Pdo);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB2PDO),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB2PDO)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB3PDO),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_USB3PDO)
+ );
+#endif
+}
+
+/**
+ Enable EHCI USBR device
+
+ @param[in] EhciPciMmBase Ehci PCI Base Address
+
+ @retval None
+**/
+VOID
+EhciUsbrEnable (
+ IN UINTN EhciPciMmBase
+ )
+{
+ ///
+ /// NOTE: EHCI USBR Enable
+ /// EHCI1_USBr_en and EHCI2_USBr_en are mutually exclusive. Both cannot be set to 1 at any one time.
+ /// SW must ensure at any one time, only 1 EHCI should have the bit set.
+ ///
+ MmioOr16 (EhciPciMmBase + 0x7A, (UINT16) BIT8);
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (EhciPciMmBase + 0x7A),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + 0x7A)
+ );
+#endif
+}
+
+/**
+ Program and enable XHCI Memory Space
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] XhciMmioBase Memory base address of XHCI Controller
+ @param[in] XhciPciMmBase XHCI PCI Base Address
+
+ @retval None
+**/
+VOID
+XhciMemorySpaceOpen (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINT32 XhciMmioBase,
+ IN UINTN XhciPciMmBase
+ )
+{
+ ///
+ /// Check if XHCI disabled, Exit function.
+ ///
+ if (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) {
+ return;
+ }
+ ///
+ /// Assign memory resources
+ ///
+ MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE, XhciMmioBase);
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_MEM_BASE),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_MEM_BASE)
+ );
+
+ MmioOr16 (
+ XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER,
+ (UINT16) (B_PCH_XHCI_COMMAND_MSE | B_PCH_XHCI_COMMAND_BME)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER)
+ );
+}
+
+/**
+ Clear and disable XHCI Memory Space
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] XhciMmioBase Memory base address of XHCI Controller
+ @param[in] XhciPciMmBase XHCI PCI Base Address
+
+ @retval None
+**/
+VOID
+XhciMemorySpaceClose (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINT32 XhciMmioBase,
+ IN UINTN XhciPciMmBase
+ )
+{
+ ///
+ /// Check if XHCI disabled, Exit function.
+ ///
+ if (UsbConfig->Usb30Settings.Mode == PCH_XHCI_MODE_OFF) {
+ return;
+ }
+ ///
+ /// Clear memory resources
+ ///
+ MmioAnd16 (
+ XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER,
+ (UINT16)~(B_PCH_XHCI_COMMAND_MSE | B_PCH_XHCI_COMMAND_BME)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER)
+ );
+
+ MmioWrite32 ((XhciPciMmBase + R_PCH_XHCI_MEM_BASE), 0);
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (XhciPciMmBase + R_PCH_XHCI_MEM_BASE),
+ 1,
+ (VOID *) (UINTN) (XhciPciMmBase + R_PCH_XHCI_MEM_BASE)
+ );
+}
+
+/**
+ Tune the USB 2.0 high-speed signals quality.
+
+ @param[in] UsbConfig The PCH Platform Policy for USB configuration
+ @param[in] LpcDeviceId The device ID of LPC
+ @param[in] RootComplexBar RootComplexBar value of this PCH device
+
+ @retval EFI_SUCCESS Successfully completed
+ @retval EFI_DEVICE_ERROR Programming is failed
+**/
+VOID
+Usb2PortLengthProgramming (
+ IN PCH_USB_CONFIG *UsbConfig,
+ IN UINT16 LpcDeviceId,
+ IN UINT32 RootComplexBar
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ PCH_SERIES PchSeries;
+ PchSeries = GetPchSeries();
+ ///
+ /// Execute the code if running in PEI phase when USB precondition feature is enabled
+ /// or in DXE phase when USB precondition feature disabled
+ /// If the precondition is enabled and running in DXE phase,
+ /// the code has already run once in PEI but the save S3 script need to run again in DXE phase
+ /// but only run if and only if both EHCI is not disabled
+ ///
+ if ((USB_RUN_IN_PEI || (!USB_PRECONDITION_POLICY_SUPPORT (UsbConfig))) ||
+ ((USB_RUN_IN_DXE) && ((UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_ENABLE) ||
+ ((UsbConfig->Usb20Settings[PchEhci2].Enable == PCH_DEVICE_ENABLE) && (PchSeries == PchH)))))
+ {
+#endif // USB_PRECONDITION_ENABLE_FLAG
+
+ //
+ // Set EHCI AFE USB2 PER PORT register
+ // IOBP registers 0xE5004000 + ((PortNumber+1) * 0x100)
+ //
+ for (Index = 0; Index < GetPchUsbMaxPhysicalPortNum (); Index++) {
+ Data32And = (UINT32)~(0x00007F00);
+ Data32Or = (UINT32) (0x00000000); // BIT[14] (PERPORTTXPEHALF) = 0
+ ASSERT (UsbConfig->PortSettings[Index].Usb20EyeDiagramTuningParam2 < 8);
+ Data32Or |= (UsbConfig->PortSettings[Index].Usb20EyeDiagramTuningParam2 & 0x07) << 11; // BIT[13:11] (PERPORTPETXISET) = Usb20EyeDiagramTuningParam2
+ ASSERT (UsbConfig->PortSettings[Index].Usb20EyeDiagramTuningParam1 < 8);
+ Data32Or |= (UsbConfig->PortSettings[Index].Usb20EyeDiagramTuningParam1 & 0x07) << 8; // BIT[10:08] (PERPORTTXISET) = Usb20EyeDiagramTuningParam1
+ Status = ProgramIobp (
+ RootComplexBar,
+ 0xE5004000 + ((Index + 1) * 0x100),
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM (
+ RootComplexBar,
+ 0xE5004000 + ((Index + 1) * 0x100),
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+#ifdef USB_PRECONDITION_ENABLE_FLAG
+ }
+#endif // USB_PRECONDITION_ENABLE_FLAG
+}
+
+VOID
+ConfigureUsbClockGating (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+)
+{
+ ConfigureEhciClockGating(PchPlatformPolicy,RootComplexBar);
+ ConfigureXhciClockGating(PchPlatformPolicy,RootComplexBar);
+}
+
+VOID
+ConfigureEhciClockGating (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+)
+{
+ UINTN EhciPciMmBase;
+ UINT8 Index;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ EFI_STATUS Status;
+ PCH_SERIES PchSeries;
+ PchSeries = GetPchSeries();
+ //
+ // Enable EHCI Clock Gating
+ //
+
+ ///
+ /// If LPT-LP when EHCI disabled, Set RCBA + Offset 3A84[2,0] = 1b, 1b
+ ///
+ if (PchSeries == PchLp) {
+ if (PchPlatformPolicy->UsbConfig->Usb20Settings[PchEhci1].Enable == PCH_DEVICE_DISABLE) {
+ MmioOr32 (
+ (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A84),
+ (UINT32) (BIT2 | BIT0)
+ );
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A84),
+ 1,
+ (VOID *) (UINTN) (RootComplexBar + R_PCH_RCRB_CIR3A84)
+ );
+ }
+ }
+
+ ///
+ /// Set IOBP register 0xE5004001[7:6] to 11b.
+ ///
+ Data32And = (UINT32)~(0);
+ Data32Or = (UINT32) (BIT7 | BIT6);
+ Status = ProgramIobp (
+ RootComplexBar,
+ 0xE5004001,
+ Data32And,
+ Data32Or
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PCH_INIT_COMMON_SCRIPT_SAVE_IOBP_S3_ITEM (
+ RootComplexBar,
+ 0xE5004001,
+ Data32And,
+ Data32Or
+ );
+ ///
+ /// For each EHCI's PCI Config space registers
+ ///
+ for (Index = 0; Index < GetPchEhciMaxControllerNum (); Index++) {
+ EhciPciMmBase = MmPciAddress (
+ 0,
+ PchPlatformPolicy->BusNumber,
+ EhciControllersMap[Index].Device,
+ EhciControllersMap[Index].Function,
+ 0
+ );
+ ///
+ /// Set D29/D26:F0 + DCh[5,2,1] to 1b
+ /// Set D29/D26:F0 + DCh[0] to 1b when EHCI controller is disable
+ ///
+ Data32Or = (UINT32) (BIT5 | BIT2 | BIT1);
+ if (PchPlatformPolicy->UsbConfig->Usb20Settings[Index].Enable == PCH_DEVICE_DISABLE) {
+ Data32Or |= (UINT32) (BIT0);
+ }
+ MmioOr32 (EhciPciMmBase + 0xDC, Data32Or);
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciPciMmBase + 0xDC),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + 0xDC)
+ );
+ ///
+ /// Set D29/D26:F0 + 78h[1:0] to 11b
+ ///
+ Data32Or = (UINT32) (BIT1 | BIT0);
+ MmioOr32 (EhciPciMmBase + 0x78, Data32Or);
+ PCH_INIT_COMMON_SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EhciPciMmBase + 0x78),
+ 1,
+ (VOID *) (UINTN) (EhciPciMmBase + 0x78)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+