/** @file
Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
AcpiPlatform.c
Abstract:
ACPI Platform Driver
--*/
#include <PiDxe.h>
#include <Protocol/TcgService.h>
#include <Protocol/FirmwareVolume.h>
#include "AcpiPlatform.h"
#include "AcpiPlatformHooks.h"
#include "AcpiPlatformHooksLib.h"
#include "Platform.h"
#include <Hpet.h>
#include <Mcfg.h>
#include "Osfr.h"
#include <Guid/GlobalVariable.h>
#include <Guid/SetupVariable.h>
#include <Guid/PlatformInfo.h>
#include <Protocol/CpuIo.h>
#include <Guid/BoardFeatures.h>
#include <Protocol/AcpiSupport.h>
#include <Protocol/AcpiS3Save.h>
#include <Protocol/Ps2Policy.h>
#include <Library/CpuIA32.h>
#include <SetupMode.h>
#include <Guid/AcpiTableStorage.h>
#include <Guid/EfiVpdData.h>
#include <PchAccess.h>
#include <Guid/Vlv2Variable.h>
#include <Guid/PlatformCpuInfo.h>
CHAR16 EfiPlatformCpuInfoVariable[] = L"PlatformCpuInfo";
CHAR16 gACPIOSFRModelStringVariableName[] = ACPI_OSFR_MODEL_STRING_VARIABLE_NAME;
CHAR16 gACPIOSFRRefDataBlockVariableName[] = ACPI_OSFR_REF_DATA_BLOCK_VARIABLE_NAME;
CHAR16 gACPIOSFRMfgStringVariableName[] = ACPI_OSFR_MFG_STRING_VARIABLE_NAME;
EFI_CPU_IO_PROTOCOL *mCpuIo;
#ifndef __GNUC__
#pragma optimize("", off)
#endif
BOOLEAN mFirstNotify;
EFI_PLATFORM_INFO_HOB *mPlatformInfo;
EFI_GUID mSystemConfigurationGuid = SYSTEM_CONFIGURATION_GUID;
SYSTEM_CONFIGURATION mSystemConfiguration;
SYSTEM_CONFIGURATION mSystemConfig;
UINT8 mSmbusRsvdAddresses[] = PLATFORM_SMBUS_RSVD_ADDRESSES;
UINT8 mNumberSmbusAddress = sizeof( mSmbusRsvdAddresses ) / sizeof( mSmbusRsvdAddresses[0] );
/**
Locate the first instance of a protocol. If the protocol requested is an
FV protocol, then it will return the first FV that contains the ACPI table
storage file.
@param[in] Protocol The protocol to find.
@param[in] Instance Return pointer to the first instance of the protocol.
@param[in] Type The type of protocol to locate.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND The protocol could not be located.
@retval EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
**/
EFI_STATUS
LocateSupportProtocol (
IN EFI_GUID *Protocol,
OUT VOID **Instance,
IN UINT32 Type
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN NumberOfHandles;
EFI_FV_FILETYPE FileType;
UINT32 FvStatus;
EFI_FV_FILE_ATTRIBUTES Attributes;
UINTN Size;
UINTN Index;
FvStatus = 0;
//
// Locate protocol.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
Protocol,
NULL,
&NumberOfHandles,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
//
// Defined errors at this time are not found and out of resources.
//
return Status;
}
//
// Looking for FV with ACPI storage file.
//
for (Index = 0; Index < NumberOfHandles; Index++) {
//
// Get the protocol on this handle.
// This should not fail because of LocateHandleBuffer.
//
Status = gBS->HandleProtocol (
HandleBuffer[Index],
Protocol,
Instance
);
ASSERT (!EFI_ERROR (Status));
if (!Type) {
//
// Not looking for the FV protocol, so find the first instance of the
// protocol. There should not be any errors because our handle buffer
// should always contain at least one or LocateHandleBuffer would have
// returned not found.
//
break;
}
//
// See if it has the ACPI storage file.
//
Status = ((EFI_FIRMWARE_VOLUME_PROTOCOL *) (*Instance))->ReadFile (
*Instance,
&gEfiAcpiTableStorageGuid,
NULL,
&Size,
&FileType,
&Attributes,
&FvStatus
);
//
// If we found it, then we are done.
//
if (!EFI_ERROR (Status)) {
break;
}
}
//
// Our exit status is determined by the success of the previous operations.
// If the protocol was found, Instance already points to it.
//
//
// Free any allocated buffers.
//
gBS->FreePool (HandleBuffer);
return Status;
}
/**
This function will update any runtime platform specific information.
This currently includes:
Setting OEM table values, ID, table ID, creator ID and creator revision.
Enabling the proper processor entries in the APIC tables.
@param[in] Table The table to update.
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
PlatformUpdateTables (
IN OUT EFI_ACPI_COMMON_HEADER *Table
)
{
EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
UINT8 *CurrPtr;
UINT8 *EndPtr;
ACPI_APIC_STRUCTURE_PTR *ApicPtr;
UINT8 CurrProcessor;
EFI_STATUS Status;
EFI_MP_SERVICES_PROTOCOL *MpService;
UINTN MaximumNumberOfCPUs;
UINTN NumberOfEnabledCPUs;
UINTN BufferSize;
ACPI_APIC_STRUCTURE_PTR *ProcessorLocalApicEntry;
UINTN BspIndex;
EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE *AsfEntry;
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *HpetTbl;
UINT64 OemIdValue;
UINT8 Index;
EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Facp;
EFI_ACPI_OSFR_TABLE *OsfrTable;
EFI_ACPI_OSFR_OCUR_OBJECT *pOcurObject;
EFI_ACPI_OSFR_OCUR_OBJECT OcurObject = {{0xB46F133D, 0x235F, 0x4634, 0x9F, 0x03, 0xB1, 0xC0, 0x1C, 0x54, 0x78, 0x5B}, 0, 0, 0, 0, 0};
CHAR16 *OcurMfgStringBuffer = NULL;
CHAR16 *OcurModelStringBuffer = NULL;
UINT8 *OcurRefDataBlockBuffer = NULL;
UINTN OcurMfgStringBufferSize;
UINTN OcurModelStringBufferSize;
UINTN OcurRefDataBlockBufferSize;
#if defined (IDCC2_SUPPORTED) && IDCC2_SUPPORTED
EFI_ACPI_ASPT_TABLE *pSpttTable;
#endif
UINT16 NumberOfHpets;
UINT16 HpetCapIdValue;
UINT32 HpetBlockID;
UINTN LocalApicCounter;
EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;
UINT8 TempVal;
EFI_ACPI_3_0_IO_APIC_STRUCTURE *IOApicType;
EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *APICTableHeader;
CurrPtr = NULL;
EndPtr = NULL;
ApicPtr = NULL;
LocalApicCounter = 0;
CurrProcessor = 0;
ProcessorLocalApicEntry = NULL;
if (Table->Signature != EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) {
TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
//
// Update the OEMID.
//
OemIdValue = mPlatformInfo->AcpiOemId;
*(UINT32 *)(TableHeader->OemId) = (UINT32)OemIdValue;
*(UINT16 *)(TableHeader->OemId + 4) = *(UINT16*)(((UINT8 *)&OemIdValue) + 4);
if ((Table->Signature != EFI_ACPI_2_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
//
// Update the OEM Table ID.
//
TableHeader->OemTableId = mPlatformInfo->AcpiOemTableId;
}
//
// Update the OEM Table ID.
//
TableHeader->OemRevision = EFI_ACPI_OEM_REVISION;
//
// Update the creator ID.
//
TableHeader->CreatorId = EFI_ACPI_CREATOR_ID;
//
// Update the creator revision.
//
TableHeader->CreatorRevision = EFI_ACPI_CREATOR_REVISION;
}
//
// Complete this function.
//
//
// Locate the MP services protocol.
//
//
// Find the MP Protocol. This is an MP platform, so MP protocol must be
// there.
//
Status = gBS->LocateProtocol (
&gEfiMpServiceProtocolGuid,
NULL,
(VOID **) &MpService
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Determine the number of processors.
//
MpService->GetNumberOfProcessors (
MpService,
&MaximumNumberOfCPUs,
&NumberOfEnabledCPUs
);
ASSERT (MaximumNumberOfCPUs <= MAX_CPU_NUM && NumberOfEnabledCPUs >= 1);
//
// Assign a invalid intial value for update.
//
//
// Update the processors in the APIC table.
//
switch (Table->Signature) {
case EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE_SIGNATURE:
//
// Update the table if ASF is enabled. Otherwise, return error so caller will not install.
//
if (mSystemConfig.Asf == 1) {
return EFI_UNSUPPORTED;
}
AsfEntry = (EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE *) Table;
TempVal = (mNumberSmbusAddress < ASF_ADDR_DEVICE_ARRAY_LENGTH)? mNumberSmbusAddress : ASF_ADDR_DEVICE_ARRAY_LENGTH;
for (Index = 0; Index < TempVal; Index++) {
AsfEntry->AsfAddr.FixedSmbusAddresses[Index] = mSmbusRsvdAddresses[Index];
}
break;
case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
Status = MpService->WhoAmI (
MpService,
&BspIndex
);
//
// PCAT_COMPAT Set to 1 indicate 8259 vectors should be disabled.
//
APICTableHeader = (EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)Table;
APICTableHeader->Flags |= EFI_ACPI_3_0_PCAT_COMPAT;
CurrPtr = (UINT8 *) &((EFI_ACPI_DESCRIPTION_HEADER *) Table)[1];
CurrPtr = CurrPtr + 8;
//
// Size of Local APIC Address & Flag.
//
EndPtr = (UINT8 *) Table;
EndPtr = EndPtr + Table->Length;
while (CurrPtr < EndPtr) {
ApicPtr = (ACPI_APIC_STRUCTURE_PTR *) CurrPtr;
switch (ApicPtr->AcpiApicCommon.Type) {
case EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC:
//
// ESS override
// Fix for Ordering of MADT to be maintained as it is in MADT table.
//
// Update processor enabled or disabled and keep the local APIC
// order in MADT intact.
//
// Sanity check to make sure proc-id is not arbitrary.
//
DEBUG ((EFI_D_ERROR, "ApicPtr->AcpiLocalApic.AcpiProcessorId = %x, MaximumNumberOfCPUs = %x\n", \
ApicPtr->AcpiLocalApic.AcpiProcessorId, MaximumNumberOfCPUs));
if(ApicPtr->AcpiLocalApic.AcpiProcessorId > MaximumNumberOfCPUs) {
ApicPtr->AcpiLocalApic.AcpiProcessorId = (UINT8)MaximumNumberOfCPUs;
}
BufferSize = 0;
ApicPtr->AcpiLocalApic.Flags = 0;
for (CurrProcessor = 0; CurrProcessor < MaximumNumberOfCPUs; CurrProcessor++) {
Status = MpService->GetProcessorInfo (
MpService,
CurrProcessor,
&ProcessorInfoBuffer
);
if (Status == EFI_SUCCESS && ProcessorInfoBuffer.ProcessorId == ApicPtr->AcpiLocalApic.ApicId) {
//
// Check to see whether or not a processor (or thread) is enabled.
//
if ((BspIndex == CurrProcessor) || ((ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) != 0)) {
//
// Go on and check if Hyper Threading is enabled. If HT not enabled
// hide this thread from OS by not setting the flag to 1. This is the
// software way to disable Hyper Threading. Basically we just hide it
// from the OS.
//
ApicPtr->AcpiLocalApic.Flags = EFI_ACPI_1_0_LOCAL_APIC_ENABLED;
if(ProcessorInfoBuffer.Location.Thread != 0) {
ApicPtr->AcpiLocalApic.Flags = 0;
}
AppendCpuMapTableEntry (&(ApicPtr->AcpiLocalApic));
}
break;
}
}
//
// If no APIC-ID match, the cpu may not be populated.
//
break;
case EFI_ACPI_3_0_IO_APIC:
IOApicType = (EFI_ACPI_3_0_IO_APIC_STRUCTURE *)CurrPtr;
IOApicType->IoApicId = 0x02;
//
// IO APIC entries can be patched here.
//
break;
}
CurrPtr = CurrPtr + ApicPtr->AcpiApicCommon.Length;
}
break;
case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
Facp = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) Table;
Facp->Flags &= (UINT32)(~(3<<2));
break;
case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
//
// Patch the memory resource.
//
PatchDsdtTable ((EFI_ACPI_DESCRIPTION_HEADER *) Table);
break;
case EFI_ACPI_3_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
//
// Gv3 support
//
// TBD: Need re-design based on the ValleyTrail platform.
//
break;
case EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
//
// Adjust HPET Table to correct the Base Address.
//
// Enable HPET always as Hpet.asi always indicates that Hpet is enabled.
//
MmioOr8 (R_PCH_PCH_HPET + R_PCH_PCH_HPET_GCFG, B_PCH_PCH_HPET_GCFG_EN);
HpetTbl = (EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *) Table;
HpetTbl->BaseAddressLower32Bit.Address = HPET_BASE_ADDRESS;
HpetTbl->EventTimerBlockId = *((UINT32*)(UINTN)HPET_BASE_ADDRESS);
HpetCapIdValue = *(UINT16 *)(UINTN)(HPET_BASE_ADDRESS);
NumberOfHpets = HpetCapIdValue & B_PCH_PCH_HPET_GCID_NT; // Bits [8:12] contains the number of Hpets
HpetBlockID = EFI_ACPI_EVENT_TIMER_BLOCK_ID;
if((NumberOfHpets) && (NumberOfHpets & B_PCH_PCH_HPET_GCID_NT)) {
HpetBlockID |= (NumberOfHpets);
}
HpetTbl->EventTimerBlockId = HpetBlockID;
break;
case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:
//
// Update MCFG base and end bus number.
//
((EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *) Table)->Segment[0].BaseAddress
= mPlatformInfo->PciData.PciExpressBase;
((EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *) Table)->Segment[0].EndBusNumber
= (UINT8)RShiftU64 (mPlatformInfo->PciData.PciExpressSize, 20) - 1;
break;
case EFI_ACPI_OSFR_TABLE_SIGNATURE:
//
// Get size of OSFR variable.
//
OcurMfgStringBufferSize = 0;
Status = gRT->GetVariable (
gACPIOSFRMfgStringVariableName,
&gACPIOSFRMfgStringVariableGuid,
NULL,
&OcurMfgStringBufferSize,
NULL
);
if (Status != EFI_BUFFER_TOO_SMALL) {
//
// Variable must not be present on the system.
//
return EFI_UNSUPPORTED;
}
//
// Allocate memory for variable data.
//
OcurMfgStringBuffer = AllocatePool (OcurMfgStringBufferSize);
Status = gRT->GetVariable (
gACPIOSFRMfgStringVariableName,
&gACPIOSFRMfgStringVariableGuid,
NULL,
&OcurMfgStringBufferSize,
OcurMfgStringBuffer
);
if (!EFI_ERROR (Status)) {
OcurModelStringBufferSize = 0;
Status = gRT->GetVariable (
gACPIOSFRModelStringVariableName,
&gACPIOSFRModelStringVariableGuid,
NULL,
&OcurModelStringBufferSize,
NULL
);
if (Status != EFI_BUFFER_TOO_SMALL) {
//
// Variable must not be present on the system.
//
return EFI_UNSUPPORTED;
}
//
// Allocate memory for variable data.
//
OcurModelStringBuffer = AllocatePool (OcurModelStringBufferSize);
Status = gRT->GetVariable (
gACPIOSFRModelStringVariableName,
&gACPIOSFRModelStringVariableGuid,
NULL,
&OcurModelStringBufferSize,
OcurModelStringBuffer
);
if (!EFI_ERROR (Status)) {
OcurRefDataBlockBufferSize = 0;
Status = gRT->GetVariable (
gACPIOSFRRefDataBlockVariableName,
&gACPIOSFRRefDataBlockVariableGuid,
NULL,
&OcurRefDataBlockBufferSize,
NULL
);
if (Status == EFI_BUFFER_TOO_SMALL) {
//
// Allocate memory for variable data.
//
OcurRefDataBlockBuffer = AllocatePool (OcurRefDataBlockBufferSize);
Status = gRT->GetVariable (
gACPIOSFRRefDataBlockVariableName,
&gACPIOSFRRefDataBlockVariableGuid,
NULL,
&OcurRefDataBlockBufferSize,
OcurRefDataBlockBuffer
);
}
OsfrTable = (EFI_ACPI_OSFR_TABLE *) Table;
//
// Currently only one object is defined: OCUR_OSFR_TABLE.
//
OsfrTable->ObjectCount = 1;
//
// Initialize table length to fixed portion of the ACPI OSFR table.
//
OsfrTable->Header.Length = sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION);
*(UINT32 *)((UINTN) OsfrTable + sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION)) = \
(UINT32) (sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION) + sizeof (UINT32));
pOcurObject = (EFI_ACPI_OSFR_OCUR_OBJECT *)((UINTN) OsfrTable + sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION) + \
sizeof (UINT32));
CopyMem (pOcurObject, &OcurObject, sizeof (EFI_ACPI_OSFR_OCUR_OBJECT));
pOcurObject->ManufacturerNameStringOffset = (UINT32)((UINTN) pOcurObject - (UINTN) OsfrTable + \
sizeof (EFI_ACPI_OSFR_OCUR_OBJECT));
pOcurObject->ModelNameStringOffset = (UINT32)((UINTN) pOcurObject - (UINTN) OsfrTable + \
sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize);
if (OcurRefDataBlockBufferSize > 0) {
pOcurObject->MicrosoftReferenceOffset = (UINT32)((UINTN) pOcurObject - (UINTN) OsfrTable + \
sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize + OcurModelStringBufferSize);
}
CopyMem ((UINTN *)((UINTN) pOcurObject + sizeof (EFI_ACPI_OSFR_OCUR_OBJECT)), OcurMfgStringBuffer, \
OcurMfgStringBufferSize);
CopyMem ((UINTN *)((UINTN) pOcurObject + sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize), \
OcurModelStringBuffer, OcurModelStringBufferSize);
if (OcurRefDataBlockBufferSize > 0) {
CopyMem ((UINTN *)((UINTN) pOcurObject + sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize + \
OcurModelStringBufferSize),OcurRefDataBlockBuffer, OcurRefDataBlockBufferSize);
}
OsfrTable->Header.Length += (UINT32)(OcurMfgStringBufferSize + OcurModelStringBufferSize + OcurRefDataBlockBufferSize);
OsfrTable->Header.Length += sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + sizeof (UINT32);
}
}
gBS->FreePool (OcurMfgStringBuffer);
gBS->FreePool (OcurModelStringBuffer);
gBS->FreePool (OcurRefDataBlockBuffer);
break;
default:
break;
}
//
//
// Update the hardware signature in the FACS structure.
//
//
// Locate the SPCR table and update based on current settings.
// The user may change CR settings via setup or other methods.
// The SPCR table must match.
//
return EFI_SUCCESS;
}
/**
Routine Description:
GC_TODO: Add function description.
Arguments:
Event - GC_TODO: add argument description
Context - GC_TODO: add argument description
Returns:
GC_TODO: add return values
**/
STATIC
VOID
EFIAPI
OnReadyToBoot (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_ACPI_TABLE_VERSION TableVersion;
EFI_ACPI_SUPPORT_PROTOCOL *AcpiSupport;
EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
SYSTEM_CONFIGURATION SetupVarBuffer;
UINTN VariableSize;
EFI_PLATFORM_CPU_INFO *PlatformCpuInfoPtr = NULL;
EFI_PLATFORM_CPU_INFO PlatformCpuInfo;
EFI_PEI_HOB_POINTERS GuidHob;
if (mFirstNotify) {
return;
}
mFirstNotify = TRUE;
//
// To avoid compiler warning of "C4701: potentially uninitialized local variable 'PlatformCpuInfo' used".
//
PlatformCpuInfo.CpuVersion.FullCpuId = 0;
//
// Get Platform CPU Info HOB.
//
PlatformCpuInfoPtr = NULL;
ZeroMem (&PlatformCpuInfo, sizeof(EFI_PLATFORM_CPU_INFO));
VariableSize = sizeof(EFI_PLATFORM_CPU_INFO);
Status = gRT->GetVariable(
EfiPlatformCpuInfoVariable,
&gEfiVlv2VariableGuid,
NULL,
&VariableSize,
PlatformCpuInfoPtr
);
if (EFI_ERROR(Status)) {
GuidHob.Raw = GetHobList ();
if (GuidHob.Raw != NULL) {
if ((GuidHob.Raw = GetNextGuidHob (&gEfiPlatformCpuInfoGuid, GuidHob.Raw)) != NULL) {
PlatformCpuInfoPtr = GET_GUID_HOB_DATA (GuidHob.Guid);
}
}
}
if ((PlatformCpuInfoPtr != NULL)) {
CopyMem(&PlatformCpuInfo, PlatformCpuInfoPtr, sizeof(EFI_PLATFORM_CPU_INFO));
}
//
// Update the ACPI parameter blocks finally.
//
VariableSize = sizeof (SYSTEM_CONFIGURATION);
Status = gRT->GetVariable (
L"Setup",
&mSystemConfigurationGuid,
NULL,
&VariableSize,
&SetupVarBuffer
);
if (EFI_ERROR (Status) || VariableSize != sizeof(SYSTEM_CONFIGURATION)) {
//The setup variable is corrupted
VariableSize = sizeof(SYSTEM_CONFIGURATION);
Status = gRT->GetVariable(
L"SetupRecovery",
&mSystemConfigurationGuid,
NULL,
&VariableSize,
&SetupVarBuffer
);
ASSERT_EFI_ERROR (Status);
}
//
// Find the AcpiSupport protocol.
//
Status = LocateSupportProtocol (&gEfiAcpiSupportProtocolGuid, (VOID **) &AcpiSupport, 0);
ASSERT_EFI_ERROR (Status);
TableVersion = EFI_ACPI_TABLE_VERSION_2_0;
//
// Publish ACPI 1.0 or 2.0 Tables.
//
Status = AcpiSupport->PublishTables (
AcpiSupport,
TableVersion
);
ASSERT_EFI_ERROR (Status);
//
// S3 script save.
//
Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
if (!EFI_ERROR (Status)) {
AcpiS3Save->S3Save (AcpiS3Save, NULL);
}
}
VOID
PR1FSASetting (
IN VOID
)
{
//
// for FSA on PR1.
//
if (mPlatformInfo->BoardId == BOARD_ID_BL_FFRD && mPlatformInfo->BoardRev >= PR1) {
DEBUG((EFI_D_ERROR, "Set FSA status = 1 for FFRD PR1\n"));
mGlobalNvsArea.Area->FsaStatus = mSystemConfiguration.PchFSAOn;
}
if (mPlatformInfo->BoardId == BOARD_ID_BL_FFRD8) {
DEBUG((EFI_D_ERROR, "Set FSA status = 1 for FFRD8\n"));
mGlobalNvsArea.Area->FsaStatus = mSystemConfiguration.PchFSAOn;
}
}
/**
Entry point for Acpi platform driver.
@param[in] ImageHandle A handle for the image that is initializing this driver.
@param[in] SystemTable A pointer to the EFI system table.
@retval EFI_SUCCESS Driver initialized successfully.
@retval EFI_LOAD_ERROR Failed to Initialize or has been loaded.
@retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
**/
EFI_STATUS
EFIAPI
AcpiPlatformEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_STATUS AcpiStatus;
EFI_ACPI_SUPPORT_PROTOCOL *AcpiSupport;
EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
INTN Instance;
EFI_ACPI_COMMON_HEADER *CurrentTable;
UINTN TableHandle;
UINT32 FvStatus;
UINT32 Size;
EFI_EVENT Event;
EFI_ACPI_TABLE_VERSION TableVersion;
UINTN VarSize;
UINTN SysCfgSize;
EFI_HANDLE Handle;
EFI_PS2_POLICY_PROTOCOL *Ps2Policy;
EFI_PEI_HOB_POINTERS GuidHob;
UINT8 PortData;
EFI_MP_SERVICES_PROTOCOL *MpService;
UINTN MaximumNumberOfCPUs;
UINTN NumberOfEnabledCPUs;
UINT32 Data32;
PCH_STEPPING pchStepping;
mFirstNotify = FALSE;
TableVersion = EFI_ACPI_TABLE_VERSION_2_0;
Instance = 0;
CurrentTable = NULL;
TableHandle = 0;
Data32 = 0;
//
// Update HOB variable for PCI resource information.
// Get the HOB list. If it is not present, then ASSERT.
//
GuidHob.Raw = GetHobList ();
if (GuidHob.Raw != NULL) {
if ((GuidHob.Raw = GetNextGuidHob (&gEfiPlatformInfoGuid, GuidHob.Raw)) != NULL) {
mPlatformInfo = GET_GUID_HOB_DATA (GuidHob.Guid);
}
}
//
// Search for the Memory Configuration GUID HOB. If it is not present, then
// there's nothing we can do. It may not exist on the update path.
//
VarSize = sizeof(SYSTEM_CONFIGURATION);
Status = gRT->GetVariable(
L"Setup",
&mSystemConfigurationGuid,
NULL,
&VarSize,
&mSystemConfiguration
);
if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
//The setup variable is corrupted
VarSize = sizeof(SYSTEM_CONFIGURATION);
Status = gRT->GetVariable(
L"SetupRecovery",
&mSystemConfigurationGuid,
NULL,
&VarSize,
&mSystemConfiguration
);
ASSERT_EFI_ERROR (Status);
}
//
// Find the AcpiSupport protocol.
//
Status = LocateSupportProtocol (&gEfiAcpiSupportProtocolGuid, (VOID **) &AcpiSupport, 0);
ASSERT_EFI_ERROR (Status);
//
// Locate the firmware volume protocol.
//
Status = LocateSupportProtocol (&gEfiFirmwareVolumeProtocolGuid, (VOID **) &FwVol, 1);
ASSERT_EFI_ERROR (Status);
//
// Read the current system configuration variable store.
//
SysCfgSize = sizeof(SYSTEM_CONFIGURATION);
Status = gRT->GetVariable (
L"Setup",
&gEfiNormalSetupGuid,
NULL,
&SysCfgSize,
&mSystemConfig
);
if (EFI_ERROR (Status) || SysCfgSize != sizeof(SYSTEM_CONFIGURATION)) {
//The setup variable is corrupted
SysCfgSize = sizeof(SYSTEM_CONFIGURATION);
Status = gRT->GetVariable(
L"SetupRecovery",
&gEfiNormalSetupGuid,
NULL,
&SysCfgSize,
&mSystemConfig
);
ASSERT_EFI_ERROR (Status);
}
Status = EFI_SUCCESS;
Instance = 0;
//
// TBD: Need re-design based on the ValleyTrail platform.
//
Status = gBS->LocateProtocol (
&gEfiMpServiceProtocolGuid,
NULL,
(VOID **) &MpService
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Determine the number of processors.
//
MpService->GetNumberOfProcessors (
MpService,
&MaximumNumberOfCPUs,
&NumberOfEnabledCPUs
);
//
// Allocate and initialize the NVS area for SMM and ASL communication.
//
Status = gBS->AllocatePool (
EfiACPIMemoryNVS,
sizeof (EFI_GLOBAL_NVS_AREA),
(void **)&mGlobalNvsArea.Area
);
ASSERT_EFI_ERROR (Status);
gBS->SetMem (
mGlobalNvsArea.Area,
sizeof (EFI_GLOBAL_NVS_AREA),
0
);
DEBUG((EFI_D_ERROR, "mGlobalNvsArea.Area is at 0x%X\n", mGlobalNvsArea.Area));
//
// Update global NVS area for ASL and SMM init code to use.
//
mGlobalNvsArea.Area->ApicEnable = 1;
mGlobalNvsArea.Area->EmaEnable = 0;
mGlobalNvsArea.Area->NumberOfBatteries = 1;
mGlobalNvsArea.Area->BatteryCapacity0 = 100;
mGlobalNvsArea.Area->BatteryStatus0 = 84;
mGlobalNvsArea.Area->OnboardCom = 1;
mGlobalNvsArea.Area->IdeMode = 0;
mGlobalNvsArea.Area->PowerState = 0;
mGlobalNvsArea.Area->LogicalProcessorCount = (UINT8)NumberOfEnabledCPUs;
mGlobalNvsArea.Area->PassiveThermalTripPoint = mSystemConfiguration.PassiveThermalTripPoint;
mGlobalNvsArea.Area->PassiveTc1Value = mSystemConfiguration.PassiveTc1Value;
mGlobalNvsArea.Area->PassiveTc2Value = mSystemConfiguration.PassiveTc2Value;
mGlobalNvsArea.Area->PassiveTspValue = mSystemConfiguration.PassiveTspValue;
mGlobalNvsArea.Area->CriticalThermalTripPoint = mSystemConfiguration.CriticalThermalTripPoint;
mGlobalNvsArea.Area->IgdPanelType = mSystemConfiguration.IgdFlatPanel;
mGlobalNvsArea.Area->IgdPanelScaling = mSystemConfiguration.PanelScaling;
mGlobalNvsArea.Area->IgdSciSmiMode = 0;
mGlobalNvsArea.Area->IgdTvFormat = 0;
mGlobalNvsArea.Area->IgdTvMinor = 0;
mGlobalNvsArea.Area->IgdSscConfig = 1;
mGlobalNvsArea.Area->IgdBiaConfig = mSystemConfiguration.IgdLcdIBia;
mGlobalNvsArea.Area->IgdBlcConfig = mSystemConfiguration.IgdLcdIGmchBlc;
mGlobalNvsArea.Area->IgdDvmtMemSize = mSystemConfiguration.IgdDvmt50TotalAlloc;
mGlobalNvsArea.Area->IgdPAVP = mSystemConfiguration.PavpMode;
mGlobalNvsArea.Area->AlsEnable = mSystemConfiguration.AlsEnable;
mGlobalNvsArea.Area->BacklightControlSupport = 2;
mGlobalNvsArea.Area->BrightnessPercentage = 100;
mGlobalNvsArea.Area->IgdState = 1;
mGlobalNvsArea.Area->LidState = 1;
mGlobalNvsArea.Area->DeviceId1 = 0x80000100 ;
mGlobalNvsArea.Area->DeviceId2 = 0x80000400 ;
mGlobalNvsArea.Area->DeviceId3 = 0x80000200 ;
mGlobalNvsArea.Area->DeviceId4 = 0x04;
mGlobalNvsArea.Area->DeviceId5 = 0x05;
mGlobalNvsArea.Area->NumberOfValidDeviceId = 4 ;
mGlobalNvsArea.Area->CurrentDeviceList = 0x0F ;
mGlobalNvsArea.Area->PreviousDeviceList = 0x0F ;
mGlobalNvsArea.Area->UartSelection = mSystemConfiguration.UartInterface;
mGlobalNvsArea.Area->PcuUart1Enable = mSystemConfiguration.PcuUart1;
mGlobalNvsArea.Area->NativePCIESupport = 1;
mGlobalNvsArea.Area->RtcBattery = mSystemConfiguration.RtcBattery;
//
// Update BootMode: 0:ACPI mode; 1:PCI mode
//
mGlobalNvsArea.Area->LpssSccMode = mSystemConfiguration.LpssPciModeEnabled;
if (mSystemConfiguration.LpssMipiHsi == 0) {
mGlobalNvsArea.Area->MipiHsiAddr = 0;
mGlobalNvsArea.Area->MipiHsiLen = 0;
mGlobalNvsArea.Area->MipiHsi1Addr = 0;
mGlobalNvsArea.Area->MipiHsi1Len = 0;
}
//
// Platform Flavor
//
mGlobalNvsArea.Area->PlatformFlavor = mPlatformInfo->PlatformFlavor;
//
// Update the Platform id
//
mGlobalNvsArea.Area->BoardID = mPlatformInfo->BoardId;
//
// Update the Board Revision
//
mGlobalNvsArea.Area->FabID = mPlatformInfo->BoardRev;
//
// Update SOC Stepping
//
mGlobalNvsArea.Area->SocStepping = (UINT8)(PchStepping());
mGlobalNvsArea.Area->OtgMode = mSystemConfiguration.PchUsbOtg;
pchStepping = PchStepping();
if (mSystemConfiguration.UsbAutoMode == 1) {
//
// Auto mode is enabled.
//
if (PchA0 == pchStepping) {
//
// For A0, EHCI is enabled as default.
//
mSystemConfiguration.PchUsb20 = 1;
mSystemConfiguration.PchUsb30Mode = 0;
mSystemConfiguration.UsbXhciSupport = 0;
DEBUG ((EFI_D_INFO, "EHCI is enabled as default. SOC 0x%x\n", pchStepping));
} else {
//
// For A1 and later, XHCI is enabled as default.
//
mSystemConfiguration.PchUsb20 = 0;
mSystemConfiguration.PchUsb30Mode = 1;
mSystemConfiguration.UsbXhciSupport = 1;
DEBUG ((EFI_D_INFO, "XHCI is enabled as default. SOC 0x%x\n", pchStepping));
}
}
mGlobalNvsArea.Area->XhciMode = mSystemConfiguration.PchUsb30Mode;
mGlobalNvsArea.Area->Stepping = mPlatformInfo->IchRevision;
//
// Override invalid Pre-Boot Driver and XhciMode combination.
//
if ((mSystemConfiguration.UsbXhciSupport == 0) && (mSystemConfiguration.PchUsb30Mode == 3)) {
mGlobalNvsArea.Area->XhciMode = 2;
}
if ((mSystemConfiguration.UsbXhciSupport == 1) && (mSystemConfiguration.PchUsb30Mode == 2)) {
mGlobalNvsArea.Area->XhciMode = 3;
}
DEBUG ((EFI_D_ERROR, "ACPI NVS XHCI:0x%x\n", mGlobalNvsArea.Area->XhciMode));
mGlobalNvsArea.Area->PmicEnable = GLOBAL_NVS_DEVICE_DISABLE;
mGlobalNvsArea.Area->BatteryChargingSolution = GLOBAL_NVS_DEVICE_DISABLE;
mGlobalNvsArea.Area->ISPDevSel = mSystemConfiguration.ISPDevSel;
mGlobalNvsArea.Area->LpeEnable = mSystemConfiguration.Lpe;
if (mSystemConfiguration.ISPEn == 0) {
mGlobalNvsArea.Area->ISPDevSel = GLOBAL_NVS_DEVICE_DISABLE;
}
mGlobalNvsArea.Area->WittEnable = mSystemConfiguration.WittEnable;
mGlobalNvsArea.Area->UtsEnable = mSystemConfiguration.UtsEnable;
mGlobalNvsArea.Area->SarEnable = mSystemConfiguration.SAR1;
mGlobalNvsArea.Area->ReservedO = 1;
SettingI2CTouchAddress();
mGlobalNvsArea.Area->IdleReserve= mSystemConfiguration.IdleReserve;
//
// Read BMBOUND and store it in GlobalNVS to pass into ASL.
//
// BUGBUG: code was moved into silicon reference code.
//
if (mSystemConfiguration.eMMCBootMode== 1) {
//
// Auto detect mode.
//
DEBUG ((EFI_D_ERROR, "Auto detect mode------------start\n"));
//
// Silicon Steppings.
//
switch (PchStepping()) {
case PchA0: // A0/A1
case PchA1:
DEBUG ((EFI_D_ERROR, "SOC A0/A1: eMMC 4.41 Configuration\n"));
mSystemConfiguration.LpsseMMCEnabled = 1;
mSystemConfiguration.LpsseMMC45Enabled = 0;
break;
case PchB0: // B0 and later.
default:
DEBUG ((EFI_D_ERROR, "SOC B0 and later: eMMC 4.5 Configuration\n"));
mSystemConfiguration.LpsseMMCEnabled = 0;
mSystemConfiguration.LpsseMMC45Enabled = 1;
break;
}
} else if (mSystemConfiguration.eMMCBootMode == 2) {
//
// eMMC 4.41
//
DEBUG ((EFI_D_ERROR, "Force to eMMC 4.41 Configuration\n"));
mSystemConfiguration.LpsseMMCEnabled = 1;
mSystemConfiguration.LpsseMMC45Enabled = 0;
} else if (mSystemConfiguration.eMMCBootMode == 3) {
//
// eMMC 4.5
//
DEBUG ((EFI_D_ERROR, "Force to eMMC 4.5 Configuration\n"));
mSystemConfiguration.LpsseMMCEnabled = 0;
mSystemConfiguration.LpsseMMC45Enabled = 1;
} else {
//
// Disable eMMC controllers.
//
DEBUG ((EFI_D_ERROR, "Disable eMMC controllers\n"));
mSystemConfiguration.LpsseMMCEnabled = 0;
mSystemConfiguration.LpsseMMC45Enabled = 0;
}
mGlobalNvsArea.Area->emmcVersion = 0;
if (mSystemConfiguration.LpsseMMCEnabled) {
DEBUG ((EFI_D_ERROR, "mGlobalNvsArea.Area->emmcVersion = 0\n"));
mGlobalNvsArea.Area->emmcVersion = 0;
}
if (mSystemConfiguration.LpsseMMC45Enabled) {
DEBUG ((EFI_D_ERROR, "mGlobalNvsArea.Area->emmcVersion = 1\n"));
mGlobalNvsArea.Area->emmcVersion = 1;
}
mGlobalNvsArea.Area->SdCardRemovable = mSystemConfiguration.SdCardRemovable;
//
// Microsoft IOT
//
if ((mSystemConfiguration.LpssHsuart0FlowControlEnabled == 1) && \
(mSystemConfiguration.LpssPwm0Enabled == 0) && \
(mSystemConfiguration.LpssPwm1Enabled == 0)) {
mGlobalNvsArea.Area->MicrosoftIoT = GLOBAL_NVS_DEVICE_ENABLE;
DEBUG ((EFI_D_ERROR, "JP1 is set to be MSFT IOT configuration.\n"));
} else {
mGlobalNvsArea.Area->MicrosoftIoT = GLOBAL_NVS_DEVICE_DISABLE;
DEBUG ((EFI_D_ERROR, "JP1 is not set to be MSFT IOT configuration.\n"));
}
//
// SIO related option.
//
Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, (void **)&mCpuIo);
ASSERT_EFI_ERROR (Status);
mGlobalNvsArea.Area->WPCN381U = GLOBAL_NVS_DEVICE_DISABLE;
mGlobalNvsArea.Area->DockedSioPresent = GLOBAL_NVS_DEVICE_DISABLE;
if (mGlobalNvsArea.Area->DockedSioPresent != GLOBAL_NVS_DEVICE_ENABLE) {
//
// Check ID for SIO WPCN381U.
//
Status = mCpuIo->Io.Read (
mCpuIo,
EfiCpuIoWidthUint8,
WPCN381U_CONFIG_INDEX,
1,
&PortData
);
ASSERT_EFI_ERROR (Status);
if (PortData != 0xFF) {
PortData = 0x20;
Status = mCpuIo->Io.Write (
mCpuIo,
EfiCpuIoWidthUint8,
WPCN381U_CONFIG_INDEX,
1,
&PortData
);
ASSERT_EFI_ERROR (Status);
Status = mCpuIo->Io.Read (
mCpuIo,
EfiCpuIoWidthUint8,
WPCN381U_CONFIG_DATA,
1,
&PortData
);
ASSERT_EFI_ERROR (Status);
if ((PortData == WPCN381U_CHIP_ID) || (PortData == WDCP376_CHIP_ID)) {
mGlobalNvsArea.Area->WPCN381U = GLOBAL_NVS_DEVICE_ENABLE;
mGlobalNvsArea.Area->OnboardCom = GLOBAL_NVS_DEVICE_ENABLE;
mGlobalNvsArea.Area->OnboardComCir = GLOBAL_NVS_DEVICE_DISABLE;
}
}
}
//
// Get Ps2 policy to set. Will be use if present.
//
Status = gBS->LocateProtocol (
&gEfiPs2PolicyProtocolGuid,
NULL,
(VOID **)&Ps2Policy
);
if (!EFI_ERROR (Status)) {
Status = Ps2Policy->Ps2InitHardware (ImageHandle);
}
mGlobalNvsArea.Area->SDIOMode = mSystemConfiguration.LpssSdioMode;
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiGlobalNvsAreaProtocolGuid,
&mGlobalNvsArea,
NULL
);
//
// Read tables from the storage file.
//
while (!EFI_ERROR (Status)) {
CurrentTable = NULL;
Status = FwVol->ReadSection (
FwVol,
&gEfiAcpiTableStorageGuid,
EFI_SECTION_RAW,
Instance,
(VOID **) &CurrentTable,
(UINTN *) &Size,
&FvStatus
);
if (!EFI_ERROR (Status)) {
//
// Allow platform specific code to reject the table or update it.
//
AcpiStatus = AcpiPlatformHooksIsActiveTable (CurrentTable);
if (!EFI_ERROR (AcpiStatus)) {
//
// Perform any table specific updates.
//
AcpiStatus = PlatformUpdateTables (CurrentTable);
if (!EFI_ERROR (AcpiStatus)) {
//
// Add the table.
//
TableHandle = 0;
AcpiStatus = AcpiSupport->SetAcpiTable (
AcpiSupport,
CurrentTable,
TRUE,
TableVersion,
&TableHandle
);
ASSERT_EFI_ERROR (AcpiStatus);
}
}
//
// Increment the instance.
//
Instance++;
}
}
Status = EfiCreateEventReadyToBootEx (
TPL_NOTIFY,
OnReadyToBoot,
NULL,
&Event
);
//
// Finished.
//
return EFI_SUCCESS;
}
UINT8
ReadCmosBank1Byte (
IN UINT8 Index
)
{
UINT8 Data;
IoWrite8(0x72, Index);
Data = IoRead8 (0x73);
return Data;
}
VOID
WriteCmosBank1Byte (
IN UINT8 Index,
IN UINT8 Data
)
{
IoWrite8 (0x72, Index);
IoWrite8 (0x73, Data);
}
VOID
SettingI2CTouchAddress (
IN VOID
)
{
if (mSystemConfiguration.I2CTouchAd == 0) {
//
// If setup menu select auto set I2C Touch Address base on board id.
//
if (mPlatformInfo->BoardId == BOARD_ID_BL_RVP ||
mPlatformInfo->BoardId == BOARD_ID_BL_STHI ||
mPlatformInfo->BoardId == BOARD_ID_BL_RVP_DDR3L ) {
//
//RVP
//
mGlobalNvsArea.Area->I2CTouchAddress = 0x4B;
} else if (mPlatformInfo->BoardId == BOARD_ID_BL_FFRD) {
//
//FFRD
//
mGlobalNvsArea.Area->I2CTouchAddress = 0x4A;
} else if (mPlatformInfo->BoardId == BOARD_ID_BB_RVP) {
mGlobalNvsArea.Area->I2CTouchAddress = 0x4C;
} else if (mPlatformInfo->BoardId == BOARD_ID_CVH) {
mGlobalNvsArea.Area->I2CTouchAddress = 0x4C;
} else if (mPlatformInfo->BoardId == BOARD_ID_BL_FFRD8) {
//
//FFRD8 uses 0x4A.
//
mGlobalNvsArea.Area->I2CTouchAddress = 0x4A;
}
} else {
mGlobalNvsArea.Area->I2CTouchAddress = mSystemConfiguration.I2CTouchAd;
}
DEBUG((EFI_D_ERROR, "GlobalNvsArea.Area->I2CTouchAddress: [%02x]\n", mGlobalNvsArea.Area->I2CTouchAddress));
}