diff options
Diffstat (limited to 'ReferenceCode/Haswell/Library/CpuPlatformLib')
3 files changed, 573 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLib.inf b/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLib.inf new file mode 100644 index 0000000..9a0e283 --- /dev/null +++ b/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLib.inf @@ -0,0 +1,66 @@ +## @file +# Component description file for CPU Platform Lib +# +#@copyright +# Copyright (c) 2012 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# This file contains a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +# + +[defines] +BASE_NAME = CpuPlatformLib +COMPONENT_TYPE = LIBRARY + +[sources.common] + CpuPlatformLibrary.h + CpuPlatformLibrary.c + +[sources.ia32] + +[sources.x64] + +[sources.ipf] + +[includes.common] + $(EDK_SOURCE)/Foundation/Efi + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework/Include + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT) + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include/Library + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT) + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library + +# +# EDK II Glue Library utilizes some standard headers from EDK +# + $(EFI_SOURCE) + $(EDK_SOURCE)/Foundation + $(EDK_SOURCE)/Foundation/Efi + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework + $(EDK_SOURCE)/Foundation/Framework/Include + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Include/IndustryStandard + $(EDK_SOURCE)/Foundation/Core/Dxe + $(EDK_SOURCE)/Foundation/Include/Pei + $(EDK_SOURCE)/Foundation/Library/Dxe/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include + +[libraries.common] + PchPlatformLib + EdkIIGlueBasePciLibPciExpress + +[nmake.common] diff --git a/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLibrary.c b/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLibrary.c new file mode 100644 index 0000000..043bfae --- /dev/null +++ b/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLibrary.c @@ -0,0 +1,476 @@ +/** @file + CPU Platform Lib implementation. + +@copyright + Copyright (c) 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "CpuPlatformLibrary.h" + +/** + Return CPU Family ID + + @retval CPU_FAMILY CPU Family ID +**/ +CPU_FAMILY +EFIAPI +GetCpuFamily ( + VOID + ) +{ + EFI_CPUID_REGISTER Cpuid; + /// + /// Read the CPUID information + /// + AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx); + return ((CPU_FAMILY) (Cpuid.RegEax & CPUID_FULL_FAMILY_MODEL)); +} + +/** + Return Cpu stepping type + + @retval UINT8 Cpu stepping type +**/ +CPU_STEPPING +EFIAPI +GetCpuStepping ( + VOID + ) +{ + EFI_CPUID_REGISTER Cpuid; + /// + /// Read the CPUID information + /// + AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx); + return ((CPU_STEPPING) (Cpuid.RegEax & CPUID_FULL_STEPPING)); +} + +/** + Determine if CPU is supported + + @retval TRUE CPU is supported + @retval FALSE CPU is not supported +**/ +BOOLEAN +IsCpuSupported ( + VOID + ) +{ + if (GetCpuFamily() == EnumCpuMax) { + return FALSE; + } + return TRUE; +} + +/** + Return CPU Sku + + @retval UINT8 CPU Sku +**/ +UINT8 +EFIAPI +GetCpuSku ( + VOID + ) +{ + UINT8 CpuType; + EFI_CPUID_REGISTER Cpuid; + /// + /// Read the CPUID information + /// + AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx); + switch (Cpuid.RegEax & CPUID_FULL_FAMILY_MODEL) { + case CPUID_FULL_FAMILY_MODEL_HASWELL_ULT: + CpuType = EnumCpuUlt; + break; + + case CPUID_FULL_FAMILY_MODEL_HASWELL: + case CPUID_FULL_FAMILY_MODEL_CRYSTALWELL: + CpuType = EnumCpuTrad; + break; + + default: + CpuType = EnumCpuUnknown; + DEBUG ((EFI_D_ERROR, "Unsupported CPU SKU, CpuFamilyId: 0x%08X!\n", (Cpuid.RegEax & CPUID_FULL_FAMILY_MODEL))); + ASSERT (FALSE); + break; + } + + return CpuType; +} + +EFI_STATUS +EFIAPI +MailboxWrite ( + IN UINT32 MailboxType, + IN UINT32 MailboxCommand, + IN UINT32 MailboxData, + OUT UINT32 *MailboxStatus + ) +/** + Generic Mailbox function for mailbox write commands. This function will + poll the mailbox interface for control, issue the write request, poll + for completion, and verify the write was succussful. + + @param[IN] MailboxType, + @param[IN] MailboxCommand, + @param[IN] MailboxData, + @param[OUT] *MailboxStatus + + @retval EFI_STATUS +**/ +{ + EFI_STATUS Status; + UINT64 MsrData; + UINT32 MchBar; + OC_MAILBOX_FULL OcMailboxFull; + OC_MAILBOX_FULL OcMailboxFullVerify; + PCODE_MAILBOX_FULL PcodeMailboxFull; + PCODE_MAILBOX_FULL PcodeMailboxFullVerify; + + /// + /// Poll the run/busy to ensure the interface is available + /// + Status = PollMailboxReady(MailboxType); + if (EFI_ERROR(Status)) { + return Status; + } + + DEBUG ((EFI_D_INFO, "(MAILBOX) Mailbox Write Command = %2X\n", (UINT8)MailboxCommand)); + + switch (MailboxType) + { + case MAILBOX_TYPE_PCODE: + /// + /// Copy in Mailbox data and write the PCODE mailbox DATA field + /// + PcodeMailboxFull.Interface.InterfaceData = MailboxCommand; + PcodeMailboxFull.Data = MailboxData; + MchBar = (MmioRead32 (MmPciAddress (0, 0, 0, 0, MCHBAR_OFFSET)) &~BIT0); + + MmioWrite32 ( (MchBar + PCODE_MAILBOX_DATA_OFFSET), PcodeMailboxFull.Data); + + /// + /// Set the Run/Busy bit to signal mailbox data is ready to process + /// + PcodeMailboxFull.Interface.Fields.RunBusy = 1; + MmioWrite32 ( (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET), PcodeMailboxFull.Interface.InterfaceData); + + /// + /// Poll run/busy to indicate the completion of write request + /// + PollMailboxReady(MailboxType); + + /// + /// Read the BIOS PCODE mailbox to verify write completion success. + /// Mailbox protocol requires software to read back the interface twice + /// to ensure the read results are consistent. + /// + PcodeMailboxFull.Interface.InterfaceData = MmioRead32 (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET); + PcodeMailboxFull.Data = MmioRead32 (MchBar + PCODE_MAILBOX_DATA_OFFSET); + + PchPmTimerStall(MAILBOX_READ_TIMEOUT); + + /// + /// Read twice to verify data is consitent + /// + PcodeMailboxFullVerify.Interface.InterfaceData = MmioRead32 (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET); + PcodeMailboxFullVerify.Data = MmioRead32 (MchBar + PCODE_MAILBOX_DATA_OFFSET); + + /// + /// If the data is inconsistent, we cannot trust the results + /// + if (PcodeMailboxFull.Interface.InterfaceData != PcodeMailboxFullVerify.Interface.InterfaceData) { + if (PcodeMailboxFull.Data != PcodeMailboxFullVerify.Data) { + DEBUG ((EFI_D_ERROR, "(MAILBOX) Mailbox read data is corrupted.\n")); + return EFI_INVALID_PARAMETER; + } + } + + /// + /// Copy PCODE mailbox completion code + /// + *MailboxStatus = (UINT32) PcodeMailboxFull.Interface.Fields.Command; + break; + + case MAILBOX_TYPE_OC: + /// + /// Set the Run/Busy bit to signal mailbox data is ready to process + /// + OcMailboxFull.Interface.InterfaceData = MailboxCommand; + OcMailboxFull.Data = MailboxData; + OcMailboxFull.Interface.Fields.RunBusy = 1; + CopyMem (&MsrData, &OcMailboxFull, sizeof(MsrData)); + + /// + /// Write mailbox command to OC mailbox + /// + AsmWriteMsr64 (OC_MAILBOX_MSR, MsrData); + + /// + /// Poll run/busy to indicate the completion of write request + /// + PollMailboxReady(MailboxType); + + /// + /// Read the mailbox command from OC mailbox. Read twice to ensure data. + /// + MsrData = AsmReadMsr64 (OC_MAILBOX_MSR); + CopyMem (&OcMailboxFull, &MsrData, sizeof(OcMailboxFull)); + + PchPmTimerStall(MAILBOX_READ_TIMEOUT); + + MsrData = AsmReadMsr64 (OC_MAILBOX_MSR); + CopyMem (&OcMailboxFullVerify, &MsrData, sizeof(OcMailboxFullVerify)); + + /// + /// If the data is inconsistent, we cannot trust the results + /// + if (OcMailboxFull.Interface.InterfaceData != OcMailboxFullVerify.Interface.InterfaceData) { + if (OcMailboxFull.Data != OcMailboxFullVerify.Data) { + DEBUG ((EFI_D_ERROR, "(MAILBOX) Mailbox read data is corrupted.\n")); + return EFI_INVALID_PARAMETER; + } + } + + /// + /// Copy Overclocking mailbox completion code and read results + /// + *MailboxStatus = OcMailboxFull.Interface.Fields.CommandCompletion; + break; + + default: + DEBUG ((EFI_D_ERROR, "(MAILBOX) Unrecognized Mailbox Type.\n")); + Status = EFI_UNSUPPORTED; + break; + } + + DEBUG ((EFI_D_INFO, "(MAILBOX) Mailbox Status = %2X\n", *MailboxStatus)); + return Status; +} + +EFI_STATUS +EFIAPI +MailboxRead ( + IN UINT32 MailboxType, + IN UINT32 MailboxCommand, + OUT UINT32 *MailboxDataPtr, + OUT UINT32 *MailboxStatus + ) +/** + Generic Mailbox function for mailbox read commands. This function will write + the read request, and populate the read results in the output data. + + @param[IN] MailboxType, + @param[IN] MailboxCommand, + @param[OUT] *MailboxDataPtr, + @param[OUT] *MailboxStatus + + @retval EFI_STATUS +**/ +{ + EFI_STATUS Status; + UINT64 MsrData; + UINT32 MchBar; + PCODE_MAILBOX_FULL PcodeMailboxFull; + PCODE_MAILBOX_FULL PcodeMailboxFullVerify; + OC_MAILBOX_FULL OcMailboxFull; + OC_MAILBOX_FULL OcMailboxFullVerify; + + /// + /// Poll the run/busy to ensure the interface is available + /// + Status = PollMailboxReady(MailboxType); + if (EFI_ERROR(Status)) { + return Status; + } + + DEBUG ((EFI_D_INFO, "(MAILBOX) Mailbox Read Command = %2X\n", (UINT8)MailboxCommand)); + + switch (MailboxType) + { + case MAILBOX_TYPE_PCODE: + /// + /// Write the PCODE mailbox read request. + /// Read requests only require a write to the PCODE interface mailbox. + /// The read results will be updated in the data mailbox. + /// + PcodeMailboxFull.Interface.InterfaceData = MailboxCommand; + PcodeMailboxFull.Interface.Fields.RunBusy = 1; + MchBar = (MmioRead32 (MmPciAddress (0, 0, 0, 0, MCHBAR_OFFSET)) &~BIT0); + + MmioWrite32 ( (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET), PcodeMailboxFull.Interface.InterfaceData); + + /// + /// Poll run/busy to indicate the completion of read request + /// + PollMailboxReady(MailboxType); + + /// + /// Read the BIOS PCODE mailbox to verify read completion success. + /// Mailbox protocol requires software to read back the interface twice + /// to ensure the read results are consistent. + /// + PcodeMailboxFull.Interface.InterfaceData = MmioRead32 (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET); + PcodeMailboxFull.Data = MmioRead32 (MchBar + PCODE_MAILBOX_DATA_OFFSET); + + PchPmTimerStall(MAILBOX_READ_TIMEOUT); + + /// + /// Read twice to verify data is consitent + /// + PcodeMailboxFullVerify.Interface.InterfaceData = MmioRead32 (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET); + PcodeMailboxFullVerify.Data = MmioRead32 (MchBar + PCODE_MAILBOX_DATA_OFFSET); + + /// + /// If the data is inconsistent, we cannot trust the results + /// + if (PcodeMailboxFull.Interface.InterfaceData != PcodeMailboxFullVerify.Interface.InterfaceData) { + if (PcodeMailboxFull.Data != PcodeMailboxFullVerify.Data) { + DEBUG ((EFI_D_ERROR, "(MAILBOX) Mailbox read data is corrupted.\n")); + return EFI_INVALID_PARAMETER; + } + } + + /// + /// Copy PCODE mailbox completion code and read results + /// + *MailboxStatus = (UINT32) PcodeMailboxFull.Interface.InterfaceData; + CopyMem(MailboxDataPtr, &PcodeMailboxFull.Data, sizeof(UINT32)); + break; + + case MAILBOX_TYPE_OC: + /// + /// Set the Run/Busy bit to signal mailbox data is ready to process + /// + OcMailboxFull.Interface.InterfaceData = MailboxCommand; + OcMailboxFull.Data = *MailboxDataPtr; + OcMailboxFull.Interface.Fields.RunBusy = 1; + CopyMem (&MsrData, &OcMailboxFull, sizeof(MsrData)); + + /// + /// Write mailbox command to OC mailbox + /// + AsmWriteMsr64 (OC_MAILBOX_MSR, MsrData); + + /// + /// Poll run/busy to indicate the completion of write request + /// + PollMailboxReady(MailboxType); + + /// + /// Read the OC mailbox to verify read completion success. + /// Mailbox protocol requires software to read back the interface twice + /// to ensure the read results are consistent. + /// + MsrData = AsmReadMsr64 (OC_MAILBOX_MSR); + CopyMem (&OcMailboxFull, &MsrData, sizeof(OcMailboxFull)); + + PchPmTimerStall(MAILBOX_READ_TIMEOUT); + + MsrData = AsmReadMsr64 (OC_MAILBOX_MSR); + CopyMem (&OcMailboxFullVerify, &MsrData, sizeof(OcMailboxFullVerify)); + + /// + /// If the data is inconsistent, we cannot trust the results + /// + if (OcMailboxFull.Interface.InterfaceData != OcMailboxFullVerify.Interface.InterfaceData) { + if (OcMailboxFull.Data != OcMailboxFullVerify.Data) { + DEBUG ((EFI_D_ERROR, "(MAILBOX) Mailbox read data is corrupted.\n")); + return EFI_INVALID_PARAMETER; + } + } + + /// + /// Copy Overclocking mailbox completion code and read results + /// + *MailboxStatus = OcMailboxFull.Interface.Fields.CommandCompletion; + CopyMem(MailboxDataPtr, &OcMailboxFull.Data, sizeof(UINT32)); + break; + + default: + DEBUG ((EFI_D_ERROR, "(MAILBOX) Unrecognized Mailbox Type.\n")); + Status = EFI_UNSUPPORTED; + break; + } + + DEBUG ((EFI_D_INFO, "(MAILBOX) Mailbox Status = %2X\n", *MailboxStatus)); + + return Status; +} + +/** + Poll the run/busy bit of the mailbox until available or timeout expires. + + @param[IN] MailboxType, + + @retval EFI_STATUS +**/ +EFI_STATUS +EFIAPI +PollMailboxReady ( + IN UINT32 MailboxType + ) +{ + EFI_STATUS Status; + UINT16 StallCount; + UINT8 RunBusyBit; + UINT64 MsrData; + UINT32 MchBar; + OC_MAILBOX_FULL OcMailboxFull; + PCODE_MAILBOX_INTERFACE PcodeMailboxInterface; + + Status = EFI_SUCCESS; + StallCount = 0; + RunBusyBit = 1; + + do { + switch (MailboxType) + { + case MAILBOX_TYPE_PCODE: + /// + /// Read the MMIO run/busy state + /// + MchBar = (MmioRead32 (MmPciAddress (0, 0, 0, 0, MCHBAR_OFFSET)) &~BIT0); + PcodeMailboxInterface.InterfaceData = MmioRead32 (MchBar + PCODE_MAILBOX_INTERFACE_OFFSET); + RunBusyBit = (UINT8) PcodeMailboxInterface.Fields.RunBusy; + break; + + case MAILBOX_TYPE_OC: + /// + /// Read the OC mailbox run/busy state + /// + MsrData = AsmReadMsr64(OC_MAILBOX_MSR); + CopyMem(&OcMailboxFull.Data, &MsrData, sizeof(OcMailboxFull)); + RunBusyBit = OcMailboxFull.Interface.Fields.RunBusy; + break; + } + // + // Wait for 1us + // + PchPmTimerStall(MAILBOX_WAIT_STALL); + StallCount++; + } + while ((RunBusyBit == 1) && (StallCount < MAILBOX_WAIT_TIMEOUT)); + + if ((RunBusyBit == 1) && (StallCount == MAILBOX_WAIT_TIMEOUT)) { + DEBUG ((EFI_D_ERROR, "(MAILBOX) Mailbox interface timed out.\n")); + Status = EFI_TIMEOUT; + } + return Status; +} + diff --git a/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLibrary.h b/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLibrary.h new file mode 100644 index 0000000..4d5d720 --- /dev/null +++ b/ReferenceCode/Haswell/Library/CpuPlatformLib/CpuPlatformLibrary.h @@ -0,0 +1,31 @@ +/** @file + Header file for Cpu Platform Lib implementation. + +@copyright + Copyright (c) 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement +**/ +#ifndef _CPU_PLATFORM_LIBRARY_IMPLEMENTATION_H_ +#define _CPU_PLATFORM_LIBRARY_IMPLEMENTATION_H_ + +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueBase.h" +#include "EdkIIGluePeim.h" +#include "CpuAccess.h" +#include "CpuPlatformLib.h" +#include "PchAccess.h" +#include "PchPlatformLib.h" +#endif + +#endif |