audk/Vlv2TbltDevicePkg/PlatformPei/Platform.c

1199 lines
33 KiB
C
Raw Normal View History

/** @file
Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
Module Name:
**/
#include "CommonHeader.h"
#include "Platform.h"
#include <Library/PciCf8Lib.h>
#include "PlatformBaseAddresses.h"
#include "PchAccess.h"
#include <Guid/PlatformInfo.h>
#include "PchCommonDefinitions.h"
#include <Ppi/MfgMemoryTest.h>
#include <Guid/SetupVariable.h>
#include <Guid/Vlv2Variable.h>
#include <Ppi/fTPMPolicy.h>
//
// Start::Alpine Valley platform
//
enum {
SMBUS_READ_BYTE,
SMBUS_WRITE_BYTE,
SMBUS_READ_BLOCK,
SMBUS_WRITE_BLOCK
};
#define EC_BASE 0xE0000000
//
// DEVICE 0 (Memroy Controller Hub)
//
#define MC_BUS 0x00
#define MC_DEV 0x00
#define MC_FUN 0x00
#define MC_DEV_FUN (MC_DEV << 3)
#define MC_BUS_DEV_FUN ((MC_BUS << 8) + MC_DEV_FUN)
//
// SysCtl SMBus address and block size
//
#define AV_SC_SMBUS_ADDRESS 0x60
#define AV_SC_BYTE_LEN 1
#define AV_SC_BLOCK_LEN 4
#define AV_SC_SMBUS_WRCMD 1
#define AV_SC_SMBUS_RDCMD 0
//
// SysCtl registers offset
//
#define AV_SC_REG_PLATFORM_ID 24 // 0x18
#define AV_SC_REG_BOARD_ID 28 // 0x1C
#define AV_SC_REG_FAB_ID 32 // 0x20
#define AV_SC_REG_ECO_ID 68 // 0x44
#define AV_SC_REG_DDR_DAUGHTER_CARD_ID 144 // 0x90
#define AV_SC_REG_SODIMM_CONFIG 36
//
// ID values
//
#define AV_SC_PLATFORM_ID_TABLET 0
#define AV_SC_PLATFORM_ID_NETBOOK 2
#define AV_SC_PLATFORM_ID_INTERPOSER 3 // Configuration TBD
#define AV_SC_BOARD_ID_AV_SVP 1492
#define BUS_TRIES 3 // How many times to retry on Bus Errors
#define GTT_SIZE_1MB 1
#define GTT_SIZE_2MB 2
#define PciCfg16Read( PciExpressBase, Bus, Device, Function, Register ) \
MmioRead16(PciExpressBase + \
(UINTN)(Bus << 20) + \
(UINTN)(Device << 15) + \
(UINTN)(Function << 12) + \
(UINTN)(Register))
#define PciCfg16Write( PciExpressBase, Bus, Device, Function, Register, Data ) \
MmioWrite16(PciExpressBase + \
(UINTN)(Bus << 20) + \
(UINTN)(Device << 15) + \
(UINTN)(Function << 12) + \
(UINTN)(Register), \
(UINT16)Data)
//
//Memory Test Manufacturing mode
//
UINT32 DataPatternForMemoryTest[] = {
0x55555555, 0xAAAAAAAA, 0x55555510, 0x555555EF, 0x55555510, 0x555555EF, 0x55555510, 0x555555EF,
0x55555555, 0xAAAAAAAA, 0x55551055, 0x5555EF55, 0x55551055, 0x5555EF55, 0x55551055, 0x5555EF55,
0x55555555, 0xAAAAAAAA, 0x55105555, 0x55EF5555, 0x55105555, 0x55EF5555, 0x55105555, 0x55EF5555,
0x55555555, 0xAAAAAAAA, 0x10555555, 0xEF555555, 0x10555555, 0xEF555555, 0x10555555, 0xEF555555
};
#define DATA_PATTERN_ARRAY_SIZE (sizeof(DataPatternForMemoryTest) / sizeof(UINT32))
//
//Memory Test Manufacturing mode
//
//
// The global indicator, the FvFileLoader callback will modify it to TRUE after loading PEIM into memory
//
BOOLEAN ImageInMemory = FALSE;
EFI_STATUS
EFIAPI
Stall (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_STALL_PPI *This,
IN UINTN Microseconds
);
EFI_STATUS
EFIAPI
MfgMemoryTest (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN PEI_MFG_MEMORY_TEST_PPI *This,
IN UINT32 BeginAddress,
IN UINT32 MemoryLength
);
static EFI_PEI_STALL_PPI mStallPpi = {
PEI_STALL_RESOLUTION,
Stall
};
static PEI_MFG_MEMORY_TEST_PPI mPeiMfgMemoryTestPpi = {
MfgMemoryTest
};
static EFI_PEI_PPI_DESCRIPTOR mInstallStallPpi[] = {
{
EFI_PEI_PPI_DESCRIPTOR_PPI,
&gEfiPeiStallPpiGuid,
&mStallPpi
},
{
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gPeiMfgMemoryTestPpiGuid,
&mPeiMfgMemoryTestPpi
}
};
EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList[1] = {
{
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiMemoryDiscoveredPpiGuid,
MemoryDiscoveredPpiNotifyCallback
}
};
EFI_STATUS
EFIAPI
InstallMonoStatusCode (
IN EFI_FFS_FILE_HEADER *FfsHeader,
IN CONST EFI_PEI_SERVICES **PeiServices
);
EFI_STATUS
ReadPlatformIds (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob
);
//
// Start::Alpine Valley platform
//
EFI_STATUS
PeiSmbusExec (
UINT16 SmbusBase,
UINT8 SlvAddr,
UINT8 Operation,
UINT8 Offset,
UINT8 *Length,
UINT8 *Buffer
);
/**
Detemine Turbot board
@return 0: Not Turbot board
1: Turbot board
**/
UINT32
DetermineTurbotBoard (
void
)
{
UINTN PciD31F0RegBase = 0;
UINT32 GpioValue = 0;
UINT32 TmpVal = 0;
UINT32 MmioConf0 = 0;
UINT32 MmioPadval = 0;
UINT32 PConf0Offset = 0x200; //GPIO_S5_4 pad_conf0 register offset
UINT32 PValueOffset = 0x208; //GPIO_S5_4 pad_value register offset
UINT32 SSUSOffset = 0x2000;
UINT32 IoBase = 0;
DEBUG ((EFI_D_ERROR, "DetermineTurbotBoard() Entry\n"));
PciD31F0RegBase = MmPciAddress (0,
0,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
0
);
IoBase = MmioRead32 (PciD31F0RegBase + R_PCH_LPC_IO_BASE) & B_PCH_LPC_IO_BASE_BAR;
MmioConf0 = IoBase + SSUSOffset + PConf0Offset;
MmioPadval = IoBase + SSUSOffset + PValueOffset;
//0xFED0E200/0xFED0E208 is pad_Conf/pad_val register address of GPIO_S5_4
DEBUG ((EFI_D_ERROR, "MmioConf0[0x%x], MmioPadval[0x%x]\n", MmioConf0, MmioPadval));
MmioWrite32 (MmioConf0, 0x2003CC00);
TmpVal = MmioRead32 (MmioPadval);
TmpVal &= ~0x6; //Clear bit 1:2
TmpVal |= 0x2; // Set the pin as GPI
MmioWrite32 (MmioPadval, TmpVal);
GpioValue = MmioRead32 (MmioPadval);
DEBUG ((EFI_D_ERROR, "Gpio_S5_4 value is 0x%x\n", GpioValue));
return (GpioValue & 0x1);
}
EFI_STATUS
FtpmPolicyInit (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN SYSTEM_CONFIGURATION *pSystemConfiguration
)
{
EFI_STATUS Status;
EFI_PEI_PPI_DESCRIPTOR *mFtpmPolicyPpiDesc;
SEC_FTPM_POLICY_PPI *mFtpmPolicyPpi;
DEBUG((EFI_D_INFO, "FtpmPolicyInit Entry \n"));
if (NULL == PeiServices || NULL == pSystemConfiguration) {
DEBUG((EFI_D_ERROR, "Input error. \n"));
return EFI_INVALID_PARAMETER;
}
Status = (*PeiServices)->AllocatePool(
PeiServices,
sizeof (EFI_PEI_PPI_DESCRIPTOR),
(void **)&mFtpmPolicyPpiDesc
);
ASSERT_EFI_ERROR (Status);
Status = (*PeiServices)->AllocatePool(
PeiServices,
sizeof (SEC_FTPM_POLICY_PPI),
(void **)&mFtpmPolicyPpi
);
ASSERT_EFI_ERROR (Status);
//
// Initialize PPI
//
(*PeiServices)->SetMem ((VOID *)mFtpmPolicyPpi, sizeof (SEC_FTPM_POLICY_PPI), 0);
mFtpmPolicyPpiDesc->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
mFtpmPolicyPpiDesc->Guid = &gSeCfTPMPolicyPpiGuid;
mFtpmPolicyPpiDesc->Ppi = mFtpmPolicyPpi;
DEBUG((EFI_D_INFO, "pSystemConfiguration->fTPM = 0x%x \n", pSystemConfiguration->fTPM));
if(pSystemConfiguration->fTPM == 1) {
mFtpmPolicyPpi->fTPMEnable = TRUE;
} else {
mFtpmPolicyPpi->fTPMEnable = FALSE;
}
Status = (*PeiServices)->InstallPpi(
PeiServices,
mFtpmPolicyPpiDesc
);
ASSERT_EFI_ERROR (Status);
DEBUG((EFI_D_INFO, "FtpmPolicyInit done \n"));
return EFI_SUCCESS;
}
/**
This routine attempts to acquire the SMBus
@retval FAILURE as failed
@retval SUCCESS as passed
**/
EFI_STATUS
AcquireBus (
UINT16 SmbusBase
)
{
UINT8 StsReg;
StsReg = 0;
StsReg = (UINT8)IoRead8(SmbusBase + R_PCH_SMBUS_HSTS);
if (StsReg & B_PCH_SMBUS_IUS) {
return EFI_DEVICE_ERROR;
} else if (StsReg & B_PCH_SMBUS_HBSY) {
//
// Clear Status Register and exit
//
// Wait for HSTS.HBSY to be clear
//
do { StsReg = (UINT8) IoRead8(SmbusBase+R_PCH_SMBUS_HSTS); } while ((StsReg & B_PCH_SMBUS_HBSY) != 0);
//
// Clear all status bits
//
IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, 0xFE);
return EFI_SUCCESS;
} else {
//
// Clear out any odd status information (Will Not Clear In Use)
//
IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, StsReg);
return EFI_SUCCESS;
}
}
//
// End::Alpine Valley platform
//
/**
This function checks the memory range in PEI.
@param PeiServices Pointer to PEI Services.
@param This Pei memory test PPI pointer.
@param BeginAddress Beginning of the memory address to be checked.
@param MemoryLength Bytes of memory range to be checked.
@param Operation Type of memory check operation to be performed.
@param ErrorAddress Return the address of the error memory address.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR Memory test failed. It's not safe to use this range of memory.
**/
EFI_STATUS
EFIAPI
MfgMemoryTest (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN PEI_MFG_MEMORY_TEST_PPI *This,
IN UINT32 BeginAddress,
IN UINT32 MemoryLength
)
{
UINT32 i;
UINT32 memAddr;
UINT32 readData;
UINT32 xorData;
UINT32 TestFlag = 0;
memAddr = BeginAddress;
//
//Output Message for MFG
//
DEBUG ((EFI_D_ERROR, "MFGMODE SET\n"));
//
//Writting the pattern in defined location.
//
while (memAddr < (BeginAddress+MemoryLength)) {
for (i = 0; i < DATA_PATTERN_ARRAY_SIZE; i++) {
if (memAddr > (BeginAddress+MemoryLength -4)) {
memAddr = memAddr + 4;
break;
}
*((volatile UINT32*) memAddr) = DataPatternForMemoryTest[i];
memAddr = memAddr + 4;
}
}
//
//Verify the pattern.
//
memAddr = BeginAddress;
while (memAddr < (BeginAddress+MemoryLength)) {
for (i = 0; i < DATA_PATTERN_ARRAY_SIZE; i++) {
if (memAddr > (BeginAddress+MemoryLength -4)) {
memAddr = memAddr + 4;
break;
}
readData = *((volatile UINT32*) memAddr);
xorData = readData ^ DataPatternForMemoryTest[i];
//
// If xorData is nonzero, this particular memAddr has a failure.
//
if (xorData != 0x00000000) {
DEBUG ((EFI_D_ERROR, "Expected value....: %x\n", DataPatternForMemoryTest[i]));
DEBUG ((EFI_D_ERROR, "ReadData value....: %x\n", readData));
DEBUG ((EFI_D_ERROR, "Pattern failure at....: %x\n", memAddr));
TestFlag = 1;
}
memAddr = memAddr + 4;
}
}
if (TestFlag) {
return EFI_DEVICE_ERROR;
}
//
//Output Message for MFG
//
DEBUG ((EFI_D_ERROR, "MFGMODE MEMORY TEST PASSED\n"));
return EFI_SUCCESS;
}
BOOLEAN
IsRtcUipAlwaysSet (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_PEI_STALL_PPI *StallPpi;
UINTN Count;
(**PeiServices).LocatePpi (PeiServices, &gEfiPeiStallPpiGuid, 0, NULL, (void **)&StallPpi);
for (Count = 0; Count < 500; Count++) { // Maximum waiting approximates to 1.5 seconds (= 3 msec * 500)
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERA);
if ((IoRead8 (R_PCH_RTC_TARGET2) & B_PCH_RTC_REGISTERA_UIP) == 0) {
return FALSE;
}
StallPpi->Stall (PeiServices, StallPpi, 3000);
}
return TRUE;
}
EFI_STATUS
RtcPowerFailureHandler (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
UINT16 DataUint16;
UINT8 DataUint8;
BOOLEAN RtcUipIsAlwaysSet;
DataUint16 = MmioRead16 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1);
RtcUipIsAlwaysSet = IsRtcUipAlwaysSet (PeiServices);
if ((DataUint16 & B_PCH_PMC_GEN_PMCON_RTC_PWR_STS) || (RtcUipIsAlwaysSet)) {
//
// Execute the sequence below. This will ensure that the RTC state machine has been initialized.
//
// Step 1.
// BIOS clears this bit by writing a '0' to it.
//
if (DataUint16 & B_PCH_PMC_GEN_PMCON_RTC_PWR_STS) {
//
// Set to invalid date in order to reset the time to
// BIOS build time later in the boot (SBRUN.c file).
//
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_YEAR);
IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_MONTH);
IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_DAYOFMONTH);
IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_DAYOFWEEK);
IoWrite8 (R_PCH_RTC_TARGET2, 0x0FF);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_SECONDSALARM);
IoWrite8 (R_PCH_RTC_TARGET2, 0x00);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_MINUTESALARM);
IoWrite8 (R_PCH_RTC_TARGET2, 0x00);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_HOURSALARM);
IoWrite8 (R_PCH_RTC_TARGET2, 0x00);
}
//
// Step 2.
// Set RTC Register 0Ah[6:4] to '110' or '111'.
//
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERA);
IoWrite8 (R_PCH_RTC_TARGET2, (V_PCH_RTC_REGISTERA_DV_DIV_RST1 | V_PCH_RTC_REGISTERA_RS_976P5US));
//
// Step 3.
// Set RTC Register 0Bh[7].
//
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB);
DataUint8 = (IoRead8 (R_PCH_RTC_TARGET2) | B_PCH_RTC_REGISTERB_SET);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB);
IoWrite8 (R_PCH_RTC_TARGET2, DataUint8);
//
// Step 4.
// Set RTC Register 0Ah[6:4] to '010'.
//
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERA);
IoWrite8 (R_PCH_RTC_TARGET2, (V_PCH_RTC_REGISTERA_DV_NORM_OP | V_PCH_RTC_REGISTERA_RS_976P5US));
//
// Step 5.
// Clear RTC Register 0Bh[7].
//
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB);
DataUint8 = (IoRead8 (R_PCH_RTC_TARGET2) & (UINT8)~B_PCH_RTC_REGISTERB_SET);
IoWrite8 (R_PCH_RTC_INDEX2, R_PCH_RTC_REGISTERB);
IoWrite8 (R_PCH_RTC_TARGET2, DataUint8);
}
return EFI_SUCCESS;
}
VOID
PchBaseInit (
VOID
)
{
//
// Program ACPI Power Management I/O Space Base Address
//
MmioWrite16 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_ACPI_BASE
),
(UINT16)((ACPI_BASE_ADDRESS & B_PCH_LPC_ACPI_BASE_BAR) | B_PCH_LPC_ACPI_BASE_EN)
);
//
// Program GPIO Base Address
//
MmioWrite16 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_GPIO_BASE
),
(UINT16)((GPIO_BASE_ADDRESS & B_PCH_LPC_GPIO_BASE_BAR) | B_PCH_LPC_GPIO_BASE_EN)
);
//
// Set PMC Base Address
//
MmioWrite32 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_PMC_BASE
),
(UINT32)((PMC_BASE_ADDRESS & B_PCH_LPC_PMC_BASE_BAR) | B_PCH_LPC_PMC_BASE_EN)
);
//
// Set IO Base Address
//
MmioWrite32 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_IO_BASE
),
(UINT32)((IO_BASE_ADDRESS & B_PCH_LPC_IO_BASE_BAR) | B_PCH_LPC_IO_BASE_EN)
);
//
// Set ILB Base Address
//
MmioWrite32 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_ILB_BASE
),
(UINT32)((ILB_BASE_ADDRESS & B_PCH_LPC_ILB_BASE_BAR) | B_PCH_LPC_ILB_BASE_EN)
);
//
// Set PUnit Base Address
//
MmioWrite32 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_PUNIT_BASE
),
(UINT32)((PUNIT_BASE_ADDRESS & B_PCH_LPC_PUNIT_BASE_BAR) | B_PCH_LPC_PUNIT_BASE_EN)
);
//
// Set SPI Base Address
//
MmioWrite32 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_SPI_BASE
),
(UINT32)((SPI_BASE_ADDRESS & B_PCH_LPC_SPI_BASE_BAR) | B_PCH_LPC_SPI_BASE_EN)
);
//
// Set Root Complex Base Address
//
MmioWrite32 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_RCBA
),
(UINT32)((RCBA_BASE_ADDRESS & B_PCH_LPC_RCBA_BAR) | B_PCH_LPC_RCBA_EN)
);
//
// Set MPHY Base Address
//
MmioWrite32 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_LPC,
PCI_FUNCTION_NUMBER_PCH_LPC,
R_PCH_LPC_MPHY_BASE
),
(UINT32)((MPHY_BASE_ADDRESS & B_PCH_LPC_MPHY_BASE_BAR) | B_PCH_LPC_MPHY_BASE_EN)
);
MmioWrite16 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_SMBUS,
PCI_FUNCTION_NUMBER_PCH_SMBUS,
R_PCH_SMBUS_BASE
),
(UINT16)(SMBUS_BASE_ADDRESS & B_PCH_SMBUS_BASE_BAR)
);
MmioOr8 (
MmPciAddress (0,
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_SMBUS,
PCI_FUNCTION_NUMBER_PCH_SMBUS,
R_PCH_SMBUS_PCICMD
),
B_PCH_SMBUS_PCICMD_IOSE
);
}
/**
This is the entrypoint of PEIM
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS if it completed successfully.
**/
EFI_STATUS
EFIAPI
PeiInitPlatform (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
UINTN SmbusRegBase;
EFI_PLATFORM_INFO_HOB PlatformInfo;
EFI_STATUS Status= EFI_SUCCESS;
EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable = NULL;
UINTN VariableSize;
SYSTEM_CONFIGURATION SystemConfiguration;
UINT32 GGC = 0;
EFI_PEI_PPI_DESCRIPTOR *mVlvMmioPolicyPpiDesc;
VLV_MMIO_POLICY_PPI *mVlvMmioPolicyPpi;
ZeroMem (&PlatformInfo, sizeof(PlatformInfo));
Status = InstallMonoStatusCode(FileHandle, PeiServices);
ASSERT_EFI_ERROR (Status);
//
// Initialize Stall PPIs
//
Status = (*PeiServices)->InstallPpi (PeiServices, &mInstallStallPpi[0]);
ASSERT_EFI_ERROR (Status);
Status = (*PeiServices)->NotifyPpi (PeiServices, &mMemoryDiscoveredNotifyList[0]);
ASSERT_EFI_ERROR (Status);
SmbusRegBase = PchPciDeviceMmBase (
DEFAULT_PCI_BUS_NUMBER_PCH,
PCI_DEVICE_NUMBER_PCH_SMBUS,
PCI_FUNCTION_NUMBER_PCH_SMBUS
);
//
// Since PEI has no PCI enumerator, set the BAR & I/O space enable ourselves
//
MmioAndThenOr32 (SmbusRegBase + R_PCH_SMBUS_BASE, B_PCH_SMBUS_BASE_BAR, SMBUS_BASE_ADDRESS);
MmioOr8 (SmbusRegBase + R_PCH_SMBUS_PCICMD, B_PCH_SMBUS_PCICMD_IOSE);
PchBaseInit();
//
//Todo: confirm if we need program 8254
//
// Setting 8254
// Program timer 1 as refresh timer
//
IoWrite8 (0x43, 0x54);
IoWrite8 (0x41, 0x12);
//
// RTC power failure handling
//
RtcPowerFailureHandler (PeiServices);
PchMmPci32( 0, 0, 2, 0, 0x50) = 0x210;
VariableSize = sizeof (SYSTEM_CONFIGURATION);
ZeroMem (&SystemConfiguration, VariableSize);
//
// Obtain variable services
//
Status = (*PeiServices)->LocatePpi(
PeiServices,
&gEfiPeiReadOnlyVariable2PpiGuid,
0,
NULL,
(void **)&Variable
);
ASSERT_EFI_ERROR(Status);
Status = Variable->GetVariable (
Variable,
L"Setup",
&gEfiSetupVariableGuid,
NULL,
&VariableSize,
&SystemConfiguration
);
if (EFI_ERROR (Status) || VariableSize != sizeof(SYSTEM_CONFIGURATION)) {
//The setup variable is corrupted
VariableSize = sizeof(SYSTEM_CONFIGURATION);
Status = Variable->GetVariable(
Variable,
L"SetupRecovery",
&gEfiSetupVariableGuid,
NULL,
&VariableSize,
&SystemConfiguration
);
ASSERT_EFI_ERROR (Status);
}
if (EFI_ERROR (Status)) {
GGC = ((2 << 3) | 0x200);
PciCfg16Write(EC_BASE, 0, 2, 0, 0x50, GGC);
GGC = PciCfg16Read(EC_BASE, 0, 2, 0, 0x50);
DEBUG((EFI_D_INFO , "GGC: 0x%08x GMSsize:0x%08x\n", GGC, (GGC & (BIT7|BIT6|BIT5|BIT4|BIT3))>>3));
} else {
if (SystemConfiguration.Igd == 1 && SystemConfiguration.PrimaryVideoAdaptor != 2) {
GGC = (SystemConfiguration.IgdDvmt50PreAlloc << 3) |
(SystemConfiguration.GTTSize == GTT_SIZE_1MB ? 0x100: 0x200);
PciCfg16Write(EC_BASE, 0, 2, 0, 0x50, GGC);
GGC = PciCfg16Read(EC_BASE, 0, 2, 0, 0x50);
DEBUG((EFI_D_INFO , "GGC: 0x%08x GMSsize:0x%08x\n", GGC, (GGC & (BIT7|BIT6|BIT5|BIT4|BIT3))>>3));
}
}
//
// Initialize PlatformInfo HOB
//
Status = ReadPlatformIds(PeiServices, &PlatformInfo);
ASSERT_EFI_ERROR (Status);
//
// 0 -> Disable , 1 -> Enable
//
if(SystemConfiguration.CfioPnpSettings == 1) {
DEBUG((EFI_D_INFO, "CheckCfioPnpSettings: CFIO Pnp Settings Enabled\n"));
PlatformInfo.CfioEnabled = 1;
} else {
DEBUG((EFI_D_INFO, "CheckCfioPnpSettings: CFIO Pnp Settings Disabled\n"));
PlatformInfo.CfioEnabled = 0;
}
//
// Build HOB for PlatformInfo
//
BuildGuidDataHob (
&gEfiPlatformInfoGuid,
&PlatformInfo,
sizeof (EFI_PLATFORM_INFO_HOB)
);
#ifdef FTPM_ENABLE
Status = FtpmPolicyInit(PeiServices, &SystemConfiguration);
if (EFI_ERROR (Status)) {
DEBUG((EFI_D_ERROR, "fTPM init failed.\n"));
}
#endif
//
// Set the new boot mode for MRC
//
#ifdef NOCS_S3_SUPPORT
Status = UpdateBootMode (PeiServices);
ASSERT_EFI_ERROR (Status);
#endif
DEBUG((EFI_D_INFO, "Setup MMIO size ... \n\n"));
//
// Setup MMIO size
//
Status = (*PeiServices)->AllocatePool(
PeiServices,
sizeof (EFI_PEI_PPI_DESCRIPTOR),
(void **)&mVlvMmioPolicyPpiDesc
);
ASSERT_EFI_ERROR (Status);
Status = (*PeiServices)->AllocatePool(
PeiServices,
sizeof (VLV_MMIO_POLICY_PPI),
(void **)&mVlvMmioPolicyPpi
);
ASSERT_EFI_ERROR (Status);
(*PeiServices)->SetMem (
(VOID *)mVlvMmioPolicyPpi,
sizeof (VLV_MMIO_POLICY_PPI),
0
);
mVlvMmioPolicyPpiDesc->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
mVlvMmioPolicyPpiDesc->Guid = &gVlvMmioPolicyPpiGuid;
mVlvMmioPolicyPpiDesc->Ppi = mVlvMmioPolicyPpi;
switch (SystemConfiguration.MmioSize) {
case 0: // 768MB
mVlvMmioPolicyPpi->MmioSize = 0x300;
break;
case 1: // 1GB
mVlvMmioPolicyPpi->MmioSize = 0x400;
break;
case 2: // 1.25GB
mVlvMmioPolicyPpi->MmioSize = 0x500;
break;
case 3: // 1.5GB
mVlvMmioPolicyPpi->MmioSize = 0x600;
break;
case 4: // 2GB
mVlvMmioPolicyPpi->MmioSize = 0x800;
break;
default:
mVlvMmioPolicyPpi->MmioSize = 0x800;
break;
}
Status = (*PeiServices)->InstallPpi(
PeiServices,
mVlvMmioPolicyPpiDesc
);
ASSERT_EFI_ERROR (Status);
return Status;
}
EFI_STATUS
ReadPlatformIds (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN OUT EFI_PLATFORM_INFO_HOB *PlatformInfoHob
)
{
{
EFI_STATUS Status = EFI_SUCCESS;
UINT8 FabId = 0;
UINTN DataSize;
EFI_PLATFORM_INFO_HOB TmpHob;
EFI_PEI_READ_ONLY_VARIABLE2_PPI *PeiVar;
UINT32 CompatibleBoard = 0;
Status = (**PeiServices).LocatePpi (
PeiServices,
&gEfiPeiReadOnlyVariable2PpiGuid,
0,
NULL,
(void **)&PeiVar
);
ASSERT_EFI_ERROR (Status);
DataSize = sizeof (EFI_PLATFORM_INFO_HOB);
Status = PeiVar->GetVariable (
PeiVar,
L"PlatformInfo",
&gEfiVlv2VariableGuid,
NULL,
&DataSize,
&TmpHob
);
if (Status == EFI_SUCCESS) {
PlatformInfoHob->BoardId = TmpHob.BoardId;
PlatformInfoHob->MemCfgID = TmpHob.MemCfgID;
PlatformInfoHob->BoardRev = TmpHob.BoardRev;
PlatformInfoHob->PlatformFlavor = TmpHob.PlatformFlavor;
return Status;
}
CompatibleBoard = DetermineTurbotBoard();
if (1 == CompatibleBoard) {
PlatformInfoHob->BoardId = BOARD_ID_MINNOW2_TURBOT;
DEBUG ((EFI_D_INFO, "I'm MinnowBoard Turbot!\n"));
} else {
PlatformInfoHob->BoardId = BOARD_ID_MINNOW2;
DEBUG ((EFI_D_INFO, "I'm MinnowBoard Max!\n"));
}
PlatformInfoHob->MemCfgID = 0;
PlatformInfoHob->BoardRev = FabId + 1; // FabId = 0 means FAB1 (BoardRev = 1), FabId = 1 means FAB2 (BoardRev = 2)...
PlatformInfoHob->PlatformFlavor = FlavorMobile;
}
return EFI_SUCCESS;
}
//
// Start::Alpine Valley platform
//
/**
This routine reads SysCtl registers
@param SmbusBase SMBUS Base Address
@param SlvAddr Targeted Smbus Slave device address
@param Operation Which SMBus protocol will be used
@param Offset Offset of the register
@param Length Number of bytes
@param Buffer Buffer contains values read from registers
@retval SUCCESS as passed
@retval Others as failed
**/
EFI_STATUS
PeiSmbusExec (
UINT16 SmbusBase,
UINT8 SlvAddr,
UINT8 Operation,
UINT8 Offset,
UINT8 *Length,
UINT8 *Buffer
)
{
EFI_STATUS Status=EFI_SUCCESS;
UINT8 AuxcReg;
UINT8 SmbusOperation = 0;
UINT8 StsReg;
UINT8 SlvAddrReg;
UINT8 HostCmdReg;
UINT8 BlockCount = 0;
BOOLEAN BufferTooSmall;
UINT8 Index;
UINT8 *CallBuffer;
UINT8 RetryCount = BUS_TRIES;
//
// MrcSmbusExec supports byte and block read.
// Only allow Byte or block access
//
if (!((*Length == AV_SC_BYTE_LEN) || (*Length == AV_SC_BLOCK_LEN))) {
return EFI_INVALID_PARAMETER;
}
//
// See if its ok to use the bus based upon INUSE_STS bit.
//
Status = AcquireBus (SmbusBase);
ASSERT_EFI_ERROR(Status);
CallBuffer = Buffer;
//
//SmbStatus Bits of interest
//[6] = IUS (In Use Status)
//[4] = FAIL
//[3] = BERR (Bus Error = transaction collision)
//[2] = DERR (Device Error = Illegal Command Field, Unclaimed Cycle, Host Device Timeout, CRC Error)
//[1] = INTR (Successful completion of last command)
//[0] = HOST BUSY
//
//
// This is the main operation loop. If the operation results in a Smbus
// collision with another master on the bus, it attempts the requested
// transaction again at least BUS_TRIES attempts.
//
while (RetryCount--) {
//
// Operation Specifics (pre-execution)
//
Status = EFI_SUCCESS;
SlvAddrReg = SlvAddr;
HostCmdReg = Offset;
AuxcReg = 0;
switch (Operation) {
case SMBUS_WRITE_BYTE:
IoWrite8 (SmbusBase+R_PCH_SMBUS_HD0, CallBuffer[0]);
SmbusOperation = V_PCH_SMBUS_SMB_CMD_BYTE_DATA;
break;
case SMBUS_READ_BYTE:
SmbusOperation = V_PCH_SMBUS_SMB_CMD_BYTE_DATA;
SlvAddrReg |= B_PCH_SMBUS_RW_SEL_READ;
if (*Length < 1) {
Status = EFI_INVALID_PARAMETER;
}
*Length = 1;
break;
case SMBUS_WRITE_BLOCK:
SmbusOperation = V_PCH_SMBUS_SMB_CMD_BLOCK;
IoWrite8 (SmbusBase+R_PCH_SMBUS_HD0, *(UINT8 *) Length);
BlockCount = (UINT8) (*Length);
if ((*Length < 1) || (*Length > 32)) {
Status = EFI_INVALID_PARAMETER;
break;
}
AuxcReg |= B_PCH_SMBUS_E32B;
break;
case SMBUS_READ_BLOCK:
SmbusOperation = V_PCH_SMBUS_SMB_CMD_BLOCK;
SlvAddrReg |= B_PCH_SMBUS_RW_SEL_READ;
if ((*Length < 1) || (*Length > 32)) {
Status = EFI_INVALID_PARAMETER;
break;
}
AuxcReg |= B_PCH_SMBUS_E32B;
break;
default:
Status = EFI_INVALID_PARAMETER;
break;
}
//
// Set Auxiliary Control register
//
IoWrite8 (SmbusBase+R_PCH_SMBUS_AUXC, AuxcReg);
//
// Reset the pointer of the internal buffer
//
IoRead8 (SmbusBase+R_PCH_SMBUS_HCTL);
//
// Now that the 32 byte buffer is turned on, we can write th block data
// into it
//
if (Operation == SMBUS_WRITE_BLOCK) {
for (Index = 0; Index < BlockCount; Index++) {
//
// Write next byte
//
IoWrite8 (SmbusBase+R_PCH_SMBUS_HBD, CallBuffer[Index]);
}
}
//
// Set SMBus slave address for the device to read
//
IoWrite8(SmbusBase+R_PCH_SMBUS_TSA, SlvAddrReg);
//
//
// Set Command register for the offset to read
//
IoWrite8(SmbusBase+R_PCH_SMBUS_HCMD, HostCmdReg );
//
// Set Control Register to Set "operation command" protocol and start bit
//
IoWrite8(SmbusBase+R_PCH_SMBUS_HCTL, (UINT8) (SmbusOperation + B_PCH_SMBUS_START));
//
// Wait for IO to complete
//
do { StsReg = (UINT8) IoRead8(SmbusBase+0); } while ((StsReg & (BIT4|BIT3|BIT2|BIT1)) == 0);
if (StsReg & B_PCH_SMBUS_DERR) {
Status = EFI_DEVICE_ERROR;
break;
} else if (StsReg & B_PCH_SMBUS_BERR) {
//
// Clear the Bus Error for another try
//
Status = EFI_DEVICE_ERROR;
IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, B_PCH_SMBUS_BERR);
//
// Clear Status Registers
//
IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, B_PCH_SMBUS_HSTS_ALL);
IoWrite8(SmbusBase+R_PCH_SMBUS_AUXS, B_PCH_SMBUS_CRCE);
continue;
}
//
// successfull completion
// Operation Specifics (post-execution)
//
switch (Operation) {
case SMBUS_READ_BYTE:
CallBuffer[0] = (UINT8)(IoRead8 (SmbusBase+R_PCH_SMBUS_HD0));
break;
case SMBUS_WRITE_BLOCK:
IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, B_PCH_SMBUS_BYTE_DONE_STS);
break;
case SMBUS_READ_BLOCK:
BufferTooSmall = FALSE;
//
// Find out how many bytes will be in the block
//
BlockCount = (UINT8)(IoRead8 (SmbusBase+R_PCH_SMBUS_HD0));
if (*Length < BlockCount) {
BufferTooSmall = TRUE;
} else {
for (Index = 0; Index < BlockCount; Index++) {
//
// Read the byte
//
CallBuffer[Index] = (UINT8)IoRead8 (SmbusBase+R_PCH_SMBUS_HBD);
}
}
*Length = BlockCount;
if (BufferTooSmall) {
Status = EFI_BUFFER_TOO_SMALL;
}
break;
default:
break;
};
if ((StsReg & B_PCH_SMBUS_BERR) && (Status == EFI_SUCCESS)) {
//
// Clear the Bus Error for another try
//
Status = EFI_DEVICE_ERROR;
IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, B_PCH_SMBUS_BERR);
continue;
} else {
break;
}
}
//
// Clear Status Registers and exit
//
IoWrite8(SmbusBase+R_PCH_SMBUS_HSTS, B_PCH_SMBUS_HSTS_ALL);
IoWrite8(SmbusBase+R_PCH_SMBUS_AUXS, B_PCH_SMBUS_CRCE);
IoWrite8(SmbusBase+R_PCH_SMBUS_AUXC, 0);
return Status;
}
//
// End::Alpine Valley platform
//