alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/PchDdtUsbPei/PchDdtUsbPei.c

1233 lines
32 KiB
C

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