diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api | |
download | zprj-master.tar.xz |
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api')
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 |