summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.c')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/Api/MrcGeneral.c1577
1 files changed, 1577 insertions, 0 deletions
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