/** @file
|
This is the driver that initializes the Intel PCH.
|
|
Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
#include "PchInit.h"
|
#include <Library/PchSerialIoLib.h>
|
|
//
|
// Module variables
|
//
|
GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol;
|
|
extern PCH_RST_PCIE_STORAGE_DETECTION mRstPcieStorageDetection[];
|
|
/**
|
Retrieve interrupt information about a PCH device from policy
|
|
@param[in] Device PCI device number
|
|
@retval PCH_DEVICE_INTERRUPT_CONFIG structure with device's interrupt information
|
**/
|
PCH_DEVICE_INTERRUPT_CONFIG
|
GetInterruptPolicy (
|
IN PCH_SERIAL_IO_CONTROLLER Device
|
)
|
{
|
PCH_DEVICE_INTERRUPT_CONFIG EmptyRecord;
|
UINT8 DevNum;
|
UINT8 FuncNum;
|
UINT8 Index;
|
|
ZeroMem (&EmptyRecord, sizeof (PCH_DEVICE_INTERRUPT_CONFIG));
|
DevNum = GetSerialIoDeviceNumber (Device);
|
FuncNum = GetSerialIoFunctionNumber (Device);
|
|
for (Index = 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig; Index++) {
|
if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device == DevNum) &&
|
(mPchConfigHob->Interrupt.DevIntConfig[Index].Function == FuncNum)) {
|
return mPchConfigHob->Interrupt.DevIntConfig[Index];
|
}
|
}
|
return EmptyRecord;
|
}
|
|
/**
|
Update ASL definitions for SerialIo devices.
|
|
@retval EFI_SUCCESS The function completed successfully
|
**/
|
EFI_STATUS
|
UpdateSerialIoAcpiData (
|
VOID
|
)
|
{
|
PCH_SERIAL_IO_CONTROLLER Index;
|
|
for (Index = 0; Index < PCH_SERIALIO_MAX_CONTROLLERS; Index++) {
|
mPchNvsAreaProtocol.Area->SMD[Index] = mPchConfigHob->SerialIo.DevMode[Index];
|
mPchNvsAreaProtocol.Area->SIR[Index] = (GetInterruptPolicy (Index)).Irq;
|
mPchNvsAreaProtocol.Area->SB0[Index] = FindSerialIoBar (Index, 0);
|
mPchNvsAreaProtocol.Area->SB1[Index] = FindSerialIoBar (Index, 1);
|
}
|
if (GetPchSeries () == PchH) {
|
mPchNvsAreaProtocol.Area->SMD[PchSerialIoIndexI2C4] = PchSerialIoDisabled;
|
mPchNvsAreaProtocol.Area->SMD[PchSerialIoIndexI2C5] = PchSerialIoDisabled;
|
}
|
|
//
|
// Update GPIO device ACPI variables
|
//
|
mPchNvsAreaProtocol.Area->GPEN = mPchConfigHob->SerialIo.Gpio;
|
mPchNvsAreaProtocol.Area->SGIR = mPchConfigHob->Interrupt.GpioIrqRoute;
|
|
|
DEBUG ((DEBUG_INFO, "UpdateSerialIoAcpiData() End\n"));
|
|
return EFI_SUCCESS;
|
}
|
|
/**
|
Update NVS Area after RST PCIe Storage Remapping and before Boot
|
|
@retval EFI_SUCCESS The function completed successfully
|
**/
|
EFI_STATUS
|
PchUpdateNvsAreaAfterRemapping (
|
VOID
|
)
|
{
|
UINTN Index;
|
|
for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) {
|
mPchNvsAreaProtocol.Area->RstPcieStorageInterfaceType[Index] = mRstPcieStorageDetection[Index].DeviceInterface;
|
mPchNvsAreaProtocol.Area->RstPcieStoragePmCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PmCapPtr;
|
mPchNvsAreaProtocol.Area->RstPcieStoragePcieCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PcieCapPtr;
|
mPchNvsAreaProtocol.Area->RstPcieStorageL1ssCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.L1ssCapPtr;
|
mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl2[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl2;
|
mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl1[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl1;
|
mPchNvsAreaProtocol.Area->RstPcieStorageLtrCapPtr[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.LtrCapPtr;
|
mPchNvsAreaProtocol.Area->RstPcieStorageEpLtrData[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLtrData;
|
mPchNvsAreaProtocol.Area->RstPcieStorageEpLctlData16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLctlData16;
|
mPchNvsAreaProtocol.Area->RstPcieStorageEpDctlData16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctlData16;
|
mPchNvsAreaProtocol.Area->RstPcieStorageEpDctl2Data16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctl2Data16;
|
mPchNvsAreaProtocol.Area->RstPcieStorageRpDctl2Data16[Index] = mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.RootPortDctl2Data16;
|
mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBar[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBar;
|
mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBarValue[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBarValue;
|
mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBar[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBar;
|
mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBarValue[Index] = mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBarValue;
|
mPchNvsAreaProtocol.Area->RstPcieStorageRootPortNum[Index] = mRstPcieStorageDetection[Index].RootPortNum;
|
}
|
return EFI_SUCCESS;
|
}
|
|
/**
|
PCH ACPI initialization before Boot Sript Table is closed
|
It update ACPI table and ACPI NVS area.
|
|
@param[in] Event A pointer to the Event that triggered the callback.
|
@param[in] Context A pointer to private data registered with the callback function.
|
**/
|
VOID
|
EFIAPI
|
PchAcpiOnEndOfDxe (
|
IN EFI_EVENT Event,
|
IN VOID *Context
|
)
|
{
|
|
PCH_SERIES PchSeries;
|
|
DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() Start\n"));
|
|
PchSeries = GetPchSeries ();
|
|
///
|
/// Closed the event to avoid call twice when launch shell
|
///
|
gBS->CloseEvent (Event);
|
|
//
|
// Init HDA Audio ACPI tables
|
//
|
PchHdAudioAcpiInit ();
|
//
|
// Update ASL definitions for SerialIo devices.
|
//
|
UpdateSerialIoAcpiData ();
|
//
|
// Define and update ASL definitions for Cio2 device (only on PCH-LP).
|
//
|
if (PchSeries >= PchLp) {
|
UpdateCio2AcpiData ();
|
}
|
|
//
|
// Update Pch Nvs Area
|
//
|
PchUpdateNvsArea ();
|
|
//
|
// Patch PchNvsArea Address
|
//
|
PatchPchNvsAreaAddress ();
|
|
DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() End\n"));
|
|
return;
|
}
|
|
/**
|
Initialize Pch acpi
|
@param[in] ImageHandle Handle for the image of this driver
|
|
@retval EFI_SUCCESS The function completed successfully
|
@retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver
|
**/
|
EFI_STATUS
|
EFIAPI
|
PchAcpiInit (
|
IN EFI_HANDLE ImageHandle
|
)
|
{
|
EFI_STATUS Status;
|
EFI_EVENT EndOfDxeEvent;
|
|
DEBUG ((DEBUG_INFO, "Install PCH NVS protocol\n"));
|
|
Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (PCH_NVS_AREA), (VOID **) &mPchNvsAreaProtocol.Area);
|
ASSERT_EFI_ERROR (Status);
|
|
ZeroMem ((VOID *) mPchNvsAreaProtocol.Area, sizeof (PCH_NVS_AREA));
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
&ImageHandle,
|
&gPchNvsAreaProtocolGuid,
|
&mPchNvsAreaProtocol,
|
NULL
|
);
|
ASSERT_EFI_ERROR (Status);
|
|
///
|
/// Update the NVS Area after RST PCIe Storage Remapping
|
///
|
PchUpdateNvsAreaAfterRemapping ();
|
//
|
// Register an end of DXE event for PCH ACPI to do tasks before invoking any UEFI drivers,
|
// applications, or connecting consoles,...
|
//
|
Status = gBS->CreateEventEx (
|
EVT_NOTIFY_SIGNAL,
|
TPL_CALLBACK,
|
PchAcpiOnEndOfDxe,
|
NULL,
|
&gEfiEndOfDxeEventGroupGuid,
|
&EndOfDxeEvent
|
);
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
}
|
|
|
/**
|
PCH Update NvsArea ExitBootServicesFlag on ExitBootService. This event is used if only ExitBootService is used
|
and not in legacy boot
|
|
@retval None
|
**/
|
VOID
|
EFIAPI
|
PchUpdateNvsOnExitBootServices (
|
VOID
|
)
|
{
|
mPchNvsAreaProtocol.Area->ExitBootServicesFlag = 1;
|
|
return;
|
}
|
|
/**
|
Update ASL object before Boot
|
|
@retval EFI_STATUS
|
@retval EFI_NOT_READY The Acpi protocols are not ready.
|
**/
|
EFI_STATUS
|
PchUpdateNvsArea (
|
VOID
|
)
|
{
|
EFI_STATUS Status;
|
PCH_SERIES PchSeries;
|
UINTN Index;
|
UINT32 HpetBaseAdress;
|
GPIO_GROUP GroupToGpeDw0;
|
GPIO_GROUP GroupToGpeDw1;
|
GPIO_GROUP GroupToGpeDw2;
|
GPIO_GROUP Group;
|
UINT32 PadNumber;
|
GPIO_PAD GpioPad;
|
GPIO_PAD_OWN PadOwnVal;
|
GPIO_CONFIG GpioData;
|
UINTN RpDev;
|
UINTN RpFun;
|
UINT32 Data32;
|
UINT16 Data16;
|
|
Status = EFI_SUCCESS;
|
PchSeries = GetPchSeries ();
|
|
//
|
// Update ASL PCIE port address according to root port device and function
|
//
|
for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) {
|
Status = GetPchPcieRpDevFun (Index, &RpDev, &RpFun);
|
ASSERT_EFI_ERROR (Status);
|
|
Data32 = ((UINT8) RpDev << 16) | (UINT8) RpFun;
|
mPchNvsAreaProtocol.Area->RpAddress[Index] = Data32;
|
|
//
|
// Update Maximum Snoop Latency and Maximum No-Snoop Latency values for PCIE
|
//
|
mPchNvsAreaProtocol.Area->PcieLtrMaxSnoopLatency[Index] = mPchConfigHob->PcieRp.RootPort[Index].LtrMaxSnoopLatency;
|
mPchNvsAreaProtocol.Area->PcieLtrMaxNoSnoopLatency[Index] = mPchConfigHob->PcieRp.RootPort[Index].LtrMaxNoSnoopLatency;
|
}
|
|
//
|
// Update PCHS.
|
//
|
mPchNvsAreaProtocol.Area->PchSeries = (UINT16) PchSeries;
|
//
|
// Update PCHG.
|
//
|
mPchNvsAreaProtocol.Area->PchGeneration = (UINT16) GetPchGeneration ();
|
//
|
// Update HPET base address.
|
//
|
PchHpetBaseGet (&HpetBaseAdress);
|
mPchNvsAreaProtocol.Area->HPTE = TRUE; // @todo remove the NVS, since it's always enabled.
|
mPchNvsAreaProtocol.Area->HPTB = HpetBaseAdress;
|
//
|
// Update SBREG_BAR.
|
//
|
mPchNvsAreaProtocol.Area->SBRG = PCH_PCR_BASE_ADDRESS;
|
|
//
|
// Update PMC ACPIBASE and PWRMBASE
|
//
|
PchAcpiBaseGet (&Data16);
|
mPchNvsAreaProtocol.Area->PMBS = Data16;
|
|
PchPwrmBaseGet (&Data32);
|
mPchNvsAreaProtocol.Area->PWRM = Data32;
|
|
//
|
// Update GPP_X to GPE_DWX mapping.
|
//
|
GpioGetGroupToGpeDwX (&GroupToGpeDw0, &GroupToGpeDw1, &GroupToGpeDw2);
|
|
//
|
// GPEM is an object for informing how GPIO groups are mapped to GPE.
|
// Mapping for GPP_x is evaluated from (GPEM >> (GroupNumber*2)) & 0x3
|
// Here GroupNumber does not match xxx_GPIO_GROUP type and is always
|
// 0 based (GPP_A = 0, both for LP and H)
|
// Possible values for each group:
|
// 00b - 2-tier
|
// 01b - 1-tier, GPE_DW0
|
// 10b - 1-tier, GPE_DW1
|
// 11b - 1-tier, GPE_DW2
|
//
|
mPchNvsAreaProtocol.Area->GPEM = (0x1 << (GpioGetGroupIndexFromGroup (GroupToGpeDw0) * 2)) |
|
(0x2 << (GpioGetGroupIndexFromGroup (GroupToGpeDw1) * 2)) |
|
(0x3 << (GpioGetGroupIndexFromGroup (GroupToGpeDw2) * 2));
|
|
//
|
// GP2T[GroupIndex] is an object for storing information about GPIO pads which are
|
// enabled for 2-tier GPE event and their interrupt is configured for level
|
// 0b - Gpio Pad which is not 2-tier event or hasn't got level interrupt
|
// 1b - Gpio Pad enabled for 2-tier event and having level interrupt
|
//
|
for (Group = GpioGetLowestGroup (); Group <= GpioGetHighestGroup (); Group++) {
|
Index = GpioGetGroupIndexFromGroup (Group);
|
if (Index >= sizeof (mPchNvsAreaProtocol.Area->GP2T) / sizeof (mPchNvsAreaProtocol.Area->GP2T[0])) {
|
DEBUG ((DEBUG_ERROR, "GpioGetGroupIndexFromGroup (%x) = %x out of GP2T table range\n", Group, GpioGetGroupIndexFromGroup (Group)));
|
continue;
|
}
|
mPchNvsAreaProtocol.Area->GP2T[Index] = 0x0;
|
|
if ((Group == GroupToGpeDw0) ||
|
(Group == GroupToGpeDw1) ||
|
(Group == GroupToGpeDw2)) {
|
//
|
// not 2-tier GPE
|
//
|
continue;
|
}
|
|
for (PadNumber = 0; PadNumber < GpioGetPadPerGroup (Group); PadNumber++) {
|
|
GpioPad = GpioGetGpioPadFromGroupAndPadNumber (Group, PadNumber);
|
|
GpioGetPadOwnership (GpioPad, &PadOwnVal);
|
if (PadOwnVal != GpioPadOwnHost) {
|
continue;
|
}
|
|
GpioGetPadConfig (GpioPad, &GpioData);
|
|
if (((GpioData.InterruptConfig & B_GPIO_INT_CONFIG_INT_SOURCE_MASK) == GpioIntSci) &&
|
((GpioData.InterruptConfig & B_GPIO_INT_CONFIG_INT_TYPE_MASK) == GpioIntLevel)) {
|
//
|
// This pad is enabled for GPE and has level interrupt
|
//
|
mPchNvsAreaProtocol.Area->GP2T[Index] |= 1 << PadNumber;
|
}
|
}
|
}
|
|
//
|
// Thermal device in ACPI mode
|
//
|
mPchNvsAreaProtocol.Area->ThermalDeviceAcpiEnabled = mPchConfigHob->Thermal.ThermalDeviceEnable == 2 ? 1 : 0;
|
//
|
// Get Thermal Device interrupt line number
|
//
|
for (Index = 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig; Index++) {
|
if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device == PCI_DEVICE_NUMBER_PCH_THERMAL) &&
|
(mPchConfigHob->Interrupt.DevIntConfig[Index].Function == PCI_FUNCTION_NUMBER_PCH_THERMAL)) {
|
mPchNvsAreaProtocol.Area->ThermalDeviceInterruptLine = mPchConfigHob->Interrupt.DevIntConfig[Index].Irq;
|
}
|
}
|
|
//
|
// SCS Configuration
|
//
|
// Update eMMC HS400 mode enablement
|
//
|
mPchNvsAreaProtocol.Area->EMH4 = (UINT8) mPchConfigHob->Scs.ScsEmmcHs400Enabled;
|
|
//
|
// Update eMMC Driver Strength
|
// Per eMMC 5.01 JEDEC Specification (JESD84-B50.1, Table 186)
|
// Nominal Impedance - Driver Type Values:
|
// 50 Ohm 0x0
|
// 33 Ohm 0x1
|
// 40 Ohm 0x4
|
//
|
switch (mPchConfigHob->Scs.ScsEmmcHs400DriverStrength) {
|
case DriverStrength33Ohm:
|
mPchNvsAreaProtocol.Area->EMDS = 0x1;
|
break;
|
case DriverStrength40Ohm:
|
mPchNvsAreaProtocol.Area->EMDS = 0x4;
|
break;
|
case DriverStrength50Ohm:
|
default:
|
mPchNvsAreaProtocol.Area->EMDS = 0x0;
|
}
|
|
//
|
// CPU SKU
|
//
|
mPchNvsAreaProtocol.Area->CpuSku = GetCpuSku ();
|
|
return Status;
|
}
|
|
/**
|
Initialize PCH Nvs Area opeartion region.
|
|
@retval EFI_SUCCESS initialized successfully
|
@retval EFI_NOT_FOUND Nvs Area operation region is not found
|
**/
|
EFI_STATUS
|
PatchPchNvsAreaAddress (
|
VOID
|
)
|
{
|
EFI_STATUS Status;
|
UINT32 Address;
|
UINT16 Length;
|
|
Address = (UINT32) (UINTN) mPchNvsAreaProtocol.Area;
|
Length = (UINT16) sizeof (PCH_NVS_AREA);
|
DEBUG ((DEBUG_INFO, "PatchPchNvsAreaAddress: PCH NVS Address %x Length %x\n", Address, Length));
|
Status = UpdateNameAslCode (SIGNATURE_32 ('P','N','V','B'), &Address, sizeof (Address));
|
ASSERT_EFI_ERROR (Status);
|
Status = UpdateNameAslCode (SIGNATURE_32 ('P','N','V','L'), &Length, sizeof (Length));
|
ASSERT_EFI_ERROR (Status);
|
|
return EFI_SUCCESS;
|
}
|
|