/** @file
|
Pch information library.
|
|
All function in this library is available for PEI, DXE, and SMM,
|
But do not support UEFI RUNTIME environment call.
|
|
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
#include <Base.h>
|
#include <Uefi/UefiBaseType.h>
|
#include <Library/IoLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/BaseLib.h>
|
#include <Library/MmPciLib.h>
|
#include <Library/PchInfoLib.h>
|
#include <PchAccess.h>
|
|
#define PCH_DO_STRINGIFY(x) #x
|
#define PCH_STRINGIFY(x) PCH_DO_STRINGIFY(x)
|
|
//
|
// This module variables are used for cache the static result.
|
// @note: please pay attention to the PEI phase, the module variables on ROM
|
// and can't be modified.
|
//
|
GLOBAL_REMOVE_IF_UNREFERENCED PCH_STEPPING mPchStepping = PchSteppingMax;
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mIsPchSupported = 0xFF;
|
GLOBAL_REMOVE_IF_UNREFERENCED PCH_SERIES mPchSeries = PchUnknownSeries;
|
GLOBAL_REMOVE_IF_UNREFERENCED PCH_GENERATION mPchGeneration = PchUnknownGeneration;
|
|
/**
|
Return Pch stepping type
|
|
@retval PCH_STEPPING Pch stepping type
|
**/
|
PCH_STEPPING
|
EFIAPI
|
PchStepping (
|
VOID
|
)
|
{
|
UINT8 RevId;
|
UINT16 LpcDeviceId;
|
UINTN LpcBaseAddress;
|
#ifndef MDEPKG_NDEBUG
|
static CHAR8 *UnsupportedPchMsg = "Unsupported PCH. Supported stepping starting from";
|
#endif
|
|
if (mPchStepping != PchSteppingMax) {
|
return mPchStepping;
|
}
|
|
LpcBaseAddress = MmPciBase (
|
DEFAULT_PCI_BUS_NUMBER_PCH,
|
PCI_DEVICE_NUMBER_PCH_LPC,
|
PCI_FUNCTION_NUMBER_PCH_LPC
|
);
|
RevId = MmioRead8 (LpcBaseAddress + PCI_REVISION_ID_OFFSET);
|
|
LpcDeviceId = MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
|
|
if (IS_SKL_PCH_H_LPC_DEVICE_ID (LpcDeviceId)) {
|
switch (RevId) {
|
case V_PCH_LPC_RID_10:
|
mPchStepping = PchHB0;
|
return PchHB0;
|
|
case V_PCH_LPC_RID_20:
|
mPchStepping = PchHC0;
|
return PchHC0;
|
|
case V_PCH_LPC_RID_30:
|
mPchStepping = PchHD0;
|
return PchHD0;
|
|
case V_PCH_LPC_RID_31:
|
mPchStepping = PchHD1;
|
return PchHD1;
|
|
default:
|
DEBUG ((DEBUG_ERROR, "%a %a\n", UnsupportedPchMsg, PCH_STRINGIFY (SKL_PCH_H_MIN_SUPPORTED_STEPPING)));
|
return PchSteppingMax;
|
}
|
}
|
|
if (IS_KBL_PCH_H_LPC_DEVICE_ID (LpcDeviceId)) {
|
switch (RevId) {
|
case V_PCH_LPC_RID_0:
|
mPchStepping = KblPchHA0;
|
return KblPchHA0;
|
|
default:
|
DEBUG ((DEBUG_ERROR, "%a %a\n", UnsupportedPchMsg, PCH_STRINGIFY (KBL_PCH_H_MIN_SUPPORTED_STEPPING)));
|
return PchSteppingMax;
|
}
|
}
|
|
if (IS_PCH_LP_LPC_DEVICE_ID (LpcDeviceId)) {
|
switch (RevId) {
|
case V_PCH_LPC_RID_10:
|
mPchStepping = PchLpB0;
|
return PchLpB0;
|
|
case V_PCH_LPC_RID_11:
|
mPchStepping = PchLpB1;
|
return PchLpB1;
|
|
case V_PCH_LPC_RID_20:
|
mPchStepping = PchLpC0;
|
return PchLpC0;
|
|
case V_PCH_LPC_RID_21:
|
mPchStepping = PchLpC1;
|
return PchLpC1;
|
|
default:
|
DEBUG ((DEBUG_ERROR, "%a %a\n", UnsupportedPchMsg, PCH_STRINGIFY (PCH_LP_MIN_SUPPORTED_STEPPING)));
|
return PchSteppingMax;
|
}
|
}
|
return PchSteppingMax;
|
}
|
|
/**
|
Determine if PCH is supported
|
|
@retval TRUE PCH is supported
|
@retval FALSE PCH is not supported
|
**/
|
BOOLEAN
|
IsPchSupported (
|
VOID
|
)
|
{
|
UINT16 LpcDeviceId;
|
UINT16 LpcVendorId;
|
UINTN LpcBaseAddress;
|
|
if (mIsPchSupported != 0xFF) {
|
return (BOOLEAN) mIsPchSupported;
|
}
|
|
LpcBaseAddress = MmPciBase (
|
DEFAULT_PCI_BUS_NUMBER_PCH,
|
PCI_DEVICE_NUMBER_PCH_LPC,
|
PCI_FUNCTION_NUMBER_PCH_LPC
|
);
|
|
LpcDeviceId = MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
|
LpcVendorId = MmioRead16 (LpcBaseAddress + PCI_VENDOR_ID_OFFSET);
|
|
///
|
/// Verify that this is a supported chipset
|
///
|
if ((LpcVendorId == V_PCH_LPC_VENDOR_ID) &&
|
(IS_PCH_LPC_DEVICE_ID (LpcDeviceId))) {
|
mIsPchSupported = TRUE;
|
return TRUE;
|
} else {
|
DEBUG ((DEBUG_ERROR, "PCH code doesn't support the LpcDeviceId: 0x%04x!\n", LpcDeviceId));
|
mIsPchSupported = FALSE;
|
return FALSE;
|
}
|
}
|
|
/**
|
Return Pch Series
|
|
@retval PCH_SERIES Pch Series
|
**/
|
PCH_SERIES
|
EFIAPI
|
GetPchSeries (
|
VOID
|
)
|
{
|
UINT16 LpcDeviceId;
|
UINT32 PchSeries;
|
|
if (mPchSeries != PchUnknownSeries) {
|
return mPchSeries;
|
}
|
|
LpcDeviceId = GetLpcDid ();
|
|
if (IS_PCH_H_LPC_DEVICE_ID (LpcDeviceId)) {
|
PchSeries = PchH;
|
} else if (IS_PCH_LP_LPC_DEVICE_ID (LpcDeviceId)) {
|
PchSeries = PchLp;
|
} else {
|
PchSeries = PchUnknownSeries;
|
DEBUG ((DEBUG_ERROR, "Unsupported PCH SKU, LpcDeviceId: 0x%04x!\n", LpcDeviceId));
|
ASSERT (FALSE);
|
}
|
mPchSeries = PchSeries;
|
|
return PchSeries;
|
}
|
|
/**
|
Return Pch Generation
|
|
@retval PCH_GENERATION Pch Generation
|
**/
|
PCH_GENERATION
|
EFIAPI
|
GetPchGeneration (
|
VOID
|
)
|
{
|
UINT16 LpcDeviceId;
|
PCH_GENERATION PchGen;
|
|
if (mPchGeneration != PchUnknownGeneration) {
|
return mPchGeneration;
|
}
|
|
LpcDeviceId = GetLpcDid ();
|
|
if (IS_SKL_PCH_LPC_DEVICE_ID (LpcDeviceId)) {
|
PchGen = SklPch;
|
} else if (IS_KBL_PCH_LPC_DEVICE_ID (LpcDeviceId)) {
|
PchGen = KblPch;
|
} else {
|
PchGen = PchUnknownGeneration;
|
DEBUG ((DEBUG_ERROR, "Unsupported PCH SKU, LpcDeviceId: 0x%04x!\n", LpcDeviceId));
|
ASSERT (FALSE);
|
}
|
mPchGeneration = PchGen;
|
|
return PchGen;
|
}
|
|
/**
|
Get PCH SKU type
|
|
@retval PCH_SKU_TYPE Type of PCH SKU
|
**/
|
PCH_SKU_TYPE
|
GetPchSkuType (
|
VOID
|
)
|
{
|
UINT16 LpcDeviceId;
|
|
LpcDeviceId = GetLpcDid ();
|
|
if (IS_PCH_LPC_DEVICE_ID_MOBILE (LpcDeviceId)) {
|
return PchMobileSku;
|
} else if (IS_PCH_LPC_DEVICE_ID_DESKTOP (LpcDeviceId)) {
|
return PchDesktopSku;
|
} else if (IS_PCH_LPC_DEVICE_ID_SERVER (LpcDeviceId)) {
|
return PchServerSku;
|
} else {
|
return PchUnknownSku;
|
}
|
}
|
|
/**
|
Get Pch Maximum Pcie Root Port Number
|
|
@retval Pch Maximum Pcie Root Port Number
|
**/
|
UINT8
|
EFIAPI
|
GetPchMaxPciePortNum (
|
VOID
|
)
|
{
|
PCH_SERIES PchSeries;
|
|
PchSeries = GetPchSeries ();
|
switch (PchSeries) {
|
case PchLp:
|
return PCH_LP_PCIE_MAX_ROOT_PORTS;
|
|
case PchH:
|
switch (GetPchGeneration ()) {
|
case SklPch:
|
return SKL_PCH_H_PCIE_MAX_ROOT_PORTS;
|
case KblPch:
|
return KBL_PCH_H_PCIE_MAX_ROOT_PORTS;
|
default:
|
return 0;
|
}
|
default:
|
return 0;
|
}
|
}
|
|
/**
|
Get Pch Maximum Sata Port Number
|
|
@retval Pch Maximum Sata Port Number
|
**/
|
UINT8
|
EFIAPI
|
GetPchMaxSataPortNum (
|
VOID
|
)
|
{
|
PCH_SERIES PchSeries;
|
|
PchSeries = GetPchSeries ();
|
switch (PchSeries) {
|
case PchLp:
|
return PCH_LP_AHCI_MAX_PORTS;
|
|
case PchH:
|
return PCH_H_AHCI_MAX_PORTS;
|
|
default:
|
return 0;
|
}
|
}
|
|
/**
|
Get Pch Usb Maximum Physical Port Number
|
|
@retval Pch Usb Maximum Physical Port Number
|
**/
|
UINT8
|
EFIAPI
|
GetPchUsbMaxPhysicalPortNum (
|
VOID
|
)
|
{
|
PCH_SERIES PchSeries;
|
|
PchSeries = GetPchSeries ();
|
switch (PchSeries) {
|
case PchLp:
|
return PCH_LP_XHCI_MAX_USB2_PHYSICAL_PORTS;
|
|
case PchH:
|
return PCH_H_XHCI_MAX_USB2_PHYSICAL_PORTS;
|
|
default:
|
return 0;
|
}
|
}
|
|
/**
|
Get Pch Maximum Usb2 Port Number of XHCI Controller
|
|
@retval Pch Maximum Usb2 Port Number of XHCI Controller
|
**/
|
UINT8
|
EFIAPI
|
GetPchXhciMaxUsb2PortNum (
|
VOID
|
)
|
{
|
PCH_SERIES PchSeries;
|
|
PchSeries = GetPchSeries ();
|
switch (PchSeries) {
|
case PchLp:
|
return PCH_LP_XHCI_MAX_USB2_PORTS;
|
|
case PchH:
|
return PCH_H_XHCI_MAX_USB2_PORTS;
|
|
default:
|
return 0;
|
}
|
}
|
|
/**
|
Get Pch Maximum Usb3 Port Number of XHCI Controller
|
|
@retval Pch Maximum Usb3 Port Number of XHCI Controller
|
**/
|
UINT8
|
EFIAPI
|
GetPchXhciMaxUsb3PortNum (
|
VOID
|
)
|
{
|
PCH_SERIES PchSeries;
|
|
PchSeries = GetPchSeries ();
|
switch (PchSeries) {
|
case PchLp:
|
return PCH_LP_XHCI_MAX_USB3_PORTS;
|
|
case PchH:
|
return PCH_H_XHCI_MAX_USB3_PORTS;
|
|
default:
|
return 0;
|
}
|
}
|
|
/**
|
Get Lpc Did
|
|
@retval UINT16 Lpc Did
|
**/
|
UINT16
|
EFIAPI
|
GetLpcDid (
|
VOID
|
)
|
{
|
UINT16 LpcDeviceId;
|
UINTN LpcBaseAddress;
|
|
LpcBaseAddress = MmPciBase (
|
DEFAULT_PCI_BUS_NUMBER_PCH,
|
PCI_DEVICE_NUMBER_PCH_LPC,
|
PCI_FUNCTION_NUMBER_PCH_LPC
|
);
|
|
LpcDeviceId = MmioRead16 (LpcBaseAddress + PCI_DEVICE_ID_OFFSET);
|
|
return LpcDeviceId;
|
}
|
|
/**
|
Get RST mode supported by the silicon
|
|
@retval RST_MODE RST mode supported by silicon
|
**/
|
RST_MODE
|
EFIAPI
|
GetSupportedRstMode (
|
VOID
|
)
|
{
|
if (IsPchRaidSupported ()) {
|
return RstPremium;
|
} else if (IsOptaneModeSupported ()) {
|
return RstOptane;
|
} else {
|
return RstUnsupported;
|
}
|
}
|
|
/**
|
Check if current SKU supports Optane mode
|
|
@retval TRUE This SKU supports Optane mode
|
@retval FALSE This SKU doesn't support Optane mode
|
**/
|
BOOLEAN
|
EFIAPI
|
IsOptaneModeSupported (
|
VOID
|
)
|
{
|
UINT16 LpcDeviceId;
|
BOOLEAN OptaneSupported;
|
|
LpcDeviceId = GetLpcDid ();
|
|
switch (LpcDeviceId) {
|
case V_KBL_PCH_H_LPC_DEVICE_ID_DT_B250:
|
case V_KBL_PCH_H_LPC_DEVICE_ID_DT_Q250:
|
OptaneSupported = TRUE;
|
break;
|
default:
|
OptaneSupported = FALSE;
|
break;
|
}
|
|
return OptaneSupported;
|
}
|
|
/**
|
Check if current SKU supports RAID feature
|
|
@retval TRUE This SKU supports RAID
|
@retval FALSE This SKU doesn't support RAID
|
**/
|
BOOLEAN
|
EFIAPI
|
IsPchRaidSupported (
|
VOID
|
)
|
{
|
UINT16 LpcDeviceId;
|
BOOLEAN RaidSupported;
|
|
LpcDeviceId = GetLpcDid ();
|
|
|
switch (LpcDeviceId) {
|
case V_PCH_LP_LPC_DEVICE_ID_MB_1: // SPT-LP Base-U (SPT-LP Mobile)
|
case V_PCH_LP_LPC_DEVICE_ID_MB_5: // KBL-LP Base-U (KBL-LP Mobile)
|
case V_PCH_LP_LPC_DEVICE_ID_MB_10: // KBL-LP Mobile (U) iHDCP 2.2 Base
|
case V_SKL_PCH_H_LPC_DEVICE_ID_DT_1: // H110 (SPT-H Desktop)
|
case V_SKL_PCH_H_LPC_DEVICE_ID_DT_6: // B150 (SPT-H Desktop)
|
case V_SKL_PCH_H_LPC_DEVICE_ID_DT_5: // Q150 (SPT-H Desktop)
|
case V_KBL_PCH_H_LPC_DEVICE_ID_DT_B250: // B250 (KBL-H Desktop)
|
case V_KBL_PCH_H_LPC_DEVICE_ID_DT_Q250: // Q250 (KBL-H Desktop)
|
case V_SKL_PCH_H_LPC_DEVICE_ID_SVR_1: // C232 (SPT-H Server)
|
RaidSupported = FALSE;
|
break;
|
default:
|
RaidSupported = TRUE;
|
break;
|
}
|
|
return RaidSupported;
|
}
|