diff options
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c')
-rw-r--r-- | ReferenceCode/Chipset/LynxPoint/PchInit/Common/PchUsbCommon.c | 3032 |
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); + } +} + |