summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcApi.h280
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.c529
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.h45
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.c1577
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.h303
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.c678
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.h78
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c481
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.h117
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.c236
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.h74
11 files changed, 4398 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcApi.h b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcApi.h
new file mode 100644
index 0000000..0348c38
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcApi.h
@@ -0,0 +1,280 @@
+/** @file
+ Mrc definition of supported features.
+
+@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 _MrcApi_h_
+#define _MrcApi_h_
+
+#include "MrcTypes.h"
+
+#define HPET_MIN 0x0001 ///< Minimum is one HPET tick = 69.841279ns
+#define HPET_1US 0x000F
+#define HPET_1MS 0x37EF
+
+#define START_TEST_DELAY (2 * HPET_MIN)
+#define IO_RESET_DELAY (2 * HPET_MIN)
+
+#define COMP_INT 0x0A ///< For 10ms
+#define MAX_POSSIBLE_VREF 54 ///< Maximum possible margin for Vref
+#define MAX_POSSIBLE_TIME 31 ///< Maximum possible margin for time
+#define TXEQFULLDRV (0x30) ///< 12 Emphasize legs (not trained)
+#define DIMMRON (ODIC_RZQ_6)
+#define BCLK_DEFAULT (100 * 1000 * 1000)
+
+///
+/// Define the frequencies that may be possible in the memory controller.
+/// Note that not all these values may be supported.
+///
+#define fNoInit (0)
+#define f800 (800)
+#define f1000 (1000)
+#define f1067 (1067)
+#define f1200 (1200)
+#define f1333 (1333)
+#define f1400 (1400)
+#define f1600 (1600)
+#define f1800 (1800)
+#define f1867 (1867)
+#define f2000 (2000)
+#define f2133 (2133)
+#define f2200 (2200)
+#define f2400 (2400)
+#define f2600 (2600)
+#define f2667 (2667)
+#define fUnSupport (0x7FFFFFFF)
+typedef U32 MrcFrequency;
+
+///
+/// Define the memory nominal voltage (VDD).
+/// Note that not all these values may be supported.
+///
+typedef enum {
+ VDD_INVALID,
+ VDD_1_00 = 1000,
+ VDD_1_05 = 1050,
+ VDD_1_10 = 1100,
+ VDD_1_15 = 1150,
+ VDD_1_20 = 1200,
+ VDD_1_25 = 1250,
+ VDD_1_30 = 1300,
+ VDD_1_35 = 1350,
+ VDD_1_40 = 1400,
+ VDD_1_45 = 1450,
+ VDD_1_50 = 1500,
+ VDD_1_55 = 1550,
+ VDD_1_60 = 1600,
+ VDD_1_65 = 1650,
+ VDD_1_70 = 1700,
+ VDD_1_75 = 1750,
+ VDD_1_80 = 1800,
+ VDD_1_85 = 1850,
+ VDD_1_90 = 1900,
+ VDD_1_95 = 1950,
+ VDD_2_00 = 2000,
+ VDD_2_05 = 2050,
+ VDD_2_10 = 2100,
+ VDD_2_15 = 2150,
+ VDD_2_20 = 2200,
+ VDD_2_25 = 2250,
+ VDD_2_30 = 2300,
+ VDD_2_35 = 2350,
+ VDD_2_40 = 2400,
+ VDD_2_45 = 2450,
+ VDD_2_50 = 2500,
+ VDD_2_55 = 2550,
+ VDD_2_60 = 2600,
+ VDD_2_65 = 2650,
+ VDD_2_70 = 2700,
+ VDD_2_75 = 2750,
+ VDD_2_80 = 2800,
+ VDD_2_85 = 2850,
+ VDD_2_90 = 2900,
+ VDD_2_95 = 2950,
+ VDD_MAXIMUM = 0x7FFFFFFF
+} MrcVddSelect;
+
+///
+/// Compile time configuration parameters - START.
+/// The user must set these values for the system.
+///
+#define MAX_EDGES 2 ///< Maximum number of edges.
+#define MAX_BITS 8 ///< BITS per byte.
+#define MAX_MR_IN_DIMM 4 ///< Maximum number of mode registers in a DIMM.
+#define MAX_CPU_SOCKETS 1 ///< The maximum number of CPUs per system.
+#define MAX_CONTROLLERS 1 ///< The maximum number of memory controllers per CPU socket.
+#define MAX_CHANNEL 2 ///< The maximum number of channels per memory controller.
+
+#define MAX_DIMMS_IN_CHANNEL 2 ///< The maximum number of DIMMs per channel.
+
+#define MAX_RANK_IN_DIMM 2 ///< The maximum number of ranks per DIMM.
+#define MAX_RANK_IN_CHANNEL (MAX_DIMMS_IN_CHANNEL * MAX_RANK_IN_DIMM) ///< The maximum number of ranks per channel.
+#define MAX_SDRAM_IN_DIMM 9 ///< The maximum number of SDRAMs per DIMM when ECC is enabled.
+#define MAX_STROBE 18 ///< Number of strobe groups.
+#define MAX_DQ 72 ///< Number of Dq bits used by the rank.
+#define CHAR_BITS 8 ///< Number of bits in a char.
+#define DIMMSIZEMIN 512 ///< The minimum size of DIMM, in MBytes.
+#define DIMMSIZEMAX (16 * 1024) ///< The maximum size of DIMM, in MBytes.
+#define FREQMIN f1067 ///< The minimum valid frequency.
+
+#define SUPPORT_DDR3 SUPPORT ///< SUPPORT means that DDR3 is supported by the MRC.
+#define ULT_SUPPORT_LPDDR3 SUPPORT ///< SUPPORT means that LPDDR3 is supported by the MRC.
+#define TRAD_SUPPORT_LPDDR3 UNSUPPORT ///< SUPPORT means that LPDDR3 is supported by the MRC.
+
+#define SUPPORT_SPD_CRC UNSUPPORT ///< SUPPORT means that the CRC of the DIMMs SPD must match.
+#define SUPPORT_FORCE UNSUPPORT ///< SUPPORT means to force tAA, tRCD, tRP to the same value.
+#define SUPPORT_ALLDIMMS UNSUPPORT ///< SUPPORT means all timings across all DIMMs in the system.
+ ///< UNSUPPORT means all timings across each memory channel's DIMMs.
+#define SUPPORT_XMP SUPPORT ///< SUPPORT means Extreme Memory Profiles are supported, else UNSUPPORT.
+#define SUPPORT_ECC SUPPORT ///< SUPPORT means ECC is suppported, else UNSUPPORT.
+#define SUPPORT_UDIMM SUPPORT ///< SUPPORT means that unbuffered DIMMs are supported, else UNSUPPORT.
+#define SUPPORT_SODIMM SUPPORT ///< SUPPORT means that SO-DIMMs are supported, else UNSUPPORT.
+#define SUPPORT_RDIMM UNSUPPORT ///< SUPPORT means that registered DIMMs are supported, else UNSUPPORT.
+#define SUPPORT_PRIWIDTH_8 UNSUPPORT ///< SUPPORT means that SDRAM primary bus width of 8 is supported by the system.
+#define SUPPORT_PRIWIDTH_16 UNSUPPORT ///< SUPPORT means that SDRAM primary bus width of 16 is supported by the system.
+#define SUPPORT_PRIWIDTH_32 UNSUPPORT ///< SUPPORT means that SDRAM primary bus width of 32 is supported by the system.
+#define SUPPORT_PRIWIDTH_64 SUPPORT ///< SUPPORT means that SDRAM primary bus width of 64 is supported by the system.
+#define SUPPORT_DEVWIDTH_4 UNSUPPORT ///< SUPPORT means that SDRAM device width of 4 is supported by the system.
+#define SUPPORT_DEVWIDTH_8 SUPPORT ///< SUPPORT means that SDRAM device width of 8 is supported by the system.
+#define SUPPORT_DEVWIDTH_16 SUPPORT ///< SUPPORT means that SDRAM device width of 16 is supported by the system.
+#define SUPPORT_DEVWIDTH_32 SUPPORT ///< SUPPORT means that SDRAM device width of 32 is supported by the system.
+#define SUPPORT_COLUMN_9 UNSUPPORT ///< SUPPORT means that 9 bit size is supported by the system.
+
+#define ULT_SUPPORT_COLUMN_10 SUPPORT ///< SUPPORT means that 10 bit size is supported by the system.
+#define ULT_SUPPORT_COLUMN_11 SUPPORT ///< SUPPORT means that 11 bit size is supported by the system.
+#define ULT_SUPPORT_COLUMN_12 SUPPORT ///< SUPPORT means that 12 bit size is supported by the system.
+#define TRAD_SUPPORT_COLUMN_10 SUPPORT ///< SUPPORT means that 10 bit size is supported by the system.
+#define TRAD_SUPPORT_COLUMN_11 UNSUPPORT ///< SUPPORT means that 11 bit size is supported by the system.
+#define TRAD_SUPPORT_COLUMN_12 UNSUPPORT ///< SUPPORT means that 12 bit size is supported by the system.
+
+#define SUPPORT_ROW_12 SUPPORT ///< SUPPORT means that 12 bit size is supported by the system.
+#define SUPPORT_ROW_13 SUPPORT ///< SUPPORT means that 13 bit size is supported by the system.
+#define SUPPORT_ROW_14 SUPPORT ///< SUPPORT means that 14 bit size is supported by the system.
+#define SUPPORT_ROW_15 SUPPORT ///< SUPPORT means that 15 bit size is supported by the system.
+#define SUPPORT_ROW_16 SUPPORT ///< SUPPORT means that 16 bit size is supported by the system.
+#define SUPPORT_BANK_8 SUPPORT ///< SUPPORT means that 8 banks is supported by the system.
+#define SUPPORT_BANK_16 UNSUPPORT ///< SUPPORT means that 16 banks is supported by the system.
+#define SUPPORT_BANK_32 UNSUPPORT ///< SUPPORT means that 32 banks is supported by the system.
+#define SUPPORT_BANK_64 UNSUPPORT ///< SUPPORT means that 64 banks is supported by the system.
+
+#define TAAMINPOSSIBLE 4 ///< tAAmin possible range, in number of tCK cycles.
+#define TAAMAXPOSSIBLE 24
+#define TWRMINPOSSIBLE 5 ///< tWRmin possible range, in number of tCK cycles.
+#define TWRMAXPOSSIBLE 16 ///< tWRmin values of 9, 11, 13 ,15 are not valid for DDR3.
+#define TRCDMINPOSSIBLE 4 ///< tRCDmin possible range, in number of tCK cycles.
+#define TRCDMAXPOSSIBLE 20
+#define TRRDMINPOSSIBLE 4 ///< tRRDmin possible range, in number of tCK cycles.
+#define TRRDSMINPOSSIBLE 4 ///< tRRD_Smin possible range, in number of tCK cycles.
+#define TRRDSMAXPOSSIBLE 65535
+#define TRRDLMINPOSSIBLE 4 ///< tRRD_Lmin possible range, in number of tCK cycles.
+#define TRRDLMAXPOSSIBLE 65535
+#define TRPMINPOSSIBLE 4 ///< tRPmin possible range, in number of tCK cycles.
+#define TRPMAXPOSSIBLE 15
+#define TRPABMINPOSSIBLE 4 ///< tRPabmin possible range, in number of tCK cycles.
+#define TRPABMAXPOSSIBLE 18
+#define TRASMINPOSSIBLE 10 ///< tRASmin possible range, in number of tCK cycles.
+#define TRASMAXPOSSIBLE 40
+#define TRCMINPOSSIBLE 1 ///< tRCmin possible range, in number of tCK cycles.
+#define TRCMAXPOSSIBLE 4095
+#define TRFCMINPOSSIBLE 1 ///< tRFCmin possible range, in number of tCK cycles.
+#define TRFCMAXPOSSIBLE 511
+#define TWTRMINPOSSIBLE 4 ///< tWTRmin possible range, in number of tCK cycles.
+#define TWTRMAXPOSSIBLE 10
+#define TRTPMINPOSSIBLE 4 ///< tRTPmin possible range, in number of tCK cycles.
+#define TRTPMAXPOSSIBLE 15
+#define TFAWMINPOSSIBLE 10 ///< tFAWmin possible range, in number of tCK cycles.
+#define TFAWMAXPOSSIBLE 54
+#define TCWLMINPOSSIBLE 5 ///< tCWLmin possible range, in number of tCK cycles.
+#define TCWLMAXPOSSIBLE 12
+#define TREFIMINPOSSIBLE 1 ///< tREFImin possible range, in number of tCK cycles.
+#define TREFIMAXPOSSIBLE 65535
+#define NMODEMINPOSSIBLE 1 ///< Command rate mode min possible range, in number of tCK cycles.
+#define NMODEMAXPOSSIBLE 3
+
+#define ULT_VDDMINPOSSIBLE 1200 ///< Vdd possible range, in milliVolts.
+#define ULT_VDDMAXPOSSIBLE 1350
+#define TRAD_VDDMINPOSSIBLE 1350 ///< Vdd possible range, in milliVolts.
+#define TRAD_VDDMAXPOSSIBLE 1500
+
+#define SPD3_MANUF_START 117 ///< The starting point for the SPD manufacturing data.
+#define SPD3_MANUF_END 127 ///< The ending point for the SPD manufacturing data.
+#define HOST_BRIDGE_BUS 0 ///< The host bridge bus number.
+#define HOST_BRIDGE_DEVICE 0 ///< The host bridge device number.
+#define HOST_BRIDGE_FUNCTION 0 ///< The host bridge function number.
+#define HOST_BRIDGE_DEVID 0 ///< The host bridge device id offset.
+#define HOST_BRIDGE_REVID 8 ///< The host bridge revision id offset.
+
+#define MEMORY_RATIO_MIN 3 ///< The minimum DDR ratio value that the hardware supports.
+#define MEMORY_RATIO_MAX 15 ///< The maximum DDR ratio value that the hardware supports.
+
+///
+/// Compile time configuration parameters - END.
+///
+
+#if (defined ULT_FLAG && defined TRAD_FLAG)
+#define SUPPORT_LPDDR3 (ULT_SUPPORT_LPDDR3 || TRAD_SUPPORT_LPDDR3)
+#define SUPPORT_COLUMN_10 (ULT_SUPPORT_COLUMN_10 || TRAD_SUPPORT_COLUMN_10)
+#define SUPPORT_COLUMN_11 (ULT_SUPPORT_COLUMN_11 || TRAD_SUPPORT_COLUMN_11)
+#define SUPPORT_COLUMN_12 (ULT_SUPPORT_COLUMN_12 || TRAD_SUPPORT_COLUMN_12)
+#define VDDMINPOSSIBLE MIN (ULT_VDDMINPOSSIBLE, TRAD_VDDMINPOSSIBLE)
+#define VDDMAXPOSSIBLE MAX (ULT_VDDMAXPOSSIBLE, TRAD_VDDMAXPOSSIBLE)
+#elif (defined ULT_FLAG)
+#define SUPPORT_LPDDR3 ULT_SUPPORT_LPDDR3
+#define SUPPORT_COLUMN_10 ULT_SUPPORT_COLUMN_10
+#define SUPPORT_COLUMN_11 ULT_SUPPORT_COLUMN_11
+#define SUPPORT_COLUMN_12 ULT_SUPPORT_COLUMN_12
+#define VDDMINPOSSIBLE ULT_VDDMINPOSSIBLE
+#define VDDMAXPOSSIBLE ULT_VDDMAXPOSSIBLE
+#elif (defined TRAD_FLAG)
+#define SUPPORT_LPDDR3 TRAD_SUPPORT_LPDDR3
+#define SUPPORT_COLUMN_10 TRAD_SUPPORT_COLUMN_10
+#define SUPPORT_COLUMN_11 TRAD_SUPPORT_COLUMN_11
+#define SUPPORT_COLUMN_12 TRAD_SUPPORT_COLUMN_12
+#define VDDMINPOSSIBLE TRAD_VDDMINPOSSIBLE
+#define VDDMAXPOSSIBLE TRAD_VDDMAXPOSSIBLE
+#endif // ULT_FLAG && TRAD_FLAG
+
+#define MRC_ALL_DDR_SUPPORTED ((SUPPORT_DDR4 == SUPPORT) && ((SUPPORT_DDR3 == SUPPORT) || (SUPPORT_LPDDR3 == SUPPORT)))
+#define MRC_DDR3_LPDDR_SUPPORTED ((SUPPORT_DDR3 == SUPPORT) || (SUPPORT_LPDDR3 == SUPPORT))
+
+///
+/// Exit mode
+///
+typedef enum {
+ emSlow = 0,
+ emFast = 1,
+ emAuto = 0xFF,
+} MrcExitMode;
+
+///
+/// System definitions
+///
+#define MRC_SYSTEM_BCLK (100)
+
+///
+/// Register default values
+///
+#define MRC_DIMM_RANK_INTERLEAVE (1)
+#define MRC_ENHANCED_INTERLEAVE_MODE (1)
+#define MRC_HORI_MODE (1)
+
+///
+/// Training definitions
+///
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.c
new file mode 100644
index 0000000..7670487
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.c
@@ -0,0 +1,529 @@
+/** @file
+ Copies the memory related timing and configuration information into the
+ Compatible BIOS data (BDAT) table.
+
+@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 "MrcTypes.h"
+#include "MrcApi.h"
+#include "MrcGlobal.h"
+#include "MrcOem.h"
+#include "MrcSpdProcessing.h"
+#include "McAddress.h"
+
+#ifdef BDAT_SUPPORT
+#define TBD 0
+#define CRC_SEED 0
+#define CRC_XOR_MASK 0x1021
+#define MAX_UINT8_VALUE (((1UL) << CHAR_BITS) - 1)
+#define HOST_BRIDGE_BUS 0
+#define HOST_BRIDGE_DEVICE 0
+#define HOST_BRIDGE_FUNCTION 0
+#define HOST_BRIDGE_OFFSET_DEVID 0
+#define HOST_BRIDGE_OFFSET_REVID 8
+#define CopyMem MrcOemMemoryCpy
+#define GetCrc16 GetDimmCrc
+
+typedef U8 UINT8;
+typedef U16 UINT16;
+
+/**
+ @brief
+ Finds the window value for the given DQ value and if it is less than the
+ current value, then save the end point values.
+
+ @param[in, out] Rank1 - Pointer to the first rank training value (left or low).
+ @param[in, out] Rank2 - Pointer to the second rank training value (right or high).
+ @param[in, out] CurrentWindow - The current window value.
+ @param[in] Value1 - The first training value (left or low).
+ @param[in] Value2 - The second training value (right or high).
+
+ @retval Nothing.
+**/
+void
+ConvertDq2Rank (
+ IN OUT UINT8 *Rank1,
+ IN OUT UINT8 *Rank2,
+ IN OUT UINT8 *CurrentWindow,
+ IN const UINT8 Value1,
+ IN const UINT8 Value2
+ )
+{
+ UINT8 Window; // The calculated window value.
+
+ Window = MAX (Value1, Value2) - MIN (Value1, Value2);
+ if (Window < *CurrentWindow) {
+ *CurrentWindow = Window;
+ *Rank1 = Value1;
+ *Rank2 = Value2;
+ } // if
+ return;
+}
+
+/**
+@brief
+ Initialize the memory rank margin area of the RMT_STRUCTURE.
+
+ @param[in] MrcData - The MRC "global data".
+ @param[in, out] RmtRankMargin - Pointer to the start of the rank margin information in the RMT table.
+ @param[in] RmtDq - Pointer to the start of the dq margin information in the RMT table.
+
+ @retval Nothing.
+**/
+void
+MrcFillRmtRankMargin (
+ IN const MrcParameters *MrcData,
+ IN OUT RmtRankMargin *RmtRankMargin,
+ IN RmtDqMargin *RmtDq
+ )
+{
+ RmtDqMargin *RmtDqMargin; // Pointer to the current DQ margin in the RMT structure.
+ UINT8 Dq; // DQ number in the rank.
+ UINT8 DqEnd;
+ UINT8 SmallestWindowRxDq; // The smallest of the Rx DQ windows.
+ UINT8 SmallestWindowTxDq; // The smallest of the Tx DQ windows.
+ UINT8 SmallestWindowRxVref; // The smallest of the Rx Vref windows.
+ UINT8 SmallestWindowTxVref; // The smallest of the Tx Vref windows.
+
+ SmallestWindowRxDq = (UINT8) MAX_UINT8_VALUE;
+ SmallestWindowTxDq = (UINT8) MAX_UINT8_VALUE;
+ SmallestWindowRxVref = (UINT8) MAX_UINT8_VALUE;
+ SmallestWindowTxVref = (UINT8) MAX_UINT8_VALUE;
+ DqEnd = (MrcData->SysOut.Outputs.EccSupport) ? MAX_DQ : (MAX_DQ - MAX_BITS);
+ for (Dq = 0; Dq < DqEnd; Dq++) {
+ RmtDqMargin = &RmtDq[Dq];
+ ConvertDq2Rank (
+ &RmtRankMargin->RxDqLeft,
+ &RmtRankMargin->RxDqRight,
+ &SmallestWindowRxDq,
+ RmtDqMargin->RxDqLeft,
+ RmtDqMargin->RxDqRight
+ );
+ ConvertDq2Rank (
+ &RmtRankMargin->TxDqLeft,
+ &RmtRankMargin->TxDqRight,
+ &SmallestWindowTxDq,
+ RmtDqMargin->TxDqLeft,
+ RmtDqMargin->TxDqRight
+ );
+ ConvertDq2Rank (
+ &RmtRankMargin->RxVrefLow,
+ &RmtRankMargin->RxVrefHigh,
+ &SmallestWindowRxVref,
+ RmtDqMargin->RxVrefLow,
+ RmtDqMargin->RxVrefHigh
+ );
+ ConvertDq2Rank (
+ &RmtRankMargin->TxVrefLow,
+ &RmtRankMargin->TxVrefHigh,
+ &SmallestWindowTxVref,
+ RmtDqMargin->TxVrefLow,
+ RmtDqMargin->TxVrefHigh
+ );
+ } // Dq loop
+ return;
+}
+
+/**
+@brief
+ Initialize the memory DQ area of the RMT_STRUCTURE.
+
+ @param[in, out] RmtDq - Pointer to the start of the DQ information in the RMT table.
+ @param[in] Channel - Specific Channel
+ @param[in] Dimm - Specific Dimm
+ @param[in] Rank - Specific Rank
+ @param[in] MrcData - The MRC "global data".
+
+ @retval Nothing.
+**/
+void
+MrcFillRmtDqMargin (
+ IN OUT RmtDqMargin *RmtDq,
+ IN const UINT8 Controller,
+ IN const UINT8 Channel,
+ IN const UINT8 Dimm,
+ IN const UINT8 Rank,
+ IN const MrcParameters *MrcData
+ )
+{
+ const MrcOutput *Outputs;
+ const MrcChannelOut *ChannelOut;
+ const MrcDqTimeMargin *RxDqMargin; // Pointer to the output portion of the MRC global data area.
+ const MrcDqTimeMargin *TxDqMargin; // Pointer to the output portion of the MRC global data area.
+ const MrcDqVrefMargin *RxVrefDqMargin; // Pointer to the output portion of the MRC global data area.
+ const MrcDqVrefMargin *TxVrefDqMargin; // Pointer to the output portion of the MRC global data area.
+ RmtDqMargin *RmtDqMargin; // Pointer to the current DQ margin in the RMT structure.
+ UINT8 RankInChannel;
+ UINT8 Sdram;
+ UINT8 Dq; // DQ number in the rank.
+ UINT8 DqEnd;
+ UINT8 Bit;
+
+ Outputs = &MrcData->SysOut.Outputs;
+ ChannelOut = &Outputs->Controller[Controller].Channel[Channel];
+ RankInChannel = (Dimm * MAX_RANK_IN_DIMM) + Rank;
+ DqEnd = (Outputs->EccSupport) ? MAX_DQ : (MAX_DQ - MAX_BITS);
+ for (Dq = 0; Dq < DqEnd; Dq++) {
+ Sdram = Dq / CHAR_BITS;
+ Bit = Dq % CHAR_BITS;
+ RxDqMargin = &ChannelOut->RxDqPb[RankInChannel][Sdram][Bit];
+ TxDqMargin = &ChannelOut->TxDqPb[RankInChannel][Sdram][Bit];
+ RxVrefDqMargin = &ChannelOut->RxDqVrefPb[RankInChannel][Sdram][Bit];
+ TxVrefDqMargin = &ChannelOut->TxDqVrefPb[RankInChannel][Sdram][Bit];
+ RmtDqMargin = &RmtDq[Dq];
+ RmtDqMargin->RxDqLeft = RxDqMargin->Left;
+ RmtDqMargin->RxDqRight = RxDqMargin->Right;
+ RmtDqMargin->TxDqLeft = TxDqMargin->Left;
+ RmtDqMargin->TxDqRight = TxDqMargin->Right;
+ RmtDqMargin->RxVrefLow = RxVrefDqMargin->Low;
+ RmtDqMargin->RxVrefHigh = RxVrefDqMargin->High;
+ RmtDqMargin->TxVrefLow = TxVrefDqMargin->Low;
+ RmtDqMargin->TxVrefHigh = TxVrefDqMargin->High;
+ } // Dq loop
+ return;
+}
+
+/**
+@brief
+ Initialize the memory rank training area of the RMT_STRUCTURE.
+
+ @param[in, out] RmtRankTraining - Pointer to the start of the rank training information in the RMT table.
+ @param[in] Channel - Specific Channel
+ @param[in] Dimm - Specific Dimm
+ @param[in] Rank - Specific Rank
+ @param[in] MrcData - The MRC "global data".
+
+ @retval Nothing.
+**/
+void
+MrcFillRmtRankTraining (
+ IN OUT RmtRankTraining *RmtRankTraining,
+ IN const UINT8 Controller,
+ IN const UINT8 Channel,
+ IN const UINT8 Dimm,
+ IN const UINT8 Rank,
+ IN const MrcParameters *MrcData
+ )
+{
+ const MrcOutput *Outputs; // Pointer to the output portion of the MRC global data area.
+ const MrcChannelOut *ChannelOut; // Pointer to the channel portion of the MRC global data area.
+ UINT8 Index;
+ UINT8 RankInChannel;
+ UINT8 Sdram;
+ UINT8 Strobe;
+
+ Outputs = &MrcData->SysOut.Outputs;
+ ChannelOut = &Outputs->Controller[Controller].Channel[Channel];
+ RankInChannel = (Dimm * MAX_RANK_IN_DIMM) + Rank;
+ for (Strobe = 0; Strobe < MAX_STROBE; Strobe++) {
+ Sdram = Strobe / 2;
+ RmtRankTraining->RecEnDelay[Strobe] = ChannelOut->RcvEn[RankInChannel][Sdram];
+ RmtRankTraining->WlDelay[Strobe] = ChannelOut->WlDelay[RankInChannel][Sdram];
+ RmtRankTraining->RxDqDelay[Strobe] = (Strobe % 2)
+ ? ChannelOut->RxDqsN[RankInChannel][Sdram]
+ : ChannelOut->RxDqsP[RankInChannel][Sdram];
+ RmtRankTraining->TxDqDelay[Strobe] = ((U8) (ChannelOut->TxDq[RankInChannel][Sdram] >> 6)) & 7;
+ } // Strobe loop
+ RmtRankTraining->ClkDelay = ChannelOut->ClkPiCode[RankInChannel];
+ RmtRankTraining->CtlDelay = ChannelOut->CtlPiCode[RankInChannel];
+ for (Index = 0; Index < (sizeof (RmtRankTraining->CmdDelay) / sizeof (RmtRankTraining->CmdDelay[0])); Index++) {
+ RmtRankTraining->CmdDelay[Index] = TBD; // Need to implement code.
+ } // Index loop
+ RmtRankTraining->IoLatency = ChannelOut->IoLatency[RankInChannel];
+ RmtRankTraining->Roundtrip = ChannelOut->RTLatency[RankInChannel];
+ return;
+}
+
+/**
+@brief
+ Initialize the memory rank area of the RMT_STRUCTURE.
+
+ @param[in, out] RmtRank - Pointer to the start of the rank information in the RMT table.
+ @param[in] MrcData - The MRC "global data".
+ @param[in] Channel - Current channel number.
+ @param[in] Dimm - Current dimm number.
+
+ @retval Nothing.
+**/
+void
+MrcFillRmtRankStructure (
+ IN OUT RmtRankList *RmtRank,
+ IN const MrcParameters *MrcData,
+ IN UINT8 Controller,
+ IN UINT8 Channel,
+ IN UINT8 Dimm
+)
+{
+ const MrcOutput *Outputs; // Pointer to the output portion of the MRC global data area.
+ const MrcChannelOut *ChannelOut; // Pointer to the DIMM output portion of the MRC global data area.
+ const MrcDimmOut *DimmOut; // Pointer to the DIMM output portion of the MRC global data area.
+ RmtRankList *RmtRankLists; // Pointer to the current rank list in the RMT structure.
+ RmtRankTraining *RmtRankTraining; // Pointer to the current rank training in the RMT structure.
+ UINT8 Rank; // Rank count for sequencing.
+ UINT8 RankInChannel; // Rank number in a channel.
+
+ Outputs = &MrcData->SysOut.Outputs;
+ ChannelOut = &Outputs->Controller[Controller].Channel[Channel];
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ for (Rank = 0; (Rank < MAX_RANK_IN_DIMM) && (Rank < DimmOut->RankInDIMM); Rank++) {
+ RmtRankLists = &RmtRank[Rank];
+ RmtRankTraining = &RmtRankLists->RankTraining;
+ RankInChannel = (Dimm * MAX_RANK_IN_DIMM) + Rank;
+ RmtRankLists->RankEnabled = TRUE;
+ RmtRankLists->RankMarginEnabled = TRUE;
+ RmtRankLists->DqMarginEnabled = TRUE;
+ MrcFillRmtDqMargin (&RmtRankLists->DqMargin[0], Controller, Channel, Dimm, Rank, MrcData);
+ MrcFillRmtRankMargin (MrcData, &RmtRankLists->RankMargin, &RmtRankLists->DqMargin[0]);
+ MrcFillRmtRankTraining (&RmtRankLists->RankTraining, Controller, Channel, Dimm, Rank, MrcData);
+ CopyMem (
+ (UINT8 *) &RmtRankLists->RankMRS.ModeRegister[0],
+ (UINT8 *) &DimmOut->Rank[Rank].MR[0],
+ sizeof (RmtRankMrs)
+ );
+ RmtRankLists->RankMargin.CmdLeft = ChannelOut->Command[RankInChannel].Left;
+ RmtRankLists->RankMargin.CmdRight = ChannelOut->Command[RankInChannel].Right;
+ RmtRankLists->RankMargin.CmdVrefLow = ChannelOut->Command[RankInChannel].Low;
+ RmtRankLists->RankMargin.CmdVrefHigh = ChannelOut->Command[RankInChannel].High;
+ RmtRankLists->RankMargin.RecvenLeft = ChannelOut->ReceiveEnable[RankInChannel].Left;
+ RmtRankLists->RankMargin.RecvenRight = ChannelOut->ReceiveEnable[RankInChannel].Right;
+ RmtRankLists->RankMargin.WrLevelLeft = ChannelOut->WriteLevel[RankInChannel].Left;
+ RmtRankLists->RankMargin.WrLevelRight = ChannelOut->WriteLevel[RankInChannel].Right;
+ } // Rank loop
+ return;
+}
+
+/**
+@brief
+ Initialize the memory dimm area of the RMT_STRUCTURE.
+
+ @param[in, out] RmtDimm - Pointer to the start of the dimm information in the RMT table.
+ @param[in] MrcData - The MRC "global data".
+ @param[in] Channel - Current channel number.
+
+ @retval Nothing.
+**/
+void
+MrcFillRmtDimmStructure (
+ IN OUT RmtDimmList *RmtDimm,
+ IN const MrcParameters *MrcData,
+ IN UINT8 Controller,
+ IN UINT8 Channel
+ )
+{
+ const MrcInput *Inputs; // Pointer to the input portion of the MRC global data area.
+ const MrcDimmIn *DimmIn; // Pointer to the DIMM input portion of the MRC global data area.
+ const MrcSpd *SpdIn; // Pointer to the SPD input portion of the MRC global data area.
+ const MrcOutput *Outputs; // Pointer to the output portion of the MRC global data area.
+ const MrcChannelOut *ChannelOut; // Pointer to the channel output portion of the MRC global data area.
+ const MrcDimmOut *DimmOut; // Pointer to the DIMM output portion of the MRC global data area.
+ RmtDimmList *RmtDimmList; // Pointer to the current DIMM in the RMT structure.
+ RmtSpd *RmtSpdList; // Pointer to the current SPD in the RMT structure.
+ UINT8 Dimm; // Dimm count for sequencing.
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ ChannelOut = &Outputs->Controller[Controller].Channel[Channel];
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ if (DimmOut->Status == DIMM_PRESENT) {
+ RmtDimmList = &RmtDimm[Dimm];
+ RmtSpdList = &RmtDimmList->SpdBytes;
+ DimmIn = &Inputs->Controller[Controller].Channel[Channel].Dimm[Dimm];
+ SpdIn = &DimmIn->Spd;
+ RmtDimmList->DimmEnabled = TRUE;
+ CopyMem ((UINT8 *) &RmtSpdList->SpdData[0], (UINT8 *) SpdIn, 128);
+#if (defined SUPPORT_XMP && SUPPORT_XMP == SUPPORT)
+ CopyMem (&RmtSpdList->SpdData[128], ((UINT8 *) SpdIn) + 128, 128);
+#endif // (defined SUPPORT_XMP && SUPPORT_XMP == SUPPORT)
+ CopyMem ((UINT8 *) &RmtSpdList->SpdValid, (UINT8 *) &DimmIn->SpdValid, sizeof (RmtDimmList->SpdBytes.SpdValid));
+
+ //
+ // Initialize the memory rank area of the RMT_STRUCTURE.
+ //
+ MrcFillRmtRankStructure (&RmtDimmList->RankList[0], MrcData, Controller, Channel, Dimm);
+ } // end if
+ } // Dimm loop
+ return;
+}
+
+/**
+@brief
+ Initialize the memory channel area of the RMT_STRUCTURE.
+
+ @param[in, out] RmtChannel - Pointer to the start of the channel information in the RMT table.
+ @param[in] MrcData - The MRC "global data".
+
+ @retval Nothing.
+**/
+void
+MrcFillRmtChannelStructure (
+ IN OUT RmtChannelList *RmtChannel,
+ IN const MrcParameters *MrcData,
+ IN const UINT8 Controller
+ )
+{
+ const MrcOutput *Outputs; // Pointer to the output portion of the MRC global data area.
+ RmtChannelList *RmtChannelList; // Pointer to the current channel in the RMT structure.
+ UINT8 Channel; // Channel count for sequencing.
+
+ Outputs = &MrcData->SysOut.Outputs;
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (Outputs->Controller[Controller].Channel[Channel].Status == CHANNEL_PRESENT) {
+ RmtChannelList = &RmtChannel[Channel];
+ RmtChannelList->ChannelEnabled = TRUE;
+ RmtChannelList->NumDimmSlot = MAX_DIMMS_IN_CHANNEL;
+
+ //
+ // Initialize the memory DIMM area of the RMT_STRUCTURE.
+ //
+ MrcFillRmtDimmStructure (&RmtChannelList->DimmList[0], MrcData, Controller, Channel);
+ } // end if
+ } // Channel loop
+ return;
+}
+
+/**
+@brief
+ Initialize the memory controller area of the RMT_STRUCTURE.
+
+ @param[in, out] RmtController - Pointer to the start of the controller information in the RMT table.
+ @param[in] MrcData - The MRC "global data".
+
+ @retval Nothing.
+**/
+void
+MrcFillRmtControllerStructure (
+ IN OUT RmtControllerList *RmtController,
+ IN const MrcParameters *MrcData
+ )
+{
+ const MrcInput *Inputs;
+ const MrcOutput *Outputs;
+ RmtControllerList *RmtControllerList;
+ UINT8 Controller;
+ MrcVddSelect VddVoltage;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ VddVoltage = Outputs->VddVoltage[Inputs->MemoryProfile];
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ if (Outputs->Controller[Controller].Status == CONTROLLER_PRESENT) {
+ RmtControllerList = &RmtController[Controller];
+ RmtControllerList->ControllerEnabled = TRUE;
+ RmtControllerList->ControllerDeviceId = Outputs->Controller[Controller].DeviceId;
+ RmtControllerList->ControllerRevisionId = Outputs->Controller[Controller].RevisionId;
+ RmtControllerList->MemoryFrequency = (UINT16) (Outputs->Frequency / 10);
+ RmtControllerList->MemoryVoltage = (UINT16) VddVoltage;
+ //
+ // Step unit = piStep * (tCK / 2048)
+ //
+ RmtControllerList->PiStep = (UINT8) PI_STEP;
+ RmtControllerList->RecvenStep = (UINT8) PI_STEP;
+ RmtControllerList->WrLevelStep = (UINT8) PI_STEP;
+ if (VddVoltage > 0) {
+ //
+ // Step unit = __VrefStep * Vdd / 100
+ //
+ RmtControllerList->RxVrefStep = (UINT16) RX_VREF (VddVoltage);
+ RmtControllerList->TxVrefStep = (UINT16) TX_VREF (VddVoltage);
+ RmtControllerList->CaVrefStep = (UINT16) CA_VREF (VddVoltage);
+ } else {
+ RmtControllerList->RxVrefStep = 0;
+ RmtControllerList->TxVrefStep = 0;
+ RmtControllerList->CaVrefStep = 0;
+ }
+ //
+ // Initialize the memory channel area of the RMT_STRUCTURE.
+ //
+ MrcFillRmtChannelStructure (&RmtControllerList->ChannelList[0], MrcData, Controller);
+ } // Controller loop
+ }
+
+ return;
+}
+
+/**
+@brief
+ Fill the compatible data structure RMT with the information provided by
+ the memory initialization code.
+
+ @param[in, out] MrcData - Constant pointer to the Mrc data structure which conatins the Rmt structure to fill.
+
+ @retval Nothing.
+**/
+MrcStatus
+MrcFillRmtStructure (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const UINT8 RmtHeaderSign[] = {'B', 'D', 'A', 'T', 'H', 'E', 'A', 'D'};
+ const MrcVersion *Version; // Pointer to the output portion of the MRC global data area.
+ RmtData *Rmt;
+ RmtHeader *RmtHeader; // Pointer to the header data area in the RMT structure.
+ RmtSystem *RmtSystem; // Pointer to the system data area in the RMT structure.
+ const MrcInput *Inputs;
+ MrcOutput *Outputs;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ if (Inputs->RmtBdatEnable) {
+ //
+ // Initialize the header area of the RMT_STRUCTURE.
+ //
+ Rmt = &MrcData->Rmt;
+ RmtHeader = &Rmt->RmtHeader;
+ CopyMem (&RmtHeader->BiosDataSignature[0], (UINT8 *) RmtHeaderSign, sizeof (RmtHeader->BiosDataSignature));
+ RmtHeader->BiosDataStructSize = sizeof (RmtData);
+ RmtHeader->Version.S[PRIMARY_OFFSET] = RMT_PRIMARY_VERSION;
+ RmtHeader->Version.S[SECONDARY_OFFSET] = RMT_SECONDARY_VERSION;
+ RmtHeader->OemOffset = OEM_OFFSET;
+ RmtHeader->Reserved1 = (Inputs->BaseTime.Hours << 16) | (Inputs->BaseTime.Minutes << 8) | Inputs->BaseTime.Seconds;
+ RmtHeader->Reserved2 = (Inputs->BaseTime.Year << 16) | (Inputs->BaseTime.Month << 8) | Inputs->BaseTime.DayOfMonth;
+
+ //
+ // Initialize the system area of the RMT_STRUCTURE.
+ //
+ Version = &Outputs->Version;
+ RmtSystem = &Rmt->RmtSystem;
+ RmtSystem->RefCodeRevision.c.Major = Version->Major;
+ RmtSystem->RefCodeRevision.c.Minor = Version->Minor;
+ RmtSystem->RefCodeRevision.c.Revision = Version->Rev;
+ RmtSystem->RefCodeRevision.c.Build = Version->Build;
+ RmtSystem->MaxController = MAX_CONTROLLERS;
+ RmtSystem->MaxChannel = MAX_CHANNEL;
+ RmtSystem->MaxDimm = MAX_DIMMS_IN_CHANNEL;
+ RmtSystem->MaxRankDimm = MAX_RANK_IN_DIMM;
+ RmtSystem->MaxStrobe = MAX_STROBE;
+ RmtSystem->MaxDq = MAX_DQ;
+ RmtSystem->MarginLoopCount = Outputs->DQPatLC;
+ //
+ // Initialize the memory controller area of the RMT_STRUCTURE.
+ //
+ MrcFillRmtControllerStructure (&RmtSystem->ControllerList[0], MrcData);
+
+ //
+ // Initialize the CRC of the RMT_STRUCTURE.
+ // Ensure that the CRC calculation is the last field initialized.
+ //
+ GetCrc16 ((const UINT8 *const) Rmt, sizeof (RmtData), &Rmt->RmtHeader.Crc16);
+ MrcOemMmioWrite (NCDECS_CR_SCRATCHPAD_NCU_2_REG, (U32) Rmt, Inputs->MchBarBaseAddress);
+ } // end if
+ return mrcSuccess;
+}
+#endif // BDAT_SUPPORT
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.h b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.h
new file mode 100644
index 0000000..a7232ae
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcBdat.h
@@ -0,0 +1,45 @@
+/** @file
+ Copies the memory related timing and configuration information into the
+ Compatible BIOS data (BDAT) table.
+
+@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 _MrcBdat_h_
+#define _MrcBdat_h_
+#pragma pack(push, 1)
+
+#include "MrcTypes.h"
+#include "MrcApi.h"
+
+/**
+ Fill the compatible data structure RMT with the information provided by
+ the memory initialization code.
+
+ @param[in, out] MrcData - Constant pointer to the Mrc data structure which conatins the Rmt structure to fill.
+
+ @retval Nothing.
+**/
+extern
+MrcStatus
+MrcFillRmtStructure (
+ IN OUT MrcParameters *const MrcData
+ );
+
+#pragma pack(pop)
+#endif // _MrcBdat_h_
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.c
new file mode 100644
index 0000000..635c786
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.c
@@ -0,0 +1,1577 @@
+/** @file
+ This file all the MRC general API to the MRC wrapper.
+
+@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 "MrcGeneral.h"
+#include "MrcDdr3.h"
+const MrcVersion cVersion = {
+#include "MrcVersion.h"
+};
+
+#ifdef ULT_FLAG
+//
+// This table is used for LPDDR3 MR5 decoding
+//
+struct {
+ U8 VendorId;
+ char *VendorName;
+} DramVendorList [] = {
+ { 1, "Samsung" },
+ { 3, "Elpida" },
+ { 6, "Hynix" }
+};
+#endif // ULT_FLAG
+
+/**
+@brief
+ Thisfunction performs Software Memory testing
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval Always returns mrcSuccess.
+**/
+MrcStatus
+MrcHwMemTest (
+ IN MrcParameters *const MrcData
+ )
+{
+ MrcStatus Status;
+
+ Status = mrcSuccess;
+
+ return Status;
+}
+
+/**
+@brief
+ This function changes the MC to normal mode, enables the ECC if needed, lock configuration and set PU_MRC_Done.
+ If the ECC is enabled, this function should be called after memory is cleaned.
+
+ @param[in, out] MrcData - Include all MRC global data.
+
+ @retval Always returns mrcSuccess.
+**/
+MrcStatus
+MrcMcActivate (
+ IN MrcParameters *const MrcData
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcOutput *Outputs;
+ MrcControllerOut *ControllerOut;
+ MrcChannelOut *ChannelOut;
+ MrcCpuModel CpuModel;
+ MrcCpuStepping CpuStepping;
+ MCHBAR_CH0_CR_CMD_RATE_STRUCT CmdRate;
+ DDRSCRAM_CR_DDRSCRAMBLECH0_STRUCT DdrScramble;
+ MCDECS_CR_MAD_DIMM_CH0_MCMAIN_STRUCT DimmCh0McMain;
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_STRUCT ReutChSeqCfg;
+ PCU_CR_M_COMP_PCU_STRUCT MCompPcu;
+ MCHBAR_CH0_CR_TC_BANK_RANK_A_STRUCT TcBankRankA;
+ U32 Offset;
+ U32 GeneratedSeed;
+ U8 Controller;
+ U8 Channel;
+ U8 Byte;
+ U32 BurstEndOdtDelay;
+#ifdef ULT_FLAG
+ U8 Rank;
+ U8 MaxRcvEn;
+ U8 RcvEnDrift;
+ U8 RcvEnTurnOff;
+ S8 OdtTurnOff;
+#endif // ULT_FLAG
+ BOOL Lpddr;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ Debug = &Inputs->Debug;
+ GeneratedSeed = 0;
+ CpuModel = Inputs->CpuModel;
+ CpuStepping = Inputs->CpuStepping;
+
+ //
+ // Oem hook before normal mode configuration starts
+ //
+ MrcOemCheckPoint (MrcData, OemBeforeNormalMode, NULL);
+
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (!(MrcChannelExist (Outputs, Channel))) {
+ continue;
+ }
+
+ ChannelOut = &ControllerOut->Channel[Channel];
+
+ //
+ // Make sure tRDRD (sr, dr, dd) are above 6 for Scrambler W/A
+ //
+ if ((Inputs->ScramblerEnable == TRUE) &&
+ ((CpuModel == cmHSW && CpuStepping < csHswC0) ||
+ (CpuModel == cmHSW_ULT && CpuStepping < csHswUltC0) ||
+ (CpuModel == cmCRW && CpuStepping < csCrwC0)
+ )
+ ) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Increasing tRDRD(sr,dr,dd) by two:\n");
+
+ Offset = MCHBAR_CH0_CR_TC_BANK_RANK_A_REG +
+ (MCHBAR_CH1_CR_TC_BANK_RANK_A_REG - MCHBAR_CH0_CR_TC_BANK_RANK_A_REG) * Channel;
+
+ TcBankRankA.Data = MrcReadCR (MrcData, Offset);
+
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "Initial Value: Channel %d\n tRDRD = 0x%X\n tRDRD_dr = 0x%X\n tRDRD_dd = 0x%X\n",
+ Channel,
+ TcBankRankA.Bits.tRDRD,
+ TcBankRankA.Bits.tRDRD_dr,
+ TcBankRankA.Bits.tRDRD_dd
+ );
+
+ TcBankRankA.Bits.tRDRD = MAX (TcBankRankA.Bits.tRDRD, 6);
+ TcBankRankA.Bits.tRDRD_dr = MAX (TcBankRankA.Bits.tRDRD_dr, 6);
+ TcBankRankA.Bits.tRDRD_dd = MAX (TcBankRankA.Bits.tRDRD_dd, 6);
+
+ MrcWriteCR (MrcData, Offset, TcBankRankA.Data);
+ ChannelOut->MchbarBANKRANKA = TcBankRankA.Data;
+
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "New value: Channel %d\n tRDRD = 0x%X\n tRDRD_dr = 0x%X\n tRDRD_dd = 0x%X\n",
+ Channel,
+ TcBankRankA.Bits.tRDRD,
+ TcBankRankA.Bits.tRDRD_dr,
+ TcBankRankA.Bits.tRDRD_dd
+ );
+ }
+
+ //
+ // Enable Scrambling
+ //
+ if (Inputs->ScramblerEnable == TRUE) {
+ GeneratedSeed = MrcGetRandomNumber ();
+ //
+ // Set Scramble key and enable bits
+ //
+ DdrScramble.Data = 0;
+ DdrScramble.Bits.ScramKey = GeneratedSeed;
+ DdrScramble.Bits.ScramEn = 1;
+ MrcWriteCR (
+ MrcData,
+ DDRSCRAM_CR_DDRSCRAMBLECH0_REG + ((DDRSCRAM_CR_DDRSCRAMBLECH1_REG - DDRSCRAM_CR_DDRSCRAMBLECH0_REG) * Channel),
+ DdrScramble.Data
+ );
+ }
+
+ //
+ // If we are in 1N mode, set Command Rate Limit to 3
+ //
+ if (ChannelOut->Timing[Inputs->MemoryProfile].NMode == 1) {
+ Offset = MCHBAR_CH0_CR_CMD_RATE_REG + ((MCHBAR_CH1_CR_CMD_RATE_REG - MCHBAR_CH0_CR_CMD_RATE_REG) * Channel);
+ CmdRate.Data = MrcReadCR (MrcData, Offset);
+ CmdRate.Bits.enable_cmd_rate_limit = 1;
+ CmdRate.Bits.cmd_rate_limit = 3;
+ CmdRate.Bits.enable_cmd_rate_limit = Inputs->EnCmdRate & 1;
+ CmdRate.Bits.cmd_rate_limit = Inputs->EnCmdRate >> 1;
+ MrcWriteCR (MrcData, Offset, CmdRate.Data);
+ }
+
+ //
+ // Enable the command tri state at the end of the training.
+ //
+ if (!Inputs->CmdTriStateDis) {
+ TcBankRankA.Data = ChannelOut->MchbarBANKRANKA;
+ TcBankRankA.Bits.CMD_3st = 0;
+ ChannelOut->MchbarBANKRANKA = TcBankRankA.Data;
+ MrcWriteCR (
+ MrcData,
+ MCHBAR_CH0_CR_TC_BANK_RANK_A_REG +
+ ((MCHBAR_CH1_CR_TC_BANK_RANK_A_REG - MCHBAR_CH0_CR_TC_BANK_RANK_A_REG) * Channel),
+ ChannelOut->MchbarBANKRANKA
+ );
+ }
+
+ //
+ // set MC to normal mode and clean the odt and cke.
+ //
+ ReutChSeqCfg.Data = 0;
+ ReutChSeqCfg.Bits.Initialization_Mode = NOP_Mode;
+ MrcWriteCR (
+ MrcData,
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG) * Channel),
+ (U32) ReutChSeqCfg.Data
+ );
+
+ //
+ // set again the rank occupancy
+ //
+ MrcWriteCR8 (
+ MrcData,
+ MCHBAR_CH0_CR_MC_INIT_STATE_REG + ((MCHBAR_CH1_CR_MC_INIT_STATE_REG - MCHBAR_CH0_CR_MC_INIT_STATE_REG) * Channel),
+ ChannelOut->ValidRankBitMask
+ );
+
+ //
+ // Set the MC to ECC mode for all channels if needed.
+ //
+ if (Outputs->EccSupport == TRUE) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "ECC support\n");
+ Offset = MCDECS_CR_MAD_DIMM_CH0_MCMAIN_REG + ((MCDECS_CR_MAD_DIMM_CH1_MCMAIN_REG - MCDECS_CR_MAD_DIMM_CH0_MCMAIN_REG) * Channel);
+ DimmCh0McMain.Data = MrcReadCR (MrcData, Offset);
+ DimmCh0McMain.Bits.ECC = emBothActive;
+ MrcWriteCR (MrcData, Offset, DimmCh0McMain.Data);
+ }
+ }
+ }
+
+ //
+ // Check if LPDDR3 memory is used
+ //
+ Lpddr = (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3);
+
+ //
+ // Update Odt timing, Samp timing and SlaveDLL to minimize power
+ // @todo TAT step is skipped on LPDDR for now.
+ //
+ if ((Inputs->TrainingEnables.TAT == 0) || Lpddr) {
+ UpdateSampOdtTiming (MrcData, 0);
+ }
+#ifdef TRAD_FLAG
+ //
+ // Update Internal clock setting
+ //
+ if ((CpuModel == cmHSW) || (CpuModel == cmCRW)) {
+ UpdateInternalClksOn (MrcData);
+ }
+#endif // TRAD_FLAG
+
+ UpdateSlaveDLLLength (MrcData);
+
+ //
+ // Program BurstEndODTDelay - it should be zero during training steps
+ //
+ BurstEndOdtDelay = ((14300 * 20) / 100 + Outputs->Qclkps / 2) / Outputs->Qclkps;
+ if (BurstEndOdtDelay > 7) {
+ BurstEndOdtDelay = 7;
+ }
+ if (BurstEndOdtDelay < 3) {
+ BurstEndOdtDelay = 0;
+ } else if (BurstEndOdtDelay < 4) {
+ BurstEndOdtDelay = 4;
+ }
+
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (MrcChannelExist (Outputs, Channel)) {
+ ChannelOut = &ControllerOut->Channel[Channel];
+ for (Byte = 0; Byte < Outputs->SdramCount; Byte++) {
+ if (CpuModel == cmHSW_ULT) {
+ ChannelOut->DqControl1[Byte].Bits.BurstEndODTDelay = (Lpddr) ? 0 : BurstEndOdtDelay; // Must be Disabled for LPDDR
+ } else if ((CpuModel == cmHSW) && (CpuStepping == csHswA0)) {
+ ChannelOut->DqControl1[Byte].Bits.BurstEndODTDelay = 0;
+ } else {
+ ChannelOut->DqControl1[Byte].Bits.BurstEndODTDelay = BurstEndOdtDelay;
+ }
+ Offset = DDRDATA0CH0_CR_DDRCRDATACONTROL1_REG +
+ ((DDRDATA1CH0_CR_DDRCRDATACONTROL1_REG - DDRDATA0CH0_CR_DDRCRDATACONTROL1_REG) * Byte) +
+ ((DDRDATA0CH1_CR_DDRCRDATACONTROL1_REG - DDRDATA0CH0_CR_DDRCRDATACONTROL1_REG) * Channel);
+ MrcWriteCR (MrcData, Offset, ChannelOut->DqControl1[Byte].Data);
+ }
+ }
+ }
+ }
+
+#ifdef ULT_FLAG
+ if (CpuModel == cmHSW_ULT) {
+ //
+ // Program RxClkStgNum
+ //
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (!MrcChannelExist (Outputs, Channel)) {
+ continue;
+ }
+ ChannelOut = &ControllerOut->Channel[Channel];
+ MaxRcvEn = 0;
+ for (Rank = 0; Rank < MAX_RANK_IN_CHANNEL; Rank++) {
+ if (!MrcRankInChannelExist (MrcData, Rank, Channel)) {
+ continue;
+ }
+ for (Byte = 0; Byte < Outputs->SdramCount; Byte++) {
+ MaxRcvEn = (U8) MAX (MaxRcvEn, ChannelOut->RcvEn[Rank][Byte] / 64);
+ }
+ }
+ RcvEnDrift = (Lpddr) ? (U8) ((tDQSCK_DRIFT + Outputs->Qclkps - 1) / Outputs->Qclkps) : 1;
+ RcvEnTurnOff = MaxRcvEn + (5 - 6) + 1 + 7 + 3 + 3 + 2 + (2 * RcvEnDrift);
+
+ for (Byte = 0; Byte < Outputs->SdramCount; Byte++) {
+ if (ChannelOut->DqControl1[Byte].Bits.LpDdrLongOdtEn) {
+ RcvEnTurnOff ++;
+ }
+
+ OdtTurnOff = MrcSE ((U8) ChannelOut->DqControl1[Byte].Bits.OdtDelay, 4, 8) +
+ (U8) ChannelOut->DqControl1[Byte].Bits.OdtDuration + 14;
+
+ ChannelOut->DqControl2[Byte].Bits.RxClkStgNum = (ChannelOut->DqControl0.Bits.OdtSampExtendEn) ?
+ MAX (ChannelOut->DqControl2[Byte].Bits.RxClkStgNum, RcvEnTurnOff) : MAX (17, OdtTurnOff);
+ Offset = DDRDATA0CH0_CR_DDRCRDATACONTROL2_REG +
+ ((DDRDATA0CH1_CR_DDRCRDATACONTROL2_REG - DDRDATA0CH0_CR_DDRCRDATACONTROL2_REG) * Channel) +
+ ((DDRDATA1CH0_CR_DDRCRDATACONTROL2_REG - DDRDATA0CH0_CR_DDRCRDATACONTROL2_REG) * Byte);
+ MrcWriteCR (MrcData, Offset, ChannelOut->DqControl2[Byte].Data);
+ }
+ }
+ }
+
+ //
+ // Program DDRPL_CR_DDR_TX_DELAY if Memory Trace is enabled
+ //
+ MrcSetDdrplTxDelay (MrcData);
+ }
+#endif // ULT_FLAG
+
+ //
+ // Enable Periodic Comp with periodic internal = 10uS*2^COMP_INT
+ //
+ MCompPcu.Data = 0;
+ MCompPcu.Bits.COMP_INTERVAL = COMP_INT;
+ MrcWriteCR (MrcData, PCU_CR_M_COMP_PCU_REG, MCompPcu.Data);
+
+ //
+ // Enable the power mode before PCU start working.
+ //
+ MrcPowerModesPostTraining (MrcData);
+
+ //
+ // Set Idle timer and Self Refresh enable bits
+ //
+ EnterSR (MrcData);
+
+ //
+ // Oem hook when normal mode configuration is done
+ //
+ MrcOemCheckPoint (MrcData, OemAfterNormalMode, (void *) &Inputs->McLock);
+
+ if (Inputs->ThermalEnables.UserPowerWeightsEn == 0) {
+ //
+ // Apply power weight values
+ //
+ MrcPowerWeight (MrcData);
+ }
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function enables Normal Mode and configures the Power Down Modes
+ for the boot flows other than Cold Boot.
+
+ @param[in] MrcData - The MRC general data.
+
+ @retval Always returns mrcSuccess.
+**/
+MrcStatus
+MrcNormalMode (
+ IN MrcParameters *const MrcData
+ )
+{
+ MrcOutput *Outputs;
+ U8 Channel;
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_STRUCT ReutChSeqCfg;
+ PCU_CR_M_COMP_PCU_STRUCT MCompPcu;
+
+ Outputs = &MrcData->SysOut.Outputs;
+
+ //
+ // Enable Periodic Comp with periodic internal = 10uS*2^COMP_INT
+ //
+ MCompPcu.Data = 0;
+ MCompPcu.Bits.COMP_INTERVAL = COMP_INT;
+ MrcWriteCR (MrcData, PCU_CR_M_COMP_PCU_REG, MCompPcu.Data);
+ //
+ // Set Normal Operation Mode.
+ //
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (MrcChannelExist (Outputs, Channel)) {
+ ReutChSeqCfg.Data = 0;
+ ReutChSeqCfg.Bits.Initialization_Mode = NOP_Mode;
+ MrcWriteCR (
+ MrcData,
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG) * Channel),
+ (U32) ReutChSeqCfg.Data
+ );
+ }
+ }
+
+ //
+ // Configure Power Down CR
+ //
+ MrcPowerDownConfig (MrcData);
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ this function is the last funtion that call from the MRC core.
+ the function set DISB and set the MRC_Done.
+
+ @param[in] MrcData - include all the MRC general data.
+
+ @retval Always returns mrcSuccess.
+**/
+MrcStatus
+MrcDone (
+ IN MrcParameters *const MrcData
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MCDECS_CR_MC_INIT_STATE_G_MCMAIN_STRUCT McInitStateG;
+#ifdef ULT_FLAG
+ MrcOutput *Outputs;
+ U32 Channel;
+ U32 Rank;
+ U8 MrrResult[4];
+ U32 MrAddr;
+ U32 Device;
+ U32 Index;
+#endif //ULT_FLAG
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Debug = &Inputs->Debug;
+
+#ifdef ULT_FLAG
+ //
+ // LPDDR: Read MR5 and MR8
+ //
+ Outputs = &MrcData->SysOut.Outputs;
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ for (Rank = 0; Rank < MAX_RANK_IN_CHANNEL; Rank++) {
+ if (!MrcRankInChannelExist (MrcData, (U8) Rank, (U8) Channel)) {
+ continue;
+ }
+
+ //
+ // MR5 - Manufacturer ID
+ //
+ MrAddr = 5;
+ MrcIssueMrr (MrcData, Channel, Rank, MrAddr, MrrResult);
+ for (Device = 0; Device < 4; Device++) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "\tDevice[%d]= 0x%02X", Device, MrrResult[Device]);
+ for (Index = 0; Index < sizeof (DramVendorList) / sizeof (DramVendorList[0]); Index++) {
+ if (DramVendorList[Index].VendorId == MrrResult[Device]) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " %s\n", DramVendorList[Index].VendorName);
+ }
+ }
+ }
+
+ //
+ // MR8 - I/O Width, Density, Type
+ //
+ MrAddr = 8;
+ MrcIssueMrr (MrcData, Channel, Rank, MrAddr, MrrResult);
+ for (Device = 0; Device < 4; Device++) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "\tDevice[%d]= 0x%02X - %s\n", Device, MrrResult[Device],
+ (MRC_BIT6 & MrrResult[Device]) ? "x16" : "x32");
+ }
+ }
+ }
+ }
+#endif //ULT_FLAG
+
+ //
+ // Set Idle timer and Self Refresh enable bits
+ // EnterSR (MrcData);
+ //
+ McInitStateG.Data = MrcReadCR (MrcData, MCDECS_CR_MC_INIT_STATE_G_MCMAIN_REG);
+ //
+ // Set refresh enable Bit
+ //
+ McInitStateG.Bits.refresh_enable = 1;
+
+ //
+ // used to know what is the state of the boot mode.
+ //
+ McInitStateG.Bits.pu_mrc_done = 1;
+
+ //
+ // set the MRC_Done bit.
+ //
+ McInitStateG.Bits.mrc_done = 1;
+
+ MrcWriteCR (MrcData, MCDECS_CR_MC_INIT_STATE_G_MCMAIN_REG, McInitStateG.Data);
+
+ //
+ // lock the MC and memory map registers.
+ //
+ McRegistersLock (MrcData);
+
+ //
+ // Poll for to make sure MRC is complete
+ //
+ // wait for mc_init_done
+ // @TODO: Possible infinite loop. Need to add a timeout counter/error handler.
+ //
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Waiting for mc_init_done Acknowledge\n");
+ do {
+ McInitStateG.Data = MrcReadCR (MrcData, MCDECS_CR_MC_INIT_STATE_G_MCMAIN_REG);
+ } while (McInitStateG.Bits.mc_init_done_ack == 0);
+ //
+ // move the MRC data to the graphics driver.
+ //
+ MrcWmRegSet (MrcData);
+ return mrcSuccess;
+}
+
+/**
+@brief
+ Print the MRC version to the MRC output device.
+
+ @param[in] Debug - Pointer to the MRC Debug structure.
+ @param[in] Version - The MRC version.
+
+ @retval Nothing.
+**/
+void
+MrcVersionPrint (
+ IN const MrcParameters *MrcData,
+ IN const MrcVersion *Version
+ )
+{
+#ifdef MRC_DEBUG_PRINT
+ const MrcDebug *Debug;
+
+ Debug = &MrcData->SysIn.Inputs.Debug;
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "*********************************************************************\n");
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "** Copyright (c) 2011-2012 Intel Corporation. All rights reserved. **\n");
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "** Haswell memory detection and initialization code. **\n");
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "** Major version number is: %2u **\n", Version->Major);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "** Minor version number is: %2u **\n", Version->Minor);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "** Rev version number is: %2u **\n", Version->Rev);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "** Build number is: %2u **\n", Version->Build);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "*********************************************************************\n");
+#endif
+ return;
+}
+
+/**
+@brief
+ This function return the MRC version.
+
+ @param[out] Version - Location to store the MRC version.
+
+ @retval Nothing.
+**/
+void
+MrcVersionGet (
+ OUT MrcVersion *const Version
+ )
+{
+ if (Version != NULL) {
+ MrcOemMemoryCpy ((U8 *) Version, (U8 *) &cVersion, sizeof (MrcVersion));
+ }
+}
+
+/**
+@brief
+ This function set the MRC vertion to MCDECS_SPARE register.
+ The function need to be call by the wrapper after MrcStartMemoryConfiguration function where the MC CLK enable.
+ The function write:
+ Major number to bits 16-23
+ Minor number to bits 8-15
+ Build number to bits 0 - 7
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval Nothing.
+**/
+MrcStatus
+MrcSetMrcVersion (
+ IN MrcParameters *const MrcData
+ )
+{
+ MrcVersion const *Version;
+ MCDECS_CR_MRC_REVISION_MCMAIN_STRUCT MrcRevision;
+
+ Version = &MrcData->SysOut.Outputs.Version;
+ MrcRevision.Data = (((U32) Version->Major) << 24) |
+ (((U32) Version->Minor) << 16) |
+ (((U32) Version->Rev) << 8) |
+ (((U32) Version->Build));
+
+ MrcWriteCR (MrcData, MCDECS_CR_MRC_REVISION_MCMAIN_REG, MrcRevision.Data);
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function locks the memory controller and memory map registers.
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval Nothing.
+**/
+void
+McRegistersLock (
+ IN MrcParameters *const MrcData
+ )
+{
+ const MrcInput *Inputs;
+ MCDECS_CR_MC_LOCK_MCMAIN_STRUCT McLock;
+ MRC_PCI_000_TOM_STRUCT Tom;
+ MRC_PCI_000_TOLUD_STRUCT Tolud;
+ MRC_PCI_000_TOUUD_STRUCT Touud;
+ MRC_PCI_000_REMAPBASE_STRUCT RemapBase;
+ MRC_PCI_000_REMAPLIMIT_STRUCT RemapLimit;
+// MRC_PCI_000_TSEGMB_STRUCT Tsegmb;
+ MRC_PCI_000_BDSM_STRUCT Bdsm;
+ MRC_PCI_000_BGSM_STRUCT Bgsm;
+ MRC_PCI_000_MESEG_MASK_STRUCT MeSegMask;
+ MRC_PCI_000_GGC_STRUCT Ggc;
+ PCU_CR_DDR_PTM_CTL_PCU_STRUCT DdrPtmCtl;
+ U32 Offset;
+
+ Inputs = &MrcData->SysIn.Inputs;
+
+ //
+ // Lock the memory controller registers.
+ //
+ McLock.Data = 0;
+ McLock.Bits.lock_addr_map = 1;
+ McLock.Bits.lock_mc_config = 1;
+ McLock.Bits.lock_iosav_init = 1;
+ McLock.Bits.lock_pwr_mngment = 1;
+ McLock.Bits.lock_mc_dft = 1;
+ MrcWriteCR (MrcData, MCDECS_CR_MC_LOCK_MCMAIN_REG, McLock.Data);
+
+ MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "\nMemory controller config is locked\n");
+
+ if (Inputs->McLock) {
+ //
+ // Lock the memory map registers.
+ // Lock TOM.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_TOM_REG);
+ MrcOemMmioRead (Offset, &Tom.Data32.Low.Data, Inputs->PciEBaseAddress);
+ Tom.Data32.Low.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, Tom.Data32.Low.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock TOLUD.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_TOLUD_REG);
+ MrcOemMmioRead (Offset, &Tolud.Data, Inputs->PciEBaseAddress);
+ Tolud.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, Tolud.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock TOUUD.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_TOUUD_REG);
+ MrcOemMmioRead (Offset, &Touud.Data32.Low.Data, Inputs->PciEBaseAddress);
+ Touud.Data32.Low.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, Touud.Data32.Low.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock REMAPBASE.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_REMAPBASE_REG);
+ MrcOemMmioRead (Offset, &RemapBase.Data32.Low.Data, Inputs->PciEBaseAddress);
+ RemapBase.Data32.Low.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, RemapBase.Data32.Low.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock REMAPLIMIT.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_REMAPLIMIT_REG);
+ MrcOemMmioRead (Offset, &RemapLimit.Data32.Low.Data, Inputs->PciEBaseAddress);
+ RemapLimit.Data32.Low.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, RemapLimit.Data32.Low.Data, Inputs->PciEBaseAddress);
+
+ //
+ // @todo: - Confirm if this has been fixed and are who is locking TSEGMB
+ // Lock TSEGMB.
+ // Rapid Start requires TSEG_BASE access so do not lock it here.
+ //
+ // Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_TSEGMB_REG);
+ // MrcOemMmioRead (Offset, &Tsegmb.Data, Inputs->PciEBaseAddress);
+ // Tsegmb.Bits.Lock = 1;
+ // MrcOemMmioWrite (Offset, Tsegmb.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock DPR register
+ // Rapid Start requires DPR access so do not lock it here.
+ // System Agent RC SaSecurityLock() will lock it during ExitPmAuth callback
+ //
+
+ //
+ // Lock BDSM.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_BDSM_REG);
+ MrcOemMmioRead (Offset, &Bdsm.Data, Inputs->PciEBaseAddress);
+ Bdsm.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, Bdsm.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock BGSM.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_BGSM_REG);
+ MrcOemMmioRead (Offset, &Bgsm.Data, Inputs->PciEBaseAddress);
+ Bgsm.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, Bgsm.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock MESEG_MASK.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_MESEG_MASK_REG);
+ MrcOemMmioRead (Offset, &MeSegMask.Data32.Low.Data, Inputs->PciEBaseAddress);
+ MeSegMask.Data32.Low.Bits.Lock = 1;
+ MrcOemMmioWrite (Offset, MeSegMask.Data32.Low.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock GGC.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_GGC_REG);
+ MrcOemMmioRead (Offset, &Ggc.Data, Inputs->PciEBaseAddress);
+ Ggc.Bits.Ggclck = 1;
+ MrcOemMmioWrite (Offset, Ggc.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Lock POWER THERMAL MANAGEMENT CONTROL
+ //
+ DdrPtmCtl.Data = MrcReadCR (MrcData, PCU_CR_DDR_PTM_CTL_PCU_REG);
+ DdrPtmCtl.Bits.LOCK_PTM_REGS_PCU = Inputs->ThermalEnables.LockPTMregs;
+ MrcWriteCR (MrcData, PCU_CR_DDR_PTM_CTL_PCU_REG, DdrPtmCtl.Data);
+
+ MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "\nMemory map registers are locked\n");
+ }
+
+ return;
+}
+
+/**
+@brief
+ This function returns the recommended MRC boot mode.
+
+ @param[in] void - No arguments
+
+ @retval bmWarm if we are in self refresh and the DISB bit is set, otherwise returns bmCold.
+**/
+MrcBootMode
+MrcGetBootMode (
+ void
+ )
+{
+ MrcBootMode BootMode;
+ U32 Register;
+ U32 ioAddress;
+
+ ioAddress = (U32) MrcOemGetPciDeviceAddress (
+ GENERAL_PM_CONFIGURATION_2_BUS_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2_DEVICE_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2_FUNCTION_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2
+ );
+
+ MrcOemOutPort32 (MrcOemPciIndex (), ioAddress);
+ //
+ // We read 32 bits but we need only 8 bits of GENERAL_PM_CONFIGURATION_2 that start at offset 0xA2 and not 0xA0.
+ //
+ Register = (MrcOemInPort32 (MrcOemPciData ()) >> 16);
+
+ if ((Register & GENERAL_PM_CONFIGURATION_2_MEM_SR_MASK) == GENERAL_PM_CONFIGURATION_2_MEM_SR_MASK &&
+ (Register & GENERAL_PM_CONFIGURATION_2_DISB_MASK) == GENERAL_PM_CONFIGURATION_2_DISB_MASK
+ ) {
+ BootMode = bmWarm;
+ } else {
+ BootMode = bmCold;
+ }
+
+ return BootMode;
+}
+//
+// @todo: - Need to find out if we need it for PCH used in HSW timeframe
+//
+/**
+@brief
+ This function sets the DISB bit in General PM Configuration 2 B:D:F 0,31,0 offset 0xA2.
+
+ @param[in] void - No arguments
+
+ @retval Nothing.
+**/
+void
+MrcSetDISB (
+ void
+ )
+{
+ U32 Register;
+ U32 ioAddress;
+
+ ioAddress = (U32) MrcOemGetPciDeviceAddress (
+ GENERAL_PM_CONFIGURATION_2_BUS_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2_DEVICE_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2_FUNCTION_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2
+ );
+
+ MrcOemOutPort32 (MrcOemPciIndex (), ioAddress);
+ Register = MrcOemInPort32 (MrcOemPciData ());
+
+ //
+ // GENERAL_PM_CONFIGURATION_2 start in A2 and not in A0.
+ //
+ Register |= (GENERAL_PM_CONFIGURATION_2_DISB_MASK << 16);
+
+ MrcOemOutPort32 (MrcOemPciIndex (), ioAddress);
+ MrcOemOutPort32 (MrcOemPciData (), Register);
+}
+
+/**
+@brief
+ This function resets the DISB bit in General PM Configuration 2 B:D:F 0,31,0 offset 0xA2.
+
+ @param[in] void - No arguments
+
+ @retval Nothing.
+**/
+void
+MrcResetDISB (
+ void
+ )
+{
+ U32 Register;
+ U32 ioAddress;
+
+ ioAddress = (U32) MrcOemGetPciDeviceAddress (
+ GENERAL_PM_CONFIGURATION_2_BUS_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2_DEVICE_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2_FUNCTION_ADDRESS,
+ GENERAL_PM_CONFIGURATION_2
+ );
+
+ MrcOemOutPort32 (MrcOemPciIndex (), ioAddress);
+ Register = MrcOemInPort32 (MrcOemPciData ());
+
+ //
+ // GENERAL_PM_CONFIGURATION_2 address is A2 and not A0.
+ //
+ Register &= ((~(GENERAL_PM_CONFIGURATION_2_DISB_MASK)) << 16);
+
+ MrcOemOutPort32 (MrcOemPciIndex (), ioAddress);
+ MrcOemOutPort32 (MrcOemPciData (), Register);
+}
+
+/**
+@brief
+ This function reads the CAPID0 register and sets the memory controller's capability.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the memory controller's capability has been determined, otherwise returns mrcFail.
+**/
+MrcStatus
+MrcMcCapability (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcSaveData *Save;
+ MrcOutput *Outputs;
+ MrcControllerOut *ControllerOut;
+ MrcChannelOut *ChannelOut;
+ MrcDimmOut *DimmOut;
+ BOOL EccSupport;
+ BOOL IgnoreNonEccDimm;
+ MRC_PCI_000_CAPID0_STRUCT Capid0Reg;
+ MRC_PCI_000_DEVEN_STRUCT Deven;
+ MrcProfile Profile;
+ U32 ChannelCount;
+ U32 DimmCount;
+ U32 Max;
+ U32 Size;
+ U32 ChannelNum;
+ U32 DimmNum;
+ U32 ChDimmCount;
+ U32 Offset;
+ U16 NModeMinimum;
+ U8 Controller;
+ U8 Channel;
+ U8 Dimm;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ Save = &MrcData->SysSave.Save.Data;
+ Debug = &Inputs->Debug;
+ ChDimmCount = MAX_DIMMS_IN_CHANNEL;
+ Profile = Inputs->MemoryProfile;
+
+ //
+ // Obtain the capabilities of the memory controller.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_CAPID0_REG);
+ MrcOemMmioRead (Offset, &Capid0Reg.Data32.A.Data, Inputs->PciEBaseAddress);
+ MrcOemMmioRead (Offset + 4, &Capid0Reg.Data32.B.Data, Inputs->PciEBaseAddress);
+ Save->McCapId.Data = Capid0Reg.Data;
+
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_DEVEN_REG);
+ MrcOemMmioRead (Offset, &Deven.Data, Inputs->PciEBaseAddress);
+
+ //
+ // Determine if the internal graphics engine is supported.
+ //
+ if ((Capid0Reg.Data32.A.Bits.IGD == 0) && (Deven.Bits.D2EN > 0)) {
+ Outputs->GraphicsStolenSize = Inputs->GraphicsStolenSize;
+ Outputs->GraphicsGttSize = Inputs->GraphicsGttSize;
+ } else {
+ Outputs->GraphicsStolenSize = 0;
+ Outputs->GraphicsGttSize = 0;
+ }
+
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "Memory allocated for IGD = %uMB and for GTT = %uMB.\n",
+ Outputs->GraphicsStolenSize,
+ Outputs->GraphicsGttSize
+ );
+
+ //
+ // Determine the maximum size of memory per channel, based on fuses.
+ //
+ switch (Capid0Reg.Data32.A.Bits.DDRSZ) {
+ case tcs16GB:
+ Outputs->MrcTotalChannelLimit = (16 * 1024);
+ break;
+
+ case tcs8GB:
+ Outputs->MrcTotalChannelLimit = (8 * 1024);
+ break;
+
+ case tcs2GB:
+ Outputs->MrcTotalChannelLimit = (2 * 1024);
+ break;
+
+ case tcs512MB:
+ default:
+ Outputs->MrcTotalChannelLimit = (512);
+ break;
+ }
+
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "Maximum size of memory allowed on a channel = %uMB.\n",
+ Outputs->MrcTotalChannelLimit
+ );
+
+ //
+ // Determine how many channels are supported on this memory controller,
+ // based on fuse and how many channels have DIMMs installed.
+ //
+ ChannelCount = (Capid0Reg.Data32.A.Bits.PDCD == 0) ? MAX_CHANNEL : 1;
+ DimmCount = (Capid0Reg.Data32.A.Bits.DDPCD == 0) ? MAX_DIMMS_IN_CHANNEL : 1;
+
+#ifdef ULT_FLAG
+ if (Inputs->CpuModel == cmHSW_ULT) {
+ //
+ // Only 1DPC is supported on ULT platform
+ //
+ DimmCount = 1;
+ }
+#endif // ULT_FLAG
+
+#ifdef EMBEDDED_FLAG
+ if (Inputs->BoardType == btCRBEMB) {
+ //
+ // Only 1DPC is supported on EMBEDDED platform
+ //
+ DimmCount = 1;
+ }
+#endif
+
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "Number of channels supported = %u\nNumber of DIMMs per channel supported = %u\n",
+ ChannelCount,
+ DimmCount
+ );
+
+ //
+ // Determine the minimum NMode supported on this memory controller.
+ //
+ NModeMinimum = (Capid0Reg.Data32.A.Bits.D1NM == 0) ? 1 : 2;
+
+ //
+ // Determine the ECC capability of the memory controller.
+ //
+ IgnoreNonEccDimm = (Capid0Reg.Data32.A.Bits.FDEE == 0) ? FALSE : TRUE;
+
+ //
+ // Set EccSupport flag to TRUE if we must NOT ignore ECC DIMMs
+ //
+ if (IgnoreNonEccDimm == TRUE) {
+ Outputs->EccSupport = TRUE;
+ EccSupport = TRUE; // FDEE has presedence over ECCDIS
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "ALL DIMMs MUST be ECC capable\n");
+ } else {
+ EccSupport = ((Capid0Reg.Data32.A.Bits.ECCDIS > 0) || (Outputs->EccSupport == FALSE)) ? FALSE : TRUE;
+ }
+ //
+ // Now copy ECC and NMode information to the channel and DIMM results.
+ //
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelOut = &ControllerOut->Channel[Channel];
+ if (ChannelOut->Status == CHANNEL_PRESENT) {
+ if ((NModeMinimum >= 2) ||
+ ((Inputs->MemoryProfile == STD_PROFILE) &&
+ ((Outputs->Frequency > f1867) || ((ChannelOut->DimmCount >= 2) && (Outputs->Frequency >= f1333))))) {
+ ChannelOut->Timing[Profile].NMode = MAX (2, ChannelOut->Timing[Profile].NMode);
+ }
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ if (DimmOut->Status == DIMM_PRESENT) {
+ DimmOut->Timing[Profile].NMode = ChannelOut->Timing[Profile].NMode;
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ " %s %u/%u/%u NMode = %u\n",
+ CcdString,
+ Controller,
+ Channel,
+ Dimm,
+ DimmOut->Timing[Profile].NMode
+ );
+ if (EccSupport == TRUE) {
+ if ((DimmOut->EccSupport == FALSE) && (IgnoreNonEccDimm == TRUE)) {
+ DimmOut->Status = DIMM_DISABLED;
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ " %s %u/%u/%u Disabling non-ECC capable DIMM\n",
+ CcdString,
+ Controller,
+ Channel,
+ Dimm
+ );
+ } else if (DimmOut->EccSupport == TRUE) {
+ DimmOut->EccSupport = TRUE;
+ DimmOut->SdramCount = MAX_SDRAM_IN_DIMM;
+ } else {
+ DimmOut->SdramCount = MAX_SDRAM_IN_DIMM - 1;
+ Outputs->EccSupport = FALSE; // Final ECCSupport must be disabled if one DIMM is NOT capable
+ }
+ } else {
+ DimmOut->EccSupport = FALSE;
+ DimmOut->SdramCount = MAX_SDRAM_IN_DIMM - 1;
+ Outputs->EccSupport = FALSE; // Final ECCSupport must be disabled if ECCDIS is set
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Update FInal SdramCount
+ //
+ Outputs->SdramCount = (Outputs->EccSupport == TRUE) ? MAX_SDRAM_IN_DIMM : (MAX_SDRAM_IN_DIMM - 1);
+
+ //
+ // Determine the size of memory in each channel.
+ // Also determine the channel with the largest amount.
+ //
+ Max = ChannelNum = Outputs->MemoryMapData.TotalPhysicalMemorySize = 0;
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelOut = &ControllerOut->Channel[Channel];
+ Size = 0;
+ if (ChannelOut->Status == CHANNEL_PRESENT) {
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ if (DimmOut->Status == DIMM_PRESENT) {
+ Size += DimmOut->DimmCapacity;
+ }
+ }
+
+ ChannelOut->Capacity = Size;
+ if (Size > Max) {
+ Max = Size;
+ ChannelNum = Channel;
+ ChDimmCount = ChannelOut->DimmCount;
+ } else if ((Size == Max) && (DimmCount == 1)) {
+ //
+ // Choose channel with least amount of DIMMs if 2DPC is disabled
+ //
+ if (ChannelOut->DimmCount < ChDimmCount) {
+ ChDimmCount = ChannelOut->DimmCount;
+ ChannelNum = Channel;
+ }
+ }
+ }
+
+ Outputs->MemoryMapData.TotalPhysicalMemorySize += ChannelOut->Capacity;
+ }
+ }
+
+ if (ChannelCount == 1) {
+ //
+ // Determine which channels are supported on this memory controller.
+ // If fused for one channel, we pick the channel with the most memory.
+ //
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelOut = &ControllerOut->Channel[Channel];
+ if ((ChannelOut->Status == CHANNEL_PRESENT) && (Channel != ChannelNum)) {
+ //
+ // Disable Channel don't skip DIMM capacity
+ //
+ MrcChannelDisable (MrcData, (U8) Channel, 0);
+ }
+ }
+
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "Controller configured to one channel, we've selected channel %u.\n",
+ ChannelNum
+ );
+ }
+ }
+
+ if (DimmCount == 1) {
+ //
+ // Determine which DIMMs are supported on this memory controller.
+ // If fused for one DIMM per channel, we pick the DIMM in a channel with the most memory.
+ //
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelOut = &ControllerOut->Channel[Channel];
+ Max = Size = DimmNum = 0;
+ if (ChannelOut->Status == CHANNEL_PRESENT) {
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ if (DimmOut->Status == DIMM_PRESENT) {
+ Size = DimmOut->DimmCapacity;
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "C%uD%uDimmCapacity = 0x%x\n", Channel, Dimm, DimmOut->DimmCapacity);
+ if (Size > Max) {
+ Max = Size;
+ DimmNum = Dimm;
+ }
+ }
+ }
+
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ if ((DimmOut->Status == DIMM_PRESENT) && (Dimm != DimmNum)) {
+ DimmOut->Status = DIMM_DISABLED;
+ }
+ }
+
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "Controller configured to one DIMM per channel, we've selected channel %u, Dimm %u.\n",
+ Channel,
+ DimmNum
+ );
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "ValidRankBitMask = 0x%x\n", ChannelOut->ValidRankBitMask);
+ }
+ }
+ }
+ }
+
+ //
+ // Now that we know the enabled and disabled DIMM/Channel population,
+ // determine if all enabled DIMMS support ASR.
+ //
+ // It is necessary to have all DIMMS in ASR or no DIMMS in ASR
+ // when enabling 2x Refresh.
+ //
+ if (Inputs->RefreshRate2x == TRUE) {
+ Outputs->AutoSelfRefresh = TRUE;
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerOut = &Outputs->Controller[Controller];
+ if (ControllerOut->Status == CONTROLLER_PRESENT) {
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelOut = &ControllerOut->Channel[Channel];
+ if (ChannelOut->Status == CHANNEL_PRESENT) {
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ if ((DimmOut->Status == DIMM_PRESENT) && (DimmOut->AutoSelfRefresh == FALSE)) {
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "Channel %d, Dimm %d does not support Auto Self Refresh. Disabling ASR since 2x Refresh is enabled!\n",
+ Channel,
+ Dimm
+ );
+ Outputs->AutoSelfRefresh = FALSE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function reads the CAPID0 register and sets the memory controller's capability.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the memory controller's capability has been determined, otherwise returns mrcFail.
+**/
+MrcStatus
+MrcMcCapabilityPreSpd (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcOutput *Outputs;
+ MrcFrequency FreqMax;
+ MrcFrequency FreqMax100;
+ MrcFrequency FreqMax133;
+ MrcRefClkSelect RefClk;
+ BOOL Capable;
+ MRC_PCI_000_CAPID0_STRUCT Capid0Reg;
+ U32 Capable100;
+ U32 Capable133;
+ U32 Offset;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ Debug = &Inputs->Debug;
+
+ //
+ // Obtain the capabilities of the memory controller.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_CAPID0_REG);
+ MrcOemMmioRead (Offset, &Capid0Reg.Data32.A.Data, Inputs->PciEBaseAddress);
+ MrcOemMmioRead (Offset + 4, &Capid0Reg.Data32.B.Data, Inputs->PciEBaseAddress);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "CAPID0 = %X_%Xh\n", Capid0Reg.Data32.B.Data, Capid0Reg.Data32.A.Data);
+
+ //
+ // Determine the maximum memory frequency supported and the memory reference clock.
+ //
+ Capable = (Capid0Reg.Data32.A.Bits.DDR_OVERCLOCK > 0) ? TRUE : FALSE;
+ Capable100 = Capid0Reg.Data32.B.Bits.PLL_REF100_CFG;
+ Capable133 = Capid0Reg.Data32.B.Bits.DMFC;
+ Outputs->RefClk = Inputs->RefClk;
+ Outputs->FreqMax = ((Inputs->FreqMax > fNoInit) && (Inputs->FreqMax < fUnSupport)) ? Inputs->FreqMax : f2667;
+
+ if (Capable100 == 0) {
+ Outputs->RefClk = MRC_REF_CLOCK_133;
+ }
+
+ RefClk = Outputs->RefClk;
+ if (Capable) {
+ Capable133 = 0;
+ if (Capable100 > 0) {
+ Capable100 = CAPID0_B_PLL_REF100_CFG_MAX;
+ Outputs->Capable100 = TRUE;
+ }
+ }
+
+ FreqMax100 = (Capable100 == 0) ? fNoInit : MrcRatioToFrequency (MrcData, (MrcClockRatio) Capable100 + 6, MRC_REF_CLOCK_100, BCLK_DEFAULT);
+ FreqMax133 = MrcRatioToFrequency (MrcData, (MrcClockRatio) ((Capable133 == 0) ? 10 : 11 - Capable133), MRC_REF_CLOCK_133, BCLK_DEFAULT);
+ //
+ // If overclocking is supported, then there is no frequency limitation, otherwise check for limitation.
+ // Note 1: If we are using standard memory profile, DIMMS should run at RefClk 133.
+ // Note 2: If the 2 values are equal, then we want to pick RefClk 133.
+ //
+
+ if (Inputs->MemoryProfile == STD_PROFILE) {
+ FreqMax = FreqMax133;
+ RefClk = MRC_REF_CLOCK_133;
+ } else {
+ if (Capable) {
+ FreqMax = (RefClk == MRC_REF_CLOCK_100) ? FreqMax100 : FreqMax133;
+ } else if (FreqMax100 > FreqMax133) {
+ FreqMax = FreqMax100;
+ RefClk = MRC_REF_CLOCK_100;
+ } else {
+ FreqMax = FreqMax133;
+ RefClk = MRC_REF_CLOCK_133;
+ }
+ }
+
+ if (FreqMax < Outputs->FreqMax) {
+ Outputs->FreqMax = FreqMax;
+ Outputs->RefClk = RefClk;
+ }
+
+ Outputs->MemoryClockMax = ConvertFreq2Clock (MrcData, Outputs->FreqMax, NULL);
+
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "The maximum memory frequency allowed is %u (%ufs)\n", Outputs->FreqMax, Outputs->MemoryClockMax);
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_NOTE,
+ "%uMHz reference clock is selected\n",
+ (Outputs->RefClk == MRC_REF_CLOCK_133) ? 133 : 100
+ );
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function sets the appropriate timing overrides in the output structure
+ prior to Spd processing.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the timing overrides have been conpleted.
+**/
+MrcStatus
+MrcSetOverridesPreSpd (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function reads the input data structure and sets the appropriate timing overrides in the output structure.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the timing overrides have been conpleted.
+**/
+MrcStatus
+MrcSetOverrides (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const MrcDebug *Debug;
+ const MrcInput *Inputs;
+ MrcOutput *Outputs;
+ MPCOHTRK_CR_GDXC_MOT_REGION_STRUCT GdxcMotRegion;
+ MPCOHTRK_CR_GDXC_OCLA_REGION_STRUCT GdxcOclaRegion;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ Debug = &Inputs->Debug;
+
+ Outputs->EccSupport = Inputs->EccSupport;
+ Outputs->VddVoltageDone = FALSE;
+
+ Outputs->Gdxc.GdxcEnable = Inputs->Gdxc.GdxcEnable;
+
+ //
+ // Read MOT register
+ //
+ MrcOemMmioRead (MPCOHTRK_CR_GDXC_MOT_REGION_REG, &GdxcMotRegion.Data, Inputs->GdxcBaseAddress);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "----- GDXC MOT LOW : 0x%x\n", GdxcMotRegion.Bits.START_ADDRESS);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "----- GDXC MOT UPP : 0x%x\n", GdxcMotRegion.Bits.END_ADDRESS);
+ if (GdxcMotRegion.Bits.START_ADDRESS == 0 && GdxcMotRegion.Bits.END_ADDRESS > 1) {
+ Outputs->Gdxc.GdxcMotSize = (U8) (GdxcMotRegion.Bits.END_ADDRESS);
+ } else {
+ Outputs->Gdxc.GdxcMotSize = Inputs->Gdxc.GdxcMotSize;
+ }
+ //
+ // Read OCLA register
+ //
+ MrcOemMmioRead (MPCOHTRK_CR_GDXC_OCLA_REGION_REG, &GdxcOclaRegion.Data, Inputs->GdxcBaseAddress);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "----- GDXC IOT LOW : 0x%x\n", GdxcOclaRegion.Bits.START_ADDRESS);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_ERROR, "----- GDXC IOT UPP : 0x%x\n", GdxcOclaRegion.Bits.END_ADDRESS);
+
+ if (GdxcOclaRegion.Bits.START_ADDRESS == 0 && GdxcOclaRegion.Bits.END_ADDRESS > 1) {
+ Outputs->Gdxc.GdxcIotSize = (U8) (GdxcOclaRegion.Bits.END_ADDRESS);
+ } else {
+ Outputs->Gdxc.GdxcIotSize = Inputs->Gdxc.GdxcIotSize;
+ }
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function set the WM0-5 values. Those values are be using by the graphics driver.
+ need to be call after PU_MRC_DONE bit is set to 1.
+
+ @param[in] MrcData - include all the MRC data.
+
+ @retval Nothing.
+
+ **/
+void
+MrcWmRegSet (
+ IN MrcParameters *const MrcData
+ )
+{
+ M_PCU_CR_SSKPD_PCU_STRUCT CrSskpdPcu;
+
+ CrSskpdPcu.Data = 0;
+ CrSskpdPcu.Bits.NewWM0 = PCU_CR_SSKPD_PCU_NEW_WM0_DEF;
+ CrSskpdPcu.Bits.WM4 = PCU_CR_SSKPD_PCU_WM4_DEF;
+ CrSskpdPcu.Bits.WM3 = PCU_CR_SSKPD_PCU_WM3_DEF;
+ CrSskpdPcu.Bits.WM2 = PCU_CR_SSKPD_PCU_WM2_DEF;
+ CrSskpdPcu.Bits.WM1 = PCU_CR_SSKPD_PCU_WM1_DEF;
+ CrSskpdPcu.Bits.OldWM0 = PCU_CR_SSKPD_PCU_OLD_WM0_DEF;
+ MrcWriteCR64 (MrcData, PCU_CR_SSKPD_PCU_REG, CrSskpdPcu.Data);
+ return;
+}
+
+
+#ifdef ULT_FLAG
+/**
+@brief
+ Program DDRPL_CR_DDR_TX_DELAY if Memory Trace is enabled
+
+ @param[in] MrcData - The MRC general data.
+
+ @retval None
+**/
+void
+MrcSetDdrplTxDelay (
+ IN MrcParameters *const MrcData
+ )
+{
+ MrcInput *Inputs;
+ MrcOutput *Outputs;
+ MrcChannelOut *ChannelOut;
+ U32 Rank;
+ U32 TxDelay;
+ U32 Roundtrip;
+ U32 tCL;
+ U32 tWCL;
+ U32 CmdDelay;
+ U32 CmdStretch;
+ U32 DecWrd;
+ U32 AddWrDelay;
+ U32 tWCL5_reduction;
+ U32 StretchMode;
+ DDRPL_CR_DDR_TX_DELAY_STRUCT DdrTxDelay;
+ MCHBAR_CH0_CR_SC_ROUNDT_LAT_STRUCT ScRoundtLat;
+ MCHBAR_CH0_CR_SC_WR_ADD_DELAY_STRUCT ScWrAddDelay;
+ MCHBAR_CH0_CR_TC_BANK_RANK_A_STRUCT TcBankRankA;
+ MCHBAR_CH0_CR_TC_BANK_RANK_B_STRUCT TcBankRankB;
+ MCHBAR_CH0_CR_TC_BANK_RANK_D_STRUCT TcBankRankD;
+ MCSCHEDS_CR_STM_CONFIG_STRUCT StmConfig;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+
+ if (!Inputs->MemoryTrace) {
+ return;
+ }
+
+ //
+ // TxDelay(rank) = Roundtrip(rank) - [2*RD_cmd2data_dclk_delay] + [2*Dec_WRD] - additional_wr_delay(rank) - [2*tCWL5_reduction] + [8*(STM - 1)] + Constant(5)
+ //
+ // RD_cmd2data_dclk_delay = tCL + tDQSCK + cmd_delay + cmd_stretch
+ // tCL, tDQSCK - according to JEDEC spec
+ // cmd_delay - MCSCHEDS_CR_TC_BANK_RANK_D. cmd_delay
+ // cmd_stretch - MCSCHEDS_CR_TC_BANK_RANK_A. cmd_stretch (0,1,2 for 1N,2N,3N respectively)
+ //
+ // tCWL5_reduction = (ddr_type==DDR3 && (tCWL + cmd_stretch - Dec_WRD == 5)) ? 1 : 0;
+ //
+ // STM = (STM_mode == SYSTEM ? STM_stf : 1)
+
+ //
+ // Assume we are tracing DDR channel 0 - taking all the timing parameters from Channel 0
+ //
+
+ ChannelOut = &Outputs->Controller[0].Channel[0];
+
+ ScRoundtLat.Data = MrcReadCR (MrcData, MCHBAR_CH0_CR_SC_ROUNDT_LAT_REG);
+ ScWrAddDelay.Data = MrcReadCR (MrcData, MCHBAR_CH0_CR_SC_WR_ADD_DELAY_REG);
+ StmConfig.Data = MrcReadCR (MrcData, MCSCHEDS_CR_STM_CONFIG_REG);
+ TcBankRankA.Data = ChannelOut->MchbarBANKRANKA;
+ TcBankRankB.Data = ChannelOut->MchbarBANKRANKB;
+ TcBankRankD.Data = ChannelOut->MchbarBANKRANKD;
+ tCL = TcBankRankD.UltBits.tCL;
+ tWCL = TcBankRankD.UltBits.tWCL;
+ CmdDelay = TcBankRankD.UltBits.cmd_delay;
+ CmdStretch = TcBankRankA.Bits.CMD_stretch;
+ DecWrd = TcBankRankB.Bits.Dec_WRD;
+
+ if ((Outputs->DdrType == MRC_DDR_TYPE_DDR3) && (tWCL + CmdStretch - DecWrd == 5)) {
+ tWCL5_reduction = 1;
+ } else {
+ tWCL5_reduction = 0;
+ }
+
+ if (StmConfig.Bits.Stretch_mode == 2) {
+ StretchMode = StmConfig.Bits.STF;
+ } else {
+ StretchMode = 1;
+ }
+
+ DdrTxDelay.Data = 0;
+ MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "TX Delay values for Memory Trace:\n");
+ for (Rank = 0; Rank < MAX_RANK_IN_CHANNEL; Rank++) {
+ if (!MrcRankInChannelExist (MrcData, (U8) Rank, 0)) {
+ continue;
+ }
+
+ Roundtrip = (ScRoundtLat.Data >> (Rank * 8)) & MCHBAR_CH0_CR_SC_ROUNDT_LAT_Lat_R0D0_MSK;
+ AddWrDelay = (ScWrAddDelay.Data >> (Rank * 2)) & MCHBAR_CH0_CR_SC_WR_ADD_DELAY_D0R0_MSK;
+
+ TxDelay = Roundtrip - (2 * tCL + 1 + 2 * CmdDelay + 2 * CmdStretch) +
+ 2 * DecWrd - 2 * AddWrDelay - 2 * tWCL5_reduction + 8 * (StretchMode - 1) + 5;
+
+ DdrTxDelay.Data |= ((TxDelay & DDRPL_CR_DDR_TX_DELAY_Tx_Delay_R0_MSK) << (Rank * DDRPL_CR_DDR_TX_DELAY_Tx_Delay_R0_WID));
+
+ MRC_DEBUG_MSG (
+ &Inputs->Debug,
+ MSG_LEVEL_NOTE,
+ "Rank%u:\n RT = %u\n tCL = %u\n cmd_delay = %u\n CMD_stretch = %u\n Dec_WRD = %u\n AddWrDelay = %u\n tWCL5_reduction = %u\n STM = %u\n",
+ Rank,
+ Roundtrip,
+ tCL,
+ CmdDelay,
+ CmdStretch,
+ DecWrd,
+ AddWrDelay,
+ tWCL5_reduction,
+ StretchMode
+ );
+ }
+
+ MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "DDRPL_CR_DDR_TX_DELAY = 0x%08X\n", DdrTxDelay.Data);
+
+ MrcOemMmioWrite (DDRPL_CR_DDR_TX_DELAY_REG, DdrTxDelay.Data, Inputs->GdxcBaseAddress);
+}
+#endif // ULT_FLAG
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.h b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.h
new file mode 100644
index 0000000..04bd977
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.h
@@ -0,0 +1,303 @@
+/** @file
+ MRC Common / Generic functions
+
+@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 _MrcGeneral_h_
+#define _MrcGeneral_h_
+
+#include "MrcTypes.h"
+#include "MrcApi.h"
+#include "MrcAddressDecodeConfiguration.h"
+#include "MrcCommon.h"
+#include "MrcCrosser.h"
+#include "MrcDebugHook.h"
+//
+// #include "MrcMemoryClean.h"
+//
+#include "MrcOem.h"
+#include "MrcPowerModes.h"
+//
+// #include "MrcRefreshConfiguration.h"
+//
+#include "MrcSpdProcessing.h"
+
+#define GENERAL_PM_CONFIGURATION_2_BUS_ADDRESS (0)
+#define GENERAL_PM_CONFIGURATION_2_DEVICE_ADDRESS (31)
+#define GENERAL_PM_CONFIGURATION_2_FUNCTION_ADDRESS (0)
+
+#define GENERAL_PM_CONFIGURATION_2 ((0xA2) & (~0x03))
+
+#define GENERAL_PM_CONFIGURATION_2_DISB_OFFSET (0x7)
+#define GENERAL_PM_CONFIGURATION_2_DISB_WIDTH (0x1)
+#define GENERAL_PM_CONFIGURATION_2_DISB_MASK (0x80)
+#define GENERAL_PM_CONFIGURATION_2_DISB_DEFAULT (0x0)
+
+#define GENERAL_PM_CONFIGURATION_2_MEM_SR_OFFSET (0x5)
+#define GENERAL_PM_CONFIGURATION_2_MEM_SR_WIDTH (0x1)
+#define GENERAL_PM_CONFIGURATION_2_MEM_SR_MASK (0x20)
+#define GENERAL_PM_CONFIGURATION_2_MEM_SR_DEFAULT (0x0)
+
+#define MEMORY_TEST_CACHELINE (100) ///< max number can be 100 from one rank
+///
+/// Define the total memory size of a channel.
+///
+typedef enum {
+ tcs16GB, ///< 16 GB per channel
+ tcs8GB, ///< 8 GB
+ tcs2GB, ///< 2 GB
+ tcs512MB ///< 512 MB
+} MrcTotalChannelSize;
+
+extern MrcUpmPwrRetrainLimits InitialLimits[MRC_NUMBER_UPM_PWR_RETRAIN_MARGINS];
+
+/**
+ Thisfunction performs Software Memory testing
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval Always returns mrcSuccess.
+**/
+extern
+MrcStatus
+MrcHwMemTest (
+ IN MrcParameters *const MrcData
+ );
+
+/**
+ This function changes the MC to normal mode, enables the ECC if needed, lock configuration and set PU_MRC_Done.
+ If the ECC is enabled, this function should be called after memory is cleaned.
+
+ @param[in, out] MrcData - Include all MRC global data.
+
+ @retval Always returns mrcSuccess.
+**/
+extern
+MrcStatus
+MrcMcActivate (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ This function enables Normal Mode and configures the Power Down Modes
+ for the boot flows other than Cold Boot.
+
+ @param[in] MrcData - The MRC general data.
+
+ @retval Always returns mrcSuccess.
+**/
+extern
+MrcStatus
+MrcNormalMode (
+ IN MrcParameters *const MrcData
+ );
+
+/**
+ This function is the last funtion that call from the MRC core.
+ The function set DISB and set the MRC_Done.
+
+ @param[in, out] MrcData - include all the MRC general data.
+
+ @retval Always returns mrcSuccess.
+**/
+extern
+MrcStatus
+MrcDone (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ Print the MRC version to the MRC output device.
+
+ @param[in] Debug - Pointer to the MRC Debug structure.
+ @param[in] Version - The MRC version.
+
+ @retval Nothing.
+**/
+extern
+void
+MrcVersionPrint (
+ IN const MrcParameters *MrcData,
+ IN const MrcVersion *Version
+ );
+
+/**
+ This function return the MRC version.
+
+ @param[out] Version - Location to store the MRC version.
+
+ @retval Nothing.
+**/
+extern
+void
+MrcVersionGet (
+ OUT MrcVersion *const Version
+ );
+
+/**
+ This function set the MRC vertion to MCDECS_SPARE register.
+ The function need to be call by the wrapper after MrcStartMemoryConfiguration function where the MC CLK enable.
+ The function write:
+ Major number to bits 16-23
+ Minor number to bits 8-15
+ Build number to bits 0 - 7
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval Nothing.
+**/
+extern
+MrcStatus
+MrcSetMrcVersion (
+ IN MrcParameters *const MrcData
+ );
+
+/**
+ This function locks the memory controller and memory map registers.
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval Nothing.
+**/
+extern
+void
+McRegistersLock (
+ IN MrcParameters *const MrcData
+ );
+
+/**
+ This function returns the recommended MRC boot mode.
+
+ @param[in] void - No arguments
+
+ @retval bmWarm if we are in self refresh and the DISB bit is set, otherwise returns bmCold.
+**/
+extern
+MrcBootMode
+MrcGetBootMode (
+ void
+ );
+
+/**
+ This function sets the DISB bit in General PM Configuration 2 B:D:F 0,31,0 offset 0xA2.
+
+ @param[in] void - No arguments
+
+ @retval Nothing.
+**/
+extern
+void
+MrcSetDISB (
+ void
+ );
+
+/**
+ This function resets the DISB bit in General PM Configuration 2 B:D:F 0,31,0 offset 0xA2.
+
+ @param[in] void - No arguments
+
+ @retval Nothing.
+**/
+extern
+void
+MrcResetDISB (
+ void
+ );
+
+/**
+ This function reads the CAPID0 register and sets the memory controller's capability.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the memory controller's capability has been determined, otherwise returns mrcFail.
+**/
+extern
+MrcStatus
+MrcMcCapability (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ This function reads the CAPID0 register and sets the memory controller's capability.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the memory controller's capability has been determined, otherwise returns mrcFail.
+**/
+MrcStatus
+MrcMcCapabilityPreSpd (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ This function sets the appropriate timing overrides in the output structure
+ prior to Spd processing.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the timing overrides have been conpleted.
+**/
+extern
+MrcStatus
+MrcSetOverridesPreSpd (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ This function reads the input data structure and sets the appropriate timing overrides in the output structure.
+
+ @param[in, out] MrcData - All the MRC global data.
+
+ @retval Returns mrcSuccess if the timing overrides have been conpleted.
+**/
+extern
+MrcStatus
+MrcSetOverrides (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ This function set the WM0-5 values. Those values are be using by the graphics driver.
+ need to be call after PU_MRC_DONE bit is set to 1.
+
+ @param[in] MrcData - include all the MRC data.
+
+ @retval Nothing.
+
+ **/
+void
+MrcWmRegSet (
+ IN MrcParameters *const MrcData
+ );
+
+
+/**
+@brief
+ Program DDRPL_CR_DDR_TX_DELAY if Memory Trace is enabled
+
+ @param[in] MrcData - The MRC general data.
+
+ @retval None
+**/
+void
+MrcSetDdrplTxDelay (
+ IN MrcParameters *const MrcData
+ );
+
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.c
new file mode 100644
index 0000000..e140250
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.c
@@ -0,0 +1,678 @@
+/** @file
+ This file contains the memory scrubbing and alias checking functions.
+
+@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 "MrcTypes.h"
+#include "MrcApi.h"
+#include "MrcMemoryScrub.h"
+
+/**
+@brief
+ This function sets all the memory to a known value when ECC is enabled and
+ either we are not in warm boot or we are in warm boot and TXT is set.
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval mrcSuccess if the clean succeeded, otherwise an error status.
+**/
+MrcStatus
+MrcEccClean (
+ IN MrcParameters *const MrcData
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ const U8 WrapCarryEn[MrcReutFieldMax] = {0, 0, 0, 0};
+ const U8 WrapTriggerEn[MrcReutFieldMax] = {0, 0, 1, 0}; // Trigger Stop on Bank Wrap
+ const U8 AddrInvertEn[MrcReutFieldMax] = {0, 0, 0, 0};
+ MrcControllerOut *ControllerOut;
+ MrcDimmOut *DimmOut;
+ MrcOutput *Outputs;
+ MrcStatus Status;
+ U32 ReutSubSeqCtl0Data;
+ U8 Pattern;
+ U8 PMask;
+ U8 Rank;
+ U8 Bank;
+ U8 Channel;
+ U8 ActiveChBitMask;
+ U8 RankToDimm;
+ MRC_REUTAddress ReutAddress;
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_STRUCT ReutChSeqCfg;
+ MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_CTRL_STRUCT ReutChPatWdbCl;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ ControllerOut = &Outputs->Controller[0];
+ Debug = &Inputs->Debug;
+ Status = mrcSuccess;
+ Pattern = 0;
+ PMask = 0;
+ MrcOemMemorySet ((U8 *) &ReutAddress, 0, sizeof (ReutAddress));
+
+ if ((Outputs->EccSupport == TRUE) || (Inputs->OemCleanMemory == TRUE)) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Scrubbing Memory\n");
+ ReutAddress.IncVal[MrcReutFieldCol] = 1; // Each write is 1 cache line which is 8 column addresses worth of data.
+ ReutAddress.IncVal[MrcReutFieldRow] = 1; // Walk through rows 1 at a time.
+
+ //
+ // Setup the first cache line to zeros.
+ //
+ WriteWDBFixedPattern (MrcData, &Pattern, &PMask, 1, 0);
+
+ //
+ // Setup Reut for both channels.
+ //
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (!MrcChannelExist (Outputs, Channel)) {
+ continue;
+ }
+
+ //
+ // Write initial Reut Address Values.
+ //
+ MrcProgramSequenceAddress (
+ MrcData,
+ Channel,
+ ReutAddress.Start,
+ NULL, // Stop
+ ReutAddress.Order,
+ ReutAddress.IncRate,
+ ReutAddress.IncVal,
+ WrapTriggerEn,
+ WrapCarryEn,
+ AddrInvertEn,
+ 0, // AddrInvertRate
+ FALSE
+ );
+
+ //
+ // Set Reut to Write
+ //
+ ReutChSeqCfg.Data = 0;
+ ReutChSeqCfg.Bits.Initialization_Mode = REUT_Testing_Mode;
+ ReutChSeqCfg.Bits.Global_Control = 1;
+ ReutChSeqCfg.Bits.Start_Test_Delay = 2;
+ ReutChSeqCfg.Bits.Address_Update_Rate_Mode = 1;
+ ReutChSeqCfg.Bits.Stop_Base_Sequence_On_Wrap_Trigger = 1;
+ MrcWriteCR64 (
+ MrcData,
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG) * Channel),
+ ReutChSeqCfg.Data
+ );
+
+ //
+ // Program new loopcount registers based on stepping.
+ //
+ if (
+ (Inputs->CpuModel == cmHSW && Inputs->CpuStepping >= csHswC0) ||
+ (Inputs->CpuModel == cmCRW && Inputs->CpuStepping >= csCrwC0) ||
+ (Inputs->CpuModel == cmHSW_ULT && Inputs->CpuStepping >= csHswUltC0) ||
+ (Inputs->CpuModel == cmBDW)
+ ) {
+ MrcWriteCR (
+ MrcData,
+ MCDFXS_CR_REUT_CH_SEQ_LOOPCOUNT_LIMIT_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_LOOPCOUNT_LIMIT_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_LOOPCOUNT_LIMIT_MCMAIN_0_REG)
+ * Channel),
+ 0
+ );
+ }
+
+ //
+ // Set up the Subsequence control.
+ //
+ ReutSubSeqCtl0Data = 0;
+ SetSubsequenceType (MrcData, &ReutSubSeqCtl0Data, BWr);
+ MrcWriteCR (
+ MrcData,
+ MCDFXS_CR_REUT_CH0_SUBSEQ_CTL_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH1_SUBSEQ_CTL_MCMAIN_0_REG - MCDFXS_CR_REUT_CH0_SUBSEQ_CTL_MCMAIN_0_REG) * Channel),
+ ReutSubSeqCtl0Data
+ );
+
+ //
+ // Program Write Data Buffer Control. Since we are using 1 cache line, we only need
+ // to set the increment scale to linear.
+ //
+ ReutChPatWdbCl.Data = 0;
+ ReutChPatWdbCl.Bits.WDB_Increment_Scale = 1;
+ MrcWriteCR (
+ MrcData,
+ MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_CTRL_REG +
+ ((MCHBAR_CH1_CR_REUT_CH_PAT_WDB_CL_CTRL_REG - MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_CTRL_REG) * Channel),
+ ReutChPatWdbCl.Data
+ );
+ }
+
+ //
+ // Run Per Rank
+ //
+ for (Rank = 0; Rank < MAX_RANK_IN_CHANNEL; Rank++) {
+ if ((MRC_BIT0 << Rank) & Outputs->ValidRankMask) {
+ //
+ // Determine the Active Channels
+ //
+ ActiveChBitMask = 0;
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ActiveChBitMask |= SelectReutRanks (MrcData, Channel, MRC_BIT0 << Rank, 0);
+ }
+
+ //
+ // Counter registers are not large enough to walk through 1 Rank for LPDDR3 support due to 11 column bits.
+ // Must walk through memory on a bank loop.
+ //
+ for (Bank = 0; Bank < 8; Bank++) {
+ ReutAddress.Start[MrcReutFieldBank] = Bank;
+ ReutAddress.Stop[MrcReutFieldBank] = Bank;
+
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (ActiveChBitMask & (MRC_BIT0 << Channel)) {
+ //
+ // Update Bank start/stop
+ //
+ RankToDimm = RANK_TO_DIMM_NUMBER (Rank);
+ DimmOut = &ControllerOut->Channel[Channel].Dimm[RankToDimm];
+ ReutAddress.Stop[MrcReutFieldRow] = (U16) DimmOut->RowSize - 1;
+ ReutAddress.Stop[MrcReutFieldCol] = DimmOut->ColumnSize - WDB_CACHE_LINE_SIZE;
+ ReutAddress.IncRate[MrcReutFieldRow] = DimmOut->ColumnSize / WDB_CACHE_LINE_SIZE;
+ MrcProgramSequenceAddress (
+ MrcData,
+ Channel,
+ ReutAddress.Start,
+ ReutAddress.Stop,
+ NULL, // Order
+ ReutAddress.IncRate,
+ NULL, // IncVal
+ NULL, // WrapTriggerEn
+ NULL, // WrapCarryEn
+ NULL, // AddrInvertEn
+ 0, // AddrInvertRate
+ FALSE
+ );
+ }
+ }
+
+ //
+ // Run the test
+ //
+ Status = MrcRunMemoryScrub (MrcData, ActiveChBitMask);
+ if (Status != mrcSuccess) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Rank %d error!\n", Rank);
+ break;
+ }
+ }
+ }
+
+ if (Status != mrcSuccess) {
+ break;
+ }
+ }
+
+ //
+ // Return to normal operation mode
+ //
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (MrcChannelExist (Outputs, Channel)) {
+ ReutChSeqCfg.Data = 0;
+ ReutChSeqCfg.Bits.Initialization_Mode = NOP_Mode;
+ MrcWriteCR (
+ MrcData,
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG) * Channel),
+ (U32) ReutChSeqCfg.Data
+ );
+ }
+ }
+
+ if (Status != mrcSuccess) {
+ MrcOemDebugHook (MrcData, MRC_ECC_CLEAN_ERROR);
+ }
+ }
+
+ return Status;
+}
+
+/**
+@brief
+ This function performs a memory alias check.
+
+ @param[in] MrcData - The global host structure
+
+ @retval mrcSuccess or error value.
+**/
+MrcStatus
+MrcAliasCheck (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const MrcDebug *Debug;
+ const MrcInput *Inputs;
+ const U8 WrapCarryEn[MrcReutFieldMax] = {0, 0, 0, 0};
+ const U8 WrapTriggerEn[MrcReutFieldMax] = {0, 0, 0, 0}; // Trigger Stop on Bank Wrap
+ const U8 AddrInvertEn[MrcReutFieldMax] = {0, 0, 0, 0};
+ const U16 SdramCapacityTable[] = {256, 512, 1024, 2048, 4096, 8192, 16384, 32768}; // Mb
+ MrcOutput *Outputs;
+ MrcControllerOut *ControllerOut;
+ MrcDimmOut *DimmOut;
+ MrcStatus Status;
+ MrcDdrType DdrType;
+ BOOL InvalidSpdAddressingCapacity;
+ U32 SdramAddressingCapacity;
+ U32 CrOffset;
+ U16 SdramCapacity;
+ U16 WritesPerPage;
+ U16 ColumnIncValUnaligned;
+ U8 Rank;
+ U8 RankToDimm;
+ U8 Channel;
+ U8 ActiveChBitMask;
+ MRC_REUTAddress ReutAddress;
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_STRUCT ReutChSeqCfg;
+ MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_CTRL_STRUCT ReutChPatWdbCl;
+ MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_STRUCT ReutChPatWdbClMuxCfg;
+ MCDFXS_CR_REUT_CH0_SUBSEQ_CTL_MCMAIN_0_STRUCT ReutSubSeqCtl;
+ MCDECS_CR_MAD_DIMM_CH0_MCMAIN_STRUCT MadDimmCh[MAX_CHANNEL];
+ MCDECS_CR_MAD_DIMM_CH0_MCMAIN_STRUCT MadDimm;
+
+ Outputs = &MrcData->SysOut.Outputs;
+ Inputs = &MrcData->SysIn.Inputs;
+ Debug = &Inputs->Debug;
+ ControllerOut = &Outputs->Controller[0];
+ Status = mrcSuccess;
+ InvalidSpdAddressingCapacity = FALSE;
+ DdrType = Outputs->DdrType;
+ //
+ // Check to see if the SDRAM Addressing * Primary Bus Width == SDRAM capacity.
+ // If not, report an alias and exit.
+ //
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ for (Rank = 0; Rank < MAX_RANK_IN_CHANNEL; Rank += MAX_RANK_IN_DIMM) {
+ if (MrcRankInChannelExist (MrcData, Rank, Channel)) {
+ RankToDimm = RANK_TO_DIMM_NUMBER (Rank);
+ DimmOut = &ControllerOut->Channel[Channel].Dimm[RankToDimm];
+ SdramAddressingCapacity = (DimmOut->ColumnSize * DimmOut->RowSize);
+ //
+ // Since the minimum number of row and coulmn bits are 12 and 9 respectivly,
+ // we can shift by 20 to get the result in Mb before multiplying by the bus width.
+ //
+ SdramAddressingCapacity = SdramAddressingCapacity >> 20;
+ SdramAddressingCapacity *= DimmOut->Banks;
+ SdramAddressingCapacity *= (DimmOut->BankGroups > 0) ? DimmOut->BankGroups : 1;
+ SdramAddressingCapacity *= DimmOut->SdramWidth;
+ SdramCapacity = SdramCapacityTable[DimmOut->DensityIndex];
+ if (SdramCapacity != SdramAddressingCapacity) {
+ InvalidSpdAddressingCapacity = TRUE;
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_ERROR,
+ "ERROR: Channel %d Dimm %d SPD SDRAM Adressing Capacity(0x%xMb) does not match SDRAM Capacity(0x%xMb)\nPlease verify:\n",
+ Channel,
+ RankToDimm,
+ SdramAddressingCapacity,
+ SdramCapacity
+ );
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_ERROR,
+ " Capacity: 0x%x\n RowSize: 0x%x\n ColumnSize: 0x%x\n Banks: 0x%x\n Bank Groups: 0x%x\n Device Width: 0x%x\n",
+ SdramCapacity,
+ DimmOut->RowSize,
+ DimmOut->ColumnSize,
+ DimmOut->Banks,
+ DimmOut->BankGroups,
+ DimmOut->SdramWidth
+ );
+ break;
+ }
+ }
+ }
+ }
+ //
+ // Since we will not hang the system, signal that an Alias could exist and return mrcSuccess.
+ //
+ if (TRUE == InvalidSpdAddressingCapacity) {
+ Outputs->SpdSecurityStatus = MrcSpdStatusAliased;
+ return Status;
+ }
+
+ if ((Inputs->CpuModel == cmHSW && Inputs->CpuStepping >= csHswB0) || (Inputs->CpuModel != cmHSW)) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Performing Alias Test\n");
+ MrcOemMemorySet ((U8 *) &ReutAddress, 0, sizeof (ReutAddress));
+
+ //
+ // Determine if we are ECC enabled. If so, disable ECC since the ECC scrub has yet to occur.
+ //
+ if (Outputs->EccSupport == TRUE) {
+ MRC_DEBUG_MSG(Debug, MSG_LEVEL_NOTE, "ECC enabled. Disabling ECC for the test. Must scrub after this!!!\n");
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (MrcChannelExist (Outputs, Channel)) {
+ CrOffset = MCDECS_CR_MAD_DIMM_CH0_MCMAIN_REG +
+ ((MCDECS_CR_MAD_DIMM_CH1_MCMAIN_REG - MCDECS_CR_MAD_DIMM_CH0_MCMAIN_REG) * Channel);
+
+ MadDimmCh[Channel].Data = MrcReadCR (MrcData, CrOffset);
+ MadDimm.Data = MadDimmCh[Channel].Data;
+ MadDimm.Bits.ECC = emNoEcc;
+ MrcWriteCR (MrcData, CrOffset, MadDimm.Data);
+ }
+ }
+ }
+
+ //
+ // Test Initialization
+ //
+ //
+ // Start with IncRate = 3 so we have 4 column writes per page. This will change with Column Size.
+ // Must have 4 (reg + 1) writes to move to the next LFSR code for unique values.
+ //
+ ReutAddress.IncRate[MrcReutFieldRow] = 3;
+ //
+ // IncVal[Col] is chosen to be 1/4 of the minimum column supported to get 4 writes per page.
+ // Each write is 1 cache line (8 column addresses worth of data).
+ // IncVal is on a cache line basis when programmed. Account for this here ( >> 3).
+ //
+ ColumnIncValUnaligned = MRC_BIT10 >> 2; // divide by 4
+ ReutAddress.IncVal[MrcReutFieldCol] = ColumnIncValUnaligned >> 3; // cache line shift
+ //
+ // Smallest Row address size is 2^12, but Row_Base_Address_Increment is a 12-bit signed field [0-11].
+ // Thus we have to increment by 2^10.
+ //
+ ReutAddress.IncVal[MrcReutFieldRow] = MRC_BIT10;
+ ReutAddress.Stop[MrcReutFieldCol] = 24; // 4 ([0-3] << 3) column writes before wrapping
+ ReutAddress.Start[MrcReutFieldBank] = 1;
+ ReutAddress.Stop[MrcReutFieldBank] = 1;
+
+ //
+ // Setup Reut all present channels.
+ //
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (!MrcChannelExist (Outputs, Channel)) {
+ continue;
+ }
+
+ //
+ // Write initial Reut Address Values.
+ //
+ MrcProgramSequenceAddress (
+ MrcData,
+ Channel,
+ ReutAddress.Start,
+ NULL, // Stop
+ ReutAddress.Order,
+ ReutAddress.IncRate,
+ ReutAddress.IncVal,
+ WrapTriggerEn,
+ WrapCarryEn,
+ AddrInvertEn,
+ 0,
+ FALSE
+ );
+
+ //
+ // Set Reut to Write
+ //
+ ReutChSeqCfg.Data = 0;
+ ReutChSeqCfg.Bits.Initialization_Mode = REUT_Testing_Mode;
+ ReutChSeqCfg.Bits.Global_Control = 1;
+ ReutChSeqCfg.Bits.Start_Test_Delay = 2;
+ ReutChSeqCfg.Bits.Subsequence_End_Pointer = 1;
+
+ if (
+ (Inputs->CpuModel == cmHSW && Inputs->CpuStepping < csHswC0) ||
+ (Inputs->CpuModel == cmCRW && Inputs->CpuStepping < csCrwC0) ||
+ (Inputs->CpuModel == cmHSW_ULT && Inputs->CpuStepping < csHswUltC0) ||
+ (Inputs->CpuModel == cmBDW)
+ ) {
+ ReutChSeqCfg.Bits.Loopcount = 1;
+ } else {
+ CrOffset = MCDFXS_CR_REUT_CH_SEQ_LOOPCOUNT_LIMIT_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_LOOPCOUNT_LIMIT_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_LOOPCOUNT_LIMIT_MCMAIN_0_REG) *
+ Channel);
+ MrcWriteCR (MrcData, CrOffset, 1);
+ }
+
+ CrOffset = MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG) * Channel);
+ MrcWriteCR64 (
+ MrcData,
+ CrOffset,
+ ReutChSeqCfg.Data
+ );
+
+ //
+ // Program Write Data Buffer Control.
+ //
+ ReutChPatWdbCl.Data = 0;
+ ReutChPatWdbCl.Bits.WDB_Increment_Scale = 1;
+ MrcWriteCR (
+ MrcData,
+ MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_CTRL_REG +
+ ((MCHBAR_CH1_CR_REUT_CH_PAT_WDB_CL_CTRL_REG - MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_CTRL_REG) * Channel),
+ ReutChPatWdbCl.Data
+ );
+
+ ReutChPatWdbClMuxCfg.Bits.ECC_Data_Source_Sel = 1;
+ ReutChPatWdbClMuxCfg.Bits.Mux2_Control = LFSRMode;
+ ReutChPatWdbClMuxCfg.Bits.Mux1_Control = LFSRMode;
+ ReutChPatWdbClMuxCfg.Bits.Mux0_Control = LFSRMode;
+ CrOffset = MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_REG +
+ ((MCHBAR_CH1_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_REG - MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_REG) * Channel);
+ MrcWriteCR (MrcData, CrOffset, ReutChPatWdbClMuxCfg.Data);
+ }
+
+ //
+ // Run test Per Dimm
+ //
+ for (Rank = 0; Rank < MAX_RANK_IN_CHANNEL; Rank += MAX_RANK_IN_DIMM){
+ if ((MRC_BIT0 << Rank) & Outputs->ValidRankMask) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Testing Dimm %d\n", Rank / 2);
+ //
+ // Determine Active Channels
+ //
+ ActiveChBitMask = 0;
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ActiveChBitMask |= SelectReutRanks (MrcData, Channel, MRC_BIT0 << Rank, 0);
+ //
+ // Update Rank stop address based on DIMM SPD if Active.
+ //
+ if (ActiveChBitMask & (MRC_BIT0 << Channel)) {
+ RankToDimm = RANK_TO_DIMM_NUMBER (Rank);
+ DimmOut = &ControllerOut->Channel[Channel].Dimm[RankToDimm];
+ //
+ // Since we're counting cache lines and won't wrap the row address,
+ // program Row Stop to RowSize - 1 to avoid resetting the current address.
+ // Column must wrap. The wrap occurs on the increment which is after writing,
+ // to that address. Thus, we set wrap to be the last accessed column.
+ //
+ WritesPerPage = DimmOut->ColumnSize / ColumnIncValUnaligned; // Should be >= 4
+ ReutAddress.Stop[MrcReutFieldRow] = (U16) DimmOut->RowSize - 1;
+ ReutAddress.Stop[MrcReutFieldCol] = DimmOut->ColumnSize - ColumnIncValUnaligned;
+ ReutAddress.IncRate[MrcReutFieldRow] = WritesPerPage - 1; // IncRate is +1 the programmed value
+
+ MrcProgramSequenceAddress (
+ MrcData,
+ Channel,
+ NULL,
+ ReutAddress.Stop,
+ NULL,
+ ReutAddress.IncRate,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ FALSE
+ );
+ //
+ // Set up the Subsequence control.
+ //
+ CrOffset = MCDFXS_CR_REUT_CH0_SUBSEQ_CTL_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH1_SUBSEQ_CTL_MCMAIN_0_REG - MCDFXS_CR_REUT_CH0_SUBSEQ_CTL_MCMAIN_0_REG) * Channel);
+ //
+ // @todo: Review that the settings programmed here are common between the steppings.
+ //
+ ReutSubSeqCtl.Data = 0;
+ ReutSubSeqCtl.Bits.Subsequence_Type = BWr;
+ //
+ // Instead of matching wrap addresses, we will stop on 1 less cache line write from the top.
+ // This works because when aliasing occurs, the physical addressing size must double for row/col.
+ //
+ ReutSubSeqCtl.Bits.Number_of_Cachelines = MrcLog2 (((DimmOut->RowSize / MRC_BIT10) * WritesPerPage) - 1);
+ MrcWriteCR (
+ MrcData,
+ CrOffset,
+ ReutSubSeqCtl.Data
+ );
+
+ CrOffset += MCDFXS_CR_REUT_CH0_SUBSEQ_CTL_MCMAIN_1_REG - MCDFXS_CR_REUT_CH0_SUBSEQ_CTL_MCMAIN_0_REG;
+ ReutSubSeqCtl.Bits.Reset_Current_Base_Address_To_Start = 1;
+ ReutSubSeqCtl.Bits.Subsequence_Type = BRd;
+ MrcWriteCR (
+ MrcData,
+ CrOffset,
+ ReutSubSeqCtl.Data
+ );
+ }
+ }
+
+ //
+ // Run the test
+ //
+ Status = MrcRunMemoryScrub (MrcData, ActiveChBitMask);
+ if (Status != mrcSuccess) {
+ break;
+ }
+ }
+ }
+
+ if (Outputs->EccSupport == TRUE) {
+ MRC_DEBUG_MSG(Debug, MSG_LEVEL_NOTE, "ReEnabling ECC Logic. Must scrub after this!\n");
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (MrcChannelExist (Outputs, Channel)) {
+ CrOffset = MCDECS_CR_MAD_DIMM_CH0_MCMAIN_REG +
+ ((MCDECS_CR_MAD_DIMM_CH1_MCMAIN_REG - MCDECS_CR_MAD_DIMM_CH0_MCMAIN_REG) * Channel);
+
+ MrcWriteCR (MrcData, CrOffset, MadDimmCh[Channel].Data);
+ }
+ }
+ }
+ //
+ // Wait 4 usec after enabling the ECC IO, needed by HW
+ //
+ MrcWait (MrcData, 4 * HPET_1US);
+
+ //
+ // Return to normal operation mode
+ //
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (MrcChannelExist (Outputs, Channel)) {
+ ReutChSeqCfg.Data = 0;
+ ReutChSeqCfg.Bits.Initialization_Mode = NOP_Mode;
+ MrcWriteCR (
+ MrcData,
+ MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG +
+ ((MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG) * Channel),
+ (U32) ReutChSeqCfg.Data
+ );
+ }
+ }
+ }
+
+ if (mrcSuccess != Status) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "*** Alias Detected! See REUT Error above. ***\n");
+ Outputs->SpdSecurityStatus = MrcSpdStatusAliased;
+ Status = mrcSuccess;
+ }
+
+ return Status;
+}
+
+/**
+@brief
+ This function runs the srcubbing test reporting any timeouts/errors.
+
+ @param[in] MrcData - The global host structure
+ @param[in] ChBitMask - Bitmask of channels the test is run on.
+
+ @retval mrcSuccess or error value.
+**/
+MrcStatus
+MrcRunMemoryScrub (
+ IN OUT MrcParameters *const MrcData,
+ IN U8 ChBitMask
+ )
+{
+ const MrcDebug *Debug;
+ MrcStatus Status;
+ U8 ErrorStatus;
+ U8 TestDoneStatus;
+ MCDFXS_CR_REUT_GLOBAL_CTL_MCMAIN_STRUCT ReutGlobalCtl;
+ MCDFXS_CR_REUT_GLOBAL_ERR_MCMAIN_STRUCT ReutGlobalErr;
+ U32 Timer;
+
+ Status = mrcSuccess;
+ Debug = &MrcData->SysIn.Inputs.Debug;
+
+ //
+ // Setup Timer and run the test
+ //
+ Timer = (U32) MrcGetCpuTime() + 10000; // 10 Second timeout
+ ReutGlobalCtl.Data = 0;
+ ReutGlobalCtl.Bits.Global_Start_Test = 1;
+ ReutGlobalCtl.Bits.Global_Clear_Errors = 1;
+ ReutGlobalCtl.Bits.Global_Stop_Test_On_Any_Error = NSOE;
+ MrcWriteCR (MrcData, MCDFXS_CR_REUT_GLOBAL_CTL_MCMAIN_REG, ReutGlobalCtl.Data);
+
+ //
+ // Wait until Channel test done status matches ChbitMask or TimeoutCounter value reaches 0;
+ //
+ do {
+ ReutGlobalErr.Data = MrcReadCR (MrcData, MCDFXS_CR_REUT_GLOBAL_ERR_MCMAIN_REG);
+ TestDoneStatus = (U8) ((ReutGlobalErr.Bits.Channel_Test_Done_Status_1 << 1) |
+ ReutGlobalErr.Bits.Channel_Test_Done_Status_0);
+ } while (((TestDoneStatus & ChBitMask) != ChBitMask) && ((U32) MrcGetCpuTime () < Timer));
+
+ if ((TestDoneStatus & ChBitMask) != ChBitMask) {
+ Status = mrcDeviceBusy;
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_ERROR,
+ "Timeout occured while running the test: ReutGlobalErr: 0x%X.\n",
+ ReutGlobalErr.Data
+ );
+ }
+
+ ErrorStatus = (U8) ((ReutGlobalErr.Bits.Channel_Error_Status_1 << 1) | ReutGlobalErr.Bits.Channel_Error_Status_0);
+ if (ErrorStatus & ChBitMask) {
+ Status = mrcReutSequenceError;
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_ERROR,
+ "REUT Error: Channel(s):%s%s\n",
+ (ReutGlobalErr.Bits.Channel_Error_Status_0 == 1) ? " 0" : "",
+ (ReutGlobalErr.Bits.Channel_Error_Status_1 == 1) ? " 1" : ""
+ );
+ }
+
+ return Status;
+}
+
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.h b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.h
new file mode 100644
index 0000000..d6d1695
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcMemoryScrub.h
@@ -0,0 +1,78 @@
+/** @file
+ This file contains memory scrubbing and alias checking related information.
+
+@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 _MrcMemoryScrub_h_
+#define _MrcMemoryScrub_h_
+#pragma pack (push, 1)
+
+#include "MrcTypes.h"
+#include "MrcApi.h"
+#include "MrcCommon.h"
+#include "MrcDebugHook.h"
+#include "MrcGlobal.h"
+
+/**
+@brief
+ This function sets all the memory to a known value when ECC is enabled and
+ either we are not in warm boot or we are in warm boot and TXT is set.
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval mrcSuccess if the clean succeeded, otherwise an error status.
+**/
+extern
+MrcStatus
+MrcEccClean (
+ IN MrcParameters *const MrcData
+ );
+
+/**
+@brief
+ This function performs a memory alias check.
+
+ @param[in] MrcData - The global host structure
+
+ @retval mrcSuccess or error value.
+**/
+extern
+MrcStatus
+MrcAliasCheck (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+@brief
+ This function runs the srcubbing test reporting any timeouts/errors.
+
+ @param[in] MrcData - The global host structure
+ @param[in] ChBitMask - Bitmask of channels the test is run on.
+
+ @retval mrcSuccess or error value.
+**/
+extern
+MrcStatus
+MrcRunMemoryScrub (
+ IN OUT MrcParameters *const MrcData,
+ IN U8 ChBitMask
+ );
+
+#pragma pack (pop)
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c
new file mode 100644
index 0000000..89464a5
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.c
@@ -0,0 +1,481 @@
+/** @file
+
+ Power state and boot mode save and restore data functions.
+
+@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 files
+//
+#include "MrcTypes.h"
+#include "MrcCommon.h"
+#include "MrcGeneral.h"
+#include "MrcGlobal.h"
+#include "MrcOem.h"
+#include "MrcSaveRestore.h"
+#include "MrcSpdProcessing.h"
+
+//
+// ------- IMPORTANT NOTE --------
+// MRC_MC_REGISTER_COUNT in Global.h should match this table.
+// Update this define whenever you add/remove registers from this table.
+//
+// Total register count = 1872 + 624 = 2496
+//
+const SaveDataControl SaveDataArray[] = {
+ {0x0000, 0x003C}, {0x0048, 0x004C}, {0x005C, 0x0078}, // 40h + 8 + 20h = 68h => 104 * 18 = 1872
+ {0x0100, 0x013C}, {0x0148, 0x014C}, {0x015C, 0x0178},
+ {0x0200, 0x023C}, {0x0248, 0x024C}, {0x025C, 0x0278},
+ {0x0300, 0x033C}, {0x0348, 0x034C}, {0x035C, 0x0378},
+ {0x0400, 0x043C}, {0x0448, 0x044C}, {0x045C, 0x0478},
+ {0x0500, 0x053C}, {0x0548, 0x054C}, {0x055C, 0x0578},
+ {0x0600, 0x063C}, {0x0648, 0x064C}, {0x065C, 0x0678},
+ {0x0700, 0x073C}, {0x0748, 0x074C}, {0x075C, 0x0778},
+ {0x0800, 0x083C}, {0x0848, 0x084C}, {0x085C, 0x0878},
+ {0x0900, 0x093C}, {0x0948, 0x094C}, {0x095C, 0x0978},
+ {0x0A00, 0x0A3C}, {0x0A48, 0x0A4C}, {0x0A5C, 0x0A78},
+ {0x0B00, 0x0B3C}, {0x0B48, 0x0B4C}, {0x0B5C, 0x0B78},
+ {0x0C00, 0x0C3C}, {0x0C48, 0x0C4C}, {0x0C5C, 0x0C78},
+ {0x0D00, 0x0D3C}, {0x0D48, 0x0D4C}, {0x0D5C, 0x0D78},
+ {0x0E00, 0x0E3C}, {0x0E48, 0x0E4C}, {0x0E5C, 0x0E78},
+ {0x0F00, 0x0F3C}, {0x0F48, 0x0F4C}, {0x0F5C, 0x0F78},
+ {0x1000, 0x103C}, {0x1048, 0x104C}, {0x105C, 0x1078},
+ {0x1100, 0x113C}, {0x1148, 0x114C}, {0x115C, 0x1178},
+ {0x1204, 0x1208}, // 8
+ {0x1214, 0x121C}, // 12
+ {0x1304, 0x1308}, // 8
+ {0x1314, 0x131C}, // 12
+ {0x1404, 0x140C}, // 12
+ {0x1504, 0x150C}, // 12
+ {0x1808, 0x1810}, // 12
+ {0x1908, 0x1910}, // 12
+ {0x1A04, 0x1A0C}, // 12
+ {0x1B04, 0x1B0C}, // 12
+ {0x1C14, 0x1C1C}, // 12
+ {0x1D14, 0x1D1C}, // 12
+ {0x2000, 0x2008}, // 12
+ {0x3A14, 0x3A1C}, // 12
+ {0x3A24, 0x3A24}, // 4
+ {0x4000, 0x4014}, // 24
+ {0x4024, 0x4028}, // 8
+ {0x40D0, 0x40D0}, // 4
+ {0x4220, 0x4224}, // 8
+ {0x4294, 0x4294}, // 4
+ {0x429C, 0x42A0}, // 8
+ {0x42EC, 0x42FC}, // 20
+ {0x438C, 0x4390}, // 8
+ {0x4328, 0x4328}, // 4
+ {0x4400, 0x4414}, // 24
+ {0x4424, 0x4428}, // 8
+ {0x44D0, 0x44D0}, // 4
+ {0x4620, 0x4624}, // 8
+ {0x4694, 0x4694}, // 4
+ {0x469C, 0x46A0}, // 8
+ {0x46EC, 0x46FC}, // 20
+ {0x4728, 0x4728}, // 4
+ {0x478C, 0x4790}, // 8
+ {0x5884, 0x5888}, // 8
+ {0x5890, 0x589C}, // 16
+ {0x58A4, 0x58A4}, // 4
+ {0x58D0, 0x58E4}, // 24
+ {0x5880, 0x5880}, // 4
+ {0x5000, 0x50DC}, // 224
+ {0x59b8, 0x59b8} // 4
+}; // = 624
+
+/**
+@brief
+ This function verifies that neither CPU fuses or DIMMs have changed.
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval mrcSuccess if fast boot is allowed, otherwise mrcColdBootRequired.
+**/
+MrcStatus
+MrcFastBootPermitted (
+ IN MrcParameters *const MrcData
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDimmIn *DimmIn;
+ const U8 *CrcStart;
+ MrcSaveData *Save;
+ MrcDimmOut *DimmSave;
+ MRC_PCI_000_CAPID0_STRUCT Capid0Reg;
+ U32 CrcSize;
+ U8 Controller;
+ U8 Channel;
+ U8 Dimm;
+ U16 DimmCrc;
+ U32 Offset;
+
+ CrcStart = NULL;
+ CrcSize = 0;
+ Inputs = &MrcData->SysIn.Inputs;
+ Save = &MrcData->SysSave.Save.Data;
+
+ //
+ // Obtain the capabilities of the memory controller and see if they have changed.
+ //
+ Offset = MrcOemGetPcieDeviceAddress (0, 0, 0, MRC_PCI_000_CAPID0_REG);
+ MrcOemMmioRead (Offset, &Capid0Reg.Data32.A.Data, Inputs->PciEBaseAddress);
+ MrcOemMmioRead (Offset + 4, &Capid0Reg.Data32.B.Data, Inputs->PciEBaseAddress);
+ if (Capid0Reg.Data != Save->McCapId.Data) {
+ MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "Capabilities have changed, cold boot required\n");
+ MRC_DEBUG_MSG (
+ &Inputs->Debug,
+ MSG_LEVEL_NOTE,
+ " '%X_%X' --> '%X_%X'\n",
+ Save->McCapId.Data32[1],
+ Save->McCapId.Data32[0],
+ Capid0Reg.Data32.B.Data,
+ Capid0Reg.Data32.A.Data
+ );
+ return mrcColdBootRequired;
+ }
+ //
+ // See if any of the DIMMs have changed.
+ //
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmIn = &Inputs->Controller[Controller].Channel[Channel].Dimm[Dimm];
+ DimmSave = &Save->Controller[Controller].Channel[Channel].Dimm[Dimm];
+ if (DimmIn->Status == DIMM_DISABLED) {
+ DimmCrc = 0;
+ } else {
+ CrcStart = MrcSpdCrcArea (MrcData, Controller, Channel, Dimm, &CrcSize);
+ GetDimmCrc ((const U8 *const) CrcStart, CrcSize, &DimmCrc);
+ }
+
+ if (DimmCrc != DimmSave->Crc) {
+ MRC_DEBUG_MSG (
+ &Inputs->Debug,
+ MSG_LEVEL_NOTE,
+ "Channel %u Dimm %u has changed, cold boot required\n",
+ Channel,
+ Dimm
+ );
+ MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, " DimmCrc %Xh, DimmSave->Crc %Xh\n", DimmCrc, DimmSave->Crc);
+ return mrcColdBootRequired;
+ }
+ }
+ }
+ }
+ //
+ // Set RestoreMRs flag to use trained Opt Param Values for Power Savings.
+ //
+ MrcData->SysOut.Outputs.RestoreMRs = TRUE;
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function saves any values that need to be used during non-cold boots.
+
+ @param[in, out] MrcData - Include all the MRC global data.
+
+ @retval mrcSuccess if the save occurred with no errors, otherwise returns an error code.
+**/
+MrcStatus
+MrcSaveMCValues (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const SaveDataControl *SaveIt;
+ const MrcInput *Inputs;
+ const MrcControllerIn *ControllerIn;
+ const MrcChannelIn *ChannelIn;
+ const MrcSpd *SpdIn;
+ MrcOutput *Outputs;
+ MrcSaveData *SaveData;
+ MrcSaveHeader *SaveHeader;
+ MrcControllerOut *ControllerOut;
+ MrcChannelOut *ChannelOut;
+ MrcContSave *ControllerSave;
+ MrcChannelSave *ChannelSave;
+ MrcSpdSave *SpdSavePtr;
+ U32 *McRegister;
+ U8 *SpdBegin;
+ MrcProfile Profile;
+ U32 Offset;
+ U32 Index;
+ U32 Value;
+ U8 Controller;
+ U8 Channel;
+ U8 Dimm;
+ U8 CopySize;
+
+ //
+ // Copy channel and DIMM information to the data area that will be saved.
+ //
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ SaveData = &MrcData->SysSave.Save.Data;
+ SaveHeader = &MrcData->SysSave.Save.Header;
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerIn = &Inputs->Controller[Controller];
+ ControllerOut = &Outputs->Controller[Controller];
+ ControllerSave = &SaveData->Controller[Controller];
+ ControllerSave->ChannelCount = ControllerOut->ChannelCount;
+ ControllerSave->Status = ControllerOut->Status;
+
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelIn = &ControllerIn->Channel[Channel];
+ ChannelOut = &ControllerOut->Channel[Channel];
+ ChannelSave = &ControllerSave->Channel[Channel];
+ ChannelSave->DimmCount = ChannelOut->DimmCount;
+ ChannelSave->ValidRankBitMask = ChannelOut->ValidRankBitMask;
+ ChannelSave->EccSupport = ChannelOut->EccSupport;
+ ChannelSave->Status = ChannelOut->Status;
+ for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) {
+ MrcOemMemoryCpy ((U8 *) &ChannelSave->Timing[Profile], (U8 *) &ChannelOut->Timing[Profile], sizeof (MrcTiming));
+ }
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ MrcOemMemoryCpy ((U8 *) &ChannelSave->Dimm[Dimm], (U8 *) &ChannelOut->Dimm[Dimm], sizeof (MrcDimmOut));
+ SpdIn = &ChannelIn->Dimm[Dimm].Spd;
+ SpdSavePtr = &ChannelSave->SpdSave[Dimm];
+ {
+ SpdSavePtr->SmbiosData.ModuleType = SpdIn->Ddr3.General.ModuleType;
+ SpdSavePtr->SmbiosData.ModuleMemoryBusWidth = SpdIn->Ddr3.General.ModuleMemoryBusWidth;
+ SpdBegin = (U8 *) &SpdIn->Ddr3.ModuleId;
+ CopySize = sizeof (SpdSavePtr->ManufacturingData.Ddr3Data);
+ }
+ //
+ // Save just enough SPD information so it can be restored during non-cold boot.
+ //
+ MrcOemMemoryCpy ((U8 *) &SpdSavePtr->ManufacturingData, SpdBegin, CopySize);
+ } // for Dimm
+ } // for Channel
+ } // for Controller
+
+ for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) {
+ SaveData->VddVoltage[Profile] = Outputs->VddVoltage[Profile];
+ }
+
+ //
+ // Copy specified memory controller MMIO registers to the data area that will be saved.
+ //
+ McRegister = SaveData->McRegister;
+ for (Index = 0; Index < (sizeof (SaveDataArray) / sizeof (SaveDataControl)); Index++) {
+ SaveIt = &SaveDataArray[Index];
+ for (Offset = SaveIt->StartMchbarOffset; Offset <= SaveIt->EndMchbarOffset; Offset += sizeof (U32)) {
+ Value = MrcReadCR (MrcData, Offset);
+ *McRegister++ = Value;
+ }
+ }
+
+//
+// ------- IMPORTANT NOTE --------
+// MeStolenSize should not be saved/restored. There is no rule stating that ME FW cannot request a different
+// amount of ME UMA space from one boot to the next. Also, if ME FW is updated/changed, the UMA Size requested
+// from the previous version should not be restored.
+//
+
+ MrcVersionGet (&SaveData->Version);
+ SaveData->CpuModel = Inputs->CpuModel;
+ SaveData->CpuStepping = Inputs->CpuStepping;
+ SaveData->Frequency = Outputs->Frequency;
+ SaveData->MemoryClock = Outputs->MemoryClock;
+ SaveData->Ratio = Outputs->Ratio;
+ SaveData->RefClk = Outputs->RefClk;
+ SaveData->EccSupport = Outputs->EccSupport;
+ SaveData->DdrType = Outputs->DdrType;
+ SaveData->XmpProfileEnable = Outputs->XmpProfileEnable;
+
+ SaveData->SaMemCfgCrc = MrcCalculateCrc32 ((U8 *) Inputs->SaMemCfgAddress, Inputs->SaMemCfgSize);
+ SaveHeader->Crc = MrcCalculateCrc32 ((U8 *) SaveData, sizeof (MrcSaveData));
+ MRC_DEBUG_MSG (&Inputs->Debug, MSG_LEVEL_NOTE, "Saved data CRC = %xh\n", SaveHeader->Crc);
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function copies the non-training information that needs to be restored
+ from the 'save' data structure to the 'Output' data structure.
+
+ @param[in, out] MrcData - include all the MRC global data.
+
+ @retval mrcSuccess if the copy completed with no errors, otherwise returns an error code.
+**/
+MrcStatus
+MrcRestoreNonTrainingValues (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ MrcInput *Inputs;
+ MrcControllerIn *ControllerIn;
+ MrcChannelIn *ChannelIn;
+ MrcSaveData *SaveData;
+ MrcContSave *ControllerSave;
+ MrcChannelSave *ChannelSave;
+ MrcDimmOut *DimmSave;
+ MrcOutput *Outputs;
+ MrcControllerOut *ControllerOut;
+ MrcChannelOut *ChannelOut;
+ MrcDimmOut *DimmOut;
+ MrcSpd *SpdIn;
+ MrcSpdSave *SpdSavePtr;
+ U8 *SpdBegin;
+ MrcProfile Profile;
+ U8 Controller;
+ U8 Channel;
+ U8 Dimm;
+ U8 CopySize;
+
+ SaveData = &MrcData->SysSave.Save.Data;
+ Outputs = &MrcData->SysOut.Outputs;
+ Inputs = &MrcData->SysIn.Inputs;
+ for (Controller = 0; Controller < MAX_CONTROLLERS; Controller++) {
+ ControllerIn = &Inputs->Controller[Controller];
+ ControllerSave = &SaveData->Controller[Controller];
+ ControllerOut = &Outputs->Controller[Controller];
+ ControllerOut->ChannelCount = ControllerSave->ChannelCount;
+ ControllerOut->Status = ControllerSave->Status;
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelIn = &ControllerIn->Channel[Channel];
+ ChannelSave = &ControllerSave->Channel[Channel];
+ ChannelOut = &ControllerOut->Channel[Channel];
+ ChannelOut->DimmCount = ChannelSave->DimmCount;
+ ChannelOut->ValidRankBitMask = ChannelSave->ValidRankBitMask;
+ ChannelOut->EccSupport = ChannelSave->EccSupport;
+ ChannelOut->Status = ChannelSave->Status;
+ for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) {
+ MrcOemMemoryCpy ((U8 *) &ChannelOut->Timing[Profile], (U8 *) &ChannelSave->Timing[Profile], sizeof (MrcTiming));
+ }
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmSave = &ChannelSave->Dimm[Dimm];
+ if (DimmSave->Status == DIMM_PRESENT || DimmSave->Status == DIMM_DISABLED) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ SpdIn = &ChannelIn->Dimm[Dimm].Spd;
+ SpdSavePtr = &ChannelSave->SpdSave[Dimm];
+ MrcOemMemoryCpy ((U8 *) DimmOut, (U8 *) DimmSave, sizeof (MrcDimmOut));
+ {
+ SpdIn->Ddr3.General.ModuleType = SpdSavePtr->SmbiosData.ModuleType;
+ SpdIn->Ddr3.General.ModuleMemoryBusWidth = SpdSavePtr->SmbiosData.ModuleMemoryBusWidth;
+ SpdBegin = (U8 *) &SpdIn->Ddr3.ModuleId;
+ CopySize = sizeof (SpdSavePtr->ManufacturingData.Ddr3Data);
+ }
+ //
+ // Restore just enough SPD information so it can be passed out in the HOB.
+ //
+ MrcOemMemoryCpy (SpdBegin, (U8 *) &SpdSavePtr->ManufacturingData, CopySize);
+ } // if
+ } // for Dimm
+ } // for Channel
+ } // for Controller
+
+ for (Profile = STD_PROFILE; Profile < MAX_PROFILE; Profile++) {
+ Outputs->VddVoltage[Profile] = SaveData->VddVoltage[Profile];
+ }
+
+//
+// ------- IMPORTANT NOTE --------
+// MeStolenSize should not be saved/restored. There is no rule stating that ME FW cannot request a different
+// amount of ME UMA space from one boot to the next. Also, if ME FW is updated/changed, the UMA Size requested
+// from the previous version should not be restored.
+//
+
+ Inputs->CpuModel = SaveData->CpuModel;
+ Inputs->CpuStepping = SaveData->CpuStepping;
+ Outputs->Frequency = SaveData->Frequency;
+ Outputs->MemoryClock = SaveData->MemoryClock;
+ Outputs->Ratio = SaveData->Ratio;
+ Outputs->RefClk = SaveData->RefClk;
+ Outputs->EccSupport = SaveData->EccSupport;
+ Outputs->DdrType = SaveData->DdrType;
+ Outputs->XmpProfileEnable = SaveData->XmpProfileEnable;
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ This function writes the previously determined training values back to the memory controller.
+
+ @param[in] MrcData - Include all the MRC global data.
+
+ @retval mrcSuccess if the memory controller write back completed with no errors, otherwise returns an error code.
+**/
+MrcStatus
+MrcRestoreTrainingValues (
+ IN MrcParameters *const MrcData
+ )
+{
+ const SaveDataControl *RestoreIt;
+ U32 *McRegister;
+ U32 Offset;
+ U32 Index;
+ U32 Value;
+
+ McRegister = MrcData->SysSave.Save.Data.McRegister;
+ for (Index = 0; Index < (sizeof (SaveDataArray) / sizeof (SaveDataControl)); Index++) {
+ RestoreIt = &SaveDataArray[Index];
+ for (Offset = RestoreIt->StartMchbarOffset; Offset <= RestoreIt->EndMchbarOffset; Offset += sizeof (U32)) {
+ Value = *McRegister++;
+ MrcWriteCR (MrcData, Offset, Value);
+ }
+ }
+
+ return mrcSuccess;
+}
+
+/**
+@brief
+ Calculates a CRC-32 of the specified data buffer.
+
+ @param[in] Data - Pointer to the data buffer.
+ @param[in] DataSize - Size of the data buffer, in bytes.
+
+ @retval The CRC-32 value.
+**/
+U32
+MrcCalculateCrc32 (
+ IN const U8 *const Data,
+ IN const U32 DataSize
+ )
+{
+ U32 i;
+ U32 j;
+ U32 crc;
+ U32 CrcTable[256];
+
+ crc = (U32) (-1);
+
+ //
+ // Initialize the CRC base table.
+ //
+ for (i = 0; i < 256; i++) {
+ CrcTable[i] = i;
+ for (j = 8; j > 0; j--) {
+ CrcTable[i] = (CrcTable[i] & 1) ? (CrcTable[i] >> 1) ^ 0xEDB88320 : CrcTable[i] >> 1;
+ }
+ }
+ //
+ // Calculate the CRC.
+ //
+ for (i = 0; i < DataSize; i++) {
+ crc = (crc >> 8) ^ CrcTable[(U8) crc ^ (Data)[i]];
+ }
+
+ return ~crc;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.h b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.h
new file mode 100644
index 0000000..e752cd4
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcSaveRestore.h
@@ -0,0 +1,117 @@
+/** @file
+ Power state and boot mode save and restore data functions.
+
+@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 _MrcSaveRestore_h_
+#define _MrcSaveRestore_h_
+#pragma pack(push, 1)
+
+#include "MrcTypes.h"
+#include "MrcGlobal.h"
+
+typedef struct {
+ U16 StartMchbarOffset;
+ U16 EndMchbarOffset;
+} SaveDataControl;
+
+/**
+ This function verifies that neither CPU fuses or DIMMs have changed.
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval mrcSuccess if fast boot is allowed, otherwise mrcColdBootRequired.
+**/
+extern
+MrcStatus
+MrcFastBootPermitted (
+ IN MrcParameters *const MrcData
+ );
+
+/**
+ This function saves any values that need to be used during non-cold boots.
+
+ @param[in, out] MrcData - Include all the MRC global data.
+
+ @retval mrcSuccess if the save occurred with no errors, otherwise returns an error code.
+**/
+extern
+MrcStatus
+MrcSaveMCValues (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+@brief
+ This function saves any remaining values that need to be used during non-cold boots.
+
+ @param[in, out] MrcData - Include all the MRC global data.
+
+ @retval mrcSuccess if the save occurred with no errors, otherwise returns an error code.
+**/
+extern
+MrcStatus
+MrcSaveMCValuesFinal (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ This function copies the non-training information that needs to be restored
+ from the 'save' data structure to the 'Output' data structure.
+
+ @param[in, out] MrcData - include all the MRC global data.
+
+ @retval mrcSuccess if the copy completed with no errors, otherwise returns an error code.
+**/
+extern
+MrcStatus
+MrcRestoreNonTrainingValues (
+ IN OUT MrcParameters *const MrcData
+ );
+
+/**
+ This function writes the previously determined training values back to the memory controller.
+
+ @param[in] MrcData - Include all the MRC global data.
+
+ @retval mrcSuccess if the memory controller write back completed with no errors, otherwise returns an error code.
+**/
+extern
+MrcStatus
+MrcRestoreTrainingValues (
+ IN MrcParameters *const MrcData
+ );
+
+/**
+ Calculates a CRC-32 of the specified data buffer.
+
+ @param[in] Data - Pointer to the data buffer.
+ @param[in] DataSize - Size of the data buffer, in bytes.
+
+ @retval The CRC-32 value.
+**/
+extern
+U32
+MrcCalculateCrc32 (
+ IN const U8 *const Data,
+ IN const U32 DataSize
+ );
+
+#pragma pack(pop)
+#endif
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.c
new file mode 100644
index 0000000..063e899
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.c
@@ -0,0 +1,236 @@
+/** @file
+ Starting point for the core memory reference code.
+
+@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 files
+//
+#include "MrcTypes.h"
+#include "MrcApi.h"
+#include "MrcCommandTraining.h"
+#include "MrcCommon.h"
+#include "MrcCrosser.h"
+#include "MrcDdr3.h"
+#include "MrcDebugHook.h"
+#include "MrcGeneral.h"
+#include "MrcGlobal.h"
+#include "MrcBdat.h"
+#include "MrcMcConfiguration.h"
+#include "MrcMemoryMap.h"
+#include "MrcMemoryScrub.h"
+#include "MrcOem.h"
+#include "MrcReadDqDqs.h"
+#include "MrcReadReceiveEnable.h"
+#include "MrcReset.h"
+#include "MrcSaveRestore.h"
+#include "MrcSpdProcessing.h"
+#include "MrcStartMemoryConfiguration.h"
+#include "MrcWriteDqDqs.h"
+#include "MrcWriteLeveling.h"
+
+/**
+ Print the input parameters to the debug message output port.
+
+ @param[in] MrcData - The MRC global data.
+
+ @retval mrcSuccess
+**/
+
+//
+// Functions:
+//
+const CallTableEntry CallTable[] = {
+ ///
+ /// The functions are executed in the following order, as the policy flag dictates.
+ /// Mrctask, post_code, OEM command, policy_flag, iteration, debug_string
+ ///
+ {MrcFastBootPermitted, MRC_FAST_BOOT_PERMITTED, OemFastBootPermitted, MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Fast boot permitted")},
+ {MrcRestoreNonTrainingValues,MRC_RESTORE_NON_TRAINING, OemRestoreNonTraining, MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Restore non-training values")},
+#ifdef MRC_DEBUG_PRINT
+ {MrcPrintInputParameters, MRC_PRINT_INPUT_PARAMS, OemPrintInputParameters,MRC_PF_COLD | MRC_PF_WARM | MRC_PF_FAST | MRC_PF_FULL_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Print input parameters")},
+#endif // MRC_DEBUG_PRINT
+ {MrcSetOverridesPreSpd, MRC_SET_OVERRIDES_PSPD, OemSetOverridePreSpd, MRC_PF_COLD | MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Pre-SPD Timing overrides")},
+ {MrcMcCapabilityPreSpd, MRC_MC_CAPABILITY_PSPD, OemMcCapabilityPreSpd, MRC_PF_COLD | MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Pre-SPD MC Capabilities")},
+ {MrcSpdProcessing, MRC_SPD_PROCESSING, OemSpdProcessingRun, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("SPD PROCESSING")},
+ {MrcSetOverrides, MRC_SET_OVERRIDES, OemSetOverride, MRC_PF_COLD | MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Timing overrides")},
+ {MrcMcCapability, MRC_MC_CAPABILITY, OemMcCapability, MRC_PF_COLD | MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MC Capabilities")},
+ {MrcMcConfiguration, MRC_MC_CONFIG, OemMcInitRun, MRC_PF_COLD | MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MC CONFIG")},
+ {MrcSetMemoryMap, MRC_MC_MEMORY_MAP, OemMcMemoryMap, MRC_PF_COLD | MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MC MEMORY MAP")},
+ {MrcResetSequence, MRC_RESET_SEQUENCE, OemMcResetRun, MRC_PF_COLD | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("JEDEC RESET")},
+ {MrcPreTraining, MRC_PRE_TRAINING, OemPreTraining, MRC_PF_COLD | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Pre-Training")},
+ {MrcSenseAmpOffsetTraining, MRC_SENSE_AMP_OFFSET, OemSenseAmpTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("SenseAmp Offset Training")},
+ {MrcEarlyCommandTraining, MRC_EARLY_COMMAND, OemEarlyCommandTraining,MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Early command training")},
+#ifdef ULT_FLAG
+ {MrcJedecInitLpddr3, MRC_JEDEC_INIT_LPDDR3, OemJedecInitLpddr3, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("LPDDR3 JEDEC INIT")},
+#endif // ULT_FLAG
+ {MrcReadLevelingTraining, MRC_RECEIVE_ENABLE, OemReceiveEnable, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read Leveling training")},
+ {MrcReadMprTraining, MRC_READ_MPR, OemReadMprTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read MPR training")},
+
+ {MrcJedecWriteLevelingTraining,MRC_JEDEC_WRITE_LEVELING, OemJedecWriteLeveling, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Jedec Write Leveling training")},
+
+ {MrcWriteTimingCentering, MRC_WRITE_TIMING_1D, OemWriteDqDqs, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Write Timing Centering")},
+ {MrcReadTimingCentering, MRC_READ_TIMING_1D, OemReadDqDqs, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read Timing Centering")},
+
+ {MrcPowerSavingMeter, MRC_PWR_MTR, OemPowerSavingMeter, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("PowerSavingMeter Base Line Update")},
+ {MrcDimmRonTraining, MRC_DIMM_RON, OemDimmRonTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("DIMM Ron Training")},
+ {MrcDimmODTTraining, MRC_DIMM_ODT, OemDimmODTTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("DIMM ODT Training")},
+ {MrcDimmODT1dTraining, MRC_DIMM_ODT, OemDimmODT1dTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("DIMM ODT 1d Training")},
+
+ {MrcWriteDriveStrength, MRC_WRITE_DS, OemWriteDriveStrength, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Write Drive Strength")},
+ {MrcWriteEQTraining, MRC_WRITE_EQ, OemWriteEQTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Write Equalization Training")},
+ {MrcReadODTTraining, MRC_READ_ODT, OemReadODTTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read ODT Training")},
+
+ {MrcWriteSlewRate, MRC_WRITE_SR, OemWriteSlewRate, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Write Slew Rate")},
+ {MrcReadAmplifierPower, MRC_READ_AMP_POWER, OemReadAmplifierPower, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read Amplifier Power")},
+ {MrcReadEQTraining, MRC_READ_EQ, OemReadEQTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read Equalization Training")},
+ {MrcOptimizeComp, MRC_CMP_OPT, OemOptimizeComp, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Comp Optimization Training")},
+//
+/// @attention This sections of tests are left for future testing. Determine later if we can remove.
+// {MrcTestGetMarginBitWrTBit, MRC_ODT_STRETCH_START, OemReadODTTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per CHANNEL")},
+// {MrcTestGetBERMarginByteWrT, MRC_READ_START, OemReadEQTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per BYTE for RcvEn")},
+// {MrcTestGetBERMarginByteRdT, MRC_READ_START, OemReadAmplifierPower, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per BYTE for RdT")},
+// {MrcTestGetBERMarginByteRcvEna, MRC_WRITE_START, OemWriteDqDqs2D, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per BYTE for WrT")},
+// {MrcTestGetBERMarginByteWrDqsT, MRC_READ_START, OemReadDqDqs2D, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per BYTE for WrdqsT")},
+// {MrcTestGetBERMarginByteWrLevel,MRC_WRITE_START, OemWriteVoltCentering2D,MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per BYTE for WrLevel")},
+// {MrcTestGetBERMarginCh, MRC_READ_START, OemReadVoltCentering2D, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per BIT for WrTBit")},
+// {MrcTestGetMarginBitRdTBit, MRC_READ_START, OemWriteXtalkCancel, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Get the Margins per BIT for RdTBit")},
+//
+ {MrcPostTraining, MRC_POST_TRAINING, OemPostTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Post-training")},
+ {MrcLateCommandTraining, MRC_LATE_COMMAND, OemLateCommandTraining, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Late command training")},
+
+ {MrcCmdVoltageCentering, MRC_CMD_VREF, OemCmdVoltCentering, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Command Voltage Centering")},
+ {MrcWriteVoltageCentering2D, MRC_WRITE_VREF_2D, OemWriteVoltCentering2D,MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Write Voltage Centering 2D")},
+ {MrcReadVoltageCentering2D, MRC_READ_VREF_2D, OemReadVoltCentering2D, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read Voltage Centering 2D")},
+
+ {MrcWriteTimingCentering2D, MRC_WRITE_TIMING_2D, OemWriteDqDqs2D, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Write Timing Centering 2D")},
+ {MrcReadTimingCentering2D, MRC_READ_TIMING_2D, OemReadDqDqs2D, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Read Timing Centering 2D")},
+
+ {MrcRoundTripLatency, MRC_ROUND_TRIP_LAT, OemRoundTripLatency, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Round Trip Latency Training")},
+ {MrcTurnAroundTiming, MRC_TURN_AROUND, OemTurnAroundTimes, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Turn Around Trip Training")},
+#ifdef ULT_FLAG
+ {MrcReceiveEnTimingCentering,MRC_RCVEN_TIMING_1D, OemRcvEnCentering1D, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Receive Enable Timing Centering")},
+#endif // ULT_FLAG
+ {MrcRetrainMarginCheck, MRC_RETRAIN_CHECK, OemRetrainMarginCheck, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, 1, MRC_DEBUG_TEXT("Check Margin for Retrain")},
+ {MrcRankMarginTool, MRC_RMT_TOOL, OemRmt, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Rank Margin Tool")},
+ {MrcPowerSavingMeter, MRC_PWR_MTR, OemPowerSavingMeter, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("PowerSavingMeter update")},
+ {MrcMcActivate, MRC_MC_ACTIVATE, OemMrcActivate, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MRC activate")},
+ {MrcSaveMCValues, MRC_SAVE_MC_VALUES, OemSaveMCValues, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Save MC Values")},
+ {MrcRestoreTrainingValues, MRC_RESTORE_TRAINING, OemRestoreTraining, MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Restore Training Values")},
+#ifdef ULT_FLAG
+ {MrcJedecInitLpddr3, MRC_JEDEC_INIT_LPDDR3, OemJedecInitLpddr3, MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("LPDDR3 JEDEC INIT")},
+#endif // ULT_FLAG
+ {MrcSelfRefreshExit, MRC_SELF_REFRESH_EXIT, OemSelfRefreshExit, MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Perform Self Refresh Exit")},
+ {MrcNormalMode, MRC_NORMAL_MODE, OemNormalMode, MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("Normal Operation For Non-Cold Boots")},
+/// @attention: MrcAliasCheck must run before any test modifying the WDB entries to zero for memory scrubbing.
+ {MrcAliasCheck, MRC_ALIAS_CHECK, OemAliasCheck, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MRC Memory alias check")},
+ {MrcHwMemTest, MRC_CPGC_MEMORY_TEST, OemMemTest, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MRC HW Memory testing")},
+ {MrcEccClean, MRC_ECC_CLEAN_START, OemHwMemInit, MRC_PF_COLD | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MRC HW Memory Init")},
+ {MrcDone, MRC_DONE, OemMrcDone, MRC_PF_COLD | MRC_PF_WARM | MRC_PF_S3 | MRC_PF_FAST | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MRC done")},
+#ifdef BDAT_SUPPORT
+ {MrcFillRmtStructure, MRC_FILL_RMT_STRUCTURE, OemMrcFillRmt, MRC_PF_COLD | MRC_PF_FULL_MRC | MRC_PF_MINI_MRC, MRC_ITERATION_MAX, MRC_DEBUG_TEXT("MRC Fill RMT Structure")},
+#endif
+};
+
+/**
+ Initializes the memory controller and DIMMs.
+
+ @param[in, out] MrcData - Include all MRC global data.
+
+ @retval mrcSuccess if the initalization suceeded, otherwise an error status indicating the failure.
+**/
+MrcStatus
+MrcStartMemoryConfiguration (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const CallTableEntry *ctptr;
+ const MrcDebug *Debug;
+ const MrcInput *Inputs;
+ MrcOutput *Outputs;
+ U64 start_time;
+ U64 finish_time;
+ U32 ElapsedTime;
+ U32 TotalTime;
+ U16 index;
+ U8 Run;
+ MrcPostCode post_code;
+ MrcStatus MrcStatus;
+
+ //
+ // Time to sequence thru the MRC tasks.
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ Debug = &Inputs->Debug;
+ Outputs->BootMode = Inputs->BootMode;
+ MrcVersionGet (&Outputs->Version);
+ MrcStatus = mrcFail;
+ post_code = MRC_INITIALIZATION_START;
+ Run = 1;
+ TotalTime = 0;
+ for (index = 0; Run && (index < (sizeof (CallTable) / sizeof (CallTableEntry))); index++, post_code++) {
+ ctptr = &CallTable[index];
+ //
+ // Output post code to post code I/O port.
+ //
+ MrcOemDebugHook (MrcData, ((ctptr->post_code_ovr == POST_CODE_NO_OVR) ? post_code : ctptr->post_code_ovr));
+ //
+ // Decide if we need to execute the selected MRC task.
+ if ((NULL != ctptr->mrc_task) && (Inputs->Iteration < ctptr->iteration)) {
+ if (((Inputs->MrcMode == MrcModeFull) && (ctptr->policy_flag & MRC_PF_FULL_MRC))
+ || ((Inputs->MrcMode == MrcModeMini) && (ctptr->policy_flag & MRC_PF_MINI_MRC))) {
+ if (((Outputs->BootMode == bmS3) && (ctptr->policy_flag & MRC_PF_S3))
+ || ((Outputs->BootMode == bmFast) && (ctptr->policy_flag & MRC_PF_FAST))
+ || ((Outputs->BootMode == bmWarm) && (ctptr->policy_flag & MRC_PF_WARM))
+ || ((Outputs->BootMode == bmCold) && (ctptr->policy_flag & MRC_PF_COLD))) {
+ if ((ctptr->oem_cmd < OemNumOfCommands) && (mrcSuccess != MrcOemCheckPoint (MrcData, ctptr->oem_cmd, NULL))) {
+ continue;
+ }
+ //
+ // Output debug string to serial output and execute the MRC task.
+ //
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "\nMRC task -- %s -- Started.\n", ctptr->String);
+ start_time = MrcGetCpuTime ();
+ MrcStatus = ctptr->mrc_task (MrcData);
+ finish_time = MrcGetCpuTime ();
+ MRC_DEBUG_MSG (
+ Debug,
+ MSG_LEVEL_ERROR,
+ "MRC task %s -- %s, Status = %Xh.\n",
+ ctptr->String,
+ (mrcSuccess == MrcStatus) ? "SUCCEEDED" : "FAILED",
+ MrcStatus
+ );
+ if (mrcSuccess != MrcStatus) {
+ Run = 0; //Stop task execution on failure.
+ }
+
+ ElapsedTime = (U32) (finish_time - start_time);
+ TotalTime += ElapsedTime;
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_TIME, "MRC timer: Task %s took %u msec.\n", ctptr->String, ElapsedTime);
+ }
+ }
+ }
+ }
+
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_TIME, "MRC timer: Total time to execute tasks = %u msec.\n", TotalTime);
+
+ return MrcStatus;
+}
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.h b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.h
new file mode 100644
index 0000000..01aa9d0
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcStartMemoryConfiguration.h
@@ -0,0 +1,74 @@
+/** @file
+ Starting point for the core memory reference code.
+
+@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 __MRC_StartMemoryConfiguration_h__
+#define __MRC_StartMemoryConfiguration_h__
+
+//
+// Include files
+//
+#include "MrcTypes.h"
+#include "MrcApi.h"
+
+typedef U16 MrcPostCode;
+#define POST_CODE_NO_OVR ((1 << ((sizeof (MrcPostCode) * 8) - 1)) + ((1 << ((sizeof (MrcPostCode) * 8) - 1)) - 1))
+
+typedef enum {
+ MRC_PF_NULL, ///< All policy flags turned off.
+ MRC_PF_COLD = (1 << 0), ///< Execute MRC function on cold reset.
+ MRC_PF_FAST = (1 << 1), ///< Execute MRC function on cold reset when S3 data is present.
+ MRC_PF_WARM = (1 << 2), ///< Execute MRC function on warm reset.
+ MRC_PF_S3 = (1 << 3), ///< Execute MRC function on S3 exit.
+ MRC_PF_FULL_MRC = (1 << 4), ///< Execute MRC function when in Full MRC mode.
+ MRC_PF_MINI_MRC = (1 << 5), ///< Execute MRC function when in Mini-MRC mode.
+ MRC_PF_UNUSED = (3 << 6), ///< Unused policy flags.
+ MRC_PF_ALL = (0xF) ///< All policy flags turned off.
+} PFSelector;
+
+typedef U8 PolicyFlag;
+
+#pragma pack(push, 1)
+typedef struct {
+ MrcStatus (*mrc_task) (MrcParameters * const MrcData); ///< Ptr to function to execute, with parameter list.
+ MrcPostCode post_code_ovr; ///< BIOS post code output to the debug port if value <> 0.
+ U32 oem_cmd; ///< OEM function to execute prior to MRC function.
+ PolicyFlag policy_flag; ///< Call table flags
+ MrcIteration iteration; ///< Maximum number of CPU only resets.
+#ifdef MRC_DEBUG_PRINT
+ char *String; ///< Output string describing this task (potentially output to debug serial port).
+#endif // MRC_DEBUG_PRINT
+} CallTableEntry;
+#pragma pack(pop)
+
+/**
+ Initializes the memory controller and DIMMs.
+
+ @param[in, out] MrcData - Include all MRC global data.
+
+ @retval mrcSuccess if the initalization suceeded, otherwise an error status indicating the failure.
+**/
+extern
+MrcStatus
+MrcStartMemoryConfiguration (
+ IN OUT MrcParameters *const MrcData
+ );
+
+#endif