summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/SaInit
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/SaInit')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c849
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.h66
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.c368
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.h76
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.c483
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.h224
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.c1371
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.h43
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaFvi.c105
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.c842
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.dxs65
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.h194
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.inf137
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.cif30
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.mak86
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.sdl24
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.c958
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.h267
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.c934
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.h70
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.c1094
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.h132
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.c955
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.h281
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c929
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.h219
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c2987
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.h452
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.c628
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.h425
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingEqSettings.c166
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingErrorCount.c195
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingLinkRecovery.c721
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingMargining.c223
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c657
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.c450
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.h94
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.c689
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.cif30
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.dxs49
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.h260
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.inf132
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.mak72
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.sdl39
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.c189
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.h56
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.c288
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.h93
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.c204
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.cif13
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.dxs45
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.h39
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.inf97
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.mak96
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.sdl26
55 files changed, 20217 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c
new file mode 100644
index 0000000..a55603a
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c
@@ -0,0 +1,849 @@
+/** @file
+ This is the driver that initializes the CPU Audio device.
+
+@copyright
+ Copyright (c) 1999 - 2013 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 "AudioInit.h"
+
+extern SYSTEM_AGENT_GLOBAL_NVS_AREA_PROTOCOL mSaGlobalNvsAreaProtocol;
+
+///
+/// Global variables
+///
+UINT32 *mVerbCodecSaveAddress = NULL;
+UINT8 mVerbCount = 0;
+
+UINT32 mSaHdaVerbTableDataDefault[] = {
+ ///
+ /// Audio Verb Table - 0x80862807
+ ///
+ ///
+ /// Pin Widget 5 - PORT B
+ ///
+ 0x00571C10,
+ 0x00571D00,
+ 0x00571E56,
+ 0x00571F18,
+ ///
+ /// Pin Widget 6 - PORT C
+ ///
+ 0x00671C20,
+ 0x00671D00,
+ 0x00671E56,
+ 0x00671F18,
+ ///
+ /// Pin Widget 7 - PORT D
+ ///
+ 0x00771C30,
+ 0x00771D00,
+ 0x00771E56,
+ 0x00771F18
+};
+
+SA_HDA_VERB_TABLE mSaHdaVerbTableDefault[] = {
+ {
+ ///
+ /// VerbTable:
+ /// Revision ID = 0xFF
+ /// Codec Vendor: 0x80862807
+ ///
+ {
+ 0x80862807, ///< Vendor ID/Device ID
+ 0x0000, ///< SubSystem ID
+ 0xFF, ///< Revision ID
+ 0x02, ///< Front panel support (1=yes, 2=no)
+ 0x0003, ///< Number of Rear Jacks
+ 0x0000 ///< Number of Front Jacks
+ },
+ 0 ///< Pointer to verb table data, need to be inited in the code.
+ }
+};
+
+/**
+ Polling the Status bit
+
+ @param[in] StatusReg The regsiter address to read the status
+ @param[in] PollingBitMap The bit mapping for polling
+ @param[in] PollingData The Data for polling
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_TIMEOUT Polling the bit map time out
+**/
+EFI_STATUS
+StatusPolling (
+ IN UINT32 StatusReg,
+ IN UINT16 PollingBitMap,
+ IN UINT16 PollingData
+ )
+{
+ UINT32 LoopTime;
+
+ for (LoopTime = 0; LoopTime < SA_HDA_MAX_LOOP_TIME; LoopTime++) {
+ if ((MmioRead16 (StatusReg) & PollingBitMap) == PollingData) {
+ break;
+ } else {
+ PchPmTimerStall (SA_HDA_WAIT_PERIOD);
+ }
+ }
+
+ if (LoopTime >= SA_HDA_MAX_LOOP_TIME) {
+ DEBUG ((EFI_D_ERROR, "Polling StatusReg 0x%X BitMap 0x%x TimeOut\n", StatusReg, PollingBitMap));
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send the command to the codec via the Immediate Command mechanism is written
+ to the IC register
+
+ @param[in] HdaBar Base address of Intel HD Audio memory mapped configuration registers
+ @param[in, out] CodecCommandData The Codec Command to be sent to the codec
+ @param[in] ReadBack Whether to get the response received from the codec
+
+ @exception EFI_DEVICE_ERROR Device status error, operation failed
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SendCodecCommand (
+ IN UINT32 HdaBar,
+ IN OUT UINT32 *CodecCommandData,
+ IN BOOLEAN ReadBack
+ )
+{
+ EFI_STATUS Status;
+
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ Status = StatusPolling (HdaBar + R_HDA_IRS, (UINT16) B_HDA_IRS_ICB, (UINT16) 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ICB bit is not zero before SendCodecCommand! \n"));
+ return EFI_DEVICE_ERROR;
+ }
+ ///
+ /// Clear Result Valid (IRV) bit (by writing a one to it) before issuing a new command
+ ///
+ MmioOr16 ((UINTN) (HdaBar + R_HDA_IRS), (UINT16) (B_HDA_IRS_IRV));
+ ///
+ /// Send command to codec
+ ///
+ MmioWrite32 (HdaBar + R_HDA_IC, *CodecCommandData);
+ ///
+ /// Set ICB bit to issue the command currently stored in IC to the codec.
+ ///
+ MmioOr16 ((UINTN) (HdaBar + R_HDA_IRS), (UINT16) (B_HDA_IRS_ICB));
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ Status = StatusPolling (HdaBar + R_HDA_IRS, (UINT16) B_HDA_IRS_ICB, (UINT16) 0);
+ if (EFI_ERROR (Status)) {
+ MmioAnd16 ((UINTN) (HdaBar + R_HDA_IRS), (UINT16)~(B_HDA_IRS_ICB));
+ return Status;
+ }
+
+ ///
+ /// Save Codec command for runtime code
+ ///
+ if (mVerbCodecSaveAddress != NULL) {
+ if ((mVerbCount * 4) < AUDIO_CODEC_MAX_SIZE) {
+ *(mVerbCodecSaveAddress + mVerbCount) = *CodecCommandData;
+ mVerbCount++;
+ DEBUG ((EFI_D_ERROR, "SendCodecCommand(0x%x): 0x%x \n",(mVerbCodecSaveAddress + (mVerbCount)), *CodecCommandData));
+ } else {
+ DEBUG ((EFI_D_ERROR, "Codec Command Save Area Overflow max value of %d\n", AUDIO_CODEC_MAX_SIZE));
+ }
+ }
+
+ if (ReadBack == TRUE) {
+ if ((MmioRead16 (HdaBar + R_HDA_IRS) & B_HDA_IRS_IRV) != 0) {
+ *CodecCommandData = MmioRead32 (HdaBar + R_HDA_IR);
+ } else {
+ DEBUG ((EFI_D_ERROR, "SendCodecCommand: ReadBack fail! \n"));
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set a "Send Codec Command" S3 dispatch item
+
+ @param[in] HdaBar Base address of Intel HD Audio memory mapped configuration registers
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SendCodecCommandS3Item (
+ IN UINT32 HdaBar
+ )
+{
+ UINT16 BitMask;
+ UINT16 BitValue;
+ UINT16 Data16And;
+ UINT16 Data16Or;
+
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ BitMask = (UINT16) B_HDA_IRS_ICB;
+ BitValue = (UINT16) 0;
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_IRS,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+ ///
+ /// Clear Result Valid (IRV) bit (by writing a one to it) before issuing a new command
+ ///
+ Data16And = 0xFFFF;
+ Data16Or = (UINT16) (B_HDA_IRS_IRV);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + R_HDA_IRS),
+ &Data16Or, /// Data to be ORed
+ &Data16And /// Data to be ANDed
+ );
+
+ ///
+ /// Send command to codec
+ ///
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_IC),
+ 1,
+ (VOID *) (UINTN) (HdaBar + R_HDA_IC)
+ );
+
+ ///
+ /// Set ICB bit to issue the command currently stored in IC to the codec.
+ ///
+ Data16And = 0xFFFF;
+ Data16Or = (UINT16) (B_HDA_IRS_ICB );
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + R_HDA_IRS),
+ &Data16Or, /// Data to be ORed
+ &Data16And /// Data to be ANDed
+ );
+
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_IRS,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect And Initialize SA Audio Codec
+
+ @param[in] ImageHandle Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Legacy Region protocol installed
+ @retval Other - No protocol installed, unload driver.
+**/
+EFI_STATUS
+DetectAndInitializeCodec (
+ IN EFI_HANDLE mImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 VendorDeviceId;
+ UINT32 RevisionId;
+ UINT8 ByteReg;
+ UINTN AudioBase;
+ UINT8 AudioSDINo;
+ UINT32 HdaBar;
+ UINT32 *VerbTable;
+ UINT32 LoopTime;
+ SA_HDA_VERB_TABLE_HEADER *VerbHeaderTable;
+ EFI_PHYSICAL_ADDRESS BaseAddressBarMem;
+ UINT8 VerbTableNum;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 Data32;
+ UINT32 CodecCmdData;
+ UINT16 AudioDeviceId;
+ UINT16 Data16;
+ UINT16 BitMask;
+ UINT16 BitValue;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+ UINT16 IsUlx;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ AudioBase = MmPciAddress (0, SA_HDA_BUS_NUM, SA_HDA_DEV_NUM, SA_HDA_FUN_NUM, 0);
+ AudioDeviceId = MmioRead16 (AudioBase + PCI_DEVICE_ID_OFFSET);
+
+ ///
+ /// Allocate resource for HDBAR
+ ///
+ BaseAddressBarMem = 0x0FFFFFFFF;
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateMaxAddressSearchBottomUp,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 14,
+ SA_HDA_HDBAR_SIZE,
+ &BaseAddressBarMem,
+ mImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ///
+ /// System BIOS should ensure that the High Definition Audio HDBAR D27:F0:Reg 10-17h contains a valid address value
+ /// and is enabled by setting D3:F0:Reg 04h[1].
+ ///
+ HdaBar = (UINT32) BaseAddressBarMem;
+ MmioWrite32 (AudioBase + SA_HDA_HDBARL, HdaBar);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARL),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARL)
+ );
+
+ MmioWrite32 (AudioBase + SA_HDA_HDBARU, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARU),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARU)
+ );
+
+ MmioOr16 ((UINTN) (AudioBase + PCI_COMMAND_OFFSET), (UINT16) BIT1);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (AudioBase + PCI_COMMAND_OFFSET),
+ 1,
+ (VOID *) (UINTN) (AudioBase + PCI_COMMAND_OFFSET)
+ );
+
+ ///
+ /// AudioWA: Apply until C0, program Chicken bit: set Dev3 mmio 101C bit 29
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) {
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) (BIT29);
+ MmioOr32 ((UINTN) (HdaBar + 0x101C), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + 0x101C),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+ if (DxePlatformSaPolicy->Revision >=4) {
+ IsUlx = 0;
+ Data16 = McD2PciCfg16 (0x2);
+ if ((Data16 == 0xA0E) || (Data16 == 0xA1E)) {
+ IsUlx = 1;
+ }
+ Data32Or = 4;
+ Data32 = 75;
+ if (DxePlatformSaPolicy->IgdConfig->CdClkVar != 0) {
+ if (DxePlatformSaPolicy->IgdConfig->CdClk == 0) {
+ Data32Or = 16;
+ Data32 = 225;
+ }
+ if (DxePlatformSaPolicy->IgdConfig->CdClk == 2) {
+ Data32Or = 4;
+ Data32 = 90;
+ }
+ }
+ if(IsUlx == 1) {
+ Data32Or = 16;
+ Data32 = 225;
+ }
+ ///
+ /// Program Dev3 EM4 and EM5 MMIO registers [17:00] based on Cd Clk frequency
+ ///
+ Data32And = 0xFFFC0000;
+ Mmio32AndThenOr ((UINTN) HdaBar, 0x100c, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + 0x100c),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ Data32And = 0xFFFC0000;
+ Data32Or = Data32;
+ Mmio32AndThenOr ((UINTN) HdaBar, 0x1010, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + 0x1010),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+
+ mSaGlobalNvsAreaProtocol.Area->AudioWaA = MmioRead32(HdaBar + 0x1010);
+ mSaGlobalNvsAreaProtocol.Area->AudioWaB = MmioRead32(HdaBar + 0x101C);
+ mSaGlobalNvsAreaProtocol.Area->AudioWaC = MmioRead32(HdaBar + 0x100C);
+
+ ///
+ /// Allocate an ACPI NVS memory buffer for Saving Codec value for Adapter Power on restore
+ /// , zero initialize, and set the pointer in the SA NVS area structure.
+ ///
+ Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, AUDIO_CODEC_MAX_SIZE, (VOID **) &mVerbCodecSaveAddress);
+ if (EFI_ERROR(Status)) {
+ mSaGlobalNvsAreaProtocol.Area->AudioCodecSaveAddress = 0;
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ ZeroMem ((VOID *) mVerbCodecSaveAddress, AUDIO_CODEC_MAX_SIZE);
+ mSaGlobalNvsAreaProtocol.Area->AudioCodecSaveAddress = (UINT32) (UINTN) (mVerbCodecSaveAddress);
+ }
+
+ ///
+ /// Codec Initialization Programming Sequence
+ /// System BIOS should also ensure that the Controller Reset# bit of Global Control register
+ /// in memory-mapped space (HDBAR+08h[0]) is set to 1 and read back as 1.
+ /// Deassert the HDA controller RESET# to start up the link
+ ///
+ DEBUG ((EFI_D_INFO, "Codec Initialization...\n"));
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) (B_HDA_GCTL_CRST);
+ MmioOr32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ BitMask = (UINT16) B_HDA_GCTL_CRST;
+ BitValue = (UINT16) B_HDA_GCTL_CRST;
+ Status = StatusPolling (HdaBar + R_HDA_GCTL, BitMask, BitValue);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_GCTL,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset SA dHDA Codec - Set Controller Reset# bit and Poll: Time Out - 0! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Read GCAP and write the same value back to the register once after Controller Reset# bit is set
+ ///
+ Data16 = MmioRead16 (HdaBar + R_HDA_GCAP);
+ MmioWrite16 (HdaBar + R_HDA_GCAP, Data16);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + R_HDA_GCAP),
+ 1,
+ (VOID *) (UINTN) (HdaBar + R_HDA_GCAP)
+ );
+ ///
+ /// Clear the "State Change Status Register" STATESTS bits for
+ /// each of the "SDIN Stat Change Status Flag"
+ ///
+ MmioOr8 ((UINTN) (HdaBar + R_HDA_STATESTS), (UINT8) (SA_HDA_MAX_SID_MASK));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (HdaBar + R_HDA_STATESTS),
+ 1,
+ (VOID *) (UINTN) (HdaBar + R_HDA_STATESTS)
+ );
+ ///
+ /// Turn off the link and poll RESET# bit until it reads back as 0 to get hardware reset report
+ ///
+ Data32And = (UINT32) (~B_HDA_GCTL_CRST);
+ Data32Or = (UINT32) 0;
+ MmioAnd32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32And);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ BitMask = (UINT16) B_HDA_GCTL_CRST;
+ BitValue = 0;
+ Status = StatusPolling (HdaBar + R_HDA_GCTL, BitMask, BitValue);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_GCTL,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset SA dHDA Codec - Turn off the link and Poll: Time Out - 1! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Turn on the link and poll RESET# bit until it reads back as 1
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) (B_HDA_GCTL_CRST);
+ MmioOr32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ ///
+ /// For some combo card that will need this delay because each codec has different latency to come out from RESET.
+ /// This delay can make sure all codecs be recognized by BIOS after RESET sequence.
+ /// Additional delay might be required to allow codec coming out of reset prior to subsequent operations,
+ /// please contact your codec vendor for detail. When clearing this bit and setting it afterward,
+ /// BIOS must ensure that minimum link timing requirements (minimum RESET# assertion time, etc.) are met..
+ ///
+ PchPmTimerStall (SA_HDA_WAIT_PERIOD);
+ SCRIPT_STALL (EFI_ACPI_S3_RESUME_SCRIPT_TABLE, 300 * STALL_ONE_MICRO_SECOND);
+
+ BitMask = (UINT16) B_HDA_GCTL_CRST;
+ BitValue = (UINT16) B_HDA_GCTL_CRST;
+ Status = StatusPolling (HdaBar + R_HDA_GCTL, BitMask, BitValue);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_GCTL,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset SA dHDA Codec - Turn on the link and Poll: Time Out - 2! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Read the "State Change Status Register" STATESTS bits twice to find out if any SDIN is connected
+ /// to a codec.
+ ///
+ for (LoopTime = 0, ByteReg = 0, AudioSDINo = 0; LoopTime < SA_HDA_MAX_LOOP_TIME; LoopTime++) {
+ ByteReg = MmioRead8 (HdaBar + R_HDA_STATESTS) & SA_HDA_MAX_SID_MASK;
+ if (ByteReg != 0 && (ByteReg == AudioSDINo)) {
+ break;
+ } else {
+ AudioSDINo = ByteReg;
+ }
+
+ PchPmTimerStall (SA_HDA_WAIT_PERIOD);
+ }
+ ///
+ /// BIT3(1000) -- SDI3
+ /// BIT2(0100) -- SDI2
+ /// BIT1(0010) -- SDI1
+ /// BIT0(0001) -- SDI0
+ ///
+ if (ByteReg == 0) {
+ ///
+ /// No Codec Detected, Turn off the link
+ ///
+ DEBUG ((EFI_D_INFO, "No Codec device is detected.\n"));
+ Data32And = (UINT32) (~B_HDA_GCTL_CRST);
+ Data32Or = (UINT32) 0;
+ MmioAnd32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32And);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ Status = EFI_DEVICE_ERROR;
+ goto ExitInitAudio;
+ }
+
+ for (AudioSDINo = 0; AudioSDINo < SA_HDA_MAX_SID_NUMBER; AudioSDINo++, ByteReg >>= 1) {
+ if ((ByteReg & 0x1) == 0) {
+ ///
+ /// SDIx has no Codec Device
+ ///
+ DEBUG ((EFI_D_INFO, "SDI%d has no Codec device.\n", AudioSDINo));
+ continue;
+ }
+ ///
+ /// Verb: 31~28 27 26~20 19~0
+ /// CAd 1 NID Verb Command and data
+ /// 0/1/2
+ ///
+ /// Read the Vendor ID/Device ID pair from the attached codec
+ ///
+ VendorDeviceId = 0x000F0000 | (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &VendorDeviceId, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Read the Codec Vendor ID/Device ID fail! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Read the Revision ID from the attached codec
+ ///
+ RevisionId = 0x000F0002 | (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &RevisionId, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Read the Codec Revision ID fail! \n"));
+ goto ExitInitAudio;
+ }
+
+ RevisionId = (RevisionId >> 8) & 0xFF;
+
+ ///
+ /// Get the match codec verb table, RevID of 0xFF applies to all steppings.
+ ///
+ if (DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum == 0) {
+ ///
+ /// Init Verb Table Data
+ ///
+ DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[0].VerbTableData = mSaHdaVerbTableDataDefault;
+ DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum = sizeof (mSaHdaVerbTableDefault) / sizeof (SA_HDA_VERB_TABLE);
+ }
+ for (VerbTableNum = 0, VerbHeaderTable = NULL, VerbTable = NULL;
+ VerbTableNum < DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum;
+ VerbTableNum++
+ ) {
+ if ((VendorDeviceId == DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader.VendorDeviceId) &&
+ (
+ (DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader.RevisionId == 0xFF) ||
+ (RevisionId == DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader.RevisionId)
+ )
+ ) {
+ VerbHeaderTable = &(DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader);
+ VerbTable = DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableData;
+ if (VerbTable == 0) {
+ DEBUG ((EFI_D_ERROR, "VerbTableData of VendorID:0x%X is null.\n", VendorDeviceId));
+ Status = EFI_INVALID_PARAMETER;
+ goto ExitInitAudio;
+ }
+
+ DEBUG ((EFI_D_INFO, "Detected SA HDA Codec with verb table, VendorID = 0x%X", VendorDeviceId));
+ DEBUG ((EFI_D_INFO, " on SDI%d, revision = 0x%0x.\n", AudioSDINo, RevisionId));
+ ///
+ /// Enable 3rd Pin and Converter Widget
+ /// Clear CAd Field
+ ///
+ CodecCmdData = SA_HDA_ENABLE_3RD_PIN_WIDGET;
+ ///
+ /// Program CAd Field per the SDI number got during codec detection
+ ///
+ CodecCmdData |= (UINT32) (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Error occurs at loading Verb 0x00878101"));
+ ///
+ /// Skip the verb table loading when find the verb table content is not
+ /// properly matched with the HDA hardware, though IDs match.
+ ///
+ DEBUG (
+ (EFI_D_ERROR,
+ "Detected Codec of VendorID:0x%X, error occurs during loading verb table.\n",
+ VendorDeviceId)
+ );
+ goto ExitInitAudio;
+ }
+
+ SendCodecCommandS3Item (HdaBar);
+ ///
+ /// Send the entire list of verbs in the matching verb table one by one to the codec
+ ///
+ for (Index = 0; Index < (UINT32) ((VerbHeaderTable->NumberOfFrontJacks + VerbHeaderTable->NumberOfRearJacks) * 4); Index++) {
+ ///
+ /// Clear CAd Field
+ ///
+ CodecCmdData = VerbTable[Index] & (UINT32)~(BIT31 | BIT30 | BIT29 | BIT28);
+ ///
+ /// Program CAd Field per the SDI number got during codec detection
+ ///
+ CodecCmdData |= (UINT32) (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Error occurs at loading Command Index:%x\n", Index));
+ ///
+ /// Skip the verb table loading when find the verb table content is not
+ /// properly matched with the HDA hardware, though IDs match.
+ ///
+ DEBUG (
+ (EFI_D_ERROR,
+ "Detected Codec of VendorID:0x%X, error occurs during loading verb table.\n",
+ VendorDeviceId)
+ );
+ goto ExitInitAudio;
+ }
+
+ SendCodecCommandS3Item (HdaBar);
+ }
+ ///
+ /// Disable 3rd Pin and Converter Widget
+ /// Clear CAd Field
+ ///
+ CodecCmdData = SA_HDA_DISABLE_3RD_PIN_WIDGET;
+ ///
+ /// Program CAd Field per the SDI number got during codec detection
+ ///
+ CodecCmdData |= (UINT32) (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Error occurs at loading verb 0x00878100"));
+ ///
+ /// Skip the verb table loading when find the verb table content is not
+ /// properly matched with the HDA hardware, though IDs match.
+ ///
+ DEBUG (
+ (EFI_D_ERROR,
+ "Detected Codec of VendorID:0x%X, error occurs during loading verb table.\n",
+ VendorDeviceId)
+ );
+ goto ExitInitAudio;
+ }
+
+ SendCodecCommandS3Item (HdaBar);
+
+ DEBUG ((EFI_D_INFO, "Verb Table loading complete to Codec on SDI%d\n", AudioSDINo));
+ break;
+ }
+ }
+
+ if (VerbTableNum >= DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum) {
+ DEBUG (
+ (EFI_D_INFO,
+ "Detected SA High Definition Audio Codec, VendorID = 0x%08x on SDI%d,",
+ VendorDeviceId,
+ AudioSDINo)
+ );
+ DEBUG ((EFI_D_INFO, " but no matching verb table found.\n"));
+ }
+ } // end of for
+ Status = EFI_SUCCESS;
+
+ExitInitAudio:
+ ///
+ /// Clear HdaBar and disable memory map access
+ ///
+ MmioAnd16 ((UINTN) (AudioBase + PCI_COMMAND_OFFSET), (UINT16) (~BIT1));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (AudioBase + PCI_COMMAND_OFFSET),
+ 1,
+ (VOID *) (UINTN) (AudioBase + PCI_COMMAND_OFFSET)
+ );
+
+ MmioWrite32 (AudioBase + SA_HDA_HDBARL, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARL),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARL)
+ );
+
+ MmioWrite32 (AudioBase + SA_HDA_HDBARU, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARU),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARU)
+ );
+
+ gDS->FreeMemorySpace (
+ BaseAddressBarMem,
+ SA_HDA_HDBAR_SIZE
+ );
+ ///
+ /// Save the final count of Audio Codec Save data in SA NVS
+ ///
+ mSaGlobalNvsAreaProtocol.Area->AudioCodecSaveCount = mVerbCount;
+
+ return Status;
+}
+
+/**
+ Initialize SystemAgent Audio Device/Codec.
+
+ @param[in] ImageHandle Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Audio/Codec initialization done
+**/
+EFI_STATUS
+AudioInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+{
+ EFI_STATUS Status;
+
+ if ((DxePlatformSaPolicy->MiscConfig->AudioEnable == 0) || (McD2PciCfg16 (R_SA_IGD_VID) == 0xFFFF)) {
+ DEBUG ((
+ EFI_D_INFO, "Skip Audio Initialization when BIOS option set to disable Or iGfx is not enabled.\n"
+ )
+ );
+ return EFI_SUCCESS;
+ }
+
+ Status = DetectAndInitializeCodec (ImageHandle, DxePlatformSaPolicy);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SA Audio Codec initialization failure!\n"));
+ }
+
+ DEBUG ((EFI_D_INFO, "AudioInit() End\n"));
+ return EFI_SUCCESS;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.h
new file mode 100644
index 0000000..cd7bc33
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.h
@@ -0,0 +1,66 @@
+/** @file
+ Header file for initialization of CPU Audio device.
+
+@copyright
+ Copyright (c) 1999 - 2013 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
+**/
+#ifndef _AUDIO_INIT_H_
+#define _AUDIO_INIT_H_
+
+#include "EdkIIGlueDxe.h"
+#include "Pci22.h"
+#include "SaAccess.h"
+#include "PchAccess.h"
+#include "PchPlatformLib.h"
+#include "EfiScriptLib.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+
+#include EFI_PROTOCOL_DEPENDENCY (BootScriptSave)
+#include EFI_PROTOCOL_DEFINITION (SaPlatformPolicy)
+#include EFI_PROTOCOL_DEFINITION (PciHostBridgeResourceAllocation)
+#include EFI_PROTOCOL_DEPENDENCY (SaGlobalNvsArea)
+
+#define SA_HDA_MAX_LOOP_TIME 10
+#define SA_HDA_WAIT_PERIOD 100
+#define SA_HDA_MAX_SID_NUMBER 4
+#define SA_HDA_MAX_SID_MASK ((1 << SA_HDA_MAX_SID_NUMBER) - 1)
+
+#define AUDIO_CODEC_MAX_SIZE 0x80
+
+#define SA_HDA_ENABLE_3RD_PIN_WIDGET 0x00878101
+#define SA_HDA_DISABLE_3RD_PIN_WIDGET 0x00878100
+
+///
+/// Functions
+///
+/**
+ Initialize SystemAgent Audio Device/Codec.
+
+ @param[in] ImageHandle Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Audio/Codec initialization Done.
+**/
+EFI_STATUS
+AudioInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.c
new file mode 100644
index 0000000..5c91336
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.c
@@ -0,0 +1,368 @@
+/** @file
+ This code provides a private implementation of the Legacy Region protocol.
+
+@copyright
+ Copyright (c) 1999 - 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 "LegacyRegion.h"
+
+///
+/// Module Global:
+/// Since this driver will only ever produce one instance of the Private Data
+/// protocol you are not required to dynamically allocate the PrivateData.
+///
+LEGACY_REGION_INSTANCE mPrivateData;
+
+UINT8 mRomData[16] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+
+UINT8 mLockData[16] = {
+ 0x01,
+ 0x10,
+ 0x01,
+ 0x10,
+ 0x01,
+ 0x10,
+ 0x01,
+ 0x10,
+ 0x01,
+ 0x10,
+ 0x01,
+ 0x10, /// it was: 0x03, 0x30, 0x03, 0x30, <-- why ??
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10
+};
+
+UINT8 mUnlockData[16] = {
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x30,
+ 0x30,
+ 0x30,
+ 0x30
+};
+
+UINT8 mMaskData[16] = {
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x30,
+ 0x03,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+
+UINT8 mReg[16] = {
+ R_SA_PAM1,
+ R_SA_PAM1,
+ R_SA_PAM2,
+ R_SA_PAM2,
+ R_SA_PAM3,
+ R_SA_PAM3,
+ R_SA_PAM4,
+ R_SA_PAM4,
+ R_SA_PAM5,
+ R_SA_PAM5,
+ R_SA_PAM6,
+ R_SA_PAM6,
+ R_SA_PAM0,
+ R_SA_PAM0,
+ R_SA_PAM0,
+ R_SA_PAM0
+};
+
+EFI_STATUS
+LegacyRegionManipulation (
+ IN EFI_LEGACY_REGION_PROTOCOL * This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ IN UINT32 Mode,
+ OUT UINT32 *Granularity OPTIONAL
+ )
+/**
+ Modify PAM registers for region specified to MODE state.
+
+ @param[in] This - Pointer to EFI_LEGACY_REGION_PROTOCOL instance.
+ @param[in] Start - Starting address of a memory region covered by PAM registers (C0000h - FFFFFh).
+ @param[in] Length - Memory region length.
+ @param[in] Mode - Action to perform on a PAM region: UNLOCK, LOCK or BOOTLOCK.
+ @param[out] Granularity - Granularity of region in bytes.
+
+ @retval EFI_SUCCESS - PAM region(s) state modified as requested.
+ @retval EFI_INVALID_PARAMETER - parameter out of boundary
+**/
+{
+ UINT8 Index;
+ UINT8 Data;
+ UINT8 TempData;
+ UINT32 TempAddr;
+ UINT32 NewStartAddr;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Pci;
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;
+ UINT64 PciAddress;
+ UINT64 Attributes;
+ EFI_STATUS Status;
+
+ Pci = mPrivateData.PciRootBridgeIo;
+ if ((Start < 0xC0000) ||
+ (Start > 0xFFFFF) ||
+ (Length > 0x40000) ||
+ ((Start + Length - 1) > 0xFFFFF)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ TempAddr = Start;
+ Index = (UINT8) ((TempAddr - 0xC0000) / PAM_GRANULARITY);
+ NewStartAddr = TempAddr = (TempAddr / PAM_GRANULARITY) * PAM_GRANULARITY;
+ while (TempAddr <= (Start + Length - 1)) {
+ if (Index >= 16) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Mode == LOCK) || (Mode == BOOTLOCK)) {
+ Data = mLockData[Index];
+ } else {
+ if (Mode == UNLOCK) {
+ Data = mUnlockData[Index];
+ } else {
+ Data = mRomData[Index];
+ }
+ }
+
+ PciAddress = EFI_PCI_ADDRESS (0, 0, 0, mReg[Index]);
+ Pci->Pci.Read (Pci, EfiPciWidthUint8, PciAddress, 1, &TempData);
+ TempData = (UINT8) ((TempData & mMaskData[Index]) | Data);
+ Pci->Pci.Write (Pci, EfiPciWidthUint8, PciAddress, 1, &TempData);
+ TempAddr += PAM_GRANULARITY;
+ Index++;
+ }
+
+ if (Granularity != NULL) {
+ *Granularity = PAM_GRANULARITY;
+ }
+ ///
+ /// Program the MTRRs
+ ///
+ switch (Mode) {
+
+ case UNLOCK:
+ Attributes = EFI_MEMORY_WT;
+ break;
+
+ case LOCK:
+ Attributes = EFI_MEMORY_WP;
+ break;
+
+ case BOOTLOCK:
+ Attributes = EFI_MEMORY_WP;
+ break;
+
+ default:
+ Attributes = EFI_MEMORY_UC;
+
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiCpuArchProtocolGuid,
+ NULL,
+ (VOID **) &CpuArch
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = CpuArch->SetMemoryAttributes (
+ CpuArch,
+ NewStartAddr,
+ TempAddr - NewStartAddr,
+ Attributes
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+LegacyRegionDecode (
+ IN EFI_LEGACY_REGION_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ IN BOOLEAN *On
+ )
+/**
+ Enable/Disable decoding of the given region
+
+ @param[in] This - Pointer to EFI_LEGACY_REGION_PROTOCOL instance.
+ @param[in] Start - Starting address of region.
+ @param[in] Length - Length of region in bytes.
+ @param[in] On - 0 = Disable decoding, 1 = Enable decoding.
+
+ @retval EFI_SUCCESS - Decoding change affected.
+**/
+{
+ UINT32 Granularity;
+ if (*On) {
+ return LegacyRegionManipulation (This, Start, Length, UNLOCK, &Granularity);
+ } else {
+ return LegacyRegionManipulation (This, Start, Length, LEGACY_REGION_DECODE_ROM, &Granularity);
+ }
+}
+
+EFI_STATUS
+EFIAPI
+LegacyRegionBootLock (
+ IN EFI_LEGACY_REGION_PROTOCOL * This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity OPTIONAL
+ )
+/**
+ Make the indicated region read from RAM / write to ROM.
+
+ @param[in] This - Pointer to EFI_LEGACY_REGION_PROTOCOL instance.
+ @param[in] Start - Starting address of region.
+ @param[in] Length - Length of region in bytes.
+ @param[out] Granularity - Granularity of region in bytes.
+
+ @retval EFI_SUCCESS - Region locked or made R/O.
+**/
+{
+ return LegacyRegionManipulation (This, Start, Length, BOOTLOCK, Granularity);
+}
+
+EFI_STATUS
+EFIAPI
+LegacyRegionLock (
+ IN EFI_LEGACY_REGION_PROTOCOL * This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity OPTIONAL
+ )
+/**
+ Make the indicated region read from RAM / write to ROM.
+
+ @param[in] This - Pointer to EFI_LEGACY_REGION_PROTOCOL instance.
+ @param[in] Start - Starting address of region.
+ @param[in] Length - Length of region in bytes.
+ @param[out] Granularity - Granularity of region in bytes.
+
+ @retval EFI_SUCCESS - Region locked or made R/O.
+**/
+{
+ return LegacyRegionManipulation (This, Start, Length, LOCK, Granularity);
+}
+
+EFI_STATUS
+EFIAPI
+LegacyRegionUnlock (
+ IN EFI_LEGACY_REGION_PROTOCOL * This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity OPTIONAL
+ )
+/**
+ Make the indicated region read from RAM / write to RAM.
+
+ @param[in] This - Pointer to EFI_LEGACY_REGION_PROTOCOL instance.
+ @param[in] Start - Starting address of region.
+ @param[in] Length - Length of region in bytes.
+ @param[out] Granularity - Granularity of region in bytes.
+
+ @retval EFI_SUCCESS - Region unlocked or made R/W.
+**/
+{
+ return LegacyRegionManipulation (This, Start, Length, UNLOCK, Granularity);
+}
+
+EFI_STATUS
+LegacyRegionInstall (
+ IN EFI_HANDLE ImageHandle
+ )
+/**
+ Install Driver to produce Legacy Region protocol.
+
+ @param[in] ImageHandle Handle for the image of this driver
+
+ @retval EFI_SUCCESS - Legacy Region protocol installed
+ @retval Other - No protocol installed, unload driver.
+**/
+{
+ EFI_STATUS Status;
+ LEGACY_REGION_INSTANCE *Private;
+ Private = &mPrivateData;
+
+ ///
+ /// Grab a copy of all the protocols we depend on. Any error would
+ /// be a dispatcher bug!.
+ ///
+ Status = gBS->LocateProtocol (
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ (VOID **) &Private->PciRootBridgeIo
+ );
+ Private->Signature = LEGACY_REGION_INSTANCE_SIGNATURE;
+ Private->LegacyRegion.Decode = LegacyRegionDecode;
+ Private->LegacyRegion.Lock = LegacyRegionLock;
+ Private->LegacyRegion.BootLock = LegacyRegionBootLock;
+ Private->LegacyRegion.UnLock = LegacyRegionUnlock;
+ Private->ImageHandle = ImageHandle;
+
+ ///
+ /// Make a new handle and install the protocol
+ ///
+ Private->Handle = NULL;
+ return gBS->InstallProtocolInterface (
+ &Private->Handle,
+ &gEfiLegacyRegionProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Private->LegacyRegion
+ );
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.h
new file mode 100644
index 0000000..d2e9b2d
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/LegacyRegion.h
@@ -0,0 +1,76 @@
+/** @file
+ This code supports a private implementation of the Legacy Region protocol.
+
+@copyright
+ Copyright (c) 1999 - 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
+**/
+#ifndef _LEGACY_REGION_H_
+#define _LEGACY_REGION_H_
+
+#include "EdkIIGlueDxe.h"
+#include "Pci22.h"
+
+#include EFI_PROTOCOL_PRODUCER (LegacyRegion)
+#include EFI_PROTOCOL_DEFINITION (PciRootBridgeIo)
+#define LEGACY_REGION_INSTANCE_SIGNATURE EFI_SIGNATURE_32 ('R', 'E', 'G', 'N')
+
+#include EFI_ARCH_PROTOCOL_CONSUMER (Cpu)
+#define LEGACY_REGION_DECODE_ROM 3
+
+#include "SaAccess.h"
+
+///
+/// PAM registers granularity is 16 KB
+///
+#define PAM_GRANULARITY 0x4000
+#define UNLOCK 0x0000
+#define LOCK 0x0001
+#define BOOTLOCK 0x0002
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_LEGACY_REGION_PROTOCOL LegacyRegion;
+ EFI_HANDLE ImageHandle;
+
+ ///
+ /// Protocol for PAM register access
+ ///
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+} LEGACY_REGION_INSTANCE;
+
+#define LEGACY_REGION_INSTANCE_FROM_THIS (this) CR (this, \
+ LEGACY_REGION_INSTANCE, \
+ LegacyRegion, \
+ LEGACY_REGION_INSTANCE_SIGNATURE \
+ )
+
+/**
+ Install Driver to produce Legacy Region protocol.
+
+ @param[in] ImageHandle Handle for the image of this driver
+
+ @retval EFI_SUCCESS - Legacy Region protocol installed
+ @retval Other - No protocol installed, unload driver.
+**/
+EFI_STATUS
+LegacyRegionInstall (
+ IN EFI_HANDLE ImageHandle
+ )
+;
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.c
new file mode 100644
index 0000000..921ae94
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.c
@@ -0,0 +1,483 @@
+/** @file
+ This driver does SA PCI Express initialization.
+
+@copyright
+ Copyright (c) 1999 - 2013 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 "PciExpressInit.h"
+
+extern SYSTEM_AGENT_GLOBAL_NVS_AREA_PROTOCOL mSaGlobalNvsAreaProtocol;
+
+EFI_STATUS
+PciExpressInit (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ PCI Express Dxe Initialization.
+ Run before PCI Bus Init, where assignment of Bus, Memory,
+ and I/O Resources are assigned.
+
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Pci Express successfully started and ready to be used
+ @exception EFI_UNSUPPORTED - Pci Express can't be initialized
+**/
+{
+ EFI_STATUS Status;
+ UINT64 EgressPortBar;
+ UINT64 MchBar;
+ UINT64 PciExpressBar;
+ UINT64 DmiBar;
+ UINT32 PchRootComplexBar;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// The SA Represents Component ID 1 (CID1), while the PCH represents
+ /// Component ID 2 (CID2). This code will completely configure both Components
+ /// CID1 Integrated Ports:
+ /// Egress Port = Port 0
+ /// DMI Port = Port 1
+ /// Peg Port10 = Port 2
+ /// Peg Port11 = Port 3
+ /// Peg Port12 = Port 4
+ /// CID2 Integated Ports:
+ /// Egress Port = Port 0
+ /// Root Port 1 = Port 1
+ /// Root Port 2 = Port 2
+ /// Root Port 3 = Port 3
+ /// Root Port 4 = Port 4
+ /// Azalia = Port 5
+ ///
+ ///
+ /// Get BAR registers
+ ///
+ PchRootComplexBar = MmPci32 (0, 0, 31, 0, 0xF0) &~BIT0;
+ PciExpressBar = McD0PciCfg64 (R_SA_PCIEXBAR) & (B_SA_PCIEXBAR_PCIEXBAR_MASK | B_SA_PCIEXBAR_ADMSK128_MASK | B_SA_PCIEXBAR_ADMSK64_MASK);
+ EgressPortBar = McD0PciCfg64 (R_SA_PXPEPBAR) &~BIT0;
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+ DmiBar = McD0PciCfg64 (R_SA_DMIBAR) &~BIT0;
+
+ ///
+ /// Configure the Egress Port (0) in CID1
+ ///
+ Status = Cid1EgressPort0Init (EgressPortBar);
+
+#ifdef PEG_FLAG
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) {
+ ///
+ /// Configure the PEG Ports in CID1
+ ///
+ Status = Cid1PegPortInit (DxePlatformSaPolicy);
+ }
+#endif // PEG_FLAG
+
+ ///
+ /// Configure the SA DMI Port (1) in CID1 and the PCH DMI Port (0) in CID2.
+ /// Note that both links must be fully configured before the link
+ /// should be checked for negotiation between the 2 CIDs.
+ ///
+ DEBUG ((EFI_D_INFO, " Going to call Cid1Cid2DmiPortInit\n"));
+ Status = Cid1Cid2DmiPortInit (DmiBar, DxePlatformSaPolicy);
+
+ ///
+ /// Configure the RootComplex Topology in CID1.
+ ///
+ DEBUG ((EFI_D_INFO, " Going to call Cid1TopologyInit\n"));
+ Status = Cid1TopologyInit (EgressPortBar, DmiBar, PchRootComplexBar);
+
+ ///
+ /// Configure the RootComplex Topology in CID2.
+ ///
+ DEBUG ((EFI_D_INFO, " Going to call Cid2TopologyInit\n"));
+ Status = Cid2TopologyInit (PchRootComplexBar, DmiBar);
+
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) {
+ if (DxePlatformSaPolicy->Revision >= DXE_SA_PLATFORM_POLICY_PROTOCOL_REVISION_7) {
+ mSaGlobalNvsAreaProtocol.Area->C7Allowed = DxePlatformSaPolicy->PcieConfig->C7Allowed; //Update the Run-time C7 Allowed for ASL usage
+ }
+ }
+
+ mSaGlobalNvsAreaProtocol.Area->PackageCstateLimit = (UINT8)(AsmReadMsr64(MSR_PMG_CST_CONFIG) & B_PACKAGE_C_STATE_LIMIT);
+
+
+ return Status;
+}
+
+UINT32
+PcieFindCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ IN UINT8 CapId
+ )
+/**
+ Find the Offset to a given Capabilities ID
+ CAPID list:
+ 0x01 = PCI Power Management Interface
+ 0x04 = Slot Identification
+ 0x05 = MSI Capability
+ 0x10 = PCI Express Capability
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] Function - Pci Function Number
+ @param[in] CapId - CAPID to search for
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+{
+ UINT8 CapHeader;
+
+ ///
+ /// Always start at Offset 0x34
+ ///
+ CapHeader = MmPci8 (0, Bus, Device, Function, PCI_CAPP);
+ if (CapHeader == 0xFF) {
+ return 0;
+ }
+
+ while (CapHeader != 0) {
+ ///
+ /// Bottom 2 bits of the pointers are reserved per PCI Local Bus Spec 2.2
+ ///
+ CapHeader &= ~(BIT1 + BIT0);
+ ///
+ /// Search for desired CapID
+ ///
+ if (MmPci8 (0, Bus, Device, Function, CapHeader) == CapId) {
+ return CapHeader;
+ }
+
+ CapHeader = MmPci8 (0, Bus, Device, Function, CapHeader + 1);
+ }
+
+ return 0;
+}
+
+UINT32
+PcieFindExtendedCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ IN UINT16 CapId
+ )
+/**
+ Search and return the offset of desired Pci Express Capability ID
+ CAPID list:
+ 0x0001 = Advanced Error Rreporting Capability
+ 0x0002 = Virtual Channel Capability
+ 0x0003 = Device Serial Number Capability
+ 0x0004 = Power Budgeting Capability
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] Function - Pci Function Number
+ @param[in] CapId - Extended CAPID to search for
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+{
+ UINT16 CapHeaderOffset;
+ UINT16 CapHeaderId;
+
+ ///
+ /// Start to search at Offset 0x100
+ /// Get Capability Header
+ ///
+ CapHeaderId = 0;
+ CapHeaderOffset = 0x100;
+
+ while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {
+ ///
+ /// Search for desired CapID
+ ///
+ CapHeaderId = MmPci16 (0, Bus, Device, Function, CapHeaderOffset);
+ if (CapHeaderId == CapId) {
+ return CapHeaderOffset;
+ }
+
+ CapHeaderOffset = (MmPci16 (0, Bus, Device, Function, CapHeaderOffset + 2) >> 4);
+ }
+
+ return 0;
+}
+
+VOID
+PcieSetClkreq (
+ IN UINT8 Bus,
+ IN UINT8 Device
+ )
+/**
+ This function enables the CLKREQ# PM on all the end point functions
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+**/
+{
+ UINT8 Function;
+ UINT32 CapOffset;
+
+ ///
+ /// Parse through all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if
+ /// exists then enable the CLKREQ# bit (BIT8) on that function
+ ///
+ for (Function = 0; Function < 8; Function++) {
+ ///
+ /// Find the PCIe Cap Id (offset 10h)
+ ///
+ CapOffset = PcieFindCapId (Bus, Device, Function, EFI_PCI_CAPABILITY_ID_PCIEXP);
+ if (CapOffset == 0) {
+ continue;
+ }
+ ///
+ /// Check if CLKREQ# is supported by the endpoints
+ ///
+ if ((MmPci32 (0, Bus, Device, Function, (CapOffset + 0x0C)) & BIT18) != BIT18) {
+ ///
+ /// CLKREQ# is not supported so dont do anything
+ ///
+ return ;
+ }
+ }
+ ///
+ /// Now enable the CLKREQ#
+ ///
+ for (Function = 0; Function < 8; Function++) {
+ ///
+ /// Find the PCIe Cap Id (offset 10h)
+ ///
+ CapOffset = PcieFindCapId (Bus, Device, Function, EFI_PCI_CAPABILITY_ID_PCIEXP);
+ if (CapOffset == 0) {
+ continue;
+ }
+
+ MmPci16Or (0, Bus, Device, Function, (CapOffset + 0x010), BIT8);
+ }
+}
+
+VOID
+AdditionalDMIProgramStepsBeforeASPM (
+ IN UINT64 DmiBar,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Additional DMI Programming Steps as in SA BIOS spec
+
+ @param[in] DmiBar - DMIBAR Address
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+{
+ UINT32 Data32And;
+ UINT32 Data32Or;
+
+ ///
+ /// Configure the De-emphasis control on DMI
+ ///
+ Data32And = (UINT32) ~BIT6;
+ Data32Or = (UINT32) ((DxePlatformSaPolicy->PcieConfig->DmiDeEmphasis & 0x1) << 6);
+ Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_LCTL2_OFFSET, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + R_SA_DMIBAR_LCTL2_OFFSET),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Set 0x22C[31] to 1 before enabling ASPM
+ ///
+ Data32And = (UINT32) ~(BIT31);
+ Data32Or = (UINT32) BIT31;
+ Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_L0SLAT_OFFSET, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + R_SA_DMIBAR_L0SLAT_OFFSET),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Set 0x238 bit29 for DMI before enabling ASPM
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT29;
+ Mmio32Or (DmiBar, 0x238, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x238),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Set DMI Offset 0xC28 [4:0]
+ ///
+ Data32And = 0xFFFFFFE0;
+ Data32Or = 0x13;
+ Mmio32AndThenOr (DmiBar, R_SA_PEG_AFE_PM_TMR_OFFSET, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + R_SA_PEG_AFE_PM_TMR_OFFSET),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+}
+
+VOID
+AdditionalPEGProgramStepsBeforeASPM (
+ IN UINT8 Bus,
+ IN UINT8 pegDev,
+ IN UINT8 pegFn,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Additional PEG Programming Steps as in SA BIOS spec
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] pegDev - Pci Device Number
+ @param[in] pegFn - Pci Func Number
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+{
+ UINT32 Data32Or;
+ UINT32 Data32And;
+ UINT32 PegBaseAddress;
+
+ PegBaseAddress = (UINT32) MmPciAddress (0x0, Bus, pegDev, pegFn, 0x0);
+
+ ///
+ /// Permanently set PEGUESEV[CTS](0x1CC bit14) to 1b during BIOS boot for all the PEG controllers
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT14;
+ Mmio32Or (PegBaseAddress, 0x1CC, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0x1CC),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Configure the De-emphasis control on PEG
+ ///
+ Data32And = (UINT32)~BIT6;
+ Data32Or = (DxePlatformSaPolicy->PcieConfig->PegDeEmphasis[pegFn] & BIT0) << 6;
+ Mmio32AndThenOr (PegBaseAddress, R_SA_PEG_LCTL2_OFFSET, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_LCTL2_OFFSET),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Set 0x22C[31] to 1 before enabling ASPM
+ ///
+ Data32And = (UINT32) ~(BIT31);
+ Data32Or = (UINT32) BIT31;
+ Mmio32AndThenOr (PegBaseAddress, R_SA_PEG_L0SLAT_OFFSET, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_L0SLAT_OFFSET),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Program 0x250 bit[22:20] to 010b for all the PEG controllers before enabling ASPM
+ ///
+ Data32And = (UINT32)~(BIT22 + BIT21 + BIT20);
+ Data32Or = 0x02 << 20;
+ Mmio32AndThenOr (PegBaseAddress, 0x250, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0x250),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Set 0x238 bit29 for PEG controller before enabling ASPM
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT29;
+ Mmio32Or (PegBaseAddress, 0x238, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0x238),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Set PEG Offset 0x1F8 bit16
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT16;
+ Mmio32Or (PegBaseAddress, 0x1F8, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0x1F8),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Set PEG Offset 0xC28 [4:0]
+ ///
+ Data32And = 0xFFFFFFE0;
+ Data32Or = 0x13;
+ Mmio32AndThenOr (PegBaseAddress, R_SA_PEG_AFE_PM_TMR_OFFSET, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_AFE_PM_TMR_OFFSET),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+}
+
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.h
new file mode 100644
index 0000000..05037b9
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PciExpressInit.h
@@ -0,0 +1,224 @@
+/** @file
+ Header file for PciExpress Initialization Driver.
+
+@copyright
+ Copyright (c) 1999 - 2013 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
+**/
+#ifndef _PCIEXPRESS_INITIALIZATION_DRIVER_H_
+#define _PCIEXPRESS_INITIALIZATION_DRIVER_H_
+
+#include "EdkIIGlueDxe.h"
+#include "SaAccess.h"
+#include "PchAccess.h"
+#include "pci23.h"
+#include "EfiScriptLib.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+#include "cpu.h"
+
+#include EFI_PROTOCOL_CONSUMER (ExitPmAuth)
+#include EFI_PROTOCOL_DEPENDENCY (BootScriptSave)
+#include EFI_PROTOCOL_CONSUMER (SaPlatformPolicy)
+#include EFI_PROTOCOL_DEPENDENCY (SaGlobalNvsArea)
+
+#define DISABLED 0
+#define AUTO 1
+#define ENABLED 1
+
+#define GEN1 1
+#define GEN2 2
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 Slot;
+ UINT8 Bus2;
+ UINT8 Device2;
+ UINT8 Function2;
+} PEG_PORT_DEVICE;
+
+///
+/// Function prototypes
+///
+/**
+ PCI Express Dxe Initialization.
+ Run before PCI Bus Init, where assignment of Bus, Memory,
+ and I/O Resources are assigned.
+
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Pci Express successfully started and ready to be used
+ @exception EFI_UNSUPPORTED - Pci Express can't be initialized
+**/
+EFI_STATUS
+PciExpressInit (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+
+/**
+ Find the Offset to a given Capabilities ID
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] Function - Pci Function Number
+ @param[in] CapId - CAPID to search fo
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+UINT32
+PcieFindCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ IN UINT8 CapId
+ )
+;
+
+/**
+ Search and return the offset of desired Pci Express Capability ID
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] Function - Pci Function Number
+ @param[in] CapId - Extended CAPID to search for
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+UINT32
+PcieFindExtendedCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ IN UINT16 CapId
+ )
+;
+
+/**
+ This function enables the CLKREQ# PM on all the end point functions
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+**/
+VOID
+PcieSetClkreq (
+ IN UINT8 Bus,
+ IN UINT8 Device
+ )
+;
+
+/**
+ Perform Egress Port 0 Initialization.
+
+ @param[in] EgressPortBar - EPBAR Address
+**/
+EFI_STATUS
+Cid1EgressPort0Init (
+ IN UINT64 EgressPortBar
+ )
+;
+
+#ifdef PEG_FLAG
+/**
+ Conditionally perform PEG Port Initialization.
+ bugbug: organize this code in a way that can utilize the
+ PchS3ItemTypeInitPcieRootPortDownstream EFI_PCH_S3_DISPATCH_ITEM_TYPE
+
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+EFI_STATUS
+Cid1PegPortInit (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+#endif // PEG_FLAG
+
+/**
+ DMI Port Initialization for both CID1 (Port 1 in MCH) and CID2 (Port 0 in ICH).
+
+ @param[in] DmiBar - DMIBAR Address
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+EFI_STATUS
+Cid1Cid2DmiPortInit (
+ IN UINT64 DmiBar,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+
+/**
+ Perform Root Complex Topology Initialization for CID1.
+
+ @param[in] EgressPortBar - EPBAR Address
+ @param[in] DmiBar - DMIBAR Address
+ @param[in] PchRootComplexBar - ICH RCBA Address
+**/
+EFI_STATUS
+Cid1TopologyInit (
+ IN UINT64 EgressPortBar,
+ IN UINT64 DmiBar,
+ IN UINT32 PchRootComplexBar
+ )
+;
+
+/**
+ Perform Root Complex Topology Initialization for CID2.
+
+ @param[in] DmiBar - DMIBAR Address
+ @param[in] PchRootComplexBar - ICH RCBA Address
+**/
+EFI_STATUS
+Cid2TopologyInit (
+ IN UINT32 PchRootComplexBar,
+ IN UINT64 DmiBar
+ )
+;
+
+/**
+ Additional PEG Programming Steps as in SA BIOS spec
+
+ @param[in] Bus - Bus Number of PEG device
+ @param[in] pegDev - Dev Number of PEG device
+ @param[in] pegFn - Func Number of PEG device
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+VOID
+AdditionalPEGProgramStepsBeforeASPM (
+ IN UINT8 Bus,
+ IN UINT8 pegDev,
+ IN UINT8 pegFn,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+
+/**
+ Additional DMI Programming Steps as in SA BIOS spec
+
+ @param[in] DmiBar - DMIBAR Address
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+VOID
+AdditionalDMIProgramStepsBeforeASPM (
+ IN UINT64 DmiBar,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.c
new file mode 100644
index 0000000..bf4b367
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.c
@@ -0,0 +1,1371 @@
+/** @file
+ This file will perform SA PCIE Root Complex initialization.
+
+@copyright
+ Copyright (c) 1999 - 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 "SaBuildFlags.h"
+#include "PciExpressInit.h"
+#include "EdkIIGluePcdPciExpressLib.h"
+#include "SaPcieLib.h"
+#include "PcieComplex.h"
+#include <Token.h>
+///
+/// Global variables
+///
+UINT8 HwStrap;
+extern UINT16 mSaIotrapSmiAddress;
+extern BOOLEAN mInitPcieAspmAfterOprom;
+extern DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy;
+
+#ifdef PEG_FLAG
+PEG_PORT_DEVICE PegDeviceTable[] = {
+ ///
+ /// Bus, Device, Function, Slot, Bus2, Device2, Function2
+ ///
+ { SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, 1, 2, 0, 0 }
+// AMI_OVERRID >>
+#if RC_PEG_1 == 1
+ ,{ SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, 2, 3, 0, 0 }
+#endif
+#if RC_PEG_2 == 1
+ ,{ SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, 3, 4, 0, 0 }
+#endif
+// AMI_OVERRID <<
+};
+#endif // PEG_FLAG
+
+///
+/// Functions
+///
+VOID
+EFIAPI
+SaLateInitSmiCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/**
+ This function gets registered as a callback to perform all SA late initialization
+
+ @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.
+**/
+{
+ if (mSaIotrapSmiAddress != 0) {
+ DEBUG ((EFI_D_INFO, "[SA] Issue IOTRAP SMI %X\n", mSaIotrapSmiAddress));
+ IoWrite8 (mSaIotrapSmiAddress, 0);
+ }
+ if (Event != NULL) {
+ gBS->CloseEvent(Event);
+ }
+ return;
+}
+
+EFI_STATUS
+Cid1EgressPort0Init (
+ IN UINT64 EgressPortBar
+ )
+/**
+ Perform Egress Port 0 Initialization.
+
+ @param[in] EgressPortBar - EPBAR Address
+
+ @retval EFI_SUCCESS - Egress Port 0 initialization successed.
+**/
+{
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT8 Data8And;
+ UINT8 Data8Or;
+ UINT8 BitMask;
+ UINT8 BitValue;
+
+ ///
+ /// Egress Port Configuration
+ ///
+ /// Egress Port Virtual Channel 0 Configuration
+ /// System BIOS must insure that only TC0 is mapped to VC0.
+ /// a. Set the Egress Port Register EPBAR offset 014h[7:1]=0000000b
+ ///
+ Data32And = BIT0;
+ Data32Or = 0;
+ Mmio32And (EgressPortBar, 0x14, Data32And);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x14),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// System BIOS must program the extended VC count field.
+ /// b. Set the Egress Port Register EPBAR offset 004h[2:0]=001b
+ ///
+ Data8And = (UINT8)~(0x07);
+ Data8Or = BIT0;
+ Mmio8AndThenOr (EgressPortBar, 0x4, Data8And, Data8Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (EgressPortBar + 0x4),
+ &Data8Or,
+ &Data8And
+ );
+
+ ///
+ /// Egress Port VC1 Configuration
+ /// a. Assign Virtual Channel ID 1 to VC1: by programming PXEPBAR Offset 020[26:24] = '001b'
+ /// b. Select and map TC1 to VC1: by programming PXPEPBAR Offset 020h[7:1] = '0000001b'
+ ///
+ Data32And = (UINT32)~(0x070000FE);
+ Data32Or = ((0x01 << 24) + BIT1);
+ Mmio32AndThenOr (EgressPortBar, 0x20, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x20),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// c. Enable VC1 (no hardware behind this bit, s/w compatibility flag only) BIT31
+ /// Program EXPEPBAR Offset 020h[31]=1
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT31;
+ Mmio32Or (EgressPortBar, 0x20, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x20),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// d. Poll the VC1 Negotiation Pending bit until it reads 0:
+ /// Read the Egress Port Register EPBAR Offset 026h until [1]==0
+ ///
+ BitMask = (UINT8) BIT1;
+ BitValue = 0;
+ while ((Mmio8 (EgressPortBar, 0x26) & BitMask) != BitValue) {
+ };
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (EgressPortBar + 0x26),
+ &BitMask,
+ &BitValue,
+ 50,
+ 200000
+ );
+
+ return EFI_SUCCESS;
+}
+
+#ifdef PEG_FLAG
+EFI_STATUS
+Cid1PegPortInit (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Conditionally perform PEG Port Initialization.
+ bugbug: organize this code in a way that can utilize the
+ PchS3ItemTypeInitPcieRootPortDownstream EFI_PCH_S3_DISPATCH_ITEM_TYPE
+
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - PEG Port initialization successed.
+**/
+{
+ UINT32 Data32;
+ UINT32 Data32Or;
+ UINT32 Data32And;
+ UINT16 Data16Or;
+ UINT16 Data16And;
+ UINT8 Data8;
+ UINT32 PegBaseAddress;
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Func;
+ UINT8 Slot;
+ UINT8 Bus2;
+ UINT8 Dev2;
+ UINT8 Func2;
+ UINT8 PegComplete;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// Read HwStrap Register - PEG1CFGSEL D1.R 504h [17:16]
+ ///
+ HwStrap = (UINT8) ((McD1PciCfg32 (R_SA_PEG_FUSESCMN_OFFSET) & (BIT17 + BIT16)) >> 16);
+
+ ///
+ /// HSW - Scan/initialize PEG devices based on HW strapping.
+ ///
+ for (PegComplete = 0; PegComplete < ((sizeof (PegDeviceTable)) / (sizeof (PEG_PORT_DEVICE))); PegComplete++) {
+ ///
+ /// Get Peg Device BDF, Slot# and EndPoint(Temporary)
+ ///
+ Bus = PegDeviceTable[PegComplete].Bus;
+ Dev = PegDeviceTable[PegComplete].Device;
+ Func = PegDeviceTable[PegComplete].Function;
+ Slot = PegDeviceTable[PegComplete].Slot;
+ Bus2 = PegDeviceTable[PegComplete].Bus2;
+ Dev2 = PegDeviceTable[PegComplete].Device2;
+ Func2 = PegDeviceTable[PegComplete].Function2;
+
+ PegBaseAddress = (UINT32) MmPciAddress (0, Bus, Dev, Func, 0);
+ ///
+ /// Check if the PEG is Enabled. Since Graphics initialization has already
+ /// occurred, simply check for PEG presence.
+ /// bugbug: need to make sure this dependency is captured in the integration guide
+ ///
+ if (McDevFunPciCfg16 (Bus, Dev, Func, PCI_VID) != 0xFFFF) {
+ ///
+ /// PEG port enable and visible
+ ///
+ ///
+ /// Initialize Slot Implemented for PCI Express Port
+ ///
+ Data16And = 0xFFFF;
+ Data16Or = BIT8;
+
+ McDevFunPciCfg16Or (Bus, Dev, Func, R_SA_PEG_CAP_OFFSET, Data16Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (PegBaseAddress + R_SA_PEG_CAP_OFFSET),
+ &Data16Or,
+ &Data16And
+ );
+
+ ///
+ /// Initialize "Physical Slot Number" for PCI Express Port
+ ///
+ Data32 = McDevFunPciCfg32 (Bus, Dev, Func, R_SA_PEG_SLOTCAP_OFFSET);
+ Data32 &= 0x0007FFFF;
+ ///
+ /// Set [31:19] - Slot # based on Peg Port
+ ///
+ Data32 |= (Slot << 19);
+
+ ///
+ /// Initialize Slot Power Limit for PCI Express Port and Power Limit Scale.
+ /// Note: this register is a write once.
+ ///
+ /// Set [14:7] - 75 Watts (Default)
+ ///
+ Data32 &= 0xFFFE007F;
+ Data32 |= (75 << 7);
+ ///
+ /// [16:15] - 1.0 Watt Scale
+ ///
+ Data32 |= (0 << 15);
+
+ McDevFunPciCfg32 (Bus, Dev, Func, R_SA_PEG_SLOTCAP_OFFSET) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_SLOTCAP_OFFSET),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Additional Programming Steps
+ ///
+ /// Set PEG D.F.R 006h [15:0] = 0FFFFh
+ ///
+ Data32And = ~(0xFFFF0000);
+ Data32Or = 0xFFFF0000;
+
+ McDevFunPciCfg32AndThenOr (Bus, Dev, Func, 0x4, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0x4),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Set PEG D.F.R 01Eh [15:0] = 0FFFFh
+ ///
+ Data32And = ~(0xFFFF0000);
+ Data32Or = 0xFFFF0000;
+
+ McDevFunPciCfg32AndThenOr (Bus, Dev, Func, 0x1C, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0x1C),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Set PEG D.F.R 0AAh [15:0] = 0FFFFh
+ ///
+ Data32And = 0xFFFF;
+ Data32Or = 0xFFFF;
+
+ McDevFunPciCfg16Or (Bus, Dev, Func, 0xAA, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (PegBaseAddress + 0xAA),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Set PEG D.F.R 1C4h [31:0] = 0FFFFFFFFh
+ ///
+ Data32 = 0xFFFFFFFF;
+
+ McDevFunPciCfg32Or (Bus, Dev, Func, R_SA_PEG_PEGUESTS_OFFSET, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_PEGUESTS_OFFSET),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Set PEG D.F.R 1D0h [31:0] = 0FFFFFFFFh
+ ///
+ Data32 = 0xFFFFFFFF;
+
+ McDevFunPciCfg32Or (Bus, Dev, Func, R_SA_PEG_PEGCESTS_OFFSET, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_PEGCESTS_OFFSET),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Set PEG D.F.R 1F0h [31:0] = 0FFFFFFFFh
+ ///
+ Data32 = 0xFFFFFFFF;
+
+ McDevFunPciCfg32Or (Bus, Dev, Func, 0x1F0, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0x1F0),
+ 1,
+ &Data32
+ );
+ ///
+ /// If HSW CPU steppingId >= B0 or CRW, set BIT19 of DCAP2 register of the PEG port,to enable OBFF support using WAKE# signaling
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswB0)) ||
+ (CpuFamilyId == EnumCpuCrw)) {
+ Data32 = (UINT32) BIT19;
+ McDevFunPciCfg32Or (Bus, Dev, Func, R_SA_PEG_DCAP2_OFFSET, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_DCAP2_OFFSET),
+ 1,
+ &Data32
+ );
+ }
+ ///
+ /// Complete Common Port and Endpoint Configuration
+ ///
+ ///
+ /// Virtual Channel Configuration of PCI Express Port
+ /// Set the VC0RCTL register D1:F0 Offset 114h [7:1] = 7Fh
+ ///
+ Data32And = 0xFFFFFF01;
+ Data32Or = BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1;
+
+ McDevFunPciCfg32AndThenOr (Bus, Dev, Func, R_SA_PEG_VC0RCTL0_OFFSET, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_VC0RCTL0_OFFSET),
+ &Data32Or,
+ &Data32And
+ );
+ ///
+ /// 6.8 Additional Programming Steps before Enabling ASPM for PEG device
+ ///
+ AdditionalPEGProgramStepsBeforeASPM (Bus, Dev, Func, DxePlatformSaPolicy);
+
+ ///
+ /// 6.10 Interrupt Routing for PCI Express*
+ /// It is recommened to re-route the legacy interrupts (INTA -> INTB,C,D)
+ /// to avoid overcrowded INTA. ACPI PRT needs update.
+ /// The ACPI _PRT() methods for PEG controllers must match the legacy interrupt routing.
+ ///
+ if ((Dev == 1) && (Func == 1)) {
+ Data32And = (UINT32)~(BIT25 | BIT24);
+ Data32Or = BIT24 | BIT25;
+ McDevFunPciCfg32AndThenOr (Bus, Dev, Func, R_SA_PEG_CFG4_OFFSET, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_CFG4_OFFSET),
+ &Data32Or,
+ &Data32And
+ );
+ }
+
+ if ((Dev == 1) && (Func == 2)) {
+ Data32And = (UINT32)~(BIT25 | BIT24);
+ Data32Or = BIT25;
+ McDevFunPciCfg32AndThenOr (Bus, Dev, Func, R_SA_PEG_CFG4_OFFSET, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_CFG4_OFFSET),
+ &Data32Or,
+ &Data32And
+ );
+ }
+ }
+
+ ///
+ /// Lock offset 3Dh for Interrupt Pin
+ ///
+ Data8 = McDevFunPciCfg8 (Bus, Dev, Func, PCI_INTPIN);
+ McDevFunPciCfg8 (Bus, Dev, Func, PCI_INTPIN) = Data8;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (PegBaseAddress + PCI_INTPIN),
+ 1,
+ &Data8
+ );
+
+ ///
+ /// Lock DCAP register
+ ///
+ Data32 = McDevFunPciCfg32 (Bus, Dev, Func, R_SA_PEG_DCAP_OFFSET);
+ McDevFunPciCfg32 (Bus, Dev, Func, R_SA_PEG_DCAP_OFFSET) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + R_SA_PEG_DCAP_OFFSET),
+ 1,
+ &Data32
+ );
+
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)
+ ){
+ if ((Bus == 0) && (Dev == 1) && (Func == 0)) {
+ Data32 = McDevFunPciCfg32 (Bus, Dev, Func, 0xCD0);
+ Data32 |= BIT11;
+ McDevFunPciCfg32 (Bus, Dev, Func, 0xCD0) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PegBaseAddress + 0xCD0),
+ 1,
+ &Data32
+ );
+ }
+ }
+
+ if ((HwStrap == SA_PEG_x16_x0_x0) && (PegComplete == 0)) {
+ break;
+ }
+ if ((HwStrap == SA_PEG_x8_x8_x0) && (PegComplete == 1)) {
+ break;
+ }
+ if ((HwStrap == SA_PEG_x8_x4_x4) && (PegComplete == 2)) {
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+#endif // PEG_FLAG
+
+EFI_STATUS
+Cid1Cid2DmiPortInit (
+ IN UINT64 DmiBar,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ DMI Port Initialization for both CID1 (Port 1 in MCH) and CID2 (Port 0 in PCH).
+
+ @param[in] DmiBar - DMIBAR Address
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - DMI Port initialization successed.
+**/
+{
+ UINT32 Data32Or;
+#ifdef DMI_FLAG
+ UINT8 Data8And;
+ UINT8 Data8Or;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = GetCpuFamily();
+#endif // DMI_FLAG
+
+#ifdef DMI_FLAG
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) {
+ ///
+ /// Additional Programming Steps
+ ///
+ AdditionalDMIProgramStepsBeforeASPM (DmiBar, DxePlatformSaPolicy);
+ }
+#endif // DMI_FLAG
+
+ ///
+ /// Set DMIBAR Offset 1C4h [31:0] = 0FFFFFFFFh
+ ///
+ Data32Or = 0xFFFFFFFF;
+ Mmio32 (DmiBar, 0x1C4) = 0xFFFFFFFF;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x1C4),
+ 1,
+ &Data32Or
+ );
+
+ ///
+ /// Set DMIBAR Offset 1D0h [31:0] = 0FFFFFFFFh
+ ///
+ Data32Or = 0xFFFFFFFF;
+ Mmio32 (DmiBar, 0x1D0) = 0xFFFFFFFF;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x1D0),
+ 1,
+ &Data32Or
+ );
+
+#ifdef DMI_FLAG
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) {
+ ///
+ /// Enable `Active State PM'. DMILCTL register at DMIBAR 088h [1:0] = '11b'.
+ /// Based on the policy:
+ ///
+ if (DxePlatformSaPolicy->PcieConfig->DmiAspm == PcieAspmAutoConfig ||
+ DxePlatformSaPolicy->PcieConfig->DmiAspm == PcieAspmL0sL1
+ ) {
+ ///
+ /// Enable ASPM = L0s and L1 Entry
+ ///
+ Data8And = 0xFC;
+ Data8Or = 0x03;
+ Mmio8Or (DmiBar, 0x88, Data8Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (DmiBar + 0x088),
+ &Data8Or,
+ &Data8And
+ );
+ } else if (DxePlatformSaPolicy->PcieConfig->DmiAspm == PcieAspmL0s) {
+ ///
+ /// Enable ASPM = L0s
+ ///
+ Data8And = 0xFC;
+ Data8Or = 0x01;
+ Mmio8Or (DmiBar, 0x88, Data8Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (DmiBar + 0x088),
+ &Data8Or,
+ &Data8And
+ );
+ } else if (DxePlatformSaPolicy->PcieConfig->DmiAspm == PcieAspmL1) {
+ ///
+ /// Enable ASPM = L1
+ ///
+ Data8And = 0xFC;
+ Data8Or = 0x02;
+ Mmio8Or (DmiBar, 0x88, Data8Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (DmiBar + 0x088),
+ &Data8Or,
+ &Data8And
+ );
+ }
+
+ if (DxePlatformSaPolicy->PcieConfig->DmiExtSync == ENABLED) {
+ ///
+ /// Enable Extended Synch
+ ///
+ Data8And = 0xFF;
+ Data8Or = 0x10;
+ Mmio8Or (DmiBar, 0x88, Data8Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (DmiBar + 0x088),
+ &Data8Or,
+ &Data8And
+ );
+ }
+
+ if (DxePlatformSaPolicy->PcieConfig->DmiIot == ENABLED) {
+ ///
+ /// if DMI Iot is enabled, set DMIBAR offset 0xD34 = 0x44
+ ///
+ Data8Or = 0x44;
+ Mmio8 (DmiBar, 0xD34) = 0x44;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (DmiBar + 0xD34),
+ 1,
+ (VOID *) (UINTN) (DmiBar + 0xD34)
+ );
+ }
+ }
+#endif // DMI_FLAG
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+Cid1TopologyInit (
+ IN UINT64 EgressPortBar,
+ IN UINT64 DmiBar,
+ IN UINT32 PchRootComplexBar
+ )
+/**
+ Perform Root Complex Topology Initialization for CID1.
+
+ @param[in] EgressPortBar - EPBAR Address
+ @param[in] DmiBar - DMIBAR Address
+ @param[in] PchRootComplexBar - PCH RCBA Address
+
+ @retval EFI_SUCCESS - Root Complex topology initialization for CID1 successed.
+**/
+{
+ UINT32 Data32;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 DwordReg;
+ UINT64 McD1Base;
+ UINT64 McD1F1Base;
+ UINT64 McD1F2Base;
+
+ McD1Base = MmPciAddress (0, 0, 1, 0, 0);
+ McD1F1Base = MmPciAddress (0, 0, 1, 1, 0);
+ McD1F2Base = MmPciAddress (0, 0, 1, 2, 0);
+
+ ///
+ /// Set the CID1 Egress Port 0 Topology
+ ///
+ ///
+ /// Step 1, Set the SA Component ID = 1.
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = BIT16;
+ Mmio32AndThenOr (EgressPortBar, 0x44, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x44),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 2, Set link 1 Target Component ID and valid (Bit 0 = 1b).
+ /// Set the Link 1 TCID = 1 (Bits 23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ Mmio32AndThenOr (EgressPortBar, 0x50, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x50),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 3, Set Link 1 to Reference the DMI RCRB (Bits 31:0 = DMI Base).
+ ///
+ Data32 = (UINT32) DmiBar;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x58, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x58),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x58 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x58 + 4),
+ 1,
+ &Data32
+ );
+
+#ifdef PEG_FLAG
+ ///
+ /// CID1 Egress port Root Topology and PciExpress Port (PEG Ports) Topology
+ /// Programming only if PEG devices are enabled.
+ ///
+ /// Step 1 PCI Express Enabled Check
+ /// Check and Configure CID1 root and Device 1 function 0
+ ///
+ if (McD1PciCfg16 (PCI_VID) != 0xFFFF) {
+ ///
+ /// Step 4, Set Link 2 to Reference the Device 1 function 0.
+ ///
+ Data32 = (UINT32) 0x8000;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x68, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x68),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x68 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x68 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 5, Set link 2 Target Component ID and valid bit(Offset 60h, Bit 0 = 1b)
+ /// Set the Link 2 TCID = 1 (Bits 23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ Mmio32AndThenOr (EgressPortBar, 0x60, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x60),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Set the CID1 PCI Express* Port Root Topology
+ ///
+ /// Step 2 Set the Link 1 CID = 1 144h(23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = BIT16;
+ MmioAndThenOr32 ((UINTN) McD1Base + 0x144, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1Base + 0x144),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 3. Set Link 1 to Reference the SA EP RCRB (Bits 31:0 = EPBAR).
+ ///
+ Data32 = (UINT32) EgressPortBar;
+ MmioWrite32 ((UINTN) McD1Base + 0x158, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1Base + 0x158),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) McD1Base + 0x158 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1Base + 0x158 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 4 Set link 1 Target Component ID and valid bit(Offset 150h, Bit 0 = 1b)
+ /// Set the Link 1 TCID = 1 (Bits 23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ MmioAndThenOr32 ((UINTN) McD1Base + 0x150, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1Base + 0x150),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 5 Program Read-Only Write-Once Registers
+ /// D1.F0.R 0C4h [31:0]
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) 0x00;
+ Data32 = McD1PciCfg32 (0xC4);
+ McD1PciCfg32 (0xC4) = Data32;
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1Base + 0xC4),
+ &Data32Or,
+ &Data32And
+ );
+ }
+ ///
+ /// Check and Configure CID1 root and Device 1 function 1
+ ///
+ if (McD1F1PciCfg16 (PCI_VID) != 0xFFFF) {
+ ///
+ /// Step 6, Set Link 3 to Reference the Device 1 function 1.
+ ///
+ Data32 = (UINT32) 0x9000;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x78, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x78),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x78 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x78 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 7. Set the Link 3 Target Component ID and Valid Bit 70h [0]
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ Mmio32AndThenOr (EgressPortBar, 0x70, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x70),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 2 Set the Link 1 CID = 1 144h(23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = BIT16;
+ MmioAndThenOr32 ((UINTN) McD1F1Base + 0x144, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F1Base + 0x144),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 3 Set Link 1 to Reference the IMC EP RCRB (Bits 31:0 = EPBAR).
+ ///
+ Data32 = (UINT32) EgressPortBar;
+ MmioWrite32 ((UINTN) McD1F1Base + 0x158, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F1Base + 0x158),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) McD1F1Base + 0x158 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F1Base + 0x158 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 4 Set link 1 Target Component ID and valid bit(Offset 150h, Bit 0 = 1b)
+ /// Set the Link 1 TCID = 1 (Bits 23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ MmioAndThenOr32 ((UINTN) McD1F1Base + 0x150, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F1Base + 0x150),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 5 Program Read-Only Write-Once Registers
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) 0x00;
+ Data32 = McD1F1PciCfg32 (0xC4);
+ McD1F1PciCfg32 (0xC4) = Data32;
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F1Base + 0xC4),
+ &Data32Or,
+ &Data32And
+ );
+ }
+ ///
+ /// Check and Configure CID1 root and Device 1 function 2
+ ///
+ if (McD1F2PciCfg16 (PCI_VID) != 0xFFFF) {
+ ///
+ /// Step 8, Set Link 4 to Reference the Device 1 function 2.
+ ///
+ Data32 = (UINT32) 0xA000;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x88, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x88),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) EgressPortBar + 0x88 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x88 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 9, Set the Link 4 Target Component ID and Valid Bit 80h [0]
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ Mmio32AndThenOr (EgressPortBar, 0x80, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (EgressPortBar + 0x80),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 2. Set the Link 1 CID = 1 144h(23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = BIT16;
+ MmioAndThenOr32 ((UINTN) McD1F2Base + 0x144, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F2Base + 0x144),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 3. Set Link 1 to Reference the IMC EP RCRB (Bits 31:0 = EPBAR).
+ ///
+ Data32 = (UINT32) EgressPortBar;
+ MmioWrite32 ((UINTN) McD1F2Base + 0x158, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F2Base + 0x158),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) McD1F2Base + 0x158 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F2Base + 0x158 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 4. Set link 1 Target Component ID and valid bit(Offset 150h, Bit 0 = 1b)
+ /// Set the Link 1 TCID = 1 (Bits 23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ MmioAndThenOr32 ((UINTN) McD1F2Base + 0x150, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F2Base + 0x150),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 5. Program Read-Only Write-Once Registers
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) 0x00;
+ Data32 = McD1F2PciCfg32 (0xC4);
+ McD1F2PciCfg32 (0xC4) = Data32;
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (McD1F2Base + 0xC4),
+ &Data32Or,
+ &Data32And
+ );
+ }
+#endif // PEG_FLAG
+
+ ///
+ /// Set the CID1 DMI Port Root Topology
+ ///
+ /// Step 1 Set the CID = 1 ( Bits 23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = BIT16;
+ Mmio32AndThenOr (DmiBar, 0x44, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x44),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 2. Set Link 1 Target Port Number = 0 (Bits 31:24 = 00h).
+ /// Step 3. Set Link 1 TCID = 2 (Bits 23:16 = 02h).
+ /// Step 4. Set Link 1 as valid (Bit 0 = 1b).
+ ///
+ Data32And = 0x0000FFFF;
+ Data32Or = (BIT17 + BIT0);
+ Mmio32AndThenOr (DmiBar, 0x50, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x50),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 5, Set Link 1 to Reference the PCH RCRB
+ ///
+ Data32 = PchRootComplexBar;
+ Mmio32 (DmiBar, 0x58) = PchRootComplexBar;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x58),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ Mmio32 (DmiBar, 0x58 + 4) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x58 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 6, Set Link 2 to Reference the IMC EP (Bits 31:0 = EP).
+ ///
+ Data32 = (UINT32) EgressPortBar;
+ MmioWrite32 ((UINTN) DmiBar + 0x68, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x68),
+ 1,
+ &Data32
+ );
+ Data32 = (UINT32) 0x00;
+ MmioWrite32 ((UINTN) DmiBar + 0x68 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x68 + 4),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Step 7, Set link 2 Target Component ID and valid Bit(Bit 0 = 1b)
+ /// Set the Link 2 TCID = 1 (Bits 23:16 = 01h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = (BIT16 | BIT0);
+ Mmio32AndThenOr (DmiBar, 0x60, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (DmiBar + 0x60),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// Step 8. Program RO and Write-Once Registers
+ /// DMIBAR Offset 004h [31:0]
+ /// DMIBAR Offset 084h [31:0]
+ ///
+ DwordReg = Mmio32 (DmiBar, 0x4);
+ Mmio32 (DmiBar, 0x4) = DwordReg;
+
+ DwordReg = Mmio32 (DmiBar, 0x84);
+ Mmio32 (DmiBar, 0x84) = DwordReg;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+Cid2TopologyInit (
+ IN UINT32 PchRootComplexBar,
+ IN UINT64 DmiBar
+ )
+/**
+ Perform Root Complex Topology Initialization for CID2.
+ Note: This sequence follows PCH BIOS specification Ver 0.5 section 8.3
+ Root Complex Topology Programming
+
+ @param[in] PchRootComplexBar - PCH RCBA Address
+ @param[in] DmiBar - DMIBAR Address
+
+ @retval EFI_SUCCESS - Root Complex topology initialization for CID2 successed.
+**/
+{
+ UINT32 Data32;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+
+ ///
+ /// PCH BIOS specification Ver 0.5 section 8.3 Note 1,2
+ /// program a value into this Component ID field to determine the Component ID of
+ /// ICH8, and this value must be different from the Component ID value of the MCH.
+ /// Set the CID = 2 (Offset 104h, Bits 23:16 = 02h).
+ ///
+ Data32And = 0xFF00FFFF;
+ Data32Or = BIT17;
+ MmioAndThenOr32 (PchRootComplexBar + 0x104, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PchRootComplexBar + 0x104),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// PCH BIOS specification Ver 0.5 section 8.3 Note 3,4
+ /// Note 3: This Target Port # field must be filled in by System BIOS with the Port
+ /// # of the RCRB DMI link in the MCH.
+ /// Note 4: This Target CID field must be filled in by System BIOS with the
+ /// Component ID of the MCH.
+ /// Set the Link 1 Target Port Number = 1 (Offset 110h, bits 31:24 = 01h).
+ /// Set the Link 1 Target Component ID = 1 (Offset 110h, bits 23:16 = 01h).
+ ///
+ Data32And = 0x0000FFFF;
+ Data32Or = (BIT24 | BIT16);
+ MmioAndThenOr32 (PchRootComplexBar + 0x110, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PchRootComplexBar + 0x110),
+ &Data32Or,
+ &Data32And
+ );
+
+ ///
+ /// PCH BIOS specification Ver 0.5 section 8.3 Note 5
+ /// Fill the Base Address field with the same base address of the RCRB DMI link in
+ /// the MCH, This register field is located at RCBA+ 0118h[63:0],
+ /// and will be locked once written until the next reset.
+ ///
+ Data32 = (UINT32) DmiBar;
+ MmioWrite32 (PchRootComplexBar + 0x118, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (PchRootComplexBar + 0x118),
+ 1,
+ &Data32
+ );
+
+ Data32 = *((UINT32 *) (&DmiBar) + 1);
+ MmioWrite32 (PchRootComplexBar + 0x118 + 4, Data32);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (PchRootComplexBar + 0x118 + 4),
+ 1,
+ &Data32
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PegInitBeforeExitPmAuth (
+ VOID
+ )
+/**
+ This function performs Peg initialization before ExitPmAuth.
+
+ @retval EFI_SUCCESS - Always.
+**/
+{
+#if SA_PCIE_ASPM_IN_SMM == 1
+ EFI_EVENT ReadyToBoot;
+ EFI_STATUS Status;
+#endif
+ BOOLEAN AspmHasBeenHandled;
+
+ DEBUG ((EFI_D_ERROR, "[SA] Pcie before ExitPmAuth callback.\n"));
+ AspmHasBeenHandled = FALSE;
+ ///
+ /// SMM mode ASPM handling
+ /// Check if supported and enabled
+ ///
+#if SA_PCIE_ASPM_IN_SMM == 1
+ if ((mInitPcieAspmAfterOprom == 1) && (mSaIotrapSmiAddress != 0)) {
+ ///
+ /// Do the Phase 1 SMI callback
+ /// This will enumerate PCIe downstream devices
+ ///
+ SaLateInitSmiCallback (NULL, NULL);
+
+ ///
+ /// Create an ReadyToBoot call back event to do the Phase 3 SMI callback
+ /// This will handle PEG ASPM programming after OROM execution
+ ///
+ Status = EfiCreateEventReadyToBootEx (
+ EFI_TPL_NOTIFY,
+ SaLateInitSmiCallback,
+ NULL,
+ &ReadyToBoot
+ );
+ ASSERT_EFI_ERROR (Status);
+ AspmHasBeenHandled = TRUE;
+ }
+#endif
+
+ ///
+ /// DXE mode ASPM handling
+ /// Check if SMM mode already taken care all things
+ /// TRUE to skip DXE mode task. Otherwise do DXE mode ASPM initialization
+ ///
+#if SA_PCIE_ASPM_IN_DXE == 1
+ if (AspmHasBeenHandled == FALSE) {
+ ///
+ /// Initialize ASPM before OpROM, S3 Save script supported
+ /// First initialize all policy settings
+ /// Initialize module global variables - Stepping ID and Platform Policy
+ ///
+ SaPcieInitPolicy (mDxePlatformSaPolicy);
+ ///
+ /// Do initialization
+ ///
+ SaPcieEnumCallback ();
+ SaPcieConfigAfterOpRom ();
+ }
+#endif
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SaSecurityInit (
+ VOID
+ )
+/**
+ This function performs SA Security locking in ExitPmAuth callback
+
+ @retval EFI_SUCCESS - Security lock has done
+ @retval EFI_UNSUPPORTED - Security lock not done successfully
+**/
+{
+ BOOLEAN SecurityHasBeenHandled;
+ SecurityHasBeenHandled = FALSE;
+#if SA_PCIE_ASPM_IN_SMM == 1
+ if ((mInitPcieAspmAfterOprom == 1) && (mSaIotrapSmiAddress != 0)) {
+ ///
+ /// Generate the Phase 2 of SA SMI to do security lock
+ ///
+ SaLateInitSmiCallback (NULL, NULL);
+
+ SecurityHasBeenHandled = TRUE;
+ }
+#endif
+
+ ///
+ /// Check if SMM mode already taken care this task
+ ///
+#if SA_PCIE_ASPM_IN_DXE == 1
+ if (SecurityHasBeenHandled == FALSE) {
+ SaSaveRestorePlatform (TRUE);
+ SaSecurityLock ();
+ SecurityHasBeenHandled = TRUE;
+ }
+#endif
+ ///
+ /// Security locking is important so fail to do this will be an ERROR.
+ ///
+ if (SecurityHasBeenHandled == TRUE) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.h
new file mode 100644
index 0000000..8a52de9
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/PcieComplex.h
@@ -0,0 +1,43 @@
+/** @file
+ This is header file for SA PCIE Root Complex initialization.
+
+@copyright
+ Copyright (c) 1999 - 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
+**/
+
+EFI_STATUS
+PegInitBeforeExitPmAuth (
+ VOID
+ )
+/**
+ This function performs Peg initialization before ExitPmAuth.
+
+ @retval EFI_SUCCESS - Always.
+**/
+;
+
+EFI_STATUS
+SaSecurityInit (
+ VOID
+ )
+/**
+ This function performs SA Security locking in ExitPmAuth callback
+
+ @retval EFI_SUCCESS - Security lock has done
+ @retval EFI_UNSUPPORTED - Security lock not done successfully
+**/
+;
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaFvi.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaFvi.c
new file mode 100644
index 0000000..d88a5e7
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaFvi.c
@@ -0,0 +1,105 @@
+/** @file
+ SA Firmware Version Info implementation.
+
+@copyright
+ Copyright (c) 2011 - 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 "SaInit.h"
+
+FVI_ELEMENT_AND_FUNCTION mSaFviElementsData[] = {
+ {
+ DEFAULT_FVI_ELEMENT_DATA(SA),
+ NULL
+ },
+ {
+ {
+ 1,
+ 0,
+ MEM_RC_VERSION,
+ MEM_FVI_STRING,
+ {
+ 0
+ },
+ },
+ NULL
+ },
+ {
+ {
+ 1,
+ 0,
+ PCIE_RC_VERSION,
+ PCIE_FVI_STRING,
+ {
+ 0
+ },
+ },
+ NULL
+ },
+ {
+ {
+ 1,
+ 2,
+ SA_CRID_VERSION,
+ SA_CRID_STATUS,
+ SA_CRID_DISABLED,
+ },
+ NULL
+ },
+ {
+ {
+ 1,
+ 0,
+ SA_CRID_VERSION,
+ SA_CRID_ORIGINAL_VALUE,
+ {
+ 0
+ },
+ },
+ NULL
+ },
+ {
+ {
+ 1,
+ 0,
+ SA_CRID_VERSION,
+ SA_CRID_NEW_VALUE,
+ {
+ 0
+ },
+ },
+ NULL
+ },
+ {
+ {
+ 1,
+ 0,
+ VBIOS_RC_VERSION,
+ VBIOS_FVI_STRING,
+ {
+ 0
+ },
+ },
+ NULL
+ }
+};
+
+FVI_DATA_HUB_CALLBACK_CONTEXT mSaFviVersionData = {
+ MISC_SUBCLASS_FVI_HEADER_ENTRY(SA),
+ mSaFviElementsData,
+};
+
+UINTN mSaFviElements = sizeof (mSaFviElementsData) / sizeof (FVI_ELEMENT_AND_FUNCTION);
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.c
new file mode 100644
index 0000000..af4d45a
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.c
@@ -0,0 +1,842 @@
+/** @file
+ This is the driver that initializes the Intel System Agent.
+
+@copyright
+ Copyright (c) 1999 - 2013 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 "SaInit.h"
+#include EFI_GUID_DEFINITION (SaDataHob)
+#include <Protocol/PciEnumerationComplete.h>
+#include EFI_PROTOCOL_DEPENDENCY (SaGlobalNvsArea)
+#include EFI_GUID_DEFINITION (SaSsdtTableStorage)
+
+///
+/// Global Variables
+///
+SYSTEM_AGENT_GLOBAL_NVS_AREA_PROTOCOL mSaGlobalNvsAreaProtocol;
+DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy;
+UINT16 mSaIotrapSmiAddress;
+BOOLEAN mInitPcieAspmAfterOprom;
+EFI_GUID gEfiPciEnumerationCompleteProtocolGuid = EFI_PCI_ENUMERATION_COMPLETE_GUID;
+
+EFI_STATUS
+InitializeSaSsdtAcpiTables (
+ VOID
+ )
+/**
+@brief
+ Initialize System Agent SSDT ACPI tables
+
+ @retval EFI_SUCCESS ACPI tables are initialized successfully
+ @retval EFI_NOT_FOUND ACPI tables not found
+**/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FV_FILETYPE FileType;
+ UINT32 FvStatus;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN i;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+ INTN Instance;
+ EFI_ACPI_COMMON_HEADER *CurrentTable;
+ UINTN AcpiTableKey;
+ UINT8 *CurrPtr;
+ UINT8 *EndPtr;
+ UINT32 *Signature;
+ EFI_ACPI_DESCRIPTION_HEADER *SaAcpiTable;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+
+ FwVol = NULL;
+ SaAcpiTable = NULL;
+
+ ///
+ /// Locate ACPI Table protocol
+ ///
+ DEBUG ((EFI_D_INFO, "Init SA SSDT table\n"));
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, &AcpiTable);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Fail to locate EfiAcpiTableProtocol.\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ ///
+ /// Locate protocol.
+ /// There is little chance we can't find an FV protocol
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// Looking for FV with ACPI storage file
+ ///
+ for (i = 0; i < NumberOfHandles; i++) {
+ ///
+ /// Get the protocol on this handle
+ /// This should not fail because of LocateHandleBuffer
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[i],
+ &gEfiFirmwareVolumeProtocolGuid,
+ &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gSaSsdtAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ ///
+ /// If we found it, then we are done
+ ///
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ }
+ ///
+ /// Free any allocated buffers
+ ///
+ FreePool (HandleBuffer);
+
+ ///
+ /// Sanity check that we found our data file
+ ///
+ ASSERT (FwVol != NULL);
+ if (FwVol == NULL) {
+ DEBUG ((EFI_D_INFO, "SA Global NVS table not found\n"));
+ return EFI_NOT_FOUND;
+ }
+ ///
+ /// Our exit status is determined by the success of the previous operations
+ /// If the protocol was found, Instance already points to it.
+ /// Read tables from the storage file.
+ ///
+ Instance = 0;
+ CurrentTable = NULL;
+ while (Status == EFI_SUCCESS) {
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gSaSsdtAcpiTableStorageGuid,
+ EFI_SECTION_RAW,
+ Instance,
+ &CurrentTable,
+ &Size,
+ &FvStatus
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// Check the table ID to modify the table
+ ///
+ if (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->OemTableId == EFI_SIGNATURE_64 ('S', 'a', 'S', 's', 'd', 't', ' ', 0)) {
+ SaAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ ///
+ /// Locate the SSDT package
+ ///
+ CurrPtr = (UINT8 *) SaAcpiTable;
+ EndPtr = CurrPtr + SaAcpiTable->Length;
+
+ for (; CurrPtr <= EndPtr; CurrPtr++) {
+ Signature = (UINT32 *) (CurrPtr + 3);
+ if (*Signature == EFI_SIGNATURE_32 ('S', 'A', 'N', 'V')) {
+ ASSERT_EFI_ERROR (*(UINT32 *) (CurrPtr + 3 + sizeof (*Signature) + 2) == 0xFFFF0000);
+ ASSERT_EFI_ERROR (*(UINT16 *) (CurrPtr + 3 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) == 0xAA55);
+ ///
+ /// SA Global NVS Area address
+ ///
+ *(UINT32 *) (CurrPtr + 3 + sizeof (*Signature) + 2) = (UINT32) (UINTN) mSaGlobalNvsAreaProtocol.Area;
+ ///
+ /// SA Global NVS Area size
+ ///
+ *(UINT16 *) (CurrPtr + 3 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) =
+ sizeof (SYSTEM_AGENT_GLOBAL_NVS_AREA);
+
+ AcpiTableKey = 0;
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ SaAcpiTable,
+ SaAcpiTable->Length,
+ &AcpiTableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ ///
+ /// Increment the instance
+ ///
+ Instance++;
+ CurrentTable = NULL;
+ }
+ }
+
+ return Status;
+
+}
+
+EFI_STATUS
+EFIAPI
+SaInitEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/**
+ SystemAgent DXE Initialization.
+
+ @param[in] ImageHandle Handle for the image of this driver
+ @param[in] SystemTable Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+**/
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+ SA_INSTANCE_PRIVATE_DATA *SaInstance;
+ UINTN MCHBAR_BASE;
+ SA_DATA_HOB *SaDataHob;
+
+ DEBUG ((EFI_D_INFO, "SaInitDxe Start\n"));
+
+ INITIALIZE_SCRIPT (ImageHandle, SystemTable);
+ SaInstance = NULL;
+
+ MCHBAR_BASE = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+
+ ///
+ /// Get the platform setup policy.
+ ///
+ Status = gBS->LocateProtocol (&gDxePlatformSaPolicyGuid, NULL, (VOID **) &mDxePlatformSaPolicy);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Dump SA Platform Policy
+ ///
+ SaDxePolicyDump (mDxePlatformSaPolicy);
+
+ ///
+ /// Get SaDataHob HOB and see if ASPM should be programmed before or after OpROM.
+ ///
+ mSaIotrapSmiAddress = 0;
+ mInitPcieAspmAfterOprom = 0;
+ SaDataHob = NULL;
+ SaDataHob = (SA_DATA_HOB *)GetFirstGuidHob (&gSaDataHobGuid);
+ if (SaDataHob != NULL) {
+ mSaIotrapSmiAddress = SaDataHob->SaIotrapSmiAddress;
+ mInitPcieAspmAfterOprom = SaDataHob->InitPcieAspmAfterOprom;
+ }
+
+ ///
+ /// If there was no DXE ASPM code, always executes SMM code
+ ///
+#if SA_PCIE_ASPM_IN_DXE == 0
+ mInitPcieAspmAfterOprom = 1;
+#endif
+ ///
+ /// If there was no SMM mode supported, always enable DXE mode
+ ///
+#if SA_PCIE_ASPM_IN_SMM == 0
+ mInitPcieAspmAfterOprom = 0;
+#endif
+
+ ///
+ /// Install System Agent Global NVS protocol
+ ///
+ DEBUG ((EFI_D_INFO, "Install SA GNVS protocol\n"));
+ Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (SYSTEM_AGENT_GLOBAL_NVS_AREA), &mSaGlobalNvsAreaProtocol.Area);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem ((VOID *) mSaGlobalNvsAreaProtocol.Area, sizeof (SYSTEM_AGENT_GLOBAL_NVS_AREA));
+ mSaGlobalNvsAreaProtocol.Area->SaRcRevision = SA_RC_VERSION;
+ mSaGlobalNvsAreaProtocol.Area->XPcieCfgBaseAddress = (UINT32) (MmPciAddress (0, 0, 0, 0, 0x0));
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gSaGlobalNvsAreaProtocolGuid,
+ &mSaGlobalNvsAreaProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// PciExpress Dxe Initialization
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing PciExpress (Dxe)\n"));
+ PciExpressInit (mDxePlatformSaPolicy);
+
+ ///
+ /// Internal devices and Misc configurations.
+ ///
+ DEBUG ((EFI_D_INFO, "Internal Device and Misc Configurations\n"));
+ DeviceConfigure (mDxePlatformSaPolicy);
+ ProgramSvidSid (mDxePlatformSaPolicy);
+
+ ///
+ /// LegacyRegion Driver
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing Legacy Region\n"));
+ LegacyRegionInstall (ImageHandle);
+
+ ///
+ /// GtPostInit Initialization
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing GT PowerManagement and other GT POST related\n"));
+ GraphicsInit (ImageHandle, mDxePlatformSaPolicy);
+
+ ///
+ /// Audio (dHDA) Initialization
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing CPU Audio (dHDA) device\n"));
+ AudioInit (ImageHandle, mDxePlatformSaPolicy);
+
+ //
+ // @todo remove this VP SKIP and prepare for PO settings to skip this code.
+ //
+ ///
+ /// Vtd Initialization
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing VT-d\n"));
+ VtdInit (mDxePlatformSaPolicy);
+
+ ///
+ /// IgdOpRegion Install Initialization
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing IGD OpRegion\n"));
+ IgdOpRegionInit ();
+
+
+ ///
+ /// Create PCI Enumeration Completed callback for SA
+ ///
+ EfiCreateProtocolNotifyEvent (
+ &gEfiPciEnumerationCompleteProtocolGuid,
+ EFI_TPL_CALLBACK,
+ SaPciEnumCompleteCallback,
+ NULL,
+ &Registration
+ );
+
+ ///
+ /// Create ExitPmAuth callback for SA
+ ///
+ EfiCreateProtocolNotifyEvent (
+ &gExitPmAuthProtocolGuid,
+ EFI_TPL_CALLBACK,
+ SaExitPmAuthCallback,
+ NULL,
+ &Registration
+ );
+
+ ///
+ /// Install SA_INFO_PROTOCOL
+ ///
+ SaInstance = AllocateZeroPool (sizeof (SA_INSTANCE_PRIVATE_DATA));
+ if (SaInstance == NULL) {
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SaInstance->SaInfo.Revision = SA_INFO_PROTOCOL_REVISION_1;
+ ///
+ /// RCVersion[31:0] is the release number.
+ /// For example:
+ /// SaFramework 0.6.0.01 should be 00 06 00 01 (0x00060001)
+ /// SaFramework 0.6.2 should be 00 06 02 00 (0x00060200)
+ ///
+ SaInstance->SaInfo.RCVersion = SA_RC_VERSION;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiSaInfoProtocolGuid,
+ &(SaInstance->SaInfo),
+ NULL
+ );
+
+ ///
+ /// Install System Agent Global NVS ACPI table
+ ///
+#ifndef Remove_SaSsdt_Data_To_Dsdt
+ Status = InitializeSaSsdtAcpiTables ();
+#endif //AMI_OVERRIDE
+
+#ifdef SG_SUPPORT
+
+ DEBUG ((EFI_D_INFO, "Initializing Switchable Graphics (Dxe)\n"));
+ SwitchableGraphicsInit (ImageHandle, SystemTable, mDxePlatformSaPolicy);
+
+#endif
+
+ DEBUG ((EFI_D_INFO, "SaInitDxe End\n"));
+
+ return EFI_SUCCESS;
+}
+
+VOID
+DeviceConfigure (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Initialize GT Post Routines.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+{
+ UINT64 MchBar;
+
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+
+ ///
+ /// Enable/Disable CHAP device (B0,D7,F0).
+ ///
+ if (DxePlatformSaPolicy->MiscConfig->ChapDeviceEnable) {
+ McD0PciCfg32Or (R_SA_DEVEN, B_SA_DEVEN_D7EN_MASK);
+ } else {
+ McD0PciCfg32And (R_SA_DEVEN, ~(B_SA_DEVEN_D7EN_MASK));
+ }
+ ///
+ /// Enable/Disable Thermal device (B0,D4,F0).
+ ///
+ if (DxePlatformSaPolicy->MiscConfig->Device4Enable) {
+ McD0PciCfg32Or (R_SA_DEVEN, B_SA_DEVEN_D4EN_MASK);
+ } else {
+ McD0PciCfg32And (R_SA_DEVEN, ~(B_SA_DEVEN_D4EN_MASK));
+ }
+ ///
+ /// Enable/Disable Audio device (B0,D3,F0).
+ ///
+ if ((DxePlatformSaPolicy->MiscConfig->AudioEnable) && (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF)) {
+ McD0PciCfg32Or (R_SA_DEVEN, B_SA_DEVEN_D3EN_MASK);
+ } else {
+ McD0PciCfg32And (R_SA_DEVEN, ~(B_SA_DEVEN_D3EN_MASK));
+ }
+
+ return ;
+}
+
+VOID
+ProgramSvidSid (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Program SA devices Subsystem Vendor Identifier (SVID) and Subsystem Identifier (SID).
+
+ @param[in] DxePlatformSaPolicy The SAPlatform Policy protocol instance
+**/
+{
+ UINT8 Index;
+ UINT8 BusNumber;
+ UINTN PciEAddressBase;
+ UINT8 DeviceNumber;
+ UINT8 FunctionNumber;
+ UINT8 SvidRegOffset;
+ UINT16 Data16;
+ STATIC SA_SVID_SID_INIT_ENTRY SvidSidInitTable[] = {
+ {
+ 0,
+ 0,
+ PCI_SVID_OFFSET
+ },
+ {
+ 1,
+ 0,
+ R_SA_PEG_SS_OFFSET
+ },
+ {
+ 1,
+ 1,
+ R_SA_PEG_SS_OFFSET
+ },
+ {
+ 1,
+ 2,
+ R_SA_PEG_SS_OFFSET
+ },
+ {
+ 2,
+ 0,
+ PCI_SVID_OFFSET
+ },
+ {
+ 3,
+ 0,
+ PCI_SVID_OFFSET
+ },
+ {
+ 4,
+ 0,
+ PCI_SVID_OFFSET
+ },
+ {
+ 7,
+ 0,
+ PCI_SVID_OFFSET
+ }
+ };
+
+ if ((DxePlatformSaPolicy->MiscConfig->DefaultSvidSid->SubSystemVendorId != 0) ||
+ (DxePlatformSaPolicy->MiscConfig->DefaultSvidSid->SubSystemId != 0)
+ ) {
+ for (Index = 0; Index < (sizeof (SvidSidInitTable) / sizeof (SA_SVID_SID_INIT_ENTRY)); Index++) {
+ BusNumber = 0;
+ DeviceNumber = SvidSidInitTable[Index].DeviceNumber;
+ FunctionNumber = SvidSidInitTable[Index].FunctionNumber;
+ SvidRegOffset = SvidSidInitTable[Index].SvidRegOffset;
+ PciEAddressBase = (UINT32) MmPciAddress (0, BusNumber, DeviceNumber, FunctionNumber, 0);
+ ///
+ /// Skip if the device is disabled
+ ///
+ if (MmioRead16 (PciEAddressBase + PCI_VID) == 0xFFFF) {
+ continue;
+ }
+ ///
+ /// Program SA devices Subsystem Vendor Identifier (SVID)
+ ///
+ Data16 = DxePlatformSaPolicy->MiscConfig->DefaultSvidSid->SubSystemVendorId;
+ MmioWrite16 (
+ (UINTN) (PciEAddressBase + SvidRegOffset),
+ Data16
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (PciEAddressBase + SvidRegOffset),
+ 1,
+ (VOID *) (UINTN) (PciEAddressBase + SvidRegOffset)
+ );
+
+ ///
+ /// Program SA devices Subsystem Identifier (SID)
+ ///
+ Data16 = DxePlatformSaPolicy->MiscConfig->DefaultSvidSid->SubSystemId;
+ MmioWrite16 (
+ (UINTN) (PciEAddressBase + SvidRegOffset + 2),
+ Data16
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (PciEAddressBase + SvidRegOffset + 2),
+ 1,
+ (VOID *) (UINTN) (PciEAddressBase + SvidRegOffset + 2)
+ );
+ }
+ }
+
+ return;
+}
+
+VOID
+SaFviExitPmAuth(
+ VOID
+ )
+/**
+ This function populates the SA FVI version numbers
+**/
+{
+ const UINT8 StrEnabled[sizeof (SA_CRID_ENABLED)] = SA_CRID_ENABLED;
+ const UINT8 StrDisabled[sizeof (SA_CRID_DISABLED)] = SA_CRID_DISABLED;
+ const CodeVersion PcieRcVersion = {
+#include "SaPcieVersion.h"
+ };
+ const CodeVersion MemRcVersion = {
+#include "MrcVersion.h"
+ };
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET RegSet;
+ UINT16 VbiosBuildNum;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ if (mDxePlatformSaPolicy->MiscConfig->FviReport) {
+ InitFviDataHubCbContext (
+ mDxePlatformSaPolicy->MiscConfig->FviSmbiosType,
+ (UINT8) mSaFviElements,
+ &mSaFviVersionData
+ );
+ mSaFviElementsData[MEM_RC_VER].Element.Version.MajorVersion = (UINT8) MemRcVersion.Major;
+ mSaFviElementsData[MEM_RC_VER].Element.Version.MinorVersion = (UINT8) MemRcVersion.Minor;
+ mSaFviElementsData[MEM_RC_VER].Element.Version.Revision = (UINT8) MemRcVersion.Rev;
+ mSaFviElementsData[MEM_RC_VER].Element.Version.BuildNum = (UINT16) MemRcVersion.Build;
+ mSaFviElementsData[PCIE_VER].Element.Version.MajorVersion = (UINT8) PcieRcVersion.Major;
+ mSaFviElementsData[PCIE_VER].Element.Version.MinorVersion = (UINT8) PcieRcVersion.Minor;
+ mSaFviElementsData[PCIE_VER].Element.Version.Revision = (UINT8) PcieRcVersion.Rev;
+ mSaFviElementsData[PCIE_VER].Element.Version.BuildNum = (UINT16) PcieRcVersion.Build;
+ mSaFviElementsData[CRID_ORIGINAL].Element.Version.BuildNum = (UINT16) McD0PciCfg8 (PCI_REVISION_ID_OFFSET);
+
+ if (mDxePlatformSaPolicy->MiscConfig->CridEnable == TRUE) {
+ CopyMem (mSaFviElementsData[CRID_STATUS].Element.VerString, StrEnabled, sizeof (StrEnabled));
+ } else {
+ CopyMem (mSaFviElementsData[CRID_STATUS].Element.VerString, StrDisabled, sizeof (StrDisabled));
+ }
+
+ mSaFviElementsData[CRID_NEW].Element.Version.BuildNum = (UINT16) McD0PciCfg8 (PCI_REVISION_ID_OFFSET);
+ //
+ // Check IGFX device
+ //
+ VbiosBuildNum = 0xFFFF;
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (void **) &LegacyBios);
+ if (Status == EFI_SUCCESS) {
+ RegSet.X.AX = 0x5f01;
+ Status = LegacyBios->Int86 (LegacyBios, 0x15, &RegSet);
+ VbiosBuildNum = (((RegSet.X.DX & 0x0F00) << 4) | ((RegSet.X.DX & 0x000F) << 8) | ((RegSet.X.BX & 0x0F00) >> 4) | (RegSet.X.BX & 0x000F));
+ }
+ mSaFviElementsData[VBIOS_VER].Element.Version.BuildNum = VbiosBuildNum;
+
+ CreateRcFviDatahub (&mSaFviVersionData);
+ }
+}
+
+VOID
+EFIAPI
+SaPciEnumCompleteCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/**
+ This function gets registered as a callback to perform SA initialization before ExitPmAuth
+
+ @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.
+**/
+{
+ EFI_STATUS Status;
+ VOID *ProtocolPointer;
+
+ ///
+ /// Check if this is first time called by EfiCreateProtocolNotifyEvent() or not,
+ /// if it is, we will skip it until real event is triggered
+ ///
+ Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL, &ProtocolPointer);
+ if (EFI_SUCCESS != Status) {
+ return;
+ }
+
+ gBS->CloseEvent (Event);
+
+ Status = PegInitBeforeExitPmAuth ();
+ if (EFI_SUCCESS != Status) {
+ DEBUG ((EFI_D_ERROR, "[SA] Pcie initialization before ExitPmAuth Error, Status = %x \n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+VOID
+EFIAPI
+SaExitPmAuthCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/**
+ This function gets registered as a callback to perform SA configuration security lock
+
+ @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.
+**/
+{
+ EFI_STATUS Status;
+ VOID *ProtocolPointer;
+
+ ///
+ /// Check if this is first time called by EfiCreateProtocolNotifyEvent() or not,
+ /// if it is, we will skip it until real event is triggered
+ ///
+ Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, &ProtocolPointer);
+ if (EFI_SUCCESS != Status) {
+ return;
+ }
+
+ gBS->CloseEvent (Event);
+
+ if (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF) {
+ Status = PostPmInitExitPmAuth();
+ if (EFI_SUCCESS != Status) {
+ DEBUG ((EFI_D_ERROR, "[SA] ExitPmAuth GraphicsInit Error, Status = %x \n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ UpdateDmarExitPmAuth();
+
+ if (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF) {
+ Status = GetVBiosVbtExitPmAuth();
+ if (EFI_SUCCESS != Status) {
+ DEBUG ((EFI_D_ERROR, "[SA] ExitPmAuth Op Region Error, Status = %x \n", Status));
+ }
+
+ Status = UpdateIgdOpRegionExitPmAuth();
+ if (EFI_SUCCESS != Status) {
+ DEBUG ((EFI_D_ERROR, "[SA] ExitPmAuth Update Op Region Error, Status = %x \n", Status));
+ }
+ }
+
+ SaFviExitPmAuth();
+
+ Status = SaSecurityInit ();
+ if (EFI_SUCCESS != Status) {
+ DEBUG ((EFI_D_ERROR, "[SA] Security lock Error, Status = %x \n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ return;
+}
+
+VOID
+SaDxePolicyDump (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy
+ )
+/**
+ This function prints the DXE phase platform policy.
+
+ @param[in] mDxePlatformSaPolicy - SA DxePlatformPolicy protocol
+**/
+{
+#ifdef EFI_DEBUG
+ INTN i;
+
+ DEBUG ((EFI_D_INFO, "\n------------------------ SA Platform Policy (DXE) dump BEGIN -----------------\n"));
+ DEBUG ((EFI_D_INFO, "Revision : %x\n", mDxePlatformSaPolicy->Revision));
+ DEBUG ((EFI_D_INFO, "------------------------ SA_VTD_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " VtdEnable : %x\n", mDxePlatformSaPolicy->Vtd->VtdEnable));
+ DEBUG ((EFI_D_INFO, " RmrrUsbBaseAddress : %x\n", mDxePlatformSaPolicy->Vtd->RmrrUsbBaseAddress));
+
+ DEBUG ((EFI_D_INFO, " VtdBaseAddress[%d] :", SA_VTD_ENGINE_NUMBER));
+ for (i = 0; i < SA_VTD_ENGINE_NUMBER; i++) {
+ DEBUG ((EFI_D_INFO, " %x", mDxePlatformSaPolicy->Vtd->BaseAddress[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, "------------------------ SA_MEMORY_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " SpdAddressTable[%d] :", SA_MC_MAX_SOCKETS));
+ for (i = 0; i < SA_MC_MAX_SOCKETS; i++) {
+ DEBUG ((EFI_D_INFO, " %x", mDxePlatformSaPolicy->MemoryConfig->SpdAddressTable[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " ChannelASlotMap : %x\n", mDxePlatformSaPolicy->MemoryConfig->ChannelASlotMap));
+ DEBUG ((EFI_D_INFO, " ChannelBSlotMap : %x\n", mDxePlatformSaPolicy->MemoryConfig->ChannelBSlotMap));
+ DEBUG ((EFI_D_INFO, " RmtBdatEnable : %x\n", mDxePlatformSaPolicy->MemoryConfig->RmtBdatEnable));
+ DEBUG ((EFI_D_INFO, " MrcTimeMeasure : %x\n", mDxePlatformSaPolicy->MemoryConfig->MrcTimeMeasure));
+ DEBUG ((EFI_D_INFO, " MrcFastBoot : %x\n", mDxePlatformSaPolicy->MemoryConfig->MrcFastBoot));
+
+ DEBUG ((EFI_D_INFO, "------------------------ SA_PCIE_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " DmiAspm : %x\n", mDxePlatformSaPolicy->PcieConfig->DmiAspm));
+
+ DEBUG ((EFI_D_INFO, " PegAspm[%d] :", SA_PEG_MAX_FUN));
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ DEBUG ((EFI_D_INFO, " %x", mDxePlatformSaPolicy->PcieConfig->PegAspm[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " PegAspmL0s[%d] :", SA_PEG_MAX_FUN));
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ DEBUG ((EFI_D_INFO, " %x", mDxePlatformSaPolicy->PcieConfig->PegAspmL0s[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " PegDeEmphasis[%d] :", SA_PEG_MAX_FUN));
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ DEBUG ((EFI_D_INFO, " %x", mDxePlatformSaPolicy->PcieConfig->PegDeEmphasis[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " DmiExtSync : %x\n", mDxePlatformSaPolicy->PcieConfig->DmiExtSync));
+ DEBUG ((EFI_D_INFO, " DmiDeEmphasis : %x\n", mDxePlatformSaPolicy->PcieConfig->DmiDeEmphasis));
+ DEBUG ((EFI_D_INFO, " DmiIot : %x\n", mDxePlatformSaPolicy->PcieConfig->DmiIot));
+
+ if (mDxePlatformSaPolicy->Revision >= DXE_SA_PLATFORM_POLICY_PROTOCOL_REVISION_2) {
+ if (mDxePlatformSaPolicy->PcieConfig->PcieAspmDevsOverride != NULL) {
+ DEBUG ((EFI_D_INFO, "------------------------ PCIE_ASPM_DEV_INFO -----------------\n"));
+ DEBUG ((EFI_D_INFO, " VendorId DeviceId RevId RootApmcMask EndpointApmcMask\n"));
+ i = 0;
+ while ((mDxePlatformSaPolicy->PcieConfig->PcieAspmDevsOverride[i].VendorId != SA_PCIE_DEV_END_OF_TABLE) &&
+ (i < MAX_PCIE_ASPM_OVERRIDE)) {
+ DEBUG ((EFI_D_INFO, " %04x %04x %02x %01x %01x\n",
+ mDxePlatformSaPolicy->PcieConfig->PcieAspmDevsOverride[i].VendorId,
+ mDxePlatformSaPolicy->PcieConfig->PcieAspmDevsOverride[i].DeviceId,
+ mDxePlatformSaPolicy->PcieConfig->PcieAspmDevsOverride[i].RevId,
+ mDxePlatformSaPolicy->PcieConfig->PcieAspmDevsOverride[i].RootApmcMask,
+ mDxePlatformSaPolicy->PcieConfig->PcieAspmDevsOverride[i].EndpointApmcMask));
+ i++;
+ }
+ DEBUG ((EFI_D_INFO, "------------------------ END_OF_TABLE -----------------------\n"));
+ }
+ if (mDxePlatformSaPolicy->PcieConfig->PcieLtrDevsOverride != NULL) {
+ DEBUG ((EFI_D_INFO, "------------------------ PCIE_LTR_DEV_INFO -----------------\n"));
+ DEBUG ((EFI_D_INFO, " VendorId DeviceId RevId SnoopLatency NonSnoopLatency\n"));
+ i = 0;
+ while ((mDxePlatformSaPolicy->PcieConfig->PcieLtrDevsOverride[i].VendorId != SA_PCIE_DEV_END_OF_TABLE) &&
+ (i < MAX_PCIE_LTR_OVERRIDE)) {
+ DEBUG ((EFI_D_INFO, " %04x %04x %02x %01x %01x\n",
+ mDxePlatformSaPolicy->PcieConfig->PcieLtrDevsOverride[i].VendorId,
+ mDxePlatformSaPolicy->PcieConfig->PcieLtrDevsOverride[i].DeviceId,
+ mDxePlatformSaPolicy->PcieConfig->PcieLtrDevsOverride[i].RevId,
+ mDxePlatformSaPolicy->PcieConfig->PcieLtrDevsOverride[i].SnoopLatency,
+ mDxePlatformSaPolicy->PcieConfig->PcieLtrDevsOverride[i].NonSnoopLatency));
+ i++;
+ }
+ DEBUG ((EFI_D_INFO, "------------------------ END_OF_TABLE ----------------------\n"));
+ }
+ }
+
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ DEBUG ((EFI_D_INFO, " PegPwrOpt[%d].LtrEnable : %x\n", i, mDxePlatformSaPolicy->PcieConfig->PegPwrOpt[i].LtrEnable));
+ DEBUG ((EFI_D_INFO, " PegPwrOpt[%d].LtrMaxSnoopLatency : %x\n", i, mDxePlatformSaPolicy->PcieConfig->PegPwrOpt[i].LtrMaxSnoopLatency));
+ DEBUG ((EFI_D_INFO, " PegPwrOpt[%d].ObffEnable : %x\n", i, mDxePlatformSaPolicy->PcieConfig->PegPwrOpt[i].ObffEnable));
+ DEBUG ((EFI_D_INFO, " PegPwrOpt[%d].LtrMaxNoSnoopLatency : %x\n", i, mDxePlatformSaPolicy->PcieConfig->PegPwrOpt[i].LtrMaxNoSnoopLatency));
+ }
+
+ if (mDxePlatformSaPolicy->Revision >= DXE_SA_PLATFORM_POLICY_PROTOCOL_REVISION_3) {
+ DEBUG ((EFI_D_INFO, "------------------------ SA_SG_VBIOS_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " LoadVbios : %x\n", mDxePlatformSaPolicy->VbiosConfig->LoadVbios));
+ DEBUG ((EFI_D_INFO, " ExecuteVbios : %x\n", mDxePlatformSaPolicy->VbiosConfig->ExecuteVbios));
+ DEBUG ((EFI_D_INFO, " VbiosSource : %x\n", mDxePlatformSaPolicy->VbiosConfig->VbiosSource));
+ }
+
+
+ DEBUG ((EFI_D_INFO, "------------------------ SA_IGD_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " RenderStandby : %x\n", mDxePlatformSaPolicy->IgdConfig->RenderStandby));
+ DEBUG ((EFI_D_INFO, "------------------------ SA_MISC_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " ChapDeviceEnable : %x\n", mDxePlatformSaPolicy->MiscConfig->ChapDeviceEnable));
+ DEBUG ((EFI_D_INFO, " Device4Enable : %x\n", mDxePlatformSaPolicy->MiscConfig->Device4Enable));
+ DEBUG ((EFI_D_INFO, " SubSystemVendorId : %x\n", mDxePlatformSaPolicy->MiscConfig->DefaultSvidSid->SubSystemVendorId));
+ DEBUG ((EFI_D_INFO, " SubSystemId : %x\n", mDxePlatformSaPolicy->MiscConfig->DefaultSvidSid->SubSystemId));
+ DEBUG ((EFI_D_INFO, " CridEnable : %x\n", mDxePlatformSaPolicy->MiscConfig->CridEnable));
+ DEBUG ((EFI_D_INFO, " AudioEnable : %x\n", mDxePlatformSaPolicy->MiscConfig->AudioEnable));
+ DEBUG ((EFI_D_INFO, " FviReport : %x\n", mDxePlatformSaPolicy->MiscConfig->FviReport));
+ DEBUG ((EFI_D_INFO, " FviSmbiosType : %x\n", mDxePlatformSaPolicy->MiscConfig->FviSmbiosType));
+ DEBUG ((EFI_D_INFO, "\n------------------------ SA Platform Policy (DXE) dump END -----------------\n"));
+#endif
+ return;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.dxs b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.dxs
new file mode 100644
index 0000000..03c23ef
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.dxs
@@ -0,0 +1,65 @@
+/** @file
+ @todo ADD DESCRIPTION
+
+@copyright
+ Copyright (c) 1999 - 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
+
+**/
+
+//
+// Common for R8 and R9 codebase
+//
+#include "AutoGen.h"
+#include "DxeDepex.h"
+//
+// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase;
+// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version
+// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase.
+//
+#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB)
+#include "EfiDepex.h"
+#endif
+
+#include EFI_PROTOCOL_DEPENDENCY (SaPlatformPolicy)
+#include EFI_PROTOCOL_DEPENDENCY (PciRootBridgeIo)
+#include EFI_PROTOCOL_DEPENDENCY (BootScriptSave)
+#include EFI_PROTOCOL_DEPENDENCY (AcpiSupport)
+#include EFI_PROTOCOL_DEPENDENCY (PciHostBridgeResourceAllocation)
+#include EFI_PROTOCOL_DEPENDENCY (CpuIo)
+#include EFI_PROTOCOL_DEPENDENCY (DataHub)
+#include EFI_PROTOCOL_DEPENDENCY (PowerMgmtInitDone)
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+#include EFI_PROTOCOL_DEPENDENCY (HiiDatabase)
+#else
+#include EFI_PROTOCOL_DEPENDENCY (HII)
+#endif
+#include EFI_PROTOCOL_DEPENDENCY (FirmwareVolume)
+
+DEPENDENCY_START
+ EFI_ACPI_SUPPORT_GUID AND
+ EFI_DATA_HUB_PROTOCOL_GUID AND
+ EFI_POWER_MGMT_INIT_DONE_PROTOCOL_GUID AND
+ EFI_FIRMWARE_VOLUME_PROTOCOL_GUID AND
+ DXE_PLATFORM_SA_POLICY_GUID AND
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID AND
+ EFI_BOOT_SCRIPT_SAVE_PROTOCOL_GUID AND
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL_GUID AND
+ EFI_CPU_IO_PROTOCOL_GUID AND
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ EFI_HII_DATABASE_PROTOCOL_GUID
+#else
+ EFI_HII_PROTOCOL_GUID
+#endif
+DEPENDENCY_END
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.h
new file mode 100644
index 0000000..a8c2b8f
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.h
@@ -0,0 +1,194 @@
+/** @file
+ Header file for SA Initialization Driver.
+
+@copyright
+ Copyright (c) 1999 - 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
+**/
+#ifndef _SA_INITIALIZATION_DRIVER_H_
+#define _SA_INITIALIZATION_DRIVER_H_
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGlueDxe.h"
+#include "EfiScriptLib.h"
+#include "SaBuildFlags.h"
+#include "LegacyRegion.h"
+#include "Vtd.h"
+#include "GraphicsInit.h"
+#include "IgdOpregion.h"
+#include "PciExpressInit.h"
+#include "AudioInit.h"
+#include "RcFviDxeLib.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+#include "PcieComplex.h"
+#include "VTd.h"
+#include "SwitchableGraphicsInit.h"
+
+///
+/// Driver Consumed Protocol Prototypes
+///
+#include EFI_PROTOCOL_DEFINITION (SaPlatformPolicy)
+#include EFI_PROTOCOL_PRODUCER (SaInfo)
+#endif
+///
+/// Data definitions
+///
+#define CRID_DATA 0x69
+#define CRID_LOCK 0x17
+
+typedef struct {
+ UINT64 BaseAddr;
+ UINT32 Offset;
+ UINT32 AndMask;
+ UINT32 OrMask;
+} BOOT_SCRIPT_REGISTER_SETTING;
+
+typedef struct {
+ UINT64 Address;
+ EFI_BOOT_SCRIPT_WIDTH Width;
+ UINT32 Value;
+} BOOT_SCRIPT_PCI_REGISTER_SAVE;
+
+typedef struct {
+ EFI_SA_INFO_PROTOCOL SaInfo;
+} SA_INSTANCE_PRIVATE_DATA;
+
+typedef struct {
+ UINT8 DeviceNumber;
+ UINT8 FunctionNumber;
+ UINT8 SvidRegOffset;
+} SA_SVID_SID_INIT_ENTRY;
+
+#define SA_FVI_STRING "Reference Code - SA - System Agent"
+#define SA_FVI_SMBIOS_TYPE 0xDD ///< Default value
+#define SA_FVI_SMBIOS_INSTANCE 0x06
+#define MEM_FVI_STRING "Reference Code - MRC"
+#define MEM_RC_VERSION \
+ { \
+ 0xFF, 0xFF, 0xFF, 0xFFFF \
+ }
+#define PCIE_FVI_STRING "SA - PCIe Version"
+#define PCIE_RC_VERSION \
+ { \
+ 0xFF, 0xFF, 0xFF, 0xFFFF \
+ }
+#define SA_CRID_STATUS "SA-CRID Status"
+#define SA_CRID_ORIGINAL_VALUE "SA-CRID Original Value"
+#define SA_CRID_NEW_VALUE "SA-CRID New Value"
+#define SA_CRID_ENABLED "Enabled "
+#define SA_CRID_DISABLED "Disabled"
+#define SA_CRID_VERSION \
+ { \
+ 0xFF, 0xFF, 0xFF, 0xFFFF \
+ }
+#define VBIOS_FVI_STRING "OPROM - VBIOS"
+#define VBIOS_RC_VERSION \
+ { \
+ 0xFF, 0xFF, 0xFF, 0xFFFF \
+ }
+
+enum {
+ SA_RC_VER = 0,
+ MEM_RC_VER,
+ PCIE_VER,
+ CRID_STATUS,
+ CRID_ORIGINAL,
+ CRID_NEW,
+ VBIOS_VER
+} SA_FVI_INDEX;
+
+extern FVI_ELEMENT_AND_FUNCTION mSaFviElementsData[];
+extern FVI_DATA_HUB_CALLBACK_CONTEXT mSaFviVersionData;
+extern UINTN mSaFviElements;
+
+///
+/// Function Prototype
+///
+VOID
+EFIAPI
+SaPciEnumCompleteCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/**
+ This function gets registered as a callback to perform SA initialization before ExitPmAuth
+
+ @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.
+
+ @retval EFI_SUCCESS - Always.
+
+ **/
+;
+
+VOID
+EFIAPI
+SaExitPmAuthCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/**
+ This function gets registered as a callback to perform SA configuration security lock
+
+ @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.
+
+ @retval EFI_SUCCESS - Always.
+
+ **/
+;
+
+VOID
+DeviceConfigure (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ This function performs SA internal devices enabling/disabling
+
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ **/
+;
+
+VOID
+ProgramSvidSid (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Program SA devices Subsystem Vendor Identifier (SVID) and Subsystem Identifier (SID).
+
+ @param[in] DxePlatformSaPolicy The SAPlatform Policy protocol instance
+**/
+;
+
+VOID
+SaDxePolicyDump (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy
+ )
+/**
+ This function prints the DXE phase platform policy.
+
+ @param[in] mDxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ **/
+;
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.inf b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.inf
new file mode 100644
index 0000000..638f6da
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInit.inf
@@ -0,0 +1,137 @@
+## @file
+# Component description file for SystemAgent Initialization driver
+#
+#@copyright
+# Copyright (c) 1999 - 2013 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 = SaInit
+FILE_GUID = DE23ACEE-CF55-4fb6-AA77-984AB53DE811
+COMPONENT_TYPE = BS_DRIVER
+
+[sources.common]
+ SaInit.h
+ SaInit.c
+ LegacyRegion.h
+ LegacyRegion.c
+ Vtd.c
+ Vtd.h
+ IgdOpRegion.h
+ IgdOpRegion.c
+ GraphicsInit.h
+ GraphicsInit.c
+ PciExpressInit.h
+ PciExpressInit.c
+ PcieComplex.c
+ PcieComplex.h
+ AudioInit.c
+ AudioInit.h
+ SaFvi.c
+ SwitchableGraphicsInit.c
+ SwitchableGraphicsInit.h
+
+#
+# Edk II Glue Driver Entry Point
+#
+ EdkIIGlueDxeDriverEntryPoint.c
+
+[includes.common]
+ .
+ ../Common
+ $(EDK_SOURCE)/Foundation
+ $(EDK_SOURCE)/Foundation/Efi
+ $(EDK_SOURCE)/Foundation/Library
+ $(EDK_SOURCE)/Foundation/Efi/Include
+ $(EDK_SOURCE)/Foundation/core/Dxe
+ $(EDK_SOURCE)/Foundation/Include
+ $(EDK_SOURCE)/Foundation/Include/IndustryStandard
+ $(EDK_SOURCE)/Foundation/Framework
+ $(EDK_SOURCE)/Foundation/Framework/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include/pcd
+ $(EDK_SOURCE)/Foundation/Library/Dxe/Include
+ $(EDK_SOURCE)/Foundation/Cpu/Pentium/Include
+ $(EDK_SOURCE)/Foundation/Library/Dxe/UefiEfiIfrSupportLib
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Protocol
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Library/SaPcieLib/Common
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Protocol
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include/Library
+ $(EFI_SOURCE)
+ $(EFI_SOURCE)/../MdePkg/Include
+
+#
+# Typically, the sample code referenced will be available in the code base already.
+# So, keep this include at the end to defer to the source base definition
+# and only use the sample code definition if source base does not include these files.
+#
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/SampleCode
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/SampleCode/Include
+
+[libraries.common]
+ EfiProtocolLib
+ EdkGuidLib
+ EfiCommonLib
+ EfiScriptLib
+ EdkIIGlueBaseLib
+ EdkIIGlueBaseIoLibIntrinsic
+ EdkIIGlueBaseMemoryLib
+ EdkIIGlueBasePciExpressLib
+ EdkIIGlueDxeReportStatusCodeLib
+ EdkIIGlueDxeDebugLibReportStatusCode
+ EdkIIGlueUefiBootServicesTableLib
+ EdkIIGlueUefiRuntimeServicesTableLib
+ EdkIIGlueDxeServicesTableLib
+ EdkIIGlueDxeHobLib
+ EdkIIGlueUefiLib
+ EdkIIGlueBasePciLibPciExpress
+ $(PROJECT_SA_FAMILY)ProtocolLib
+ $(PROJECT_PCH_FAMILY)ProtocolLib
+ RcFviDxeLib
+ PchPlatformLib
+ UefiEfiIfrSupportLib
+ SaGuidLib
+ EdkProtocolLib
+ CpuPlatformLib
+#
+# Comment out SaPcieDxeLib if ASPM initialization in DXE phase was not supported
+#
+ SaPcieDxeLib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT = _ModuleEntryPoint
+ DPX_SOURCE = SaInit.dxs
+
+ C_FLAGS = $(C_FLAGS) -D"__EDKII_GLUE_MODULE_ENTRY_POINT__=SaInitEntryPoint" \
+ -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ -D __EDKII_GLUE_BASE_LIB__ \
+ -D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ -D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \
+ -D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \
+ -D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ -D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__\
+ -D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \
+ -D __EDKII_GLUE_DXE_HOB_LIB__ \
+ -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \
+ -D __EDKII_GLUE_UEFI_LIB__
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.cif b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.cif
new file mode 100644
index 0000000..f705e96
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.cif
@@ -0,0 +1,30 @@
+<component>
+ name = "SaInitDxe"
+ category = ModulePart
+ LocalRoot = "ReferenceCode\Chipset\SystemAgent\SaInit\Dxe"
+ RefName = "SaInitDxe"
+[files]
+"SaInitDxe.sdl"
+"SaInitDxe.mak"
+"SaInit.c"
+"SaInit.dxs"
+"SaInit.h"
+"SaInit.inf"
+"graphicsinit.c"
+"graphicsinit.h"
+"igdopregion.c"
+"igdopregion.h"
+"LegacyRegion.c"
+"LegacyRegion.h"
+"PcieComplex.c"
+"PcieComplex.h"
+"PciExpressInit.c"
+"PciExpressInit.h"
+"VTd.c"
+"VTd.h"
+"AudioInit.c"
+"AudioInit.h"
+"SaFvi.c"
+"SwitchableGraphicsInit.c"
+"SwitchableGraphicsInit.h"
+<endComponent>
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.mak b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.mak
new file mode 100644
index 0000000..809ba05
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.mak
@@ -0,0 +1,86 @@
+#---------------------------------------------------------------------------
+# Create SaInitDxe Driver
+#---------------------------------------------------------------------------
+EDK : SaInitDxe
+
+SaInitDxe: $(BUILD_DIR)\SaInitDxe.mak SaInitDxeBin
+
+$(BUILD_DIR)\SaInitDxe.mak : $(SaInitDxe_DIR)\$(@B).cif $(SaInitDxe_DIR)\$(@B).mak $(BUILD_RULES)
+ $(CIF2MAK) $(SaInitDxe_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS)
+
+SaInitDxe_INCLUDES=\
+ $(EdkIIGlueLib_INCLUDES)\
+ $(INTEL_MCH_INCLUDES) \
+ $(INTEL_PCH_INCLUDES)\
+ $(IndustryStandard_INCLUDES)\
+ $(INTEL_PLATFORM_PROTOCOL_INCLUDES)\
+ $(PROJECT_CPU_INCLUDES)\
+ /I$(INTEL_SYSTEM_AGENT_DIR)\Library\SaPcieLib\Common\
+ /I$(INTEL_SYSTEM_AGENT_DIR)\SampleCode\
+
+SaInitDxe_DEFINES =$(MY_DEFINES)\
+ /D "__EDKII_GLUE_MODULE_ENTRY_POINT__=SaInitEntryPoint" \
+ /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ /D __EDKII_GLUE_BASE_LIB__ \
+ /D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ /D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \
+ /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \
+ /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__\
+ /D __EDKII_GLUE_DXE_HOB_LIB__ \
+ /D __EDKII_GLUE_UEFI_LIB__\
+ /D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \
+ /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \
+
+SaInitDxe_LIB_LINKS =\
+ $(EFIPROTOCOLLIB)\
+ $(EDKGUIDLIB)\
+ $(EFICOMMONLIB)\
+ $(EFISCRIPTLIB)\
+ $(EdkIIGlueBaseLib_LIB)\
+!IF "$(x64_BUILD)"=="1"
+ $(EdkIIGlueBaseLibX64_LIB)\
+!ELSE
+ $(EdkIIGlueBaseLibIA32_LIB)\
+!ENDIF
+ $(EdkIIGlueBaseIoLibIntrinsic_LIB)\
+ $(EdkIIGlueBaseMemoryLib_LIB)\
+ $(EdkIIGlueDxeReportStatusCodeLib_LIB)\
+ $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\
+ $(EdkIIGlueUefiBootServicesTableLib_LIB)\
+ $(EdkIIGlueDxeServicesTableLib_LIB)\
+ $(EdkIIGlueDxeHobLib_LIB)\
+ $(EdkIIGlueUefiLib_LIB)\
+ $(INTEL_SA_PROTOCOL_LIB)\
+ $(INTEL_PCH_PROTOCOL_LIB)\
+ $(IntelPlatformProtocolLib_LIB)\
+!IF $(EFI_SPECIFICATION_VERSION) >= 0x0002000A
+ $(UEFIEFIIFRSUPPORTLIB)\
+!ELSE
+ $(EFIIFRSUPPORTLIB) \
+!ENDIF
+ $(SaGuidLib_LIB)\
+ $(EdkIIGlueBasePciExpressLib_LIB)\
+ $(EdkIIGlueUefiRuntimeServicesTableLib_LIB)\
+ $(EdkIIGlueBasePciLibPciExpress_LIB)\
+ $(EDKPROTOCOLLIB)\
+ $(RcFviDxeLib_LIB)\
+ $(PchPlatformDxeLib_LIB)\
+ $(CpuPlatformLib_LIB)\
+#
+# Comment out SaPcieDxeLib if ASPM initialization in DXE phase was not supported
+#
+ $(SaPcieDxeLib_LIB)\
+
+SaInitDxeBin: $(SaInitDxe_LIB_LINKS)
+ $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\
+ /f $(BUILD_DIR)\SaInitDxe.mak all \
+ "MY_INCLUDES=$(SaInitDxe_INCLUDES)"\
+ "MY_DEFINES=$(SaInitDxe_DEFINES)"\
+ GUID=DE23ACEE-CF55-4fb6-AA77-984AB53DE811\
+ ENTRY_POINT=_ModuleEntryPoint \
+ TYPE=BS_DRIVER\
+ EDKIIModule=DXEDRIVER\
+ DEPEX1=$(SaInitDxe_DIR)\SaInit.dxs\
+ DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX\
+ COMPRESS=1
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.sdl b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.sdl
new file mode 100644
index 0000000..e4a95b4
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SaInitDxe.sdl
@@ -0,0 +1,24 @@
+TOKEN
+ Name = "SaInitDxe_SUPPORT"
+ Value = "1"
+ Help = "Main switch to enable SaInitDxe support in Project"
+ TokenType = Boolean
+ TargetEQU = Yes
+ TargetMAK = Yes
+ Master = Yes
+End
+
+PATH
+ Name = "SaInitDxe_DIR"
+End
+
+MODULE
+ File = "SaInitDxe.mak"
+ Help = "Includes SaInitDxe.mak to Project"
+End
+
+ELINK
+ Name = "$(BUILD_DIR)\SaInitDxe.ffs"
+ Parent = "FV_MAIN"
+ InvokeOrder = AfterParent
+End \ No newline at end of file
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.c
new file mode 100644
index 0000000..599a01a
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.c
@@ -0,0 +1,958 @@
+/** @file
+ SwitchableGraphics Dxe driver.
+ This DXE driver loads SwitchableGraphics acpi tables
+ for the platform.
+
+@copyright
+ Copyright (c) 2010 - 2013 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 "SwitchableGraphicsInit.h"
+#include EFI_PROTOCOL_CONSUMER (ExitPmAuth)
+#include <Token.h> //<< AMI_OVERRIDE >>
+
+extern DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy;
+
+EFI_BOOT_SERVICES *gBS;
+SA_DATA_HOB *SaDataHob;
+
+EFI_GUID gSaDataHobGuid = SA_DATA_HOB_GUID;
+EFI_GUID gSgAcpiTableStorageGuid = SG_ACPI_TABLE_STORAGE_GUID;
+EFI_GUID gSgAcpiTablePchStorageGuid = SG_ACPI_TABLE_PCH_STORAGE_GUID;
+
+VOID *VbiosAddress = NULL;
+BOOLEAN DgpuOpRomCopied;
+UINT32 VbiosSize;
+
+UINT8 EndpointBus;
+UINT16 GpioBaseAddress;
+UINT8 GpioSupport;
+
+UINT8 RootPortDev;
+UINT8 RootPortFun;
+
+CPU_FAMILY CpuFamilyId;
+
+// AMI MODIFY BEGIN
+EFI_STATUS
+LoadTpvAcpiTables(
+ VOID
+ );
+// AMI MODIFY END
+
+/**
+ Initialize the SwitchableGraphics support (DXE).
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - SwitchableGraphics initialization complete
+ @retval EFI_OUT_OF_RESOURCES - Unable to allocated memory
+ @retval EFI_NOT_FOUND - SA DataHob not found
+ @retval EFI_DEVICE_ERROR - Error Accessing SG GPIO
+**/
+EFI_STATUS
+SwitchableGraphicsInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+ UINTN PciD31F0RegBase;
+ UINT32 RootComplexBar;
+ UINT32 RpFn;
+
+ CpuFamilyId = GetCpuFamily();
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ /// For SwitchableGraphics support the dGPU is present on PCH RootPort
+ RootPortDev = PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS;
+ //AMI override begin
+ RootPortFun = SG_ULT_PORT_FUNC;
+ //RootPortFun = PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_5;
+ //AMI override end
+
+ PciD31F0RegBase = MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ 0
+ );
+ RootComplexBar = MmioRead32 (PciD31F0RegBase + R_PCH_LPC_RCBA) & B_PCH_LPC_RCBA_BAR;
+ RpFn = MmioRead32 (RootComplexBar + R_PCH_RCRB_RPFN);
+ /// dGPU sits on Root Port 5 [1-based]
+ /// Root Port 5 Function Number (RP5FN) = RPFN[18:16]
+ //AMI override begin
+ //RootPortFun = (UINT8) ((RpFn >> (4 * S_PCH_RCRB_PRFN_RP_FIELD)) & B_PCH_RCRB_RPFN_RP1FN);
+ RootPortFun = (UINT8) ((RpFn >> (RootPortFun * S_PCH_RCRB_PRFN_RP_FIELD)) & B_PCH_RCRB_RPFN_RP1FN);
+ ////AMI override end
+ } else {
+ /// Assume: For SwitchableGraphics support the dGPU is present on PEG RootPort by default
+ RootPortDev = SA_PEG10_DEV_NUM;
+ RootPortFun = SA_PEG10_FUN_NUM;
+ }
+
+ DEBUG ((EFI_D_INFO, "dGPU Rootport info[B/D/F] : [0x00/0x%x/0x%x]\n", RootPortDev, RootPortFun));
+
+ gBS = SystemTable->BootServices;
+
+ ///
+ /// Get SG GPIO info from SA HOB.
+ ///
+ Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, (VOID **) &SaDataHob);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SaDataHob = GetNextGuidHob (&gSaDataHobGuid, SaDataHob);
+ if (SaDataHob == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ GpioSupport = SaDataHob->SgInfo.SgGpioSupport;
+
+ ///
+ /// Read GPIO base
+ ///
+ GpioBaseAddress = McDevFunPciCfg16 (0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GPIO_BASE) &~BIT0;
+ if (GpioBaseAddress == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ///
+ /// Update GlobalNvs data for runtime usage
+ ///
+ Status = UpdateGlobalNvsData (SaDataHob->SgInfo, DxePlatformSaPolicy);
+// AMI MODIFY BEGIN
+ DEBUG ((EFI_D_INFO, "SG:: OEM SSDT start"));
+#if SGOEMSSDT_SUPPORT
+ // Load OEM SSDT
+ if (SaDataHob->SgInfo.SgMode == SgModeDgpu) { // In PEG mode
+
+ DEBUG ((EFI_D_INFO, "SG:: OEM SSDT start1"));
+ Status = LoadAndExecuteDgpuVbios (mDxePlatformSaPolicy->VbiosConfig);
+ return Status;
+ }
+#endif
+// AMI MODIFY END
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ///
+ /// Load Intel SG SSDT tables
+ ///
+ Status = LoadAcpiTables ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ///
+ /// Check to see if Switchable Graphics Mode is enabled
+ ///
+ if (SaDataHob->SgInfo.SgMode == SgModeMuxless) {
+ ///
+ /// Create ReadyToBoot callback for SG
+ ///
+ EfiCreateProtocolNotifyEvent (
+ &gExitPmAuthProtocolGuid,
+ EFI_TPL_CALLBACK,
+ SgExitPmAuthCallback,
+ NULL,
+ &Registration
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Initialize the runtime SwitchableGraphics support data for ACPI tables in GlobalNvs.
+
+ @param[in] SaDataHob->SgInfo - Pointer to Hob for SG system details.
+ @param[in] DxePlatformSaPolicy - Pointer to the loaded image protocol for this driver.
+
+ @retval EFI_SUCCESS - The data updated successfully.
+**/
+EFI_STATUS
+UpdateGlobalNvsData (
+ IN SG_INFO_HOB SgInfo,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+{
+ SYSTEM_AGENT_GLOBAL_NVS_AREA_PROTOCOL *SaGlobalNvsArea;
+ UINT8 CapOffset;
+ UINT16 ExtendedCapOffset;
+ EFI_STATUS Status;
+ UINT32 Data32;
+
+ ///
+ /// Locate the SA Global NVS Protocol.
+ ///
+ Status = gBS->LocateProtocol (
+ &gSaGlobalNvsAreaProtocolGuid,
+ NULL,
+ (VOID **) &SaGlobalNvsArea
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ///
+ /// SG Mode for ASL usage
+ ///
+ SaGlobalNvsArea->Area->SgMode |= SaDataHob->SgInfo.SgMode;
+
+ SaGlobalNvsArea->Area->PXFixedDynamicMode = SaDataHob->SgInfo.PXFixedDynamicMode; // AMI_OVERRIDE_FOR ATI 5.0 Fixed/Dynamic
+
+ SaGlobalNvsArea->Area->GpioBaseAddress = GpioBaseAddress;
+
+ SaGlobalNvsArea->Area->SgGPIOSupport = SaDataHob->SgInfo.SgGpioSupport;
+
+ DEBUG ((EFI_D_INFO, "SG:: Switchable Graphics Mode : 0x%x\n", SaDataHob->SgInfo.SgMode));
+
+ if (SaDataHob->SgInfo.SgMode == SgModeMuxless) {
+ ///
+ /// SG Feature List for ASL usage
+ ///
+ //SaGlobalNvsArea->Area->SgFeatureList |= DxePlatformSaPolicy->FeatureList->WirelessDisplay;
+
+ if (SaDataHob->SgInfo.SgGpioSupport) {
+ ///
+ /// GPIO Assignment for ASL usage
+ ///
+ SaGlobalNvsArea->Area->SgDgpuPwrOK = SaDataHob->SgInfo.SgDgpuPwrOK;
+ SaGlobalNvsArea->Area->SgDgpuHoldRst = SaDataHob->SgInfo.SgDgpuHoldRst;
+ SaGlobalNvsArea->Area->SgDgpuPwrEnable = SaDataHob->SgInfo.SgDgpuPwrEnable;
+ SaGlobalNvsArea->Area->SgDgpuPrsnt = SaDataHob->SgInfo.SgDgpuPrsnt;
+
+ DEBUG ((EFI_D_INFO, "SG:: dGPU_PWROK GPIO GPIO assigned = %d\n", SaDataHob->SgInfo.SgDgpuPwrOK & 0x7f));
+ DEBUG ((EFI_D_INFO, "SG:: dGPU_HOLD_RST# GPIO assigned = %d\n", SaDataHob->SgInfo.SgDgpuHoldRst & 0x7f));
+ DEBUG ((EFI_D_INFO, "SG:: dGPU_PWR_EN# GPIO assigned = %d\n", SaDataHob->SgInfo.SgDgpuPwrEnable & 0x7f));
+ DEBUG ((EFI_D_INFO, "SG:: dGPU_PRSNT# GPIO assigned = %d\n", SaDataHob->SgInfo.SgDgpuPrsnt & 0x7f));
+ }
+
+ DEBUG ((EFI_D_INFO, "SG:: VBIOS Configurations:\n"));
+ DEBUG (
+ (
+ EFI_D_INFO, "SG:: Load VBIOS (0=No Vbios;1=Load VBIOS) =%d\n", DxePlatformSaPolicy->VbiosConfig->
+ LoadVbios
+ )
+ );
+ DEBUG (
+ (
+ EFI_D_INFO, "SG:: Execute VBIOS (0=Do not execute;1=Execute Vbios) =%d\n", DxePlatformSaPolicy->VbiosConfig->
+ ExecuteVbios
+ )
+ );
+ DEBUG (
+ (
+ EFI_D_INFO, "SG:: VBIOS Source (0=PCIE Card;1=FW Volume) =%d\n", DxePlatformSaPolicy->VbiosConfig->
+ VbiosSource
+ )
+ );
+
+ ///
+ /// PEG Endpoint Base Addresses and Capability Structure Offsets for ASL usage
+ ///
+
+ ///
+ /// Save bus numbers on the PEG/PCH bridge.
+ ///
+ Data32 = MmPci32 (0, 0, RootPortDev, RootPortFun, PCI_PBUS);
+ Data32 &= 0x00FFFF00;
+
+ ///
+ /// Set PEG/PCH PortBus = 1 to Read Endpoint.
+ ///
+ MmPci32AndThenOr (0, 0, RootPortDev, RootPortFun, PCI_PBUS, 0xFF0000FF, 0x00010100);
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ McDevFunPciCfg16 (1, 0, 0, PCI_VID) = 0;
+
+ EndpointBus = MmPci8 (0, 0, RootPortDev, RootPortFun, PCI_SBUS);
+
+ if (EndpointBus != 0xFF) {
+ //AMI override begin
+ SaGlobalNvsArea->Area->EndpointBaseAddress = (UINT32) (MmPciAddress (0, EndpointBus, 0, 0, 0x0));
+ //AMI override end
+ SaGlobalNvsArea->Area->CapStrPresence = 0;
+
+ CapOffset = (UINT8) PcieFindCapId (EndpointBus, 0, 0, PEG_CAP_ID);
+ SaGlobalNvsArea->Area->EndpointPcieCapOffset = CapOffset;
+ DEBUG ((EFI_D_INFO, "SG:: Endpoint PCI Express Capability Offset : 0x%x\n", SaGlobalNvsArea->Area->EndpointPcieCapOffset));
+
+ ExtendedCapOffset = (UINT16) PcieFindExtendedCapId (EndpointBus, 0, 0, PEG_CAP_VER);
+ if (ExtendedCapOffset != 0) {
+ SaGlobalNvsArea->Area->CapStrPresence |= BIT0;
+ SaGlobalNvsArea->Area->EndpointVcCapOffset = ExtendedCapOffset;
+ DEBUG ((EFI_D_INFO, "SG:: Endpoint Virtual Channel Capability Offset : 0x%x\n", SaGlobalNvsArea->Area->EndpointVcCapOffset));
+ }
+ }
+
+ ///
+ /// Restore bus numbers on the PEG/PCH bridge.
+ ///
+ MmPci32AndThenOr (0, 0, RootPortDev, RootPortFun, PCI_PBUS, 0xFF0000FF, Data32);
+ } else {
+ DEBUG ((EFI_D_ERROR, "SG:: Switchable Graphics Mode disabled!!!\n"));
+ Status = EFI_LOAD_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Load and execute the dGPU VBIOS.
+
+ @param[in] VbiosConfig - Pointer to VbiosConfig policy for Load/Execute and VBIOS Source.
+ LoadVbios - 0 = Do Not Load ; 1 = Load VBIOS
+ ExecuteVbios - 0 = Do Not Execute; 1 = Execute VBIOS
+ VbiosSource - 0 = PCIE Device ; 1 = FirmwareVolume => TBD
+
+ @retval EFI_SUCCESS - Load and execute successful.
+ @exception EFI_UNSUPPORTED - Secondary VBIOS not loaded.
+**/
+EFI_STATUS
+LoadAndExecuteDgpuVbios (
+ IN SA_SG_VBIOS_CONFIGURATION *VbiosConfig
+ )
+{
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ VBIOS_PCIR_STRUCTURE *PcirBlockPtr;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ VBIOS_OPTION_ROM_HEADER *VBiosRomImage;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_IA32_REGISTER_SET RegSet;
+ EFI_PHYSICAL_ADDRESS ImageLocation;
+ UINTN Offset;
+
+ HandleBuffer = NULL;
+ DgpuOpRomCopied = FALSE;
+
+ DEBUG ((EFI_D_INFO, "SG:: LoadAndExecuteDgpuVbios\n"));
+
+ ///
+ /// Endpoint Device Bus#
+ ///
+ EndpointBus = MmPci8 (0, 0, RootPortDev, RootPortFun, PCI_SBUS);
+
+ ///
+ /// Endpoint Device Not found
+ ///
+ if (EndpointBus == 0xFF) {
+ DEBUG ((EFI_D_ERROR, "SG:: 0x00/0x%x/0x%x Rootport's Endpoint Device Not found\n", RootPortDev, RootPortFun));
+ return EFI_UNSUPPORTED;
+ }
+
+ ///
+ /// Check Policy setting for loading VBIOS
+ ///
+ if (VbiosConfig->LoadVbios != 0) {
+
+ DEBUG ((EFI_D_INFO, "SG:: Start to load dGPU VBIOS if available\n"));
+
+ ///
+ /// Set as if an umcompressed video BIOS image was not obtainable.
+ ///
+ VBiosRomImage = NULL;
+
+ ///
+ /// Get all PCI IO protocols
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ///
+ /// Find the video BIOS by checking each PCI IO handle for DGPU video
+ /// BIOS OPROM.
+ ///
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status) || (PciIo->RomImage == NULL)) {
+ ///
+ /// If this PCI device doesn't have a ROM image, skip to the next device.
+ ///
+ continue;
+ }
+
+ VBiosRomImage = PciIo->RomImage;
+
+ ///
+ /// Get pointer to PCIR structure
+ ///
+ PcirBlockPtr = (VBIOS_PCIR_STRUCTURE *) ((UINTN) VBiosRomImage + VBiosRomImage->PcirOffset);
+ //AMI override begin
+ if (( PcirBlockPtr->VendorId != 0x10DE) && (PcirBlockPtr->VendorId != 0x1002)){
+ continue;
+ }
+ //AMI override end
+ ///
+ /// Check if we have an video BIOS OPROM for DGPU.
+ ///
+ if ((VBiosRomImage->Signature == OPTION_ROM_SIGNATURE) &&
+ (McDevFunPciCfg16 (EndpointBus, 0, 0, PCI_VID) == PcirBlockPtr->VendorId) &&
+ (PcirBlockPtr->ClassCode[2] == 0x03)
+ ) {
+
+ DEBUG ((EFI_D_INFO, "SG:: Loading dGPU VBIOS...\n"));
+
+ ///
+ /// Allocate space for copying Oprom
+ ///
+ VbiosSize = (PcirBlockPtr->ImageLength) * 512;
+ Status = (gBS->AllocatePool) (EfiBootServicesData, VbiosSize, &VbiosAddress);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ///
+ /// Execute VBIOS based on Policy setting
+ ///
+ if (VbiosConfig->ExecuteVbios) {
+ DEBUG ((EFI_D_INFO, "SG:: Execute dGPU VBIOS...\n"));
+ ///
+ /// Memory IO Bus Master needs to be enabled when we execute the vbios
+ ///
+ ///
+ /// Enable Memory Access, IO Access Bus Master enable on PEG/PCH ROOT PORT
+ ///
+ MmPci16Or (0, 0, RootPortDev, RootPortFun, PCI_CMD, BIT0 + BIT1 + BIT2);
+
+ ///
+ /// Enable Memory Access, IO Access Bus Master enable and Rom Enable on Peg/PCH Endpoint device
+ ///
+ McDevFunPciCfg16Or (EndpointBus, 0, 0, PCI_CMD, BIT0 + BIT1 + BIT2);
+
+ ///
+ /// Allocate 64kb under 1MB memory region
+ ///
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ CONVENTIONAL_MEMORY_TOP,
+ (BIN_FILE_SIZE_MAX / 4096),
+ &ImageLocation
+ );
+ if (!EFI_ERROR (Status)) {
+ (gBS->SetMem) ((VOID *) (UINTN) ImageLocation, BIN_FILE_SIZE_MAX, 0);
+
+ ///
+ /// After allocation copy VBIOS to buffer
+ ///
+ (gBS->CopyMem) ((VOID *) (UINTN) ImageLocation, PciIo->RomImage, VbiosSize);
+
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+ if (!EFI_ERROR (Status)) {
+ (gBS->SetMem) (&RegSet, sizeof (EFI_IA32_REGISTER_SET), 0);
+
+ RegSet.H.AH = MmPci8 (0, 0, RootPortDev, RootPortFun, PCI_SBUS);
+ Offset = MemoryRead16 ((UINTN) ImageLocation + 0x40);
+ LegacyBios->FarCall86 (
+ LegacyBios,
+ ((UINT16) RShiftU64 ((ImageLocation & 0x000FFFF0),
+ 4)),
+ ((UINT16) Offset),
+ &RegSet,
+ NULL,
+ 0
+ );
+
+ Offset = MemoryRead16 ((UINTN) ImageLocation + 0x42) + (UINTN) ImageLocation;
+ if (MemoryRead16 ((UINTN) ImageLocation + 0x44) == 0x0) {
+ VbiosSize = MemoryRead8 ((UINTN) ImageLocation + 0x2) * 512;
+ } else {
+ VbiosSize = MemoryRead16 ((UINTN) ImageLocation + 0x44) * 512;
+ }
+ ///
+ /// Copy Oprom to allocated space for the following scenario:
+ /// # Load vbios and Execute vbios policy setting
+ ///
+ DEBUG ((EFI_D_INFO, "Copy Oprom to allocated space: Load & Execute policy satisfied\n"));
+ (gBS->CopyMem) (VbiosAddress, (VOID *) Offset, VbiosSize);
+ DgpuOpRomCopied = TRUE;
+ (gBS->SetMem) ((VOID *) (UINTN) ImageLocation, BIN_FILE_SIZE_MAX, 0);
+ }
+ (gBS->FreePages) (ImageLocation, (BIN_FILE_SIZE_MAX / 4096));
+ }
+
+ ///
+ /// Disable Memory Access, IO Access Bus Master enable and Rom Enable on PEG/PCH Endpoint device
+ ///
+ McDevFunPciCfg16And (EndpointBus, 0, 0, PCI_CMD, ~(BIT0 + BIT1 + BIT2));
+
+ ///
+ /// Disable Memory Access, IO Access Bus Master enable on PEG/PCH Root Port
+ ///
+ MmPci16And (0, 0, RootPortDev, RootPortFun, PCI_CMD, ~(BIT0 + BIT1 + BIT2));
+ }
+
+ ///
+ /// Copy Oprom to allocated space for the following scenario:
+ /// # Load vbios and Execute vbios policy setting in which dGPU execution is not called
+ /// # Load vbios but don't Execute vbios policy setting
+ ///
+ if ((VbiosAddress!=NULL) && (!DgpuOpRomCopied)) {
+ DEBUG ((EFI_D_INFO, "Copy Oprom to allocated space: Load policy satisfied\n"));
+ (gBS->CopyMem) (VbiosAddress, PciIo->RomImage, VbiosSize);
+ DgpuOpRomCopied = TRUE;
+ }
+
+ // AMI MODIFY BEGIN
+ //
+ //
+#ifdef AMI_SgTpv_SUPPORT
+ if (!EFI_ERROR (Status)) {
+ Status = LoadTpvAcpiTables ();
+ }
+#endif // AMI_SgTpv_SUPPORT
+ //
+ // AMI MODIFY ENDS
+ //
+ break;
+ }
+ }
+
+ }
+
+
+ if (VbiosAddress!=NULL) {
+ (gBS->FreePool) (VbiosAddress);
+ }
+
+ if (HandleBuffer!=NULL) {
+ (gBS->FreePool) (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read SG GPIO value
+
+ @param[in] Value - PCH GPIO number and Active value
+ Bit0 to Bit7 - PCH GPIO Number
+ Bit8 - GPIO Active value (0 = Active Low; 1 = Active High)
+
+ @retval GPIO read value.
+**/
+BOOLEAN
+GpioRead (
+ IN UINT8 Value
+ )
+{
+ BOOLEAN Active;
+ UINT32 Data;
+ UINT16 BitOffset=0;
+ UINT16 Offset=0;
+
+ ///
+ /// Check if SG GPIOs are supported
+ ///
+ if (GpioSupport == 0) {
+ return FALSE;
+ }
+ ///
+ /// Extract GPIO number and Active value
+ ///
+ Active = (BOOLEAN) (Value >> 7);
+ Value &= 0x7F;
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ Offset = R_PCH_GP_N_CONFIG0 + (Value * 0x08);
+ BitOffset = 30; //GPI_LVL
+ } else {
+ if (Value < 0x20) {
+ Offset = R_PCH_GPIO_LVL;
+ BitOffset = Value;
+ } else if (Value < 0x40) {
+ Offset = R_PCH_GPIO_LVL2;
+ BitOffset = Value - 0x20;
+ } else {
+ Offset = R_PCH_GPIO_LVL3;
+ BitOffset = Value - 0x40;
+ }
+ }
+
+ ///
+ /// Read specified value GPIO
+ ///
+ Data = IoRead32 (GpioBaseAddress + Offset);
+ Data >>= BitOffset;
+
+ if (Active == 0) {
+ Data = ~Data;
+ }
+
+ return (BOOLEAN) (Data & 0x1);
+}
+
+/**
+ Write SG GPIO value
+
+ @param[in] Value - PCH GPIO number and Active value
+ Bit0 to Bit7 - PCH GPIO Number
+ Bit8 - GPIO Active value (0 = Active Low; 1 = Active High)
+ @param[in] Level - Write data (0 = Disable; 1 = Enable)
+**/
+VOID
+GpioWrite (
+ IN UINT8 Value,
+ IN BOOLEAN Level
+ )
+{
+ BOOLEAN Active;
+ UINT32 Data;
+ UINT16 BitOffset=0;
+ UINT16 Offset=0;
+
+ ///
+ /// Check if SG GPIOs are supported
+ ///
+ if (GpioSupport == 0) {
+ return ;
+ }
+
+ Active = (BOOLEAN) (Value >> 7);
+ Value &= 0x7F;
+
+ if (Active == 0) {
+ Level = (~Level) & 0x1;
+ }
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ Offset = R_PCH_GP_N_CONFIG0 + (Value * 0x08);
+ BitOffset = 31; //GPO_LVL
+ } else {
+ if (Value < 0x20) {
+ Offset = R_PCH_GPIO_LVL;
+ BitOffset = Value;
+ } else if (Value < 0x40) {
+ Offset = R_PCH_GPIO_LVL2;
+ BitOffset = Value - 0x20;
+ } else {
+ Offset = R_PCH_GPIO_LVL3;
+ BitOffset = Value - 0x40;
+ }
+ }
+
+ Data = IoRead32 (GpioBaseAddress + Offset);
+ Data &= ~(0x1 << BitOffset);
+ Data |= (Level << BitOffset);
+ IoWrite32 (GpioBaseAddress + Offset, Data);
+
+ return ;
+}
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param[in] AllocateType - Allocated Legacy Memory Type
+ @param[in] StartPageAddress - Start address of range
+ @param[in] Pages - Number of pages to allocate
+ @param[in, out] Result - Result of allocation
+
+ @retval EFI_SUCCESS - Legacy16 code loaded
+ @retval Other - No protocol installed, unload driver.
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemPage;
+
+ ///
+ /// Allocate Pages of memory less <= StartPageAddress
+ ///
+ MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;
+ Status = (gBS->AllocatePages) (AllocateType, EfiBootServicesCode, Pages, &MemPage);
+
+ ///
+ /// Do not ASSERT on Status error but let caller decide since some cases
+ /// memory is already taken but that is ok.
+ ///
+ if (!EFI_ERROR (Status)) {
+ *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;
+ }
+
+ return Status;
+}
+
+/**
+ Load Intel SG SSDT Tables
+
+ @param[in] None
+
+ @retval EFI_SUCCESS - SG SSDT Table load successful.
+**/
+EFI_STATUS
+LoadAcpiTables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ BOOLEAN LoadTable;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ INTN Instance;
+ UINTN Size;
+ UINT32 FvStatus;
+ UINTN TableHandle;
+ EFI_GUID AcpiTableGuid;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ EFI_ACPI_TABLE_VERSION Version;
+ EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
+ EFI_ACPI_COMMON_HEADER *Table;
+
+ FwVol = NULL;
+ Table = NULL;
+
+ AcpiTableGuid = gSgAcpiTableStorageGuid;
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ AcpiTableGuid = gSgAcpiTablePchStorageGuid;
+ }
+
+ DEBUG ((EFI_D_INFO, "SG:: Loading ACPI Tables...\n"));
+
+ ///
+ /// Locate FV protocol.
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Look 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],
+ &gEfiFirmwareVolumeProtocolGuid,
+ (VOID **) &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (FwVol == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &AcpiTableGuid,
+ 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);
+
+ ///
+ /// Sanity check that we found our data file
+ ///
+ ASSERT (FwVol);
+
+ ///
+ /// By default, a table belongs in all ACPI table versions published.
+ ///
+ Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
+
+ ///
+ /// Locate ACPI tables
+ ///
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+
+ ///
+ /// Read tables from the storage file.
+ ///
+ if (FwVol == NULL) {
+ ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+ return EFI_NOT_FOUND;
+ }
+ Instance = 0;
+
+ while (Status == EFI_SUCCESS) {
+ ///
+ /// Read the ACPI tables
+ ///
+ Status = FwVol->ReadSection (
+ FwVol,
+ &AcpiTableGuid,
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID **) &Table,
+ &Size,
+ &FvStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// check and load SwitchableGraphics SSDT table
+ ///
+ LoadTable = FALSE;
+ TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
+
+ if (((EFI_ACPI_DESCRIPTION_HEADER *) TableHeader)->OemTableId == EFI_SIGNATURE_64 (
+ 'S',
+ 'g',
+ 'P',
+ 'e',
+ 'g',
+ 0,
+ 0,
+ 0
+ )
+ ) {
+ ///
+ /// This is SG SSDT [dGPU is present on PEG RootPort]
+ ///
+ DEBUG ((EFI_D_INFO, "SG:: ---- SG SSDT ----\n"));
+ DEBUG ((EFI_D_INFO, "SG:: Found out SSDT:SgPeg [SgSsdt.asl]. dGPU is present on PEG RootPort.\n"));
+ LoadTable = TRUE;
+ }
+
+ if (((EFI_ACPI_DESCRIPTION_HEADER *) TableHeader)->OemTableId == EFI_SIGNATURE_64 (
+ 'S',
+ 'g',
+ 'P',
+ 'c',
+ 'h',
+ 0,
+ 0,
+ 0
+ )
+ ) {
+ ///
+ /// This is SG SSDT [dGPU is present on PCH RootPort]
+ ///
+ DEBUG ((EFI_D_INFO, "SG:: ---- SG SSDT ----\n"));
+ DEBUG ((EFI_D_INFO, "SG:: Found out SSDT:SgPch [SgSsdtPch.asl]. dGPU is present on PCH RootPort.\n"));
+ LoadTable = TRUE;
+ }
+
+ ///
+ /// Add the table
+ ///
+ if (LoadTable) {
+ TableHandle = 0;
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ TableHeader,
+ TableHeader->Length,
+ &TableHandle
+ );
+ }
+ ///
+ /// Increment the instance
+ ///
+ Instance++;
+ Table = NULL;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+VOID
+EFIAPI
+SgExitPmAuthCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *ProtocolPointer;
+
+ ///
+ /// Check if this is first time called by EfiCreateProtocolNotifyEvent() or not,
+ /// if it is, we will skip it until real event is triggered
+ ///
+ Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, &ProtocolPointer);
+ if (EFI_SUCCESS != Status) {
+ return;
+ }
+
+ gBS->CloseEvent (Event);
+
+ DEBUG ((EFI_D_INFO, "SG:: ExitPmAuth Callback\n"));
+ ///
+ /// Load and Execute dGPU VBIOS
+ ///
+ Status = LoadAndExecuteDgpuVbios (mDxePlatformSaPolicy->VbiosConfig);
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.h
new file mode 100644
index 0000000..4d32f8f
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/SwitchableGraphicsInit.h
@@ -0,0 +1,267 @@
+/** @file
+ Header file for the SwitchableGraphics Dxe driver.
+ This driver loads SwitchableGraphics ACPI tables.
+
+@copyright
+ Copyright (c) 2010 - 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
+
+**/
+
+#ifndef _SWITCHABLE_GRAPHICS_DXE_H_
+#define _SWITCHABLE_GRAPHICS_DXE_H_
+
+//
+// External include files do NOT need to be explicitly specified in real EDKII
+// environment
+//
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGlueDxe.h"
+#include "EfiScriptLib.h"
+#endif
+
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+
+#include "PchAccess.h"
+#include "Acpi3_0.h"
+#include "SaAccess.h"
+
+#include EFI_PROTOCOL_DEPENDENCY (PciIo)
+#include EFI_PROTOCOL_DEPENDENCY (AcpiTable)
+#include EFI_PROTOCOL_DEPENDENCY (FirmwareVolume)
+#include EFI_PROTOCOL_DEPENDENCY (SaGlobalNvsArea)
+#include EFI_GUID_DEFINITION (SaDataHob)
+#include EFI_PROTOCOL_DEFINITION (SaPlatformPolicy)
+
+///
+/// SG ACPI table data storage file
+///
+#include EFI_GUID_DEFINITION (SgAcpiTableStorage)
+
+///
+/// Switchable Graphics defines.
+///
+#define CONVENTIONAL_MEMORY_TOP 0xA0000 ///< 640 KB
+#define BIN_FILE_SIZE_MAX 0x10000
+
+#define OPTION_ROM_SIGNATURE 0xAA55
+
+#define MemoryRead16(Address) * (UINT16 *) (Address)
+#define MemoryRead8(Address) * (UINT8 *) (Address)
+
+///
+/// PEG Capability Equates
+///
+#define PEG_CAP_ID 0x10
+#define PEG_CAP_VER 0x2
+
+#pragma pack(1)
+typedef struct {
+ UINT16 Signature; ///< 0xAA55
+ UINT8 Reserved[22];
+ UINT16 PcirOffset;
+} VBIOS_OPTION_ROM_HEADER;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+ UINT32 Signature; ///< "PCIR"
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 Reserved0;
+ UINT16 Length;
+ UINT8 Revision;
+ UINT8 ClassCode[3];
+ UINT16 ImageLength;
+ UINT16 CodeRevision;
+ UINT8 CodeType;
+ UINT8 Indicator;
+ UINT16 Reserved1;
+} VBIOS_PCIR_STRUCTURE;
+#pragma pack()
+
+/**
+ Initialize the SwitchableGraphics support.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - SwitchableGraphics initialization complete
+ @retval EFI_OUT_OF_RESOURCES - Unable to allocated memory
+**/
+EFI_STATUS
+SwitchableGraphicsInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+
+/**
+ Load and execute the dGPU VBIOS.
+
+ @param[in] VbiosData - Pointer to VbiosData policy for Load/Execute and VBIOS Source.
+ LoadVbios - 0 = Do Not Load ; 1 = Load VBIOS
+ ExecuteVbios - 0 = Do Not Execute; 1 = Execute VBIOS
+ VbiosSource - 0 = PCIE Device ; 1 = FirmwareVolume => TBD
+
+ @retval EFI_SUCCESS - Load and execute successful.
+ @exception EFI_UNSUPPORTED - Secondary VBIOS not loaded.
+**/
+EFI_STATUS
+LoadAndExecuteDgpuVbios (
+ IN SA_SG_VBIOS_CONFIGURATION *VbiosConfig
+ )
+;
+
+/**
+ Initialize the runtime SwitchableGraphics support data for ACPI tables in GlobalNvs.
+ @param[in] SgInfoDataHob - Pointer to Hob for SG system details.
+ @param[in] DxePlatformSgPolicy - Pointer to the loaded image protocol for this driver.
+
+ @retval EFI_SUCCESS - The data updated successfully.
+**/
+EFI_STATUS
+UpdateGlobalNvsData (
+ IN SG_INFO_HOB SgInfo,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+;
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param[in] AllocateType - Allocated Legacy Memory Type
+ @param[in] StartPageAddress - Start address of range
+ @param[in] Pages - Number of pages to allocate
+ @param[in, out] Result - Result of allocation
+
+ @retval EFI_SUCCESS - Legacy16 code loaded
+ @retval Other - No protocol installed, unload driver.
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Result
+ )
+;
+
+/**
+ Search and return the offset of desired Pci Express Capability ID
+ CAPID list:
+ 0x0001 = Advanced Error Rreporting Capability
+ 0x0002 = Virtual Channel Capability
+ 0x0003 = Device Serial Number Capability
+ 0x0004 = Power Budgeting Capability
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] Function - Pci Function Number
+ @param[in] CapId - Extended CAPID to search for
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+UINT32
+PcieFindExtendedCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ IN UINT16 CapId
+ )
+;
+
+/**
+ Find the Offset to a given Capabilities ID
+ CAPID list:
+ 0x01 = PCI Power Management Interface
+ 0x04 = Slot Identification
+ 0x05 = MSI Capability
+ 0x10 = PCI Express Capability
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] Function - Pci Function Number
+ @param[in] CapId - CAPID to search for
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+UINT32
+PcieFindCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ IN UINT8 CapId
+ )
+;
+
+/**
+ Read SG GPIO value
+
+ @param[in] Value - PCH GPIO number and Active value
+ Bit0 to Bit7 - PCH GPIO Number
+ Bit8 - GPIO Active value (0 = Active Low; 1 = Active High)
+
+ @retval GPIO read value.
+**/
+BOOLEAN
+GpioRead (
+ IN UINT8 Value
+ )
+;
+
+/**
+ Write SG GPIO value
+
+ @param[in] Value - PCH GPIO number and Active value
+ Bit0 to Bit7 - PCH GPIO Number
+ Bit8 - GPIO Active value (0 = Active Low; 1 = Active High)
+ @param[in] Level - Write data (0 = Disable; 1 = Enable)
+**/
+VOID
+GpioWrite (
+ IN UINT8 Value,
+ IN BOOLEAN Level
+ )
+;
+
+/**
+ Load Intel SG SSDT Tables
+
+ @param[in] None
+
+ @retval EFI_SUCCESS - SG SSDT Table load successful.
+**/
+EFI_STATUS
+LoadAcpiTables (
+ VOID
+ )
+;
+
+
+VOID
+EFIAPI
+SgExitPmAuthCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.c
new file mode 100644
index 0000000..1dea621
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.c
@@ -0,0 +1,934 @@
+/** @file
+ This code provides a initialization of intel VT-d (Virtualization Technology for Directed I/O).
+
+@copyright
+ Copyright (c) 1999 - 2013 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
+
+@todo assumption is ANDD table will use device path to be loaded dynamically, need to use pchplatformpolicy if assumption is incorrect.
+**/
+#include "SaInit.h"
+#include "VTd.h"
+
+UINT32 mPchRootComplexBar;
+DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy;
+DXE_PCH_PLATFORM_POLICY_PROTOCOL *mDxePlatformPchPolicy;
+PCH_SERIES mPchSeries;
+
+/**
+For device that specified by Device Num and Function Num,
+mDevEnMap is used to check device presence.
+ 0x80 means use Device ID to detemine presence
+
+ The structure is used to check if device scope is valid when update DMAR table
+**/
+UINT16 mDevEnMap[][2] = {
+ {
+ 0x0200,
+ 0x80
+ }, ///< D2F0
+ {
+ 0x1D00,
+ 0x80
+ }, ///< D29F0
+ {
+ 0x1A00,
+ 0x80
+ }, ///< D26F0
+ {
+ 0x1400,
+ 0x80
+ } ///< D20F0
+};
+
+BOOLEAN mInterruptRemappingSupport;
+
+UINT16
+GetFunDisableBit (
+ UINT8 DevNum,
+ UINT8 FunNum
+ )
+/**
+ Get the corresponding device Enable/Disable bit according DevNum and FunNum
+
+ @param[in] DevNum - Device Number
+ @param[in] FunNum - Function Number
+
+ @retval If the device is found, return disable/Enable bit in FD/Deven reigster
+ @retval If not found return 0xFF
+**/
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof (mDevEnMap) / 4; Index++) {
+ if (mDevEnMap[Index][0] == ((DevNum << 0x08) | FunNum)) {
+ return mDevEnMap[Index][1];
+ }
+ }
+
+ return 0xFF;
+}
+
+VOID
+UpdateDRHD (
+ IN OUT VOID *DrhdEnginePtr
+ )
+/**
+ Update the DRHD structure
+
+ @param[in, out] DrhdEnginePtr - A pointer to DRHD structure
+**/
+{
+ UINT16 Length;
+ UINT16 DisableBit;
+ UINTN DeviceScopeNum;
+ BOOLEAN NeedRemove;
+ EFI_ACPI_DRHD_ENGINE1_STRUCT *DrhdEngine;
+
+ //
+ // Convert DrhdEnginePtr to EFI_ACPI_DRHD_ENGINE1_STRUCT Pointer
+ //
+ DrhdEngine = (EFI_ACPI_DRHD_ENGINE1_STRUCT *) DrhdEnginePtr;
+
+ Length = DrhdEngine->Length;
+ DeviceScopeNum = (DrhdEngine->Length - EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) / sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
+ DisableBit = GetFunDisableBit (
+ DrhdEngine->DeviceScope[0].PciPath[0],
+ DrhdEngine->DeviceScope[0].PciPath[1]
+ );
+ NeedRemove = FALSE;
+ if ((DisableBit == 0xFF) ||
+ (DrhdEngine->RegisterBaseAddress == 0) ||
+ ((DisableBit == 0x80) &&
+ (MmPci32 (0, 0, DrhdEngine->DeviceScope[0].PciPath[0], DrhdEngine->DeviceScope[0].PciPath[1], 0x00) == 0xFFFFFFFF))
+ ){
+ NeedRemove = TRUE;
+ }
+ if (NeedRemove) {
+ Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
+ }
+ ///
+ /// If no devicescope is left, we set the structure length as 0x00
+ ///
+ if ((Length > EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) || (DrhdEngine->Flags == 0x01)) {
+ DrhdEngine->Length = Length;
+ } else {
+ DrhdEngine->Length = 0;
+ }
+}
+
+UINT8
+GetIoApicID (
+ VOID
+ )
+/**
+ Get IOAPIC ID from LPC
+
+ @retval APIC ID
+**/
+{
+ UINT8 VOLATILE *IoapicIndex;
+ UINT32 VOLATILE *IoapicData;
+ UINT32 Data32;
+
+ ///
+ /// Get IOAPIC base
+ ///
+ IoapicIndex = (UINT8 *) (UINTN) (R_PCH_IO_APIC_INDEX + ((PchMmRcrb16 (R_PCH_RCRB_OIC) & 0x0ff) << 12));
+ IoapicData = (UINT32 *) (UINTN) (R_PCH_IO_APIC_DATA + ((PchMmRcrb16 (R_PCH_RCRB_OIC) & 0x0ff) << 12));
+
+ ///
+ /// Get APIC ID from Identification Register (Index 0)
+ ///
+ *IoapicIndex = 0;
+ Data32 = (*IoapicData & 0x0F000000) >> 24;
+
+ return (UINT8) Data32;
+}
+
+VOID
+UpdateDRHD2 (
+ IN OUT VOID *DrhdEnginePtr
+ )
+/**
+ Update the second DRHD structure
+
+ @param[in, out] DrhdEnginePtr - A pointer to DRHD structure
+**/
+{
+ UINT16 Length;
+ UINTN DeviceScopeNum;
+ UINTN ValidDeviceScopeNum;
+ UINT16 Data16;
+ UINT16 HpetReg;
+ UINT16 Index;
+ UINT8 Bus;
+ UINT8 Path[2] = { 0, 0 };
+ BOOLEAN NeedRemove;
+ EFI_ACPI_DRHD_ENGINE2_STRUCT *DrhdEngine;
+
+ ///
+ /// Convert DrhdEnginePtr to EFI_ACPI_DRHD_ENGINE2_STRUCT Pointer
+ ///
+ DrhdEngine = (EFI_ACPI_DRHD_ENGINE2_STRUCT *) DrhdEnginePtr;
+
+ Length = DrhdEngine->Length;
+ DeviceScopeNum = (DrhdEngine->Length - EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) / sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
+ Data16 = 0;
+ Bus = 0;
+ HpetReg = R_PCH_LPC_HPET0;
+ ValidDeviceScopeNum = 0;
+
+ for (Index = 0; Index < DeviceScopeNum; Index++) {
+ NeedRemove = FALSE;
+ /**
+ For HPET and APIC, update device scope if Interrupt remapping is supported. remove device scope
+ if interrupt remapping is not supported.
+ - Index = 0 - IOAPIC
+ - Index = 1 - HPET
+ For Serial IO devices, they do not appear in PCI space, use platform policy to determine existence, also remove if PCH not LP
+ - Index = 2 - I2C0
+ - Index = 3 - I2C1
+ - Index = 4 - SPI0
+ - Index = 5 - SPI1
+ - Index = 6 - UART0
+ - Index = 7 - UART1
+ - Index = 8 - SDIO
+ **/
+ if (mInterruptRemappingSupport) {
+ if (Index == 0) {
+ ///
+ /// Update source id for IoApic's device scope entry
+ ///
+ Data16 = PchLpcPciCfg16 (R_PCH_LPC_IOXAPIC);
+ Bus = (UINT8) (Data16 >> 8);
+ if (Bus != 0x00) {
+ Path[0] = (UINT8) ((Data16 & 0xff) >> 3);
+ Path[1] = (UINT8) (Data16 & 0x7);
+ } else {
+ //
+ // BUGBUG: Here we just hardcode, because in this version, R_PCH_LPC_IOXAPIC is initialized AFTER Vtd run. We can NOT get proper setting from PCH
+ // We can NOT get proper setting from PCH
+ /// @todo check if code still needed
+ //
+ DEBUG ((EFI_D_WARN, "BUGBUG: UpdateApicHpet use hardcode value - To be fixed!\n"));
+ Bus = 0xF0;
+ Path[0] = 0x1F;
+ Path[1] = 0x0;
+ }
+ DrhdEngine->DeviceScope[Index].StartBusNumber = Bus;
+ //
+ // Update APIC ID
+ //
+ DrhdEngine->DeviceScope[Index].EnumId = GetIoApicID ();
+ }
+ if (Index == 1) {
+ ///
+ /// Update source id for HPET's device scope entry
+ ///
+ Data16 = PchLpcPciCfg16 (HpetReg);
+ Bus = (UINT8) (Data16 >> 8);
+ Path[0] = (UINT8) ((Data16 & 0xFF) >> 3);
+ Path[1] = (UINT8) (Data16 & 0x7);
+ DrhdEngine->DeviceScope[Index].StartBusNumber = Bus;
+ }
+ } else {
+ if ((Index == 0) || (Index == 1)) {
+ NeedRemove = TRUE;
+ }
+ }
+ /*
+ Pch removed device from PCI space and it is visible by ACPI only, we use platform policy to check
+ if device is present. If Pch is 2 chip, remove all serialio devices.
+ */
+#ifdef SERIAL_IO_FLAG
+ if (mPchSeries == PchLp){
+ if (Index == 2){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoI2c0 == 0){
+ NeedRemove = TRUE;
+ }
+ }
+ if (Index == 3){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoI2c1 == 0){
+ NeedRemove = TRUE;
+ }
+ }
+ if (Index == 4){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoSpi0 == 0){
+ NeedRemove = TRUE;
+ }
+ }
+ if (Index == 5){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoSpi1 == 0){
+ NeedRemove = TRUE;
+ }
+ }
+ if (Index == 6){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoUart0 == 0){
+ NeedRemove = TRUE;
+ }
+ }
+ if (Index == 7){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoUart1 == 0){
+ NeedRemove = TRUE;
+ }
+ }
+ if (Index == 8){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoSdio == 0){
+ NeedRemove = TRUE;
+ }
+ }
+ } else {
+#endif
+ if ((Index >= 2) && (Index <= 8)){
+ NeedRemove = TRUE;
+ }
+#ifdef SERIAL_IO_FLAG
+ }
+#endif
+ CopyMem (
+ &DrhdEngine->DeviceScope[ValidDeviceScopeNum],
+ &DrhdEngine->DeviceScope[Index],
+ sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE)
+ );
+ if (NeedRemove) {
+ Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
+ } else {
+ ValidDeviceScopeNum++;
+ }
+ }
+ ///
+ /// If no devicescope is left, we set the structure length as 0x00
+ ///
+ if ((Length > EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) || (DrhdEngine->Flags == 0x01)) {
+ DrhdEngine->Length = Length;
+ } else {
+ DrhdEngine->Length = 0;
+ }
+}
+
+VOID
+UpdateRMRR (
+ IN OUT VOID *RmrrPtr
+ )
+/**
+ Update the RMRR structure
+
+ @param[in, out] RmrrPtr - A pointer to RMRR structure
+**/
+{
+ UINT16 Length;
+ UINT16 DisableBit;
+ UINTN DeviceScopeNum;
+ UINTN ValidDeviceScopeNum;
+ UINTN Index;
+ BOOLEAN NeedRemove;
+ EFI_ACPI_RMRR_USB_STRUC *Rmrr;
+
+ ///
+ /// To make sure all devicescope can be checked,
+ /// we convert the RmrrPtr to EFI_ACPI_RMRR_USB_STRUC pointer
+ ///
+ Rmrr = (EFI_ACPI_RMRR_USB_STRUC *) RmrrPtr;
+ Length = Rmrr->Length;
+ ValidDeviceScopeNum = 0;
+ DeviceScopeNum = (Rmrr->Length - EFI_ACPI_RMRR_HEADER_LENGTH) / sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
+ for (Index = 0; Index < DeviceScopeNum; Index++) {
+ ///
+ /// here we assume Device will exist on PCH if Device Number is greater than 0x0F
+ ///
+ DisableBit = GetFunDisableBit (
+ Rmrr->DeviceScope[Index].PciPath[0],
+ Rmrr->DeviceScope[Index].PciPath[1]
+ );
+ NeedRemove = FALSE;
+ if ((DisableBit == 0xFF) ||
+ ((DisableBit == 0x80) &&
+ (MmPci32 (0, 0, Rmrr->DeviceScope[Index].PciPath[0], Rmrr->DeviceScope[Index].PciPath[1], 0x00) == 0xFFFFFFFF))
+ ){
+ NeedRemove = TRUE;
+ }
+ CopyMem (
+ &Rmrr->DeviceScope[ValidDeviceScopeNum],
+ &Rmrr->DeviceScope[Index],
+ sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE)
+ );
+ if (NeedRemove) {
+ Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
+ } else {
+ ValidDeviceScopeNum++;
+ }
+ }
+ ///
+ /// If No deviceScope is left, set length as 0x00
+ ///
+ if (Length > EFI_ACPI_RMRR_HEADER_LENGTH) {
+ Rmrr->Length = Length;
+ } else {
+ Rmrr->Length = 0;
+ }
+}
+
+VOID
+DmarTableUpdate (
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader,
+ IN OUT EFI_ACPI_TABLE_VERSION *Version
+ )
+/**
+ Update the DMAR table
+
+ @param[in, out] TableHeader - The table to be set
+ @param[in, out] Version - Version to publish
+**/
+{
+ EFI_ACPI_DMAR_TABLE *DmarTable;
+ EFI_ACPI_DMAR_TABLE TempDmarTable;
+ UINTN Offset;
+ UINTN StructureLen;
+ UINT16 IgdMode;
+ UINT16 GttMode;
+ UINT32 IgdMemSize;
+ UINT32 GttMemSize;
+
+ IgdMemSize = 0;
+ GttMemSize = 0;
+ DmarTable = (EFI_ACPI_DMAR_TABLE *) TableHeader;
+
+ if (mInterruptRemappingSupport) {
+ DmarTable->Flags |= BIT0; ///< Set INTR_REMAP bit (BIT 0) if interrupt remapping is supported
+ }
+ ///
+ /// Find IGD memsize
+ ///
+ IgdMode = (McD0PciCfg16 (R_SA_GGC) & B_SA_GGC_GMS_MASK) >> 3;
+ if (IgdMode <= V_SA_GGC_GMS_512MB) {
+ IgdMemSize = IgdMode * 32 * (1024) * (1024);
+ } else {
+ IgdMemSize = 0;
+ }
+ ///
+ /// Find GTT mem size
+ ///
+ GttMode = (McD0PciCfg16 (R_SA_GGC) & B_SA_GGC_GGMS_MASK) >> 8;
+ if (GttMode <= V_SA_GGC_GGMS_2MB) {
+ GttMemSize = GttMode * (1024) * (1024);
+ } else {
+ GttMemSize = 0;
+ }
+
+ DmarTable->RmrrIgd.RmrBaseAddress = (McD0PciCfg32 (R_SA_TOLUD) &~(0x01)) - IgdMemSize - GttMemSize;
+ DmarTable->RmrrIgd.RmrLimitAddress = DmarTable->RmrrIgd.RmrBaseAddress + IgdMemSize + GttMemSize - 1;
+ DEBUG ((EFI_D_INFO, "RMRR Base address IGD %016lX\n", DmarTable->RmrrIgd.RmrBaseAddress));
+ DEBUG ((EFI_D_INFO, "RMRR Limit address IGD %016lX\n", DmarTable->RmrrIgd.RmrLimitAddress));
+
+ DmarTable->RmrrUsb.RmrBaseAddress = mDxePlatformSaPolicy->Vtd->RmrrUsbBaseAddress[0];
+ DmarTable->RmrrUsb.RmrLimitAddress = mDxePlatformSaPolicy->Vtd->RmrrUsbBaseAddress[1];
+
+ ///
+ /// Convert to 4KB alignment.
+ ///
+ DmarTable->RmrrUsb.RmrBaseAddress &= ~0xFFF;
+ DmarTable->RmrrUsb.RmrLimitAddress &= ~0xFFF;
+ DmarTable->RmrrUsb.RmrLimitAddress += 0x1000 - 1;
+
+ DEBUG ((EFI_D_INFO, "RMRR Base address USB %016lX\n", DmarTable->RmrrUsb.RmrBaseAddress));
+ DEBUG ((EFI_D_INFO, "RMRR Limit address USB %016lX\n", DmarTable->RmrrUsb.RmrLimitAddress));
+
+ ///
+ /// @todo check if this check is still needed.
+ ///
+ if (DmarTable->RmrrUsb.RmrBaseAddress == 0) {
+ DEBUG ((EFI_D_WARN, "BUGBUG: RmrrUsb.RmrBaseAddress is 0 - To be fixed\n"));
+ }
+ ///
+ /// Update DRHD structures of DmarTable
+ ///
+ DmarTable->DrhdEngine1.RegisterBaseAddress = (McMmio32 (R_SA_MCHBAR_VTD1_OFFSET) &~1);
+ DmarTable->DrhdEngine2.RegisterBaseAddress = (McMmio32 (R_SA_MCHBAR_VTD2_OFFSET) &~1);
+
+ DEBUG ((EFI_D_INFO, "VTD base address1 %x\n", DmarTable->DrhdEngine1.RegisterBaseAddress));
+ DEBUG ((EFI_D_INFO, "VTD base address2 %x\n", DmarTable->DrhdEngine2.RegisterBaseAddress));
+ ///
+ /// copy DmarTable to TempDmarTable to be processed
+ ///
+ CopyMem (&TempDmarTable, DmarTable, sizeof (EFI_ACPI_DMAR_TABLE));
+
+ ///
+ /// Update DRHD structures of temp DMAR table
+ ///
+ UpdateDRHD (&TempDmarTable.DrhdEngine1);
+ UpdateDRHD2 (&TempDmarTable.DrhdEngine2);
+
+ ///
+ /// Update RMRR structures of temp DMAR table
+ ///
+ UpdateRMRR ((VOID *) &TempDmarTable.RmrrUsb);
+ UpdateRMRR ((VOID *) &TempDmarTable.RmrrIgd);
+
+ ///
+ /// Remove unused device scope or entire DRHD structures
+ ///
+ Offset = (UINTN) (&TempDmarTable.DrhdEngine1);
+ if (TempDmarTable.DrhdEngine1.Length != 0) {
+ Offset += TempDmarTable.DrhdEngine1.Length;
+ }
+ if (TempDmarTable.DrhdEngine2.Length != 0) {
+ StructureLen = TempDmarTable.DrhdEngine2.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.DrhdEngine2, TempDmarTable.DrhdEngine2.Length);
+ Offset += StructureLen;
+ }
+ ///
+ /// Remove unused device scope or entire RMRR structures
+ ///
+ if (TempDmarTable.RmrrUsb.Length != 0) {
+ StructureLen = TempDmarTable.RmrrUsb.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.RmrrUsb, TempDmarTable.RmrrUsb.Length);
+ Offset += StructureLen;
+ }
+ if (TempDmarTable.RmrrIgd.Length != 0) {
+ StructureLen = TempDmarTable.RmrrIgd.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.RmrrIgd, TempDmarTable.RmrrIgd.Length);
+ Offset += StructureLen;
+ }
+#ifdef SERIAL_IO_FLAG
+ ///
+ /// Include necessary ANDD structures. If not PchLp, remove all ANDD.
+ ///
+ if (mPchSeries == PchLp){
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoI2c0 != 0) {
+ StructureLen = TempDmarTable.AnddI2C0.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C0, TempDmarTable.AnddI2C0.Length);
+ Offset += StructureLen;
+ }
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoI2c1 != 0) {
+ StructureLen = TempDmarTable.AnddI2C1.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C1, TempDmarTable.AnddI2C1.Length);
+ Offset += StructureLen;
+ }
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoSpi0 != 0) {
+ StructureLen = TempDmarTable.AnddSpi0.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddSpi0, TempDmarTable.AnddSpi0.Length);
+ Offset += StructureLen;
+ }
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoSpi1 != 0) {
+ StructureLen = TempDmarTable.AnddSpi1.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddSpi1, TempDmarTable.AnddSpi1.Length);
+ Offset += StructureLen;
+ }
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoUart0 != 0) {
+ StructureLen = TempDmarTable.AnddUa00.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddUa00, TempDmarTable.AnddUa00.Length);
+ Offset += StructureLen;
+ }
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoUart1 != 0) {
+ StructureLen = TempDmarTable.AnddUa01.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddUa01, TempDmarTable.AnddUa01.Length);
+ Offset += StructureLen;
+ }
+ if (mDxePlatformPchPolicy->DeviceEnabling->SerialIoSdio != 0) {
+ StructureLen = TempDmarTable.AnddSdhc.Length;
+ CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddSdhc, TempDmarTable.AnddSdhc.Length);
+ Offset += StructureLen;
+ }
+ }
+#endif
+ Offset = Offset - (UINTN) &TempDmarTable;
+ TempDmarTable.Header.Checksum = (UINT8) (TempDmarTable.Header.Checksum + TempDmarTable.Header.Length - Offset);
+ TempDmarTable.Header.Length = (UINT32) Offset;
+ ///
+ /// Replace DMAR table with rebuilt table TempDmarTable
+ ///
+ CopyMem ((VOID *) DmarTable, (VOID *) &TempDmarTable, TempDmarTable.Header.Length);
+}
+
+EFI_STATUS
+WaForVc0RemappingEngine (
+ UINT64 MchBar
+ )
+/**
+ Workaround for VC0 remapping engine
+
+ @param[in] MchBar - MCHBAR address
+
+ @retval EFI_SUCCESS - successed.
+**/
+{
+ UINT16 DeviceId;
+ UINT32 Vc0RemapEngineBase;
+ UINT32 Data32Or;
+ UINT32 Data32And;
+
+ DeviceId = PchLpcPciCfg16(R_PCH_LPC_DEVICE_ID);
+ Vc0RemapEngineBase = Mmio32(MchBar, R_SA_MCHBAR_VTD2_OFFSET) & 0xFFFFFFFE;
+
+ ///
+ /// Disable VTD SuperPage policy when iGfx is enabled
+ ///
+ if (McD2PciCfg16(R_SA_IGD_VID) != 0xFFFF) {
+ Data32And = (UINT32)~(BIT25);
+ Data32Or = 0;
+ Mmio32And(Vc0RemapEngineBase, 0xFF0, Data32And);
+ SCRIPT_MEM_READ_WRITE
+ (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (Vc0RemapEngineBase + 0xFF0),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+UpdateDmarExitPmAuth (
+ VOID
+ )
+/**
+ ExitPmAuth routine for update DMAR
+**/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FV_FILETYPE FileType;
+ UINT32 FvStatus;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN i;
+ INTN Instance;
+ EFI_ACPI_TABLE_VERSION Version;
+ EFI_ACPI_COMMON_HEADER *CurrentTable;
+ UINTN AcpiTableHandle;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ EFI_ACPI_DESCRIPTION_HEADER *VtdAcpiTable;
+ STATIC BOOLEAN Triggered = FALSE;
+
+ if (Triggered) {
+ return;
+ }
+
+ Triggered = TRUE;
+
+ FwVol = NULL;
+ AcpiTable = NULL;
+ VtdAcpiTable = NULL;
+
+ ///
+ /// Locate PCH platform policy protocol and PCH series to support feature enabling/disabling
+ ///
+ Status = gBS->LocateProtocol (
+ &gDxePchPlatformPolicyProtocolGuid,
+ NULL,
+ (VOID**) &mDxePlatformPchPolicy
+ );
+ ASSERT_EFI_ERROR (Status);
+ mPchSeries = GetPchSeries();
+
+ if ((!mDxePlatformSaPolicy->Vtd->VtdEnable) || (McD0PciCfg32 (R_SA_MC_CAPID0_A_OFFSET) & BIT23)) {
+ DEBUG ((EFI_D_INFO, "Vtd Disabled, skip DMAR Table install\n"));
+
+ return;
+ }
+
+ ///
+ /// Locate ACPI support protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+
+ ///
+ /// Locate protocol.
+ /// There is little chance we can't find an FV protocol
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Looking for FV with ACPI storage file
+ ///
+ for (i = 0; i < NumberOfHandles; i++) {
+ ///
+ /// Get the protocol on this handle
+ /// This should not fail because of LocateHandleBuffer
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[i],
+ &gEfiFirmwareVolumeProtocolGuid,
+ (VOID **) &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gSaAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ ///
+ /// If we found it, then we are done
+ ///
+ if (Status == EFI_SUCCESS) {
+ 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
+ ///
+ FreePool (HandleBuffer);
+
+ ///
+ /// Sanity check that we found our data file
+ ///
+ ASSERT (FwVol);
+ if (FwVol == NULL) {
+ return ;
+ }
+ ///
+ /// By default, a table belongs in all ACPI table versions published.
+ ///
+ Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
+
+ ///
+ /// Read tables from the storage file.
+ ///
+ Instance = 0;
+ CurrentTable = NULL;
+
+ while (Status == EFI_SUCCESS) {
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gSaAcpiTableStorageGuid,
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID **) &CurrentTable,
+ &Size,
+ &FvStatus
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// Check the Signature ID to modify the table
+ ///
+ switch (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Signature) {
+
+ case EFI_ACPI_VTD_DMAR_TABLE_SIGNATURE:
+ VtdAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
+ DmarTableUpdate (VtdAcpiTable, &Version);
+ break;
+
+ default:
+ break;
+ }
+ ///
+ /// Increment the instance
+ ///
+ Instance++;
+ CurrentTable = NULL;
+ }
+ }
+ ///
+ /// Update the VTD table in the ACPI tables.
+ ///
+ AcpiTableHandle = 0;
+ if (VtdAcpiTable != NULL) {
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ VtdAcpiTable,
+ VtdAcpiTable->Length,
+ &AcpiTableHandle
+ );
+ }
+}
+
+EFI_STATUS
+VtdInit (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+@brief
+ Locate the VT-d ACPI tables data file and read ACPI SSDT tables.
+ Publish the appropriate SSDT based on current configuration and capabilities.
+
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Vtd initialization complete
+ @exception EFI_UNSUPPORTED - Vtd is not enabled by policy
+**/
+{
+ EFI_STATUS Status;
+ UINTN i;
+ UINT64 MchBar;
+ UINT32 Data32Or;
+ UINT32 Data32And;
+ UINT32 VtdBase;
+ UINT32 VtBarReg [SA_VTD_ENGINE_NUMBER];
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuStepping;
+
+ mInterruptRemappingSupport = FALSE;
+ mPchRootComplexBar = MmPci32 (0, 0, 31, 0, 0xF0) &~BIT0;
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+
+ VtBarReg[0] = R_SA_MCHBAR_VTD1_OFFSET;
+ VtBarReg[1] = R_SA_MCHBAR_VTD2_OFFSET;
+ mDxePlatformSaPolicy = DxePlatformSaPolicy;
+
+ ///
+ /// Check SA supports VTD and VTD is enabled in setup menu
+ ///
+ if ((!mDxePlatformSaPolicy->Vtd->VtdEnable) || (McD0PciCfg32 (R_SA_MC_CAPID0_A_OFFSET) & BIT23)) {
+ DEBUG ((EFI_D_WARN, "VTd disabled or no capability!\n"));
+ return EFI_UNSUPPORTED;
+ }
+ DEBUG ((EFI_D_INFO, "VTd enabled\n"));
+
+ ///
+ /// 14.1 Program Remap Engine Base Address
+ /// Configure VTD1 BAR
+ ///
+ i = 0;
+
+ ///
+ /// Skip GFXVTBAR if IGD is disabled
+ ///
+ if (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF) {
+ Data32Or = mDxePlatformSaPolicy->Vtd->BaseAddress[i];
+ Data32Or |= 0x1;
+ Mmio32 (MchBar, R_SA_MCHBAR_VTD1_OFFSET) = Data32Or;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MchBar + R_SA_MCHBAR_VTD1_OFFSET),
+ 1,
+ &Data32Or
+ );
+ i++;
+ }
+
+ ///
+ /// Configure VTD2 BAR
+ ///
+ Data32Or = mDxePlatformSaPolicy->Vtd->BaseAddress[i];
+ Data32Or |= 0x1;
+ Mmio32 (MchBar, R_SA_MCHBAR_VTD2_OFFSET) = Data32Or;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MchBar + R_SA_MCHBAR_VTD2_OFFSET),
+ 1,
+ &Data32Or
+ );
+
+ ///
+ /// Workaround for VC0 remapping engine
+ ///
+ Status = WaForVc0RemappingEngine (MchBar);
+ ASSERT_EFI_ERROR (Status);
+
+ for (i = 0; i < SA_VTD_ENGINE_NUMBER; i++) {
+ VtdBase = Mmio32 (MchBar, VtBarReg[i]) & 0xfffffffe;
+
+ ///
+ /// skip if the VT bar is 0
+ ///
+ if (VtdBase == 0) {
+ continue;
+ }
+
+ CpuFamilyId = GetCpuFamily();
+ CpuStepping = GetCpuStepping();
+
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuHswUlt) || (CpuFamilyId == EnumCpuCrw)
+ ) {
+ Data32And = (UINT32) ~(BIT15+BIT16+BIT17+BIT18+BIT19); ///< mask out 19:15
+ Data32Or = BIT15;
+ if (i == 1) {
+ Mmio32AndThenOr (VtdBase, 0xF04, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (VtdBase + 0xF04),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+ }
+ }
+ ///
+ /// 14.2 Set the remap engine policy bits
+ ///
+ Data32And = 0x0; ///< mask out all bits
+ Data32Or = 0;
+
+
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuHswUlt) || (CpuFamilyId == EnumCpuCrw)) {
+ if (i == 0) {
+ Data32Or |= 0x02100000;
+ }
+ if (i == 1) {
+ if (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF) {
+ Data32Or |= 0x000A5003;
+ } else {
+ Data32Or |= 0x020A5003;
+ }
+ }
+ }
+
+ ///
+ /// Set lock bit
+ ///
+ Data32Or |= BIT31;
+
+
+ Mmio32AndThenOr (VtdBase, 0xFF0, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (VtdBase + 0xFF0),
+ &Data32Or, ///< Data to be ORed
+ &Data32And ///< Data to be ANDed
+ );
+
+ ///
+ /// Check IR status
+ ///
+ if ((Mmio32 (VtdBase, VTD_ECAP_REG) & IR) && !(mInterruptRemappingSupport)) {
+ mInterruptRemappingSupport = TRUE;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.h
new file mode 100644
index 0000000..2d9daa4
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/VTd.h
@@ -0,0 +1,70 @@
+/** @file
+ This code provides a initialization of intel VT-d (Virtualization Technology for Directed I/O).
+
+@copyright
+ Copyright (c) 1999 - 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
+**/
+#ifndef _VT_D_H_
+#define _VT_D_H_
+
+///
+/// Include files
+///
+#include "DmaRemappingTable.h"
+#include "SaAccess.h"
+#include "PchAccess.h"
+
+#include EFI_PROTOCOL_DEPENDENCY (AcpiTable)
+#include EFI_PROTOCOL_DEFINITION (SaPlatformPolicy)
+#include EFI_PROTOCOL_DEFINITION (PchPlatformPolicy)
+
+///
+/// SA ACPI table data storage file
+///
+#include EFI_GUID_DEFINITION (SaAcpiTableStorage)
+
+#define VTD_ECAP_REG 0x10
+#define IR BIT3
+
+#define VTD_GCMD_REG 0x18
+#define QIE BIT26
+#define IRE BIT25
+
+EFI_STATUS
+VtdInit (
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Locate the VT-d ACPI tables data file and read ACPI SSDT tables.
+ Publish the appropriate SSDT based on current configuration and capabilities.
+
+ @param[in] DxePlatformSaPolicy SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Vtd initialization complete
+ @retval Other - No Vtd function initiated
+**/
+;
+
+VOID
+UpdateDmarExitPmAuth (
+ VOID
+ )
+/**
+ ExitPmAuth routine for update DMAR
+**/
+;
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.c
new file mode 100644
index 0000000..2b1af13
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.c
@@ -0,0 +1,1094 @@
+/** @file
+ DXE driver for Initializing SystemAgent Graphics initialization.
+
+@copyright
+ Copyright (c) 1999 - 2013 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 "GraphicsInit.h"
+#include EFI_PROTOCOL_DEFINITION (LegacyBios)
+#include EFI_PROTOCOL_DEFINITION (GopComponentName2)
+#ifndef AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+#if (defined(IntelSaGopDriver_SUPPORT) && (IntelSaGopDriver_SUPPORT == 1))
+#include "Include\Protocol\IntelSaGopDriver.h"
+#endif
+#endif
+UINT64 GTTMMADR;
+UINTN MCHBAR_BASE;
+UINT8 rP1GraphicsFreq;
+EFI_EVENT mExitPmAuthEvent;
+
+DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy;
+GOP_COMPONENT_NAME2_PROTOCOL *GopComponentName2Protocol = NULL;
+
+///
+/// RC6 Settings
+///
+BOOT_SCRIPT_REGISTER_SETTING gSaGtRC6Registers[] = {
+ 0x0,
+ 0xA090,
+ 0xFFFFFFFF,
+ 0x0,
+ ///
+ /// RC1e - RC6/6p - RC6pp Wake Rate Limits
+ ///
+ 0x0,
+ 0xA098,
+ 0xFFFFFFFF,
+ 0x3E80000,
+ 0x0,
+ 0xA09C,
+ 0xFFFFFFFF,
+ 0x00280000,
+ 0x0,
+ 0xA0A8,
+ 0xFFFFFFFF,
+ 0x1E848,
+ 0x0,
+ 0xA0AC,
+ 0xFFFFFFFF,
+ 0x19,
+ ///
+ /// Render/Video/Blitter Idle Max Count
+ ///
+ 0x0,
+ 0x2054,
+ 0x0,
+ 0xA,
+ 0x0,
+ 0x12054,
+ 0x0,
+ 0xA,
+ 0x0,
+ 0x22054,
+ 0x0,
+ 0xA,
+ 0x0,
+ 0x1a054,
+ 0x0,
+ 0xA,
+ ///
+ /// RC Sleep / RCx Thresholds
+ ///
+ 0x0,
+ 0xA0B0,
+ 0xFFFFFFFF,
+ 0,
+ 0x0,
+ 0xA0B4,
+ 0xFFFFFFFF,
+ 0x3E8,
+ 0x0,
+ 0xA0B8,
+ 0xFFFFFFFF,
+ 0xC350,
+ ///
+ /// RP Settings
+ ///
+ 0x0,
+ 0xA010,
+ 0xFFFFFFFF,
+ 0xF4240,
+ 0x0,
+ 0xA014,
+ 0xFFFFFFFF,
+ 0x12060000,
+ 0x0,
+ 0xA02C,
+ 0xFFFFFFFF,
+ 0x0000E808,
+ 0x0,
+ 0xA030,
+ 0xFFFFFFFF,
+ 0x0003BD08,
+ 0x0,
+ 0xA068,
+ 0xFFFFFFFF,
+ 0x000101D0,
+ 0x0,
+ 0xA06C,
+ 0xFFFFFFFF,
+ 0x00055730,
+ 0x0,
+ 0xA070,
+ 0xFFFFFFFF,
+ 0xA
+};
+
+///
+/// PM Lock Settings
+///
+BOOT_SCRIPT_REGISTER_SETTING gSaGtPmLockBits[] = {
+ 0x0,
+ 0xA248,
+ 0xFFFFFFFF,
+ BIT31,
+ 0x0,
+ 0xA004,
+ 0xFFFFFFFF,
+ BIT4,
+ 0x0,
+ 0xA080,
+ 0xFFFFFFFF,
+ BIT2,
+ 0x0,
+ 0xA180,
+ 0xFFFFFFFF,
+ BIT31
+};
+
+EFI_STATUS
+PmInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Initialize GT PowerManagement of SystemAgent.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - GT Power Management initialization complete
+**/
+{
+ UINT8 i;
+ UINT32 RegOffset;
+ UINT32 Data32;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 Data32Mask;
+ UINT32 Result;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// Multi Threaded Force Wake
+ ///
+ RegOffset = 0xA180;
+ Data32 = BIT5;
+ Mmio32 (GTTMMADR, RegOffset) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ 1,
+ &Data32
+ );
+
+ RegOffset = 0xA188;
+ Data32 = 0x00010001;
+ Mmio32 (GTTMMADR, RegOffset) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ 1,
+ &Data32
+ );
+ ///
+ /// Force Wake Acknowledge Bit
+ ///
+ RegOffset = 0x130044;
+ Data32Mask = BIT0;
+ Result = 1;
+ PollGtReady (GTTMMADR, RegOffset, Data32Mask, Result);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ &Data32Mask,
+ &Result,
+ 50,
+ 200000
+ );
+
+ ///
+ /// Enable counters except Power Meter
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = 0x16;
+ Mmio32AndThenOr (GTTMMADR, 0xA248, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0xA248),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ ///
+ /// GFXPAUSE Settings
+ ///
+ Data32 = 0x70020;
+
+
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0) ) ||
+ ((CpuFamilyId == EnumCpuHswUlt) && (CpuSteppingId < EnumHswUltC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0) )) {
+ Data32 |= 0xFFFF;
+ }
+
+ Mmio32 (GTTMMADR, 0xA000) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0xA000),
+ 1,
+ &Data32
+ );
+
+
+ ///
+ /// ECO Settings
+ /// BIT28 = 1 GFX will be blocked from accessing memory (go=0) during CPD enter
+ /// BIT26 = 1 indicates to PCU that we are doing a fifo block due to RC6 and not CPD
+ /// BIT[24:22] = 100 RC6 Control
+ ///
+ RegOffset = 0xA180;
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT28 + BIT26;
+ if (DxePlatformSaPolicy->IgdConfig->RenderStandby) {
+ Data32And = (UINT32)~(BIT23 + BIT22);
+ Data32Or |= BIT24;
+ }
+
+ ///
+ /// Force CPD Non-IA. for steppings less than C0 for HSW/CRW
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) {
+ Data32Or |= BIT30;
+ }
+ ///
+ /// Force CPD Block memory bits. for stepping less than C0 for HSW/ULT/CRW
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0) ) ||
+ ((CpuFamilyId == EnumCpuHswUlt) && (CpuSteppingId < EnumHswUltC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0) )) {
+ Data32And &= (UINT32)~(BIT28);
+ Data32Or &= (UINT32)~(BIT28);
+ }
+
+ Mmio32AndThenOr (GTTMMADR, RegOffset, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ ///
+ /// Clock Gating Settings
+ ///
+ Data32 = 0x3FD;
+ Mmio32 (GTTMMADR, 0x9424) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x9424),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Enable Unit Level Clock Gates
+ ///
+ Data32 = 0x80;
+ Mmio32 (GTTMMADR, 0x9400) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x9400),
+ 1,
+ &Data32
+ );
+
+ Data32 = 0x40401000;
+ Mmio32 (GTTMMADR, 0x9404) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x9404),
+ 1,
+ &Data32
+ );
+
+ Data32 = 0;
+ Mmio32 (GTTMMADR, 0x9408) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x9408),
+ 1,
+ &Data32
+ );
+
+ Data32 = 0x02000001;
+ Mmio32 (GTTMMADR, 0x940c) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x940c),
+ 1,
+ &Data32
+ );
+
+ Data32 = 0x08000000;
+ Mmio32 (GTTMMADR, 0xA008) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0xA008),
+ 1,
+ &Data32
+ );
+ ///
+ /// RC6 Settings
+ ///
+ for (i = 0; i < sizeof (gSaGtRC6Registers) / sizeof (BOOT_SCRIPT_REGISTER_SETTING); ++i) {
+ RegOffset = gSaGtRC6Registers[i].Offset;
+ Data32And = gSaGtRC6Registers[i].AndMask;
+ Data32Or = gSaGtRC6Registers[i].OrMask;
+
+ Mmio32AndThenOr (GTTMMADR, RegOffset, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+
+ ///
+ /// RP Control
+ ///
+ Data32 = 0xB92;
+ Mmio32 (GTTMMADR, 0xA024) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0xA024),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// HW RC6 Control Settings
+ ///
+ Data32 = 0;
+
+ if (DxePlatformSaPolicy->IgdConfig->RenderStandby) {
+ Data32 = 0x88040000;
+ }
+
+ Mmio32 (GTTMMADR, 0xA090) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0xA090),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Video frequency request
+ ///
+ Data32 = 0x08000000;
+ Mmio32 (GTTMMADR, 0xA00C) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0xA00C),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// RC6 Settings
+ ///
+ ///
+ /// Wait for Mailbox ready
+ ///
+ Data32Mask = BIT31;
+ Result = 0;
+
+ PollGtReady (GTTMMADR, 0x138124, Data32Mask, Result);
+
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x138124),
+ &Data32Mask,
+ &Result,
+ 50,
+ 200000
+ );
+
+ ///
+ /// Mailbox Data - RC6 VIDS
+ ///
+ Data32 = 0x0;
+ Mmio32 (GTTMMADR, 0x138128) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x138128),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Mailbox Command
+ ///
+ Data32 = 0x80000004;
+ Mmio32 (GTTMMADR, 0x138124) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x138124),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Wait for Mailbox ready
+ ///
+ Data32Mask = BIT31;
+ Result = 0;
+
+ PollGtReady (GTTMMADR, 0x138124, Data32Mask, Result);
+
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x138124),
+ &Data32Mask,
+ &Result,
+ 50,
+ 200000
+ );
+
+ ///
+ /// Enable PM Interrupts
+ ///
+ Data32 = 0x3000076;
+ Mmio32 (GTTMMADR, 0x4402C) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x4402C),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// RC6 setting
+ ///
+ if (mDxePlatformSaPolicy->IgdConfig->RenderStandby) {
+ ///
+ /// Software RC state - RC6
+ ///
+ Data32 = 0x40000;
+ Mmio32 (GTTMMADR, 0xA094) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (GTTMMADR + 0xA094),
+ 1,
+ &Data32
+ );
+ }
+
+ ///
+ /// PM Lock Settings
+ ///
+ for (i = 0; i < sizeof (gSaGtPmLockBits) / sizeof (BOOT_SCRIPT_REGISTER_SETTING); ++i) {
+ RegOffset = gSaGtPmLockBits[i].Offset;
+ Data32And = gSaGtPmLockBits[i].AndMask;
+ Data32Or = gSaGtPmLockBits[i].OrMask;
+
+ Mmio32AndThenOr (GTTMMADR, RegOffset, Data32And, Data32Or);
+
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PavpInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Initialize PAVP feature of SystemAgent.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - PAVP initialization complete
+**/
+{
+
+ UINT32 DwordData;
+ UINT32 PcmBase;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ McD0PciCfg32And (R_SA_PAVPC, ~(B_SA_PAVPC_HVYMODSEL_MASK | B_SA_PAVPC_PCMBASE_MASK | B_SA_PAVPC_PAVPE_MASK | B_SA_PAVPC_PCME_MASK));
+ McD0PciCfg16Or (R_SA_PAVPC, B_SA_PAVPC_PCME_MASK | B_SA_PAVPC_PAVPE_MASK);
+ PcmBase = ((UINT32) RShiftU64 ((McD0PciCfg32 (R_SA_TOLUD)), 20)) - PAVP_PCM_SIZE_1_MB;
+ McD0PciCfg32Or (R_SA_PAVPC, (UINT32) LShiftU64 (PcmBase, 20));
+
+ if ((CpuFamilyId == EnumCpuHsw) ||
+ (CpuFamilyId == EnumCpuHswUlt) ||
+ (CpuFamilyId == EnumCpuCrw)
+ ){
+ McD0PciCfg32Or (R_SA_PAVPC, (BIT4));
+ }
+
+ DwordData = McD0PciCfg32 (R_SA_PAVPC);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0,
+ 0,
+ 0,
+ 0,
+ R_SA_PAVPC)),
+ 1,
+ &DwordData
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PostPmInitExitPmAuth (
+ VOID
+ )
+/**
+ Do Post GT PM Init Steps after VBIOS Initialization.
+
+ @retval EFI_SUCCESS Succeed.
+**/
+{
+ UINT32 RegOffset;
+ UINT32 Data32;
+ EFI_STATUS Status;
+ UINT32 Data32Mask;
+ UINT32 Result;
+ UINT16 Data16;
+ CHAR16 *DriverVersion;
+ UINTN Index;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios = NULL;
+
+ ///
+ /// Get the platform setup policy.
+ ///
+ Status = gBS->LocateProtocol (&gDxePlatformSaPolicyGuid, NULL, (VOID **) &mDxePlatformSaPolicy);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// only 32bit read/write is legal for device 0:2:0
+ ///
+ GTTMMADR = (UINT64) (McD2PciCfg32 (R_SA_IGD_GTTMMADR));
+ GTTMMADR = LShiftU64 ((UINT64) McD2PciCfg32 (R_SA_IGD_GTTMMADR + 4), 32) | (GTTMMADR);
+
+ ///
+ /// Save the current GTMMADR value into S3 resume script before other S3 resume items in this function.
+ /// GTTMMADR may have been modified by the PCI enumeration code at this point,
+ /// but not saved into the S3 resume script yet.
+ ///
+ ///
+ /// only 32bit read/write is legal for device 0:2:0
+ ///
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0,
+ 0,
+ 2,
+ 0,
+ R_SA_IGD_GTTMMADR)),
+ 1,
+ &GTTMMADR
+ );
+
+ ///
+ /// only 32bit read/write is legal for device 0:2:0
+ ///
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0,
+ 0,
+ 2,
+ 0,
+ R_SA_IGD_GTTMMADR + 4)),
+ 1,
+ (&(UINT32) GTTMMADR) + 1
+ );
+
+ GTTMMADR = GTTMMADR &~(BIT2 | BIT1);
+
+ ///
+ /// Enable Bus Master, I/O and Memory access on 0:2:0
+ ///
+ McD2PciCfg16Or (R_SA_IGD_CMD, (BIT2 | BIT1));
+ Data16 = McD2PciCfg16(R_SA_IGD_CMD);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (MmPciAddress (0, 0, 2, 0, R_SA_IGD_CMD)),
+ 1,
+ &Data16
+ );
+
+ ///
+ /// Deassert Force Wake
+ RegOffset = 0xA188;
+ Data32 = 0x00010000;
+ Mmio32 (GTTMMADR, RegOffset) = Data32;
+
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ 1,
+ &Data32
+ );
+
+ RegOffset = 0x130044;
+ Data32Mask = BIT0;
+ Result = 0;
+ PollGtReady (GTTMMADR, RegOffset, Data32Mask, Result);
+
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ &Data32Mask,
+ &Result,
+ 50,
+ 200000
+ );
+
+ RegOffset = 0xA188;
+ Data32 = 0x00000001;
+ Mmio32 (GTTMMADR, RegOffset) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + RegOffset),
+ 1,
+ &Data32
+ );
+
+
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+
+
+#ifndef AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+#if (defined(IntelSaGopDriver_SUPPORT) && (IntelSaGopDriver_SUPPORT == 1))
+{
+ EFI_PHYSICAL_ADDRESS VbtAddress;
+ UINT32 VbtSize;
+ PLATFORM_GOP_POLICY_PROTOCOL *PlatformGOPPolicy;
+ EFI_GUID PlatformGOPPolicyGuid = EFI_PLATFORM_GOP_POLICY_PROTOCOL_GUID;
+ EFI_STATUS Status2 = EFI_SUCCESS;
+ //
+ // Locate Platform GOP policy protocol
+ //
+ Status = gBS->LocateProtocol (&PlatformGOPPolicyGuid, NULL, &PlatformGOPPolicy);
+ if (!EFI_ERROR(Status)) {
+ Status2 = PlatformGOPPolicy->GetVbtData(&VbtAddress, &VbtSize);
+ if (!EFI_ERROR(Status2)) LegacyBios = NULL;
+ }
+}
+#endif
+#endif // AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+
+ if (!LegacyBios) {
+ Status = gBS->LocateProtocol (&gGopComponentName2ProtocolGuid, NULL, (VOID **)&GopComponentName2Protocol);
+ if (!EFI_ERROR (Status)) {
+ Status = GopComponentName2Protocol->GetDriverVersion (
+ GopComponentName2Protocol,
+ "en-US",
+ &DriverVersion
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; (DriverVersion[Index] != '\0'); Index++) {
+ }
+ Index = (Index+1)*2;
+ CopyMem(mDxePlatformSaPolicy->IgdConfig->GopVersion, DriverVersion, Index);
+ }
+ }
+ }
+
+ ///
+ /// Return final status
+ ///
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GraphicsInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+Initialize GT Post Routines.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - GT POST initialization complete
+ @retval EFI_NOT_FOUND - Dxe System Table not found.
+**/
+{
+ EFI_PHYSICAL_ADDRESS MemBaseAddress;
+ UINT32 LoGTBaseAddress;
+ UINT32 HiGTBaseAddress;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ EFI_STATUS Status;
+ UINTN DwordData;
+ UINT32 Data32Mask;
+ UINT32 Result;
+ UINT16 Data16;
+ CPU_FAMILY CpuFamilyId;
+ UINT8 CpuSteppingId;
+ UINT32 Data32;
+ UINT16 IsUlx;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ GTTMMADR = 0;
+ Status = EFI_SUCCESS;
+ MCHBAR_BASE = McD0PciCfg64 (0x48) &~BIT0;
+
+ ///
+ /// Read the RP1 Graphics Frequency
+ ///
+ rP1GraphicsFreq = (UINT8) ((Mmio32 (MCHBAR_BASE, 0x5998) >> 8) & 0xFF);
+
+ ///
+ /// If device 0:2:0 (Internal Graphics Device, or GT) is enabled, then Program GTTMMADR,
+ ///
+ if (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF) {
+ gDS = NULL;
+ Status = EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT(gDS != NULL);
+ if (gDS == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ///
+ /// Means Allocate 4MB for GTTMADDR
+ ///
+ MemBaseAddress = 0x0ffffffffffffffff;
+
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAnySearchBottomUp,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ GTT_MEM_ALIGN,
+ GTTMMADR_SIZE_4MB,
+ &MemBaseAddress,
+ ImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Program GT PM Settings if GTTMMADR allocation is Successful
+ ///
+ GTTMMADR = (UINTN) MemBaseAddress;
+
+ LoGTBaseAddress = (UINT32) (MemBaseAddress & 0xFFFFFFFF);
+ HiGTBaseAddress = (UINT32) RShiftU64 ((MemBaseAddress & 0xFFFFFFFF00000000), 32);
+ McD2PciCfg32 (R_SA_IGD_GTTMMADR) = LoGTBaseAddress | BIT2;
+ McD2PciCfg32 (R_SA_IGD_GTTMMADR + 4) = HiGTBaseAddress;
+
+ DwordData = McD2PciCfg32 (R_SA_IGD_GTTMMADR);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0,
+ 0,
+ 2,
+ 0,
+ R_SA_IGD_GTTMMADR)),
+ 1,
+ &DwordData
+ );
+
+ DwordData = McD2PciCfg32 (R_SA_IGD_GTTMMADR + 4);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0,
+ 0,
+ 2,
+ 0,
+ R_SA_IGD_GTTMMADR + 4)),
+ 1,
+ &DwordData
+ );
+
+ ///
+ /// Enable Bus Master, I/O and Memory access on 0:2:0
+ ///
+ McD2PciCfg16Or (R_SA_IGD_CMD, (BIT2 | BIT1));
+ Data16 = McD2PciCfg16 (R_SA_IGD_CMD);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (MmPciAddress (0, 0, 2, 0, R_SA_IGD_CMD)),
+ 1,
+ &Data16
+ );
+
+ ///
+ /// PAVP Initialization
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing PAVP\n"));
+ PavpInit (ImageHandle, DxePlatformSaPolicy);
+ ///
+ /// PmInit Initialization
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing GT PowerManagement\n"));
+ PmInit (ImageHandle, DxePlatformSaPolicy);
+
+ ///
+ /// Enable PowerWell for DP and Audio: set Dev2 mmio 45400 bit 31 and poll bit30 (1 means enabled)
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) (BIT31);
+ Mmio32Or (GTTMMADR, 0x45400, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x45400),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ Data32Mask = BIT30;
+ Result = BIT30;
+ PollGtReady (GTTMMADR, 0x45400, Data32Mask, Result);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x45400),
+ &Data32Mask,
+ &Result,
+ 50,
+ 200000
+ );
+
+ if (DxePlatformSaPolicy->Revision >=4) {
+ IsUlx = 0;
+ Data16 = McD2PciCfg16 (0x2);
+ if ((Data16 == 0xA0E) || (Data16 == 0xA1E)) {
+ IsUlx = 1;
+ }
+ ///
+ /// BIOS to get supported CD frequency
+ ///
+ if (((MmioRead32 (GTTMMADR + 0x42014) & 0x1000000) != 0) || (IsUlx == 1) || (CpuFamilyId == EnumCpuHswUlt)) {
+ ///fixed frequency
+ mDxePlatformSaPolicy->IgdConfig->CdClkVar = 0;
+ } else {
+ ///choice of varying frequency
+ mDxePlatformSaPolicy->IgdConfig->CdClkVar = 2;
+ }
+
+ if (IsUlx == 1) {
+ Data32And = 0xF7FFFFFF;
+ Data32Or = 0x4000000;
+ } else {
+ if ((mDxePlatformSaPolicy->IgdConfig->CdClk) != 1) {
+ if ((mDxePlatformSaPolicy->IgdConfig->CdClkVar != 0)) {
+ ///540 or 337.5Mhz
+ Data32And = 0xF7FFFFFF;
+ Data32Or = 0x4000000;
+ }
+ } else {
+ ///450 Mhz
+ Data32And = 0xF3FFFFFF;
+ Data32Or = 0;
+ }
+ }
+ Mmio32AndThenOr (GTTMMADR, 0x130040, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x130040),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ if ((CpuFamilyId == EnumCpuHswUlt)||(IsUlx == 1)) {
+ Data32 = 1;
+ if (((mDxePlatformSaPolicy->IgdConfig->CdClk) == 1) && (IsUlx == 0)) {
+ Data32 = 0;
+ }
+
+ Mmio32 (GTTMMADR, 0x138128) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x138128),
+ 1,
+ &Data32
+ );
+
+ Data32 = 0x0;
+ Mmio32 (GTTMMADR, 0x13812c) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x13812c),
+ 1,
+ &Data32
+ );
+
+ Data32 = 0x80000017;
+ Mmio32 (GTTMMADR, 0x138124) = Data32;
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (GTTMMADR + 0x138124),
+ 1,
+ &Data32
+ );
+ }
+ }
+
+ McD2PciCfg16And (R_SA_IGD_CMD, ~(BIT2 | BIT1));
+ Data16 = McD2PciCfg16(R_SA_IGD_CMD);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (MmPciAddress (0, 0, 2, 0, R_SA_IGD_CMD)),
+ 1,
+ &Data16
+ );
+
+ McD2PciCfg64 (R_SA_IGD_GTTMMADR) = 0;
+ DwordData = McD2PciCfg64(R_SA_IGD_GTTMMADR);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0, 0, 2, 0, R_SA_IGD_GTTMMADR)),
+ 1,
+ &DwordData
+ );
+
+ ///
+ /// Free allocated resources
+ ///
+ gDS->FreeMemorySpace (MemBaseAddress, GTTMMADR_SIZE_4MB);
+ }
+
+ ///
+ /// Lock PAVPC Register
+ ///
+ McD0PciCfg32Or (R_SA_PAVPC, B_SA_PAVPC_PAVPLCK_MASK);
+
+ DwordData = McD0PciCfg32 (R_SA_PAVPC);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0,
+ 0,
+ 0,
+ 0,
+ R_SA_PAVPC)),
+ 1,
+ &DwordData
+ );
+
+ return EFI_SUCCESS;
+}
+
+VOID
+PollGtReady (
+ UINT64 Base,
+ UINT32 Offset,
+ UINT32 Mask,
+ UINT32 Result
+ )
+/**
+ "Poll Status" for GT Readiness
+
+ @param[in] Base - Base address of MMIO
+ @param[in] Offset - MMIO Offset
+ @param[in] Mask - Mask
+ @param[in] Result - Value to wait for
+**/
+{
+ UINT32 GtStatus;
+ UINT16 StallCount;
+
+ StallCount = 0;
+
+ ///
+ /// Register read
+ ///
+ GtStatus = Mmio32 (Base, Offset);
+
+ while (((GtStatus & Mask) != Result) && (StallCount < GT_WAIT_TIMEOUT)) {
+
+ GtStatus = Mmio32 (Base, Offset);
+ ///
+ /// 1mSec wait
+ ///
+ gBS->Stall (1000);
+ StallCount = StallCount + 1;
+ }
+
+ ASSERT ((StallCount != GT_WAIT_TIMEOUT));
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.h
new file mode 100644
index 0000000..d5696e3
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/graphicsinit.h
@@ -0,0 +1,132 @@
+/** @file
+ Header file for initialization of GT PowerManagement
+
+@copyright
+ Copyright (c) 1999 - 2013 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
+**/
+#ifndef _GRAPHICS_INIT_H_
+#define _GRAPHICS_INIT_H_
+
+#include "EdkIIGlueDxe.h"
+#include "SaAccess.h"
+#include "EfiScriptLib.h"
+#include EFI_PROTOCOL_DEFINITION (SaPlatformPolicy)
+#include EFI_PROTOCOL_DEFINITION (PciHostBridgeResourceAllocation)
+#include EFI_PROTOCOL_CONSUMER (ExitPmAuth)
+#include "SaInit.h"
+#include "PchAccess.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+
+///
+/// Data definitions
+///
+///
+/// GT RELATED EQUATES
+///
+#define GTT_MEM_ALIGN 22
+#define GTTMMADR_SIZE_4MB 0x400000
+#define GT_WAIT_TIMEOUT 3000 ///< ~3 seconds
+
+///
+/// PAVP Modes
+///
+#define PAVP_LITE_MODE 1
+#define PAVP_SERPENT_MODE 2
+#define PAVP_PCM_SIZE_1_MB 1
+
+EFI_STATUS
+PavpInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Initialize PAVP feature of SystemAgent.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - PAVP initialization complete
+**/
+;
+
+/**
+ Initialize PAVP.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - PAVP initialization complete
+**/
+EFI_STATUS
+PmInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Initialize GT PowerManagement of SystemAgent.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - GT Power Management initialization complete
+**/
+;
+
+EFI_STATUS
+GraphicsInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+/**
+ Initialize GT PowerManagement of SystemAgent.
+
+ @param[in] ImageHandle - Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy - SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - GT Power Management initialization complete
+**/
+;
+
+VOID
+PollGtReady (
+ UINT64 Base,
+ UINT32 Offset,
+ UINT32 Mask,
+ UINT32 Result
+ )
+/**
+ "Poll Status" for GT Readiness
+
+ @param[in] Base - Base address of MMIO
+ @param[in] Offset - MMIO Offset
+ @param[in] Mask - Mask
+ @param[in] Result - Value to wait for
+**/
+;
+
+EFI_STATUS
+PostPmInitExitPmAuth (
+ VOID
+ )
+/**
+ Do Post GT PM Init Steps after VBIOS Initialization.
+
+ @retval EFI_SUCCESS Succeed.
+**/
+;
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.c
new file mode 100644
index 0000000..0774807
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.c
@@ -0,0 +1,955 @@
+/** @file
+ This is part of the implementation of an Intel Graphics drivers OpRegion /
+ Software SCI interface between system BIOS, ASL code, and Graphics drivers.
+ The code in this file will load the driver and initialize the interface
+
+ Supporting Specifiction: OpRegion / Software SCI SPEC 0.70
+
+ Acronyms:
+ IGD: Internal Graphics Device
+ NVS: ACPI Non Volatile Storage
+ OpRegion: ACPI Operational Region
+ VBT: Video BIOS Table (OEM customizable data)
+
+@copyright
+ Copyright (c) 1999 - 2013 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 files
+///
+#include "IgdOpRegion.h"
+#include "CpuIA32.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+#include <Protocol\SaPlatformPolicy\SaPlatformPolicy.h>
+#ifndef AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+#include "Token.h"
+#if (defined(IntelSaGopDriver_SUPPORT) && (IntelSaGopDriver_SUPPORT == 1))
+#include "Include\Protocol\IntelSaGopDriver.h"
+#endif
+#endif
+
+///
+/// Global variables
+///
+IGD_OPREGION_PROTOCOL mIgdOpRegion;
+EFI_GUID mMiscSubClass = EFI_MISC_SUBCLASS_GUID;
+EFI_EVENT mExitPmAuthEvent;
+BOOLEAN mRunExitPmAuthRoutine;
+SYSTEM_AGENT_GLOBAL_NVS_AREA_PROTOCOL *mSaGlobalNvsArea;
+DXE_PLATFORM_SA_POLICY_PROTOCOL *mDxePlatformSaPolicy;
+
+///
+/// Function implementations.
+///
+EFI_STATUS
+GetIntegratedIntelVbtPtr (
+ OUT VBIOS_VBT_STRUCTURE **VbtFileBuffer
+ )
+/**
+ Get VBT data using SaPlaformPolicy
+
+ @param[in] VbtFileBuffer Pointer to VBT data buffer.
+
+ @retval EFI_SUCCESS VBT data was returned.
+ @retval EFI_NOT_FOUND VBT data not found.
+ @exception EFI_UNSUPPORTED Invalid signature in VBT data.
+**/
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS VbtAddress;
+ UINT32 Size;
+
+ ///
+ /// Get the platform SA policy.
+ ///
+ Status = gBS->LocateProtocol (
+ &gDxePlatformSaPolicyGuid,
+ NULL,
+ (VOID **) &mDxePlatformSaPolicy
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ VbtAddress = mDxePlatformSaPolicy->IgdConfig->VbtAddress;
+ Size = mDxePlatformSaPolicy->IgdConfig->Size ;
+
+ if (VbtAddress == 0x00000000) {
+ return EFI_NOT_FOUND;
+ } else {
+ ///
+ /// Check VBT signature
+ ///
+ *VbtFileBuffer = NULL;
+ *VbtFileBuffer = (VBIOS_VBT_STRUCTURE *) (UINTN) VbtAddress;
+ if ((*((UINT32 *) ((*VbtFileBuffer)->HeaderSignature))) != VBT_SIGNATURE) {
+ FreePool (*VbtFileBuffer);
+ *VbtFileBuffer = NULL;
+ return EFI_UNSUPPORTED;
+ }
+ }
+ if (Size == 0) {
+ return EFI_NOT_FOUND;
+ } else {
+ ///
+ /// Check VBT size
+ ///
+ if ((*VbtFileBuffer)->HeaderVbtSize > Size) {
+ (*VbtFileBuffer)->HeaderVbtSize = (UINT16) Size;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetIntegratedIntelVBiosPtr (
+ OUT INTEL_VBIOS_OPTION_ROM_HEADER **VBiosImage
+ )
+/**
+ Get a pointer to an uncompressed image of the Intel video BIOS.
+
+ Note: This function would only be called if the video BIOS at 0xC000 is
+ missing or not an Intel video BIOS. It may not be an Intel video BIOS
+ if the Intel graphic contoller is considered a secondary adapter.
+
+ @param[in] VBiosImage - Pointer to an uncompressed Intel video BIOS. This pointer must
+ be set to NULL if an uncompressed image of the Intel Video BIOS
+ is not obtainable.
+
+ @retval EFI_SUCCESS - VBiosPtr is updated.
+ @exception EFI_UNSUPPORTED - No Intel video BIOS found.
+**/
+
+{
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ INTEL_VBIOS_PCIR_STRUCTURE *PcirBlockPtr;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ INTEL_VBIOS_OPTION_ROM_HEADER *VBiosRomImage;
+ ///
+ /// Set as if an umcompressed Intel video BIOS image was not obtainable.
+ ///
+ VBiosRomImage = NULL;
+
+ ///
+ /// Get all PCI IO protocols
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Find the video BIOS by checking each PCI IO handle for an Intel video
+ /// BIOS OPROM.
+ ///
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ VBiosRomImage = PciIo->RomImage;
+
+ ///
+ /// If this PCI device doesn't have a ROM image, skip to the next device.
+ ///
+ if (!VBiosRomImage) {
+ continue;
+ }
+ ///
+ /// Get pointer to PCIR structure
+ ///
+ PcirBlockPtr = (INTEL_VBIOS_PCIR_STRUCTURE *) ((UINT8 *) VBiosRomImage + VBiosRomImage->PcirOffset);
+
+ ///
+ /// Check if we have an Intel video BIOS OPROM.
+ ///
+ if ((VBiosRomImage->Signature == OPTION_ROM_SIGNATURE) &&
+ (PcirBlockPtr->VendorId == V_SA_MC_VID) &&
+ (PcirBlockPtr->ClassCode[0] == 0x00) &&
+ (PcirBlockPtr->ClassCode[1] == 0x00) &&
+ (PcirBlockPtr->ClassCode[2] == 0x03)
+ ) {
+ ///
+ /// Found Intel video BIOS.
+ ///
+ *VBiosImage = VBiosRomImage;
+ return EFI_SUCCESS;
+ }
+ }
+ ///
+ /// No Intel video BIOS found.
+ ///
+ ///
+ /// Free any allocated buffers
+ ///
+ FreePool (HandleBuffer);
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+GetVBiosVbtExitPmAuth (
+ VOID
+ )
+/**
+ Get Intel video BIOS VBT information (i.e. Pointer to VBT and VBT size).
+ The VBT (Video BIOS Table) is a block of customizable data that is built
+ within the video BIOS and edited by customers.
+
+ @retval EFI_SUCCESS - Video BIOS VBT information returned.
+ @exception EFI_UNSUPPORTED - Could not find VBT information (*VBiosVbtPtr = NULL).
+**/
+{
+ INTEL_VBIOS_PCIR_STRUCTURE *PcirBlockPtr;
+ UINT16 PciVenderId;
+ INTEL_VBIOS_OPTION_ROM_HEADER *VBiosPtr;
+ VBIOS_VBT_STRUCTURE *VBiosVbtPtr;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_STATUS Status;
+ VBIOS_VBT_STRUCTURE *VbtFileBuffer;
+ UINTN Index;
+#ifndef AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+#if (defined(IntelSaGopDriver_SUPPORT) && (IntelSaGopDriver_SUPPORT == 1))
+ EFI_PHYSICAL_ADDRESS VbtAddress;
+ UINT32 VbtSize;
+ PLATFORM_GOP_POLICY_PROTOCOL *PlatformGOPPolicy;
+ EFI_GUID PlatformGOPPolicyGuid = EFI_PLATFORM_GOP_POLICY_PROTOCOL_GUID;
+ EFI_STATUS Status2 = EFI_SUCCESS;
+#endif
+#endif // AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+
+ if (!mRunExitPmAuthRoutine) {
+ return EFI_SUCCESS;
+ }
+
+ ///
+ /// Get the platform SA policy.
+ ///
+ Status = gBS->LocateProtocol (
+ &gDxePlatformSaPolicyGuid,
+ NULL,
+ (VOID **) &mDxePlatformSaPolicy
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios = NULL;
+ VBiosPtr = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+
+#ifndef AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+#if (defined(IntelSaGopDriver_SUPPORT) && (IntelSaGopDriver_SUPPORT == 1))
+ //
+ // Locate Platform GOP policy protocol
+ //
+ Status = gBS->LocateProtocol (&PlatformGOPPolicyGuid, NULL, &PlatformGOPPolicy);
+ if (!EFI_ERROR(Status)) {
+ Status2 = PlatformGOPPolicy->GetVbtData(&VbtAddress, &VbtSize);
+ if (!EFI_ERROR(Status2)) LegacyBios = NULL;
+ }
+#endif
+#endif // AMI_OVERRIDE_FOR_INTEL_GOP_SUPPORT
+
+ if (LegacyBios) {
+ VBiosPtr = (INTEL_VBIOS_OPTION_ROM_HEADER *) (UINTN) (VBIOS_LOCATION_PRIMARY);
+ PcirBlockPtr = (INTEL_VBIOS_PCIR_STRUCTURE *) ((UINT8 *) VBiosPtr + VBiosPtr->PcirOffset);
+ PciVenderId = PcirBlockPtr->VendorId;
+ ///
+ /// If the video BIOS is not at 0xC0000 or it is not an Intel video BIOS get
+ /// the integrated Intel video BIOS (must be uncompressed).
+ ///
+ if ((VBiosPtr->Signature != OPTION_ROM_SIGNATURE) || (PciVenderId != V_SA_MC_VID)) {
+ GetIntegratedIntelVBiosPtr (&VBiosPtr);
+ if (VBiosPtr != NULL) {
+ ///
+ /// Video BIOS found.
+ ///
+ PcirBlockPtr = (INTEL_VBIOS_PCIR_STRUCTURE *) ((UINT8 *) VBiosPtr + VBiosPtr->PcirOffset);
+ PciVenderId = PcirBlockPtr->VendorId;
+
+ if ((VBiosPtr->Signature != OPTION_ROM_SIGNATURE) || (PciVenderId != V_SA_MC_VID)) {
+ ///
+ /// Intel video BIOS not found.
+ ///
+ VBiosVbtPtr = NULL;
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+ } else {
+ ///
+ /// No Video BIOS found, try to get VBT from FV.
+ ///
+ GetIntegratedIntelVbtPtr (&VbtFileBuffer);
+ if (VbtFileBuffer != NULL) {
+ ///
+ /// Video BIOS not found, use VBT from SaPlatformPolicy
+ ///
+ DEBUG ((EFI_D_INFO, "VBT data found\n"));
+ for (Index = 0; (mDxePlatformSaPolicy->IgdConfig->GopVersion[Index] != '\0'); Index++) {
+ }
+ Index = (Index+1)*2;
+ CopyMem (mIgdOpRegion.OpRegion->Header.DVER, mDxePlatformSaPolicy->IgdConfig->GopVersion, Index);
+ (gBS->CopyMem) (mIgdOpRegion.OpRegion->VBT.GVD1, VbtFileBuffer, VbtFileBuffer->HeaderVbtSize);
+ FreePool (VbtFileBuffer);
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (VBiosPtr == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG ((EFI_D_INFO, "VBIOS found at 0x%X\n", VBiosPtr));
+ VBiosVbtPtr = (VBIOS_VBT_STRUCTURE *) ((UINT8 *) VBiosPtr + VBiosPtr->VbtOffset);
+
+ if ((*((UINT32 *) (VBiosVbtPtr->HeaderSignature))) != VBT_SIGNATURE) {
+ return EFI_UNSUPPORTED;
+ }
+ ///
+ /// No PlatformGopPolicy.h in EDK II code
+ ///
+#if 0
+ GetSVER (mIgdOpRegion.OpRegion->Header.SVER);
+#endif
+ DEBUG ((EFI_D_INFO, "System BIOS ID is %a\n", mIgdOpRegion.OpRegion->Header.SVER));
+
+ ///
+ /// Initialize Video BIOS version with its build number.
+ ///
+ mIgdOpRegion.OpRegion->Header.VVER[0] = VBiosVbtPtr->CoreBlockBiosBuild[0];
+ mIgdOpRegion.OpRegion->Header.VVER[1] = VBiosVbtPtr->CoreBlockBiosBuild[1];
+ mIgdOpRegion.OpRegion->Header.VVER[2] = VBiosVbtPtr->CoreBlockBiosBuild[2];
+ mIgdOpRegion.OpRegion->Header.VVER[3] = VBiosVbtPtr->CoreBlockBiosBuild[3];
+ (gBS->CopyMem) (mIgdOpRegion.OpRegion->VBT.GVD1, VBiosVbtPtr, VBiosVbtPtr->HeaderVbtSize);
+
+ ///
+ /// Return final status
+ ///
+ return EFI_SUCCESS;
+}
+///
+/// No PlatformGopPolicy.h in EDK II code
+///
+#if 0
+EFI_STATUS
+GetSVER (
+ OUT UINT8 *SVER
+ )
+/**
+ Set the SVER (system BIOS ID) string with the system BIOS build number.
+
+ @param[in] SVER String to populate with system BIOS build number.
+
+ @retval EFI_SUCCESS The SVER string is populated.
+ @exception EFI_UNSUPPORTED The SVER string is not populated.
+**/
+{
+ EFI_SUBCLASS_TYPE1_HEADER *DataHeader;
+ EFI_DATA_HUB_PROTOCOL *DataHub;
+ EFI_MISC_BIOS_VENDOR *BiosVendor;
+ UINTN Length;
+ UINT64 MonotonicCount;
+ CHAR16 *NewString;
+ EFI_DATA_RECORD_HEADER *Record;
+ EFI_STATUS Status;
+
+ ///
+ /// Locate the data hub protocol.
+ ///
+ Status = gBS->LocateProtocol (
+ &gEfiDataHubProtocolGuid,
+ NULL,
+ &DataHub
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Get the BIOS ID from the data hub.
+ ///
+ MonotonicCount = 0;
+ Record = NULL;
+
+ do {
+ ///
+ /// Check each data class record
+ ///
+ Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {
+ ///
+ /// Check for BIOS vendor information
+ ///
+ DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);
+ if (CompareGuid (&Record->DataRecordGuid, &mMiscSubClass) &&
+ (DataHeader->RecordType == EFI_MISC_BIOS_VENDOR_RECORD_NUMBER)
+ ) {
+ BiosVendor = (EFI_MISC_BIOS_VENDOR *) (DataHeader + 1);
+
+ ///
+ /// Get the BIOS ID string from the HII database
+ ///
+ Status = GetStringFromToken (&Record->ProducerName, BiosVendor->BiosVersion, &NewString);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Convert from Unicode to ASCII
+ ///
+ if (NewString != NULL) {
+ Length = StrLen (NewString);
+ ASSERT (Length <= SVER_SIZE);
+ ASPrint (SVER, Length, "%s", NewString);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ } while ((!EFI_ERROR (Status)) && (MonotonicCount != 0));
+
+ ///
+ /// We assume BIOS ID is present and required.
+ /// If this is not the case, BIOS ID will need to be determined in another way.
+ ///
+ ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
+ return EFI_UNSUPPORTED;
+}
+
+#if (EFI_SPECIFICATION_VERSION < 0x0002000A)
+EFI_STATUS
+GetStringFromToken (
+ IN EFI_GUID *ProducerGuid,
+ IN STRING_REF Token,
+ OUT CHAR16 **String
+ )
+/**
+ Acquire the string associated with the ProducerGuid and return it.
+
+ @param[in] ProducerGuid - The Guid to search the HII database for
+ @param[in] Token - The token value of the string to extract
+ @param[in] String - The string that is extracted
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_NOT_FOUND The requested string was not found
+**/
+{
+ EFI_STATUS Status;
+ UINT16 HandleBufferLength;
+ EFI_HII_HANDLE *HiiHandleBuffer;
+ UINTN StringBufferLength;
+ UINTN NumberOfHiiHandles;
+ UINTN Index;
+ UINT16 Length;
+ EFI_GUID HiiGuid;
+ EFI_HII_PROTOCOL *Hii;
+
+ HandleBufferLength = 0x1000;
+ HiiHandleBuffer = NULL;
+
+ ///
+ /// Locate HII protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, &Hii);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Get all the Hii handles
+ ///
+ HiiHandleBuffer = AllocateZeroPool (HandleBufferLength);
+
+ Status = Hii->FindHandles (Hii, &HandleBufferLength, HiiHandleBuffer);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Get the Hii Handle that matches the StructureNode->ProducerName
+ ///
+ NumberOfHiiHandles = HandleBufferLength / sizeof (EFI_HII_HANDLE);
+ for (Index = 0; Index < NumberOfHiiHandles; Index++) {
+ Length = 0;
+ Status = ExtractDataFromHiiHandle (
+ HiiHandleBuffer[Index],
+ &Length,
+ NULL,
+ &HiiGuid
+ );
+ if (CompareGuid (ProducerGuid, &HiiGuid)) {
+ break;
+ }
+ }
+ ///
+ /// Find the string based on the current language
+ ///
+ StringBufferLength = 0x100;
+ *String = AllocateZeroPool (0x100);
+ Status = Hii->GetString (
+ Hii,
+ HiiHandleBuffer[Index],
+ Token,
+ FALSE,
+ NULL,
+ &StringBufferLength,
+ *String
+ );
+
+ (gBS->FreePool) (HiiHandleBuffer);
+
+ if (EFI_ERROR (Status)) {
+ (gBS->FreePool) (*String);
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+#endif
+#endif
+
+EFI_STATUS
+IgdOpRegionInit (
+ VOID
+ )
+/**
+ Graphics OpRegion / Software SCI driver installation function.
+
+ @param[in] void - None
+ @retval EFI_SUCCESS - The driver installed without error.
+ @retval EFI_ABORTED - The driver encountered an error and could not complete
+ installation of the ACPI tables.
+**/
+
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ ///
+ /// VBIOS_VBT_STRUCTURE *VBiosVbtPtr;
+ ///
+ UINT32 DwordData;
+ EFI_CPU_IO_PROTOCOL *CpuIo;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT16 PchAcpiBaseAddress;
+ UINT16 DeviceId;
+ PCH_SERIES PchSeries;
+ CPU_FAMILY CpuFamilyId;
+ EFI_GUID DxePlatformSaPolicyGuid = DXE_PLATFORM_SA_POLICY_GUID;
+ DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy;
+
+ CpuFamilyId = GetCpuFamily();
+
+ ///
+ /// Get the platform SA policy.
+ ///
+ Status = gBS->LocateProtocol (
+ &gDxePlatformSaPolicyGuid,
+ NULL,
+ (VOID **) &mDxePlatformSaPolicy
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ///
+ /// Locate the SA Global NVS Protocol.
+ ///
+ Status = gBS->LocateProtocol (
+ &gSaGlobalNvsAreaProtocolGuid,
+ NULL,
+ (VOID **) &mSaGlobalNvsArea
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Allocate an ACPI NVS memory buffer as the IGD OpRegion, zero initialize
+ /// the first 1K, and set the IGD OpRegion pointer in the Global NVS
+ /// area structure.
+ ///
+ Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (IGD_OPREGION_STRUC), (VOID **) &mIgdOpRegion.OpRegion);
+ ASSERT_EFI_ERROR (Status);
+
+ (gBS->SetMem) (mIgdOpRegion.OpRegion, 0x2000, 0);
+ mSaGlobalNvsArea->Area->IgdOpRegionAddress = (UINT32) (UINTN) (mIgdOpRegion.OpRegion);
+
+ ///
+ /// If IGD is disabled return
+ ///
+ mRunExitPmAuthRoutine = TRUE;
+ if (IgdMmPci32 (0) == 0xFFFFFFFF) {
+ mRunExitPmAuthRoutine = FALSE;
+ return EFI_SUCCESS;
+ }
+
+ PchSeries = GetPchSeries();
+ ///
+ /// Initialize OpRegion Header
+ ///
+ (gBS->CopyMem) (mIgdOpRegion.OpRegion->Header.SIGN, HEADER_SIGNATURE, sizeof (HEADER_SIGNATURE));
+ ///
+ /// Set OpRegion Size in KBs
+ ///
+ mIgdOpRegion.OpRegion->Header.SIZE = HEADER_SIZE / 1024;
+ mIgdOpRegion.OpRegion->Header.OVER = (UINT32) (LShiftU64 (HEADER_OPREGION_VER, 16) + LShiftU64 (HEADER_OPREGION_REV, 8));
+
+ ///
+ /// Get CPU Flavor by reading System Agent's Device ID (B0:D1F:F0:R02)
+ ///
+ DeviceId = McD0PciCfg16 (R_SA_MC_DEVICE_ID);
+ if (IS_SA_DEVICE_ID_MOBILE (DeviceId)) {
+ ///
+ /// For Mobile, all Mailbox are supported.
+ ///
+ mIgdOpRegion.OpRegion->Header.MBOX = HEADER_MBOX_SUPPORT_MOBILE;
+ } else if (IS_SA_DEVICE_ID_DESKTOP (DeviceId) || IS_SA_DEVICE_ID_SERVER (DeviceId)) {
+ ///
+ /// For Desktop and Server, Mailbox 1/3/5 are not supported.
+ ///
+ mIgdOpRegion.OpRegion->Header.MBOX = HEADER_MBOX_SUPPORT_DESKTOP;
+ } else {
+ DEBUG ((EFI_D_ERROR, "Hang if unknown System Agent\n"));
+ ASSERT (FALSE);
+ ///
+ /// Hang if unknown System Agent
+ ///
+ }
+ ///
+ /// Initialize OpRegion Mailbox 1 (Public ACPI Methods).
+ ///
+ /// @todo: The initial setting of mailbox 1 fields is implementation specific.
+ /// Adjust them as needed many even coming from user setting in setup.
+ ///
+ ///
+ /// Initialize OpRegion Mailbox 3 (ASLE Interrupt and Power Conservation).
+ ///
+ /// @todo: The initial setting of mailbox 3 fields is implementation specific.
+ /// Adjust them as needed many even coming from user setting in setup.
+ ///
+ ///
+ /// Do not initialize TCHE. This field is written by the graphics driver only.
+ ///
+ ///
+ /// The ALSI field is generally initialized by ASL code by reading the embedded controller.
+ ///
+ if (mDxePlatformSaPolicy->Revision >= 5) {
+ mIgdOpRegion.OpRegion->Header.PCON = mDxePlatformSaPolicy->IgdConfig->PlatformConfig;
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ mIgdOpRegion.OpRegion->Header.PCON = mIgdOpRegion.OpRegion->Header.PCON | 0x2;
+ }
+ }
+ mIgdOpRegion.OpRegion->MBox3.BCLP = BACKLIGHT_BRIGHTNESS;
+
+ mIgdOpRegion.OpRegion->MBox3.PFIT = (FIELD_VALID_BIT | PFIT_STRETCH);
+
+ ///
+ /// Reporting to driver for VR IMON Calibration. Bits [5-1] values supported 14A to 31A.
+ ///
+ mIgdOpRegion.OpRegion->MBox3.PCFT = (mSaGlobalNvsArea->Area->GfxTurboIMON << 1) & 0x003E;
+
+ ///
+ /// Set Initial current Brightness
+ ///
+ mIgdOpRegion.OpRegion->MBox3.CBLV = (INIT_BRIGHT_LEVEL | FIELD_VALID_BIT);
+
+ ///
+ /// <EXAMPLE> Create a static Backlight Brightness Level Duty cycle Mapping Table
+ /// Possible 20 entries (example used 10), each 16 bits as follows:
+ /// [15] = Field Valid bit, [14:08] = Level in Percentage (0-64h), [07:00] = Desired duty cycle (0 - FFh).
+ ///
+ mIgdOpRegion.OpRegion->MBox3.BCLM[0] = (0x0000 + WORD_FIELD_VALID_BIT); ///< 0%
+ ///
+ mIgdOpRegion.OpRegion->MBox3.BCLM[1] = (0x0A19 + WORD_FIELD_VALID_BIT); ///< 10%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[2] = (0x1433 + WORD_FIELD_VALID_BIT); ///< 20%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[3] = (0x1E4C + WORD_FIELD_VALID_BIT); ///< 30%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[4] = (0x2866 + WORD_FIELD_VALID_BIT); ///< 40%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[5] = (0x327F + WORD_FIELD_VALID_BIT); ///< 50%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[6] = (0x3C99 + WORD_FIELD_VALID_BIT); ///< 60%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[7] = (0x46B2 + WORD_FIELD_VALID_BIT); ///< 70%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[8] = (0x50CC + WORD_FIELD_VALID_BIT); ///< 80%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[9] = (0x5AE5 + WORD_FIELD_VALID_BIT); ///< 90%
+ mIgdOpRegion.OpRegion->MBox3.BCLM[10] = (0x64FF + WORD_FIELD_VALID_BIT); ///< 100%
+
+ mIgdOpRegion.OpRegion->MBox3.IUER = 0x00;
+
+ Status = gBS->LocateProtocol (&DxePlatformSaPolicyGuid, NULL, &DxePlatformSaPolicy);
+
+ if (!EFI_ERROR(Status)) {
+ mIgdOpRegion.OpRegion->MBox3.IUER = DxePlatformSaPolicy->IgdConfig->IuerStatusVal;
+ }
+
+ ///
+ /// Initialize hardware state:
+ /// Set ASLS Register to the OpRegion physical memory address.
+ /// Set SWSCI register bit 15 to a "1" to activate SCI interrupts.
+ ///
+ IgdMmPci32 (R_SA_IGD_ASLS_OFFSET) = (UINT32) (UINTN) (mIgdOpRegion.OpRegion);
+ IgdMmPci16AndThenOr (R_SA_IGD_SWSCI_OFFSET, ~(BIT0), BIT15);
+
+ DwordData = IgdMmPci32 (R_SA_IGD_ASLS_OFFSET);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0x0,
+ SA_IGD_BUS,
+ SA_IGD_DEV,
+ SA_IGD_FUN_0,
+ R_SA_IGD_ASLS_OFFSET)),
+ 1,
+ &DwordData
+ );
+ DwordData = IgdMmPci32 (R_SA_IGD_SWSCI_OFFSET);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (MmPciAddress (0x0,
+ SA_IGD_BUS,
+ SA_IGD_DEV,
+ SA_IGD_FUN_0,
+ R_SA_IGD_SWSCI_OFFSET)),
+ 1,
+ &DwordData
+ );
+ PchAcpiBaseAddress = MmPci16 (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_ACPI_BASE
+ ) &~BIT0;
+
+ ///
+ /// Find the CPU I/O Protocol. ASSERT if not found.
+ ///
+ Status = gBS->LocateProtocol (
+ &gEfiCpuIoProtocolGuid,
+ NULL,
+ (VOID **) &CpuIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ CpuIo->Io.Read (
+ CpuIo,
+ EfiCpuIoWidthUint16,
+ PchAcpiBaseAddress + PCH_TCO_BASE + R_PCH_TCO1_STS,
+ 1,
+ &Data16
+ );
+ ///
+ /// Clear the B_DMISCI_STS bit in R_TCO1_STS by writing a '1'.
+ ///
+ Data16 &= B_PCH_TCO1_STS_DMISCI;
+
+ CpuIo->Io.Write (
+ CpuIo,
+ EfiCpuIoWidthUint16,
+ PchAcpiBaseAddress + PCH_TCO_BASE + R_PCH_TCO1_STS,
+ 1,
+ &Data16
+ );
+
+ if (PchSeries == PchLp) {
+ ///
+ /// Clear the ACPI TCO status.
+ ///
+ Data32 = B_PCH_ACPI_GPE0_STS_127_96_TC0SCI;
+ CpuIo->Io.Write (
+ CpuIo,
+ EfiCpuIoWidthUint32,
+ (UINT64) (PchAcpiBaseAddress + R_PCH_ACPI_GPE0_STS_127_96),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Enable ACPI TCO SCI's.
+ ///
+ CpuIo->Io.Read (
+ CpuIo,
+ EfiCpuIoWidthUint16,
+ (UINT64) (PchAcpiBaseAddress + R_PCH_ACPI_GPE0_EN_127_96),
+ 1,
+ &Data16
+ );
+ Data16 |= B_PCH_ACPI_GPE0_EN_127_96_TC0SCI;
+ CpuIo->Io.Write (
+ CpuIo,
+ EfiCpuIoWidthUint16,
+ (UINT64) (PchAcpiBaseAddress + R_PCH_ACPI_GPE0_EN_127_96),
+ 1,
+ &Data16
+ );
+ } else if (PchSeries == PchH) {
+ ///
+ /// Clear the ACPI TCO status.
+ ///
+ Data32 = B_PCH_ACPI_GPE0a_STS_TC0SCI;
+ CpuIo->Io.Write (
+ CpuIo,
+ EfiCpuIoWidthUint32,
+ (UINT64) (PchAcpiBaseAddress + R_PCH_ACPI_GPE0a_STS),
+ 1,
+ &Data32
+ );
+
+ ///
+ /// Enable ACPI TCO SCI's.
+ ///
+ CpuIo->Io.Read (
+ CpuIo,
+ EfiCpuIoWidthUint16,
+ (UINT64) (PchAcpiBaseAddress + R_PCH_ACPI_GPE0a_EN),
+ 1,
+ &Data16
+ );
+ Data16 |= B_PCH_ACPI_GPE0a_EN_TC0SCI;
+ CpuIo->Io.Write (
+ CpuIo,
+ EfiCpuIoWidthUint16,
+ (UINT64) (PchAcpiBaseAddress + R_PCH_ACPI_GPE0a_EN),
+ 1,
+ &Data16
+ );
+ }
+
+ ///
+ /// Install OpRegion / Software SCI protocol
+ ///
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gIgdOpRegionProtocolGuid,
+ &mIgdOpRegion,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Return final status
+ ///
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+UpdateIgdOpRegionExitPmAuth (
+ VOID
+ )
+/**
+ Update Graphics OpRegion after PCI enumeration.
+
+ @param[in] void - None
+ @retval EFI_SUCCESS - The function completed successfully.
+**/
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+
+ DEBUG ((EFI_D_INFO, "UpdateIgdOpRegionExitPmAuth\n"));
+
+ mIgdOpRegion.OpRegion->Header.PCON |= BIT8; //Set External Gfx Adapter field is valid
+ mIgdOpRegion.OpRegion->Header.PCON &= (UINT32) (~BIT7); //Assume No External Gfx Adapter
+
+ ///
+ /// Get all PCI IO protocols handles
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ ///
+ /// Get the PCI IO Protocol Interface corresponding to each handle
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// Read the PCI configuration space
+ ///
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+
+ ///
+ /// Find the display controllers devices
+ ///
+ if (!EFI_ERROR (Status) && IS_PCI_DISPLAY (&Pci)) {
+ Status = PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+
+ //
+ // Assumption: Onboard devices will be sits on Bus no 0, while external devices will be sits on Bus no > 0
+ //
+ if (!EFI_ERROR (Status) && (Bus > 0)) {
+ //External Gfx Adapter Detected and Available
+ DEBUG ((EFI_D_INFO, "PCON - External Gfx Adapter Detected and Available\n"));
+ mIgdOpRegion.OpRegion->Header.PCON |= BIT7;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Free any allocated buffers
+ ///
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ ///
+ /// Return final status
+ ///
+ return Status;
+} \ No newline at end of file
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.h
new file mode 100644
index 0000000..085c665
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/igdopregion.h
@@ -0,0 +1,281 @@
+/** @file
+ This is part of the implementation of an Intel Graphics drivers OpRegion /
+ Software SCI interface between system BIOS, ASL code, and Graphics drivers.
+
+ Supporting Specifiction: OpRegion / Software SCI SPEC 0.70
+
+ Acronyms:
+ IGD: Internal Graphics Device
+ NVS: ACPI Non Volatile Storage
+ OpRegion: ACPI Operational Region
+ VBT: Video BIOS Table (OEM customizable data)
+
+@copyright
+ Copyright (c) 1999 - 2013 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
+**/
+#ifndef _IGD_OPREGION_H_
+#define _IGD_OPREGION_H_
+
+///
+/// Statements that include other header files.
+///
+#include "EdkIIGlueDxe.h"
+#include "EfiScriptLib.h"
+#include "PchAccess.h"
+#include "PchPlatformLib.h"
+#include "SaAccess.h"
+#include "EfiMgmtModeRuntimeLib.h"
+#include "EfiApi.h"
+#include "pci22.h"
+
+///
+/// Driver Consumed Protocol Prototypes
+///
+#include EFI_GUID_DEFINITION (DataHubRecords)
+#include EFI_PROTOCOL_DEFINITION (SaPlatformPolicy)
+
+#include EFI_PROTOCOL_CONSUMER (PciIo)
+#include EFI_PROTOCOL_CONSUMER (PciRootBridgeIo)
+
+#include EFI_PROTOCOL_DEPENDENCY (CpuIo)
+#include EFI_PROTOCOL_DEPENDENCY (DataHub)
+#include EFI_PROTOCOL_DEPENDENCY (SaGlobalNvsArea)
+#include EFI_PROTOCOL_CONSUMER (ExitPmAuth)
+
+///
+/// Driver Produced Protocol Prototypes
+///
+#include EFI_PROTOCOL_PRODUCER (IgdOpRegion)
+
+///
+///
+/// OpRegion (Miscellaneous) #defines.
+///
+/// OpRegion Header #defines.
+///
+#define HEADER_SIGNATURE "IntelGraphicsMem"
+#define HEADER_SIZE 0x2000
+#define HEADER_OPREGION_VER 0x0200
+#define HEADER_OPREGION_REV 0x00
+#define HEADER_MBOX_SUPPORT (HD_MBOX5 + HD_MBOX4 + HD_MBOX3 + HD_MBOX2 + HD_MBOX1)
+#define HEADER_MBOX_SUPPORT_MOBILE HEADER_MBOX_SUPPORT
+#define HEADER_MBOX_SUPPORT_DESKTOP HEADER_MBOX_SUPPORT
+#define HD_MBOX1 BIT0
+#define HD_MBOX2 BIT1
+#define HD_MBOX3 BIT2
+#define HD_MBOX4 BIT3
+#define HD_MBOX5 BIT4
+#define SVER_SIZE 32
+
+///
+/// OpRegion Mailbox 1 EQUates.
+///
+/// OpRegion Mailbox 3 EQUates.
+///
+#define ALS_ENABLE BIT0
+#define BLC_ENABLE BIT1
+#define BACKLIGHT_BRIGHTNESS 0xFF
+#define FIELD_VALID_BIT BIT31
+#define WORD_FIELD_VALID_BIT BIT15
+#define PFIT_ENABLE BIT2
+#define PFIT_OPRN_AUTO 0x00000000
+#define PFIT_OPRN_SCALING 0x00000007
+#define PFIT_OPRN_OFF 0x00000000
+#define PFIT_SETUP_AUTO 0
+#define PFIT_SETUP_SCALING 1
+#define PFIT_SETUP_OFF 2
+#define INIT_BRIGHT_LEVEL 0x64
+#define PFIT_STRETCH 6
+
+///
+/// GMCH PCI register access #defines.
+///
+#define IgdMmPci32(Register) MmPci32 (0, SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, Register)
+#define IgdMmPci16Or(Register, OrData) MmPci16Or (0, SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, Register, OrData)
+#define IgdMmPci16AndThenOr(Register, AndData, OrData) \
+ MmPci16AndThenOr ( \
+ 0, \
+ SA_IGD_BUS, \
+ SA_IGD_DEV, \
+ SA_IGD_FUN_0, \
+ Register, \
+ AndData, \
+ OrData \
+ )
+
+///
+/// Video BIOS / VBT #defines
+///
+#define OPTION_ROM_SIGNATURE 0xAA55
+#define VBIOS_LOCATION_PRIMARY 0xC0000
+
+#define VBT_SIGNATURE EFI_SIGNATURE_32 ('$', 'V', 'B', 'T')
+///
+/// Typedef stuctures
+///
+#pragma pack(1)
+typedef struct {
+ UINT16 Signature; /// 0xAA55
+ UINT8 Size512;
+ UINT8 Reserved[21];
+ UINT16 PcirOffset;
+ UINT16 VbtOffset;
+} INTEL_VBIOS_OPTION_ROM_HEADER;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+ UINT32 Signature; /// "PCIR"
+ UINT16 VendorId; /// 0x8086
+ UINT16 DeviceId;
+ UINT16 Reserved0;
+ UINT16 Length;
+ UINT8 Revision;
+ UINT8 ClassCode[3];
+ UINT16 ImageLength;
+ UINT16 CodeRevision;
+ UINT8 CodeType;
+ UINT8 Indicator;
+ UINT16 Reserved1;
+} INTEL_VBIOS_PCIR_STRUCTURE;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+ UINT8 HeaderSignature[20];
+ UINT16 HeaderVersion;
+ UINT16 HeaderSize;
+ UINT16 HeaderVbtSize;
+ UINT8 HeaderVbtCheckSum;
+ UINT8 HeaderReserved;
+ UINT32 HeaderOffsetVbtDataBlock;
+ UINT32 HeaderOffsetAim1;
+ UINT32 HeaderOffsetAim2;
+ UINT32 HeaderOffsetAim3;
+ UINT32 HeaderOffsetAim4;
+ UINT8 DataHeaderSignature[16];
+ UINT16 DataHeaderVersion;
+ UINT16 DataHeaderSize;
+ UINT16 DataHeaderDataBlockSize;
+ UINT8 CoreBlockId;
+ UINT16 CoreBlockSize;
+ UINT16 CoreBlockBiosSize;
+ UINT8 CoreBlockBiosType;
+ UINT8 CoreBlockReleaseStatus;
+ UINT8 CoreBlockHWSupported;
+ UINT8 CoreBlockIntegratedHW;
+ UINT8 CoreBlockBiosBuild[4];
+ UINT8 CoreBlockBiosSignOn[155];
+} VBIOS_VBT_STRUCTURE;
+#pragma pack()
+///
+/// Driver Private Function definitions
+///
+EFI_STATUS
+GetSVER (
+ OUT UINT8 *SVER
+ )
+/**
+ Set the SVER (system BIOS ID) string with the system BIOS build number.
+
+ @param[in] SVER String to populate with system BIOS build number.
+
+ @retval EFI_SUCCESS The SVER string is populated.
+ @exception EFI_UNSUPPORTED The SVER string is not populated.
+**/
+;
+
+EFI_STATUS
+GetStringFromToken (
+ IN EFI_GUID *ProducerGuid,
+ IN STRING_REF Token,
+ OUT CHAR16 **String
+ )
+/**
+ Acquire the string associated with the ProducerGuid and return it.
+
+ @param[in] ProducerGuid - The Guid to search the HII database for
+ @param[in] Token - The token value of the string to extract
+ @param[in] String - The string that is extracted
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_NOT_FOUND The requested string was not found
+**/
+;
+
+EFI_STATUS
+IgdOpRegionInit (
+ void
+ )
+/**
+ Graphics OpRegion / Software SCI driver installation function.
+
+ @param[in] void - None
+ @retval EFI_SUCCESS - The driver installed without error.
+ @retval EFI_ABORTED - The driver encountered an error and could not complete
+ installation of the ACPI tables.
+**/
+;
+
+EFI_STATUS
+ExtractDataFromHiiHandle (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN OUT UINT16 *ImageLength,
+ OUT UINT8 *DefaultImage,
+ OUT EFI_GUID *Guid
+ )
+/**
+ Extract information pertaining to the HiiHandle
+
+ @param[in] HiiHandle - Hii handle
+ @param[in] ImageLength - For input, length of DefaultImage;
+ For output, length of actually required
+ @param[in] DefaultImage - Image buffer prepared by caller
+ @param[in] Guid - Guid information about the form
+
+ @retval EFI_OUT_OF_RESOURCES - No enough buffer to allocate
+ @retval EFI_BUFFER_TOO_SMALL - DefualtImage has no enough ImageLength
+ @retval EFI_SUCCESS - Successfully extract data from Hii database.
+**/
+;
+
+EFI_STATUS
+GetVBiosVbtExitPmAuth (
+ VOID
+ )
+/**
+ Get Intel video BIOS VBT information (i.e. Pointer to VBT and VBT size).
+ The VBT (Video BIOS Table) is a block of customizable data that is built
+ within the video BIOS and edited by customers.
+
+ @retval EFI_SUCCESS - Video BIOS VBT information returned.
+ @exception EFI_UNSUPPORTED - Could not find VBT information (*VBiosVbtPtr = NULL).
+**/
+;
+
+EFI_STATUS
+UpdateIgdOpRegionExitPmAuth (
+ VOID
+ )
+/**
+ Update Graphics OpRegion after PCI enumeration.
+
+ @param[in] void - None
+ @retval EFI_SUCCESS - The function completed successfully.
+**/
+;
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c
new file mode 100644
index 0000000..ab08eb3
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.c
@@ -0,0 +1,929 @@
+/** @file
+ PEIM to initialize both IGD, PEG and PCI graphics card.
+
+@copyright
+ Copyright (c) 1999 - 2013 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 "GraphicsInit.h"
+#include "CpuIA32.h"
+#include <Token.h>
+#define IGD_ENABLE 1
+#define IGD_DISABLE 0
+
+/**
+ GraphicsInit: Initialize the IGD if no other external graphics is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+**/
+VOID
+GraphicsInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ DISPLAY_DEVICE PrimaryDisplay;
+ UINT8 GMSData;
+ UINT32 PciMmioLength;
+ UINT32 PchPcieMmioLength;
+ UINT32 PegMmioLength;
+ UINT32 IGfxMmioLength;
+ UINT32 TotalMmioLength;
+ BOOLEAN IGfxSupported;
+ UINT32 LoGTBaseAddress;
+ UINT32 HiGTBaseAddress;
+ UINT32 RegOffset;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 Data32Mask;
+ UINT32 Result;
+ PEI_STALL_PPI *StallPpi;
+ EFI_STATUS Status;
+ UINT64 GttMmAdr;
+ UINTN MchBarBase;
+ CPU_FAMILY CpuFamilyId;
+
+ PciMmioLength = 0;
+ PchPcieMmioLength = 0;
+ PegMmioLength = 0;
+ IGfxMmioLength = 0;
+ GttMmAdr = 0;
+ MchBarBase = McD0PciCfg32 (0x48) &~BIT0;
+ CpuFamilyId = GetCpuFamily();
+
+ ///
+ /// Set the VGA Decode bits to a good known starting point where both PEG and
+ /// IGD VGA Decode Bits are both disabled.
+ ///
+ McD0PciCfg16Or (R_SA_GGC, B_SA_GGC_IVD_MASK);
+ PrimaryDisplay = IGD;
+
+ ///
+ /// Check if IGfx is supported
+ ///
+ IGfxSupported = (BOOLEAN) (McD2PciCfg16 (R_SA_IGD_VID) != 0xFFFF);
+
+ ///
+ /// Check external VGA devices
+ ///
+ CheckOffboardPcieVga (PeiServices, &PchPcieMmioLength, &PrimaryDisplay);
+ CheckAndInitializePegVga (
+ PeiServices,
+ SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg,
+ &PrimaryDisplay,
+ SaPlatformPolicyPpi->GtConfig->PrimaryDisplay,
+ &PegMmioLength
+ );
+
+ ///
+ /// Temporarily program GttMmAdr
+ ///
+ GttMmAdr = SaPlatformPolicyPpi->GtConfig->GttMmAdr;
+
+ ///
+ /// Program GttMmAdr
+ ///
+ LoGTBaseAddress = (UINT32) (GttMmAdr & 0xFFFFFFFF);
+ HiGTBaseAddress = (UINT32) RShiftU64 ((GttMmAdr & 0xFFFFFFFF00000000), 32);
+ McD2PciCfg32 (R_SA_IGD_GTTMMADR) = LoGTBaseAddress | BIT2;
+ McD2PciCfg32 (R_SA_IGD_GTTMMADR + 4) = HiGTBaseAddress;
+
+ ///
+ /// Enable Bus Master and Memory access on 0:2:0
+ ///
+ McD2PciCfg16Or (R_SA_IGD_CMD, (BIT2 | BIT1));
+
+ ///
+ /// If primary display device is IGD or no other display detected then enable IGD
+ ///
+ if (IGfxSupported &&
+ (
+ (
+ ((PrimaryDisplay == IGD) || (SaPlatformPolicyPpi->GtConfig->PrimaryDisplay == IGD)) &&
+ (SaPlatformPolicyPpi->GtConfig->InternalGraphics != IGD_DISABLE)
+ ) || (SaPlatformPolicyPpi->GtConfig->InternalGraphics == IGD_ENABLE)
+ )
+ ) {
+
+ DEBUG ((EFI_D_INFO, "IGD enabled.\n"));
+
+ ///
+ /// Program GFX Memory by setting D0.F0.R 050h [7:3]
+ ///
+ McD0PciCfg16And (R_SA_GGC, ~(B_SA_GGC_GMS_MASK));
+
+ GMSData = SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc;
+
+ McD0PciCfg8Or (R_SA_GGC, (GMSData << N_SA_GGC_GMS_OFFSET));
+
+ ///
+ /// Program Graphics GTT Memory D0:F0:R50h[9:8] = 10b => 2MB of GTT
+ ///
+ McD0PciCfg16AndThenOr (R_SA_GGC, ~(B_SA_GGC_GGMS_MASK), 1 << (N_SA_GGC_GGMS_OFFSET + 1));
+
+ ///
+ /// Set register D2.F0.R 062h [2:1] = `01b' to set a 256MByte aperture.
+ /// This must be done before Device 2 registers are enumerated.
+ ///
+ if (SaPlatformPolicyPpi->GtConfig->ApertureSize == APERTURE_SIZE_128MB) {
+ McD2PciCfg8And (R_SA_IGD_MSAC_OFFSET, ~(BIT2 + BIT1));
+ } else if (SaPlatformPolicyPpi->GtConfig->ApertureSize == APERTURE_SIZE_256MB) {
+ McD2PciCfg8AndThenOr (R_SA_IGD_MSAC_OFFSET, ~(BIT2 + BIT1), BIT1);
+ } else {
+ McD2PciCfg8Or (R_SA_IGD_MSAC_OFFSET, (BIT2 + BIT1));
+ }
+ ///
+ /// Enable IGD VGA Decode. This is needed so the Class Code will
+ /// be correct for the IGD Device when determining which device
+ /// should be primary. If disabled, IGD will show up as a non VGA device.
+ ///
+ if ((SaPlatformPolicyPpi->GtConfig->PrimaryDisplay != IGD) && (PrimaryDisplay != IGD)) {
+ ///
+ /// If IGD is forced to be enabled, but is a secondary display, disable IGD VGA Decode
+ ///
+ McD0PciCfg16Or (R_SA_GGC, B_SA_GGC_IVD_MASK);
+ DEBUG ((EFI_D_INFO, "IGD VGA Decode is disabled because it's not a primary display.\n"));
+ } else {
+ McD0PciCfg16And (R_SA_GGC, ~(B_SA_GGC_IVD_MASK));
+ }
+
+ FindPciDeviceMmioLength (0, 2, 0, &IGfxMmioLength);
+
+ if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_12) && (SaPlatformPolicyPpi->GtConfig->PanelPowerEnable == 1)) {
+ ///
+ /// Panel Enable VDD bit
+ ///
+ Mmio32Or (GttMmAdr, 0xc7204, 0x8);
+ }
+ } else {
+
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, &StallPpi);
+ ASSERT_PEI_ERROR (PeiServices, Status);
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ ///
+ /// For HSW ULT, Disable LCPLL
+ /// Set LCPLL_CTL (GTTMMADR Offset 0x130040) PLL_disable (Bit 31) to 1b to disable LCPLL.
+ /// Poll for LCPLL_CTL PLL_lock (Bit 30) = 0b to indicate LCPLL lost lock.Timeout and continue after 1 ms.
+ /// Set D_COMP COMP_DISABLE (MCHBAR offset 0x5F0C Bit 0)to 1b.
+ /// Wait > 100 ns for write to complete.
+ /// Poll for D_COMP RCOMP_IN_PROGRESS Bit 9 = 0b.Timeout and continue after 1 ms.
+ ///
+
+ RegOffset = 0x130040;
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT31;
+ Mmio32AndThenOr (GttMmAdr, RegOffset, Data32And, Data32Or);
+
+ if (IGfxSupported) {
+ Data32Mask = BIT30;
+ Result = 0;
+ PollGtReady (PeiServices, StallPpi, GttMmAdr, RegOffset, Data32Mask, Result);
+ }
+
+ RegOffset = 0x5F0C;
+ Data32And = 0xFFFFFFFF;
+ Data32Or = BIT0;
+ Mmio32AndThenOr (MchBarBase, RegOffset, Data32And, Data32Or);
+
+ ///
+ /// 1uSec wait
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, 1);
+
+ if (IGfxSupported) {
+ Data32Mask = BIT9;
+ Result = 0;
+ PollGtReady (PeiServices, StallPpi, MchBarBase, RegOffset, Data32Mask, Result);
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Disable IGD Device.\n"));
+ ///
+ /// Disable IGD device
+ ///
+ /// Register D0:F0 Offset 50h [7:3] = '00000b'.
+ /// This prevents UMA memory from being pre-allocated to IGD.
+ /// Set D0:F0 Offset 50h [9:8] = '00b'.
+ /// GTT Graphics Memory Size to 0
+ /// Set VGA Disable (IVD) in D0:F0 Offset 50h [1] = '1b'.
+ ///
+ McD0PciCfg16AndThenOr (R_SA_GGC, ~(B_SA_GGC_GGMS_MASK | B_SA_GGC_GMS_MASK), B_SA_GGC_IVD_MASK);
+ SaPlatformPolicyPpi->GtConfig->GttSize = 0;
+ SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc = 0;
+
+ ///
+ /// Disable IGD. D0.F0.R 054h [4] = '0b'.
+ ///
+ McD0PciCfg8And (R_SA_DEVEN, ~(B_SA_DEVEN_D2EN_MASK));
+ }
+
+ TotalMmioLength = PciMmioLength + PchPcieMmioLength + PegMmioLength + IGfxMmioLength;
+ DEBUG ((EFI_D_INFO, "TotalMmioLength: 0x%08X bytes\n", TotalMmioLength));
+
+ ///
+ /// Disable Bus Master and Memory access on 0:2:0 and clear GTTMMADR
+ ///
+ McD2PciCfg16And (R_SA_IGD_CMD, ~(BIT2 | BIT1));
+ McD2PciCfg32And (R_SA_IGD_GTTMMADR, 0x0);
+ McD2PciCfg32And (R_SA_IGD_GTTMMADR + 0x4, 0x0);
+
+ ///
+ /// Determine MMIO Size for Dynamic Tolud
+ ///
+ if (SaPlatformPolicyPpi->MemConfig->MaxTolud == 0x00) {
+ ///
+ /// if total MMIO need 1GB or over
+ ///
+ if (TotalMmioLength >= 0x40000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x800;
+ }
+ ///
+ /// if total MMIO need 728MB~1GB
+ ///
+ else if (TotalMmioLength >= 0x30000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x700;
+ }
+ ///
+ /// if total MMIO need 512MB~728MB
+ ///
+ else if (TotalMmioLength >= 0x20000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x600;
+ }
+ ///
+ /// if total MMIO need 256MB~512MB
+ ///
+ else if (TotalMmioLength >= 0x10000000) {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x500;
+ }
+ ///
+ /// if total MMIO need less than 256MB
+ ///
+ else {
+ SaPlatformPolicyPpi->GtConfig->MmioSize = 0x400;
+ }
+ }
+}
+
+/**
+ CheckAndInitializePegVga: Check if PEG card is present and configure accordingly
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] AlwaysEnablePeg - 0 - Peg is not always enabled.
+ @param[in, out] PrimaryDisplay - Primary Display - default is IGD
+ @param[in] PrimaryDisplaySelection - Primary display selection from BIOS Setup
+ @param[in, out] PegMmioLength - Total PEG MMIO length on all PEG ports
+**/
+VOID
+CheckAndInitializePegVga (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 AlwaysEnablePeg,
+ IN OUT DISPLAY_DEVICE *PrimaryDisplay,
+ IN UINT8 PrimaryDisplaySelection,
+ IN OUT UINT32 *PegMmioLength
+ )
+{
+ UINT8 ClassCode;
+ BOOLEAN IgdPresent;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+ UINT16 PegDevenReg;
+ UINT8 PegComplete;
+ UINT16 PegEnable;
+ BOOLEAN CardDetect;
+ UINT32 MmioLength;
+ UINT8 Func;
+ UINT8 MaxFunction;
+ UINT8 HeaderType;
+ UINT8 PegVgaFunc;
+
+ PEG_DEVEN PegDevenTable[] = {
+ ///
+ /// Bus, Device, Function, DevenMask
+ ///
+ {
+ SA_PEG_BUS_NUM,
+ SA_PEG10_DEV_NUM,
+ SA_PEG10_FUN_NUM,
+ BIT3
+ }
+// AMI_OVERRID >>
+#if RC_PEG_1 == 1
+,
+ {
+ SA_PEG_BUS_NUM,
+ SA_PEG11_DEV_NUM,
+ SA_PEG11_FUN_NUM,
+ BIT2
+ }
+#endif
+#if RC_PEG_2 == 1
+,
+ {
+ SA_PEG_BUS_NUM,
+ SA_PEG12_DEV_NUM,
+ SA_PEG12_FUN_NUM,
+ BIT1
+ }
+#endif
+// AMI_OVERRID <<
+ };
+
+ MmioLength = 0;
+ CardDetect = FALSE;
+ PegVgaFunc = 0xFF;
+
+ ///
+ /// Read the DEVEN register for PEG0/1/2 controllers configuration
+ ///
+ PegDevenReg = MmPci16 (0, SA_MC_BUS, 0, 0, R_SA_DEVEN) & (BIT3 + BIT2 + BIT1);
+
+ ///
+ /// If IGD is disabled
+ /// or not present IgdPresent is set to false
+ ///
+ if (McD2PciCfg16 (PCI_VID) == 0xFFFF) {
+ IgdPresent = FALSE;
+ } else {
+ IgdPresent = TRUE;
+ }
+ ///
+ /// Scan PEG device vs DEVEN register for PEG controllers configuration
+ ///
+ for (PegComplete = 0; PegComplete < ((sizeof (PegDevenTable)) / (sizeof (PEG_DEVEN))); PegComplete++) {
+
+ PegBus = PegDevenTable[PegComplete].Bus;
+ PegDev = PegDevenTable[PegComplete].Device;
+ PegFunc = PegDevenTable[PegComplete].Function;
+ PegEnable = PegDevenTable[PegComplete].DevenMask;
+
+ if ((PegDevenReg & PegEnable) == 0) {
+ continue;
+ }
+ ///
+ /// Check for a card presence in the PEG slot.
+ /// We don't know if it's a graphics card yet.
+ ///
+ if ((MmPci8 (0, PegBus, PegDev, PegFunc, R_SA_PEG_SLOTSTS_OFFSET) & BIT6) == 0) {
+ continue;
+ }
+ ///
+ /// Set PEG PortBus = 1 to Read Endpoint.
+ ///
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF, 0x00010100);
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ MmPci16 (0, 1, 0, 0, PCI_VID) = 0;
+
+ ///
+ /// Read Vendor ID to check if endpoint exists
+ /// if no device exists, then check next device
+ ///
+ if (MmPci16 (0, 1, 0, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+ ///
+ /// Check for a multifunction device
+ ///
+ HeaderType = MmPci8 (0, 1, 0, 0, PCI_HEADER_TYPE_OFFSET);
+ if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) != 0) {
+ MaxFunction = 7;
+ } else {
+ MaxFunction = 0;
+ }
+ ///
+ /// Calculate total PEG MMIO length on all functions of the endpoint
+ ///
+ for (Func = 0; Func <= MaxFunction; Func++) {
+ if (MmPci16 (0, 1, 0, Func, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ FindPciDeviceMmioLength (1, 0, Func, &MmioLength);
+ *PegMmioLength += MmioLength;
+ }
+ ///
+ /// Perform PEG Endpoint Class Code Check. If the Endpoint Class Code is
+ /// not GFX, then the Port is being used as a standard PCI Express Port.
+ ///
+ ClassCode = MmPci8 (0, 1, 0, 0, PCI_BCC);
+ if (ClassCode == 0x03) {
+ ///
+ /// Disable PEG if IGD or PCI VGA take precedence.
+ ///
+ if (AlwaysEnablePeg == 0) {
+ ///
+ /// If IGD is present and selected as primary, skip the PEG VGA enabling
+ ///
+ if (IgdPresent && (PrimaryDisplaySelection == IGD)) {
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ continue;
+ }
+ ///
+ /// If PCI video card was detected, skip the PEG VGA enabling
+ ///
+ if (*PrimaryDisplay == PCI) {
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ continue;
+ }
+ }
+ ///
+ /// Enable PEG video and Execute 16-bit address decodes on VGA I/O accesses
+ ///
+ /// Check if PEG VGA already detected
+ ///
+ if (*PrimaryDisplay != PEG) {
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_BCTRL_OFFSET, (BIT3 + BIT4));
+ *PrimaryDisplay = PEG;
+ PegVgaFunc = PegFunc;
+ DEBUG ((EFI_D_INFO, "PCIe card on PEG%x%x (%x:%x:%x) enabled as VGA.\n", PegDev, PegFunc, PegBus, PegDev, PegFunc));
+ }
+ }
+
+ if (ClassCode == 0x06) {
+ CardDetect = EnumerateBridgeDevice (PegBus, PegDev, PegFunc, PegMmioLength);
+ if (CardDetect == TRUE) {
+ ///
+ /// Check if PEG VGA already detected
+ ///
+ if (*PrimaryDisplay != PEG) {
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_BCTRL_OFFSET, (BIT3 + BIT4));
+ *PrimaryDisplay = PEG;
+ PegVgaFunc = PegFunc;
+ DEBUG ((EFI_D_INFO, "PCIe card on PEG%x%x (%x:%x:%x) enabled as VGA.\n", PegDev, PegFunc, PegBus, PegDev, PegFunc));
+ }
+ }
+ }
+ ///
+ /// Restore bus numbers on the PEG bridge.
+ ///
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ } // End of the for Loop
+
+ ///
+ /// If a PEG device is used for primary graphics, set the ISAEN bit on all other PEG ports.
+ ///
+ if (PegVgaFunc != 0xFF) {
+ for (PegComplete = 0; PegComplete < ((sizeof (PegDevenTable)) / (sizeof (PEG_DEVEN))); PegComplete++) {
+ if (PegVgaFunc == PegComplete) {
+ continue;
+ }
+ PegBus = PegDevenTable[PegComplete].Bus;
+ PegDev = PegDevenTable[PegComplete].Device;
+ PegFunc = PegDevenTable[PegComplete].Function;
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_BCTRL_OFFSET, BIT2);
+ DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) ISAEN has been set.\n", PegDev, PegFunc, PegBus, PegDev, PegFunc));
+ }
+ }
+}
+
+/**
+ Find the MMIO size that a given PCI device requires
+
+ @param[in] BusNum - Bus number of the device
+ @param[in] DevNum - device Number of the device
+ @param[in] FunNum - Function number of the device
+ @param[out] MmioLength - MMIO Length in bytes
+**/
+VOID
+FindPciDeviceMmioLength (
+ IN UINT32 BusNum,
+ IN UINT32 DevNum,
+ IN UINT32 FunNum,
+ OUT UINT32 *MmioLength
+ )
+{
+ UINT32 CurrentMmioLength;
+ UINT32 SavedBAR;
+ UINT32 i;
+ UINT64 BarAlign;
+ UINT8 ClassCode;
+
+ *MmioLength = 0;
+ BarAlign = PCI_BAR_OLD_ALIGN;
+
+ ClassCode = MmPci8 (0, BusNum, DevNum, FunNum, PCI_BCC);
+ if (ClassCode == PCI_CLASS_BRIDGE) {
+ return ;
+ }
+
+ for (i = PCI_BAR0; i <= PCI_BAR5; i += 4) {
+ SavedBAR = MmPci32 (0, BusNum, DevNum, FunNum, i);
+ ///
+ /// Check BAR is read-only or not
+ ///
+ MmPci32And (0, BusNum, DevNum, FunNum, i, (UINT32) PCI_BAR_NOCHANGE);
+ MmPci32Or (0, BusNum, DevNum, FunNum, i, BarAlign);
+ if (SavedBAR == MmPci32 (0, BusNum, DevNum, FunNum, i)) {
+ ///
+ /// Restore BAR as original value
+ ///
+ MmPci32 (0, BusNum, DevNum, FunNum, i) = SavedBAR;
+ continue;
+ }
+ ///
+ /// If BAR is not memory map, skip it
+ ///
+ if ((SavedBAR & BIT0) != 0) {
+ ///
+ /// Restore BAR as original value
+ ///
+ MmPci32 (0, BusNum, DevNum, FunNum, i) = SavedBAR;
+ continue;
+ }
+ ///
+ /// Calculate the MMIO length through BAR
+ ///
+ CurrentMmioLength = ~(MmPci32 (0, BusNum, DevNum, FunNum, i) &~0xF) + 1;
+ *MmioLength += CurrentMmioLength;
+
+ ///
+ /// Restore BAR as original value
+ ///
+ MmPci32 (0, BusNum, DevNum, FunNum, i) = SavedBAR;
+ ///
+ /// Skip next index if BAR is 64bit address
+ ///
+ if ((SavedBAR & (BIT1 + BIT2)) == 0x4) {
+ i += 4;
+ }
+ }
+}
+
+/**
+ CheckOffboardPcieVga: Check if off board PCIe graphics Card is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in, out] PchPcieMmioLength - Total PCIe MMIO length on all PCH root ports
+ @param[in, out] PrimaryDisplay - Primary Display - default is IGD
+**/
+VOID
+CheckOffboardPcieVga (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT32 *PchPcieMmioLength,
+ IN OUT DISPLAY_DEVICE *PrimaryDisplay
+ )
+{
+ UINT8 PortNo;
+ UINT32 PcieBusNum;
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Func;
+ UINT8 MaxFunction;
+ UINT8 SubBusNum;
+ UINT8 HeaderType;
+ UINT16 Buffer16;
+ BOOLEAN CardDetect;
+ UINT32 MmioLength;
+
+ MmioLength = 0;
+
+ ///
+ /// Initialize Secondary and Subordinate bus number for first Pcie root port
+ ///
+ PcieBusNum = 0x00010100;
+
+ SubBusNum = 0;
+
+ CardDetect = FALSE;
+
+ for (PortNo = 0; PortNo < GetPchMaxPciePortNum (); PortNo++) {
+ ///
+ /// Check if root port exists
+ ///
+ if (MmPci16 (0, 0, 0x1C, PortNo, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ MmPci32 (0, 0, 0x1c, PortNo, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = PcieBusNum;
+ Bus = MmPci8 (0, 0, 0x1c, PortNo, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+
+ ///
+ /// Assign temporary subordinate bus number so that device this bridge can be seen
+ ///
+ MmPci8 (0, 0, 0x1c, PortNo, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET) = 0xFF;
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ MmPci16 (0, Bus, 0, 0, PCI_VID) = 0;
+
+ SubBusNum = EnumerateDownstream (Bus);
+ ///
+ /// Update the actual subordinate bus number
+ ///
+ MmPci8 (0, 0, 0x1c, PortNo, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET) = SubBusNum;
+ PcieBusNum = (SubBusNum + 1) << 8;
+ }
+
+ for (Bus = 1; Bus <= SubBusNum; Bus++) {
+ for (Dev = 0; Dev < 32; Dev++) {
+ ///
+ /// Read Vendor ID to check if device exists
+ /// if no device exists, then check next device
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+ ///
+ /// Check for a multifunction device
+ ///
+ HeaderType = MmPci8 (0, Bus, Dev, 0, PCI_HDR);
+ if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) != 0) {
+ MaxFunction = 7;
+ } else {
+ MaxFunction = 0;
+ }
+
+ for (Func = 0; Func <= MaxFunction; Func++) {
+ if (MmPci16 (0, Bus, Dev, Func, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ FindPciDeviceMmioLength (Bus, Dev, Func, &MmioLength);
+ *PchPcieMmioLength += MmioLength;
+
+ ///
+ /// Video cards can have Base Class 0 with Sub-class 1
+ /// or Base Class 3.
+ ///
+ if (MmPci16 (0, Bus, Dev, Func, PCI_SCC) == 0x0300) {
+ if (CardDetect != TRUE) {
+ *PrimaryDisplay = PCI;
+ DEBUG ((EFI_D_INFO, "PCH PCIe Graphics Card enabled.\n"));
+ CardDetect = TRUE;
+ }
+ }
+ }
+ }
+ }
+ ///
+ /// Clear bus number on all the bridges that we have opened so far.
+ /// We have to do it in the reverse Bus number order.
+ ///
+ for (Bus = SubBusNum; Bus >= 1; Bus--) {
+ for (Dev = 0; Dev < 32; Dev++) {
+ ///
+ /// Read Vendor ID to check if device exists
+ /// if no device exists, then check next device
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ Buffer16 = MmPci16 (0, Bus, Dev, 0, PCI_SCC);
+ ///
+ /// Clear Bus Number for PCI/PCI Bridge Device
+ ///
+ if (Buffer16 == 0x0604) {
+ MmPci32 (0, Bus, Dev, 0, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+ }
+ }
+ }
+
+ for (PortNo = 0; PortNo < GetPchMaxPciePortNum (); PortNo++) {
+ ///
+ /// Clear bus numbers so that PCIe slots are hidden
+ ///
+ MmPci32 (0, 0, 0x1c, PortNo, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+ }
+}
+
+/**
+ This function enumerate all downstream bridge.
+
+ @param[in] BusNum - Primary bus number of current bridge.
+
+ @retval BusNum: return current bus number if current bus is an enpoint device.
+ @retval SubBus: return subordinate bus number if current bus is a bridge.
+**/
+UINT8
+EnumerateDownstream (
+ IN UINT8 BusNum
+ )
+{
+ UINT8 DevNum;
+ UINT16 Buffer16;
+ UINT8 SubBus;
+ UINT8 SecBus;
+
+ SubBus = 0;
+
+ SecBus = BusNum;
+
+ for (DevNum = 0; DevNum < 32; DevNum++) {
+ ///
+ /// Read Vendor ID to check if device exists
+ /// if no device exists, then check next device
+ ///
+ if (MmPci16 (0, BusNum, DevNum, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ Buffer16 = MmPci16 (0, BusNum, DevNum, 0, PCI_SCC);
+ ///
+ /// Check for PCI/PCI Bridge Device Base Class 6 with subclass 4
+ ///
+ if (Buffer16 == 0x0604) {
+ SecBus++;
+ MmPci8 (0, BusNum, DevNum, 0, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = BusNum;
+ MmPci8 (0, BusNum, DevNum, 0, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET) = SecBus;
+ ///
+ /// Assign temporary subordinate bus number so that device behind this bridge can be seen
+ ///
+ MmPci8 (0, BusNum, DevNum, 0, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET) = 0xFF;
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ MmPci16 (0, SecBus, 0, 0, PCI_VID) = 0;
+
+ ///
+ /// Enumerate bus behind this bridge by calling this funstion recursively
+ ///
+ SubBus = EnumerateDownstream (SecBus);
+ ///
+ /// Update the correct subordinate bus number
+ ///
+ MmPci8 (0, BusNum, DevNum, 0, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET) = SubBus;
+ SecBus = SubBus;
+ }
+ }
+
+ if (SubBus == 0) {
+ return BusNum;
+ } else {
+ return SubBus;
+ }
+}
+
+/**
+ This function enumerate the bridge on the device
+
+ @param[in] PegBus - Particular Bus number
+ @param[in] PegDev - Particular Device number
+ @param[in] PegFunc - Particular Func number
+ @param[in, out] PegMmioLength - PEG MMIO length
+
+ @retval CardDetect : TRUE if current bridge device has a Graphics card.
+ @retval CardDetect : FALSE if current bridge device has no Graphics card.
+**/
+BOOLEAN
+EnumerateBridgeDevice (
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc,
+ IN OUT UINT32 *PegMmioLength
+ )
+{
+
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 SubBusNum;
+ UINT16 Buffer16;
+ BOOLEAN CardDetect;
+
+ CardDetect = FALSE;
+
+ ///
+ /// Temporarily program the secondary and subordinate bus numbers
+ /// of PEG bridge to (1, 0xFF) so that devices behind the bridge can be seen
+ ///
+ Bus = 1;
+ MmPci8 (0, PegBus, PegDev, PegFunc, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET) = Bus;
+ MmPci8 (0, PegBus, PegDev, PegFunc, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET) = 0xFF;
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ MmPci16 (0, Bus, 0, 0, PCI_VID) = 0;
+
+ SubBusNum = EnumerateDownstream (Bus);
+
+ for (Bus = 1; Bus <= SubBusNum; Bus++) {
+ for (Dev = 0; Dev < 32; Dev++) {
+ ///
+ /// Read Vendor ID to check if device exists
+ /// if no device exists, then check next device
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+
+ }
+ ///
+ /// Video cards can have Base Class 0 with Sub-class 1
+ /// or Base Class 3.
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_SCC) == 0x0300) {
+ FindPciDeviceMmioLength (Bus, Dev, 0, PegMmioLength);
+ CardDetect = TRUE;
+ break;
+ }
+ }
+
+ if (CardDetect == TRUE) {
+ break;
+ }
+ }
+ ///
+ /// Clear bus number on all the bridges that we have opened so far.
+ /// We have to do it in the reverse Bus number order.
+ ///
+ for (Bus = SubBusNum; Bus >= 1; Bus--) {
+ for (Dev = 0; Dev < 32; Dev++) {
+ ///
+ /// Read Vendor ID to check if device exists
+ /// if no device exists, then check next device
+ ///
+ if (MmPci16 (0, Bus, Dev, 0, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ Buffer16 = MmPci16 (0, Bus, Dev, 0, PCI_SCC);
+ ///
+ /// Clear Bus Number for PCI/PCI Bridge Device
+ ///
+ if (Buffer16 == 0x0604) {
+ MmPci32 (0, Bus, Dev, 0, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+ }
+ }
+ }
+ ///
+ /// Clear the bus numbers on the PEG bridge
+ ///
+ MmPci32 (0, PegBus, PegDev, PegFunc, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET) = 0;
+
+ return CardDetect;
+}
+
+/**
+
+ "Poll Status" for GT Readiness
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to Stall PPI
+ @param[in] Base - Base address of MMIO
+ @param[in] Offset - MMIO Offset
+ @param[in] Mask - Mask
+ @param[in] Result - Value to wait for
+
+
+**/
+VOID
+PollGtReady (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ UINT64 Base,
+ UINT32 Offset,
+ UINT32 Mask,
+ UINT32 Result
+ )
+{
+ UINT32 GtStatus;
+ UINT16 StallCount;
+
+ StallCount = 0;
+
+ ///
+ /// Register read
+ ///
+ GtStatus = Mmio32 (Base, Offset);
+
+ while (((GtStatus & Mask) != Result) && (StallCount < GT_WAIT_TIMEOUT)) {
+
+ GtStatus = Mmio32 (Base, Offset);
+ ///
+ /// 1mSec wait
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, 1000);
+ StallCount = StallCount + 1;
+ }
+
+ ASSERT ((StallCount != GT_WAIT_TIMEOUT));
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.h
new file mode 100644
index 0000000..6d060cb
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/GraphicsInit.h
@@ -0,0 +1,219 @@
+/** @file
+ Graphics header file
+
+@copyright
+ Copyright (c) 1999 - 2013 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
+**/
+#ifndef _GRAPHICS_INIT_H_
+#define _GRAPHICS_INIT_H_
+
+#include "EdkIIGluePeim.h"
+#include "SaAccess.h"
+#include "PchAccess.h"
+#include "EdkIIGluePcdPciExpressLib.h"
+#include "EdkIIGlueConfig.h"
+#include "Pci22.h"
+#include "PchPlatformLib.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+
+///
+/// Driver Consumed PPI Prototypes
+///
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 DevenMask;
+} PEG_DEVEN;
+
+typedef enum {
+ IGD = 0,
+ PEG,
+ PCI,
+ DISPLAY_DEVICE_MAX
+} DISPLAY_DEVICE;
+
+typedef enum {
+ VBIOS_DEFAULT = 0,
+ CRT,
+ LFP,
+ CRT_LFP,
+ TV,
+ LFPSDVO,
+ EFP,
+ TVSDVO,
+ CRT_LFPSDVO,
+ CRT_EFP,
+ IGD_BOOT_TYPE_MAX
+} IGD_BOOT_TYPE;
+
+typedef enum {
+ GMS_FIXED = 0,
+ GMS_DVMT,
+ GMS_FIXED_DVMT,
+ GMS_MAX
+} GRAPHICS_MEMORY_SELECTION;
+
+typedef enum {
+ GM_32M = 1,
+ GM_64M = 2,
+ GM_128M = 4,
+ GM_MAX
+} STOLEN_MEMORY;
+
+typedef enum {
+ PAVP_DISABLED = 0,
+ PAVP_LITE,
+ PAVP_HIGH
+} PAVP_MODE;
+
+#define GTTMMADR_SIZE_4MB 0x400000
+#define GTT_SIZE_2MB 2
+#define GT_WAIT_TIMEOUT 3000 ///< ~3 seconds
+
+#define APERTURE_SIZE_128MB 1
+#define APERTURE_SIZE_256MB 2
+#define APERTURE_SIZE_512MB 3
+
+/**
+ CheckAndInitializePegVga: Check if PEG card is present and configure accordingly
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] AlwaysEnablePeg - 0 - Peg is not always enabled.
+ @param[in, out] PrimaryDisplay - Primary Display - default is IGD
+ @param[in] PrimaryDisplaySelection - Primary display selection from BIOS Setup
+ @param[in, out] PegMmioLength - Total PEG MMIO length on all PEG ports
+**/
+VOID
+CheckAndInitializePegVga (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 AlwaysEnablePeg,
+ IN OUT DISPLAY_DEVICE *PrimaryDisplay,
+ IN UINT8 PrimaryDisplaySelection,
+ IN OUT UINT32 *PegMmioLength
+ )
+;
+
+/**
+ CheckOffboardPciVga: Check if off board PCI graphics Card is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in, out] PciMmioLength - PCI MMIO length
+ @param[in, out] PrimaryDisplay - Primary Display - default is IGD
+**/
+VOID
+CheckOffboardPciVga (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT32 *PciMmioLength,
+ IN OUT DISPLAY_DEVICE *PrimaryDisplay
+ )
+;
+
+/**
+ CheckOffboardPcieVga: Check if off board PCIe graphics Card is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in, out] PchPcieMmioLength - Total PCIe MMIO length on all PCH root ports
+ @param[in, out] PrimaryDisplay - Primary Display - default is IGD
+**/
+VOID
+CheckOffboardPcieVga (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT32 *PchPcieMmioLength,
+ IN OUT DISPLAY_DEVICE *PrimaryDisplay
+ )
+;
+
+/**
+ Find the MMIO size that a given PCI device requires
+
+ @param[in] BusNum - Bus number of the device
+ @param[in] DevNum - device Number of the device
+ @param[in] FunNum - Function number of the device
+ @param[out] MmioLength - MMIO Length in bytes
+**/
+VOID
+FindPciDeviceMmioLength (
+ IN UINT32 BusNum,
+ IN UINT32 DevNum,
+ IN UINT32 FunNum,
+ OUT UINT32 *MmioLength
+ )
+;
+
+/**
+ This function enumerate all downstream bridge.
+
+ @param[in] BusNum - Primary bus number of current bridge
+
+ @retval Current bus number: if current bus is an enpoint device
+ @retval subordinate bus number: if current bus is a bridge
+**/
+UINT8
+EnumerateDownstream (
+ IN UINT8 BusNum
+ )
+;
+
+/**
+ This function enumerate the bridge on the device
+
+ @param[in] PegBus - Particular Bus number
+ @param[in] PegDev - Particular Device number
+ @param[in] PegFunc - Particular Func number
+ @param[in, out] PegMmioLength - PEG MMIO length
+
+ @retval CardDetect : TRUE if current bridge device has a Graphics card.
+ @retval CardDetect : FALSE if current bridge device has no Graphics card.
+**/
+BOOLEAN
+EnumerateBridgeDevice (
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc,
+ IN OUT UINT32 *PegMmioLength
+ )
+;
+
+/**
+
+ "Poll Status" for GT Readiness
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to Stall PPI
+ @param[in] Base - Base address of MMIO
+ @param[in] Offset - MMIO Offset
+ @param[in] Mask - Mask
+ @param[in] Result - Value to wait for
+
+
+**/
+VOID
+PollGtReady (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ UINT64 Base,
+ UINT32 Offset,
+ UINT32 Mask,
+ UINT32 Result
+ )
+;
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c
new file mode 100644
index 0000000..bead6ce
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.c
@@ -0,0 +1,2987 @@
+/** @file
+ PEI Function to initialize SA PciExpress.
+
+@copyright
+ Copyright (c) 1999 - 2014 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 "PciExpressInit.h"
+#include "PcieTraining.h"
+#include "PchPlatformLib.h"
+
+#include <Token.h> //AMI_OVERRIDE
+
+#ifdef PEG_FLAG
+#include EFI_GUID_DEFINITION (SaDataHob)
+
+#define SA_PEG_VMARGIN_UP 0
+#define SA_PEG_VMARGIN_DOWN 1
+
+#define SA_PEG_LINK_DISABLE_MAXWAIT 100*10
+
+VOID
+ReportPcieLinkStatus (
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc
+)
+/**
+ This function reports a PEG controller's link status
+
+ @param[in] PegBus - Peg Bus
+ @param[in] PegDev - Peg Device
+ @param[in] PegFunc - Peg Function
+
+ @retval None
+**/
+{
+ UINT32 Deven;
+ UINT16 LinkStatus;
+ UINT8 LinkWidth;
+ UINT8 LinkSpeed;
+ UINT16 Vc0Pending;
+
+ Deven = MmPci32 (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_DEVEN);
+ Deven = (Deven >> 1) & 0x7;
+ DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) - ", PegDev, PegFunc, PegBus, PegDev, PegFunc));
+ if (((Deven >> (SA_PEG_MAX_FUN - 1 - PegFunc)) & 0x1) == 0x1) {
+ LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET);
+ LinkWidth = (LinkStatus >> 4) & 0x3F;
+ LinkSpeed = LinkStatus & 0xF;
+ Vc0Pending = ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) >> 1) & 0x1;
+ DEBUG ((EFI_D_INFO, "Trained to x%d at Gen%d.", LinkWidth, LinkSpeed));
+ DEBUG ((EFI_D_INFO, " VC0 Negotiation Pending = %d.", Vc0Pending));
+ DEBUG ((EFI_D_INFO, "\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Disabled.\n"));
+ }
+}
+
+VOID
+WaitForVc0Negotiation (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc
+)
+/**
+ This function prints the time required for VC0 Negotiation Pending to be cleared. Quits after 100 msec.
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] PegBus - Peg Bus
+ @param[in] PegDev - Peg Device
+ @param[in] PegFunc - Peg Function
+
+ @retval None
+**/
+{
+ UINT32 Deven;
+ UINT32 MsecWait;
+ UINT16 Vc0Pending;
+
+ Deven = MmPci32 (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_DEVEN);
+ Deven = (Deven >> 1) & 0x7;
+ if (((Deven >> (SA_PEG_MAX_FUN - 1 - PegFunc)) & 0x1) == 0x1) {
+ MsecWait = 0;
+ Vc0Pending = ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) >> 1) & 0x1;
+
+ while (Vc0Pending && (MsecWait < 100)) {
+ MsecWait++;
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND);
+ Vc0Pending = ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) >> 1) & 0x1;
+ }
+ DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) - VC0 Negotiation Pending = %x after %d msec.\n",
+ PegDev, PegFunc, PegBus, PegDev, PegFunc, Vc0Pending, MsecWait));
+ }
+}
+
+VOID
+GracefulLinkStatusStall (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN UINT8 HwStrap
+ )
+/**
+ If we have a record of links that did not train from last boot, then do not stall for them
+ For links that did train last boot, stall until they train or 100ms pass
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] SaDataHob - Pointer to SA_DATA_HOB
+ @param[in] HwStrap - HwStrap configuration from FUSESCMN
+
+ @retval None
+**/
+{
+ UINT8 LinkStatusGood;
+ UINT8 PegLinkFailMask;
+ UINT8 i;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+ UINT8 CurrentPegFuncBit;
+ UINT8 SkipFuncMask;
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+
+ PegLinkFailMask = 0;
+ ///
+ /// If this is S3 Resume or Warm Boot, check if PEG delay can be skipped when no PEG devices populated.
+ ///
+ Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);
+ ASSERT_EFI_ERROR (Status);
+ if ((BootMode == BOOT_ON_S3_RESUME) || (GetPchPmStatus (WarmBoot) == TRUE)) {
+ if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) {
+ if (SaDataHob->PegData.PegLinkFailMask != 0) {
+ PegLinkFailMask = SaDataHob->PegData.PegLinkFailMask;
+ DEBUG ((EFI_D_INFO, "Previous Link Training Fail Mask 0x%2.2X\n", SaDataHob->PegData.PegLinkFailMask));
+ } else {
+ PegLinkFailMask = 0xFF;
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ PegLinkFailMask &= (UINT8) ~(0x1 << i);
+ }
+ }
+ }
+ }
+ DEBUG ((EFI_D_INFO, "New Link Training Fail Mask 0x%2.2X\n", PegLinkFailMask));
+
+ switch (HwStrap) {
+ case SA_PEG_x16_x0_x0:
+ SkipFuncMask = BIT2 | BIT1;
+ break;
+
+ case SA_PEG_x8_x8_x0:
+ SkipFuncMask = BIT2;
+ break;
+
+ default:
+ case SA_PEG_x8_x4_x4:
+ SkipFuncMask = 0;
+ break;
+ }
+
+ LinkStatusGood = 0;
+ PegDev = 1;
+ for (i = 0; i < 100; i++) {
+ ///
+ /// Poll endpoints
+ /// Skip endpoints that failed last boot
+ /// Skip endpoints that trained good this boot
+ /// Loop in 1-ms increments until all endpoints are:
+ /// reported bad from last boot, or
+ /// have trained good on this boot
+ ///
+ for (PegFunc = 0, CurrentPegFuncBit = 1; PegFunc < SA_PEG_MAX_FUN; PegFunc++, CurrentPegFuncBit <<= 1) {
+ if (CurrentPegFuncBit == (CurrentPegFuncBit & SkipFuncMask)) {
+ if (i == 0) {
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - skipping due to furcation\n", PegDev, PegFunc, SA_PEG_BUS_NUM, PegDev, PegFunc));
+ }
+ continue;
+ }
+ ///
+ /// If configuration change, then break out of loop.
+ /// Test if current PEG is neither in fail mask nor previously tested good.
+ ///
+ if (CurrentPegFuncBit != (CurrentPegFuncBit & (UINT8) (PegLinkFailMask | LinkStatusGood))) {
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - checking\n", PegDev, PegFunc, SA_PEG_BUS_NUM, PegDev, PegFunc));
+ ///
+ /// VC negotiation is complete
+ ///
+ if ((BIT1 & MmPci16(0, SA_PEG_BUS_NUM, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) {
+ DEBUG ((EFI_D_INFO, " VC negotiation is complete\n"));
+ ///
+ /// Record as a good link
+ ///
+ LinkStatusGood |= CurrentPegFuncBit;
+ }
+ }
+ }
+ ///
+ /// If all links accounted for, then exit.
+ ///
+ if (((UINT8) (LinkStatusGood | PegLinkFailMask | SkipFuncMask)) == 0xFF) {
+ break;
+ }
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND);
+ } ///< End of stall loop
+
+ DEBUG ((EFI_D_INFO, "Total Stall: %d msec\n", i));
+ if (SaDataHob != NULL) {
+ SaDataHob->PegData.PegLinkFailMask = (UINT8) ~LinkStatusGood;
+ DEBUG ((EFI_D_INFO, "Returned PegLinkFailMask 0x%2.2X\n", SaDataHob->PegData.PegLinkFailMask));
+ }
+
+}
+
+UINT32
+PcieFindCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 PegFunc,
+ IN UINT8 CapId
+ )
+/**
+ Find the Offset to a given Capabilities ID
+ CAPID list:
+ 0x01 = PCI Power Management Interface
+ 0x04 = Slot Identification
+ 0x05 = MSI Capability
+ 0x10 = PCI Express Capability
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] PegFunc - Pci Function Number
+ @param[in] CapId - CAPID to search for
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+{
+ UINT8 CapHeader;
+
+ ///
+ /// Always start at Offset 0x34
+ ///
+ CapHeader = MmPci8 (0, Bus, Device, PegFunc, PCI_CAPBILITY_POINTER_OFFSET);
+ if (CapHeader == 0xFF) {
+ return 0;
+ }
+
+ while (CapHeader != 0) {
+ ///
+ /// Bottom 2 bits of the pointers are reserved per PCI Local Bus Spec 2.2
+ ///
+ CapHeader &= ~(BIT1 | BIT0);
+ ///
+ /// Search for desired CapID
+ ///
+ if (MmPci8 (0, Bus, Device, PegFunc, CapHeader) == CapId) {
+ return CapHeader;
+ }
+
+ CapHeader = MmPci8 (0, Bus, Device, PegFunc, CapHeader + 1);
+ }
+
+ return 0;
+}
+
+
+VOID
+SetLoadBus (
+ IN UINT32 DmiBar,
+ IN UINTN Dev,
+ IN UINTN Lane,
+ IN UINT32 LoadSel,
+ IN UINT32 LoadData,
+ IN UINT8 CpuSteppingId
+ )
+/**
+ Set Load Bus
+
+ @param[in] DmiBar - DMIBAR address
+ @param[in] Dev - Device Number
+ @param[in] Lane - Number of Lane
+ @param[in] LoadSel - Load selection value
+ @param[in] LoadData - Load Data
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+
+ @retval None
+**/
+{
+ UINT32 lbcvalue;
+ UINT32 lbcdata;
+ UINT32 lbclnsel;
+ UINT32 lbcldsel;
+ UINT32 lbcaddr;
+
+ lbcaddr = R_SA_PEG_LOADBUSCTL0_OFFSET + BUNDLE_STEP * (Lane >> 1);
+ lbcvalue = 0x70000000;
+
+ lbclnsel = ((Lane & 1) == 0) ? 0x80000 : 0x100000;
+ lbcldsel = (LoadSel & 0x3f) << 21;
+ lbcdata = (LoadData << 1) & 0x7FFF;
+
+ lbcvalue = lbcvalue | lbclnsel | lbcldsel | lbcdata;
+
+ if (Dev == 0) {
+ Mmio32 (DmiBar, lbcaddr) = lbcvalue;
+ } else {
+ MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr) = lbcvalue;
+ }
+
+ return;
+}
+
+UINT32
+GetMonBus (
+ IN UINT32 DmiBar,
+ IN UINTN Dev,
+ IN UINTN Lane,
+ IN UINT32 LoadSel,
+ IN UINT8 CpuSteppingId
+ )
+/**
+ Get monitor bus from the lane selected
+
+ @param[in] DmiBar - DMIBAR address
+ @param[in] Dev - Device number
+ @param[in] Lane - Number of Lane
+ @param[in] LoadSel - Load selection value
+ @param[in] LoadData - Load selecttion data
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+
+ @retval UINT32 - Load bus address
+**/
+{
+ UINT32 monvalue;
+ UINT32 prevalue;
+ UINT32 lbclnsel;
+ UINT32 lbcldsel;
+ UINT32 lbcaddr;
+ UINT32 Result;
+
+ lbcaddr = R_SA_PEG_LOADBUSCTL0_OFFSET + BUNDLE_STEP * (Lane >> 1);
+ monvalue = 0x068008000;
+
+ if (Dev == 0) {
+ prevalue = Mmio32 (DmiBar, lbcaddr);
+ } else {
+ prevalue = MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr);
+ }
+ monvalue = monvalue | (prevalue & 0x7FFE);
+
+ lbclnsel = ((Lane & 1) == 0) ? 0x80000 : 0x100000;
+ lbcldsel = (LoadSel & 0x3f) << 21;
+ monvalue = monvalue | lbclnsel | lbcldsel;
+
+ if (Dev == 0) {
+ Mmio32 (DmiBar, lbcaddr) = monvalue;
+ Result = Mmio32 (DmiBar, lbcaddr);
+ } else {
+ MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr) = monvalue;
+ Result = MmPci32 (0, SA_PEG_BUS_NUM, Dev, SA_PEG10_FUN_NUM, lbcaddr);
+ }
+
+ return (Result >> 1) & 0x3FFF;
+}
+
+VOID
+ProgramPreset (
+ IN UINT8 Direction,
+ IN UINT8 PresetValue,
+ IN UINT8 PegFunc,
+ IN UINT8 Lane
+ )
+/**
+ Program PEG Gen3 preset value
+
+ @param[in] Direction - 0 = Root Port, 1 = End Point
+ @param[in] PresetValue - Preset value to program
+ @param[in] PegFunc - Peg function number to be configured
+ @param[in] Lane - Lane to be configured
+
+ @retval None
+**/
+{
+ UINT32 Data32Or;
+ UINT32 Data32And;
+ UINT8 OriginalLane;
+
+ OriginalLane = Lane;
+ switch (PegFunc) {
+ case 1:
+ if (Lane < 8) {
+ DEBUG ((EFI_D_WARN, "Invalid input to ProgramPreset() function! PegFunc=%d, Lane=%d\n", PegFunc, Lane));
+ return;
+ } else {
+ Lane -= 8;
+ }
+ break;
+ case 2:
+ if (Lane < 12) {
+ DEBUG ((EFI_D_WARN, "Invalid input to ProgramPreset() function! PegFunc=%d, Lane=%d\n", PegFunc, Lane));
+ return;
+ } else {
+ Lane -= 12;
+ }
+ break;
+ default:
+ break;
+ }
+ ///
+ /// RP preset goes to bits [3:0] for even lane and [19:16] for odd lane
+ /// EP preset goes to bits [11:8] for even lane and [27:24] for odd lane
+ ///
+ if (Direction != 0) {
+ if ((Lane % 2) == 0) {
+ Data32And = 0xFFFFF0FF;
+ Data32Or = PresetValue << 8;
+ } else {
+ Data32And = 0xF0FFFFFF;
+ Data32Or = PresetValue << 24;
+ }
+ } else {
+ if (OriginalLane >= 8) {
+ if ((Lane % 2) == 0) {
+ Data32And = 0xFFF0FFFF;
+ Data32Or = PresetValue << 16;
+ } else {
+ Data32And = 0xFFFFFFF0;
+ Data32Or = PresetValue;
+ }
+ } else {
+ if ((Lane % 2) == 0) {
+ Data32And = 0xFFFFFFF0;
+ Data32Or = PresetValue;
+ } else {
+ Data32And = 0xFFF0FFFF;
+ Data32Or = PresetValue << 16;
+ }
+ }
+ }
+
+ MmPci32AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, PegFunc, R_SA_PEG_EQCTL0_1_OFFSET + (Lane / 2) * 4, Data32And, Data32Or);
+
+ return;
+}
+
+VOID
+ProgramPresetPerLane (
+ IN UINT8 *RootPortPreset,
+ IN UINT8 *EndPointPreset,
+ IN UINT8 *EndPointHint,
+ IN UINTN HwStrap
+ )
+/**
+ Program PEG Gen3 preset values per lane
+
+ @param[in] RootPortPreset - Array of root port preset values to program
+ @param[in] EndPointPreset - Array of end point preset values to program
+ @param[in] EndPointHint - Array of end point hint value to program
+ @param[in] HwStrap - HwStrap configuration from FUSESCMN
+
+ @retval None
+**/
+{
+ UINTN i;
+
+ for (i = 0; i < SA_PEG_MAX_LANE; i++) {
+ if (RootPortPreset[i] > 9) {
+ RootPortPreset[i] = 8;
+ }
+ if (EndPointPreset[i] > 9) {
+ EndPointPreset[i] = 7;
+ }
+ if (EndPointHint[i] > 6) {
+ EndPointHint[i] = 2;
+ }
+ }
+
+ ///
+ /// RP preset goes to bits [3:0] and [19:16]
+ /// EP preset goes to bits [11:8] and [27:24]
+ /// EP hint goes to bits [14:12] and [30:28]
+ ///
+ switch (HwStrap) {
+ case SA_PEG_x16_x0_x0:
+ ///
+ /// PEG10 x16
+ ///
+
+ for (i = 0; i < 4; ++i) {
+ McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0,
+ RootPortPreset[2 * i] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i + 1] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28));
+ }
+ for (i = 4; i < 8; ++i) {
+ McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0,
+ RootPortPreset[2 * i + 1] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28));
+ }
+ break;
+
+ case SA_PEG_x8_x8_x0:
+ ///
+ /// PEG10 x8 / PEG11 x8
+ ///
+ for (i = 0; i < 4; ++i) {
+ McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0,
+ RootPortPreset[2 * i] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i + 1] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28));
+ McD1F1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0,
+ RootPortPreset[8 + 2 * i + 1] | (EndPointPreset[8 + 2 * i] << 8) | (EndPointHint[8 + 2 * i] << 12) | (RootPortPreset[8 + 2 * i] << 16) | (EndPointPreset[8 + 2 * i + 1] << 24) | (EndPointHint[8 + 2 * i + 1] << 28));
+ }
+ break;
+
+ case SA_PEG_x8_x4_x4:
+ ///
+ /// PEG10 x8 / PEG11 x4 / PEG12 x4
+ ///
+ for (i = 0; i < 4; ++i) {
+ McD1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0,
+ RootPortPreset[2 * i] | (EndPointPreset[2 * i] << 8) | (EndPointHint[2 * i] << 12) | (RootPortPreset[2 * i + 1] << 16) | (EndPointPreset[2 * i + 1] << 24) | (EndPointHint[2 * i + 1] << 28));
+ }
+ for (i = 0; i < 2; ++i) {
+ McD1F1PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0,
+ RootPortPreset[8 + 2 * i + 1] | (EndPointPreset[8 + 2 * i] << 8) | (EndPointHint[8 + 2 * i] << 12) | (RootPortPreset[8 + 2 * i] << 16) | (EndPointPreset[8 + 2 * i + 1] << 24) | (EndPointHint[8 + 2 * i + 1] << 28));
+ McD1F2PciCfg32AndThenOr (R_SA_PEG_EQCTL0_1_OFFSET + i * 4, 0x80F080F0,
+ RootPortPreset[12 + 2 * i + 1] | (EndPointPreset[12 + 2 * i] << 8) | (EndPointHint[12 + 2 * i] << 12) | (RootPortPreset[12 + 2 * i] << 16) | (EndPointPreset[12 + 2 * i + 1] << 24) | (EndPointHint[12 + 2 * i + 1] << 28));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+VOID
+PegGen3Equalization (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT8 CpuSteppingId,
+ IN UINTN HwStrap
+ )
+/**
+ Perform PEG Gen3 Equalization steps
+
+ @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+ @param[in] HwStrap - HwStrap configuration from FUSESCMN
+
+ @retval None
+**/
+{
+ UINT8 *RootPortPreset;
+ UINT8 *EndPointPreset;
+ UINT8 *EndPointHint;
+
+ ///
+ /// Apply static presets for root port and endpoint
+ ///
+ RootPortPreset = SaPlatformPolicyPpi->PcieConfig->Gen3RootPortPreset;
+ EndPointPreset = SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset;
+ EndPointHint = SaPlatformPolicyPpi->PcieConfig->Gen3EndPointHint;
+
+ ProgramPresetPerLane (RootPortPreset, EndPointPreset, EndPointHint, HwStrap);
+
+ return;
+}
+
+#endif // PEG_FLAG
+
+#if defined(DMI_FLAG) || defined(PEG_FLAG)
+VOID
+PegDmiRecipe (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT32 MchBar,
+ IN UINT32 DmiBar,
+ IN UINTN Dev,
+ IN UINT8 SwingControl
+ )
+/**
+ Perform PEG/DMI PCIe Recipe steps
+
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] MchBar - MCHBAR or zero if called for PEG
+ @param[in] DmiBar - DMIBAR or zero if called for PEG
+ @param[in] Dev - PEG device number: 1 for PEG10, 0 if called for DMI.
+ @param[in] SwingControl - 1 = Half, 2 = Full
+
+ @retval None
+**/
+{
+ UINTN i;
+ UINTN BundlesCount;
+ UINTN LanesCount;
+ UINT32 Data32;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 VcuAddress;
+ UINT8 VcuReadOp;
+ UINT8 VcuWriteOp;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ BOOLEAN IsSingleCall;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// With both DMI_FLAG and PEG_FLAG defined, this function is called twice: once for DMI and once for PEG.
+ /// Some registers are shared between DMI and PEG, so they are only programmed during one of the calls.
+ /// If only one flag is defined, this function will only be called once, so the shared registers need to be
+ /// programmed during the first/only call.
+ ///
+ IsSingleCall = TRUE;
+#if defined(DMI_FLAG) && defined(PEG_FLAG)
+ IsSingleCall = FALSE;
+#endif
+
+ if (Dev == SA_PEG_DEV_NUM) {
+ ///
+ /// PEG10
+ ///
+ LanesCount = SA_PEG_MAX_LANE;
+ } else {
+ ///
+ /// DMI
+ ///
+ LanesCount = SA_DMI_MAX_LANE;
+ }
+
+ BundlesCount = LanesCount >> 1;
+
+ ///
+ /// g23rxvref = 0xC (DMI & PEG)
+ ///
+ Data32And = (UINT32) ~(BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ Data32Or = 0xC;
+ for (i = 0; i < LanesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFELN0CFG0_OFFSET + i * LANE_STEP, Data32And, Data32Or);
+ }
+ ///
+ /// CDRPDDATMODE = 0x1 (DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < LanesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFELN0CFG1_OFFSET + i * LANE_STEP, 0xFFFFFFFF, BIT11);
+ }
+ }
+ ///
+ /// irefctl = 0x2 (PEG only)
+ ///
+ if (DmiBar == 0) {
+ ///
+ /// Switch on
+ /// SwingControl 1 == Half
+ /// 2 == Full (Default)
+ ///
+ switch (SwingControl) {
+ case SA_SWING_HALF:
+ Data32Or = 0x0C;
+ break;
+
+ default:
+ case SA_SWING_FULL:
+ Data32Or = 0x02;
+ break;
+ }
+
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0x1F), Data32Or);
+ }
+ }
+ ///
+ /// txvrefsel = 0x3 (PEG only)
+ ///
+ if (DmiBar == 0) {
+ ///
+ /// Switch on
+ /// SwingControl 1 == Half
+ /// 2 == Full (Default)
+ ///
+ switch (SwingControl) {
+ case SA_SWING_HALF:
+ Data32Or = 0x0E;
+ break;
+
+ default:
+ case SA_SWING_FULL:
+ Data32Or = 0x03;
+ break;
+ }
+
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0x1F << 5), Data32Or << 5);
+ }
+ }
+ ///
+ /// igacq = 0x0 (HSW A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(7 << 22), 0);
+ }
+ }
+ ///
+ /// dfegainacq = 0x1 (HSW A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 29), 1 << 29);
+ }
+ }
+ ///
+ /// PGTRK = 0x9 (DMI & PEG)
+ ///
+ Data32And = (UINT32) ~(BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5);
+ Data32Or = 0x9 << 5;
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or);
+ }
+ ///
+ /// igtrk = 0x0 (HSW A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, (UINT32) ~(7 << 17), 0);
+ }
+ }
+ ///
+ /// RXRTBIN = 0x5 (PEG only)
+ ///
+ if (DmiBar == 0) {
+ Data32And = (UINT32) ~(BIT24 | BIT23 | BIT22 | BIT21);
+ Data32Or = 0x5 << 21;
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or);
+ }
+ }
+ ///
+ /// G3RXCTLEPEAK = 0x8 (PEG only)
+ ///
+ if (DmiBar == 0) {
+ Data32And = (UINT32) ~(BIT9 | BIT8 | BIT7 | BIT6);
+ for (i = 0; i < BundlesCount; i++) {
+ if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) {
+ Data32Or = SaPlatformPolicyPpi->PcieConfig->Gen3RxCtleP[i] << 6;
+ } else {
+ Data32Or = 8 << 6;
+ }
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG4_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or);
+ }
+ }
+ ///
+ /// g2rxctlepeak = 0x0 (DMI & PEG)
+ ///
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG4_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0xF << 10), 0);
+ }
+ ///
+ /// AFEBNDSPARE[uneqmm] = 0x4 (HSW == A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG4_OFFSET + i * BUNDLE_STEP, (UINT32) ~(7 << 29), 4 << 29);
+ }
+ }
+ ///
+ /// AGCACQLEN = 0x2 (HSW == A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 7), 2 << 7);
+ }
+ }
+ ///
+ /// G2DFEC1CTL = 0x0 (HSW == A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 12), 0);
+ }
+ }
+ ///
+ /// RXSQEXCTL = 0x0 (DMI & PEG)
+ ///
+ Data32And = (UINT32) ~(BIT20 | BIT19 | BIT18);
+ Data32Or = 0;
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or);
+ }
+ ///
+ /// dfemfc = 0x3 (HSW == A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG5_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 21), 3 << 21);
+ }
+ }
+
+ ///
+ /// ICOMPGAIN = 0x6 (HSW == A0: DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ VcuAddress = R_SA_VCU_AFECMNCFG0_ADDRESS_REV1;
+ VcuReadOp = V_SA_VCU_OPCODE_READ_MMIO_REV1;
+ VcuWriteOp = V_SA_VCU_OPCODE_WRITE_MMIO_REV1;
+ } else {
+ VcuAddress = R_SA_VCU_AFECMNCFG0_ADDRESS_REV2;
+ VcuReadOp = V_SA_VCU_OPCODE_READ_MMIO_REV2;
+ VcuWriteOp = V_SA_VCU_OPCODE_WRITE_MMIO_REV2;
+ }
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ if ((DmiBar != 0) || (IsSingleCall)) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 &= (UINT32) ~(BIT12 | BIT11 | BIT10 | BIT9);
+ Data32 |= 0x6 << 9;
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ }
+ }
+
+ ///
+ /// PEGVCMSEL = 0x3 (PEG only)
+ ///
+ if (DmiBar == 0) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 &= (UINT32) ~(BIT29 | BIT28 | BIT27 | BIT26 | BIT25);
+ ///
+ /// Switch on
+ /// SwingControl 1 == Half
+ /// 2 == Full (Default)
+ ///
+ switch (SwingControl) {
+ case SA_SWING_HALF:
+ Data32 |= (UINT32) (0x0E << 25);
+ break;
+
+ default:
+ case SA_SWING_FULL:
+ Data32 |= (UINT32) (0x03 << 25);
+ break;
+ }
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ }
+
+ ///
+ /// PH3EQFFEKNOBS = 0x8 (DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ VcuAddress = R_SA_VCU_AFECMNCFG2_ADDRESS_REV1;
+ } else {
+ VcuAddress = R_SA_VCU_AFECMNCFG2_ADDRESS_REV2;
+ }
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ if ((DmiBar != 0) || (IsSingleCall)) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 &= (UINT32) ~(BIT30 | BIT29 | BIT28 | BIT27 | BIT26 | BIT25);
+ Data32 |= 0x8 << 25;
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ }
+ }
+
+ ///
+ /// FIXUNCORRDATA = 0x0 (DMI & PEG)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ VcuAddress = R_SA_VCU_AFECMNCFG3_ADDRESS_REV1;
+ } else {
+ VcuAddress = R_SA_VCU_AFECMNCFG3_ADDRESS_REV2;
+ }
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ if ((DmiBar != 0) || (IsSingleCall)) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 &= (UINT32) ~(BIT20);
+ Data32 |= 0;
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ }
+ }
+ ///
+ /// BLEGCTL = 0x0 (DMI & PEG)
+ ///
+ if ((DmiBar != 0) || (IsSingleCall)) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 &= (UINT32) ~(BIT28 | BIT27 | BIT26 | BIT25 | BIT24 | BIT23);
+ Data32 |= 0;
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ }
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) &&
+ ((DmiBar != 0) || (IsSingleCall) )) {
+ VcuAddress = R_SA_VCU_AFECMNCFG7_ADDRESS_REV1;
+ VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV1;
+ VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV1;
+
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ ///
+ /// VREFRXDET = 0x19 (PEG only)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ Data32 &= (UINT32) ~(BIT18 | BIT17 | BIT16 | BIT15 | BIT14);
+ Data32 |= 0x19 << 14;
+ }
+ ///
+ /// DFEFIX = 0x4 (PEG only)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ Data32 &= (UINT32) ~(BIT30 | BIT29 | BIT28);
+ Data32 |= 0x4 << 28;
+ }
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ }
+
+
+ ///
+ /// RXDETECT_SAMPLE_TIME = 0x4 (PEG only)
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ if (DmiBar == 0) {
+ Data32And = (UINT32) ~(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8 | BIT7);
+ Data32Or = 0x4 << 7;
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFE_PWRON_OFFSET, Data32And, Data32Or);
+ }
+ }
+
+ ///
+ /// RXL0S_ENTRY_EXIT_TIMER = 0x00 (HSW == A0: DMI & PEG)
+ /// = 0x13 (HSW >= B0: DMI & PEG)
+ ///
+ Data32And = (UINT32) ~(BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ Data32Or = 0x00;
+ } else {
+ Data32Or = 0x13;
+ }
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFE_PM_TMR_OFFSET, Data32And, Data32Or);
+
+ ///
+ /// Set 0xC38[6] = 0x1 (HSW == A0), 0x0 (HSW >= B0) (DMI & PEG)
+ ///
+ Data32And = (UINT32) ~(BIT6);
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ Data32Or = 0x1 << 6;
+ } else {
+ Data32Or = 0x0 << 6;
+ }
+ if (DmiBar == 0) {
+ McD1PciCfg16AndThenOr (R_SA_PEG_CMNSPARE_OFFSET, Data32And, Data32Or);
+ McD1F1PciCfg16AndThenOr (R_SA_PEG_CMNSPARE_OFFSET, Data32And, Data32Or);
+ McD1F2PciCfg16AndThenOr (R_SA_PEG_CMNSPARE_OFFSET, Data32And, Data32Or);
+ } else {
+ Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_CMNSPARE_OFFSET, Data32And, Data32Or);
+ }
+
+ ///
+ /// Set 0x260[1:0] = '10b' (DMI & PEG)
+ ///
+ Data32And = (UINT32) ~(BIT1 | BIT0);
+ Data32Or = 0x2;
+ if (DmiBar == 0) {
+ McD1PciCfg16AndThenOr (R_SA_PEG_CFG6_OFFSET, Data32And, Data32Or);
+ McD1F1PciCfg16AndThenOr (R_SA_PEG_CFG6_OFFSET, Data32And, Data32Or);
+ McD1F2PciCfg16AndThenOr (R_SA_PEG_CFG6_OFFSET, Data32And, Data32Or);
+ } else {
+ Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_CFG6_OFFSET, Data32And, Data32Or);
+ }
+
+ ///
+ /// setdfelsbsel = 0
+ ///
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG0_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 26), 0);
+ }
+ ///
+ /// OFFCORGAIN = 0x3 (HSW >= A0)
+ ///
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG1_OFFSET + i * BUNDLE_STEP, (UINT32) ~(3 << 10), 3 << 10);
+ }
+
+ ///
+ /// fixtxrtermoffset = -3; (PEG only)
+ ///
+ if (DmiBar == 0) {
+ for (i = 0; i < BundlesCount; i++) {
+ SaMmio32AndThenOr (DmiBar, Dev, R_SA_PEG_AFEBND0CFG3_OFFSET + i * BUNDLE_STEP, (UINT32) ~(0x1F << 25), ((0x03 << 1) | 0x01) << 25);
+ }
+ }
+
+ ///
+ /// Set BND0SPARE[29:27] = '101b' (PEG)
+ ///
+ Data32And = (UINT32) ~(BIT29 | BIT28 | BIT27);
+ Data32Or = (UINT32) 0x28000000;
+ for (i = 0; i < BundlesCount; i++) {
+ MmPci32AndThenOr (
+ 0,
+ SA_PEG_BUS_NUM,
+ SA_PEG10_DEV_NUM,
+ SA_PEG10_FUN_NUM,
+ R_SA_PEG_BND0SPARE_OFFSET + (i * BUNDLE_STEP),
+ Data32And,
+ Data32Or
+ );
+ }
+ return;
+}
+#endif // DMI_FLAG || PEG_FLAG
+
+#ifdef PEG_FLAG
+VOID
+BubbleSort (
+ IN OUT DATA_SAMPLE Array[]
+ )
+/**
+ Bubble sort from DATA_SAMPLE
+
+ @param[in, out] - Array[]: array of DATA_SAMPLE
+
+ @retval None
+**/
+{
+ UINTN n;
+ UINTN i;
+ UINTN j;
+ DATA_SAMPLE Temp;
+
+ n = (UINTN) Array[0].Count;
+
+ for (i = 1; i <= n; i++) {
+ for (j = n; j > i; j--) {
+ if (Array[j - 1].Data > Array[j].Data) {
+ Temp = Array[j - 1];
+ Array[j - 1] = Array[j];
+ Array[j] = Temp;
+ }
+ }
+ }
+
+ return;
+}
+
+UINT32
+GetMiddleValue (
+ IN OUT DATA_SAMPLE Array[]
+ )
+/**
+ Get Middle Value from DATA_SAMPLE
+
+ @param[in, out] - Array[]: array of DATA_SAMPLE
+
+ @retval UINT32 : Middle Value of DATA_SAMPLE
+**/
+{
+ UINT32 n;
+
+ n = Array[0].Count;
+
+ return Array[n / 2 + 1].Data;
+}
+
+#ifdef EFI_DEBUG
+VOID
+DumpSamplerValues (
+ IN UINT32 DmiBar,
+ IN UINT8 CpuSteppingId,
+ IN UINTN Dev,
+ IN UINTN LanesCount
+ )
+/**
+ Dump Sampler Values
+
+ @param[in] DmiBar - DMIBAR address
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+ @param[in] Dev - Device number
+ @param[in] LanesCount - Value of Lanes
+
+ @retval None
+**/
+{
+ UINTN Lane;
+ UINT32 Sampler;
+ UINT8 SampleData;
+
+ DEBUG ((EFI_D_INFO, "Lane DS0 DS1 ESP0 ESP1 ESM0 ESM1\n"));
+ for (Lane = 0; Lane < LanesCount; Lane++) {
+ DEBUG ((EFI_D_INFO, "%2d: ", Lane));
+ for (Sampler = 0; Sampler < 6; Sampler++) {
+ SampleData = GetMonBus (DmiBar, Dev, Lane, 0x31 + Sampler, CpuSteppingId) & 0x3F;
+ DEBUG ((EFI_D_INFO, "%02X ", SampleData));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+
+ return;
+}
+#endif // EFI_DEBUG
+
+VOID
+SamplerCalibratePegPort (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT8 CpuSteppingId,
+ IN UINTN Dev,
+ IN UINTN LanesCount,
+ IN UINTN HwStrap
+ )
+/**
+ This function performs the PEG Sampler Calibration for HSW on a given PEG controller
+ It also calls the Step 2 of PEG Recipe routine.
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - pointer to PEI_STALL_PPI
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+ @param[in] Dev - Device number
+ @param[in] LanesCount - Value of Lanes
+ @param[in] HwStrap - HwStrap configuration from FUSESCMN
+
+ @retval None
+**/
+{
+ UINTN Iteration;
+ UINTN PegSamplerIterations;
+ UINTN Lane;
+ UINTN i;
+ BOOLEAN Peg11Present;
+ BOOLEAN Peg12Present;
+ BOOLEAN EarlyExit;
+ BOOLEAN CodeFound;
+ UINT8 SampleData;
+ UINT32 Sampler;
+ UINT16 CodesFound;
+ UINT32 MiddleCode;
+ UINTN OcDelay;
+
+ ///
+ /// Array of sampling data - 16 lanes max, 6 samplers per lane, up to MAX_CODES per sampler
+ /// Size is 3 * 16 * 6 * 11 = 3168 bytes
+ ///
+ DATA_SAMPLE SampleArray[16][6][MAX_CODES + 1];
+
+ PegSamplerIterations = SA_PEG_SAMPLER_ITERATIONS;
+ Peg11Present = FALSE;
+ Peg12Present = FALSE;
+
+ if (LanesCount == 16) {
+ OcDelay = 10;
+ } else {
+ OcDelay = 20;
+ }
+
+ ZeroMem (&SampleArray, sizeof (SampleArray));
+
+ if (HwStrap == SA_PEG_x8_x8_x0) {
+ Peg11Present = TRUE;
+ }
+
+
+ if (HwStrap == SA_PEG_x8_x4_x4) {
+ Peg11Present = TRUE;
+ Peg12Present = TRUE;
+ }
+ ///
+ /// Dump the Sampler values before calibration
+ ///
+ DEBUG ((EFI_D_INFO, "--- Sampler values before calibration ---\n"));
+#ifdef EFI_DEBUG
+ DumpSamplerValues (0, CpuSteppingId, Dev, LanesCount);
+#endif // EFI_DEBUG
+ ///
+ /// Disable the link
+ ///
+ MmPci16Or (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_LCTL_OFFSET, BIT4);
+ if (Peg11Present) {
+ MmPci16Or (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_LCTL_OFFSET, BIT4);
+ }
+ if (Peg12Present) {
+ MmPci16Or (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_LCTL_OFFSET, BIT4);
+ }
+
+ ///
+ /// Delay 10 ms after link disable
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, 10 * STALL_ONE_MILLI_SECOND);
+
+ ///
+ /// Override L0s and L1 - set bits 11, 13 & 15 of AFEOVR
+ ///
+ MmPci32Or (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_AFEOVR_OFFSET, 0xA800);
+ if (Peg11Present) {
+ MmPci32Or (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_AFEOVR_OFFSET, 0xA800);
+ }
+ if (Peg12Present) {
+ MmPci32Or (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_AFEOVR_OFFSET, 0xA800);
+ }
+
+ for (Iteration = 0; Iteration < PegSamplerIterations; Iteration++) {
+ PostCode ((UINT8) (Iteration / 100));
+ ///
+ /// First trigger OC on each lane
+ ///
+ for (Lane = 0; Lane < LanesCount; Lane++) {
+ SetLoadBus (0, Dev, Lane, 0x39, 0x1, CpuSteppingId);
+ SetLoadBus (0, Dev, Lane, 0x3A, 0xC, CpuSteppingId);
+ }
+ ///
+ /// Delay to give the OC time to complete
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, OcDelay * STALL_ONE_MICRO_SECOND);
+
+ for (Lane = 0; Lane < LanesCount; Lane++) {
+ for (Sampler = 0; Sampler < 6; Sampler++) {
+ SampleData = GetMonBus (0, Dev, Lane, 0x31 + Sampler, CpuSteppingId) & 0x3F;
+
+ ///
+ /// SampleArray[Lane][Sampler][0].Count holds the number of distinct codes found so far
+ ///
+ CodeFound = FALSE;
+ for (i = 1; i <= SampleArray[Lane][Sampler][0].Count; ++i) {
+ if (SampleArray[Lane][Sampler][i].Data == SampleData) {
+ CodeFound = TRUE;
+ SampleArray[Lane][Sampler][i].Count++;
+ break;
+ }
+ }
+
+ if (!CodeFound) {
+ if (i > MAX_CODES) {
+ DEBUG ((EFI_D_ERROR, "ERROR: PEG dev=%d, lane=%d, sampler=%d, iteration=%d, found more than %d distinct codes!!!\n", Dev, Lane, Sampler, Iteration, MAX_CODES));
+ if (LanesCount == 16) {
+ PostCode ((UINT8) (ERROR_BY_16 >> 8));
+ } else {
+ PostCode ((UINT8) (ERROR_NOT_BY_16 >> 8));
+ }
+
+ EFI_DEADLOOP ();
+ }
+ ///
+ /// Increment the number of distinct codes found for this sampler
+ ///
+ SampleArray[Lane][Sampler][0].Count++;
+
+ ///
+ /// Save the new code
+ ///
+ SampleArray[Lane][Sampler][i].Data = SampleData;
+ SampleArray[Lane][Sampler][i].Count = 1;
+ }
+ }
+ }
+ ///
+ /// Exit early if all the sampled lanes have more than 5 codes,
+ /// and we covered at least 20% of iterations.
+ /// Ignore the inactive lanes, these will only show one code.
+ ///
+ if (Iteration > PegSamplerIterations / 5) {
+ EarlyExit = TRUE;
+ for (Lane = 0; Lane < LanesCount; Lane++) {
+ for (Sampler = 0; Sampler < 6; Sampler++) {
+ CodesFound = SampleArray[Lane][Sampler][0].Count;
+ if ((CodesFound > 1) && (CodesFound < 5)) {
+ EarlyExit = FALSE;
+ break;
+ }
+ }
+
+ if (!EarlyExit) {
+ break;
+ }
+ }
+
+ if (EarlyExit) {
+ break;
+ }
+ }
+ }
+ ///
+ /// Iteration
+ ///
+ for (Lane = 0; Lane < LanesCount; Lane++) {
+ for (Sampler = 0; Sampler < 6; Sampler++) {
+ ///
+ /// Sort the codes for this Lane / Sampler
+ ///
+ BubbleSort (SampleArray[Lane][Sampler]);
+ ///
+ /// Find the middle value
+ ///
+ MiddleCode = GetMiddleValue (SampleArray[Lane][Sampler]);
+ ///
+ /// Set the middle calibration code
+ ///
+ SetLoadBus (0, Dev, Lane, 0x31 + Sampler, MiddleCode, CpuSteppingId);
+ }
+ }
+ ///
+ /// Restore AFEOVR
+ ///
+ MmPci32 (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_AFEOVR_OFFSET) = 0;
+ if (Peg11Present) {
+ MmPci32 (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_AFEOVR_OFFSET) = 0;
+ }
+ if (Peg12Present) {
+ MmPci32 (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_AFEOVR_OFFSET) = 0;
+ }
+ ///
+ /// Delay 1 ms before link enable
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND);
+
+ ///
+ /// Enable the link
+ ///
+ MmPci16And (0, SA_PEG_BUS_NUM, Dev, 0, R_SA_PEG_LCTL_OFFSET, ~BIT4);
+ if (Peg11Present) {
+ MmPci16And (0, SA_PEG_BUS_NUM, Dev, 1, R_SA_PEG_LCTL_OFFSET, ~BIT4);
+ }
+ if (Peg12Present) {
+ MmPci16And (0, SA_PEG_BUS_NUM, Dev, 2, R_SA_PEG_LCTL_OFFSET, ~BIT4);
+ }
+ ///
+ /// Dump the Sampler values after calibration
+ ///
+ DEBUG ((EFI_D_INFO, "--- Sampler values after calibration ---\n"));
+#ifdef EFI_DEBUG
+ DumpSamplerValues (0, CpuSteppingId, Dev, LanesCount);
+#endif // EFI_DEBUG
+ return;
+}
+
+VOID
+PegSamplerCalibration (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT8 CpuSteppingId,
+ IN UINT8 HwStrap
+ )
+/**
+ This function performs the PEG Sampler Calibration
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] StallPpi - pointer to PEI_STALL_PPI
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+ @param[in] HwStrap - HwStrap configuration from FUSESCMN
+
+ @retval None
+**/
+{
+ UINT32 Data32;
+
+ ///
+ /// Calibrate PEG10/PEG11/PEG12 - 16 lanes total
+ ///
+ if (MmPci16 (0, 0, 1, 0, PCI_VID) != 0xFFFF) {
+ Data32 = MmPci32 (0, 0, 1, 0, R_SA_PEG_PEGSTS_OFFSET);
+ if (((Data32 & 0xFFFF) != 0) && (((Data32 >> 16) & 0x0F) >= 7)) {
+ SamplerCalibratePegPort (PeiServices, StallPpi, CpuSteppingId, SA_PEG10_DEV_NUM, 16, HwStrap);
+ }
+ }
+
+ return;
+}
+
+VOID
+PegGen2AutoSpeedDisable (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEG_PORT *PegPortTable,
+ IN UINTN PegPortTableSize,
+ IN UINT8 HwStrap
+ )
+/**
+ This function performs the PEG GEN2 Auto Speed Disable
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] SaDataHob - Pointer to SA_DATA_HOB
+ @param[in] PegPortTable - Pointer to PEG Port Table
+ @param[in] PegPortTableSize - Size of PEG Port Table
+ @param[in] HwStrap - Furcation HW Strap Value
+
+ @retval None
+**/
+{
+ UINTN PortIndex;
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ UINT8 DisableAutoSpeedUp;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+
+ DisableAutoSpeedUp = 0;
+ Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ for (PortIndex = 0; PortIndex < PegPortTableSize; PortIndex++) {
+ PegBus = PegPortTable[PortIndex].Bus;
+ PegDev = PegPortTable[PortIndex].Device;
+ PegFunc = PegPortTable[PortIndex].Function;
+
+ ///
+ /// If VC0 is still pending
+ /// And presence of an endpoint was detected, enable GEN2 auto speed disable
+ ///
+ if ((MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID ) != 0xFFFF) &&
+ ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) != 0) &&
+ ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_SLOTSTS_OFFSET) & BIT6) != 0)) {
+ DisableAutoSpeedUp |= 1 << PegFunc;
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT4);
+ MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_CFG5_OFFSET, BIT9);
+ MmPci16And (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, (UINT16)~(BIT4));
+ }
+ }
+ ///
+ /// If needed, reinitialize link after disable
+ ///
+ if (DisableAutoSpeedUp != 0) {
+ if ((BootMode == BOOT_ON_S3_RESUME) || (GetPchPmStatus (WarmBoot) == TRUE)) {
+ if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) {
+ if (SaDataHob->PegData.PegLinkFailMask != 0) {
+ ///
+ /// Even on warm boot/S3 resume, we still want to force checking of VC0 status
+ ///
+ SaDataHob->PegData.PegLinkFailMask = 0;
+ }
+ }
+ }
+ GracefulLinkStatusStall (PeiServices, StallPpi, SaPlatformPolicyPpi, SaDataHob, HwStrap);
+ for (PortIndex = 0; PortIndex < PegPortTableSize; PortIndex++) {
+ PegBus = PegPortTable[PortIndex].Bus;
+ PegDev = PegPortTable[PortIndex].Device;
+ PegFunc = PegPortTable[PortIndex].Function;
+ if (((DisableAutoSpeedUp >> PegFunc) & 1) == 1) {
+ ///
+ /// Retrain to allow link to reach GEN2
+ ///
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5);
+ }
+ }
+ ///
+ /// Ensure all links are now ready
+ ///
+ if ((BootMode == BOOT_ON_S3_RESUME) || (GetPchPmStatus (WarmBoot) == TRUE)) {
+ if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) {
+ if (SaDataHob->PegData.PegLinkFailMask != 0) {
+ ///
+ /// Even on warm boot/S3 resume, we still want to force checking of VC0 status
+ ///
+ SaDataHob->PegData.PegLinkFailMask = 0;
+ }
+ }
+ }
+ GracefulLinkStatusStall (PeiServices, StallPpi, SaPlatformPolicyPpi, SaDataHob, HwStrap);
+ DEBUG ((EFI_D_INFO, "PEG Link Status after auto speed disable:\n"));
+ for (PortIndex = 0; PortIndex < PegPortTableSize; PortIndex++) {
+ PegBus = PegPortTable[PortIndex].Bus;
+ PegDev = PegPortTable[PortIndex].Device;
+ PegFunc = PegPortTable[PortIndex].Function;
+ ReportPcieLinkStatus (PegBus, PegDev, PegFunc);
+ }
+ }
+}
+
+VOID
+PciExpressInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Initialize the SA PciExpress in PEI
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+**/
+{
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+ UINT8 PegIndex;
+ UINT8 HwStrap;
+ UINT64 MchBar;
+ UINT64 DmiBar;
+ BOOLEAN DisableFun0;
+ BOOLEAN DisableFun1;
+ BOOLEAN DisableFun2;
+ BOOLEAN DisableLinkFunc0;
+ EFI_STATUS Status;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ UINTN PegComplete;
+ UINT16 Peg10Speed;
+ UINT16 Peg11Speed;
+ UINT16 Peg12Speed;
+ UINT8 SwingControl;
+ UINT8 Gen3Capable;
+ UINT8 i;
+ PEI_STALL_PPI *StallPpi;
+ UINT32 Data32;
+ UINT32 CapOffset;
+ BOOLEAN AnyGen3Endpoint;
+ UINT8 FullSwing;
+ UINT8 PreCursor;
+ UINT8 Cursor;
+ UINT8 PostCursor;
+
+ PEG_PORT PegPortTable[] = {
+ ///
+ /// Bus, Device, Function, Index, PresenceDetect, MaxLinkWidth, EndpointMaxLinkSpeed
+ ///
+ { SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, 0, FALSE, 16, 0}
+//AMI_OVERRIDE>>
+#if RC_PEG_1 == 1
+ ,{ SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, 1, FALSE, 8, 0}
+#endif
+#if RC_PEG_2 == 1
+ ,{ SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, 2, FALSE, 4, 0}
+#endif
+//AMI_OVERRIDE<<
+ };
+ SA_DATA_HOB *SaDataHob;
+ BOOLEAN S3Flow;
+ UINT8 LinkStatusGood;
+ BOOLEAN FunctionExists;
+ UINT8 UnusedLanes;
+ UINT8 CtrlMaxLinkWidth;
+ UINT8 EpMaxLinkWidth;
+ UINT16 LoopCount;
+ UINT8 MaxBndlPwrdnCount;
+ UINT8 BndlPwrdnCount;
+ UINT8 PwrDnUnusedBundlesSetupData;
+
+ HwStrap = SA_PEG_x16_x0_x0;
+ DisableFun0 = FALSE;
+ DisableFun1 = FALSE;
+ DisableFun2 = FALSE;
+ DisableLinkFunc0 = FALSE;
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+ DmiBar = McD0PciCfg64 (R_SA_DMIBAR) &~BIT0;
+ PegDev = 0x1;
+
+ Peg10Speed = 0;
+ Peg11Speed = 0;
+ Peg12Speed = 0;
+ SwingControl = SaPlatformPolicyPpi->PcieConfig->PegSwingControl;
+ SaDataHob = NULL;
+ S3Flow = FALSE;
+ Gen3Capable = TRUE;
+ AnyGen3Endpoint = FALSE;
+ FullSwing = 0;
+ CtrlMaxLinkWidth = 0;
+ EpMaxLinkWidth = 0;
+ UnusedLanes = 0;
+ LoopCount = 0;
+ MaxBndlPwrdnCount = 0;
+ BndlPwrdnCount = 0;
+ PwrDnUnusedBundlesSetupData = 0xFF;
+
+ ///
+ /// Check to see if PEG exists and leave initialization function if non-existant
+ ///
+ if (McD1PciCfg16 (PCI_VID) == 0xFFFF) {
+ DEBUG ((EFI_D_INFO, "PEG controller not detected\n"));
+ return;
+ }
+
+ ///
+ /// Read the HW straps - Bus 0, Device 1, Fun 0, Reg 0x504 BIT17,16
+ /// Fun 1 & 2 disabled = Pcie 1x16, Fun 2 disabled = Pcie 2x8
+ /// Fun 1 & 2 enabled = Pcie 1x8 + (2+4)
+ ///
+ HwStrap = (UINT8) ((MmPci32 (0, SA_MC_BUS, PegDev, 0, R_SA_PEG_FUSESCMN_OFFSET) >> 16) & 0x03);
+ DEBUG ((EFI_D_INFO, "PEG HW Strap value %x\n", HwStrap));
+
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPeiStallPpiGuid, 0, NULL, &StallPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Update PEG LCAP.MLW based on PEG port Split configuration.
+ /// This is Write-Once field, so keep the values in the structure,
+ /// and write later together with LCAP.MLS.
+ ///
+ switch (HwStrap) {
+ case SA_PEG_x8_x4_x4:
+ ///
+ /// 0x0: Device 1 functions 1 and 2 enabled
+ /// PEG10: x16->x8, PEG11: x8->x4, PEG12: x4
+ ///
+ PegPortTable[0].MaxLinkWidth = 8;
+//AMI_OVERRIDE >>
+#if RC_PEG_1 == 1
+ PegPortTable[1].MaxLinkWidth = 4;
+#endif
+//AMI_OVERRIDE <<
+ break;
+
+
+ case SA_PEG_x8_x8_x0:
+ ///
+ /// 0x2: Device 1 function 1 enabled; function 2 disabled
+ /// PEG10: x16->x8, PEG11: x8, PEG12: N/A
+ ///
+ PegPortTable[0].MaxLinkWidth = 8;
+ break;
+
+ default:
+ case SA_PEG_x16_x0_x0:
+ break;
+ }
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// Read PEG Gen3 Fuse to see if it should override programming
+ ///
+ if (MmPci32 (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, R_SA_MC_CAPID0_B) & BIT20) {
+ Gen3Capable = FALSE;
+ DEBUG ((EFI_D_INFO, "PEG Gen3 Fused off\n"));
+ }
+
+ ///
+ /// Gen3 Preset Search: 0 = Disabled, 1 = Enabled (default)
+ ///
+ if (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch == 2) {
+ SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch = 1;
+ }
+
+ ///
+ /// Restore SA Data HOB's PEG data
+ ///
+ if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) {
+ SaDataHob = (SA_DATA_HOB *) GetFirstGuidHob (&gSaDataHobGuid);
+
+ if (SaDataHob != NULL) {
+ if (SaPlatformPolicyPpi->PcieConfig->PegDataPtr != NULL) {
+ DEBUG ((EFI_D_INFO, "\nRestore SA PEG DATA from previous boot: Size=%X\n", sizeof (SA_PEG_DATA)));
+ CopyMem (&(SaDataHob->PegData), SaPlatformPolicyPpi->PcieConfig->PegDataPtr, sizeof (SA_PEG_DATA));
+ SaDataHob->PegDataValid = TRUE;
+ if ((SaDataHob->PegData.PegGen3PresetSearch != SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch) && (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch != 1)) {
+ ///
+ /// Zero out previous boot GEN3 Preset data so old data won't be re-used when PegGen3PresetSearch re-enabled later
+ ///
+ DEBUG ((EFI_D_INFO, "\nPegGen3PresetSearch is disabled, Clear old Preset data\n"));
+ for (PegIndex = 0; PegIndex < SA_PEG_MAX_FUN; PegIndex++) {
+ SaDataHob->PegData.EndPointVendorIdDeviceId[PegIndex] = 0;
+ for (i = 0; i < SA_PEG_MAX_LANE; i++) {
+ SaDataHob->PegData.BestPreset[i] = 0;
+ }
+ }
+ }
+ }
+ SaDataHob->PegData.PegGen3PresetSearch = SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch;
+ }
+ }
+
+ ///
+ /// Perform PEG Pre-Detection steps
+ ///
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ PegBus = PegPortTable[PegComplete].Bus;
+ PegDev = PegPortTable[PegComplete].Device;
+ PegFunc = PegPortTable[PegComplete].Function;
+ PegPreDetectionSteps (PegBus, PegDev, PegFunc, SaPlatformPolicyPpi);
+ }
+
+ ///
+ /// Perform PEG Recipe steps
+ ///
+ DEBUG ((EFI_D_INFO, "PEG Recipe...\n"));
+ PegDmiRecipe (SaPlatformPolicyPpi, (UINT32) MchBar, 0, SA_PEG10_DEV_NUM, SwingControl);
+
+ ///
+ /// Perform PEG Gen3 Equalization steps and load preset values
+ ///
+ if (Gen3Capable == TRUE) {
+ if (SaPlatformPolicyPpi->PcieConfig->PegGen3Equalization != 0) {
+ DEBUG ((EFI_D_INFO, "PEG Gen3 Equalization...\n"));
+ PegGen3Equalization (SaPlatformPolicyPpi, CpuSteppingId, HwStrap);
+ }
+ }
+
+ ///
+ /// PEG Sampler Calibration: 0 = Disabled (default), 1 = Enabled
+ ///
+ if (SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate == 2) {
+ SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate = 0;
+ }
+
+ if (SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate == 1) {
+ ///
+ /// Back up the current PEG speed in LCTL2.TLS[3:0]
+ ///
+ Peg10Speed = McD1PciCfg16 (R_SA_PEG_LCTL2_OFFSET) & 0x0F;
+ Peg11Speed = McD1F1PciCfg16 (R_SA_PEG_LCTL2_OFFSET) & 0x0F;
+ Peg12Speed = McD1F2PciCfg16 (R_SA_PEG_LCTL2_OFFSET) & 0x0F;
+ ///
+ /// Set the PEG speed in LCTL2.TLS[3:0] to Gen1 before clearing DEFER_OC,
+ /// in order to run Sampler Calibration at Gen1.
+ ///
+ McD1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, 1);
+ McD1F1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, 1);
+ McD1F2PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, 1);
+ }
+
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ ///
+ /// Program the PEG speed according to Setup options: Auto/Gen1/2/3
+ /// We have to do it before endpoint enumeration, so that uncompliant card
+ /// can train at a lower speed.
+ ///
+ ConfigurePegGenX (
+ PeiServices,
+ StallPpi,
+ SaPlatformPolicyPpi,
+ PegPortTable,
+ PegComplete,
+ CpuSteppingId,
+ Gen3Capable
+ );
+ }
+
+ ///
+ /// RxCEM Loopback (LPBK) Mode
+ ///
+ if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) && (SaPlatformPolicyPpi->PcieConfig->RxCEMLoopback == 1)) {
+ McD1PciCfg32AndThenOr (R_SA_PEG_PEGTST_OFFSET, ~(BIT19|BIT18|BIT17|BIT16), (SaPlatformPolicyPpi->PcieConfig->RxCEMLoopbackLane & 0xF) << 16);
+ for (i = 0; i < SA_PEG_MAX_LANE; i++) {
+ if (i == SaPlatformPolicyPpi->PcieConfig->RxCEMLoopbackLane) {
+ McD1PciCfg32And (R_SA_PEG_AFELN0CFG0_OFFSET + LANE_STEP * i, ~BIT9);
+ } else {
+ McD1PciCfg32Or (R_SA_PEG_AFELN0CFG0_OFFSET + LANE_STEP * i, BIT9);
+ }
+ }
+ }
+
+ ///
+ /// Enable 3-OC retry for PEG(0/1/2). HSW/CRW earlier than C0.
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) {
+ McD1PciCfg32Or (R_SA_PEG_AFE_PWRON_OFFSET, BIT5);
+ McD1F1PciCfg32Or (R_SA_PEG_AFE_PWRON_OFFSET, BIT5);
+ McD1F2PciCfg32Or (R_SA_PEG_AFE_PWRON_OFFSET, BIT5);
+ }
+
+ ///
+ /// Bypass phase2
+ ///
+ Data32 = McD1PciCfg32 (R_SA_PEG_EQCFG_OFFSET);
+ Data32 |= BIT15 | BIT1;
+ McD1PciCfg32 (R_SA_PEG_EQCFG_OFFSET) = Data32;
+
+ ///
+ /// Clear DEFER_OC in offset 0xC24[16] on all PEG controllers to start the PEG training
+ ///
+ McD1PciCfg32And (R_SA_PEG_AFE_PWRON_OFFSET, ~BIT16);
+ McD1F1PciCfg32And (R_SA_PEG_AFE_PWRON_OFFSET, ~BIT16);
+ McD1F2PciCfg32And (R_SA_PEG_AFE_PWRON_OFFSET, ~BIT16);
+
+ ///
+ /// Delay for 100ms to meet the timing requirements of the PCI Express Base
+ /// Specification, Revision 1.0A, Section 6.6 ("...software must wait at least
+ /// 100 ms from the end of reset of one or more device before it is permitted
+ /// to issue Configuration Requests to those devices").
+ ///
+ GracefulLinkStatusStall (PeiServices, StallPpi, SaPlatformPolicyPpi, SaDataHob, HwStrap);
+
+ PegGen2AutoSpeedDisable (PeiServices,
+ SaPlatformPolicyPpi,
+ StallPpi,
+ SaDataHob,
+ &(PegPortTable[0]),
+ ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))),
+ HwStrap);
+
+ ///
+ /// Read the presence detect bit for each PEG port - must be done before sampler calibration
+ ///
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ PegBus = PegPortTable[PegComplete].Bus;
+ PegDev = PegPortTable[PegComplete].Device;
+ PegFunc = PegPortTable[PegComplete].Function;
+ if (( MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID ) != 0xFFFF) &&
+ ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_SLOTSTS_OFFSET) & BIT6) != 0)) {
+ PegPortTable[PegComplete].PresenceDetect = TRUE;
+
+ ///
+ /// Read the endpoint's Max Link Speed
+ ///
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF, 0x00010100);
+ MmPci16 (0, 1, 0, 0, PCI_VID) = 0;
+ CapOffset = PcieFindCapId (1, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP);
+ if (CapOffset != 0) {
+ Data32 = MmPci32 (0, 1, 0, 0, CapOffset + 0xC);
+ PegPortTable[PegComplete].EndpointMaxLinkSpeed = Data32 & 0xF;
+ if (PegPortTable[PegComplete].EndpointMaxLinkSpeed >= 0x3) {
+ AnyGen3Endpoint = TRUE;
+ }
+ }
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ }
+ }
+ DEBUG ((EFI_D_INFO, "Presence detect table...\n"));
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ DEBUG ((EFI_D_INFO, " PEG%d%d PresenceDetect: %x. EndpointMaxLinkSpeed: %x.\n",
+ PegPortTable[PegComplete].Device,
+ PegPortTable[PegComplete].Function,
+ PegPortTable[PegComplete].PresenceDetect,
+ PegPortTable[PegComplete].EndpointMaxLinkSpeed));
+ }
+
+ ///
+ /// If any Gen3 device, setup equalization values and retrain link
+ ///
+ if (AnyGen3Endpoint &&
+ (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswB0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwB0)))) {
+ ///
+ /// Program presets based upon endpoint fullswing value
+ ///
+ for (i = 0; i < SA_PEG_MAX_LANE; i++) {
+ switch (i) {
+ case 0:
+ GetLinkPartnerFullSwing (i, &FullSwing);
+ break;
+ case 8:
+ if (PegPortTable[1].PresenceDetect) {
+ GetLinkPartnerFullSwing (i, &FullSwing);
+ }
+ break;
+ case 12:
+ if (PegPortTable[2].PresenceDetect) {
+ GetLinkPartnerFullSwing (i, &FullSwing);
+ }
+ break;
+ default:
+ break;
+ }
+ GetCoefficientsFromPreset (SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[i], FullSwing, &PreCursor, &Cursor, &PostCursor);
+ SetPartnerTxCoefficients (i, &PreCursor, &Cursor, &PostCursor);
+ }
+
+ ///
+ /// Redo EQ
+ ///
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ if (PegPortTable[PegComplete].PresenceDetect) {
+ PegBus = PegPortTable[PegComplete].Bus;
+ PegDev = PegPortTable[PegComplete].Device;
+ PegFunc = PegPortTable[PegComplete].Function;
+ MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0); ///< DOEQ
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5); ///< Retrain link
+ }
+ }
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ if (PegPortTable[PegComplete].PresenceDetect) {
+ WaitForL0 (PeiServices, StallPpi, &(PegPortTable[PegComplete]), FALSE);
+ }
+ }
+ }
+
+ ///
+ /// Sampler Calibration
+ ///
+ if (SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate == 1) {
+ DEBUG ((EFI_D_INFO, "PEG SamplerCalibration...\n"));
+ PegSamplerCalibration (PeiServices, SaPlatformPolicyPpi, StallPpi, CpuSteppingId, HwStrap);
+
+ ///
+ /// Restore the PEG speed
+ ///
+ McD1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, Peg10Speed);
+ McD1F1PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, Peg11Speed);
+ McD1F2PciCfg16AndThenOr (R_SA_PEG_LCTL2_OFFSET, 0xFFF0, Peg12Speed);
+
+ ///
+ /// Delay 100ms to let endpoint train properly
+ ///
+ StallPpi->Stall (PeiServices, StallPpi, 100 * STALL_ONE_MILLI_SECOND);
+ }
+ ///
+ /// Gen3 Preset Search: 0 = Disabled, 1 = Enabled (default)
+ ///
+ if (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch == 2) {
+ SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch = 1;
+ }
+
+ if (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch == 1) {
+ PegGen3PresetSearch (PeiServices, SaPlatformPolicyPpi, StallPpi, SaDataHob);
+ }
+
+ ///
+ /// After last equalization, set PH3 bypass
+ ///
+ McD1PciCfg32Or (R_SA_PEG_EQCFG_OFFSET, BIT15 | BIT14);
+
+ ///
+ /// Scan PEG Ports for device population
+ ///
+ DEBUG ((EFI_D_INFO, "PEG Ports Scanning starts.\n"));
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+
+ PegBus = PegPortTable[PegComplete].Bus;
+ PegDev = PegPortTable[PegComplete].Device;
+ PegFunc = PegPortTable[PegComplete].Function;
+ PegIndex = PegPortTable[PegComplete].Index;
+
+ ///
+ /// Check for a card presence in the PEG slot, or if the PEG port exists.
+ ///
+ if ((MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID) == 0xFFFF) ||
+ (PegPortTable[PegComplete].PresenceDetect == FALSE)) {
+ if (SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg == 0) {
+ goto PegDisable;
+ }
+ } else {
+ if (SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg == 0) {
+ ///
+ /// Set PEG PortBus = 1 to Read Endpoint.
+ ///
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF, 0x00010100);
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ MmPci16 (0, 1, 0, 0, PCI_VID) = 0;
+
+ ///
+ /// Negotiation Done?
+ ///
+ if ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) != 0) {
+ goto PegDisable;
+ }
+
+ ///
+ /// Restore bus numbers on the PEG bridge.
+ ///
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+ }
+
+ if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_8) {
+ PwrDnUnusedBundlesSetupData = SaPlatformPolicyPpi->PcieConfig->PowerDownUnusedBundles[PegIndex];
+ } else {
+ PwrDnUnusedBundlesSetupData = 0xFF; ///< Forced to AUTO mode for calculating unused bundles to powerdown
+ }
+
+ if (PwrDnUnusedBundlesSetupData == 0xff) { ///< AUTO mode for calculating unused bundles to powerdown
+ ///
+ /// Read the controller's Max Link Width
+ ///
+ CtrlMaxLinkWidth = (UINT8) ((MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCAP_OFFSET) >> 4) & 0x3F);
+
+ ///
+ /// Read the endpoint's Max Link Width
+ ///
+
+ ///
+ /// Set PEG PortBus = 1 to Read Endpoint.
+ ///
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF, 0x00010100);
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ MmPci16 (0, 1, 0, 0, PCI_VID) = 0;
+
+ ///
+ /// Check if the device actually got mapped into config space,
+ /// if the device wasn't able to be mapped into config space then
+ /// it's possible that it's a test card or some other device that
+ /// does not support config space. In that case our only option is
+ /// to assume that the link trains to its max width and use that to
+ /// determine which bundles to power down
+ ///
+ if (MmPci32 (0, 1, 0, 0, PCI_VID) == 0xFFFFFFFF) {
+ EpMaxLinkWidth = (UINT8) ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET) & 0x3f0) >> 4);
+ DEBUG ((EFI_D_INFO,
+ "PEG%d%d - Endpoint not responding to PCI config space access, assuming negotiated width (X%d) is max width\n",
+ PegDev,
+ PegFunc,
+ EpMaxLinkWidth
+ ));
+ } else {
+ CapOffset = PcieFindCapId (1, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP);
+ if (CapOffset != 0) {
+ EpMaxLinkWidth = (UINT8) ((MmPci32 (0, 1, 0, 0, CapOffset + 0xC) >> 4) & 0x3F);
+ }
+ }
+
+ ///
+ /// Restore bus numbers on the PEG bridge.
+ ///
+ MmPci32And (0, PegBus, PegDev, PegFunc, PCI_PBUS, 0xFF0000FF);
+
+ if (CtrlMaxLinkWidth > EpMaxLinkWidth) {
+ UnusedLanes = CtrlMaxLinkWidth - EpMaxLinkWidth;
+ } else {
+ UnusedLanes = 0;
+ }
+
+ BndlPwrdnCount = (UnusedLanes / 2);
+
+ DEBUG ((EFI_D_INFO, "CtrlMLW[%d]. EpMLW[%d]. UnusedLanes[%d]. BndlPwrdnCount[%d].\n", CtrlMaxLinkWidth, EpMaxLinkWidth, UnusedLanes, BndlPwrdnCount));
+ } else if (PwrDnUnusedBundlesSetupData != 0) { ///< User selection mode: 1...8 unused bundles
+ BndlPwrdnCount = PwrDnUnusedBundlesSetupData;
+ DEBUG ((EFI_D_INFO, "BndlPwrdnCount[%d].\n", BndlPwrdnCount));
+ }
+
+ ///
+ /// PowerOff unused lanes for PEGs
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) {
+ if (PwrDnUnusedBundlesSetupData != 0) {
+ MaxBndlPwrdnCount = GetMaxBundles(PeiServices, PegFunc, HwStrap);
+ if (BndlPwrdnCount > MaxBndlPwrdnCount) {
+ BndlPwrdnCount = MaxBndlPwrdnCount;
+ DEBUG ((EFI_D_INFO+EFI_D_ERROR, "BndlPwrdnCount violation! Overriding BndlPwrdnCount! BndlPwrdnCount[%d].\n", BndlPwrdnCount));
+ }
+ PowerDownUnusedBundles(PeiServices, PegFunc, HwStrap, BndlPwrdnCount);
+ }
+ }
+
+ ///
+ /// Additional Programming Steps for PEGs
+ ///
+ DEBUG ((EFI_D_INFO, "Run AdditionalPegProgramSteps on PEG%x%x!\n", PegDev, PegFunc));
+ AdditionalPegProgramSteps (SaPlatformPolicyPpi, PegBus, PegDev, PegFunc);
+ }
+
+ if ((HwStrap == SA_PEG_x16_x0_x0) && (PegIndex == 0)) {
+ DisableFun1 = TRUE;
+ DisableFun2 = TRUE;
+ break;
+ }
+ if ((HwStrap == SA_PEG_x8_x8_x0) && (PegIndex == 1)) {
+ DisableFun2 = TRUE;
+ break;
+ }
+ if ((HwStrap == SA_PEG_x8_x4_x4) && (PegIndex == 2)) {
+ break;
+ }
+
+ continue;
+
+PegDisable:
+ ///
+ /// SA_PEG_x16_x0_x0 Mode: in this mode, PEG11 and PEG12 need to be Disabled by BIOS in this driver.
+ /// Only PEG10 needs to be checked (whether has a VGA device on it) and disabled if not.
+ ///
+ /// SA_PEG_x8_x8_x0 Mode: in this mode, PEG12 needs to be disabled, PEG10 and PEG11
+ /// need to be checked and disabled if no device installed.
+ ///
+ ///
+ /// SA_PEG_x8_x4_x4 Mode: in this mode, all PEG10, PEG11 and PEG12 devices
+ /// need to be checked and disabled if no device installed.
+ ///
+ if (HwStrap == SA_PEG_x16_x0_x0) {
+ DisableFun0 = TRUE;
+ DisableFun1 = TRUE;
+ DisableFun2 = TRUE;
+ break;
+ } else if (HwStrap == SA_PEG_x8_x8_x0) {
+ DisableFun2 = TRUE;
+ if (PegIndex == 0) {
+ DisableFun0 = TRUE;
+ } else {
+ DisableFun1 = TRUE;
+ break;
+ }
+ } else if (HwStrap == SA_PEG_x8_x4_x4) {
+ if (PegIndex == 0) {
+ DisableFun0 = TRUE;
+ } else if (PegIndex == 1) {
+ DisableFun1 = TRUE;
+ } else {
+ DisableFun2 = TRUE;
+ break;
+ }
+ }
+ } ///< End of the for Loop
+
+ if (!DisableFun1 || !DisableFun2) {
+ ///
+ /// PEG10 must be enabled if PEG11 and/or PEG12 are enabled
+ ///
+ if (DisableFun0) {
+ DisableLinkFunc0 = TRUE;
+ }
+
+ DisableFun0 = FALSE;
+ }
+
+ if (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_VID_OFFSET) != 0xFFFF) {
+ FunctionExists = TRUE;
+ } else {
+ FunctionExists = FALSE;
+ DEBUG ((EFI_D_WARN, "PEG10 Disabled.\n"));
+ }
+ if ((DisableFun0 || DisableLinkFunc0) && FunctionExists) {
+ ///
+ /// Set D1.F0.R 224h [8] = 1
+ ///
+ MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_LTSSMC_OFFSET, BIT8);
+
+ ///
+ /// DisableLink. Set D1.F0.R 0B0h [4] (LD (Link Disable) bit in Link Control Register
+ /// Set D1.F0.R D10h [0].
+ ///
+ MmPci8Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_LCTL_OFFSET, BIT4);
+
+ ///
+ /// Poll until D1.F0.R 464h [5:0] = 2
+ ///
+ LoopCount = 0;
+ while( ((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_REUT_PH1_PIS_OFFSET) & 0x3F) != 2)
+ && (LoopCount < SA_PEG_LINK_DISABLE_MAXWAIT)) {
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND*100); //100usec
+ LoopCount++;
+ }
+
+ ///
+ /// Program AFEOVR.RXSQDETOVR
+ /// PCIe link disable for Switchable GFx
+ /// Additional Power savings: Set 0:1:0 0xC20 BIT4 = 0 & BIT5 = 1
+ ///
+ MmPci8AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_AFEOVR_OFFSET, ~(BIT5 | BIT4), BIT5);
+
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) {
+ MaxBndlPwrdnCount = GetMaxBundles(PeiServices, 0, HwStrap);
+ PowerDownUnusedBundles(PeiServices, 0, HwStrap, MaxBndlPwrdnCount);
+ }
+
+ if (DisableFun0) {
+ ///
+ /// Set D1.F0.R D20h [30] to power off PEG lanes when no device is attached (prvtexdetq=1).
+ /// Clear D0.F0.R 054h (DEVEN) enable bit.
+ ///
+ MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_PEGCOMLCGCTRL_OFFSET, BIT30);
+ MmPci8And (0, SA_MC_BUS, 0, 0, R_SA_DEVEN, ~B_SA_DEVEN_D1F0EN_MASK);
+ DEBUG ((EFI_D_WARN, "PEG10 Disabled.\n"));
+ }
+ }
+
+ if (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_VID_OFFSET) != 0xFFFF) {
+ FunctionExists = TRUE;
+ } else {
+ FunctionExists = FALSE;
+ DEBUG ((EFI_D_WARN, "PEG11 Disabled.\n"));
+ }
+ if (DisableFun1 && FunctionExists) {
+ ///
+ /// Set D1.F1.R 224h [8] = 1
+ ///
+ MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_LTSSMC_OFFSET, BIT8);
+
+ ///
+ /// DisableLink. Set D1.F1.R 0B0h [4] (LD (Link Disable) bit in Link Control Register.
+ /// Set D1.F1.R D10h [0].
+ /// Set D1.F1.R D20h [30] to power off PEG lanes when no device is attached (prvtexdetq=1).
+ /// Clear B0,D0,F0 054h (DEVEN) enable bit.
+ ///
+ MmPci8Or (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_LCTL_OFFSET, BIT4);
+
+ ///
+ /// Poll until D1.F0.R 464h [13:8] = 2
+ ///
+ LoopCount = 0;
+ while( (((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_REUT_PH1_PIS_OFFSET) >> 8) & 0x3F) != 2)
+ && (LoopCount < SA_PEG_LINK_DISABLE_MAXWAIT)) {
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND*100); //100usec
+ LoopCount++;
+ }
+
+ ///
+ /// Program AFEOVR.RXSQDETOVR
+ /// PCIe link disable for Switchable GFx
+ /// Additional Power savings: Set 0:1:1 0xC20 BIT4 = 0 & BIT5 = 1
+ ///
+ MmPci8AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_AFEOVR_OFFSET, ~(BIT5 | BIT4), BIT5);
+
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) {
+ MaxBndlPwrdnCount = GetMaxBundles(PeiServices, 1, HwStrap);
+ PowerDownUnusedBundles(PeiServices, 1, HwStrap, MaxBndlPwrdnCount);
+ }
+
+ MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_PEGCOMLCGCTRL_OFFSET, BIT30);
+ MmPci8And (0, SA_MC_BUS, 0, 0, R_SA_DEVEN, ~B_SA_DEVEN_D1F1EN_MASK);
+ DEBUG ((EFI_D_WARN, "PEG11 Disabled.\n"));
+ }
+
+ if (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_VID_OFFSET) != 0xFFFF) {
+ FunctionExists = TRUE;
+ } else {
+ FunctionExists = FALSE;
+ DEBUG ((EFI_D_WARN, "PEG12 Disabled.\n"));
+ }
+ if (DisableFun2 && FunctionExists) {
+ ///
+ /// Set D1.F2.R 224h [8] = 1
+ ///
+ MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_LTSSMC_OFFSET, BIT8);
+
+ ///
+ /// DisableLink. Set D1.F2.R 0B0h [4] (LD (Link Disable) bit in Link Control Register.
+ /// Set D1.F2.R D10h [0].
+ /// Set D1.F2.R D20h [30] to power off PEG lanes when no device is attached (prvtexdetq=1).
+ /// Clear B0,D0,F0 054h (DEVEN) enable bit.
+ ///
+ MmPci8Or (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_LCTL_OFFSET, BIT4);
+
+ ///
+ /// Poll until D1.F0.R 464h [21:16] = 2
+ ///
+ LoopCount = 0;
+ while( (((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_REUT_PH1_PIS_OFFSET) >> 16) & 0x3F) != 2)
+ && (LoopCount < SA_PEG_LINK_DISABLE_MAXWAIT)) {
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND*100); //100usec
+ LoopCount++;
+ }
+
+ ///
+ /// Program AFEOVR.RXSQDETOVR
+ /// PCIe link disable for Switchable GFx
+ /// Additional Power savings: Set 0:1:2 0xC20 BIT4 = 0 & BIT5 = 1
+ ///
+ MmPci8AndThenOr (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_AFEOVR_OFFSET, ~(BIT5 | BIT4), BIT5);
+
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId >= EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId >= EnumCrwC0))) {
+ MaxBndlPwrdnCount = GetMaxBundles(PeiServices, 2, HwStrap);
+ PowerDownUnusedBundles(PeiServices, 2, HwStrap, MaxBndlPwrdnCount);
+ }
+
+ MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_PEGCOMLCGCTRL_OFFSET, BIT30);
+ MmPci8And (0, SA_MC_BUS, 0, 0, R_SA_DEVEN, ~B_SA_DEVEN_D1F2EN_MASK);
+ DEBUG ((EFI_D_WARN, "PEG12 Disabled.\n"));
+ }
+
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ PegBus = PegPortTable[PegComplete].Bus;
+ PegDev = PegPortTable[PegComplete].Device;
+ PegFunc = PegPortTable[PegComplete].Function;
+ WaitForVc0Negotiation(PeiServices, StallPpi, PegBus, PegDev, PegFunc);
+ ReportPcieLinkStatus(PegBus, PegDev, PegFunc);
+ }
+
+ ///
+ /// Re-check Link again and see if PegLinkFailMask in SaDataHob needed update
+ ///
+ if (SaDataHob != NULL) {
+ LinkStatusGood = 0;
+ if ((BIT1 & MmPci16(0, 0, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) {
+ LinkStatusGood |= BIT0;
+ }
+ if ((BIT1 & MmPci16(0, 0, SA_PEG10_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) {
+ LinkStatusGood |= BIT1;
+ }
+ if ((BIT1 & MmPci16(0, 0, SA_PEG10_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_VC0RSTS_OFFSET)) != BIT1) {
+ LinkStatusGood |= BIT2;
+ }
+ if (SaDataHob->PegData.PegLinkFailMask != (UINT8) (~LinkStatusGood)) {
+ DEBUG ((EFI_D_INFO, "Original PegLinkFailMask=%X, Final PegLinkFailMask=%X\n", SaDataHob->PegData.PegLinkFailMask, (UINT8) (~LinkStatusGood)));
+ SaDataHob->PegData.PegLinkFailMask = (UINT8) (~LinkStatusGood);
+ }
+ }
+
+ if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_11) &&
+ (SaPlatformPolicyPpi->PcieConfig->PegComplianceTestingMode == 1)) {
+ for (PegComplete = 0; PegComplete < ((sizeof (PegPortTable)) / (sizeof (PEG_PORT))); PegComplete++) {
+ PegBus = PegPortTable[PegComplete].Bus;
+ PegDev = PegPortTable[PegComplete].Device;
+ PegFunc = PegPortTable[PegComplete].Function;
+ MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_CFG5_OFFSET, BIT0);
+ }
+ }
+
+ ///
+ /// Maximize the dedicated credits for the PEG controllers
+ ///
+ MaximizeSharedCredits();
+ RebalancePegPerformanceCredits (DisableFun0, DisableFun1, DisableFun2);
+ return;
+}
+
+VOID
+ConfigurePegGenX (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEG_PORT *PegPortTable,
+ IN UINTN TableIndex,
+ IN UINT8 CpuSteppingId,
+ IN UINT8 Gen3Capable
+ )
+/**
+ Configure PEG GenX mode
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] PegPortTable - Pointer to PEG_PORT array
+ @param[in] TableIndex - Index in PEG_PORT array
+ @param[in] CpuSteppingId - CPU stepping
+ @param[in] Gen3Capable - Selected PEG_PORT is Gen3 capable
+
+ @retval None
+**/
+{
+ UINT8 PegPortGenx;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+ UINT8 PegIndex;
+ UINT8 MaxLinkWidth;
+ UINT16 LinkSpeed;
+
+ PegBus = PegPortTable[TableIndex].Bus;
+ PegDev = PegPortTable[TableIndex].Device;
+ PegFunc = PegPortTable[TableIndex].Function;
+ PegIndex = PegPortTable[TableIndex].Index;
+ MaxLinkWidth = PegPortTable[TableIndex].MaxLinkWidth;
+
+ ///
+ /// Check if this port exists
+ ///
+ if (MmPci16 (0, PegBus, PegDev, PegFunc, PCI_VID) == 0xFFFF) {
+ return;
+ }
+
+ ///
+ /// PegPortGenx: 0 = Auto, 1 = Gen1, 2 = Gen2, 3 = Gen3
+ ///
+ PegPortGenx = SaPlatformPolicyPpi->PcieConfig->PegGenx[PegIndex];
+
+ if (PegPortGenx == PEG_AUTO) {
+ DEBUG ((EFI_D_ERROR, "Auto\n"));
+ LinkSpeed = (UINT16)(MmPci32(0, PegBus, PegDev, PegFunc, R_SA_PEG_LCAP_OFFSET) & 0x0F);
+ } else {
+ LinkSpeed = SaPlatformPolicyPpi->PcieConfig->PegGenx[PegIndex];
+ DEBUG ((EFI_D_ERROR, "Speed From Setup %x\n", LinkSpeed));
+ }
+ ///
+ /// If Gen3 is fused off, limit is Gen2
+ ///
+ if (Gen3Capable == FALSE) {
+ if (LinkSpeed > 2) {
+ LinkSpeed = 2;
+ }
+ }
+ ///
+ /// Set the requested speed in Max Link Speed in LCAP[3:0] and Target Link Speed in LCTL2[3:0].
+ /// Update LCAP.MLW in the same write as it's a Write-Once field
+ ///
+ DEBUG ((EFI_D_INFO, "PEG%x%x (%x:%x:%x) - Max Link Speed = Gen%d\n", PegDev, PegFunc, PegBus, PegDev, PegFunc, LinkSpeed));
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCAP_OFFSET, 0xFFFFFC00, ((UINT32) MaxLinkWidth << 4) | LinkSpeed);
+ MmPci16AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL2_OFFSET, ~(0x0F), LinkSpeed);
+
+ return;
+}
+
+VOID
+AdditionalPegProgramSteps (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc
+ )
+/**
+ Additional PEG Programming Steps at PEI
+
+ @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] PegBus - Pci Bus Number
+ @param[in] PegDev - Pci Device Number
+ @param[in] PegFunc - Pci Func Number
+
+ @retval None
+**/
+{
+ UINT32 Data32And;
+ UINT32 Data32Or;
+
+
+ ///
+ /// Set L0SLAT[15:0] to 0x2020
+ ///
+ Data32And = (UINT32) ~(0xFFFF);
+ Data32Or = 0x00002020;
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_L0SLAT_OFFSET, Data32And, Data32Or);
+
+ ///
+ /// Disable PEG Debug Align Message - set 258[29] = '1b'
+ ///
+ Data32And = (UINT32) ~BIT29;
+ Data32Or = BIT29;
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_CFG4_OFFSET, Data32And, Data32Or);
+
+ ///
+ /// Retrain the link only if VC0 negotiation is complete at this point.
+ /// This is to support CLB card together with "Aways Enable PEG" option
+ ///
+ if ((MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) == 0) {
+ ///
+ /// Set LCTL.RL (0xb0 bit 5) to initiate link retrain
+ ///
+ MmPci8Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5);
+ ///
+ /// Wait for Link training complete
+ ///
+ while (MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET) & BIT11) {
+ };
+ }
+
+ return;
+}
+
+VOID
+MaximizeSharedCredits (
+ )
+/**
+ Maximize the dedicated credits for the PEG controllers
+**/
+{
+
+ UINT64 MchBar;
+ UINT32 Crdtctl0;
+ UINT32 Crdtctl1;
+ UINT32 Crdtctl2;
+ UINT32 Crdtctl3;
+ UINT8 Data8;
+ UINT8 Iotrk;
+ UINT8 Rrtrk;
+ BOOL CommitUpdates;
+ UINT8 i;
+
+ Iotrk = 40;
+ Rrtrk = 71;
+ CommitUpdates = FALSE;
+
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) & ~BIT0;
+ Crdtctl0 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL0_OFFSET);
+ Crdtctl1 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL1_OFFSET);
+ Crdtctl2 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL2_OFFSET);
+ Crdtctl3 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL3_OFFSET);
+
+ Data8 = 0;
+ for (i = 0; i < 24; i += 3) {
+ Data8 += (Crdtctl0 >> i) & 0x7;
+ Data8 += (Crdtctl1 >> i) & 0x7;
+ }
+ if (Data8 > Iotrk) {
+ DEBUG ((EFI_D_ERROR, "ERROR: Attempted to reserve > %d IOTRK (Attempt = %d)! Skipping programming.\n", Iotrk, Data8));
+ CommitUpdates = FALSE;
+ } else {
+ Iotrk -= Data8;
+ DEBUG ((EFI_D_INFO, "IOTRK: Reserved = %d. Shared = %d. Total = %d.\n", Data8, Iotrk, Data8 + Iotrk));
+ }
+
+ Data8 = 0;
+ for (i = 0; i < 24; i += 3) {
+ Data8 += (Crdtctl2 >> i) & 0x7;
+ }
+ Data8 += (Crdtctl2 >> 24) & 0x3F;
+ if (Data8 > Rrtrk) {
+ DEBUG ((EFI_D_ERROR, "ERROR: Attempted to reserve > %d RRTRK (Attempt = %d)! Skipping programming.\n", Rrtrk, Data8));
+ CommitUpdates = FALSE;
+ } else {
+ Rrtrk -= Data8;
+ DEBUG ((EFI_D_INFO, "RRTRK: Reserved = %d. Shared = %d. Total = %d.\n", Data8, Rrtrk, Data8 + Rrtrk));
+ }
+
+ if (CommitUpdates) {
+ Crdtctl3 = ((Rrtrk & 0x7F) << 6) | (Iotrk & 0x3F);
+ Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL3_OFFSET, (UINT32) ~(0x00001FFF), Crdtctl3);
+ }
+
+ return;
+}
+
+VOID
+RebalancePegPerformanceCredits (
+ IN BOOLEAN DisablePeg10,
+ IN BOOLEAN DisablePeg11,
+ IN BOOLEAN DisablePeg12
+ )
+/**
+ Rebalance Credits when PEG controllers so that no starvation occurs
+
+ @param[in] DisablePeg10 - Peg10 disable/enable status
+ @param[in] DisablePeg11 - Peg11 disable/enable status
+ @param[in] DisablePeg12 - Peg12 disable/enable status
+
+ @retval None
+**/
+{
+ UINT64 MchBar;
+ UINT32 Crdtctl4;
+ UINT32 Crdtctl6;
+ UINT32 Crdtctl8;
+ UINT16 PegLinkWidth10;
+ UINT16 PegLinkWidth11;
+ UINT16 PegLinkWidth12;
+
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) & ~BIT0;
+ Crdtctl4 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL4_OFFSET);
+ Crdtctl6 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL6_OFFSET);
+ Crdtctl8 = Mmio32 (MchBar, R_SA_MCHBAR_CRDTCTL8_OFFSET);
+
+ DEBUG ((EFI_D_INFO, "Crdtctl4 Crdtctl6 Crdtctl8 Before = %x %x %x\n", Crdtctl4, Crdtctl6, Crdtctl8));
+
+ PegLinkWidth10 = 0;
+ PegLinkWidth11 = 0;
+ PegLinkWidth12 = 0;
+
+ if (!DisablePeg10) {
+ PegLinkWidth10 = (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_LSTS_OFFSET) & 0x3F0) >> 4;
+ }
+ if (!DisablePeg11) {
+ PegLinkWidth11 = (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG11_DEV_NUM, SA_PEG11_FUN_NUM, R_SA_PEG_LSTS_OFFSET) & 0x3F0) >> 4;
+ }
+ if (!DisablePeg12) {
+ PegLinkWidth12 = (MmPci16 (0, SA_PEG_BUS_NUM, SA_PEG12_DEV_NUM, SA_PEG12_FUN_NUM, R_SA_PEG_LSTS_OFFSET) & 0x3F0) >> 4;
+ }
+
+ DEBUG ((EFI_D_INFO, "PEG10: LinkDisabled = %x. Width = %x\n", DisablePeg10, PegLinkWidth10));
+ DEBUG ((EFI_D_INFO, "PEG11: LinkDisabled = %x. Width = %x\n", DisablePeg11, PegLinkWidth11));
+ DEBUG ((EFI_D_INFO, "PEG12: LinkDisabled = %x. Width = %x\n", DisablePeg12, PegLinkWidth12));
+
+ ///
+ /// PEG10 = x8 and PEG11 = x8
+ ///
+ if (!DisablePeg10 && !DisablePeg11 && (PegLinkWidth10 == 8) && (PegLinkWidth11 == 8)) {
+ Crdtctl4 &= ~0x3E0;
+ Crdtctl4 |= (Crdtctl4 & 0x7C00) >> 5;
+ Crdtctl6 &= ~0x3E0;
+ Crdtctl6 |= (Crdtctl6 & 0x7C00) >> 5;
+ Crdtctl8 &= ~0xFC0;
+ Crdtctl8 |= (Crdtctl8 & 0x3F000) >> 6;
+ }
+
+ ///
+ /// PEG12 = x4
+ ///
+ if (!DisablePeg12 && (PegLinkWidth12 == 4)) {
+ ///
+ /// PEG10 = x4
+ ///
+ if (!DisablePeg10 && (PegLinkWidth10 == 4)) {
+ Crdtctl4 &= ~0x3E0;
+ Crdtctl4 |= (Crdtctl4 & 0xF8000) >> 10;
+ Crdtctl6 &= ~0x3E0;
+ Crdtctl6 |= (Crdtctl6 & 0xF8000) >> 10;
+ Crdtctl8 &= ~0xFC0;
+ Crdtctl8 |= (Crdtctl8 & 0xFC0000) >> 12;
+ }
+ ///
+ /// PEG11 = x4
+ ///
+ if (!DisablePeg11 && (PegLinkWidth11 == 4)) {
+ Crdtctl4 &= ~0x7C00;
+ Crdtctl4 |= (Crdtctl4 & 0xF8000) >> 5;
+ Crdtctl6 &= ~0x7C00;
+ Crdtctl6 |= (Crdtctl6 & 0xF8000) >> 5;
+ Crdtctl8 &= ~0x3F000;
+ Crdtctl8 |= (Crdtctl8 & 0xFC0000) >> 6;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "Crdtctl4 Crdtctl6 Crdtctl8 After = %x %x %x\n", Crdtctl4, Crdtctl6, Crdtctl8));
+
+ Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL4_OFFSET, (UINT32) ~0x01FFFFFF, Crdtctl4);
+ Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL6_OFFSET, (UINT32) ~0x01FFFFFF, Crdtctl6);
+ Mmio32AndThenOr (MchBar, R_SA_MCHBAR_CRDTCTL8_OFFSET, (UINT32) ~0x3FFFFFFF, Crdtctl8);
+
+ return;
+}
+
+VOID
+PegPreDetectionSteps (
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Additional PEG Programming Steps before PEG detection at PEI
+
+ @param[in] PegBus - Pci Bus Number
+ @param[in] PegDev - Pci Device Number
+ @param[in] PegFunc - Pci Func Number
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+**/
+{
+ UINT32 Data32;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 i;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuSteppingId = GetCpuStepping();
+ CpuFamilyId = GetCpuFamily();
+
+
+ Data32Or = (UINT32) (BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ Data32And = (UINT32) ~(BIT8);
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_LTSSMC_OFFSET, Data32And, Data32Or);
+
+ ///
+ /// Set PPCIE_CR_REUT_OVR_CTL_0_1_0_MMR.GRCLKGTDIS [28] to 1 (for PCIE Margin Test, Default is kept 0)
+ ///
+ if ((PegDev == 1) && (PegFunc == 0)) {
+ Data32And = (UINT32) ~BIT28;
+ Data32Or = 0;
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_REUT_OVR_CTL_OFFSET, Data32And, Data32Or);
+ }
+
+ if ((PegDev == 1) && (PegFunc == 0)) {
+ ///
+ /// DCBLNC = 0
+ ///
+ Data32And = (UINT32) ~(BIT3 | BIT2);
+ Data32Or = 0;
+ for (i = 0; i < SA_PEG_MAX_BUNDLE; i++) {
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_G3CTL0_OFFSET + i * BUNDLE_STEP, Data32And, Data32Or);
+ }
+ }
+
+ ///
+ /// DEBUP3[4] = 1
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) {
+ Data32And = (UINT32) ~(BIT4);
+ Data32Or = BIT4;
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_DEBUP3_OFFSET, Data32And, Data32Or);
+ }
+
+ ///
+ /// FCLKGTTLLL[2] = 1
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) {
+ Data32And = (UINT32) ~(BIT2);
+ Data32Or = BIT2;
+ MmPci32AndThenOr (0, PegBus, PegDev, PegFunc, R_SA_PEG_FCLKGTTLLL_OFFSET, Data32And, Data32Or);
+ }
+
+ ///
+ /// Program Read-Only Write-Once Registers
+ /// R 308h [31:0]
+ /// R 314h [31:0]
+ /// R 32Ch [31:0]
+ /// R 330h [31:0]
+ ///
+ Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0PRCA_OFFSET);
+ MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0PRCA_OFFSET) = Data32;
+ Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0NPRCA_OFFSET);
+ MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC0NPRCA_OFFSET) = Data32;
+ Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1PRCA_OFFSET);
+ MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1PRCA_OFFSET) = Data32;
+ Data32 = MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1NPRCA_OFFSET);
+ MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_VC1NPRCA_OFFSET) = Data32;
+
+ return;
+}
+#endif // PEG_FLAG
+
+#if defined(DMI_FLAG) || defined(PEG_FLAG)
+UINT32
+SendVcuApiSequence (
+ IN UINT32 MchBar,
+ IN UINT32 Address,
+ IN UINT16 OpCode,
+ IN UINT32 WriteData
+ )
+/**
+ Send one sequence to VCU MailBox
+
+ @param[in] MchBar - MCHBAR value
+ @param[in] Address - Target address
+ @param[in] OpCode - OpCode number
+ @param[in] WriteData - Data value (only used if OpCode is a write)
+**/
+{
+ BOOL IsWrite;
+ BOOL IsCsr;
+ UINT32 DataOpCode;
+ UINT32 SequenceId;
+ UINT32 VcuData;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ if ((OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV1) || (OpCode == V_SA_VCU_OPCODE_WRITE_MMIO_REV1)) {
+ IsWrite = TRUE;
+ } else {
+ IsWrite = FALSE;
+ }
+
+ if ((OpCode == V_SA_VCU_OPCODE_READ_CSR_REV1) || (OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV1)) {
+ IsCsr = TRUE;
+ } else {
+ IsCsr = FALSE;
+ }
+ } else {
+ if ((OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV2) || (OpCode == V_SA_VCU_OPCODE_WRITE_MMIO_REV2)) {
+ IsWrite = TRUE;
+ } else {
+ IsWrite = FALSE;
+ }
+
+ if ((OpCode == V_SA_VCU_OPCODE_READ_CSR_REV2) || (OpCode == V_SA_VCU_OPCODE_WRITE_CSR_REV2)) {
+ IsCsr = TRUE;
+ } else {
+ IsCsr = FALSE;
+ }
+ }
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ if (IsWrite) {
+ DataOpCode = V_SA_VCU_OPCODE_WRITE_DATA_REV1;
+ if (IsCsr) {
+ SequenceId = V_SA_VCU_SEQID_WRITE_CSR_REV1;
+ } else {
+ SequenceId = V_SA_VCU_SEQID_WRITE_MMIO_REV1;
+ }
+ } else {
+ DataOpCode = V_SA_VCU_OPCODE_READ_DATA_REV1;
+ if (IsCsr) {
+ SequenceId = V_SA_VCU_SEQID_READ_CSR_REV1;
+ } else {
+ SequenceId = V_SA_VCU_SEQID_READ_MMIO_REV1;
+ }
+ }
+ } else {
+ if (IsWrite) {
+ DataOpCode = V_SA_VCU_OPCODE_WRITE_DATA_REV2;
+ if (IsCsr) {
+ SequenceId = V_SA_VCU_SEQID_WRITE_CSR_REV2;
+ } else {
+ SequenceId = V_SA_VCU_SEQID_WRITE_MMIO_REV2;
+ }
+ } else {
+ DataOpCode = V_SA_VCU_OPCODE_READ_DATA_REV2;
+ if (IsCsr) {
+ SequenceId = V_SA_VCU_SEQID_READ_CSR_REV2;
+ } else {
+ SequenceId = V_SA_VCU_SEQID_READ_MMIO_REV2;
+ }
+ }
+ }
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV1, SequenceId);
+ } else {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV2, SequenceId);
+ }
+ SendVcuApiCmd (MchBar, OpCode, Address);
+ SendVcuApiCmd (MchBar, DataOpCode, WriteData);
+ VcuData = Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_DATA_OFFSET);
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV1, SequenceId);
+ } else {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV2, SequenceId);
+ }
+
+ return VcuData;
+}
+
+VOID
+SendVcuApiCmd (
+ IN UINT32 MchBar,
+ IN UINT32 Interface,
+ IN UINT32 Data
+ )
+/**
+ Send one command to VCU MailBox
+
+ @param[in] MchBar - MCHBAR value
+ @param[in] Interface - Interface number
+ @param[in] Data - Data value
+**/
+{
+ UINT32 ResponseCounter;
+ UINT16 ResponseCode;
+ UINT32 BusyCounter;
+ UINT32 RunBusy;
+ BOOL BusyStatus;
+
+ ResponseCode = V_SA_VCU_RESPONSE_SUCCESS;
+ for (ResponseCounter = 0; ResponseCounter < V_SA_VCU_RESPONSE_RETRY_LIMIT; ResponseCounter++) {
+ Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_DATA_OFFSET) = Data;
+ Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_INTERFACE_OFFSET) = (Interface | B_SA_MCHBAR_VCU_STATUS_RUN_BUSY);
+ BusyStatus = FALSE;
+ for (BusyCounter = 0; BusyCounter < V_SA_VCU_STATUS_BUSY_LIMIT; BusyCounter++) {
+ RunBusy = Mmio32 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_INTERFACE_OFFSET);
+ BusyStatus = (RunBusy & B_SA_MCHBAR_VCU_STATUS_RUN_BUSY) ? TRUE : FALSE;
+ if (BusyStatus == FALSE) {
+ break;
+ }
+ }
+
+ if (BusyStatus) {
+ DEBUG ((EFI_D_INFO, "VCU Busy Timeout after %d tries: MCHBAR=%8.8X. Interface=%8.8X. Data=%4.4X.\n", BusyCounter, MchBar, Interface, Data));
+ }
+ ResponseCode = Mmio16 (MchBar, R_SA_MCHBAR_VCU_MAILBOX_INTERFACE_OFFSET);
+ if (ResponseCode == V_SA_VCU_RESPONSE_SUCCESS) {
+ break;
+ }
+ }
+
+ if (ResponseCode != V_SA_VCU_RESPONSE_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "ERROR: VCU Response Error after %d tries: MCHBAR=%8.8X. Interface=%4.4X. Data=%8.8X. ResponseCode=%4.4X\n", ResponseCounter, MchBar, Interface, Data, ResponseCode));
+ }
+
+ return;
+}
+#endif // DMI_FLAG || PEG_FLAG
+
+#ifdef PEG_FLAG
+
+UINT8
+GetMaxBundles (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 PegFunc,
+ IN UINT8 HwStrap
+ )
+/**
+ GetMaxBundles: Get the maximum bundle numbers for the corresponding PEG
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] PegFunc - Points to PEG0/PEG1/PEG2/...
+ @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...]
+
+ @retval - MaxBndlPwrdnCount [Maximun number of bundles for this HW configuration]
+**/
+{
+ UINT8 MaxBndlPwrdnCount;
+
+ MaxBndlPwrdnCount = 0;
+
+ DEBUG ((EFI_D_INFO, "In GetMaxBundles procedure\n"));
+
+ if (PegFunc == 0) { // PEG10
+ if (HwStrap == SA_PEG_x16_x0_x0) {
+ MaxBndlPwrdnCount = 8;
+ } else {
+ MaxBndlPwrdnCount = 4;
+ }
+ } else if (PegFunc == 1) { // PEG11
+ if (HwStrap == SA_PEG_x8_x8_x0) {
+ MaxBndlPwrdnCount = 4;
+ } else if (HwStrap == SA_PEG_x8_x4_x4) {
+ MaxBndlPwrdnCount = 2;
+ }
+ } else if (PegFunc == 2) { // PEG12
+ if (HwStrap == SA_PEG_x8_x4_x4) {
+ MaxBndlPwrdnCount = 2;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "MaxBndlPwrdnCount = %d\n", MaxBndlPwrdnCount));
+ return MaxBndlPwrdnCount;
+}
+
+VOID
+PowerDownUnusedBundles (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 PegFunc,
+ IN UINT8 HwStrap,
+ IN UINT8 BndlPwrdnCount
+ )
+/**
+ PowerDownUnusedBundles: Program the PEG BundleSpare registers for power on sequence [PowerOff unused bundles for PEGs]
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] PegFunc - Points to PEG0/PEG1/PEG2/...
+ @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...]
+ @param[in] BndlPwrdnCount - Points to how many bundles are unused and should be powered down
+**/
+{
+ BOOLEAN PegLaneReversal;
+ UINT8 BndlPwrdnFirst;
+
+ UINT8 i;
+ UINT8 j;
+
+ PegLaneReversal = FALSE;
+ BndlPwrdnFirst = 0;
+
+ DEBUG ((EFI_D_INFO, "In PowerDownUnusedBundles sequence\n"));
+
+ if (BndlPwrdnCount == 0) {
+ ///
+ /// If all lanes are used. Do nothing
+ ///
+ DEBUG ((EFI_D_INFO, "All lanes are used. Do nothing.\n"));
+ return;
+ }
+
+ if ((MmPci32 (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_PEGTST_OFFSET) & BIT20) != 0) {
+ DEBUG ((EFI_D_INFO, "PegLaneReversal is true\n"));
+ PegLaneReversal = TRUE;
+ }
+
+ if (PegFunc == 0) { // PEG10
+ if (HwStrap == SA_PEG_x16_x0_x0) {
+ if (!PegLaneReversal) {
+ BndlPwrdnFirst = 8 - BndlPwrdnCount;
+ } else {
+ BndlPwrdnFirst = 0;
+ }
+ } else {
+ if (!PegLaneReversal) {
+ BndlPwrdnFirst = 4 - BndlPwrdnCount;
+ } else {
+ BndlPwrdnFirst = 4;
+ }
+ }
+ } else if (PegFunc == 1) { // PEG11
+ if (HwStrap == SA_PEG_x8_x8_x0) {
+ if (!PegLaneReversal) {
+ BndlPwrdnFirst = 8 - BndlPwrdnCount;
+ } else {
+ BndlPwrdnFirst = 0;
+ }
+ } else if (HwStrap == SA_PEG_x8_x4_x4) {
+ if (!PegLaneReversal) {
+ BndlPwrdnFirst = 6 - BndlPwrdnCount;
+ } else {
+ BndlPwrdnFirst = 2;
+ }
+ }
+ } else if (PegFunc == 2) { // PEG12
+ if (HwStrap == SA_PEG_x8_x4_x4) {
+ if (!PegLaneReversal) {
+ BndlPwrdnFirst = 8 - BndlPwrdnCount;
+ } else {
+ BndlPwrdnFirst = 0;
+ }
+ }
+ }
+
+ ///
+ /// Power down unused lanes per request
+ ///
+ DEBUG ((EFI_D_INFO, "BNDL_PWRDN PEG%d%d[%d:%d]\n", 0, PegFunc, BndlPwrdnFirst, (BndlPwrdnFirst+BndlPwrdnCount-1)));
+ for (i = BndlPwrdnFirst, j=1; j <= BndlPwrdnCount; i++, j++) {
+ MmPci32Or (0, SA_PEG_BUS_NUM, SA_PEG10_DEV_NUM, SA_PEG10_FUN_NUM, R_SA_PEG_BND0SPARE_OFFSET + (i * BUNDLE_STEP), BIT31);
+ }
+
+ return;
+}
+#endif // PEG_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.h
new file mode 100644
index 0000000..2ca1bbe
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PciExpressInit.h
@@ -0,0 +1,452 @@
+/** @file
+ PciExpressInit header file
+
+@copyright
+ Copyright (c) 1999 - 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
+
+**/
+#ifndef _PCIEXPRESS_INIT_H_
+#define _PCIEXPRESS_INIT_H_
+
+#include "EdkIIGluePeim.h"
+#include "SaAccess.h"
+#include "PchAccess.h"
+#include "EdkIIGluePcdPciExpressLib.h"
+#include "EdkIIGlueConfig.h"
+#include "Pci30.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+
+///
+/// Driver Consumed PPI Prototypes
+///
+#include EFI_PPI_DEPENDENCY (Stall)
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+
+#define PEG_AUTO 0
+#define PEG_GEN1 1
+#define PEG_GEN2 2
+#define PEG_GEN3 3
+
+#define DMI_GEN1 1
+#define DMI_GEN2 2
+
+#define LANE_STEP 0x10
+#define BUNDLE_STEP 0x20
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 Index;
+ BOOLEAN PresenceDetect;
+ UINT8 MaxLinkWidth;
+ UINT8 EndpointMaxLinkSpeed;
+} PEG_PORT;
+
+///
+/// Data structure used in Sampler Calibration
+///
+#pragma pack(1)
+typedef struct _SAMPLE {
+ UINT8 Data;
+ UINT16 Count;
+} DATA_SAMPLE;
+#pragma pack()
+
+#define MAX_CODES 10
+
+///
+/// Data structure used in Preset Search
+///
+typedef struct _PRESET_DATA {
+ UINT8 Preset;
+ UINTN TimingMargin[SA_PEG_MAX_BUNDLE];
+ UINTN VoltageUpMargin[SA_PEG_MAX_BUNDLE];
+ UINTN VoltageDownMargin[SA_PEG_MAX_BUNDLE];
+} PRESET_DATA;
+
+#define MAX_PRESETS 3
+
+#define SA_PEG_SAMPLER_ITERATIONS 500
+///
+/// Common register access macros - use either DMIBAR or PEG10
+///
+#define SaMmio32AndThenOr(BaseAddr, Device, Register, AndData, OrData) \
+ if (BaseAddr != 0) { \
+ Mmio32AndThenOr (BaseAddr, Register, AndData, OrData); \
+ } else { \
+ MmPci32AndThenOr (0, 0, Device, 0, Register, AndData, OrData); \
+ }
+
+#ifdef PEG_FLAG
+VOID
+BubbleSort (
+ IN OUT DATA_SAMPLE Array[]
+ )
+/**
+ Bubble sort from DATA_SAMPLE
+
+ @param[in, out] - Array[]: array of DATA_SAMPLE
+
+ @retval None
+**/
+;
+
+UINT32
+GetMiddleValue (
+ IN OUT DATA_SAMPLE Array[]
+ )
+/**
+ Get Middle Value from DATA_SAMPLE
+
+ @param[in, out] - Array[]: array of DATA_SAMPLE
+
+ @retval UINT32 : Middle Value of DATA_SAMPLE
+**/
+;
+
+VOID
+SetLoadBus (
+ IN UINT32 DmiBar,
+ IN UINTN Dev,
+ IN UINTN Lane,
+ IN UINT32 LoadSel,
+ IN UINT32 LoadData,
+ IN UINT8 CpuSteppingId
+ )
+/**
+ Set Load Bus
+
+ @param[in] DmiBar - DMIBAR address
+ @param[in] Dev - Device Number
+ @param[in] Lane - Number of Lane
+ @param[in] LoadSel - Load selection value
+ @param[in] LoadData - Load Data
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+
+ @retval None
+**/
+;
+
+UINT32
+GetMonBus (
+ IN UINT32 DmiBar,
+ IN UINTN Dev,
+ IN UINTN Lane,
+ IN UINT32 LoadSel,
+ IN UINT8 CpuSteppingId
+ )
+/**
+ Get monitor bus from the lane selected
+
+ @param[in] DmiBar - DMIBAR address
+ @param[in] Dev - Device number
+ @param[in] Lane - Number of Lane
+ @param[in] LoadSel - Load selection value
+ @param[in] LoadData - Load selecttion data
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+
+ @retval UINT32 - Load bus address
+**/
+;
+
+VOID
+DumpSamplerValues (
+ IN UINT32 DmiBar,
+ IN UINT8 CpuSteppingId,
+ IN UINTN Dev,
+ IN UINTN LanesCount
+ )
+/**
+ Dump Sampler Values
+
+ @param[in] DmiBar - DMIBAR address
+ @param[in] CpuSteppingId - CPUID.1.EAX[3:0], CPU stepping ID
+ @param[in] Dev - Device number
+ @param[in] LanesCount - Value of Lanes
+
+ @retval None
+**/
+;
+#endif // PEG_FLAG
+
+#if defined(DMI_FLAG) || defined(PEG_FLAG)
+VOID
+PegDmiRecipe (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT32 MchBar,
+ IN UINT32 DmiBar,
+ IN UINTN Dev,
+ IN UINT8 SwingControl
+ )
+/**
+ Perform PEG/DMI PCIe Recipe steps
+
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] MchBar - MCHBAR or zero if called for PEG
+ @param[in] DmiBar - DMIBAR or zero if called for PEG
+ @param[in] Dev - PEG device number: 1 for PEG10, 0 if called for DMI.
+ @param[in] SwingControl - 1 = Half, 2 = Full
+
+ @retval None
+**/
+;
+#endif // DMI_FLAG || PEG_FLAG
+
+#ifdef PEG_FLAG
+VOID
+ConfigurePegGenX (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEG_PORT *PegPortTable,
+ IN UINTN TableIndex,
+ IN UINT8 CpuSteppingId,
+ IN UINT8 Gen3Capable
+ )
+/**
+ Configure PEG GenX mode
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] PegPortTable - Pointer to PEG_PORT array
+ @param[in] TableIndex - Index in PEG_PORT array
+ @param[in] CpuSteppingId - CPU stepping
+ @param[in] Gen3Capable - Selected PEG_PORT is Gen3 capable
+
+ @retval None
+**/
+;
+
+VOID
+AdditionalPegProgramSteps (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc
+ )
+/**
+ Additional PEG Programming Steps at PEI
+
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+ @param[in] PegBus - Pci Bus Number
+ @param[in] PegDev - Pci Device Number
+ @param[in] PegFunc - Pci Func Number
+**/
+;
+
+VOID
+MaximizeSharedCredits (
+ )
+/**
+ Maximize the dedicated credits for the PEG controllers
+**/
+;
+
+VOID
+RebalancePegPerformanceCredits (
+ IN BOOLEAN DisablePeg10,
+ IN BOOLEAN DisablePeg11,
+ IN BOOLEAN DisablePeg12
+ )
+/**
+ Rebalance Credits when PEG controllers so that no stavation occurs
+
+ @param[in] DisablePeg10 - Peg10 disable/enable status
+ @param[in] DisablePeg11 - Peg11 disable/enable status
+ @param[in] DisablePeg12 - Peg12 disable/enable status
+
+ @retval None
+**/
+;
+
+VOID
+PegPreDetectionSteps (
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Additional PEG Programming Steps before PEG detection at PEI
+
+ @param[in] PegBus - Pci Bus Number
+ @param[in] PegDev - Pci Device Number
+ @param[in] PegFunc - Pci Func Number
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+**/
+;
+#endif // PEG_FLAG
+
+#if defined(DMI_FLAG) || defined(PEG_FLAG)
+UINT32
+SendVcuApiSequence (
+ IN UINT32 MchBar,
+ IN UINT32 Address,
+ IN UINT16 OpCode,
+ IN UINT32 WriteData
+ )
+/**
+ Send one sequence to VCU MailBox
+
+ @param[in] MchBar - MCHBAR value
+ @param[in] Address - Target address
+ @param[in] OpCode - OpCode number
+ @param[in] WriteData - Data value (only used if OpCode is a write)
+**/
+;
+
+VOID
+SendVcuApiCmd (
+ IN UINT32 MchBar,
+ IN UINT32 Interface,
+ IN UINT32 Data
+ )
+/**
+ Send one command to VCU MailBox
+
+ @param[in] MchBar - MCHBAR value
+ @param[in] Interface - Interface number
+ @param[in] Data - Data value
+**/
+;
+
+VOID
+ReportPcieLinkStatus (
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc
+)
+/**
+ This function reports a PEG controller's link status
+
+ @param[in] PegBus - Peg Bus
+ @param[in] PegDev - Peg Device
+ @param[in] PegFunc - Peg Function
+
+ @retval None
+**/
+;
+
+VOID
+WaitForVc0Negotiation (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT8 PegBus,
+ IN UINT8 PegDev,
+ IN UINT8 PegFunc
+)
+/**
+ This function prints the time required for VC0 Negotiation Pending to be cleared. Quits after 100 msec.
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] PegBus - Peg Bus
+ @param[in] PegDev - Peg Device
+ @param[in] PegFunc - Peg Function
+
+ @retval None
+**/
+;
+
+UINT32
+PcieFindCapId (
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 PegFunc,
+ IN UINT8 CapId
+ )
+/**
+ Find the Offset to a given Capabilities ID
+ CAPID list:
+ 0x01 = PCI Power Management Interface
+ 0x04 = Slot Identification
+ 0x05 = MSI Capability
+ 0x10 = PCI Express Capability
+
+ @param[in] Bus - Pci Bus Number
+ @param[in] Device - Pci Device Number
+ @param[in] PegFunc - Pci Function Number
+ @param[in] CapId - CAPID to search for
+
+ @retval 0 - CAPID not found
+ @retval Other - CAPID found, Offset of desired CAPID
+**/
+;
+
+VOID
+ProgramPreset (
+ IN UINT8 Direction,
+ IN UINT8 PresetValue,
+ IN UINT8 PegFunc,
+ IN UINT8 Lane
+ )
+/**
+ Program PEG Gen3 preset value
+
+ @param[in] Direction - 0 = Root Port, 1 = End Point
+ @param[in] PresetValue - Preset value to program
+ @param[in] PegFunc - Peg function number to be configured
+ @param[in] Lane - Lane to be configured
+
+ @retval None
+**/
+;
+
+#endif // DMI_FLAG || PEG_FLAG
+
+#ifdef PEG_FLAG
+UINT8
+GetMaxBundles (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 PegFunc,
+ IN UINT8 HwStrap
+ )
+/**
+ GetMaxBundles: Get the maximum bundle numbers for the corresponding PEG
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] PegFunc - Points to PEG0/PEG1/PEG2/...
+ @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...]
+
+ @retval - MaxBndlPwrdnCount [Maximun number of bundles for this HW configuration]
+**/
+;
+
+VOID
+PowerDownUnusedBundles (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 PegFunc,
+ IN UINT8 HwStrap,
+ IN UINT8 BndlPwrdnCount
+ )
+/**
+ PowerDownUnusedBundles: Program the PEG BundleSpare registers for power on sequence [PowerOff unused bundles for PEGs]
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] PegFunc - Points to PEG0/PEG1/PEG2/...
+ @param[in] HwStrap - Points to PEG configuration information [x16_x0_x0/x8_x8_x0/x8_x4_x4/...]
+ @param[in] BndlPwrdnCount - Points to how many bundles are unused and should be powered down
+
+ @retval - None
+**/
+;
+#endif // PEG_FLAG
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.c
new file mode 100644
index 0000000..26f16be
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.c
@@ -0,0 +1,628 @@
+/** @file
+ This driver trains the PEG interface.
+
+@copyright
+ Copyright (c) 2012 - 2013 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 "PcieTraining.h"
+
+#ifdef PEG_FLAG
+
+UINT16
+GetErrorTarget (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ UINT16 ErrorTarget;
+
+ if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) &&
+ (SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchErrorTarget >= 1)) {
+ ErrorTarget = SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchErrorTarget;
+ } else {
+ ErrorTarget = 4;
+ }
+
+ return ErrorTarget;
+}
+
+VOID
+GetPortInfo (
+ OUT PORT_INFO *PortInfoList,
+ OUT UINT8 *PortInfoListLength,
+ OUT BOOLEAN *SkipBundle0
+ )
+{
+ UINT32 HwStrap;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PcieController;
+ UINT8 Index;
+ UINT8 Lane;
+ UINT8 LaneIndex;
+ UINT8 FurcationSetup[SA_PEG_MAX_FUN];
+ UINT8 PcieControllerList[SA_PEG_MAX_FUN];
+ UINT8 NumberToCheck;
+ UINT8 StartLane;
+ UINT8 Width;
+ UINT32 Lcap;
+ UINT32 CapOffset;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+
+ PegBus = SA_MC_BUS;
+ PegDev = 1;
+ HwStrap = (McD1PciCfg32(R_SA_PEG_FUSESCMN_OFFSET) >> 16) & 0x3;
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ switch(HwStrap) {
+ case SA_PEG_x8_x4_x4:
+ FurcationSetup[0] = 8;
+ FurcationSetup[1] = 4;
+ FurcationSetup[2] = 4;
+ NumberToCheck = 3;
+ break;
+ case SA_PEG_x8_x8_x0:
+ FurcationSetup[0] = 8;
+ FurcationSetup[1] = 8;
+ NumberToCheck = 2;
+ break;
+ default:
+ case SA_PEG_x16_x0_x0:
+ FurcationSetup[0] = 16;
+ NumberToCheck = 1;
+ break;
+ }
+
+ ///
+ /// Figure out which PcieControllers are enabled
+ ///
+ (*PortInfoListLength) = 0;
+ for (PcieController = 0; PcieController < NumberToCheck; PcieController++) {
+ ///
+ /// Sanity check to make sure width > 0
+ ///
+ if (FurcationSetup[PcieController] == 0) {
+ continue;
+ }
+
+ ///
+ /// Check to make sure the Root Port Exists
+ ///
+ if (MmPci16 (0, PegBus, PegDev, PcieController, PCI_VID) == 0xFFFF) {
+ continue;
+ }
+
+ ///
+ /// Add the PcieController to the list of enabled controllers
+ ///
+ PcieControllerList[(*PortInfoListLength)] = PcieController;
+ (*PortInfoListLength)++;
+ }
+
+ ///
+ /// If needed, skip Bundle 0's preset search and use Bundle 1's preset instead.
+ ///
+ (*SkipBundle0) = FALSE;
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) {
+ (*SkipBundle0) = TRUE;
+ }
+ if ((*SkipBundle0)) {
+ DEBUG ((EFI_D_INFO, "Skipping each controller's Lane 0-1 preset searches; using their Lane 2 preset instead.\n"));
+ }
+
+ StartLane = 0;
+ for (Index = 0; Index < (*PortInfoListLength); Index++) {
+ PcieController = PcieControllerList[Index];
+
+ ///
+ /// Get information for the current port
+ ///
+ (PortInfoList[Index]).EnableMargin = TRUE;
+ (PortInfoList[Index]).FoundUsablePreset = FALSE;
+ (PortInfoList[Index]).PegPort.Bus = PegBus;
+ (PortInfoList[Index]).PegPort.Device = PegDev;
+ (PortInfoList[Index]).PegPort.Function = PcieController;
+ (PortInfoList[Index]).PegPort.Index = PcieController;
+ (PortInfoList[Index]).PegPort.EndpointMaxLinkSpeed = 0;
+ ReportPcieLinkStatus (PegBus, PegDev, PcieController);
+ Width = GetNegotiatedWidth(&((PortInfoList[Index]).PegPort));
+ (PortInfoList[Index]).LaneListLength = Width;
+ for (Lane = 0, LaneIndex = 0; Lane < Width; Lane++) {
+ if ((*SkipBundle0)) {
+ if ((Lane == 0) || (Lane == 1)) {
+ (PortInfoList[Index]).LaneListLength--;
+ continue;
+ }
+ }
+ if (LaneIndex < SA_PEG_MAX_LANE) {
+ (PortInfoList[Index]).LaneList[LaneIndex] = (Lane + StartLane);
+ }
+ LaneIndex++;
+ }
+
+ ///
+ /// Check that both root port and endpoint support Gen3
+ ///
+ Lcap = MmPci32 (0, PegBus, PegDev, PcieController, R_SA_PEG_LCAP_OFFSET);
+ if ((Lcap & 0x0F) != 3) {
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Root Port is not Gen3-capable. Max Link Speed = %d.\n",
+ PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F));
+ (PortInfoList[Index]).LinkIsGen3Capable = FALSE;
+ } else {
+
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Root Port is Gen3-capable.\n",
+ PegDev, PcieController, PegBus, PegDev, PcieController));
+
+ ///
+ /// Set PEG PortBus = 1 to Read Endpoint.
+ ///
+ MmPci32AndThenOr (0, PegBus, PegDev, PcieController, PCI_PBUS, 0xFF0000FF, 0x00010100);
+
+ ///
+ /// A config write is required in order for the device to re-capture the Bus number,
+ /// according to PCI Express Base Specification, 2.2.6.2
+ /// Write to a read-only register VendorID to not cause any side effects.
+ ///
+ MmPci16 (0, 1, 0, 0, PCI_VID) = 0;
+
+ ///
+ /// Save end point vendor id and device id
+ ///
+ (PortInfoList[Index]).EndPointVendorIdDeviceId = MmPci32 (0, 1, 0, 0, 0);
+
+ ///
+ /// Negotiation Done?
+ ///
+ if ((MmPci16 (0, PegBus, PegDev, PcieController, R_SA_PEG_VC0RSTS_OFFSET) & BIT1) != 0) {
+ (PortInfoList[Index]).LinkIsGen3Capable = FALSE;
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - VC0 negotiation is pending! Skipping endpoint.\n",
+ PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F));
+ ReportPcieLinkStatus (PegBus, PegDev, PcieController);
+ } else {
+ ///
+ /// Get the pointer to the Port PCI Express Capability Structure.
+ ///
+ CapOffset = PcieFindCapId (1, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP);
+ if (CapOffset == 0) {
+ (PortInfoList[Index]).LinkIsGen3Capable = FALSE;
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Endpoint is not Gen3-capable. No PCIe Capability found.\n",
+ PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F));
+ } else {
+ Lcap = MmPci32 (0, 1, 0, 0, CapOffset + 0x0C);
+ (PortInfoList[Index]).PegPort.EndpointMaxLinkSpeed = Lcap & 0x0F;
+ if ((Lcap & 0x0F) < 3) {
+ (PortInfoList[Index]).LinkIsGen3Capable = FALSE;
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Endpoint is not Gen3-capable. Max Link Speed = %d.\n",
+ PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F));
+ } else {
+ (PortInfoList[Index]).LinkIsGen3Capable = TRUE;
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - Endpoint is Gen3-capable\n",
+ PegDev, PcieController, PegBus, PegDev, PcieController, Lcap & 0x0F));
+ }
+ }
+ }
+ ///
+ /// Restore bus numbers on the PEG bridge.
+ ///
+ MmPci32And (0, PegBus, PegDev, PcieController, PCI_PBUS, 0xFF0000FF);
+ }
+
+ StartLane += FurcationSetup[PcieController];
+ } ///< End of for each port
+
+ return;
+}
+
+EFI_STATUS
+RunMarginTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT32 MonitorPort,
+ IN PORT_INFO *PortInfoList,
+ IN UINT8 PortInfoListLength,
+ IN MARGIN_TEST_TYPE MarginTest,
+ OUT INT32 *Margins
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *LaneList;
+ UINT8 Lane;
+ UINT8 PortListIndex;
+ UINT8 OriginalSpeed;
+ UINT8 OriginalWidth;
+ UINT8 LaneListLength;
+ PEG_PORT *PegPort;
+
+ Status = EFI_SUCCESS;
+
+ ///
+ /// Initialize Margins to -1. Since -1 is an invalid value, we know that lane wasn't tested if its margin == -1
+ ///
+ for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) {
+ Margins[Lane] = -1;
+ }
+
+ for (PortListIndex = 0; PortListIndex < PortInfoListLength; PortListIndex++) {
+ ///
+ /// Test all lanes associated with this the current port
+ ///
+ LaneList = &((PortInfoList[PortListIndex]).LaneList[0]);
+ LaneListLength = (PortInfoList[PortListIndex]).LaneListLength;
+ PegPort = &((PortInfoList[PortListIndex]).PegPort);
+ if ((PortInfoList[PortListIndex]).EnableMargin == FALSE ||
+ (PortInfoList[PortListIndex]).SkipMargin == TRUE) {
+ continue;
+ }
+
+ if ((PortInfoList[PortListIndex]).LinkIsGen3Capable) {
+ OriginalSpeed = 3;
+ } else {
+ OriginalSpeed = GetLinkSpeed (PegPort);
+ }
+ OriginalWidth = GetNegotiatedWidth (PegPort);
+
+ switch (MarginTest) {
+ case LaneLevelRxJitter:
+ Status = LaneLevelJitterTest (
+ PeiServices,
+ SaPlatformPolicyPpi,
+ SaDataHob,
+ StallPpi,
+ MonitorPort,
+ LaneList,
+ LaneListLength,
+ PegPort,
+ OriginalSpeed,
+ OriginalWidth,
+ FALSE,
+ Margins
+ );
+ break;
+ default:
+ DEBUG ((EFI_D_WARN, "Invalid Margin Test Requested.\n"));
+ break;
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+LaneLevelJitterTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT32 MonitorPort,
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth,
+ IN BOOLEAN TxJitterTest,
+ OUT INT32 *Margins
+ )
+{
+ EFI_STATUS Status;
+ UINT8 LaneListIndex;
+ INT8 Jitter;
+ UINT32 Errors;
+ UINT32 PreviousErrors;
+ UINT8 Lane;
+ UINT32 RecoveryCount;
+ BOOLEAN AbortMargin;
+ UINT16 ErrorTarget;
+ UINT8 ConvergenceCounter;
+ INT32 LastMargin;
+ INT32 MarginDifference;
+ INT32 StartJitter;
+ INT8 MarginDirection;
+ UINT8 RepeatCount;
+
+ ErrorTarget = GetErrorTarget (SaPlatformPolicyPpi);
+
+ for (LaneListIndex = 0; LaneListIndex < LaneListLength; LaneListIndex++) {
+ Lane = LaneList[LaneListIndex];
+ Errors = 0;
+ AbortMargin = FALSE;
+ Margins[Lane] = 0;
+ MarginDirection = 1;
+
+ if (TxJitterTest) {
+ ConfigureTxJitterMux (Lane, SaPlatformPolicyPpi->PlatformData->MchBar);
+ EnableTxJitterInjection (Lane, TRUE);
+ }
+
+ ///
+ /// Determine value to start at
+ ///
+ if (LaneListIndex == 0) {
+ StartJitter = 0;
+ } else {
+ StartJitter = (Margins[LaneList[LaneListIndex - 1]] / 100) - JITTER_MARGIN_INITIAL_OFFSET;
+ if (StartJitter < 0) {
+ StartJitter = 0;
+ }
+ }
+
+ ConvergenceCounter = 0;
+ LastMargin = -1;
+ RepeatCount = 0;
+ while (ConvergenceCounter < MARGIN_CONVERGANCE_MIN_MATCHES && RepeatCount < MARGIN_CONVERGANCE_MAX_REPEATS) {
+ RepeatCount++;
+ ///
+ /// Determine whether to go up or down from starting point
+ ///
+ AbortMargin = FALSE;
+ RecoveryCount = SaPcieGetErrorCount (MonitorPort, PegPort->Function);
+ Status = SetJitterTolerance (&Lane, 1, (UINT8) StartJitter);
+ ASSERT_EFI_ERROR (Status);
+
+ Errors = SaPciePointTest (PeiServices, SaPlatformPolicyPpi, StallPpi, MonitorPort, PegPort, RecoveryCount);
+ if (Errors >= ErrorTarget) {
+ if (StartJitter == 0) {
+ Margins[Lane] = 0;
+ AbortMargin = TRUE;
+ } else {
+ MarginDirection = -1;
+ }
+ } else {
+ MarginDirection = 1;
+ }
+ for (Jitter = (INT8) (StartJitter + MarginDirection);
+ Jitter < JITTER_LENGTH &&
+ Jitter >= 0 &&
+ (!AbortMargin);
+ Jitter = (INT8) (Jitter + MarginDirection)) {
+ ///
+ /// Check for a link downgrade
+ ///
+ AbortMargin = LinkIsDowngraded (PegPort, OriginalLinkSpeed, OriginalLinkWidth);
+ if (AbortMargin) {
+ if (MarginDirection < 0) {
+ LastMargin = -1;
+ ConvergenceCounter = 0;
+ StartJitter = 0;
+ MarginDirection = 1;
+ } else {
+ if (Jitter == 0) {
+ Margins[Lane] = 0;
+ } else {
+ Margins[Lane] = (Jitter - 1) * 100;
+ }
+ }
+ break;
+ }
+
+ ///
+ /// Get initial recovery count
+ ///
+ RecoveryCount = SaPcieGetErrorCount (MonitorPort, PegPort->Function);
+ Status = SetJitterTolerance (&Lane, 1, Jitter);
+ ASSERT_EFI_ERROR (Status);
+
+ PreviousErrors = Errors;
+ Errors = SaPciePointTest (PeiServices, SaPlatformPolicyPpi, StallPpi, MonitorPort, PegPort, RecoveryCount);
+ if (MarginDirection < 0) {
+ if (Errors < ErrorTarget) { ///< Downward direction has started passing
+ Margins[Lane] = InterpolateMargin (ErrorTarget, PreviousErrors, Errors, (INT32) Jitter);
+ break;
+ }
+ } else {
+ if (Errors >= ErrorTarget) { ///< Upward direction has started failing
+ Margins[Lane] = InterpolateMargin (ErrorTarget, Errors, PreviousErrors, (INT32) Jitter);
+ break;
+ }
+ }
+ } ///< End of for loop
+
+ ///
+ /// Check if we never reached the error target
+ ///
+ if (MarginDirection < 0) {
+ if ((Errors >= ErrorTarget) && (!AbortMargin)) {
+ Margins[Lane] = 0;
+ }
+ } else {
+ if ((Errors < ErrorTarget) && (!AbortMargin)) {
+ Margins[Lane] = JITTER_LENGTH * 100;
+ }
+ }
+
+ ///
+ /// Compute the next margin point to start at
+ ///
+ StartJitter = (Margins[Lane] / 100) - JITTER_MARGIN_INITIAL_OFFSET;
+ if (StartJitter < 0) {
+ StartJitter = 0;
+ }
+
+ ///
+ /// Check for convergance
+ ///
+ if (LastMargin == -1) {
+ LastMargin = Margins[Lane];
+ } else {
+ MarginDifference = CalculateMarginDifference (LastMargin, Margins[Lane]);
+ if (MarginDifference <= MARGIN_CONVERGANCE_ALLOWED_DELTA) {
+ ConvergenceCounter++;
+ } else {
+ ConvergenceCounter = 0;
+ }
+ LastMargin = Margins[Lane];
+ }
+
+ if (LinkIsDowngraded (PegPort, OriginalLinkSpeed, OriginalLinkWidth)) {
+ Status = SetJitterTolerance (&Lane, 1, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ ///
+ /// If the link degraded in any way, bring it back to functional state
+ ///
+ Status = EnsureLinkIsHealthy (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } ///< End of repeat while loop
+
+ ///
+ /// Remove Jitter in preparation for testing the next lane
+ ///
+ Status = SetJitterTolerance (&Lane, 1, 0);
+ ASSERT_EFI_ERROR (Status);
+ if (TxJitterTest) {
+ EnableTxJitterInjection (Lane, FALSE);
+ }
+ } ///< End of for each lane loop
+
+ return EFI_SUCCESS;
+}
+
+UINT32
+SaPciePointTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT32 MonitorPort,
+ IN PEG_PORT *PegPort,
+ IN UINT32 InitialRecoveryCount
+ )
+{
+ UINT32 Data32;
+
+ StallPpi->Stall (PeiServices, StallPpi, SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchDwellTime);
+ Data32 = SaPcieGetErrorCount (MonitorPort, PegPort->Function) - InitialRecoveryCount;
+
+ return Data32;
+}
+
+INT32
+CalculateMarginDifference (
+ IN INT32 Margin1,
+ IN INT32 Margin2
+ )
+{
+ if (Margin1 < Margin2) {
+ return Margin2 - Margin1;
+ } else {
+ return Margin1 - Margin2;
+ }
+}
+
+INT32
+InterpolateMargin (
+ IN UINT32 ErrorTarget,
+ IN UINT32 CurrentErrorCount,
+ IN UINT32 PreviousErrorCount,
+ IN INT32 FailingPoint
+ )
+{
+ UINT32 LnErrorTarget;
+ UINT32 LnCurrentErrorCount;
+ UINT32 LnPreviousErrorCount;
+ INT32 Margin;
+
+ if (ErrorTarget > 40000) {
+ ErrorTarget = 40000;
+ }
+ if (CurrentErrorCount > 40000) {
+ CurrentErrorCount = 40000;
+ }
+ if (PreviousErrorCount > 40000) {
+ PreviousErrorCount = 40000;
+ }
+
+ LnErrorTarget = NaturalLog (ErrorTarget * 100);
+ LnCurrentErrorCount = NaturalLog (CurrentErrorCount * 100);
+ LnPreviousErrorCount = NaturalLog (PreviousErrorCount * 100);
+
+ if (FailingPoint >= 0) {
+ if ((LnCurrentErrorCount - LnPreviousErrorCount) == 0) {
+ Margin = (FailingPoint - 1) * 100;
+ } else {
+ Margin = ((LnErrorTarget - LnPreviousErrorCount) * 100) /
+ (LnCurrentErrorCount - LnPreviousErrorCount) +
+ ((FailingPoint - 1) * 100);
+ }
+ if (Margin < 0) {
+ Margin = 0;
+ }
+ } else {
+ if ((LnCurrentErrorCount - LnPreviousErrorCount) == 0) {
+ Margin = (FailingPoint + 1) * 100;
+ } else {
+ Margin = ((FailingPoint + 1) * 100) -
+ ((LnErrorTarget - LnPreviousErrorCount) * 100) /
+ (LnCurrentErrorCount - LnPreviousErrorCount);
+ }
+ if (Margin > 0) {
+ Margin = 0;
+ }
+ }
+
+ return Margin;
+}
+
+
+UINT32
+NaturalLog (
+ IN UINT32 Input
+ )
+ /*++
+
+ Routine Description:
+
+ This function calculates the Natural Log of the Input parameter using integers
+
+ Arguments:
+
+ Input - 100 times a number to get the Natural log from.
+ - Max Input Number is 40,000 (without 100x)
+
+ Returns:
+
+ Output - 100 times the actual result. Accurate within +/- 2
+
+ --*/
+{
+ UINT32 Output;
+
+ ///
+ ///Special case - treat 0 recoveries as 1 recovery for interpolation purposes
+ ///
+ if (Input == 0) {
+ return 0;
+ }
+
+ Output = 0;
+ while (Input > 271) {
+ Input = (Input * 1000) / 2718;
+ Output += 100;
+ }
+
+ Output += ((-16 * Input * Input + 11578 * Input - 978860) / 10000);
+
+ return Output;
+}
+
+#endif // PEG_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.h
new file mode 100644
index 0000000..5c7ee57
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTraining.h
@@ -0,0 +1,425 @@
+/** @file
+ Header file for PcieTraining Initialization Driver.
+
+@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
+**/
+
+#ifndef _PCIETRAINING_H_
+#define _PCIETRAINING_H_
+
+#include "EdkIIGluePeim.h"
+#include "SaAccess.h"
+#include "PciExpressInit.h"
+
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+#include EFI_GUID_DEFINITION (SaDataHob)
+
+///
+/// Data structures
+///
+
+typedef struct {
+ PEG_PORT PegPort;
+ UINT32 EndPointVendorIdDeviceId;
+ BOOLEAN LinkIsGen3Capable;
+ UINT8 LaneList[SA_PEG_MAX_LANE];
+ UINT8 LaneListLength;
+ BOOLEAN EnableMargin;
+ BOOLEAN SkipMargin;
+ BOOLEAN FoundUsablePreset;
+} PORT_INFO;
+
+typedef struct {
+ INT8 Depth;
+ UINT8 Step;
+ UINT8 ReportedMargin;
+ UINT8 DoubleMargin;
+} JITTER_SETTING;
+
+typedef struct {
+ UINT8 Lane;
+ UINT32 InitialDs0Dac;
+ UINT32 InitialDs0Value;
+ INT32 Ds0MarginOffset;
+ UINT32 InitialDs1Dac;
+ UINT32 InitialDs1Value;
+ INT32 Ds1MarginOffset;
+ INT32 MaxUpMargin;
+ INT32 MaxDownMargin;
+} VOC_STATE;
+
+typedef enum {
+ LaneLevelRxJitter,
+ VocUp,
+ VocDown
+} MARGIN_TEST_TYPE;
+
+#define JITTER_LENGTH 25
+#define JITTER_MARGIN_INITIAL_OFFSET 1
+#define MARGIN_CONVERGANCE_ALLOWED_DELTA 100
+#define MARGIN_CONVERGANCE_MIN_MATCHES 2
+#define MARGIN_CONVERGANCE_MAX_REPEATS 30
+
+#define SA_PEI_MONITOR_OFFSET 0xFED85000
+
+///
+/// Register Definitions
+///
+#define B_SA_PEG_LTSSMC_WIDTH_MASK 0xFFFFFFE0
+
+#define R_SA_PEG_REUT_PH_CTR_OFFSET 0x444
+#define B_SA_PEG_REUT_PH_CTR_PHYRESET_MASK 0x1
+#define B_SA_PEG_REUT_PH_CTR_RESETMOD_MASK 0x2
+#define B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK 0x2000
+
+#define R_SA_PEG_REUT_PH1_PIS_OFFSET 0x464
+#define B_SA_PEG_REUT_PH1_PIS_ST_MASK 0x3F
+#define B_SA_PEG_REUT_PH1_PIS_ST_STEP 0x8
+
+#define B_SA_PEG_BCTRL_SRESET_MASK BIT6
+
+#define V_SA_VCU_OPCODE_SET_TXJITTER_MUX 0x3002
+#define V_SA_VCU_SEQID_SET_TXJITTER_MUX 0x00030003
+
+#define R_SA_VCU_REUT_PH_CTR_ADDRESS_REV1 0x04448808
+#define R_SA_VCU_REUT_PH_CTR_ADDRESS_REV2 0x04448080
+
+#define R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV1 0x04648808
+#define R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV2 0x04648080
+
+///
+/// Function Prototypes
+///
+
+
+
+UINT16
+GetErrorTarget (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ );
+
+VOID GetPortInfo (
+ OUT PORT_INFO *PortInfoList,
+ OUT UINT8 *PortInfoListLength,
+ OUT BOOLEAN *SkipBundle0
+ );
+
+EFI_STATUS
+RunMarginTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT32 MonitorPort,
+ IN PORT_INFO *PortInfoList,
+ IN UINT8 PortInfoListLength,
+ IN MARGIN_TEST_TYPE MarginTest,
+ OUT INT32 *Margins
+ );
+
+EFI_STATUS
+LaneLevelJitterTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT32 MonitorPort,
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth,
+ IN BOOLEAN TxJitterTest,
+ OUT INT32 *Margins
+ );
+
+UINT32
+SaPciePointTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi,
+ IN UINT32 MonitorPort,
+ IN PEG_PORT *PegPort,
+ IN UINT32 InitialRecoveryCount
+ );
+
+INT32
+CalculateMarginDifference (
+ IN INT32 Margin1,
+ IN INT32 Margin2
+ );
+
+INT32
+InterpolateMargin (
+ IN UINT32 ErrorTarget,
+ IN UINT32 CurrentErrorCount,
+ IN UINT32 PreviousErrorCount,
+ IN INT32 FailingPoint
+ );
+
+
+UINT32
+NaturalLog (
+ IN UINT32 Input
+ );
+
+
+VOID
+PegGen3PresetSearch (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi,
+ SA_DATA_HOB *SaDataHob
+ );
+
+BOOLEAN
+SaPolicyEnablesGen3 (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ );
+
+
+EFI_STATUS
+EnsureLinkIsHealthy (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth
+ );
+
+EFI_STATUS
+WaitForL0 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN BOOLEAN UseVcu
+ );
+
+EFI_STATUS
+TogglePegSlotReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ );
+
+EFI_STATUS
+AssertPegSlotReset (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ );
+
+EFI_STATUS
+DeassertPegSlotReset (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ );
+
+EFI_STATUS
+RecoverLinkFailure (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth
+ );
+
+BOOLEAN
+LinkIsDowngraded (
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth
+ );
+
+EFI_STATUS
+SecondaryBusReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort
+ );
+
+EFI_STATUS
+ResetPhyLayer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort
+ );
+
+EFI_STATUS
+RetrainLink (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort
+ );
+
+UINT8
+GetNegotiatedWidth (
+ IN PEG_PORT *PegPort
+ );
+
+EFI_STATUS
+RecoverLinkWidth (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkWidth
+ );
+
+UINT8
+GetLinkSpeed (
+ IN PEG_PORT *PegPort
+ );
+
+EFI_STATUS
+RecoverLinkSpeed (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed
+ );
+
+VOID
+PcieTrainingWarmReset (
+ IN EFI_PEI_SERVICES **PeiServices
+ );
+
+
+EFI_STATUS
+SetJitterTolerance (
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ IN UINT8 ReportedMargin
+ );
+
+EFI_STATUS
+SetRawJitterTolerance (
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ IN UINT8 Step,
+ IN UINT8 Depth,
+ IN UINT8 DoubleMargin,
+ IN BOOLEAN EnableJitter
+ );
+
+VOID
+EnableTxJitterInjection (
+ IN UINT8 Lane,
+ IN BOOLEAN EnableTxJitter
+ );
+
+VOID
+ConfigureTxJitterMux (
+ IN UINT8 Lane,
+ IN UINT32 MchBar
+ );
+
+EFI_STATUS
+GetBundleList (
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ OUT UINT8 *BundleList,
+ OUT UINT8 *BundleListLength
+ );
+
+
+UINT32
+OpenMonitor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi
+ );
+
+VOID
+CloseMonitor (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT32 MonitorPort
+ );
+
+UINT32
+SaPcieGetErrorCount (
+ IN UINT32 MonitorPort,
+ IN UINT8 PcieController
+ );
+
+VOID
+SaPcieClearErrorCount (
+ IN UINT32 MonitorPort,
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi
+ );
+
+VOID
+InitMonitor (
+ IN UINT32 MchBar,
+ IN UINT32 GdxcBar
+ );
+
+VOID
+TearDownMonitor (
+ IN UINT32 MchBar,
+ IN UINT32 GdxcBar
+ );
+
+UINT32
+EnableMonitor (
+ VOID
+ );
+
+VOID
+DisableMonitor (
+ VOID
+ );
+
+VOID
+FullMonitorReset (
+ IN UINT32 MonitorPort
+ );
+
+VOID
+ProgramMonitor (
+ IN UINT32 MonitorPort,
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi
+ );
+
+
+VOID
+GetLinkPartnerFullSwing (
+ IN UINT8 Lane,
+ OUT UINT8 *FullSwing
+ );
+
+VOID
+GetCoefficientsFromPreset (
+ IN UINT8 Preset,
+ IN UINT8 FullSwing,
+ OUT UINT8 *PreCursor,
+ OUT UINT8 *Cursor,
+ OUT UINT8 *PostCursor
+ );
+
+VOID
+SetPartnerTxCoefficients (
+ IN UINT8 Lane,
+ IN UINT8 *PreCursor,
+ IN UINT8 *Cursor,
+ IN UINT8 *PostCursor
+ );
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingEqSettings.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingEqSettings.c
new file mode 100644
index 0000000..dc4515e
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingEqSettings.c
@@ -0,0 +1,166 @@
+/*++ @file
+ This file adds equalization setting support.
+
+@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 "PcieTraining.h"
+#include "PciExpressInit.h"
+
+#ifdef PEG_FLAG
+
+VOID
+GetLinkPartnerFullSwing (
+ IN UINT8 Lane,
+ OUT UINT8 *FullSwing
+ )
+{
+ UINT32 Data32;
+
+ Data32 = BIT25 | BIT23 | (Lane << 19) | BIT18;
+ McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = Data32;
+ Data32 = McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET);
+ McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = 0;
+
+ *FullSwing = (Data32 >> 6) & 0x3F;
+
+ return;
+}
+
+VOID
+GetCoefficientsFromPreset (
+ IN UINT8 Preset,
+ IN UINT8 FullSwing,
+ OUT UINT8 *PreCursor,
+ OUT UINT8 *Cursor,
+ OUT UINT8 *PostCursor
+ )
+{
+ INT32 PreCursorMilli;
+ INT32 PostCursorMilli;
+
+ PreCursorMilli = 0;
+ PostCursorMilli = 0;
+
+ ///
+ /// Get starting values from Table 4-16 of the PCIe Base Spec v3.0
+ ///
+ switch (Preset) {
+ case 0:
+ PreCursorMilli = 0;
+ PostCursorMilli = -250;
+ break;
+
+ case 1:
+ PreCursorMilli = 0;
+ PostCursorMilli = -167;
+ break;
+
+ case 2:
+ PreCursorMilli = 0;
+ PostCursorMilli = -200;
+ break;
+
+ case 3:
+ PreCursorMilli = 0;
+ PostCursorMilli = -125;
+ break;
+
+ case 4:
+ PreCursorMilli = 0;
+ PostCursorMilli = 0;
+ break;
+
+ case 5:
+ PreCursorMilli = -100;
+ PostCursorMilli = 0;
+ break;
+
+ case 6:
+ PreCursorMilli = -125;
+ PostCursorMilli = 0;
+ break;
+
+ case 7:
+ PreCursorMilli = -100;
+ PostCursorMilli = -200;
+ break;
+
+ case 8:
+ PreCursorMilli = -125;
+ PostCursorMilli = -125;
+ break;
+
+ case 9:
+ PreCursorMilli = -166;
+ PostCursorMilli = 0;
+ break;
+
+ case 10: ///< P10 is unsupported
+ default:
+ PreCursorMilli = -100;
+ PostCursorMilli = -200;
+ DEBUG ((EFI_D_WARN, "GetCoefficientsFromPreset(): Unsupported Preset Requested: P%d. Using P7.\n", Preset));
+ break;
+ }
+
+ ///
+ /// Convert to absolute values
+ ///
+ if (PreCursorMilli < 0) {
+ PreCursorMilli *= -1;
+ }
+ if (PostCursorMilli < 0) {
+ PostCursorMilli *= -1;
+ }
+
+ ///
+ /// Apply FullSwing
+ ///
+ PreCursorMilli *= FullSwing;
+ PostCursorMilli *= FullSwing;
+
+ ///
+ /// Convert to integers
+ ///
+ *PreCursor = (( PreCursorMilli % 1000) >= 500) ? (UINT8) (( PreCursorMilli / 1000) + 1) : (UINT8) ( PreCursorMilli / 1000);
+ *PostCursor = ((PostCursorMilli % 1000) >= 500) ? (UINT8) ((PostCursorMilli / 1000) + 1) : (UINT8) (PostCursorMilli / 1000);
+ *Cursor = FullSwing - (*PreCursor) - (*PostCursor);
+
+ return;
+}
+
+VOID
+SetPartnerTxCoefficients (
+ IN UINT8 Lane,
+ IN UINT8 *PreCursor,
+ IN UINT8 *Cursor,
+ IN UINT8 *PostCursor
+ )
+{
+ UINT32 Data32;
+
+ Data32 = (Lane << 19) | BIT18 | (*Cursor << 12) | (*PreCursor << 6) | (*PostCursor);
+ McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = Data32;
+ McD1PciCfg32(R_SA_PEG_EQPH3_OFFSET) = 0;
+
+ return;
+}
+
+#endif // PEG_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingErrorCount.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingErrorCount.c
new file mode 100644
index 0000000..d1fb107
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingErrorCount.c
@@ -0,0 +1,195 @@
+/** @file
+ Error Counting for PEG training.
+
+@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 "PcieTraining.h"
+
+#ifdef PEG_FLAG
+
+UINT32
+OpenMonitor (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi
+ )
+{
+ UINT32 MonitorPort;
+
+ InitMonitor (SaPlatformPolicyPpi->PlatformData->MchBar, SaPlatformPolicyPpi->PlatformData->GdxcBar);
+ MonitorPort = EnableMonitor ();
+ FullMonitorReset (MonitorPort);
+ ProgramMonitor (MonitorPort, PeiServices, StallPpi);
+
+ return MonitorPort;
+}
+
+VOID
+CloseMonitor (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT32 MonitorPort
+ )
+{
+ FullMonitorReset (MonitorPort);
+ DisableMonitor ();
+ TearDownMonitor (SaPlatformPolicyPpi->PlatformData->MchBar, SaPlatformPolicyPpi->PlatformData->GdxcBar);
+
+ return;
+}
+
+UINT32
+SaPcieGetErrorCount (
+ IN UINT32 MonitorPort,
+ IN UINT8 PcieController
+ )
+{
+ UINT32 Data32;
+
+ Data32 = Mmio32 (MonitorPort, (0xC + (PcieController * 0x10)));
+
+ return Data32;
+}
+
+VOID
+SaPcieClearErrorCount (
+ IN UINT32 MonitorPort,
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi
+ )
+{
+ FullMonitorReset (MonitorPort);
+ ProgramMonitor (MonitorPort, PeiServices, StallPpi);
+
+ return;
+}
+
+VOID
+InitMonitor (
+ IN UINT32 MchBar,
+ IN UINT32 GdxcBar
+ )
+{
+ Mmio32 (MchBar, 0x6430) = 0x3;
+ Mmio32 (MchBar, 0x6434) = 0x76543210;
+ McD1PciCfg32 (0x630) = 0xB;
+ McD1PciCfg32 (0x600) = 0x60B;
+ McD1PciCfg32 (0x604) = 0x76543980;
+ McD1F1PciCfg32 (0x600) = 0x60B;
+ McD1F1PciCfg32 (0x604) = 0x76543280;
+ McD1F2PciCfg32 (0x600) = 0xB;
+ McD1F2PciCfg32 (0x604) = 0x76543210;
+ Mmio32 (MchBar, 0x6438) = 0x680000;
+ Mmio32 (GdxcBar, 0xA04) = 0xA;
+
+ return;
+}
+
+VOID
+TearDownMonitor (
+ IN UINT32 MchBar,
+ IN UINT32 GdxcBar
+ )
+{
+ Mmio32 (MchBar, 0x6430) = 0x0;
+ Mmio32 (MchBar, 0x6434) = 0x0;
+ McD1PciCfg32 (0x630) = 0x0;
+ McD1PciCfg32 (0x600) = 0x0;
+ McD1PciCfg32 (0x604) = 0x0;
+ McD1F1PciCfg32 (0x600) = 0x0;
+ McD1F1PciCfg32 (0x604) = 0x0;
+ McD1F2PciCfg32 (0x600) = 0x0;
+ McD1F2PciCfg32 (0x604) = 0x0;
+ Mmio32 (MchBar, 0x6438) = 0x0;
+ Mmio32 (GdxcBar, 0xA04) = 0x0;
+
+ return;
+}
+
+UINT32
+EnableMonitor (
+ VOID
+ )
+{
+ UINT32 Data32;
+
+ Data32 = (McD0PciCfg32 (0140) & ~(07));
+ Mmio32Or (Data32, 0124, 040000);
+ Mmio64 (Data32, 0700020) = (UINT64) SA_PEI_MONITOR_OFFSET;
+ Mmio16Or (Data32, 0700004, 02);
+
+ return SA_PEI_MONITOR_OFFSET;
+}
+
+VOID
+DisableMonitor (
+ VOID
+ )
+{
+ UINT32 Data32;
+
+ Data32 = (McD0PciCfg32 (0140) & ~(07));
+ Mmio16And (Data32, 0700004, 0177775);
+ Mmio64And (Data32, 0700020, 07777);
+ Mmio32And (Data32, 0124, 037777737777);
+
+ return;
+}
+
+VOID
+FullMonitorReset (
+ IN UINT32 MonitorPort
+ )
+{
+ Mmio32 (MonitorPort, 0x0) = 0x40000;
+ Mmio32 (MonitorPort, 0x4) = 0x0;
+ Mmio32 (MonitorPort, 0x10) = 0x40000;
+ Mmio32 (MonitorPort, 0x14) = 0x0;
+ Mmio32 (MonitorPort, 0x20) = 0x40000;
+ Mmio32 (MonitorPort, 0x24) = 0x0;
+ Mmio32 (MonitorPort, 0x8) = 0xFF000000;
+ Mmio32 (MonitorPort, 0x18) = 0xFF000000;
+ Mmio32 (MonitorPort, 0x28) = 0xFF000000;
+ Mmio32 (MonitorPort, 0xC) = 0x0;
+ Mmio32 (MonitorPort, 0x1C) = 0x0;
+ Mmio32 (MonitorPort, 0x2C) = 0x0;
+
+ return;
+}
+
+VOID
+ProgramMonitor (
+ IN UINT32 MonitorPort,
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi
+ )
+{
+ Mmio32 (MonitorPort, 0x4) = 0xA100;
+ Mmio32 (MonitorPort, 0x14) = 0xA101;
+ Mmio32 (MonitorPort, 0x24) = 0xA102;
+ Mmio32 (MonitorPort, 0x0) = 0x110000;
+ StallPpi->Stall (PeiServices, StallPpi, 1 * STALL_ONE_MILLI_SECOND);
+
+ Mmio32 (MonitorPort, 0x0) = 0x22100;
+ Mmio32 (MonitorPort, 0x10) = 0x22101;
+ Mmio32 (MonitorPort, 0x20) = 0x22102;
+
+ return;
+}
+
+#endif // PEG_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingLinkRecovery.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingLinkRecovery.c
new file mode 100644
index 0000000..1480bc7
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingLinkRecovery.c
@@ -0,0 +1,721 @@
+/*++ @file
+ This driver recovers the PEG link.
+
+@copyright
+ Copyright (c) 2012 - 2014 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 "PcieTraining.h"
+#include "PciExpressInit.h"
+#include EFI_PPI_CONSUMER (PchReset)
+
+#ifdef PEG_FLAG
+
+EFI_STATUS
+EnsureLinkIsHealthy (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ ///
+ /// Check Link Status and Recover the Link if needed
+ ///
+ Status = RecoverLinkWidth (PeiServices, StallPpi, PegPort, OriginalLinkWidth);
+ if (EFI_ERROR (Status)) {
+ Status = RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ Status = RecoverLinkSpeed (PeiServices, StallPpi, PegPort, OriginalLinkSpeed);
+ if (EFI_ERROR (Status)) {
+ Status = RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "DOWNGRADE, Link is not in L0\n"));
+ Status = RetrainLink (PeiServices, StallPpi, PegPort);
+ if (EFI_ERROR (Status)) {
+ Status = RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi, PegPort, OriginalLinkSpeed, OriginalLinkWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Wait until link is up.
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] PegPort - Pointer PEG Port
+ @param[in] UseVcu - If TRUE, use VCU to determine link state. If FALSE, use MMIO CFG to determine link state.
+
+ @retval EFI_SUCCESS - Completed successfully before timeout
+ @retval EFI_TIMEOUT - Timed out
+**/
+EFI_STATUS
+WaitForL0 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN BOOLEAN UseVcu
+ )
+{
+ UINT32 MchBar;
+ UINT32 i;
+ EFI_STATUS Status;
+ UINT32 VcuAddress;
+ UINT8 VcuReadOp;
+ UINT8 VcuWriteOp;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ BOOLEAN CheckEq;
+ BOOLEAN CompletedEq;
+ UINT32 EqStatus;
+ UINT32 LinkStatus;
+
+ Status = EFI_TIMEOUT;
+ CheckEq = (PegPort->EndpointMaxLinkSpeed >= 0x3) ? TRUE : FALSE;
+ CompletedEq = FALSE;
+ i = 0;
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) & ~BIT0;
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+#ifndef AMI_OVERRIDE_FOR_ULT_FASTBOOT
+ if (CpuFamilyId == EnumCpuHswUlt) return EFI_UNSUPPORTED;
+#endif // AMI_OVERRIDE_FOR_ULT_FASTBOOT
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ VcuAddress = R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV1;
+ VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV1;
+ VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV1;
+ } else {
+ VcuAddress = R_SA_VCU_REUT_PH1_PIS_ADDRESS_REV2;
+ VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV2;
+ VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV2;
+ }
+
+ ///
+ /// If endpoint's LCAP.MLS (Spec section 7.8.6) indicated Gen3 capability, first wait for equalization to complete.
+ /// Check equalization status LSTS2.EC (Spec section 7.8.20) until Gen3 equalization successfully completed.
+ ///
+ if (CheckEq && !UseVcu) {
+ for (; i < 100; i++) {
+ EqStatus = MmPci16 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LSTS2_OFFSET);
+ EqStatus = (EqStatus >> 1) & 0x1;
+ if (EqStatus == 0x1) {
+ CompletedEq = TRUE;
+ break;
+ }
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND);
+ }
+ }
+
+ ///
+ /// Check for L0 status. If !UseVcu, check PEGSTS.
+ /// Continue up to 100 msec of combined delay.
+ /// Skip if equalization was needed but didn't successfully complete.
+ ///
+ if ((CheckEq && CompletedEq) || !CheckEq || UseVcu) {
+ for (; i < 100; i++) {
+ if (UseVcu) {
+ LinkStatus = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ LinkStatus = (LinkStatus >> (PegPort->Function * B_SA_PEG_REUT_PH1_PIS_ST_STEP)) & B_SA_PEG_REUT_PH1_PIS_ST_MASK;
+ if (LinkStatus == 0x10) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ } else {
+ LinkStatus = MmPci32 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_PEGSTS_OFFSET);
+ LinkStatus = (LinkStatus >> 16) & 0xF;
+ if (LinkStatus == 0x7) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MILLI_SECOND);
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+SetPchGpio (
+ IN UINT8 GpioNumber,
+ IN UINT8 Level
+ )
+/**
+ This function sets a GPIO to a particular level.
+
+ @param[in] GpioNumber - PCH GPIO number
+ @param[in] Level - 0 = Low, 1 = High
+
+ @retval EFI_SUCCESS - Did toggle GPIO
+ @retval EFI_UNSUPPORTED - Didn't toggle GPIO
+ @retval EFI_INVALID_PARAMETER - Didn't toggle GPIO
+**/
+{
+ UINT32 Data32;
+ UINT16 LpcDeviceId;
+ UINT16 GpioBase;
+ UINT16 UseSelOffset;
+ UINT16 IoSelOffset;
+ UINT16 LvlOffset;
+ UINT8 GpioBit;
+ EFI_STATUS Status;
+
+ Level &= 0x1;
+ Status = EFI_SUCCESS;
+ GpioBase = 0;
+ UseSelOffset = 0;
+ IoSelOffset = 0;
+ LvlOffset = 0;
+ GpioBit = 0;
+
+ LpcDeviceId = McDevFunPciCfg16 (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_DEVICE_ID
+ );
+ if (!IS_PCH_LPT_LPC_DEVICE_ID (LpcDeviceId)) {
+ Status = EFI_UNSUPPORTED;
+ return Status;
+ }
+
+ GpioBase = McDevFunPciCfg16 (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_GPIO_BASE
+ ) & B_PCH_LPC_GPIO_BASE_BAR;
+ if (GpioBase == 0) {
+ Status = EFI_UNSUPPORTED;
+ return Status;
+ }
+
+ if (GpioNumber < 0x20) {
+ UseSelOffset = R_PCH_GPIO_USE_SEL;
+ IoSelOffset = R_PCH_GPIO_IO_SEL;
+ LvlOffset = R_PCH_GPIO_LVL;
+ GpioBit = GpioNumber;
+ } else if (GpioNumber < 0x40) {
+ UseSelOffset = R_PCH_GPIO_USE_SEL2;
+ IoSelOffset = R_PCH_GPIO_IO_SEL2;
+ LvlOffset = R_PCH_GPIO_LVL2;
+ GpioBit = GpioNumber - 0x20;
+ } else if (GpioNumber < 0x60) {
+ UseSelOffset = R_PCH_GPIO_USE_SEL3;
+ IoSelOffset = R_PCH_GPIO_IO_SEL3;
+ LvlOffset = R_PCH_GPIO_LVL3;
+ GpioBit = GpioNumber - 0x40;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Setting GPIO%d to %x\n", GpioNumber, Level));
+ IoOr32 ((UINTN) (GpioBase + UseSelOffset), (UINT32) (1 << GpioBit));
+ IoAnd32 ((UINTN) (GpioBase + IoSelOffset), (UINT32) ~(1 << GpioBit));
+ Data32 = IoRead32 ((UINTN) (GpioBase + LvlOffset));
+ Data32 &= (UINT32) ~(1 << GpioBit);
+ Data32 |= (UINT32) (Level << GpioBit);
+ IoWrite32 ((UINTN) (GpioBase + LvlOffset), Data32);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+TogglePegSlotReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ This function asserts and deasserts a GPIO that controls PERST#.
+ The specific GPIO and its active level is provided by a policy.
+ The GPIO minimum assertion time, T_PERST (100 usec), is defined in the PCIe CEM Specification.
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] StallPpi - Pointer to PEI_STALL_PPI
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+
+ @retval EFI_SUCCESS - Did toggle GPIO
+ @retval EFI_UNSUPPORTED - Didn't toggle GPIO
+ @retval EFI_INVALID_PARAMETER - Didn't toggle GPIO
+**/
+{
+ EFI_STATUS Status;
+ UINT8 i;
+
+ DEBUG ((EFI_D_INFO, "Toggling PEG slot reset.\n"));
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ MmPci16Or (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, i, R_SA_PEG_LCTL_OFFSET, BIT4);
+ }
+ Status = AssertPegSlotReset (SaPlatformPolicyPpi);
+ if (!EFI_ERROR (Status)) {
+ StallPpi->Stall (PeiServices, StallPpi, 100 * STALL_ONE_MICRO_SECOND);
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ MmPci16And (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, i, R_SA_PEG_LCTL_OFFSET, (UINT16) ~(BIT4));
+ }
+ Status = DeassertPegSlotReset (SaPlatformPolicyPpi);
+ } else {
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ MmPci16And (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, i, R_SA_PEG_LCTL_OFFSET, (UINT16) ~(BIT4));
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AssertPegSlotReset (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ This function asserts a GPIO that controls PERST#.
+ The specific GPIO and its active level is provided by a policy.
+ The GPIO minimum assertion time, T_PERST (100 usec), is defined in the PCIe CEM Specification.
+
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+
+ @retval EFI_SUCCESS - Did assert GPIO
+ @retval EFI_UNSUPPORTED - Didn't assert GPIO
+ @retval EFI_INVALID_PARAMETER - Didn't assert GPIO
+**/
+{
+ EFI_STATUS Status;
+ UINT8 GpioNumber;
+ UINT8 AssertLevel;
+
+ Status = EFI_SUCCESS;
+
+ DEBUG ((EFI_D_INFO, "Asserting PEG slot reset.\n"));
+
+ if (!((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) &&
+ (SaPlatformPolicyPpi->PcieConfig->PegGpioData->GpioSupport == TRUE))) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ GpioNumber = (UINT8) (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Value);
+ AssertLevel = (UINT8) (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Active & 0x1);
+ Status = SetPchGpio (GpioNumber, AssertLevel);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+DeassertPegSlotReset (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ This function deasserts a GPIO that controls PERST#.
+ The specific GPIO and its active level is provided by a policy.
+ The GPIO minimum assertion time, T_PERST (100 usec), is defined in the PCIe CEM Specification.
+
+ @param[in] SaPlatformPolicyPpi - Pointer to SA_PLATFORM_POLICY_PPI
+
+ @retval EFI_SUCCESS - Did deassert GPIO
+ @retval EFI_UNSUPPORTED - Didn't deassert GPIO
+ @retval EFI_INVALID_PARAMETER - Didn't deassert GPIO
+**/
+{
+ EFI_STATUS Status;
+ UINT8 GpioNumber;
+ UINT8 DeassertLevel;
+
+ Status = EFI_SUCCESS;
+
+ DEBUG ((EFI_D_INFO, "Deasserting PEG slot reset.\n"));
+
+ if (!((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) &&
+ (SaPlatformPolicyPpi->PcieConfig->PegGpioData->GpioSupport == TRUE))) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ GpioNumber = (UINT8) (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Value);
+ DeassertLevel = (UINT8) ((SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Active & 0x1) ^ 0x1);
+ SetPchGpio (GpioNumber, DeassertLevel);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+RecoverLinkFailure (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 CurrentLinkWidth;
+ UINT8 CurrentLinkSpeed;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+
+ ///
+ /// A platform reset should be done after presets are saved in NVRAM
+ ///
+ if (SaDataHob != NULL) {
+ if ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) &&
+ (SaPlatformPolicyPpi->PcieConfig->PegGen3ForcePresetSearch == 0)) {
+ SaDataHob->PegPlatformResetRequired = TRUE;
+ } else if (SaPlatformPolicyPpi->Revision < SA_PLATFORM_POLICY_PPI_REVISION_2) {
+ SaDataHob->PegPlatformResetRequired = TRUE;
+ }
+ }
+
+ ///
+ /// Bypass phase2 and assert slot reset
+ ///
+ McD1PciCfg32Or (R_SA_PEG_EQCFG_OFFSET, BIT15);
+ Status = TogglePegSlotReset (PeiServices, StallPpi, SaPlatformPolicyPpi);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Error 0x%x.\n", Status));
+ } else {
+ DEBUG ((EFI_D_INFO, "Success.\n"));
+ }
+ PegBus = PegPort->Bus;
+ PegDev = PegPort->Device;
+ PegFunc = PegPort->Function;
+ ///
+ /// Wait for Equalization Done
+ ///
+ while (((MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS2_OFFSET) >> 1) & 0x1) != 0x1);
+ ///
+ /// Wait for flow control credits exchange
+ ///
+ WaitForVc0Negotiation (PeiServices, StallPpi, PegBus, PegDev, PegFunc);
+
+ CurrentLinkWidth = GetNegotiatedWidth (PegPort);
+ if (CurrentLinkWidth < OriginalLinkWidth) {
+ DEBUG ((EFI_D_ERROR, "Link Width DOWNGRADED!\n"));
+ Status = EFI_TIMEOUT;
+ }
+ CurrentLinkSpeed = GetLinkSpeed (PegPort);
+ if (CurrentLinkSpeed < OriginalLinkSpeed) {
+ DEBUG ((EFI_D_ERROR, "Link Speed DOWNGRADED!\n"));
+ Status = EFI_TIMEOUT;
+ }
+
+ return Status;
+}
+
+BOOLEAN
+LinkIsDowngraded (
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed,
+ IN UINT8 OriginalLinkWidth
+ )
+{
+ BOOLEAN IsDowngraded;
+
+ IsDowngraded = FALSE;
+
+ if (OriginalLinkSpeed != GetLinkSpeed (PegPort)) {
+ DEBUG ((EFI_D_INFO, "Link speed downgrade detected\n"));
+ IsDowngraded = TRUE;
+ }
+ if (OriginalLinkWidth != GetNegotiatedWidth (PegPort)) {
+ DEBUG ((EFI_D_INFO, "Link width downgrade detected\n"));
+ IsDowngraded = TRUE;
+ }
+ return IsDowngraded;
+}
+
+EFI_STATUS
+SecondaryBusReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ DEBUG ((EFI_D_INFO, "SECONDARY BUS RESET!\n"));
+ MmPci16Or (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_BCTRL_OFFSET, B_SA_PEG_BCTRL_SRESET_MASK);
+ MmPci16And (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_BCTRL_OFFSET,~(B_SA_PEG_BCTRL_SRESET_MASK));
+ Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE);
+ DEBUG ((EFI_D_INFO, "Reset Complete\n"));
+
+ return Status;
+}
+
+EFI_STATUS
+ResetPhyLayer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort
+ )
+{
+ EFI_STATUS Status;
+ UINT32 MchBar;
+ UINT32 Data32;
+ UINT32 VcuAddress;
+ UINT8 VcuReadOp;
+ UINT8 VcuWriteOp;
+ BOOLEAN UseVcu;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+
+ UseVcu = TRUE;
+ Status = EFI_SUCCESS;
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+#ifndef AMI_OVERRIDE_FOR_ULT_FASTBOOT
+ if (CpuFamilyId == EnumCpuHswUlt) return EFI_UNSUPPORTED;
+#endif // AMI_OVERRIDE_FOR_ULT_FASTBOOT
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ VcuAddress = R_SA_VCU_REUT_PH_CTR_ADDRESS_REV1;
+ VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV1;
+ VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV1;
+ } else {
+ VcuAddress = R_SA_VCU_REUT_PH_CTR_ADDRESS_REV2;
+ VcuReadOp = V_SA_VCU_OPCODE_READ_CSR_REV2;
+ VcuWriteOp = V_SA_VCU_OPCODE_WRITE_CSR_REV2;
+ }
+
+ DEBUG ((EFI_D_INFO, "PHY LAYER RESET!\n"));
+ if (UseVcu) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 &= (UINT32) ~(BIT1);
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ } else {
+ McD1PciCfg32And (R_SA_PEG_REUT_PH_CTR_OFFSET, ~(B_SA_PEG_REUT_PH_CTR_RESETMOD_MASK));
+ }
+
+ if (UseVcu) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 |= (UINT32) BIT0;
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ } else {
+ McD1PciCfg32Or (R_SA_PEG_REUT_PH_CTR_OFFSET, B_SA_PEG_REUT_PH_CTR_PHYRESET_MASK);
+ }
+
+ if (UseVcu) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 |= (UINT32) BIT13;
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ } else {
+ McD1PciCfg32Or (R_SA_PEG_REUT_PH_CTR_OFFSET, B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK);
+ }
+
+ if (UseVcu) {
+ Data32 = SendVcuApiSequence (MchBar, VcuAddress, VcuReadOp, 0);
+ Data32 &= (UINT32) ~(BIT0);
+ SendVcuApiSequence (MchBar, VcuAddress, VcuWriteOp, Data32);
+ } else {
+ McD1PciCfg32And (R_SA_PEG_REUT_PH_CTR_OFFSET, ~(B_SA_PEG_REUT_PH_CTR_PHYRESET_MASK));
+ }
+
+ Status = WaitForL0 (PeiServices, StallPpi, PegPort, TRUE);
+ DEBUG ((EFI_D_INFO, "Reset Complete\n"));
+
+ return Status;
+}
+
+EFI_STATUS
+RetrainLink (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort
+ )
+{
+ EFI_STATUS Status;
+
+ ///
+ /// Initiate Link Retrain
+ ///
+ MmPci16Or (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LCTL_OFFSET, 0x20);
+
+ Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Link retrain FAILED!!!\n"));
+ }
+
+ return Status;
+}
+
+UINT8
+GetNegotiatedWidth (
+ IN PEG_PORT *PegPort
+ )
+{
+ UINT16 Lsts;
+
+ Lsts = MmPci16 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LSTS_OFFSET);
+
+ return (UINT8)((Lsts >> 4) & 0x3F);
+}
+
+EFI_STATUS
+RecoverLinkWidth (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 CurrentLinkWidth;
+
+ Status = EFI_SUCCESS;
+
+ CurrentLinkWidth = GetNegotiatedWidth (PegPort);
+ if (CurrentLinkWidth < OriginalLinkWidth) {
+ DEBUG ((EFI_D_INFO, "DOWNGRADE from x%d to x%d detected\n", OriginalLinkWidth, CurrentLinkWidth));
+ MmPci32AndThenOr (
+ 0,
+ PegPort->Bus,
+ PegPort->Device,
+ PegPort->Function,
+ R_SA_PEG_LTSSMC_OFFSET,
+ B_SA_PEG_LTSSMC_WIDTH_MASK,
+ OriginalLinkWidth
+ );
+ MmPci16Or (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LCTL_OFFSET, 0x10);
+ StallPpi->Stall (PeiServices, StallPpi, STALL_ONE_MICRO_SECOND);
+ MmPci16And (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LCTL_OFFSET, 0xFFEF);
+ Status = WaitForL0 (PeiServices, StallPpi, PegPort, FALSE);
+ MmPci32Or (
+ 0,
+ PegPort->Bus,
+ PegPort->Device,
+ PegPort->Function,
+ R_SA_PEG_LTSSMC_OFFSET,
+ 0x1F
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CurrentLinkWidth = GetNegotiatedWidth (PegPort);
+ if (CurrentLinkWidth == OriginalLinkWidth) {
+ DEBUG ((EFI_D_INFO, "Width Recovery Successful\n"));
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUG ((EFI_D_INFO, "Width Recovery FAILED!\n"));
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ return Status;
+}
+
+UINT8
+GetLinkSpeed (
+ IN PEG_PORT *PegPort
+ )
+{
+ UINT16 Lsts;
+
+ Lsts = MmPci16 (0, PegPort->Bus, PegPort->Device, PegPort->Function, R_SA_PEG_LSTS_OFFSET);
+
+ return (UINT8)(Lsts & 0xF);
+}
+
+EFI_STATUS
+RecoverLinkSpeed (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_STALL_PPI *StallPpi,
+ IN PEG_PORT *PegPort,
+ IN UINT8 OriginalLinkSpeed
+ )
+{
+ EFI_STATUS Status;
+ UINT8 CurrentLinkSpeed;
+
+ Status = EFI_SUCCESS;
+
+ CurrentLinkSpeed = GetLinkSpeed (PegPort);
+ if (CurrentLinkSpeed < OriginalLinkSpeed) {
+ DEBUG ((EFI_D_INFO, "DOWNGRADE from Gen %d to Gen %d detected\n", OriginalLinkSpeed, CurrentLinkSpeed));
+
+ Status = RetrainLink (PeiServices, StallPpi, PegPort);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Link Speed Recovery FAILED!\n"));
+ return Status;
+ }
+
+ CurrentLinkSpeed = GetLinkSpeed (PegPort);
+ if (CurrentLinkSpeed < OriginalLinkSpeed) {
+ DEBUG ((EFI_D_INFO, "Link Speed Recovery FAILED!\n"));
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ DEBUG ((EFI_D_INFO, "Link Speed Recovery Successful\n"));
+ }
+ }
+
+ return Status;
+}
+
+VOID
+PcieTrainingWarmReset (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PCH_RESET_PPI *PchResetPpi;
+
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gPchResetPpiGuid,
+ 0,
+ NULL,
+ &PchResetPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+ PchResetPpi->Reset (PchResetPpi, WarmReset);
+
+ return;
+}
+
+#endif // PEG_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingMargining.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingMargining.c
new file mode 100644
index 0000000..7d2f63d
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingMargining.c
@@ -0,0 +1,223 @@
+/** @file
+ Margining for PEG Training
+
+@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 "PcieTraining.h"
+
+#ifdef PEG_FLAG
+
+///
+/// Jitter Calculations
+///
+JITTER_SETTING Jitter_Gen3[/* 083.333 */] = {{1, 64, 1, 0}, {1, 33, 2, 0}, {3, 64, 3, 0}, {4, 80, 4, 0}, {5, 97, 5, 0}, {6, 128, 6, 0}, {7, 129, 7, 0}, {8, 161, 8, 0}, {9, 192, 9, 0}, {10, 193, 10, 0}, {11, 225, 11, 0}, {12, 128, 12, 1}, {13, 129, 13, 1}, {14, 145, 14, 1}, {15, 160, 15, 1}, {16, 161, 16, 1}, {17, 177, 17, 1}, {18, 192, 18, 1}, {19, 193, 19, 1}, {20, 209, 20, 1}, {21, 224, 21, 1}, {22, 225, 22, 1}, {23, 241, 23, 1}, {24, 246, 24, 1}};
+
+EFI_STATUS
+SetJitterTolerance (
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ IN UINT8 ReportedMargin
+ )
+{
+ JITTER_SETTING Settings = {0, 0, 0, 0};
+ UINT8 i;
+ BOOLEAN Found;
+
+ if (ReportedMargin > 0) {
+ Found = FALSE;
+ for (i = 0; i < (JITTER_LENGTH - 1); ++i) {
+ Settings = Jitter_Gen3[i];
+ if (Settings.ReportedMargin == ReportedMargin) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (Found) {
+ return SetRawJitterTolerance (
+ LaneList,
+ LaneListLength,
+ Settings.Step,
+ Settings.Depth,
+ Settings.DoubleMargin,
+ TRUE
+ );
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ return SetRawJitterTolerance (
+ LaneList,
+ LaneListLength,
+ Settings.Step,
+ Settings.Depth,
+ Settings.DoubleMargin,
+ FALSE
+ );
+ }
+}
+
+EFI_STATUS
+SetRawJitterTolerance (
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ IN UINT8 Step,
+ IN UINT8 Depth,
+ IN UINT8 DoubleMargin,
+ IN BOOLEAN EnableJitter
+ )
+{
+ UINT8 BundleList[8];
+ UINT8 BundleListLength;
+ UINT8 i;
+ UINT8 Lane;
+ UINT8 Bundle;
+
+ BundleListLength = 0;
+
+ GetBundleList (LaneList, LaneListLength, &BundleList[0], &BundleListLength);
+
+ for (i = 0; i < LaneListLength; ++i) {
+ Lane = LaneList[i];
+
+ McD1PciCfg32And (R_SA_PEG_AFELN0CFG0_OFFSET + (Lane * LANE_STEP), 0xFFFFFBFF);
+ }
+
+ for (i = 0; i < BundleListLength; ++i) {
+ Bundle = BundleList[i];
+
+ McD1PciCfg32AndThenOr (
+ R_SA_PEG_AFEBND0CFG0_OFFSET + (Bundle * BUNDLE_STEP),
+ (UINT32) ~(BIT28 | BIT17 | BIT16 | BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | BIT10),
+ (UINT32) ((DoubleMargin << 28) | (Step << 10))
+ );
+
+ McD1PciCfg32AndThenOr (
+ R_SA_PEG_AFEBND0CFG3_OFFSET + (Bundle * BUNDLE_STEP),
+ (UINT32) ~(BIT16 | BIT15 | BIT14 | BIT13 | BIT12 | BIT11),
+ (UINT32) (Depth << 11)
+ );
+ }
+
+ if (EnableJitter) {
+ for (i = 0; i < LaneListLength; ++i) {
+ Lane = LaneList[i];
+ McD1PciCfg32Or (R_SA_PEG_AFELN0CFG0_OFFSET + (Lane * LANE_STEP), BIT10);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+EnableTxJitterInjection (
+ IN UINT8 Lane,
+ IN BOOLEAN EnableTxJitter
+ )
+{
+ UINT8 Bundle;
+
+ Bundle = Lane / 2;
+
+ if (EnableTxJitter) {
+ McD1PciCfg32AndThenOr (
+ R_SA_PEG_AFEBND0CFG0_OFFSET + (Bundle * BUNDLE_STEP),
+ ~(BIT1 | BIT2),
+ 0x6
+ );
+ } else {
+ McD1PciCfg32And (
+ R_SA_PEG_AFEBND0CFG0_OFFSET + (Bundle * BUNDLE_STEP),
+ ~(BIT1 | BIT2)
+ );
+ }
+}
+
+
+VOID
+ConfigureTxJitterMux (
+ IN UINT8 Lane,
+ IN UINT32 MchBar
+ )
+{
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ UINT32 SequenceId;
+
+ CpuFamilyId = GetCpuFamily ();
+ CpuSteppingId = GetCpuStepping ();
+ SequenceId = V_SA_VCU_SEQID_SET_TXJITTER_MUX;
+
+#ifndef AMI_OVERRIDE_FOR_ULT_FASTBOOT
+ if (CpuFamilyId == EnumCpuHswUlt) return;
+#endif // AMI_OVERRIDE_FOR_ULT_FASTBOOT
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV1, SequenceId);
+ } else {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_OPEN_SEQ_REV2, SequenceId);
+ }
+
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_SET_TXJITTER_MUX, Lane);
+
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV1, 0);
+ } else {
+ SendVcuApiCmd (MchBar, V_SA_VCU_OPCODE_CLOSE_SEQ_REV2, 0);
+ }
+
+ return;
+}
+
+EFI_STATUS
+GetBundleList (
+ IN UINT8 *LaneList,
+ IN UINT8 LaneListLength,
+ OUT UINT8 *BundleList,
+ OUT UINT8 *BundleListLength
+ )
+{
+ UINT8 Bundle;
+ BOOLEAN HasBundle;
+ UINT8 i;
+ UINT8 j;
+
+ (*BundleListLength) = 0;
+
+ for (i = 0; i < LaneListLength; ++i) {
+ Bundle = LaneList[i] / 2;
+
+ HasBundle = FALSE;
+ for (j = 0; j < (*BundleListLength); ++j) {
+ if (BundleList[j] == Bundle) {
+ HasBundle = TRUE;
+ break;
+ }
+ }
+
+ if (!HasBundle) {
+ BundleList[*BundleListLength] = Bundle;
+ ++(*BundleListLength);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+#endif // PEG_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c
new file mode 100644
index 0000000..6123968
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/PcieTrainingPhase3.c
@@ -0,0 +1,657 @@
+/** @file
+ This driver trains the PEG interface.
+
+@copyright
+ Copyright (c) 2012 - 2014 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 "PcieTraining.h"
+
+#ifdef PEG_FLAG
+
+#include EFI_PPI_DEFINITION (PchMeUma)
+#include "PchMeUma.h"
+
+typedef struct _MARGIN_DATA {
+ UINT8 Preset;
+ INT32 TimingMargin[SA_PEG_MAX_LANE];
+} MARGIN_DATA;
+
+UINT8
+SelectBestPresetForLane (
+ IN PORT_INFO *PortInfo,
+ IN UINT8 Lane,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN SA_DATA_HOB *SaDataHob,
+ IN UINT8 TrainingPreset
+ )
+{
+ UINT8 BestPreset;
+
+ ///
+ /// Init to EV default
+ ///
+ BestPreset = 7;
+
+ ///
+ /// EnableMargin FoundUsablePreset SaDataHob
+ /// Y Y !NULL -> Use training results; update SaDataHob
+ /// Y Y NULL -> Use training results
+ /// Y N !NULL -> Use Policy value; update SaDataHob
+ /// X N NULL -> Use Policy value
+ /// N X !NULL -> Restore from SaDataHob
+ ///
+ if (Lane < SA_PEG_MAX_LANE) {
+ DEBUG ((EFI_D_INFO, "Preset for Lane %2d: ", Lane));
+ if ((PortInfo->EnableMargin) && (PortInfo->FoundUsablePreset)) {
+ ///
+ /// Use the best preset found during training
+ ///
+ BestPreset = TrainingPreset;
+ DEBUG ((EFI_D_INFO, "Search Result: P%d", BestPreset));
+ if (SaDataHob != NULL) {
+ DEBUG ((EFI_D_INFO, ". Saving value for next boot."));
+ SaDataHob->PegData.BestPreset[Lane] = BestPreset;
+ }
+ } else if ((PortInfo->EnableMargin) && (!PortInfo->FoundUsablePreset) && (SaDataHob != NULL)) {
+ ///
+ /// Use the policy value; update SaDataHob
+ ///
+ BestPreset = (UINT8) SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[Lane];
+ DEBUG ((EFI_D_INFO, "Applying Policy value: P%d. Saving value for next boot.", BestPreset));
+ SaDataHob->PegData.BestPreset[Lane] = BestPreset;
+ } else if ((!PortInfo->FoundUsablePreset) && (SaDataHob == NULL)) {
+ ///
+ /// Use the policy value
+ ///
+ BestPreset = (UINT8) SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[Lane];
+ DEBUG ((EFI_D_INFO, "Applying Policy value: P%d", BestPreset));
+ } else if ((!PortInfo->EnableMargin) && (SaDataHob != NULL)) {
+ ///
+ /// Use the preset found on a previous boot
+ ///
+ BestPreset = (UINT8) SaDataHob->PegData.BestPreset[Lane];
+ DEBUG ((EFI_D_INFO, "Restoring previous value: P%d", BestPreset));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ } else {
+ ///
+ /// Error: Non-existent lane
+ ///
+ DEBUG ((EFI_D_ERROR, "Illegal Lane: %d", Lane));
+ }
+
+ return BestPreset;
+}
+
+VOID
+PegGen3PresetSearch (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN PEI_STALL_PPI *StallPpi,
+ SA_DATA_HOB *SaDataHob
+ )
+{
+ UINT8 Index;
+ INT32 MarginScore;
+ UINT8 PegBus;
+ UINT8 PegDev;
+ UINT8 PegFunc;
+ UINT16 LinkStatus;
+ BOOLEAN LoadedSavedPreset;
+ BOOLEAN EndpointDeviceChanged;
+ UINT8 TempIndex;
+ BOOLEAN SkipBundle0;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ MARGIN_DATA MarginData[MAX_PRESETS];
+ PORT_INFO PortInfoList[SA_PEG_MAX_FUN];
+ INT32 LaneScores[SA_PEG_MAX_LANE];
+ INT32 BestScores[SA_PEG_MAX_LANE];
+ UINT8 BestPresets[SA_PEG_MAX_LANE];
+ EFI_STATUS Status;
+ UINT32 MonitorPort;
+ UINT8 PortInfoListLength;
+ UINT8 PortIndex;
+ UINT8 Lane;
+ BOOLEAN AnyGen3CapableLinks;
+ BOOLEAN AnyMarginingNeeded;
+ UINT8 PreCursor;
+ UINT8 Cursor;
+ UINT8 PostCursor;
+ UINT8 FullSwing;
+ UINT32 NominalRecoveryCount;
+ UINT8 FirstSkippedLane;
+ UINT8 LastSkippedLane;
+ UINT32 Data32;
+ BOOLEAN SlotResetNeeded;
+ PCH_ME_UMA_PPI *PchMeUmaPpi;
+ UINT8 DetectedReplacedCpu;
+
+ AnyMarginingNeeded = FALSE;
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// Setup default presets to search
+ ///
+ MarginData[0].Preset = 7;
+ MarginData[1].Preset = 3;
+ MarginData[2].Preset = 5;
+
+ ///
+ /// Initialize Arrays
+ ///
+ for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) {
+ LaneScores[Lane] = -1;
+ BestScores[Lane] = -1;
+ BestPresets[Lane] = MarginData[0].Preset;
+ }
+
+ DEBUG ((EFI_D_INFO, "PEG Gen3 Preset Search\n"));
+
+ if (!SaPolicyEnablesGen3 (SaPlatformPolicyPpi)) {
+ DEBUG ((EFI_D_INFO, " Gen3 is disabled by policy\n"));
+ return;
+ }
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswB0)) {
+ DEBUG ((EFI_D_WARN, " Gen3 preset search is not supported on this stepping\n"));
+ return;
+ }
+ Data32 = (McD1PciCfg32 (R_SA_PEG_PEGTST_OFFSET) & BIT20) >> 20;
+ if (Data32 != 0) {
+ DEBUG ((EFI_D_WARN, " Gen3 preset search does not support lane reversal\n"));
+ return;
+ }
+
+ ///
+ /// If ME is supported and the CPU has been replaced, redo the Preset Search.
+ /// Note that calling CpuReplacementCheck() can induce an ME-required warm reset.
+ ///
+ DetectedReplacedCpu = 0;
+ Status = EFI_SUCCESS;
+
+ if ((SaDataHob != NULL) && (SaDataHob->PegDataValid)) {
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPchMeUmaPpiGuid, 0, NULL, &PchMeUmaPpi);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "Calling CpuReplacementCheck\n"));
+ Status = PchMeUmaPpi->CpuReplacementCheck (PeiServices, NULL, &DetectedReplacedCpu);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, " ME reported CPU Replacement value: %x\n", DetectedReplacedCpu));
+ }
+
+ ///
+ /// Get the furcation setup and port information
+ ///
+ GetPortInfo (&(PortInfoList[0]), &PortInfoListLength, &SkipBundle0);
+
+ ///
+ /// Make sure we at Gen3 before starting, if not attempt reset and see if that helps
+ ///
+ SlotResetNeeded = FALSE;
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET);
+ if (((LinkStatus & 0x0F) != 3) && ((PortInfoList[PortIndex]).LinkIsGen3Capable)) {
+ SlotResetNeeded = TRUE;
+ break;
+ }
+ }
+ if (SlotResetNeeded) {
+ ///
+ /// Bypass phase2 and assert slot reset
+ ///
+ McD1PciCfg32Or (R_SA_PEG_EQCFG_OFFSET, BIT15);
+ Status = TogglePegSlotReset (PeiServices, StallPpi, SaPlatformPolicyPpi);
+ if (!EFI_ERROR (Status)) {
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ ///
+ /// Wait for Equalization Done
+ ///
+ while (((MmPci32 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS2_OFFSET) >> 1) & 0x1) != 0x1);
+ ///
+ /// Wait for flow control credits exchange
+ ///
+ WaitForVc0Negotiation (PeiServices, StallPpi, PegBus, PegDev, PegFunc);
+ }
+ }
+ }
+
+ ///
+ /// Determine which PEG ports require testing
+ ///
+ AnyGen3CapableLinks = FALSE;
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+
+ ///
+ /// If we already have Best Preset value from previous boot, use it and skip PresetSearch when end point device no change
+ ///
+ LoadedSavedPreset = FALSE;
+ EndpointDeviceChanged = TRUE;
+ if (SaDataHob != NULL) {
+ if (SaDataHob->PegDataValid) {
+ LoadedSavedPreset = TRUE;
+ if (SaDataHob->PegData.EndPointVendorIdDeviceId[PegFunc] == (PortInfoList[PortIndex]).EndPointVendorIdDeviceId) {
+ EndpointDeviceChanged = FALSE;
+ }
+ }
+ if (EndpointDeviceChanged) {
+ ///
+ /// Save new device ID vendor ID
+ ///
+ SaDataHob->PegData.EndPointVendorIdDeviceId[PegFunc] = (PortInfoList[PortIndex]).EndPointVendorIdDeviceId;
+ }
+ }
+ DEBUG ((EFI_D_INFO, " PEG%x%x (%x:%x:%x) - LoadedSavedPreset = %d. EndpointDeviceChanged = %d.\n",
+ PegDev, PegFunc, PegBus, PegDev, PegFunc, LoadedSavedPreset, EndpointDeviceChanged));
+
+ ReportPcieLinkStatus (PegBus, PegDev, PegFunc);
+
+ if ( (!LoadedSavedPreset) ||
+ (EndpointDeviceChanged) ||
+ (DetectedReplacedCpu != 0) ||
+ ((SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) &&
+ (SaPlatformPolicyPpi->PcieConfig->PegGen3ForcePresetSearch == 1 ))) {
+ (PortInfoList[PortIndex]).EnableMargin = TRUE;
+ } else {
+ (PortInfoList[PortIndex]).EnableMargin = FALSE;
+ }
+
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ (PortInfoList[PortIndex]).EnableMargin = FALSE;
+ } else {
+ AnyGen3CapableLinks = TRUE;
+ }
+ } ///< PegFunc Loop end
+
+ if (!AnyGen3CapableLinks) {
+ DEBUG ((EFI_D_INFO, "Skipping Preset Search - No Gen3 capable links\n"));
+ return;
+ }
+
+ ///
+ /// Determine if any ports need to be trained.
+ /// If any ports are trained, the corresponding endpoint should also be reset with PERST#.
+ ///
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ if ((PortInfoList[PortIndex]).EnableMargin == TRUE) {
+ AnyMarginingNeeded = TRUE;
+ break;
+ }
+ }
+
+ if (AnyMarginingNeeded) {
+ MonitorPort = OpenMonitor (PeiServices, SaPlatformPolicyPpi, StallPpi);
+
+ McD1PciCfg32Or (R_SA_PEG_REUT_PH_CTR_OFFSET, B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK);
+
+ ///
+ /// Presets Loop start
+ ///
+ for (Index = 0; Index < MAX_PRESETS; Index++) {
+ ///
+ /// Clear out old values
+ ///
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_LANE; TempIndex++) {
+ MarginData[Index].TimingMargin[TempIndex] = 0;
+ } ///< End of for each Lane
+
+
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ (PortInfoList[PortIndex]).SkipMargin = FALSE;
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ DEBUG ((EFI_D_INFO, "Skipping PEG%d%d - Not Gen3 capable\n", PegDev, PegFunc));
+ continue;
+ }
+
+ ///
+ /// Find first lane of the port for coefficient programming
+ ///
+ switch (PegFunc) {
+ default:
+ case 0:
+ Lane = 0;
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ Lane = 8;
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ Lane = 12;
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+
+ ///
+ /// Get FullSwing
+ ///
+ GetLinkPartnerFullSwing (Lane, &FullSwing);
+
+ ///
+ /// Get Coefficients
+ ///
+ GetCoefficientsFromPreset (MarginData[Index].Preset, FullSwing, &PreCursor, &Cursor, &PostCursor);
+
+ ///
+ /// Set Lane's Coefficients
+ ///
+ if (SkipBundle0) {
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ SetPartnerTxCoefficients (TempIndex, &PreCursor, &Cursor, &PostCursor);
+ ProgramPreset (1, MarginData[Index].Preset, PegFunc, TempIndex);
+ }
+ }
+ for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) {
+ SetPartnerTxCoefficients ((PortInfoList[PortIndex]).LaneList[TempIndex], &PreCursor, &Cursor, &PostCursor);
+ ProgramPreset (1, MarginData[Index].Preset, PegFunc, (PortInfoList[PortIndex]).LaneList[TempIndex]);
+ }
+
+ ///
+ /// Set DOEQ bit
+ ///
+ MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0);
+ RetrainLink (PeiServices, StallPpi, &((PortInfoList[PortIndex]).PegPort));
+
+ ///
+ /// Get the current link status
+ ///
+ LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET);
+ ///
+ /// No need to margin if couldn't get to Gen3 with this preset
+ ///
+ if ((LinkStatus & 0x0F) != 3) {
+ RecoverLinkFailure (PeiServices, SaPlatformPolicyPpi, SaDataHob, StallPpi,
+ &((PortInfoList[PortIndex]).PegPort), 3,
+ GetNegotiatedWidth (&((PortInfoList[PortIndex]).PegPort)));
+ LinkStatus = MmPci16 (0, PegBus, PegDev, PegFunc, R_SA_PEG_LSTS_OFFSET);
+ if ((LinkStatus & 0x0F) != 3) {
+ (PortInfoList[PortIndex]).SkipMargin = TRUE;
+ continue;
+ }
+ }
+
+ NominalRecoveryCount = SaPcieGetErrorCount (MonitorPort, PegFunc);
+ StallPpi->Stall (PeiServices, StallPpi, SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchDwellTime * STALL_ONE_MICRO_SECOND);
+ NominalRecoveryCount = SaPcieGetErrorCount (MonitorPort, PegFunc) - NominalRecoveryCount;
+ if (NominalRecoveryCount > 0) {
+ (PortInfoList[PortIndex]).SkipMargin = TRUE;
+ continue;
+ }
+ (PortInfoList[PortIndex]).FoundUsablePreset = TRUE;
+ } ///< End of for each Port
+
+ Status = RunMarginTest (
+ PeiServices,
+ SaPlatformPolicyPpi,
+ SaDataHob,
+ StallPpi,
+ MonitorPort,
+ &(PortInfoList[0]),
+ PortInfoListLength,
+ LaneLevelRxJitter,
+ MarginData[Index].TimingMargin
+ );
+
+ if (EFI_ERROR (Status)) {
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_LANE; TempIndex++) {
+ MarginData[Index].TimingMargin[TempIndex] = 0;
+ }
+ }
+ } ///< Presets Loop end
+
+ McD1PciCfg32And (R_SA_PEG_REUT_PH_CTR_OFFSET, ~B_SA_PEG_REUT_PH_CTR_AUTOCOMP_MASK);
+ CloseMonitor (SaPlatformPolicyPpi, MonitorPort);
+
+ ///
+ /// Find the preset with the maximum margin (largest of all margin values)
+ ///
+ for (Index = 0; Index < sizeof (MarginData) / sizeof (MarginData[0]); Index++) {
+ for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) {
+ LaneScores[Lane] = -1;
+ }
+ for (Lane = 0; Lane < SA_PEG_MAX_LANE; Lane++) {
+ if (MarginData[Index].TimingMargin[Lane] != -1) {
+ MarginScore = MarginData[Index].TimingMargin[Lane];
+ LaneScores[Lane] = MarginScore;
+ }
+ if (LaneScores[Lane] > BestScores[Lane]) {
+ BestScores[Lane] = LaneScores[Lane];
+ BestPresets[Lane] = MarginData[Index].Preset;
+ }
+ } ///< End of for each Lane
+ } ///< End of for each Preset
+
+ ///
+ /// If Lanes 0-1 were skipped, copy the values from Lane 2
+ ///
+ if (SkipBundle0) {
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ switch (PegFunc) {
+ default:
+ case 0:
+ Lane = 2;
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ Lane = 10;
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ Lane = 14;
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+ if (BestScores[Lane] != -1) {
+ DEBUG ((EFI_D_INFO, "Using Lane %2d's Best Preset for Lanes %2d-%2d.\n", Lane, FirstSkippedLane, LastSkippedLane));
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ BestScores[TempIndex] = BestScores[Lane];
+ BestPresets[TempIndex] = BestPresets[Lane];
+ }
+ }
+ } ///< End of for each port
+ } ///< End of SkipBundle0
+ } ///< End of AnyMarginingNeeded
+
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ continue;
+ }
+ if (SkipBundle0) {
+ switch (PegFunc) {
+ default:
+ case 0:
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ BestPresets[TempIndex] = SelectBestPresetForLane (
+ &(PortInfoList[PortIndex]),
+ TempIndex,
+ SaPlatformPolicyPpi,
+ SaDataHob,
+ BestPresets[TempIndex]
+ );
+ }
+ }
+ for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) {
+ BestPresets[(PortInfoList[PortIndex]).LaneList[TempIndex]] = SelectBestPresetForLane (
+ &(PortInfoList[PortIndex]),
+ (PortInfoList[PortIndex]).LaneList[TempIndex],
+ SaPlatformPolicyPpi,
+ SaDataHob,
+ BestPresets[(PortInfoList[PortIndex]).LaneList[TempIndex]]
+ );
+ }
+ }
+
+ ///
+ /// Program the presets. If any link was margined, also reset the
+ /// endpoints in order to return the endpoints to a known-good state.
+ ///
+ if (AnyMarginingNeeded) {
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_FUN; TempIndex++) {
+ MmPci16Or (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, TempIndex, R_SA_PEG_LCTL_OFFSET, BIT4);
+ }
+ AssertPegSlotReset (SaPlatformPolicyPpi);
+ }
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ if (!(PortInfoList[PortIndex]).LinkIsGen3Capable) {
+ DEBUG ((EFI_D_INFO, "PEG%d%d - Not Gen3 capable, skip coefficient programming.\n", PegDev, PegFunc));
+ continue;
+ }
+ ///
+ /// Find first lane of the port for coefficient programming
+ ///
+ switch (PegFunc) {
+ default:
+ case 0:
+ Lane = 0;
+ FirstSkippedLane = 0;
+ LastSkippedLane = 1;
+ break;
+ case 1:
+ Lane = 8;
+ FirstSkippedLane = 8;
+ LastSkippedLane = 9;
+ break;
+ case 2:
+ Lane = 12;
+ FirstSkippedLane = 12;
+ LastSkippedLane = 13;
+ break;
+ }
+ ///
+ /// Get FullSwing
+ ///
+ GetLinkPartnerFullSwing (Lane, &FullSwing);
+
+ if (SkipBundle0) {
+ for (TempIndex = FirstSkippedLane; TempIndex <= LastSkippedLane; TempIndex++) {
+ GetCoefficientsFromPreset (BestPresets[TempIndex], FullSwing, &PreCursor, &Cursor, &PostCursor);
+ SetPartnerTxCoefficients (TempIndex, &PreCursor, &Cursor, &PostCursor);
+ ProgramPreset (1, BestPresets[TempIndex], PegFunc, TempIndex);
+ }
+ }
+ for (TempIndex = 0; TempIndex < (PortInfoList[PortIndex]).LaneListLength; TempIndex++) {
+ ///
+ /// Get Coefficients
+ ///
+ GetCoefficientsFromPreset (BestPresets[((PortInfoList[PortIndex]).LaneList[TempIndex])], FullSwing, &PreCursor, &Cursor, &PostCursor);
+
+ ///
+ /// Set Lane's Coefficients
+ ///
+ SetPartnerTxCoefficients ((PortInfoList[PortIndex]).LaneList[TempIndex], &PreCursor, &Cursor, &PostCursor);
+
+ ///
+ /// Set Phase 1 Presets
+ ///
+ ProgramPreset (1, BestPresets[((PortInfoList[PortIndex]).LaneList[TempIndex])], PegFunc, (PortInfoList[PortIndex]).LaneList[TempIndex]);
+ }
+
+ MmPci32Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL3_OFFSET, BIT0); ///< DOEQ
+ MmPci16Or (0, PegBus, PegDev, PegFunc, R_SA_PEG_LCTL_OFFSET, BIT5); ///< Retrain link
+ }
+
+ if (AnyMarginingNeeded) {
+ StallPpi->Stall (PeiServices, StallPpi, 100 * STALL_ONE_MICRO_SECOND);
+ for (TempIndex = 0; TempIndex < SA_PEG_MAX_FUN; TempIndex++) {
+ MmPci16And (0, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, TempIndex, R_SA_PEG_LCTL_OFFSET, (UINT16) ~(BIT4));
+ }
+ DeassertPegSlotReset (SaPlatformPolicyPpi);
+ }
+
+ for (PortIndex = 0; PortIndex < PortInfoListLength; PortIndex++) {
+ PegBus = (PortInfoList[PortIndex]).PegPort.Bus;
+ PegDev = (PortInfoList[PortIndex]).PegPort.Device;
+ PegFunc = (PortInfoList[PortIndex]).PegPort.Function;
+ WaitForL0 (PeiServices, StallPpi, &(PortInfoList[PortIndex].PegPort), FALSE);
+ ReportPcieLinkStatus (PegBus, PegDev, PegFunc);
+ }
+
+ DEBUG ((EFI_D_INFO, "PEG Gen3 Preset Search done\n\n"));
+
+ return;
+}
+
+BOOLEAN
+SaPolicyEnablesGen3 (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ UINTN PegPortGenx;
+ BOOLEAN Gen3Enabled;
+ UINT8 Index;
+
+ Gen3Enabled = FALSE;
+
+ ///
+ /// Check if Gen3 is enabled on PEG10/11/12
+ ///
+ for (Index = 0; Index < SA_PEG_MAX_FUN; Index++) {
+ ///
+ /// PegPortGenx: 0 = Auto, 1 = Gen1, 2 = Gen2, 3 = Gen3
+ ///
+ PegPortGenx = SaPlatformPolicyPpi->PcieConfig->PegGenx[Index];
+
+ ///
+ /// Check if the root port is present and the speed is not limited to Gen1/Gen2
+ ///
+ if ((PegPortGenx == PEG_AUTO) || (PegPortGenx == PEG_GEN3)) {
+ Gen3Enabled = TRUE;
+ break;
+ }
+ }
+ return Gen3Enabled;
+}
+
+#endif // PEG_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.c
new file mode 100644
index 0000000..ea817d8
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.c
@@ -0,0 +1,450 @@
+/** @file
+ SA Dmi PEI Initialization library
+
+@copyright
+ Copyright (c) 1999 - 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 "SaDmiPeim.h"
+#include "PciExpressInit.h"
+
+///
+/// Functions
+///
+/**
+ Initialize DMI Tc/Vc mapping through SA-PCH.
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+SaDmiTcVcInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ EFI_STATUS Status;
+ UINT64 MchBar;
+ UINT64 DmiBar;
+ PCH_INIT_PPI *PchInitPpi;
+ PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi;
+ CPU_FAMILY CpuFamilyId;
+ UINT8 i;
+
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+ DmiBar = McD0PciCfg64 (R_SA_DMIBAR) &~BIT0;
+ CpuFamilyId = GetCpuFamily();
+
+ ///
+ /// Locate PchInitPpi and PchDmiTcVcMapPpi
+ ///
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPchInitPpiGuid, 0, NULL, (VOID **) &PchInitPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPchDmiTcVcMapPpiGuid, 0, NULL, (VOID **) &PchDmiTcVcMapPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// SA OPI Initialization
+ ///
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ MmioOr8 ((UINTN) (DmiBar + 0xA78), BIT1);
+ }
+
+ ///
+ /// Update DmiTcVcMapping based on Policy
+ ///
+ PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVc1].Enable = (BOOLEAN) SaPlatformPolicyPpi->PcieConfig->DmiVc1;
+ PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcp].Enable = (BOOLEAN) SaPlatformPolicyPpi->PcieConfig->DmiVcp;
+ PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcm].Enable = (BOOLEAN) SaPlatformPolicyPpi->PcieConfig->DmiVcm;
+
+ for (i = 0; i < DmiTcTypeMax; i++) {
+ if (((PchDmiTcVcMapPpi->DmiTc[i].Vc == DmiVcTypeVc1) && (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVc1].Enable == FALSE)) ||
+ ((PchDmiTcVcMapPpi->DmiTc[i].Vc == DmiVcTypeVcp) && (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcp].Enable == FALSE)) ||
+ ((PchDmiTcVcMapPpi->DmiTc[i].Vc == DmiVcTypeVcm) && (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVcm].Enable == FALSE))
+ ) {
+ PchDmiTcVcMapPpi->DmiTc[i].Vc = DmiVcTypeVc0;
+ }
+ }
+ ///
+ /// Program NB TC/VC mapping
+ ///
+ SaSetDmiTcVcMapping (PchDmiTcVcMapPpi, DmiBar);
+
+ ///
+ /// Call PchDmiTcVcProgPoll
+ ///
+ Status = PchInitPpi->DmiTcVcProgPoll (PeiServices);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Poll NB negotiation completion
+ ///
+ SaPollDmiVcStatus (PchDmiTcVcMapPpi, DmiBar);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Map SA DMI TCs to VC
+
+ @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI
+ @param[in] DmiBar - DMIBAR address
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Wrong phase parameter passed in.
+**/
+EFI_STATUS
+SaSetDmiTcVcMapping (
+ IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi,
+ IN UINT64 DmiBar
+ )
+{
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT8 Data8And;
+ UINT8 Data8Or;
+ UINT8 Index;
+ UINT16 Register;
+ UINT8 VcId;
+ UINT8 VcMap[DmiVcTypeMax] = { 0 };
+
+ ///
+ /// Set the TC/VC mappings
+ ///
+ for (Index = 0; Index < DmiTcTypeMax; Index++) {
+ VcMap[PchDmiTcVcMapPpi->DmiTc[Index].Vc] |= (BIT0 << Index);
+ }
+ ///
+ /// System BIOS must perform the following steps for VC0 configuration.
+ /// Program the TCs/VC0 map by setting DMIBAR offset 014h [7:1] = '0111 101b'.
+ ///
+ /// Private Virtual Channel Configuration
+ /// Step1. Assign Virtual Channel ID 2 to VCp:
+ /// Programming the DMIVCPRCTL DMI Port Register DMIBAR Offset 02Ch[26:24] = '010b'.
+ ///
+ /// Step2. Set TC2 to VCp:
+ /// Program the DMIVCPRCTL DMI Port Register DMIBAR offset 02Ch [7:1] = '0000 010b'.
+ ///
+ /// Step3. Enable VCp by programming the DMIVCPRCTL DMI Port Register DMIBAR Offset 02Ch[31] = '1b'.
+ ///
+ /// Virtual Channel for ME (VCm) Configuration
+ /// This is configured by ConfigMemMe
+ ///
+ /// Step1. Assign Virtual Channel ID 7 to VCm:
+ /// Programming the DMIVCMRCTL DMI Port Register DMIBAR Offset 038h[26:24] = '111b'.
+ ///
+ /// Step2. Enable VCm:
+ /// Programming the DMIVMPRCTL DMI Port Register DMIBAR Offset 038h[31] = '1b'.
+ ///
+ /// Step3. Enable VCm by programming the DMIVCMRCTL DMI Port Register DMIBAR Offset 038h[31] = '1b'.
+ ///
+ for (Index = 0; Index < DmiVcTypeMax; Index++) {
+ if (PchDmiTcVcMapPpi->DmiVc[Index].Enable == PCH_DEVICE_ENABLE) {
+ ///
+ /// Map TCs to VC, Set the VC ID, Enable VC
+ ///
+ VcId = PchDmiTcVcMapPpi->DmiVc[Index].VcId,
+
+ Data32And = (UINT32) (~(V_SA_DMIBAR_DMIVCCTL_ID | B_SA_DMIBAR_DMIVCCTL_TVM_MASK));
+ Data32Or = VcId << N_SA_DMIBAR_DMIVCCTL_ID;
+ Data32Or |= VcMap[Index];
+ Data32Or |= N_SA_DMIBAR_DMIVCCTL_EN;
+
+ switch (Index) {
+ case DmiVcTypeVc0:
+ Register = R_SA_DMIBAR_DMIVC0RCTL_OFFSET;
+ break;
+
+ case DmiVcTypeVc1:
+ Register = R_SA_DMIBAR_DMIVC1RCTL_OFFSET;
+ break;
+
+ case DmiVcTypeVcp:
+ Register = R_SA_DMIBAR_DMIVCPRCTL_OFFSET;
+ break;
+
+ case DmiVcTypeVcm:
+ Register = R_SA_DMIBAR_DMIVCMRCTL_OFFSET;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MmioAndThenOr32 ((UINTN) (DmiBar + Register), Data32And, Data32Or);
+ }
+ }
+ ///
+ /// System BIOS must program the extended VC Count:
+ /// Set the DMI Port Register DMIBAR Offset 004h[2:0]=001b
+ ///
+ Data8And = (UINT8) (~0x07);
+ if (PchDmiTcVcMapPpi->DmiVc[DmiVcTypeVc1].Enable == TRUE) {
+ Data8Or = 1;
+ } else {
+ Data8Or = 0;
+ }
+
+ MmioAndThenOr8 ((UINTN) (DmiBar + R_SA_DMIBAR_DMIPVCCAP1_OFFSET), Data8And, Data8Or);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Poll SA DMI negotiation completion
+
+ @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI
+ @param[in] DmiBar - DMIBAR address
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Wrong phase parameter passed in.
+**/
+EFI_STATUS
+SaPollDmiVcStatus (
+ IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi,
+ IN UINT64 DmiBar
+ )
+{
+ UINT8 Index;
+ UINT16 Register;
+
+ ///
+ /// 6.2.3.2 - Step 4, Poll until VC1 has been negotiated
+ /// Read the DMIVC1RSTS DMI Port Register Offset 026h until [1]==0
+ ///
+ /// 6.2.3.3 - Step4. Poll the VCp Negotiation Pending bit until it reads 0:
+ /// Read the DMIVCPRSTS DMI Port Register Offset 032h until [1]==0
+ ///
+ /// 6.2.3.4 - Step4. Poll the VCm Negotiation Pending bit until it reads 0:
+ /// Read the DMIVCMRSTS DMI Port Register Offset 03Eh until [1]==0
+ ///
+ for (Index = 0; Index < DmiVcTypeMax; Index++) {
+ if (PchDmiTcVcMapPpi->DmiVc[Index].Enable == PCH_DEVICE_ENABLE) {
+ switch (Index) {
+ case DmiVcTypeVc0:
+ Register = R_SA_DMIBAR_DMIVC0RSTS_OFFSET;
+ break;
+
+ case DmiVcTypeVc1:
+ Register = R_SA_DMIBAR_DMIVC1RSTS_OFFSET;
+ break;
+
+ case DmiVcTypeVcp:
+ Register = R_SA_DMIBAR_DMIVCPRSTS_OFFSET;
+ break;
+
+ case DmiVcTypeVcm:
+ Register = R_SA_DMIBAR_DMIVCMRSTS_OFFSET;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ ///
+ /// Wait for negotiation to complete
+ ///
+ while ((MmioRead16 ((UINTN) (DmiBar + Register)) & B_SA_DMIBAR_DMISTS_NP) != 0);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+#ifdef DMI_FLAG
+/**
+ Initialize DMI.
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+DmiInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ EFI_STATUS Status;
+ UINT64 MchBar;
+ UINT64 DmiBar;
+ PCH_INIT_PPI *PchInitPpi;
+ PCH_PLATFORM_POLICY_PPI *PchPlatformPolicyPpi;
+ UINT8 CpuSteppingId;
+ BOOLEAN DmiGen2Enable;
+ UINT16 LinkStatus;
+ UINT32 Data32Or;
+
+ ///
+ /// Read the CPU stepping
+ ///
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// BridgeId = (UINT8) (McD0PciCfg16 (R_MC_DEVICE_ID) & 0xF0);
+ /// BridgeSteppingId = BridgeId + CpuSteppingId;
+ ///
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+ DmiBar = McD0PciCfg64 (R_SA_DMIBAR) &~BIT0;
+
+ ///
+ /// Get RCBA through the PchPlatformPolicy PPI
+ ///
+ Status = (**PeiServices).LocatePpi (
+ PeiServices,
+ &gPchPlatformPolicyPpiGuid,
+ 0,
+ NULL,
+ &PchPlatformPolicyPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Can't locate PchPlatformPolicy PPI - exiting.\n"));
+ return Status;
+ }
+ ///
+ /// Perform DMI Recipe steps
+ ///
+ DEBUG ((EFI_D_INFO, "DMI Recipe...\n"));
+ PegDmiRecipe (SaPlatformPolicyPpi, (UINT32) MchBar, (UINT32) DmiBar, 0, 0);
+
+ ///
+ /// Additional DMI steps. See SA BIOS Spec.
+ ///
+ DEBUG ((EFI_D_INFO, "Run AdditionalDmiProgramSteps!\n"));
+ AdditionalDmiProgramSteps (SaPlatformPolicyPpi, (UINT32) MchBar, (UINT32) DmiBar);
+
+ DmiGen2Enable = TRUE;
+ if ((SaPlatformPolicyPpi->PcieConfig->DmiGen2 == 0) ||
+ ((MmioRead8 ((UINTN) PchPlatformPolicyPpi->Rcba + R_PCH_RCRB_LCAP) & (BIT0 | BIT1 | BIT2 | BIT3)) == 0x1) ||
+ (McDevFunPciCfg32 (0, 0, 0, R_SA_MC_CAPID0_A_OFFSET) & BIT22)
+ ) {
+ DEBUG ((EFI_D_WARN, "DMI Gen2 is Disabled or not capable, staying at Gen1 !\n"));
+ DmiGen2Enable = FALSE;
+ }
+
+ if (DmiGen2Enable) {
+ ///
+ /// Locate PchInitPpi
+ ///
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gPchInitPpiGuid, 0, NULL, &PchInitPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Program PCH TLS to Gen 2
+ ///
+ PchInitPpi->DmiGen2Prog (PeiServices);
+
+ ///
+ /// Program CPU Max Link Speed to Gen 2
+ ///
+ MmioAndThenOr32 ((UINTN) (DmiBar + R_SA_DMIBAR_LCAP_OFFSET), (UINT32)~0xF, 2);
+ }
+ Data32Or = (MmioRead32 ((UINTN) (DmiBar + R_SA_DMIBAR_LCAP_OFFSET)) & (BIT3 | BIT2 | BIT1 | BIT0));
+ MmioAndThenOr32 ((UINTN) (DmiBar + R_SA_DMIBAR_LCTL2_OFFSET), (UINT32)~(BIT3 | BIT2 | BIT1 | BIT0), Data32Or);
+
+ ///
+ /// Retrain link
+ ///
+ DmiLinkTrain (DmiBar);
+
+ ///
+ /// Retrain link if it is GEN2 Capable and it is not yet set to GEN2
+ ///
+ if (DmiGen2Enable &&
+ ((((MmioRead16 ((UINTN) (DmiBar + R_SA_DMIBAR_LSTS_OFFSET))) & 0x0F) != DMI_GEN2) ||
+ (((MmioRead16 ((UINTN) PchPlatformPolicyPpi->Rcba + R_PCH_RCRB_LSTS)) & 0x0F) != DMI_GEN2))
+ ) {
+ DEBUG ((EFI_D_INFO, "DMI Link re-train to set GEN2\n"));
+ DmiLinkTrain (DmiBar);
+ }
+ ///
+ /// Get the current link status
+ ///
+ LinkStatus = MmioRead16 ((UINTN) (DmiBar + R_SA_DMIBAR_LSTS_OFFSET));
+ DEBUG ((EFI_D_INFO, "DMI trained to x%d at Gen%d\n", (LinkStatus >> 4) & 0x3F, LinkStatus & 0x0F));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ DMI link training
+
+ @param[in] DmiBar - DMIBAR address
+**/
+VOID
+DmiLinkTrain (
+ IN UINT64 DmiBar
+ )
+{
+ ///
+ /// Retrain link
+ ///
+ MmioOr8 ((UINTN) (DmiBar + R_SA_DMIBAR_LCTL_OFFSET), BIT5);
+
+ ///
+ /// Wait for link training complete
+ ///
+ while ((MmioRead16 ((UINTN) (DmiBar + R_SA_DMIBAR_LSTS_OFFSET)) & BIT11) != 0)
+ ;
+}
+
+/**
+ Additional DMI Programming Steps at PEI
+
+ @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] MchBar - MCHBAR address
+ @param[in] DmiBar - DMIBAR address
+**/
+VOID
+AdditionalDmiProgramSteps (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT32 MchBar,
+ IN UINT32 DmiBar
+ )
+{
+ UINT32 Data32And;
+ UINT32 Data32Or;
+
+ ///
+ /// Disable DMI and PEG Debug Align Message - set 0x258[29] = '1b'
+ ///
+ Data32And = (UINT32) ~BIT29;
+ Data32Or = BIT29;
+ Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_CFG4_OFFSET, Data32And, Data32Or);
+
+ ///
+ /// Overwrite DMICC (DMIBAR offset 0x208) to 0x6B5
+ ///
+ Data32And = (UINT32)~(BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ Data32Or = 0x6B5;
+ Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_DMICC_OFFSET, Data32And, Data32Or);
+
+ ///
+ /// Set L0SLAT[15:0] to 0x2020
+ ///
+ Data32And = (UINT32) ~(0xFFFF);
+ Data32Or = 0x00002020;
+ Mmio32AndThenOr (DmiBar, R_SA_DMIBAR_L0SLAT_OFFSET, Data32And, Data32Or);
+}
+#endif // DMI_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.h
new file mode 100644
index 0000000..799eb13
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaDmiPeim.h
@@ -0,0 +1,94 @@
+/** @file
+ Header file for the SA Dmi Init library.
+
+@copyright
+ Copyright (c) 1999 - 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
+**/
+#ifndef _SA_DMI_PEIM_H_
+#define _SA_DMI_PEIM_H_
+
+#include "EdkIIGluePeim.h"
+#include "SaAccess.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+
+///
+/// Driver Consumed PPI Prototypes
+///
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+#include EFI_PPI_DEPENDENCY (PchPlatformPolicy)
+#include EFI_PPI_DEPENDENCY (PchInit)
+#include EFI_PPI_DEPENDENCY (PchDmiTcVcMap)
+
+/**
+ Map SA DMI TCs to VC
+
+ @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI
+ @param[in] DmiBar - DMIBAR address
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+SaSetDmiTcVcMapping (
+ IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi,
+ IN UINT64 DmiBar
+ )
+;
+
+/**
+ Poll SA DMI negotiation completion
+
+ @param[in] PchDmiTcVcMapPpi - Instance of PCH_DMI_TC_VC_PPI
+ @param[in] DmiBar - DMIBAR address
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+SaPollDmiVcStatus (
+ IN PCH_DMI_TC_VC_PPI *PchDmiTcVcMapPpi,
+ IN UINT64 DmiBar
+ )
+;
+
+#ifdef DMI_FLAG
+/**
+ DMI link training
+
+ @param[in] DmiBar - DMIBAR address
+**/
+VOID
+DmiLinkTrain (
+ IN UINT64 DmiBar
+ )
+;
+
+/**
+ Additional DMI Programming Steps at PEI
+
+ @param[in] SaPlatformPolicyPpi - pointer to SA_PLATFORM_POLICY_PPI
+ @param[in] MchBar - MCHBAR address
+ @param[in] DmiBar - DMIBAR address
+**/
+VOID
+AdditionalDmiProgramSteps (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi,
+ IN UINT32 MchBar,
+ IN UINT32 DmiBar
+ )
+;
+#endif // DMI_FLAG
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.c
new file mode 100644
index 0000000..28fc22e
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.c
@@ -0,0 +1,689 @@
+/** @file
+ The PEIM implements the SA PEI Initialization.
+
+@copyright
+ Copyright (c) 1999 - 2013 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 "SaInitPeim.h"
+#ifdef RAPID_START_FLAG
+#include EFI_PPI_CONSUMER (RapidStart)
+#endif
+
+static EFI_PEI_PPI_DESCRIPTOR mSaPeiInitPpi[] = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gSaPeiInitPpiGuid,
+ NULL
+};
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mSaResetCompleteNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gMemoryInitHobGuid,
+ SaResetComplete
+};
+
+EFI_GUID gEfiPeiEndOfPeiPhasePpiGuid = EFI_PEI_END_OF_PEI_PHASE_PPI_GUID;
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mSaS3ResumeNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiEndOfPeiPhasePpiGuid,
+ SaS3ResumeAtEndOfPei
+};
+
+#ifdef RAPID_START_FLAG
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mSaOnRapidStartPpiNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gRapidStartPpiGuid,
+ SaCheckRapidStartMode
+};
+#endif
+
+///
+/// Functions
+///
+static
+EFI_STATUS
+SaS3ResumeAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+/**
+ This function handles SA S3 resume task
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS - Always return EFI_SUCCESS
+**/
+{
+ SA_DATA_HOB *SaDataHob;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuSteppingId = GetCpuStepping();
+ CpuFamilyId = GetCpuFamily();
+ ///
+ /// Get SaPegDataHob HOB
+ ///
+ SaDataHob = NULL;
+ SaDataHob = (SA_DATA_HOB *)GetFirstGuidHob (&gSaDataHobGuid);
+ if (SaDataHob != NULL) {
+ ///
+ /// If there was no DXE mode supported, always enable SMM mode
+ ///
+#if SA_PCIE_ASPM_IN_DXE == 0
+ SaDataHob->InitPcieAspmAfterOprom = 1;
+#endif
+ ///
+ /// If there was no SMM mode supported, always enable DXE mode
+ ///
+#if SA_PCIE_ASPM_IN_SMM == 0
+ SaDataHob->InitPcieAspmAfterOprom = 0;
+#endif
+
+ if ((SaDataHob->SaIotrapSmiAddress != 0) && (SaDataHob->InitPcieAspmAfterOprom == 1)) {
+#if SA_PCIE_ASPM_IN_SMM == 1
+ ///
+ /// Always generate SA IO TRAP SMI when supported
+ /// The SMI handler will directly return if not PCIe ASPM init after Oprom was enabled
+ ///
+ DEBUG ((EFI_D_INFO, "Generate SA IOTRAP SMI port=%X\n", SaDataHob->SaIotrapSmiAddress));
+ IoWrite8 (SaDataHob->SaIotrapSmiAddress, 0);
+#endif
+ }
+ }
+#if SA_PCIE_ASPM_IN_DXE == 1
+ if ((SaDataHob == NULL) || (SaDataHob->InitPcieAspmAfterOprom == 0)) {
+ ///
+ /// When SaDataHob not preset/corrupted or InitPcieAspmAfterOprom set to 0,
+ /// try to do DXE mode S3 resume task.
+ ///
+ ///
+ /// Lock processor/chipset BAR registers
+ /// Other save/restore were done by S3 Save script table
+ ///
+ if (!(((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId <= EnumHswB0) ) ||
+ ((CpuFamilyId == EnumCpuHswUlt) && (CpuSteppingId <= EnumHswUltB0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId <= EnumCrwB0) ) )) {
+ AsmMsrOr64 (0x2e7, 1);
+ }
+ }
+#endif
+ return EFI_SUCCESS;
+}
+
+#ifdef RAPID_START_FLAG
+static
+EFI_STATUS
+SaCheckRapidStartMode (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+/**
+ This function will check Rapid Start mode and install SaS3Resume callback notify if it was Rapid Start Resume
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS - Always return EFI_SUCCESS
+**/
+{
+ RAPID_START_PPI *RapidStartPpi;
+ EFI_STATUS Status;
+
+ ///
+ /// When Rapid Start implemented and in the Rapid Start Resume transition, this SA S3 resume Notify should happen early than Rapid Start End-Of-Pei callback
+ /// This is because Rapid Start End-Of-Pei callback will generate ACPI_ENABLE SMI which should be after SA S3 resume completed.
+ ///
+ Status = PeiServicesLocatePpi (&gRapidStartPpiGuid, 0, NULL, &RapidStartPpi);
+ ASSERT_EFI_ERROR (Status);
+ if (RapidStartPpi->GetMode (RapidStartPpi) == RapidStartExit) {
+ DEBUG ((EFI_D_INFO, "[SA] Install Notify callback for Rapid Start Resume\n"));
+ Status = PeiServicesNotifyPpi (&mSaS3ResumeNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ }
+ return EFI_SUCCESS;
+}
+#endif
+
+EFI_STATUS
+EFIAPI
+SaInitPeiEntryPoint (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+/**
+ SA PEI Initialization.
+
+ @param[in] FfsHeader - Pointer to Firmware File System file header.
+ @param[in] PeiServices - General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS
+**/
+{
+ EFI_STATUS Status;
+ SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi;
+ EFI_BOOT_MODE BootMode;
+#ifdef RAPID_START_FLAG
+ RAPID_START_PPI *RapidStartPpi;
+#endif
+#if defined(DMI_FLAG) || defined(PEG_FLAG)
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = GetCpuFamily();
+#endif // DMI_FLAG || PEG_FLAG
+
+ ///
+ /// Get platform policy settings through the SaPlatformPolicy PPI
+ ///
+ Status = (**PeiServices).LocatePpi (
+ PeiServices,
+ &gSaPlatformPolicyPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &SaPlatformPolicyPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Dump SA Platform Policy
+ ///
+ SaPeiPolicyDump (SaPlatformPolicyPpi);
+
+ ///
+ /// Program SA Bar Registers
+ ///
+ DEBUG ((EFI_D_INFO, "Programming SA Bars\n"));
+ ProgramSaBars (SaPlatformPolicyPpi);
+
+ ///
+ /// Install SA HOBs
+ ///
+ InstallSaHob (PeiServices, SaPlatformPolicyPpi);
+
+ ///
+ /// Report SA PCIe code version
+ ///
+ DEBUG ((EFI_D_INFO, "Reporting SA PCIe code version\n"));
+ ReportPcieVersion (SaPlatformPolicyPpi);
+
+#ifdef DMI_FLAG
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) {
+ ///
+ /// Initialize DMI
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing DMI\n"));
+ DmiInit (PeiServices, SaPlatformPolicyPpi);
+ }
+#endif // DMI_FLAG
+
+#ifdef SG_SUPPORT
+ ///
+ /// Initialize SwitchableGraphics
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing SwitchableGraphics\n"));
+ SwitchableGraphicsInit (PeiServices, SaPlatformPolicyPpi);
+#endif
+
+#ifdef PEG_FLAG
+ if ((CpuFamilyId == EnumCpuHsw) || (CpuFamilyId == EnumCpuCrw)) {
+ ///
+ /// Initialize SA PCIe
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing SA PCIe\n"));
+ PciExpressInit (PeiServices, SaPlatformPolicyPpi);
+ }
+#endif // PEG_FLAG
+
+ ///
+ /// Initialize Graphics (IGD/External)
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing Graphics\n"));
+ GraphicsInit (PeiServices, SaPlatformPolicyPpi);
+
+ ///
+ /// Initialize Overclocking
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing System Agent Overclocking\n"));
+ SaOcInit(PeiServices, SaPlatformPolicyPpi);
+
+ ///
+ /// Initialize DMI Tc/Vc mapping setting
+ ///
+ DEBUG ((EFI_D_INFO, "Initializing DMI Tc/Vc mapping\n"));
+ SaDmiTcVcInit (PeiServices, SaPlatformPolicyPpi);
+
+ ///
+ /// Early BIOS POST Programming
+ ///
+ DEBUG ((EFI_D_INFO, "Early BIOS POST Programming\n"));
+ EarlyBiosPostProgramming(SaPlatformPolicyPpi);
+
+ ///
+ /// Install Notify
+ ///
+ Status = PeiServicesNotifyPpi (&mSaResetCompleteNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Install SA S3 resume Notify only when booting from S3 resume
+ ///
+ Status = PeiServicesGetBootMode (&BootMode);
+ DEBUG ((EFI_D_INFO, "[SA] BootMode = %X\n", BootMode));
+ if ((Status == EFI_SUCCESS) && (BootMode == BOOT_ON_S3_RESUME)) {
+ DEBUG ((EFI_D_INFO, "[SA] Install SA S3 Notify callback\n"));
+ Status = PeiServicesNotifyPpi (&mSaS3ResumeNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ }
+#ifdef RAPID_START_FLAG
+ else {
+ ///
+ /// When Rapid Start implemented and in the Rapid Start Resume transition, this SA S3 resume Notify should happen early than Rapid Start End-Of-Pei callback
+ /// This is because Rapid Start End-Of-Pei callback will generate ACPI_ENABLE SMI which should be after SA S3 resume completed.
+ ///
+ Status = PeiServicesLocatePpi (&gRapidStartPpiGuid, 0, NULL, &RapidStartPpi);
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((EFI_D_INFO, "[SA] Check Rapid Start transition mode\n"));
+ if (RapidStartPpi->GetMode (RapidStartPpi) == RapidStartExit) {
+ DEBUG ((EFI_D_INFO, "[SA] Install Notify callback for Rapid Start Resume\n"));
+ Status = PeiServicesNotifyPpi (&mSaS3ResumeNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, "[SA] Postpone Rapid Start mode checking after RapidStartPpi installed\n"));
+ Status = PeiServicesNotifyPpi (&mSaOnRapidStartPpiNotifyDesc);
+ }
+ }
+#endif
+
+ ///
+ /// Install Ppi with SaInitPeim complete
+ ///
+ Status = (**PeiServices).InstallPpi (PeiServices, mSaPeiInitPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SaResetComplete (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+/**
+ BIOS_RESET_CPL bit is set for processor to activate the power and thermal management
+ features on the platform.
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS
+**/
+{
+ EFI_STATUS Status;
+ UINT64 MchBar;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi;
+
+ MchBar = McD0PciCfg64 (R_SA_MCHBAR) &~BIT0;
+
+ ///
+ /// Get platform policy settings through the SaPlatformPolicy PPI
+ ///
+ Status = PeiServicesLocatePpi (&gSaPlatformPolicyPpiGuid, 0, NULL, (VOID **) &SaPlatformPolicyPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Set MCHBAR Offset 5F00h [10:9] = 11b
+ ///
+ Data32And = (UINT32)~(BIT10 | BIT9);
+ Data32Or = 0x3 << 9;
+ Mmio32AndThenOr (MchBar, R_SA_MCHBAR_SAPMCTL_OFFSET, Data32And, Data32Or);
+
+ ///
+ /// Set BIOS_RESET_CPL
+ ///
+ DEBUG ((EFI_D_INFO, "Set BIOS_RESET_CPL to indicate all configurations complete\n"));
+ Mmio8Or ((UINTN) MchBar, R_SA_MCHBAR_BIOS_RESET_CPL_OFFSET, BIT0 | BIT1);
+
+ return EFI_SUCCESS;
+}
+
+VOID
+ProgramSaBars (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Programs SA Bars
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+**/
+{
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = GetCpuFamily();
+
+ ///
+ /// Program SA MchBar, DmiBar and EpBar
+ ///
+ McD0PciCfg64 (R_SA_MCHBAR) = (UINT64) (SaPlatformPolicyPpi->PlatformData->MchBar | BIT0);
+ McD0PciCfg64 (R_SA_DMIBAR) = (UINT64) (SaPlatformPolicyPpi->PlatformData->DmiBar | BIT0);
+ McD0PciCfg64 (R_SA_PXPEPBAR) = (UINT64) (SaPlatformPolicyPpi->PlatformData->EpBar | BIT0);
+
+ ///
+ /// Program SA GdxcBar
+ ///
+ Mmio64 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar), R_SA_MCHBAR_GDXCBAR_OFFSET) = (UINT64)
+ (SaPlatformPolicyPpi->PlatformData->GdxcBar | BIT0);
+
+ if (CpuFamilyId == EnumCpuCrw) {
+ ///
+ /// Program SA EdramBar
+ ///
+ Mmio64 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar), R_SA_MCHBAR_EDRAMBAR_OFFSET) = (UINT64)
+ (SaPlatformPolicyPpi->PlatformData->EdramBar | BIT0);
+ }
+}
+
+VOID
+EarlyBiosPostProgramming (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Do Early BIOS POST Programming
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+**/
+{
+ /// SA BS 11.1 Early BIOS POST Programming
+ /// 1. Enable System Agent Clock Gating by setting the MCHBAR offset 5F00h [0] = '1b'.
+ MmioOr32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar + 0x5F00), BIT0);
+}
+
+EFI_STATUS
+InstallSaHob (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Init and Install SA Hob
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+
+ @retval EFI_SUCCESS
+**/
+{
+ EFI_STATUS Status;
+ SA_DATA_HOB *SaDataHob;
+ PEI_CPU_PLATFORM_POLICY_PPI *CpuPlatformPolicy;
+
+ ///
+ /// Create HOB for SA Data
+ ///
+ Status = (**PeiServices).CreateHob (
+ PeiServices,
+ EFI_HOB_TYPE_GUID_EXTENSION,
+ sizeof (SA_DATA_HOB),
+ (VOID **) &SaDataHob
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Initialize default HOB data
+ ///
+ SaDataHob->EfiHobGuidType.Name = gSaDataHobGuid;
+ ZeroMem (&(SaDataHob->DprDirectory[EnumDprDirectoryTxt]), sizeof (DPR_DIRECTORY_ENTRY));
+ ZeroMem (&(SaDataHob->DprDirectory[EnumDprDirectoryPfat]), sizeof (DPR_DIRECTORY_ENTRY));
+ ZeroMem (&(SaDataHob->PegData), sizeof (SA_PEG_DATA));
+ SaDataHob->PegDataValid = FALSE;
+ SaDataHob->PegPlatformResetRequired = FALSE;
+ if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) {
+ SaDataHob->SaIotrapSmiAddress = SaPlatformPolicyPpi->PcieConfig->SaIotrapSmiAddress;
+ SaDataHob->InitPcieAspmAfterOprom = SaPlatformPolicyPpi->PcieConfig->InitPcieAspmAfterOprom;
+ } else {
+ SaDataHob->SaIotrapSmiAddress = 0;
+ SaDataHob->InitPcieAspmAfterOprom = 0;
+ }
+
+ ///
+ /// Get platform policy settings through the SaPlatformPolicy PPI
+ ///
+ Status = (**PeiServices).LocatePpi (
+ PeiServices,
+ &gPeiCpuPlatformPolicyPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &CpuPlatformPolicy
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// TXT DPR Directory Entry
+ ///
+#if defined(TXT_SUPPORT_FLAG) && (TXT_SUPPORT_FLAG == 1)
+ SaDataHob->DprDirectory[EnumDprDirectoryTxt].Type = DPR_DIRECTORY_TYPE_TXT;
+ if (CpuPlatformPolicy->CpuConfig->Txt) {
+ SaDataHob->DprDirectory[EnumDprDirectoryTxt].Size = (UINT8) RShiftU64 (CpuPlatformPolicy->SecurityConfig->TxtConfig->TxtDprMemorySize, 20);
+ }
+#endif
+
+ ///
+ /// PFAT Directory Entry
+ ///
+ SaDataHob->DprDirectory[EnumDprDirectoryPfat].Type = DPR_DIRECTORY_TYPE_PFAT;
+ if (CpuPlatformPolicy->CpuConfig->Pfat) {
+ SaDataHob->DprDirectory[EnumDprDirectoryPfat].Size = CpuPlatformPolicy->SecurityConfig->PfatConfig->PfatMemSize;
+ }
+
+ DEBUG ((EFI_D_INFO, "SA Data HOB installed\n"));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ReportPcieVersion (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Report the SA PCIe initialization code version.
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+
+ @retval EFI_SUCCESS
+**/
+{
+ UINT32 Version;
+ CPU_FAMILY CpuFamilyId;
+ CPU_STEPPING CpuSteppingId;
+ const CodeVersion SaPcieCodeVersion = {
+#include "SaPcieVersion.h"
+ };
+
+ DEBUG ((EFI_D_INFO, "***************** System Agent PCIe code version *****************\n"));
+ DEBUG ((EFI_D_INFO, "** Major version number is: %3d **\n", SaPcieCodeVersion.Major));
+ DEBUG ((EFI_D_INFO, "** Minor version number is: %3d **\n", SaPcieCodeVersion.Minor));
+ DEBUG ((EFI_D_INFO, "** Rev version number is: %3d **\n", SaPcieCodeVersion.Rev));
+ DEBUG ((EFI_D_INFO, "** Build number is: %3d **\n", SaPcieCodeVersion.Build));
+ DEBUG ((EFI_D_INFO, "******************************************************************\n"));
+
+ Version = (((UINT32) SaPcieCodeVersion.Major) << 24) | (((UINT32) SaPcieCodeVersion.Minor) << 16) | (((UINT32) SaPcieCodeVersion.Rev) << 8) | (((UINT32) SaPcieCodeVersion.Build));
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ ///
+ /// Store SA Reference Code version and SA PCIe code version in scrachpad registers
+ ///
+ if ((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId == EnumHswA0)) {
+ Mmio32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->MchBar), R_SA_MCHBAR_PCIE_CODE_VERSION_OFFSET_HSW) = Version;
+ } else {
+ Mmio32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->DmiBar), R_SA_DMIBAR_SCRATCHPAD0_OFFSET) = SaPlatformPolicyPpi->Revision;
+ Mmio32 ((UINTN) (SaPlatformPolicyPpi->PlatformData->DmiBar), R_SA_DMIBAR_SCRATCHPAD1_OFFSET) = Version;
+ }
+ return EFI_SUCCESS;
+}
+
+VOID
+SaPeiPolicyDump (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ This function prints the PEI phase platform policy.
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+**/
+{
+#ifdef EFI_DEBUG
+ INTN i;
+
+ DEBUG ((EFI_D_INFO, "\n------------------------ SA Platform Policy (PEI) dump BEGIN -----------------\n"));
+ DEBUG ((EFI_D_INFO, "Revision : %x\n", SaPlatformPolicyPpi->Revision));
+
+ DEBUG ((EFI_D_INFO, "------------------------ SA_PLATFORM_DATA -----------------\n"));
+
+ DEBUG ((EFI_D_INFO, " SpdAddressTable[%d] :", SA_MC_MAX_SOCKETS));
+ for (i = 0; i < SA_MC_MAX_SOCKETS; i++) {
+ DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PlatformData->SpdAddressTable[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " MchBar : %x\n", SaPlatformPolicyPpi->PlatformData->MchBar));
+ DEBUG ((EFI_D_INFO, " DmiBar : %x\n", SaPlatformPolicyPpi->PlatformData->DmiBar));
+ DEBUG ((EFI_D_INFO, " EpBar : %x\n", SaPlatformPolicyPpi->PlatformData->EpBar));
+ DEBUG ((EFI_D_INFO, " PciExpressBar : %x\n", SaPlatformPolicyPpi->PlatformData->PciExpressBar));
+ DEBUG ((EFI_D_INFO, " SmbusBar : %x\n", SaPlatformPolicyPpi->PlatformData->SmbusBar));
+ DEBUG ((EFI_D_INFO, " GdxcBar : %x\n", SaPlatformPolicyPpi->PlatformData->GdxcBar));
+ DEBUG ((EFI_D_INFO, " TsegSize : %x\n", SaPlatformPolicyPpi->PlatformData->TsegSize));
+ DEBUG ((EFI_D_INFO, " UserBd : %x\n", SaPlatformPolicyPpi->PlatformData->UserBd));
+ DEBUG ((EFI_D_INFO, " FastBoot : %x\n", SaPlatformPolicyPpi->PlatformData->FastBoot));
+ DEBUG ((EFI_D_INFO, " EdramBar : %x\n", SaPlatformPolicyPpi->PlatformData->EdramBar));
+
+ DEBUG ((EFI_D_INFO, "------------------------ GT_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " MmioSize : %x MB\n", SaPlatformPolicyPpi->GtConfig->MmioSize));
+ DEBUG ((EFI_D_INFO, " GttSize : %x MB\n", SaPlatformPolicyPpi->GtConfig->GttSize));
+ DEBUG ((EFI_D_INFO, " IgdDvmt50PreAlloc : %x\n", SaPlatformPolicyPpi->GtConfig->IgdDvmt50PreAlloc));
+ DEBUG ((EFI_D_INFO, " InternalGraphics : %x\n", SaPlatformPolicyPpi->GtConfig->InternalGraphics));
+ DEBUG ((EFI_D_INFO, " PrimaryDisplay : %x\n", SaPlatformPolicyPpi->GtConfig->PrimaryDisplay));
+ DEBUG ((EFI_D_INFO, " ApertureSize : %x\n", SaPlatformPolicyPpi->GtConfig->ApertureSize));
+ DEBUG ((EFI_D_INFO, " GttMmAdr : %x\n", SaPlatformPolicyPpi->GtConfig->GttMmAdr));
+
+ DEBUG ((EFI_D_INFO, "------------------------ PCIE_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " DmiVc1 : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiVc1));
+ DEBUG ((EFI_D_INFO, " DmiVcp : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiVcp));
+ DEBUG ((EFI_D_INFO, " DmiVcm : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiVcm));
+ DEBUG ((EFI_D_INFO, " DmiGen2 : %x\n", SaPlatformPolicyPpi->PcieConfig->DmiGen2));
+ DEBUG ((EFI_D_INFO, " AlwaysEnablePeg : %x\n", SaPlatformPolicyPpi->PcieConfig->AlwaysEnablePeg));
+
+ DEBUG ((EFI_D_INFO, " PegGenx[%d] :", SA_PEG_MAX_FUN));
+ for (i = 0; i < SA_PEG_MAX_FUN; i++) {
+ DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->PegGenx[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " PegGen3Equalization : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3Equalization));
+
+ DEBUG ((EFI_D_INFO, " Gen3RootPortPreset[%d] :", SA_PEG_MAX_LANE));
+ for (i = 0; i < SA_PEG_MAX_LANE; i++) {
+ DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3RootPortPreset[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " Gen3EndPointPreset[%d] :", SA_PEG_MAX_LANE));
+ for (i = 0; i < SA_PEG_MAX_LANE; i++) {
+ DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3EndPointPreset[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " Gen3EndPointHint[%d] :", SA_PEG_MAX_LANE));
+ for (i = 0; i < SA_PEG_MAX_LANE; i++) {
+ DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3EndPointHint[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ DEBUG ((EFI_D_INFO, " PegSamplerCalibrate : %x\n", SaPlatformPolicyPpi->PcieConfig->PegSamplerCalibrate));
+ DEBUG ((EFI_D_INFO, " PegGen3EqualizationPhase2 : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3EqualizationPhase2));
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearch : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearch));
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearchDwellTime : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchDwellTime));
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearchMarginSteps : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchMarginSteps));
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearchStartMargin : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchStartMargin));
+ DEBUG ((EFI_D_INFO, " PegSwingControl : %x\n", SaPlatformPolicyPpi->PcieConfig->PegSwingControl));
+ if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_2) {
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearchVoltageMarginSteps : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchVoltageMarginSteps));
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearchVoltageStartMargin : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchVoltageStartMargin));
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearchFavorTiming : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchFavorTiming));
+ DEBUG ((EFI_D_INFO, " PegDataPtr : %p\n", SaPlatformPolicyPpi->PcieConfig->PegDataPtr));
+ DEBUG ((EFI_D_INFO, " PegGen3ForcePresetSearch : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3ForcePresetSearch));
+ DEBUG ((EFI_D_INFO, " InitPcieAspmAfterOprom : %x\n", SaPlatformPolicyPpi->PcieConfig->InitPcieAspmAfterOprom));
+ DEBUG ((EFI_D_INFO, " SaIotrapSmiAddress : %x\n", SaPlatformPolicyPpi->PcieConfig->SaIotrapSmiAddress));
+ }
+ if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) {
+ DEBUG ((EFI_D_INFO, " PegGpioData : %p\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData));
+ if (SaPlatformPolicyPpi->PcieConfig->PegGpioData != NULL) {
+ DEBUG ((EFI_D_INFO, " PegGpioData->GpioSupport : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData->GpioSupport));
+ if (SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset != NULL) {
+ DEBUG ((EFI_D_INFO, " PegGpioData->SaPegReset->Value : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Value));
+ DEBUG ((EFI_D_INFO, " PegGpioData->SaPegReset->Active : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGpioData->SaPegReset->Active));
+ }
+ }
+ DEBUG ((EFI_D_INFO, " PegGen3PresetSearchErrorTarget : %x\n", SaPlatformPolicyPpi->PcieConfig->PegGen3PresetSearchErrorTarget));
+ DEBUG ((EFI_D_INFO, " RxCEMLoopback : %x\n", SaPlatformPolicyPpi->PcieConfig->RxCEMLoopback));
+ DEBUG ((EFI_D_INFO, " RxCEMLoopbackLane : %x\n", SaPlatformPolicyPpi->PcieConfig->RxCEMLoopbackLane));
+
+ DEBUG ((EFI_D_INFO, " Gen3RxCtleP[%d] :", SA_PEG_MAX_BUNDLE));
+ for (i = 0; i < SA_PEG_MAX_BUNDLE; i++) {
+ DEBUG ((EFI_D_INFO, " %x", SaPlatformPolicyPpi->PcieConfig->Gen3RxCtleP[i]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+
+ DEBUG ((EFI_D_INFO, "------------------------ OVERCLOCKING_CONFIGURATION -----------------\n"));
+ DEBUG ((EFI_D_INFO, " GtVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->GtVoltageOffset));
+ DEBUG ((EFI_D_INFO, " GtVoltageOverride : %x\n", SaPlatformPolicyPpi->OcConfig->GtVoltageOverride));
+ DEBUG ((EFI_D_INFO, " GtExtraTurboVoltage : %x\n", SaPlatformPolicyPpi->OcConfig->GtExtraTurboVoltage));
+ DEBUG ((EFI_D_INFO, " GtMaxOcTurboRatio : %x\n", SaPlatformPolicyPpi->OcConfig->GtMaxOcTurboRatio));
+ DEBUG ((EFI_D_INFO, " SaVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->SaVoltageOffset));
+ DEBUG ((EFI_D_INFO, " GtVoltageMode : %x\n", SaPlatformPolicyPpi->OcConfig->GtVoltageMode));
+ DEBUG ((EFI_D_INFO, " OcSupport : %x\n", SaPlatformPolicyPpi->OcConfig->OcSupport));
+ DEBUG ((EFI_D_INFO, " IoaVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->IoaVoltageOffset));
+ DEBUG ((EFI_D_INFO, " IodVoltageOffset : %x\n", SaPlatformPolicyPpi->OcConfig->IodVoltageOffset));
+
+ DEBUG ((EFI_D_INFO, "------------------------ Misc -----------------\n"));
+ DEBUG ((EFI_D_INFO, " S3DataPtr : %x\n", SaPlatformPolicyPpi->S3DataPtr));
+
+ if (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_3) {
+ DEBUG ((EFI_D_INFO, "------------------------ SG_GPIO_DATA -----------------\n"));
+ DEBUG ((EFI_D_INFO, " SgGpioData : %x\n", SaPlatformPolicyPpi->SgGpioData));
+ if (SaPlatformPolicyPpi->SgGpioData != NULL) {
+ DEBUG ((EFI_D_INFO, " SgGpioData->GpioSupport : %x\n", SaPlatformPolicyPpi->SgGpioData->GpioSupport));
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "\n------------------------ SA Platform Policy (PEI) dump END -----------------\n"));
+#endif
+ return;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.cif b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.cif
new file mode 100644
index 0000000..c60de34
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.cif
@@ -0,0 +1,30 @@
+<component>
+ name = "SaInitPeim"
+ category = ModulePart
+ LocalRoot = "ReferenceCode\Chipset\SystemAgent\SaInit\Pei"
+ RefName = "SaInitPeim"
+[files]
+"SaInitPeim.sdl"
+"SaInitPeim.mak"
+"SaInitPeim.h"
+"SaInitPeim.c"
+"SaInitPeim.dxs"
+"SaInitPeim.inf"
+"GraphicsInit.h"
+"GraphicsInit.c"
+"SaDmiPeim.h"
+"SaDmiPeim.c"
+"PciExpressInit.h"
+"PciExpressInit.c"
+"PcieTraining.c"
+"PcieTraining.h"
+"PcieTrainingEqSettings.c"
+"PcieTrainingErrorCount.c"
+"PcieTrainingLinkRecovery.c"
+"PcieTrainingMargining.c"
+"PcieTrainingPhase3.c"
+"SaOcInit.c"
+"SaOcInit.h"
+"SwitchableGraphicsInit.c"
+"SwitchableGraphicsInit.h"
+<endComponent>
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.dxs b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.dxs
new file mode 100644
index 0000000..4eedf37
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.dxs
@@ -0,0 +1,49 @@
+/** @file
+ Dependency expression source file.
+
+@copyright
+ Copyright (c) 2009 - 2013 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
+
+**/
+
+
+//
+// Common for R8 and R9 codebase
+//
+#include "AutoGen.h"
+#include "PeimDepex.h"
+
+//
+// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase;
+// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version
+// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase.
+//
+#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB)
+#include "EfiDepex.h"
+#endif
+
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+#include EFI_PPI_DEPENDENCY (CpuPlatformPolicy)
+#include EFI_PPI_DEPENDENCY (PchInit)
+#include EFI_PPI_DEPENDENCY (Stall)
+#include EFI_PPI_DEPENDENCY (PchMeUma)
+
+DEPENDENCY_START
+ SA_PLATFORM_POLICY_PPI_GUID AND
+ PCH_INIT_PPI_GUID AND
+ PEI_STALL_PPI_GUID AND
+ PEI_CPU_PLATFORM_POLICY_PPI_GUID
+ AND PCH_ME_UMA_PPI_GUID
+DEPENDENCY_END
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.h
new file mode 100644
index 0000000..2f3263c
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.h
@@ -0,0 +1,260 @@
+/** @file
+ Header file for the SA Init PEIM
+
+@copyright
+ Copyright (c) 1999 - 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
+**/
+#ifndef _SA_INIT_PEIM_H_
+#define _SA_INIT_PEIM_H_
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGluePeim.h"
+#include "SaAccess.h"
+#include "MemInfoHob.h"
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+#include "SaOcInit.h"
+
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+#include EFI_PPI_DEPENDENCY (CpuPlatformPolicy)
+#include EFI_PPI_PRODUCER (SaPeiInit)
+#include EFI_GUID_DEFINITION (SaDataHob)
+#endif
+///
+/// Data definitions & structures
+///
+
+EFI_GUID gMemoryInitHobGuid = EFI_PEI_PERMANENT_MEMORY_INSTALLED_PPI_GUID;
+
+///
+/// Functions
+///
+EFI_STATUS
+EFIAPI
+SaInitPeiEntryPoint (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+/**
+ SA PEI Initialization.
+
+ @param[in] FfsHeader - Pointer to Firmware File System file header.
+ @param[in] PeiServices - General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS
+**/
+;
+
+VOID
+ProgramSaBars (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Programs Sa Bars
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+**/
+;
+
+VOID
+SwitchableGraphicsInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ SwitchableGraphicsInit: Initialize the Switchable Graphics if enabled
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the SgConfig related information
+**/
+;
+
+VOID
+EarlyBiosPostProgramming (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Do Early BIOS POST Programming
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+**/
+;
+
+VOID
+GraphicsInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ GraphicsInit: Initialize the IGD if no other external graphics is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+**/
+;
+
+EFI_STATUS
+SaDmiTcVcInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Initialize DMI Tc/Vc mapping through SA-PCH.
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+
+ @retval EFI_SUCCESS
+**/
+;
+
+#ifdef DMI_FLAG
+EFI_STATUS
+DmiInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Initialize DMI.
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+
+ @retval EFI_SUCCESS
+**/
+;
+#endif // DMI_FLAG
+
+#ifdef PEG_FLAG
+VOID
+PciExpressInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ GraphicsInit: Initialize the IGD if no other external graphics is present
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+**/
+;
+#endif // PEG_FLAG
+
+EFI_STATUS
+InstallSaHob (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Init and Install SA Hob
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+
+ @retval EFI_SUCCESS
+**/
+;
+
+EFI_STATUS
+ReportPcieVersion (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Report the SA PCIe initialization code version.
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+
+ @retval EFI_SUCCESS
+**/
+;
+
+STATIC
+EFI_STATUS
+SaResetComplete (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+/**
+ BIOS_CPL_BIT is set for processor to activate the power and thermal management
+ features on the platform.
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS
+**/
+;
+
+VOID
+SaPeiPolicyDump (
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ This function prints the PEI phase platform policy.
+
+ @param[in] SaPlatformPolicyPpi - Instance of SA_PLATFORM_POLICY_PPI
+**/
+;
+
+static
+EFI_STATUS
+SaS3ResumeAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+/**
+ This function handles SA S3 resume task
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS - Always return EFI_SUCCESS
+**/
+;
+
+#ifdef RAPID_START_FLAG
+static
+EFI_STATUS
+SaCheckRapidStartMode (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+/**
+ This function will check Rapid Start mode and install SaS3Resume callback notify if it was Rapid Start Resume
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS - Always return EFI_SUCCESS
+**/
+;
+#endif // RAPID_START_FLAG
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.inf b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.inf
new file mode 100644
index 0000000..8ca75a4
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.inf
@@ -0,0 +1,132 @@
+## @file
+# Component description file for the SA Init PEIM.
+#
+#@copyright
+# Copyright (c) 2010 - 2014 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 = SaInitPeim
+FILE_GUID = FD236AE7-0791-48c4-B29E-29BDEEE1A811
+COMPONENT_TYPE = PE32_PEIM
+
+[sources.common]
+ SaInitPeim.h
+ SaInitPeim.c
+ GraphicsInit.h
+ GraphicsInit.c
+ SaDmiPeim.h
+ SaDmiPeim.c
+ PciExpressInit.h
+ PciExpressInit.c
+ SwitchableGraphicsInit.c
+ SwitchableGraphicsInit.h
+ PcieTraining.h
+ PcieTraining.c
+ PcieTrainingEqSettings.c
+ PcieTrainingErrorCount.c
+ PcieTrainingMargining.c
+ PcieTrainingLinkRecovery.c
+ PcieTrainingPhase3.c
+ SaOcInit.h
+ SaOcInit.c
+#
+# Edk II Glue Driver Entry Point
+#
+ EdkIIGluePeimEntryPoint.c
+
+
+[includes.common]
+ .
+ ../Common
+ $(EDK_SOURCE)/Foundation/Efi
+ $(EDK_SOURCE)/Foundation/Include
+ $(EDK_SOURCE)/Foundation/Efi/Include
+ $(EDK_SOURCE)/Foundation/Framework/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Library
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Library/OverclockingLib
+
+#
+# EDK II Glue Library utilizes some standard headers from EDK
+#
+ $(EFI_SOURCE)
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)
+ $(EDK_SOURCE)/Foundation
+ $(EDK_SOURCE)/Foundation/Framework
+ $(EDK_SOURCE)/Foundation/Include/IndustryStandard
+ $(EDK_SOURCE)/Foundation/Core/Dxe
+ $(EDK_SOURCE)/Foundation/Include/Pei
+ $(EDK_SOURCE)/Foundation/Library/Pei/Include
+ $(EDK_SOURCE)/Foundation/Library/Dxe/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include/Library
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include/Pcd
+ $(EDK_SOURCE)/Foundation/Cpu/Pentium/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Api
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Include/MrcRegisters
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_CPU_ROOT)/Include/Library
+ $(EFI_SOURCE)/$(PROJECT_ME_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/PchMeUma
+
+[libraries.common]
+ $(PROJECT_PCH_FAMILY)PpiLib
+ EdkFrameworkPpiLib
+ EdkIIGlueBaseIoLibIntrinsic
+ EdkIIGlueBaseMemoryLib
+ EdkIIGluePeiDebugLibReportStatusCode
+ EdkIIGluePeiReportStatusCodeLib
+ EdkIIGluePeiServicesLib
+ EdkIIGluePeiMemoryAllocationLib
+ EdkIIGlueBasePciExpressLib
+ EdkIIGlueBasePostCodeLibPort80
+ PeiLib
+ $(PROJECT_SA_FAMILY)PpiLib
+ SAGuidLib
+ EdkPpiLib
+ CpuPpiLib
+ CpuPlatformLib
+ EdkIIGluePeiHobLib
+ PchPlatformLib
+ OverclockingLib
+ MeLibPpi
+#
+# Uncomment all the RapidStart include directories and library if RapidStart is supported
+#
+# RapidStartPpiLib
+
+
+[nmake.common]
+ IMAGE_ENTRY_POINT = _ModuleEntryPoint
+ DPX_SOURCE = SaInitPeim.dxs
+#
+# Module Entry Point
+#
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=SaInitPeiEntryPoint
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ -D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ -D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ -D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__ \
+ -D __EDKII_GLUE_PEI_SERVICES_LIB__ \
+ -D __EDKII_GLUE_PEI_MEMORY_ALLOCATION_LIB__ \
+ -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.mak b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.mak
new file mode 100644
index 0000000..935d761
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.mak
@@ -0,0 +1,72 @@
+#---------------------------------------------------------------------------
+# Create SaInitPeim module
+#---------------------------------------------------------------------------
+all : SaInitPeim
+SaInitPeim : $(BUILD_DIR)\SaInitPeim.mak SaInitPeimBin
+
+$(BUILD_DIR)\SaInitPeim.mak : $(SaInitPeim_DIR)\$(@B).cif $(SaInitPeim_DIR)\$(@B).mak $(BUILD_RULES)
+ $(CIF2MAK) $(SaInitPeim_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS)
+
+SaInitPeim_INCLUDES=\
+ $(INTEL_MCH_INCLUDES)\
+ $(INTEL_PCH_INCLUDES)\
+ $(EdkIIGlueLib_INCLUDES)\
+ $(PROJECT_CPU_INCLUDES)\
+ $(RAPIDSTART_INCLUDES)\
+ $(PchMeUma_INCLUDES)\
+ /I$(PROJECT_CPU_ROOT)\Library\OverclockingLib \
+
+SaInitPeim_DEFINES = $(MY_DEFINES)\
+ /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=SaInitPeiEntryPoint"\
+ /D __EDKII_GLUE_BASE_LIB__ \
+ /D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ /D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ /D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__ \
+ /D __EDKII_GLUE_PEI_SERVICES_LIB__ \
+ /D __EDKII_GLUE_PEI_MEMORY_ALLOCATION_LIB__ \
+ /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \
+
+SaInitPeim_LIB_LINKS =\
+ $(INTEL_SA_PPI_LIB) \
+ $(IntelPchPpiLib_LIB)\
+ $(EDKFRAMEWORKPPILIB) \
+ $(EdkIIGlueBaseLib_LIB)\
+ $(EdkIIGlueBaseLibIA32_LIB)\
+ $(EdkIIGlueBaseIoLibIntrinsic_LIB) \
+ $(EdkIIGluePeiDebugLibReportStatusCode_LIB) \
+ $(EdkIIGluePeiReportStatusCodeLib_LIB) \
+ $(EdkIIGluePeiServicesLib_LIB) \
+ $(EdkIIGluePeiMemoryAllocationLib_LIB) \
+ $(EdkIIGlueBasePciLibPciExpress_LIB) \
+ $(EdkIIGlueBasePciExpressLib_LIB)\
+ $(PEILIB)\
+ $(SaGuidLib_LIB)\
+ $(EdkIIGlueBasePciExpressLib_LIB)\
+ $(EdkIIGlueBasePostCodeLibPort80_LIB)\
+ $(CPU_PPI_LIB)\
+ $(CpuPlatformLib_LIB)\
+ $(PchPlatformPeiLib_LIB)\
+ $(EdkIIGluePeiHobLib_LIB)\
+ $(OcPlatformLib_LIB)\
+#
+# Uncomment all the RapidStart include directories and library if RapidStart is supported
+#
+# RapidStartPpiLib
+ $(RapidStartPpiLib_LIB)\
+ $(MeLibPpi_LIB)
+
+SaInitPeimBin: $(SaInitPeim_LIB_LINKS)
+ $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\
+ /f $(BUILD_DIR)\SaInitPeim.mak all \
+ "MY_INCLUDES=$(SaInitPeim_INCLUDES)"\
+ "MY_DEFINES=$(SaInitPeim_DEFINES)"\
+ NAME=SaInitPeim\
+ MAKEFILE=$(BUILD_DIR)\SaInitPeim.mak \
+ GUID=FD236AE7-0791-48c4-B29E-29BDEEE1A811\
+ ENTRY_POINT=_ModuleEntryPoint \
+ TYPE=PEIM \
+ EDKIIModule=PEIM\
+ DEPEX1=$(SaInitPeim_DIR)\SaInitPeim.dxs\
+ DEPEX1_TYPE=EFI_SECTION_PEI_DEPEX\
+ COMPRESS=0
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.sdl b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.sdl
new file mode 100644
index 0000000..38ceadb
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaInitPeim.sdl
@@ -0,0 +1,39 @@
+TOKEN
+ Name = "SaInitPeim_SUPPORT"
+ Value = "1"
+ Help = "Main switch to enable SaInitPeim support in Project"
+ TokenType = Boolean
+ TargetEQU = Yes
+ TargetMAK = Yes
+ Master = Yes
+End
+
+TOKEN
+ Name = "SA_DEBUG_INFO"
+ Value = "1"
+ TokenType = Boolean
+ Range = "0-1 "
+ TargetMAK = Yes
+End
+
+ELINK
+ Name = "/D SA_DEBUG_FLAG"
+ Parent = "INTEL_SA_RC_FLAGS"
+ Token = "SA_DEBUG_INFO" "=" "1"
+ InvokeOrder = AfterParent
+End
+
+PATH
+ Name = "SaInitPeim_DIR"
+End
+
+MODULE
+ File = "SaInitPeim.mak"
+ Help = "Includes SaInitPeim.mak to Project"
+End
+
+ELINK
+ Name = "$(BUILD_DIR)\SaInitPeim.ffs"
+ Parent = "FV_BB"
+ InvokeOrder = AfterParent
+End
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.c
new file mode 100644
index 0000000..80a1ffb
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.c
@@ -0,0 +1,189 @@
+/** @file
+ OC System Agent Early Post initializations.
+
+@copyright
+ Copyright (c) 2011 - 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
+**/
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGluePeim.h"
+#include "SaOcInit.h"
+#endif
+
+EFI_STATUS
+SaOcInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Initializes Overclocking settings in the processor.
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] OverclockingtConfig Pointer to Policy protocol instance
+
+ @retval EFI_SUCCESS
+**/
+{
+ EFI_STATUS Status;
+ OC_CAPABILITIES_ITEM OcCaps;
+ VOLTAGE_FREQUENCY_ITEM CurrentVfItem;
+ VOLTAGE_FREQUENCY_ITEM RequestedVfItem;
+ UINT32 LibStatus;
+ UINT8 DomainId;
+ BOOLEAN VfUpdateNeeded;
+ WDT_PPI *gWdtPei;
+
+ LibStatus = 0;
+ VfUpdateNeeded = FALSE;
+
+ if (SaPlatformPolicyPpi->OcConfig->OcSupport == 0){
+ ///
+ /// Overclocking is disabled
+ ///
+ DEBUG ((EFI_D_ERROR, "(OC) Overclocking is disabled. Bypassing SA overclocking flow.\n"));
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ ZeroMem(&CurrentVfItem,sizeof(CurrentVfItem));
+ ZeroMem(&RequestedVfItem,sizeof(RequestedVfItem));
+
+ //
+ // Locate WDT_PPI (ICC WDT PPI)
+ //
+ Status = PeiServicesLocatePpi (
+ &gWdtPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &gWdtPei
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// We will loop on the CPU domains to manage the voltage/frequency settings
+ ///
+ for (DomainId = OC_LIB_DOMAIN_ID_GT; DomainId <= OC_LIB_DOMAIN_ID_IOD; DomainId++) {
+ ///
+ /// Only GT, Uncore, IOA, and IOD are valid for System Agent
+ ///
+ if ((DomainId == OC_LIB_DOMAIN_ID_GT) ||(DomainId == OC_LIB_DOMAIN_ID_UNCORE) ||
+ (DomainId == OC_LIB_DOMAIN_ID_IOA) || (DomainId == OC_LIB_DOMAIN_ID_IOD)){
+ ///
+ /// Get OC Capabilities of the domain
+ ///
+ ZeroMem(&OcCaps,sizeof(OcCaps));
+ OcCaps.DomainId = DomainId;
+ Status = GetOcCapabilities(&OcCaps,&LibStatus);
+
+ if (LibStatus == OC_LIB_COMPLETION_CODE_SUCCESS){
+ ///
+ /// If any OC is supported on this domain, then proceed
+ ///
+ if (OcCaps.RatioOcSupported || OcCaps.VoltageOverridesSupported || OcCaps.VoltageOffsetSupported){
+ ///
+ /// Need to populate the user requested settings from the platform policy
+ /// to determine if OC changes are desired.
+ ///
+ ZeroMem(&CurrentVfItem,sizeof(CurrentVfItem));
+ CurrentVfItem.DomainId = DomainId;
+
+ ///
+ /// Get a copy of the current domain VfSettings from the Mailbox Library
+ ///
+ Status = GetVoltageFrequencyItem(&CurrentVfItem,&LibStatus);
+ if ((Status != EFI_SUCCESS) || (LibStatus != OC_LIB_COMPLETION_CODE_SUCCESS)){
+ continue;
+ }
+
+ ///
+ /// Populate the user requested VfSettings struct
+ ///
+ ZeroMem(&RequestedVfItem,sizeof(RequestedVfItem));
+ RequestedVfItem.DomainId = DomainId;
+ if (DomainId == OC_LIB_DOMAIN_ID_GT){
+ RequestedVfItem.VfSettings.MaxOcRatio = (UINT8) SaPlatformPolicyPpi->OcConfig->GtMaxOcTurboRatio;
+
+ ///
+ /// VoltageTarget has 2 uses and we need to update the target based
+ /// on the voltagemode requested
+ ///
+ RequestedVfItem.VfSettings.VoltageTargetMode = SaPlatformPolicyPpi->OcConfig->GtVoltageMode;
+ if (RequestedVfItem.VfSettings.VoltageTargetMode == OC_LIB_OFFSET_ADAPTIVE){
+ RequestedVfItem.VfSettings.VoltageTarget = SaPlatformPolicyPpi->OcConfig->GtExtraTurboVoltage;
+ }
+ else {
+ RequestedVfItem.VfSettings.VoltageTarget = SaPlatformPolicyPpi->OcConfig->GtVoltageOverride;
+ }
+ RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->GtVoltageOffset;
+
+ VfUpdateNeeded = (BOOLEAN)CompareMem((VOID*)&RequestedVfItem,(VOID*)&CurrentVfItem,sizeof(VOLTAGE_FREQUENCY_ITEM));
+ }
+ else if ((DomainId == OC_LIB_DOMAIN_ID_UNCORE) || (DomainId == OC_LIB_DOMAIN_ID_IOA) || (DomainId == OC_LIB_DOMAIN_ID_IOD)){
+ ///
+ /// Uncore,IOA, and IOD domains only supports voltage offset, other settings are ignored
+ ///
+ switch (DomainId) {
+ case OC_LIB_DOMAIN_ID_UNCORE:
+ RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->SaVoltageOffset;
+ break;
+
+ case OC_LIB_DOMAIN_ID_IOA:
+ RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->IoaVoltageOffset;
+ break;
+
+ case OC_LIB_DOMAIN_ID_IOD:
+ RequestedVfItem.VfSettings.VoltageOffset = SaPlatformPolicyPpi->OcConfig->IodVoltageOffset;
+ break;
+ }
+
+ if (RequestedVfItem.VfSettings.VoltageOffset != CurrentVfItem.VfSettings.VoltageOffset)
+ VfUpdateNeeded = TRUE;
+ }
+
+ if (VfUpdateNeeded){
+ VfUpdateNeeded = FALSE;
+
+ ///
+ /// Arm watchdog timer for OC changes
+ ///
+ Status = gWdtPei->ReloadAndStart (WDT_TIMEOUT_BETWEEN_PEI_DXE);
+
+ ///
+ /// Need to update the requested voltage/frequency values
+ ///
+ Status = SetVoltageFrequencyItem(RequestedVfItem,&LibStatus);
+ if ((Status != EFI_SUCCESS) || (LibStatus != OC_LIB_COMPLETION_CODE_SUCCESS)){
+ DEBUG ((EFI_D_ERROR, "(OC) Set Voltage Frequency failed. EFI Status = %X, Library Status = %X\n", Status, LibStatus));
+ }
+ }
+ }
+ else {
+ DEBUG ((EFI_D_INFO, "(OC) No OC support for this Domain = %X\n", DomainId));
+ }
+ }
+ else {
+ DEBUG ((EFI_D_ERROR, "(OC) GetOcCapabilities message failed. Library Status = %X, Domain = %X\n", LibStatus, DomainId));
+ }
+ }
+ }
+
+ return Status;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.h
new file mode 100644
index 0000000..0ebff94
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SaOcInit.h
@@ -0,0 +1,56 @@
+/** @file
+ Describes the functions visible to the rest of the OcInit.
+
+@copyright
+ Copyright (c) 2011 - 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
+**/
+#ifndef _SA_INIT_H_
+#define _SA_INIT_H_
+
+#include "OverclockingLibrary.h"
+#include EFI_PPI_DEPENDENCY (CpuPlatformPolicy)
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+#include EFI_PPI_CONSUMER (Wdt)
+
+#ifdef USE_WDT_IN_DEBUG_BIOS
+//
+// MRC takes a lot of time to execute in debug mode
+//
+#define WDT_TIMEOUT_BETWEEN_PEI_DXE 120
+#else
+#define WDT_TIMEOUT_BETWEEN_PEI_DXE 60
+#endif
+
+///
+/// Function Prototypes
+///
+EFI_STATUS
+SaOcInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+/**
+ Initializes Overclocking settings in the processor.
+
+ @param[in] PeiServices - General purpose services available to every PEIM.
+ @param[in] OverclockingtConfig Pointer to Policy protocol instance
+
+ @retval EFI_SUCCESS
+**/
+;
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.c
new file mode 100644
index 0000000..cbb8748
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.c
@@ -0,0 +1,288 @@
+/** @file
+ SwitchableGraphics Pei driver.
+ This Pei driver initialize GPIO programming
+ for the platform.
+
+@copyright
+ Copyright (c) 2010 - 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 "SwitchableGraphicsInit.h"
+#include EFI_GUID_DEFINITION (SaDataHob)
+
+#ifdef SG_SUPPORT
+
+/**
+ Initialize the SwitchableGraphics support (PEI).
+
+ @param[in] PeiServices - Pointer to the PEI services table
+ @param[in] SaPlatformPolicyPpi - SaPlatformPolicyPpi to access the GtConfig related information
+**/
+VOID
+SwitchableGraphicsInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi
+ )
+{
+ EFI_STATUS Status;
+ PEI_STALL_PPI *StallPpi;
+ EFI_GUID StallPpiGuid = PEI_STALL_PPI_GUID;
+ UINT16 GpioAddress;
+ SA_DATA_HOB *SaDataHob;
+ BOOLEAN SgDgpuPrsntGpioIsValid = TRUE;
+ CPU_FAMILY CpuFamilyId;
+
+ CpuFamilyId = GetCpuFamily();
+
+ ///
+ /// Get SaDataHob HOB
+ ///
+ SaDataHob = NULL;
+ SaDataHob = (SA_DATA_HOB *) GetFirstGuidHob (&gSaDataHobGuid);
+
+ if (SaDataHob != NULL) {
+ SaDataHob->SgInfo.SgMode = SaPlatformPolicyPpi->PlatformData->SgMode;
+ SaDataHob->SgInfo.PXFixedDynamicMode = SaPlatformPolicyPpi->PlatformData->PXFixedDynamicMode; // AMI_OVERRIDE_FOR ATI 5.0 Fixed/Dynamic
+
+ ///
+ /// GPIO Assigned from policy
+ ///
+ SaDataHob->SgInfo.SgGpioSupport = SaPlatformPolicyPpi->SgGpioData->GpioSupport;
+
+ if (SaPlatformPolicyPpi->SgGpioData->GpioSupport == 1) {
+ ///
+ /// Get GPIO Base Address
+ ///
+ GpioAddress = MmPci16 (0, 0, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_GPIO_BASE) &~BIT0;
+
+ SaDataHob->SgInfo.SgDgpuPwrOK = SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrOK->Value;
+ SaDataHob->SgInfo.SgDgpuHoldRst = SaPlatformPolicyPpi->SgGpioData->SgDgpuHoldRst->Value;
+ SaDataHob->SgInfo.SgDgpuPwrEnable = SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrEnable->Value;
+ SaDataHob->SgInfo.SgDgpuPrsnt = SaPlatformPolicyPpi->SgGpioData->SgDgpuPrsnt->Value;
+
+ ///
+ /// Set Bit7 as indicator for GPIO Active Low/High
+ ///
+ SaDataHob->SgInfo.SgDgpuPwrOK |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrOK->Active << 7);
+ SaDataHob->SgInfo.SgDgpuHoldRst |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuHoldRst->Active << 7);
+ SaDataHob->SgInfo.SgDgpuPwrEnable |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuPwrEnable->Active << 7);
+ SaDataHob->SgInfo.SgDgpuPrsnt |= (SaPlatformPolicyPpi->SgGpioData->SgDgpuPrsnt->Active << 7);
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ PEI_DEBUG ((PeiServices, EFI_D_INFO, "SgDgpuPrsntGpioIsValid = FALSE\n"));
+ SgDgpuPrsntGpioIsValid = FALSE;
+ }
+
+ ///
+ /// Locate PPI stall service
+ ///
+ Status = (**PeiServices).LocatePpi (
+ PeiServices,
+ &StallPpiGuid,
+ 0,
+ NULL,
+ &StallPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ ///
+ /// if DGPU PRSNT is Disabled, it means that MXM card was not detected, and
+ /// DGPU HOLD RST must be driven high to allow the board to support a normal PEG card
+ ///
+ if ( (SgDgpuPrsntGpioIsValid)
+ && (GpioRead (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuPrsnt) == GP_DISABLE)) {
+ GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuHoldRst, GP_DISABLE);
+ ///
+ /// Set SG mode as disabled
+ ///
+ SaDataHob->SgInfo.SgMode = SgModeDisabled;
+ } else {
+ ///
+ /// DGPU PRSNT Enabled. MXM is present.
+ /// If PEG Mode or SG Muxless
+ /// Power on MXM
+ /// Configure GPIOs to drive MXM in PEG mode or SG Muxless
+ /// else
+ /// Do Nothing
+ ///
+ if ((SaPlatformPolicyPpi->PlatformData->SgMode == SgModeMuxless) ||
+ (SaPlatformPolicyPpi->PlatformData->SgMode == SgModeDgpu)) {
+ PEI_DEBUG ((PeiServices, EFI_D_INFO, "Configure GPIOs for driving the dGPU.\n"));
+ ///
+ /// Drive DGPU HOLD RST Enable to make sure we hold reset
+ ///
+ GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuHoldRst, GP_ENABLE);
+ ///
+ /// wait 100ms
+ ///
+ StallPpi->Stall (
+ PeiServices,
+ StallPpi,
+ SG_DELAY_HOLD_RST
+ );
+
+ ///
+ /// Drive DGPU PWR EN to Power On MXM
+ ///
+ GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuPwrEnable, GP_ENABLE);
+
+ ///
+ /// wait 300ms
+ ///
+ StallPpi->Stall (
+ PeiServices,
+ StallPpi,
+ SG_DELAY_PWR_ENABLE
+ );
+
+ ///
+ /// Drive DGPU HOLD RST Disabled to remove reset
+ ///
+ GpioWrite (PeiServices, CpuFamilyId, GpioAddress, SaDataHob->SgInfo.SgDgpuHoldRst, GP_DISABLE);
+
+ ///
+ /// wait 100ms
+ ///
+ StallPpi->Stall (
+ PeiServices,
+ StallPpi,
+ SG_DELAY_HOLD_RST
+ );
+ }
+ }
+ }
+ }
+ }
+ ///
+ /// Program SubsystemID for IGFX
+ ///
+ PEI_DEBUG ((PeiServices, EFI_D_INFO, "Program SDID [Subsystem ID] for IGFX: 0x%x\n", SaPlatformPolicyPpi->PlatformData->SgSubSystemId));
+ McD2PciCfg16Or (PCI_SID, SaPlatformPolicyPpi->PlatformData->SgSubSystemId);
+
+}
+
+/**
+ SG GPIO Read
+
+ @param[in] PeiServices - General purpose services available to every PEIM
+ @param[in] CpuFamilyId - Specifies the CPU family
+ @param[in] GpioAddress - GPIO base address
+ @param[in] Value - PCH GPIO number
+
+ @retval GPIO read value (0/1)
+**/
+BOOLEAN
+GpioRead (
+ EFI_PEI_SERVICES **PeiServices,
+ CPU_FAMILY CpuFamilyId,
+ IN UINT16 GpioAddress,
+ IN UINT8 Value
+ )
+{
+ BOOLEAN Active;
+ UINT16 BitOffset=0;
+ UINT32 Data;
+
+ Active = (BOOLEAN) (Value >> 7);
+ Value &= 0x7F;
+
+ ASSERT (GpioAddress != 0);
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ GpioAddress += R_PCH_GP_N_CONFIG0 + (Value * 0x08);
+ BitOffset = 30; //GPI_LVL
+ } else {
+ if (Value < 0x20) {
+ GpioAddress += R_PCH_GPIO_LVL;
+ BitOffset = Value;
+ } else if (Value < 0x40) {
+ GpioAddress += R_PCH_GPIO_LVL2;
+ BitOffset = Value - 0x20;
+ } else {
+ GpioAddress += R_PCH_GPIO_LVL3;
+ BitOffset = Value - 0x40;
+ }
+ }
+
+ Data = IoRead32 (GpioAddress);
+ Data >>= BitOffset;
+
+ if (Active == 0) {
+ Data = ~Data;
+ }
+
+ return (BOOLEAN) (Data & 0x1);
+}
+
+/**
+ SG GPIO Write
+
+ @param[in] PeiServices - General purpose services available to every PEIM
+ @param[in] CpuFamilyId - Specifies the CPU family
+ @param[in] GpioAddress - GPIO base address
+ @param[in] Value - PCH GPIO number
+ @param[in] Level - Write SG GPIO value (0/1)
+
+ @retval none
+**/
+VOID
+GpioWrite (
+ EFI_PEI_SERVICES **PeiServices,
+ CPU_FAMILY CpuFamilyId,
+ IN UINT16 GpioAddress,
+ IN UINT8 Value,
+ IN BOOLEAN Level
+ )
+{
+ BOOLEAN Active;
+ UINT32 Data;
+ UINT16 BitOffset=0;
+
+ Active = (BOOLEAN) (Value >> 7);
+ Value &= 0x7F;
+
+ if (Active == 0) {
+ Level = (~Level) & 0x1;
+ }
+
+ ASSERT (GpioAddress != 0);
+
+ if (CpuFamilyId == EnumCpuHswUlt) {
+ GpioAddress += R_PCH_GP_N_CONFIG0 + (Value * 0x08);
+ BitOffset = 31; //GPO_LVL
+ } else {
+ if (Value < 0x20) {
+ GpioAddress += R_PCH_GPIO_LVL;
+ BitOffset = Value;
+ } else if (Value < 0x40) {
+ GpioAddress += R_PCH_GPIO_LVL2;
+ BitOffset = Value - 0x20;
+ } else {
+ GpioAddress += R_PCH_GPIO_LVL3;
+ BitOffset = Value - 0x40;
+ }
+ }
+
+ Data = IoRead32 (GpioAddress);
+ Data &= ~(0x1 << BitOffset);
+ Data |= (Level << BitOffset);
+
+ IoWrite32 (GpioAddress, Data);
+ return ;
+}
+
+#endif //SG_SUPPORT \ No newline at end of file
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.h
new file mode 100644
index 0000000..7126b19
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Pei/SwitchableGraphicsInit.h
@@ -0,0 +1,93 @@
+/** @file
+ Header file for the SwitchableGraphics Pei driver.
+
+@copyright
+ Copyright (c) 2010 - 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
+**/
+
+#ifndef _SWITCHABLE_GRAPHICS_PEI_H_
+#define _SWITCHABLE_GRAPHICS_PEI_H_
+
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGluePeim.h"
+#include "EdkIIGlueIoLib.h"
+#endif
+
+#include "CpuRegs.h"
+#include "CpuPlatformLib.h"
+
+#include "PchAccess.h"
+#include "SaAccess.h"
+
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+#include EFI_PPI_DEPENDENCY (Stall)
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef HIGH
+#define HIGH 1
+#endif
+
+#ifndef LOW
+#define LOW 0
+#endif
+
+#define SG_DELAY_HOLD_RST 100 * STALL_ONE_MILLI_SECOND
+#define SG_DELAY_PWR_ENABLE 300 * STALL_ONE_MILLI_SECOND
+
+/**
+ SG GPIO Write
+
+ @param[in] PeiServices - General purpose services available to every PEIM
+ @param[in] CpuFamilyId - Specifies the CPU family
+ @param[in] GpioAddress - GPIO base address
+ @param[in] Value - PCH GPIO number
+ @param[in] Level - Write SG GPIO value (0/1)
+
+ @retval none
+**/
+VOID
+GpioWrite (
+ EFI_PEI_SERVICES **PeiServices,
+ CPU_FAMILY CpuFamilyId,
+ IN UINT16 GpioAddress,
+ IN UINT8 Value,
+ IN BOOLEAN Level
+ )
+;
+
+/**
+ SG GPIO Read
+
+ @param[in] PeiServices - General purpose services available to every PEIM
+ @param[in] CpuFamilyId - Specifies the CPU family
+ @param[in] GpioAddress - GPIO base address
+ @param[in] Value - PCH GPIO number
+
+ @retval GPIO read value (0/1)
+**/
+BOOLEAN
+GpioRead (
+ EFI_PEI_SERVICES **PeiServices,
+ CPU_FAMILY CpuFamilyId,
+ IN UINT16 GpioAddress,
+ IN UINT8 Value
+ )
+;
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.c
new file mode 100644
index 0000000..45ce0af
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.c
@@ -0,0 +1,204 @@
+/** @file
+ This SMM driver will handle SA relevant late initialization
+
+@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
+**/
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "SaBuildFlags.h"
+#include "EdkIIGlueDxe.h"
+#include "SaLateInitSmm.h"
+#include "SaRegs.h"
+#include "SaAccess.h"
+#include "PchAccess.h"
+#include "CpuIA32.h"
+#include "SaPcieLib.h"
+#include EFI_PROTOCOL_DEPENDENCY (SmmIoTrapDispatch)
+#include EFI_GUID_DEFINITION (SaDataHob)
+#endif
+
+typedef enum {
+ EnumSaSmiCallbackForMaxPayLoad,
+ EnumSaSmiCallbackForSecurityLock,
+ EnumSaSmiCallbackForLateInit,
+ EnumSaSmiCallbackForS3resume,
+ EnumSaSmiCallbackMax
+} SMI_OPERATION;
+
+UINT8 mSaSmiCallbackPhase = EnumSaSmiCallbackForMaxPayLoad;
+
+/**
+ A SMI callback to do SA relevant late initialization
+
+ @param[in] DispatchHandle - The handle of this callback, obtained when registering
+ @param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
+
+ @retval None
+**/
+VOID
+EFIAPI
+SaIoTrapSmiCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT *CallbackContext
+ )
+{
+
+ if (mSaSmiCallbackPhase == EnumSaSmiCallbackMax) {
+ return;
+ }
+ if (mSaSmiCallbackPhase == EnumSaSmiCallbackForMaxPayLoad) {
+ SaPcieEnumCallback ();
+ ///
+ /// Switch to next phase
+ ///
+ mSaSmiCallbackPhase = EnumSaSmiCallbackForSecurityLock;
+ } else if (mSaSmiCallbackPhase == EnumSaSmiCallbackForSecurityLock) {
+ ///
+ /// Save platform registers including IGFX BAR & COMMAND registers and PAM
+ ///
+ SaSaveRestorePlatform (TRUE);
+ SaSecurityLock ();
+ ///
+ /// Switch to next phase
+ ///
+ mSaSmiCallbackPhase = EnumSaSmiCallbackForLateInit;
+ } else if (mSaSmiCallbackPhase == EnumSaSmiCallbackForLateInit) {
+ ///
+ /// Expected to execute in ReadyToBoot point (after OROM)
+ ///
+ SaPcieConfigAfterOpRom ();
+ ///
+ /// Switch to next phase
+ ///
+ mSaSmiCallbackPhase = EnumSaSmiCallbackForS3resume;
+ } else if (mSaSmiCallbackPhase == EnumSaSmiCallbackForS3resume) {
+ ///
+ /// Expected to execute in end of S3 resume flow
+ ///
+ SaS3ResumeCallback ();
+ }
+}
+
+/**
+ Initializes the SA SMM handler
+
+ @param[in] ImageHandle - The image handle of Wake On Lan driver
+ @param[in] SystemTable - The standard EFI system table
+
+ @retval EFI_SUCCESS - SA SMM handler was installed or not necessary
+ @retval EFI_NOT_FOUND - DxePlatformSaPolicy not found
+**/
+EFI_STATUS
+SaLateInitSmmEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL *PchIoTrap;
+ EFI_HANDLE PchIoTrapHandle;
+ EFI_SMM_IO_TRAP_DISPATCH_REGISTER_CONTEXT PchIoTrapContext;
+ SA_DATA_HOB *SaDataHob;
+ DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy;
+ BOOLEAN InitPcieAspmAfterOprom;
+ EFI_PHYSICAL_ADDRESS IotrapAddress;
+
+ DEBUG ((EFI_D_INFO, "SaLateInitSmmEntryPoint()\n"));
+
+ SaDataHob = NULL;
+ SaDataHob = (SA_DATA_HOB *)GetFirstGuidHob (&gSaDataHobGuid);
+ Status = EFI_NOT_FOUND;
+ if ((SaDataHob != NULL)) {
+ ///
+ /// Locate the PCH Trap dispatch protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiSmmIoTrapDispatchProtocolGuid, NULL, (VOID **) &PchIoTrap);
+ ASSERT_EFI_ERROR (Status);
+ if ((Status == EFI_SUCCESS) && (SaDataHob->SaIotrapSmiAddress != 0)) {
+ ///
+ /// Allocate 16 byte range from GCD for this IO trap address
+ ///
+ IotrapAddress = SaDataHob->SaIotrapSmiAddress;
+ DEBUG ((EFI_D_INFO, "Iotrap address=%X\n", SaDataHob->SaIotrapSmiAddress));
+ Status = gDS->AllocateIoSpace (
+ EfiGcdAllocateAddress,
+ EfiGcdIoTypeIo,
+ 0,
+ 0x10,
+ &IotrapAddress,
+ ImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (Status == EFI_SUCCESS) {
+ PchIoTrapContext.Type = ReadWriteTrap;
+ PchIoTrapContext.Length = 4;
+ PchIoTrapContext.Address = SaDataHob->SaIotrapSmiAddress;
+ PchIoTrapContext.Context = NULL;
+ PchIoTrapContext.MergeDisable = FALSE;
+ Status = PchIoTrap->Register (
+ PchIoTrap,
+ SaIoTrapSmiCallback,
+ &PchIoTrapContext,
+ &PchIoTrapHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (Status == EFI_SUCCESS) {
+ InitPcieAspmAfterOprom = SaDataHob->InitPcieAspmAfterOprom;
+#if SA_PCIE_ASPM_IN_DXE == 0
+ ///
+ /// There is no DXE ASPM code so always executes SMM code
+ ///
+ InitPcieAspmAfterOprom = 1;
+#endif
+ if (InitPcieAspmAfterOprom == 1) {
+ ///
+ /// Initialize module global variables - Stepping ID and Platform Policy for runtime SMI handler
+ /// Get the platform setup policy.
+ ///
+ Status = gBS->LocateProtocol (&gDxePlatformSaPolicyGuid, NULL, (VOID **) &DxePlatformSaPolicy);
+ ASSERT_EFI_ERROR (Status);
+ if (DxePlatformSaPolicy != NULL) {
+ SaPcieInitPolicy (DxePlatformSaPolicy);
+ }
+ } else {
+ ///
+ /// InitPcieAspmAfterOprom was not available or disabled, make this SMI handler directly return.
+ ///
+ mSaSmiCallbackPhase = EnumSaSmiCallbackMax;
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// For security consideration, if this SMM driver was compiled/executed, the IOTRAP SMI handler must be registered successfully.
+ /// If not, hang system here
+ ///
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Failed to register SaIotrapSmiCallback! System halt!\n"));
+ EFI_DEADLOOP ();
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.cif b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.cif
new file mode 100644
index 0000000..6fbd4ba
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.cif
@@ -0,0 +1,13 @@
+<component>
+ name = "SaLateInitSmm"
+ category = ModulePart
+ LocalRoot = "ReferenceCode\Chipset\SystemAgent\SaInit\Smm\"
+ RefName = "SaLateInitSmm"
+[files]
+"SaLateInitSmm.sdl"
+"SaLateInitSmm.mak"
+"SaLateInitSmm.h"
+"SaLateInitSmm.c"
+"SaLateInitSmm.dxs"
+"SaLateInitSmm.inf"
+<endComponent>
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.dxs b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.dxs
new file mode 100644
index 0000000..8890d7d
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.dxs
@@ -0,0 +1,45 @@
+/** @file
+ Dependency expression source file.
+
+@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
+
+**/
+
+
+//
+// Common for R8 and R9 codebase
+//
+#include "AutoGen.h"
+#include "DxeDepex.h"
+
+//
+// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase;
+// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version
+// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase.
+//
+#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB)
+#include "EfiDepex.h"
+
+#include EFI_PROTOCOL_DEPENDENCY (SmmBase)
+#include EFI_PROTOCOL_DEPENDENCY (SmmIoTrapDispatch)
+#include EFI_PROTOCOL_DEPENDENCY (SaPlatformPolicy)
+#endif
+
+DEPENDENCY_START
+ EFI_SMM_BASE_PROTOCOL_GUID AND
+ EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL_GUID AND
+ DXE_PLATFORM_SA_POLICY_GUID
+DEPENDENCY_END
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.h b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.h
new file mode 100644
index 0000000..71ff7e4
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.h
@@ -0,0 +1,39 @@
+/** @file
+ Header file for SA SMM Handler
+
+@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
+**/
+
+#ifndef _SaLateInitSmm_H_
+#define _SaLateInitSmm_H_
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGlueDxe.h"
+///
+/// Driver Consumed Protocol Prototypes
+///
+#include EFI_PROTOCOL_DEPENDENCY (SmmBase)
+#include EFI_PROTOCOL_DEPENDENCY (SmmIchnDispatch)
+#include EFI_PROTOCOL_DEPENDENCY (SaPlatformPolicy)
+
+#endif
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.inf b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.inf
new file mode 100644
index 0000000..3fd8846
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.inf
@@ -0,0 +1,97 @@
+## @file
+# Component description file for the SA late initialization SMM module.
+#
+#@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 = SaLateInitSmm
+FILE_GUID = 2D1E361C-7B3F-4d15-8B1F-66E551FABDC7
+COMPONENT_TYPE = RT_DRIVER
+
+[sources.common]
+ SaLateInitSmm.c
+ SaLateInitSmm.h
+
+#
+# Edk II Glue Driver Entry Point
+#
+ EdkIIGlueSmmDriverEntryPoint.c
+
+[includes.common]
+ $(EDK_SOURCE)/Foundation
+ $(EDK_SOURCE)/Foundation/Efi
+ $(EDK_SOURCE)/Foundation/Framework
+ $(EDK_SOURCE)/Foundation/Include
+ $(EDK_SOURCE)/Foundation/Efi/Include
+ $(EDK_SOURCE)/Foundation/Framework/Include
+ $(EDK_SOURCE)/Foundation/Include/IndustryStandard
+ $(EDK_SOURCE)/Foundation/Core/Dxe
+ $(EDK_SOURCE)/Foundation/Core/Dxe/Include
+ $(EDK_SOURCE)/Foundation/Library/Dxe/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include/Pcd
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include/Library
+ $(EDK_SOURCE)/Foundation/Cpu/Pentium/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Library/SaPcieLib/Common
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)
+
+
+[libraries.common]
+ EdkProtocolLib
+ ArchProtocolLib
+ EdkFrameworkProtocolLib
+ EdkIIGlueBaseLib
+ EdkIIGlueBaseIoLibIntrinsic
+ EdkIIGlueBaseMemoryLib
+ EdkIIGlueDxeMemoryAllocationLib
+ EdkIIGlueDxeDebugLibReportStatusCode
+ EdkIIGlueSmmRuntimeDxeReportStatusCodeLib
+ EdkIIGlueBasePciLibPciExpress
+ EdkIIGlueUefiLib
+ EdkIIGlueUefiBootServicesTableLib
+ EdkIIGlueDxeServicesTableLib
+ EdkIIGlueUefiRuntimeServicesTableLib
+ EdkIIGlueUefiDevicePathLib
+ EfiProtocolLib
+ $(PROJECT_SA_FAMILY)ProtocolLib
+ SaGuidLib
+ EdkIIGlueDxeHobLib
+ CpuPlatformLib
+ SaPcieSmmLib
+ $(PROJECT_PCH_FAMILY)ProtocolLib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT=_ModuleEntryPoint
+ DPX_SOURCE=SaLateInitSmm.dxs
+
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=SaLateInitSmmEntryPoint
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_LIB__ \
+ -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ -D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ -D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \
+ -D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ -D __EDKII_GLUE_SMM_RUNTIME_DXE_REPORT_STATUS_CODE_LIB__ \
+ -D __EDKII_GLUE_UEFI_LIB__\
+ -D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \
+ -D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \
+ -D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \
+ -D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__ \
+ -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \
+ -D __EDKII_GLUE_DXE_HOB_LIB__
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.mak b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.mak
new file mode 100644
index 0000000..dfa035d
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.mak
@@ -0,0 +1,96 @@
+#*************************************************************************
+#*************************************************************************
+#** **
+#** (C)Copyright 1985-2011, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#*************************************************************************
+#*************************************************************************
+
+#---------------------------------------------------------------------------
+# Create SaLateInitSmm Driver
+#---------------------------------------------------------------------------
+EDK : SaLateInitSmm
+SaLateInitSmm : $(BUILD_DIR)\SaLateInitSmm.mak SaLateInitSmmBin
+
+
+$(BUILD_DIR)\SaLateInitSmm.mak : $(SaLateInitSmm_DIR)\$(@B).cif $(SaLateInitSmm_DIR)\$(@B).mak $(BUILD_RULES)
+ $(CIF2MAK) $(SaLateInitSmm_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS)
+
+SaLateInitSmm_INCLUDES=\
+ $(EdkIIGlueLib_INCLUDES)\
+ $(INTEL_MCH_INCLUDES)\
+ $(INTEL_PCH_INCLUDES)\
+ /I$(INTEL_SYSTEM_AGENT_DIR)\Library\SaPcieLib\Common\
+
+SaLateInitSmm_DEFINES = $(MY_DEFINES)\
+ /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=SaLateInitSmmEntryPoint"\
+ /D __EDKII_GLUE_BASE_LIB__ \
+ /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ /D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ /D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \
+ /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ /D __EDKII_GLUE_SMM_RUNTIME_DXE_REPORT_STATUS_CODE_LIB__ \
+ /D __EDKII_GLUE_UEFI_LIB__ \
+ /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \
+ /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \
+ /D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \
+ /D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__ \
+ /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \
+ /D __EDKII_GLUE_DXE_HOB_LIB__ \
+
+SaLateInitSmm_LIB_LINKS =\
+ $(EDKPROTOCOLLIB)\
+ $(ArchProtocolLib)\
+ $(EDKFRAMEWORKPROTOCOLLIB)\
+ $(EdkIIGlueBaseLib_LIB)\
+ $(EdkIIGlueBaseIoLibIntrinsic_LIB)\
+ $(EdkIIGlueBaseMemoryLib_LIB)\
+ $(EdkIIGlueDxeMemoryAllocationLib_LIB)\
+ $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\
+ $(EdkIIGlueSmmRuntimeDxeReportStatusCodeLib_LIB)\
+ $(EdkIIGlueBasePciLibPciExpress_LIB)\
+ $(EdkIIGlueUefiLib_LIB)\
+ $(EdkIIGlueSmmFirmwarePerformanceLib_LIB)\
+ $(EdkIIGlueDxeServicesTableLib_LIB)\
+ $(EdkIIGlueUefiRuntimeServicesTableLib_LIB)\
+ $(EdkIIGlueUefiDevicePathLib_LIB)\
+ $(EFIPROTOCOLLIB)\
+ $(INTEL_SA_PROTOCOL_LIB)\
+ $(SaGuidLib_LIB)\
+ $(EdkIIGlueDxeHobLib_LIB)\
+ $(CpuPlatformLib_LIB)\
+ $(PchPlatformDxeLib_LIB)\
+ $(SaPcieSmmLib_LIB)\
+ $(INTEL_PCH_PROTOCOL_LIB)\
+
+SaLateInitSmmBin: $(COMPILERSTUB) $(SaLateInitSmm_LIB_LINKS)
+ $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\
+ /f $(BUILD_DIR)\SaLateInitSmm.mak all \
+ "MY_INCLUDES=$(SaLateInitSmm_INCLUDES)" \
+ "MY_DEFINES=$(SaLateInitSmm_DEFINES)" \
+ GUID=2D1E361C-7B3F-4d15-8B1F-66E551FABDC7\
+ ENTRY_POINT=_ModuleEntryPoint \
+ TYPE=BS_DRIVER\
+ EDKIIModule=SMMDRIVER\
+ DEPEX1=$(SaLateInitSmm_DIR)\SaLateInitSmm.dxs\
+ DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \
+ COMPRESS=1
+#*************************************************************************
+#*************************************************************************
+#** **
+#** (C)Copyright 1985-2011, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#*************************************************************************
+#*************************************************************************
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.sdl b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.sdl
new file mode 100644
index 0000000..285ea16
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Smm/SaLateInitSmm.sdl
@@ -0,0 +1,26 @@
+TOKEN
+ Name = "SaLateInitSmm_SUPPORT"
+ Value = "1"
+ Help = "Main switch to enable SaLateInitSmm support in Project"
+ TokenType = Boolean
+ TargetEQU = Yes
+ TargetMAK = Yes
+ TargetH = Yes
+ Master = Yes
+End
+
+PATH
+ Name = "SaLateInitSmm_DIR"
+ Help = "SaLateInitSmm file source directory"
+End
+
+MODULE
+ Help = "Includes SaLateInitSmm.mak to Project"
+ File = "SaLateInitSmm.mak"
+End
+
+ELINK
+ Name = "$(BUILD_DIR)\SaLateInitSmm.ffs"
+ Parent = "FV_MAIN"
+ InvokeOrder = AfterParent
+End \ No newline at end of file