summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/McConfiguration/MrcTimingConfiguration.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/McConfiguration/MrcTimingConfiguration.c')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/McConfiguration/MrcTimingConfiguration.c921
1 files changed, 921 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/McConfiguration/MrcTimingConfiguration.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/McConfiguration/MrcTimingConfiguration.c
new file mode 100644
index 0000000..8f98dd2
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/Source/McConfiguration/MrcTimingConfiguration.c
@@ -0,0 +1,921 @@
+/** @file
+ This module configures the memory controller timing parameters.
+
+@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 "MrcTimingConfiguration.h"
+
+/**
+@brief
+ This function returns the tCKE value for the specified frequency.
+
+ @param[in] DdrType - DDR type
+ @param[in] Frequency - The memory frequency.
+
+ @retval The tCKE value for the specified frequency.
+**/
+static
+U32
+tCKEValue (
+ IN MrcDdrType DdrType,
+ IN const MrcFrequency Frequency
+ )
+{
+ U32 tCKE;
+
+#if (SUPPORT_LPDDR3 == SUPPORT)
+ if (DdrType == MRC_DDR_TYPE_LPDDR3) {
+ if (Frequency <= f1067) {
+ tCKE = tCKE_LPDDR_1067;
+ } else if (Frequency <= f1333) {
+ tCKE = tCKE_LPDDR_1333;
+ } else {
+ tCKE = tCKE_LPDDR_1600;
+ }
+ return tCKE;
+ }
+#endif // SUPPORT_LPDDR3
+
+ if (Frequency <= f800) {
+ tCKE = TCKE_800;
+ } else if (Frequency <= f1067) {
+ tCKE = TCKE_1067;
+ } else if (Frequency <= f1333) {
+ tCKE = TCKE_1333;
+ } else if (Frequency <= f1600) {
+ tCKE = TCKE_1600;
+ } else if (Frequency <= f1867) {
+ tCKE = TCKE_1867;
+ } else if (Frequency <= f2133) {
+ tCKE = TCKE_2133;
+ } else if (Frequency <= f2400) {
+ tCKE = TCKE_2400;
+ } else {
+ tCKE = TCKE_2667;
+ }
+
+ return tCKE;
+}
+
+/**
+@brief
+ This function returns the tXPDLL value for the specified frequency.
+
+ @param[in] Frequency - The memory frequency.
+
+ @retval The tXPDLL value for the specified frequency.
+**/
+static
+U32
+tXPDLLValue (
+ IN const MrcFrequency Frequency
+ )
+{
+ U32 tXPDLL;
+
+ if (Frequency <= f800) {
+ tXPDLL = TXPDLL_800;
+ } else if (Frequency <= f1067) {
+ tXPDLL = TXPDLL_1067;
+ } else if (Frequency <= f1333) {
+ tXPDLL = TXPDLL_1333;
+ } else if (Frequency <= f1600) {
+ tXPDLL = TXPDLL_1600;
+ } else if (Frequency <= f1867) {
+ tXPDLL = TXPDLL_1867;
+ } else if (Frequency <= f2133) {
+ tXPDLL = TXPDLL_2133;
+ } else if (Frequency <= f2400) {
+ tXPDLL = TXPDLL_2400;
+ } else {
+ tXPDLL = TXPDLL_2667;
+ }
+
+ return tXPDLL;
+}
+
+/**
+@brief
+ This function returns the tXP value for the specified frequency.
+
+ @param[in] DdrType - DDR type
+ @param[in] Frequency - The memory frequency.
+ @param[in] NMode - Command mode to lookup.
+
+ @retval The tXP value for the specified frequency.
+**/
+U32
+tXPValue (
+ IN MrcDdrType DdrType,
+ IN const MrcFrequency Frequency,
+ IN U8 NMode
+ )
+{
+ U32 tXP;
+
+#if (SUPPORT_LPDDR3 == SUPPORT)
+ if (DdrType == MRC_DDR_TYPE_LPDDR3) {
+ if (Frequency <= f1333) {
+ tXP = tXP_LPDDR_1333;
+ } else {
+ tXP = tXP_LPDDR_1600;
+ }
+ } else
+#endif // SUPPORT_LPDDR3
+ {
+ if (Frequency <= f1600) {
+ tXP = ((MC_tXP_1600_1N - 1) + NMode);
+ } else if (Frequency <= f1867) {
+ tXP = ((NMode <= 2) ? MC_tXP_1867_2N : MC_tXP_1867_3N);
+ } else if (Frequency <= f2133) {
+ tXP = (MC_tXP_2133_1N);
+ } else {
+ tXP = MC_tXP_MAX;
+ }
+ }
+ return (tXP);
+}
+
+/**
+@brief
+ This function returns the tAONPD value for the specified frequency.
+
+ @param[in] Frequency - The memory frequency.
+
+ @retval The tAONPD value for the specified frequency.
+**/
+static
+U32
+tAONPDValue (
+ IN const MrcFrequency Frequency
+ )
+{
+ U32 tAONPD;
+
+ if (Frequency <= f800) {
+ tAONPD = TAONPD_800;
+ } else if (Frequency <= f1067) {
+ tAONPD = TAONPD_1067;
+ } else if (Frequency <= f1333) {
+ tAONPD = TAONPD_1333;
+ } else if (Frequency <= f1600) {
+ tAONPD = TAONPD_1600;
+ } else if (Frequency <= f1867) {
+ tAONPD = TAONPD_1867;
+ } else if (Frequency <= f2133) {
+ tAONPD = TAONPD_2133;
+ } else if (Frequency <= f2400) {
+ tAONPD = TAONPD_2400;
+ } else {
+ tAONPD = TAONPD_2667;
+ }
+
+ return tAONPD;
+}
+
+/**
+@brief
+ This function sets up the TC-BANK register,
+ which includes the tRCD, tRP, tRAS, tRDPRE, tRTP, tWRPRE, and tRRD values.
+
+ @param[in, out] MrcData - Include all MRC global data.
+ @param[in] Channel - Channel select.
+
+ @retval Nothing.
+**/
+static
+void
+SetTcBankReg (
+ IN OUT MrcParameters *const MrcData,
+ IN const U32 Channel
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcOutput *Outputs;
+ MrcChannelOut *ChannelOut;
+ MrcTiming *Timing;
+ MCHBAR_CH0_CR_TC_BANK_STRUCT CrTcBank;
+ U32 tWRPRE;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Debug = &Inputs->Debug;
+ Outputs = &MrcData->SysOut.Outputs;
+ ChannelOut = &Outputs->Controller[0].Channel[Channel];
+ Timing = &ChannelOut->Timing[Inputs->MemoryProfile];
+
+ //
+ // tWRPRE is = 4tCK + tWR + tWL = 4DCLK + tWR + tWL
+ //
+ tWRPRE = 4 + Timing->tCWL + Timing->tWR;
+
+ CrTcBank.Data = 0;
+ CrTcBank.Bits.tRCD = MIN (MCHBAR_CH0_CR_TC_BANK_tRCD_MAX, Timing->tRCD);
+ CrTcBank.Bits.tRP = MIN (MCHBAR_CH0_CR_TC_BANK_tRP_MAX, Timing->tRP);
+ CrTcBank.Bits.tRAS = MIN (MCHBAR_CH0_CR_TC_BANK_tRAS_MAX, Timing->tRAS);
+ CrTcBank.Bits.tRDPRE = MIN (MCHBAR_CH0_CR_TC_BANK_tRDPRE_MAX, Timing->tRTP);
+ CrTcBank.Bits.tWRPRE = MIN (MCHBAR_CH0_CR_TC_BANK_tWRPRE_MAX, tWRPRE);
+ CrTcBank.Bits.tRRD = MIN (MCHBAR_CH0_CR_TC_BANK_tRRD_MAX, Timing->tRRD);
+#ifdef ULT_FLAG
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ CrTcBank.Bits.tRPab_ext = MIN (MCHBAR_CH0_CR_TC_BANK_tRPab_ext_MAX, Timing->tRPab - Timing->tRP);
+ }
+#endif
+ MrcWriteCR (
+ MrcData,
+ MCHBAR_CH0_CR_TC_BANK_REG + ((MCHBAR_CH1_CR_TC_BANK_REG - MCHBAR_CH0_CR_TC_BANK_REG) * Channel),
+ CrTcBank.Data
+ );
+
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Channel %u:\n tRCD = %u\n", Channel, CrTcBank.Bits.tRCD);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRP = %u\n", CrTcBank.Bits.tRP);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRAS = %u\n", CrTcBank.Bits.tRAS);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDPRE = %u\n", CrTcBank.Bits.tRDPRE);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWRPRE = %u\n", CrTcBank.Bits.tWRPRE);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRRD = %u\n", CrTcBank.Bits.tRRD);
+#ifdef ULT_FLAG
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRPab_ext = %u\n", CrTcBank.Bits.tRPab_ext);
+ }
+#endif
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " TC_BANK = %Xh\n", CrTcBank.Data);
+
+ //
+ // Save in MrcData structure
+ //
+ ChannelOut->MchbarBANK = CrTcBank.Data;
+
+ return;
+}
+
+/**
+@brief
+ This function sets up the TC_BANK_RANK_D register,
+ which includes the tCL and tWCL values.
+
+ @param[in, out] MrcData - Include all MRC global data.
+ @param[in] Channel - Channel select.
+
+ @retval Nothing.
+**/
+static
+void
+SetTcBankRankDReg (
+ IN OUT MrcParameters *const MrcData,
+ IN const U32 Channel
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcOutput *Outputs;
+ MrcChannelOut *ChannelOut;
+ MrcTiming *Timing;
+ MCHBAR_CH0_CR_TC_BANK_RANK_D_STRUCT TcBankRankD;
+ U32 OdtReadDelay;
+#ifdef ULT_FLAG
+ U32 OdtWriteDelay;
+ U32 OdtWriteDuration;
+ U32 DclkPs;
+#endif // ULT_FLAG
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Outputs = &MrcData->SysOut.Outputs;
+ Debug = &Inputs->Debug;
+ ChannelOut = &MrcData->SysOut.Outputs.Controller[0].Channel[Channel];
+ Timing = &ChannelOut->Timing[Inputs->MemoryProfile];
+
+ //
+ // @todo: Need to make sure this value, after power on, follows the restrictions in the XML description.
+ //
+ OdtReadDelay = Timing->tCL - Timing->tCWL;
+
+ TcBankRankD.Data = 0;
+ TcBankRankD.Bits.tWCL = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_D_tWCL_MAX, Timing->tCWL);
+ TcBankRankD.Bits.tCL = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_D_tCL_MAX, Timing->tCL);
+ TcBankRankD.Bits.tCPDED = MCHBAR_CH0_CR_TC_BANK_RANK_D_tCPDED_DEF;
+ TcBankRankD.Bits.tPRPDEN = MCHBAR_CH0_CR_TC_BANK_RANK_D_tPRPDEN_DEF;
+ TcBankRankD.Bits.Odt_Read_Delay = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_D_Odt_Read_Delay_MAX, OdtReadDelay);
+
+#ifdef ULT_FLAG
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ if (Inputs->LpddrDramOdt) {
+ //
+ // Only ODT[0] is used in ULT, need to use it for both ranks
+ //
+ TcBankRankD.UltBits.Odt_Always_Rank0 = 1;
+ }
+
+ //
+ // Timing->tCWL has 1 extra clock because of tDQSS - subtract it here.
+ //
+ TcBankRankD.Bits.tWCL--;
+
+ //
+ // JEDEC Spec requires tCPDED should be 2 clocks for all LPDDR3 frequencies
+ //
+ TcBankRankD.Bits.tCPDED = 2;
+
+ DclkPs = Outputs->Qclkps * 2;
+
+ //
+ // Odt_Write_Delay = WL - 1 - RU(tODTon(max))
+ //
+ OdtWriteDelay = Timing->tCWL - 1 - (tODT_ON_MAX + DclkPs - 1) / DclkPs;
+
+ //
+ // Odt_Write_Duration = 6 + RU(tODTon(max)-tODToff(min)) - 6 + 1
+ //
+ OdtWriteDuration = 1 + (tODT_ON_MAX - tODT_OFF_MIN + DclkPs - 1) / DclkPs;
+
+ TcBankRankD.UltBits.Odt_Write_Delay = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_D_Odt_Write_Delay_Ult_MAX, OdtWriteDelay);
+ TcBankRankD.UltBits.Odt_Write_Duration = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_D_Odt_Write_Duration_Ult_MAX, OdtWriteDuration);
+ }
+#endif // ULT_FLAG
+
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Channel %u:\n tCL = %u\n", Channel, TcBankRankD.Bits.tCL);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWCL = %u\n", TcBankRankD.Bits.tWCL);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tCPDED = %u\n", TcBankRankD.Bits.tCPDED);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tPRPDEN = %u\n", TcBankRankD.Bits.tPRPDEN);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " Odt_Read_Delay = %u\n", TcBankRankD.Bits.Odt_Read_Delay);
+#ifdef ULT_FLAG
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " Odt_Write_Delay = %u\n", TcBankRankD.UltBits.Odt_Write_Delay);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " Odt_Write_Duration = %u\n", TcBankRankD.UltBits.Odt_Write_Duration);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " Odt_Always_Rank0 = %u\n", TcBankRankD.UltBits.Odt_Always_Rank0);
+ }
+#endif // ULT_FLAG
+
+ MrcWriteCR (
+ MrcData,
+ MCHBAR_CH0_CR_TC_BANK_RANK_D_REG + ((MCHBAR_CH1_CR_TC_BANK_RANK_D_REG - MCHBAR_CH0_CR_TC_BANK_RANK_D_REG) * Channel),
+ TcBankRankD.Data
+ );
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " TC_BANK_RANK_D = %Xh\n", TcBankRankD.Data);
+
+ //
+ // Save in MrcData structure
+ //
+ ChannelOut->MchbarBANKRANKD = TcBankRankD.Data;
+
+ return;
+}
+
+/**
+@brief
+ This function sets up the TC_BANK_RANK_A register.
+ which includes the tCKE, tFAW, tRDRD, tRDRD_dr, tRDRD_dd, tRDPDEN, and command rate mode.
+
+ @param[in, out] MrcData - Include all MRC global data.
+ @param[in] Channel - Channel select.
+
+ @retval Nothing.
+**/
+static
+void
+SetTcBankRankAReg (
+ IN OUT MrcParameters *const MrcData,
+ IN const U32 Channel
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcOutput *Outputs;
+ MrcTiming *Timing;
+ MrcDdrType DdrType;
+ MCHBAR_CH0_CR_TC_BANK_RANK_A_STRUCT TcBankRankA;
+ U32 CRValue;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Debug = &Inputs->Debug;
+ Outputs = &MrcData->SysOut.Outputs;
+ Timing = &Outputs->Controller[0].Channel[Channel].Timing[Inputs->MemoryProfile];
+ DdrType = Outputs->DdrType;
+ TcBankRankA.Data = 0;
+
+ //
+ // Get the tCKE value.
+ //
+ CRValue = tCKEValue (DdrType, Outputs->Frequency);
+ TcBankRankA.Bits.tCKE = MIN (MCHBAR_CH1_CR_TC_BANK_RANK_A_tCKE_MAX, CRValue);
+
+ //
+ // Get the command rate mode value.
+ // Use 3N mode during training steps
+ //
+#ifdef ULT_FLAG
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ //
+ // Need to use 1N mode for LPDDR
+ //
+ TcBankRankA.Bits.CMD_stretch = 0;
+ } else
+#endif // ULT_FLAG
+ {
+ TcBankRankA.Bits.CMD_stretch = MIN (MCHBAR_CH1_CR_TC_BANK_RANK_A_CMD_stretch_MAX, 3);
+ }
+ //
+ // Program tFAW value
+ //
+ TcBankRankA.Bits.tFAW = MIN (MCHBAR_CH1_CR_TC_BANK_RANK_A_tFAW_MAX, Timing->tFAW);
+
+ //
+ // Calculate tRDRD
+ //
+ TcBankRankA.Bits.tRDRD = MIN (MCHBAR_CH1_CR_TC_BANK_RANK_A_tRDRD_MAX, TCCD_ALL_FREQ);
+
+ //
+ // Calculate tRDRD_dr = BL/2 + max(tRTR, ODT(R,R,DR)) + tRPRE
+ //
+ CRValue = 4 + 1 + TRPRE_ALL_FREQ;
+
+#ifdef ULT_FLAG
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ //
+ // Increase tRDRD_dr from 6 to 7 DCLKs on LPDDR3
+ //
+ CRValue++;
+ }
+#endif // ULT_FLAG
+
+ TcBankRankA.Bits.tRDRD_dr = MIN (MCHBAR_CH1_CR_TC_BANK_RANK_A_tRDRD_dr_MAX, CRValue);
+
+ //
+ // Calculate tRDRD_dd = BL/2 + max(tRTR, ODT(R,R,DD)) + tRPRE
+ //
+ TcBankRankA.Bits.tRDRD_dd = MIN (MCHBAR_CH1_CR_TC_BANK_RANK_A_tRDRD_dd_MAX, CRValue);
+
+ //
+ // Calculate tRDPDEN = tCL + BL/2 +1
+ //
+ CRValue = Timing->tCL + 5;
+ TcBankRankA.Bits.tRDPDEN = MIN (MCHBAR_CH1_CR_TC_BANK_RANK_A_tRDPDEN_MAX, CRValue);
+
+ //
+ // Disable command tri state before training.
+ //
+ TcBankRankA.Bits.CMD_3st = 1;
+
+ 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),
+ TcBankRankA.Data
+ );
+
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Channel %u:\n tCKE = %u\n", Channel, TcBankRankA.Bits.tCKE);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " NMode = %u\n", TcBankRankA.Bits.CMD_stretch);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tFAW = %u\n", TcBankRankA.Bits.tFAW);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDRD = %u\n", TcBankRankA.Bits.tRDRD);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDRD_dr = %u\n", TcBankRankA.Bits.tRDRD_dr);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDRD_dd = %u\n", TcBankRankA.Bits.tRDRD_dd);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDPDEN = %u\n", TcBankRankA.Bits.tRDPDEN);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " CMD_3st = %u\n", TcBankRankA.Bits.CMD_3st);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " TC_BANK_RANK_A = %Xh\n", TcBankRankA.Data);
+
+ //
+ // Save in MrcData structure
+ //
+ Outputs->Controller[0].Channel[Channel].MchbarBANKRANKA = TcBankRankA.Data;
+
+ return;
+}
+
+/**
+@brief
+ This function sets up the TC_BANK_RANK_B register, which includes
+ Dec_WRD, tWRPDEN, tWRWR_dd, tWRWR_dr, tWRWR, tWRRD_dd, tWRRD_dr and tWRRD.
+
+ @param[in, out] MrcData - Include all MRC global data.
+ @param[in] Channel - Channel select.
+
+ @retval Nothing.
+**/
+static
+void
+SetTcBankRankBReg (
+ IN OUT MrcParameters *const MrcData,
+ IN const U32 Channel
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcOutput *Outputs;
+ MrcTiming *Timing;
+ MCHBAR_CH0_CR_TC_BANK_RANK_B_STRUCT TcBankRankB;
+ MCHBAR_CH0_CR_TC_BANK_RANK_D_STRUCT TcBankRankD;
+ MCHBAR_CH0_CR_SC_WR_ADD_DELAY_STRUCT ScWrAddDelay;
+ U32 CRValue;
+ U32 tWRRD_dr;
+ U32 tWRWR_dr;
+ U32 Offset;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Debug = &Inputs->Debug;
+ Outputs = &MrcData->SysOut.Outputs;
+ Timing = &Outputs->Controller[0].Channel[Channel].Timing[Inputs->MemoryProfile];
+ TcBankRankB.Data = 0;
+
+ //
+ // Calculate tWRRD = tCCD + tCWL + tWTR + max(tWrCAS2RdCAS_sr,ODT(W,R,SR)).
+ //
+ CRValue = TCCD_ALL_FREQ + Timing->tCWL + Timing->tWTR + 2;
+ TcBankRankB.Bits.tWRRD = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_B_tWRRD_MAX, CRValue);
+
+ //
+ // Calculate tWRRD_dr = tCWL-tCL + BL/2 + max(tWRDRDD,ODT(W,R,DR)) + tRPRE
+ //
+ tWRRD_dr = Timing->tCWL - Timing->tCL + 4 + 2 + TRPRE_ALL_FREQ;
+
+#ifdef ULT_FLAG
+ if (Outputs->DdrType == MRC_DDR_TYPE_LPDDR3) {
+ //
+ // tWRRD_dr is 8 for all LPDDR bins
+ //
+ tWRRD_dr = 8;
+ }
+#endif // ULT_FLAG
+
+ TcBankRankB.Bits.tWRRD_dr = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_B_tWRRD_dr_MAX, tWRRD_dr);
+
+ //
+ // Calculate tWRRD_dd = tCWL-tCL + BL/2 + max(tWRDRDD,ODT(W,R,DR)) + tRPRE
+ //
+ TcBankRankB.Bits.tWRRD_dd = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_B_tWRRD_dd_MAX, tWRRD_dr);
+
+ //
+ // Calculate tWRWR
+ //
+ TcBankRankB.Bits.tWRWR = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_B_tWRWR_MAX, TCCD_ALL_FREQ);
+
+ //
+ // Calculate tWRWR_dr = BL/2 + max(tWWDR,ODT(W,W,DR)) + tWPRE
+ //
+ tWRWR_dr = 4 + 2 + TWPRE_ALL_FREQ;
+ TcBankRankB.Bits.tWRWR_dr = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_B_tWRWR_dr_MAX, tWRWR_dr);
+
+ //
+ // Calculate tWRWR_dd = BL/2 + max(tWWDD,ODT(W,W,DR)) + tWPRE
+ //
+ TcBankRankB.Bits.tWRWR_dd = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_B_tWRWR_dd_MAX, tWRWR_dr);
+
+ //
+ // Calculate tWRPDEN = tWR+tWL+BL/2
+ //
+ CRValue = Timing->tWR + Timing->tCWL + 4;
+ TcBankRankB.Bits.tWRPDEN = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_B_tWRPDEN_MAX, CRValue);
+
+ //
+ // Set Dec_WRD.
+ // Can be set to 1 only if tWCL is 6 or more.
+ //
+ Offset = MCHBAR_CH0_CR_TC_BANK_RANK_D_REG +
+ (MCHBAR_CH1_CR_TC_BANK_RANK_D_REG - MCHBAR_CH0_CR_TC_BANK_RANK_D_REG) * Channel;
+ TcBankRankD.Data = MrcReadCR (MrcData, Offset);
+ if (TcBankRankD.Bits.tWCL >= 6) {
+ TcBankRankB.Bits.Dec_WRD = 1;
+ } else {
+ TcBankRankB.Bits.Dec_WRD = 0;
+ }
+
+ MrcWriteCR (
+ MrcData,
+ MCHBAR_CH0_CR_TC_BANK_RANK_B_REG + ((MCHBAR_CH1_CR_TC_BANK_RANK_B_REG - MCHBAR_CH0_CR_TC_BANK_RANK_B_REG) * Channel),
+ TcBankRankB.Data
+ );
+
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Channel %u:\n tWRRD = %u\n", Channel, TcBankRankB.Bits.tWRRD);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWRRD_dr = %u\n", TcBankRankB.Bits.tWRRD_dr);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWRRD_dd = %u\n", TcBankRankB.Bits.tWRRD_dd);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWRWR = %u\n", TcBankRankB.Bits.tWRWR);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWRWR_dr = %u\n", TcBankRankB.Bits.tWRWR_dr);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWRWR_dd = %u\n", TcBankRankB.Bits.tWRWR_dd);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tWRPDEN = %u\n", TcBankRankB.Bits.tWRPDEN);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " Dec_WRD = %u\n", TcBankRankB.Bits.Dec_WRD);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " TC_BANK_RANK_B = %Xh\n", TcBankRankB.Data);
+
+ //
+ // Save in MrcData structure
+ //
+ Outputs->Controller[0].Channel[Channel].MchbarBANKRANKB = TcBankRankB.Data;
+
+ //
+ // Set sc_wr_add_delay accordingly = 1 + Dec_WRD
+ //
+ CRValue = TcBankRankB.Bits.Dec_WRD + 1;
+ ScWrAddDelay.Data = 0;
+ ScWrAddDelay.Bits.D1R1 = MIN (MCHBAR_CH0_CR_SC_WR_ADD_DELAY_D1R1_MAX, CRValue);
+ ScWrAddDelay.Bits.D1R0 = MIN (MCHBAR_CH0_CR_SC_WR_ADD_DELAY_D1R0_MAX, CRValue);
+ ScWrAddDelay.Bits.D0R1 = MIN (MCHBAR_CH0_CR_SC_WR_ADD_DELAY_D0R1_MAX, CRValue);
+ ScWrAddDelay.Bits.D0R0 = MIN (MCHBAR_CH0_CR_SC_WR_ADD_DELAY_D0R0_MAX, CRValue);
+ MrcWriteCR8 (
+ MrcData,
+ MCHBAR_CH0_CR_SC_WR_ADD_DELAY_REG +
+ ((MCHBAR_CH1_CR_SC_WR_ADD_DELAY_REG - MCHBAR_CH0_CR_SC_WR_ADD_DELAY_REG) * Channel),
+ (U8) ScWrAddDelay.Data
+ );
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " SC_WR_ADD_Delay = %Xh\n", ScWrAddDelay.Data);
+
+ return;
+}
+
+/**
+@brief
+ This function sets up the TC_BANK_RANK_C register, which includes
+ TAONPD, tXP, tXPDLL, tRDWR, tRDWR_dr, and tRDWR_dd.
+
+ @param[in, out] MrcData - Include all MRC global data.
+ @param[in] Channel - Channel select.
+
+ @retval Nothing.
+**/
+static
+void
+SetTcBankRankCReg (
+ IN OUT MrcParameters *const MrcData,
+ IN const U32 Channel
+ )
+{
+ const MrcInput *Inputs;
+ const MrcDebug *Debug;
+ MrcOutput *Outputs;
+ MrcTiming *Timing;
+ MrcDdrType DdrType;
+ MCHBAR_CH0_CR_TC_BANK_RANK_C_STRUCT TcBankRankC;
+ U32 Value;
+ U32 DclkPs;
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Debug = &Inputs->Debug;
+ Outputs = &MrcData->SysOut.Outputs;
+ Timing = &Outputs->Controller[0].Channel[Channel].Timing[Inputs->MemoryProfile];
+ DdrType = Outputs->DdrType;
+ TcBankRankC.Data = 0;
+
+ Value = tXPDLLValue (Outputs->Frequency);
+ TcBankRankC.Bits.tXPDLL = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_C_tXPDLL_MAX, Value);
+
+ Value = tXPValue (DdrType, Outputs->Frequency, 3);
+ TcBankRankC.Bits.tXP = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_C_tXP_MAX, Value);
+
+ Value = tAONPDValue (Outputs->Frequency);
+ TcBankRankC.Bits.TAONPD = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_C_TAONPD_MAX, Value);
+
+ //
+ // Calculate tRDWR = tCL-tCWL+tCCD+tWPRE+max(tRWSR,ODT(R,W,SR))
+ // tWPRE - Write Preamble
+ //
+ Value = Timing->tCL - Timing->tCWL + TCCD_ALL_FREQ + TWPRE_ALL_FREQ + 2;
+ //
+ // Add 1 for frequencies above 1333.
+ //
+ if (Outputs->Frequency > f1333) {
+ Value++;
+ }
+
+ DclkPs = Outputs->Qclkps * 2;
+
+#ifdef ULT_FLAG
+ if (DdrType == MRC_DDR_TYPE_LPDDR3) {
+ //
+ // tRDWR = tCL - tCWL + tDQSCK_max + tCCD + tWPRE + ElectricalTurnaround
+ //
+ Value = Timing->tCL - Timing->tCWL + (tDQSCK_MAX + DclkPs - 1) / DclkPs +
+ TCCD_ALL_FREQ + TWPRE_ALL_FREQ + 1;
+ }
+#endif // ULT_FLAG
+
+ TcBankRankC.Bits.tRDWR = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_C_tRDWR_MAX, Value);
+
+ //
+ // Calculate tRDWR_dr = tCL-tCWL+tCCD+tWPRE+max(tRWSR,ODT(R,W,SR))
+ //
+ TcBankRankC.Bits.tRDWR_dr = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_C_tRDWR_dr_MAX, Value);
+
+ //
+ // Calculate tRDWR_dd = tCL-tCWL+tCCD+tWPRE+max(tRWSR,ODT(R,W,SR))
+ //
+ TcBankRankC.Bits.tRDWR_dd = MIN (MCHBAR_CH0_CR_TC_BANK_RANK_C_tRDWR_dd_MAX, Value);
+
+ MrcWriteCR (
+ MrcData,
+ MCHBAR_CH0_CR_TC_BANK_RANK_C_REG + ((MCHBAR_CH1_CR_TC_BANK_RANK_C_REG - MCHBAR_CH0_CR_TC_BANK_RANK_C_REG) * Channel),
+ TcBankRankC.Data
+ );
+
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Channel %u:\n tXPDLL = %u\n", Channel, TcBankRankC.Bits.tXPDLL);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tXP = %u\n", TcBankRankC.Bits.tXP);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tAONPD = %u\n", TcBankRankC.Bits.TAONPD);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDWR = %u\n", TcBankRankC.Bits.tRDWR);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDWR_dr = %u\n", TcBankRankC.Bits.tRDWR_dr);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " tRDWR_dd = %u\n", TcBankRankC.Bits.tRDWR_dd);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, " TC_BANK_RANK_C = %Xh\n", TcBankRankC.Data);
+
+ //
+ // Save in MrcData structure
+ //
+ Outputs->Controller[0].Channel[Channel].MchbarBANKRANKC = TcBankRankC.Data;
+
+ return;
+}
+
+/**
+@brief
+ This function configures the memory controller timings.
+
+ @param[in] MrcData - Include all MRC global data.
+
+ @retval Nothing.
+**/
+void
+MrcTimingConfiguration (
+ IN MrcParameters *const MrcData
+ )
+{
+ U8 Channel;
+
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (MrcChannelExist (&MrcData->SysOut.Outputs, Channel)) {
+ //
+ // setup TC-BANK register
+ //
+ SetTcBankReg (MrcData, Channel);
+
+ //
+ // setup TC-BANK_RANK_D register
+ //
+ SetTcBankRankDReg (MrcData, Channel);
+
+ //
+ // setup TC-BANK_RANK_A register
+ //
+ SetTcBankRankAReg (MrcData, Channel);
+
+ //
+ // setup TC-BANK_RANK_B register
+ //
+ SetTcBankRankBReg (MrcData, Channel);
+
+ //
+ // setup TC-BANK_RANK_C register
+ //
+ SetTcBankRankCReg (MrcData, Channel);
+ }
+ }
+
+ //
+ // Check RawCard Types and adjust Read ODT if needed
+ //
+ RdOdtStretch (MrcData);
+
+ return;
+}
+
+/**
+@brief
+ This function sets up the Read ODTD values based on RawCard types and adjusts the tDRRD2RD, tDDRD2RD, tDRRD2WR and tDDRD2WR
+
+ @param[in, out] MrcData - Include all MRC global data.
+
+ @retval Nothing.
+**/
+void
+RdOdtStretch (
+ IN OUT MrcParameters *const MrcData
+ )
+{
+ const MrcDebug *Debug;
+ const MrcInput *Inputs;
+ MrcControllerOut *ControllerOut;
+ MrcChannelOut *ChannelOut;
+ U8 Channel;
+ U8 ChBitMask;
+ U8 RankMaskCh;
+ S8 OdtStretch;
+#if SUPPORT_SODIMM == SUPPORT
+ MrcDimmOut *DimmOut;
+ BOOL SoDimm;
+ U8 Value;
+ U8 Dimm;
+ U8 DimmRawCardType[MAX_DIMMS_IN_CHANNEL];
+ MCHBAR_CH0_CR_TC_BANK_RANK_A_STRUCT TcBankRankA;
+ MCHBAR_CH0_CR_TC_BANK_RANK_C_STRUCT TcBankRankC;
+#endif //SUPPORT_SODIMM == SUPPORT
+
+ Inputs = &MrcData->SysIn.Inputs;
+ Debug = &Inputs->Debug;
+ ControllerOut = &MrcData->SysOut.Outputs.Controller[0];
+
+ ChBitMask = 0;
+
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ ChannelOut = &ControllerOut->Channel[Channel];
+ if (ChannelOut->ValidRankBitMask && (ChannelOut->DimmCount == 2)) {
+ ChBitMask |= (MRC_BIT0 << Channel);
+ }
+ }
+
+ for (Channel = 0; Channel < MAX_CHANNEL; Channel++) {
+ if (!((MRC_BIT0 << Channel) & ChBitMask)) {
+ //
+ // Skip any channels that do not have 2 DIMMs populated
+ //
+ continue;
+ }
+
+ ChannelOut = &ControllerOut->Channel[Channel];
+ RankMaskCh = ChannelOut->ValidRankBitMask;
+ //
+ // Start with the most aggressive setting
+ //
+ OdtStretch = 6;
+
+#if SUPPORT_SODIMM == SUPPORT
+ SoDimm = FALSE;
+ for (Dimm = 0; Dimm < MAX_DIMMS_IN_CHANNEL; Dimm++) {
+ DimmOut = &ChannelOut->Dimm[Dimm];
+ if (((DimmOut->ModuleType == MRC_MODULE_TYPE_SODIMM) || (DimmOut->ModuleType == MRC_MODULE_72B_SO_UDIMM))
+ && (SoDimm == FALSE)) {
+ SoDimm = TRUE;
+ }
+ if (SoDimm) {
+ DimmRawCardType[Dimm] = DimmOut->ReferenceRawCard;
+ }
+ }
+
+ if (SoDimm) {
+ if ((DimmRawCardType[0] == rcF || DimmRawCardType[1] == rcF)
+ && (DimmRawCardType[0] != DimmRawCardType[1])) {
+ OdtStretch = 7;
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE,"Rd Odt Stretch F\n");
+ }
+ }
+#endif //SUPPORT_SODIMM == SUPPORT
+ //
+ // Program Rdodtd value
+ //
+ UpdateTAParamOffset (MrcData, Channel, 0, rdodtd, OdtStretch, 1, 1, RankMaskCh);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Selected RdOdtD Offset for channel %d is = %d\n", Channel, OdtStretch);
+
+#if SUPPORT_SODIMM == SUPPORT
+ if (OdtStretch > 6) {
+ TcBankRankA.Data = ChannelOut->MchbarBANKRANKA;
+ Value = (U8)(TcBankRankA.Bits.tRDRD_dr);
+ Value += OdtStretch - 6;
+ //
+ // Program Different Rank RD 2 RD value
+ //
+ UpdateTAParamOffset (MrcData, Channel, 0, drrd2rd, Value, 1, 1, RankMaskCh);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Selected DR RD2RD Offset for channel %d is = %d\n", Channel, Value);
+
+ Value = (U8)(TcBankRankA.Bits.tRDRD_dd);
+ Value += OdtStretch - 6;
+ //
+ // Program Different DIMM RD 2 RD value
+ //
+ UpdateTAParamOffset (MrcData, Channel, 0, ddrd2rd, Value, 1, 1, RankMaskCh);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Selected DD RD2RD Offset for channel %d is = %d\n", Channel, Value);
+
+ TcBankRankC.Data = ChannelOut->MchbarBANKRANKC;
+ Value = (U8)(TcBankRankC.Bits.tRDWR_dr);
+ Value += OdtStretch - 6;
+ //
+ // Program Different Rank RD 2 WR value
+ //
+ UpdateTAParamOffset (MrcData, Channel, 0, drrd2wr, Value, 1, 1, RankMaskCh);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Selected DR RD2WR Offset for channel %d is = %d\n", Channel, Value);
+
+ Value = (U8)(TcBankRankC.Bits.tRDWR_dd);
+ Value += OdtStretch - 6;
+ //
+ // Program Different DIMM RD 2 WR value
+ //
+ UpdateTAParamOffset (MrcData, Channel, 0, ddrd2wr, Value, 1, 1, RankMaskCh);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Selected DD RD2WR Offset for channel %d is = %d\n", Channel, Value);
+
+ Value = (U8)(TcBankRankC.Bits.tRDWR);
+ Value += OdtStretch - 6;
+ //
+ // Program Same Rank RD 2 WR value
+ //
+ UpdateTAParamOffset (MrcData, Channel, 0, srrd2wr, Value, 1, 1, RankMaskCh);
+ MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "Selected SR RD2WR Offset for channel %d is = %d\n", Channel, Value);
+ }
+#endif //SUPPORT_SODIMM == SUPPORT
+ }
+
+}