diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f16kb/Proc/Mem/NB/KB/mndctkb.c')
-rw-r--r-- | src/vendorcode/amd/agesa/f16kb/Proc/Mem/NB/KB/mndctkb.c | 1217 |
1 files changed, 1217 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/NB/KB/mndctkb.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/NB/KB/mndctkb.c new file mode 100644 index 0000000000..819fb20a50 --- /dev/null +++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/NB/KB/mndctkb.c @@ -0,0 +1,1217 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mndctkb.c + * + * Northbridge DCT support for KB + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/NB/KB) + * @e \$Revision: 86880 $ @e \$Date: 2013-01-28 11:15:07 -0600 (Mon, 28 Jan 2013) $ + * + **/ +/***************************************************************************** +* + * Copyright (c) 2008 - 2013, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Advanced Micro Devices, Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* *************************************************************************** +* +*/ + + +/* + *---------------------------------------------------------------------------- + * MODULES USED + * + *---------------------------------------------------------------------------- + */ + + + +#include "AGESA.h" +#include "amdlib.h" +#include "Ids.h" +#include "mport.h" +#include "mm.h" +#include "mn.h" +#include "mt.h" +#include "mu.h" +#include "OptionMemory.h" +#include "PlatformMemoryConfiguration.h" +#include "mnkb.h" +#include "mftds.h" +#include "merrhdl.h" +#include "cpuFamRegisters.h" +#include "GeneralServices.h" +#include "cpuFamilyTranslation.h" +#include "cpuF16Utilities.h" +#include "IdsF16KbAllService.h" +#include "Filecode.h" +CODE_GROUP (G3_DXE) +RDATA_GROUP (G3_DXE) + + +#define FILECODE PROC_MEM_NB_KB_MNDCTKB_FILECODE + +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ +#define UNUSED_CLK 4 + +CONST BIT_FIELD_NAME MemPstateBF[4] = {BFMemPstate0, BFMemPstate1, BFMemPstate2, BFMemPstate3}; +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ +UINT32 +STATIC +MemNTotalSyncComponentsKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ); + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +extern BUILD_OPT_CFG UserOptions; + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function programs the memory controller with configuration parameters + * + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * @return TRUE - An Error value lower than AGESA_FATAL may have occurred + * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred + * @return NBPtr->MCTPtr->ErrCode - Contains detailed AGESA_STATUS value + */ + +BOOLEAN +MemNAutoConfigKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 i; + DIE_STRUCT *MCTPtr; + DCT_STRUCT *DCTPtr; + MEM_PARAMETER_STRUCT *RefPtr; + UINT32 PowerDownMode; + UINT32 Tstag; + + RefPtr = NBPtr->RefPtr; + MCTPtr = NBPtr->MCTPtr; + DCTPtr = NBPtr->DCTPtr; + + // + //====================================================================== + // Build Dram Config Lo Register Value + //====================================================================== + MemNSetBitFieldNb (NBPtr, BFUnBuffDimm, 1); + MemNSetBitFieldNb (NBPtr, BFPendRefPaybackS3En, 1); + MemNSetBitFieldNb (NBPtr, BFStagRefEn, 1); + // + // DimmEccEn + // + if (MCTPtr->Status[SbEccDimms]) { + MemNSetBitFieldNb (NBPtr, BFDimmEccEn, 1); + } + // + //====================================================================== + // Build Dram Config Hi Register Value + //====================================================================== + // + // + // MemClkFreq + // + MemNSetBitFieldNb (NBPtr, BFMemClkFreq, MemNGetMemClkFreqIdUnb (NBPtr, DCTPtr->Timings.Speed)); + + PowerDownMode = 1; + IDS_OPTION_HOOK (IDS_POWERDOWN_MODE, &PowerDownMode, &(NBPtr->MemPtr->StdHeader)); + MemNSetBitFieldNb (NBPtr, BFPowerDownMode, PowerDownMode); + + if (NBPtr->MemPstateStage == MEMORY_PSTATE_1ST_STAGE) { + MemNBrdcstSetNb (NBPtr, BFM1MemClkFreq, MemNGetMemClkFreqIdUnb (NBPtr, DDR667_FREQUENCY)); + MemNSetBitFieldNb (NBPtr, BFDphyMemPsSelEn, 0); + MemNBrdcstSetNb (NBPtr, BFRate, MemNGetMemClkFreqIdUnb (NBPtr, DDR667_FREQUENCY) | 0x8); + MemNBrdcstSetNb (NBPtr, BFMxMrsEn, 7); + } + + MemNSetBitFieldNb (NBPtr, BFDphyMemPsSelEn, 1); + // + //====================================================================== + // Build Dram MRS Register Value + //====================================================================== + // + MemNSetBitFieldNb (NBPtr, BFPchgPDModeSel, 1); + MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 1); + + //====================================================================== + // DRAM Controller Miscellaneous 2 + //====================================================================== + MemNSetBitFieldNb (NBPtr, BFPerRankTimingEn, 1); + IDS_HDT_CONSOLE (MEM_FLOW, "\n\nEnable Per Rank Training....\n\n"); + MemNSetBitFieldNb (NBPtr, BFPrtlChPDEnhEn, 0); + MemNSetBitFieldNb (NBPtr, BFAggrPDEn, 1); + MemNSetBitFieldNb (NBPtr, BFDctSelBankSwap, 1); + + //====================================================================== + // Trace Buffer Extended Address Initialization + //====================================================================== + MemNSetBitFieldNb (NBPtr, BFTrcBufAdrPtrHi, 0); + MemNSetBitFieldNb (NBPtr, BFTrcBufDramLimitHi, 0); + MemNSetBitFieldNb (NBPtr, BFTrcBufDramBaseHi, 0); + + //====================================================================== + // GMC to DCT control + //====================================================================== + MemNSetBitFieldNb (NBPtr, BFGmcTokenLimit, 4); + MemNSetBitFieldNb (NBPtr, BFMctTokenLimit, 4); + MemNSetBitFieldNb (NBPtr, BFGmcToDctControl1, 0x04040404); + MemNSetBitFieldNb (NBPtr, BFCpuElevPrioPeriod, 0xC); + MemNSetBitFieldNb (NBPtr, BFCpuElevPrioDis, 0); + + //====================================================================== + // Other Registers + //====================================================================== + // + // + // Non-SPD Timings + // + MemNSetBitFieldNb (NBPtr, BFTrwtWB, 0x17); + MemNSetBitFieldNb (NBPtr, BFTrwtTO, 0x16); + MemNSetBitFieldNb (NBPtr, BFTwrrd, 0xB ); + + MemNSetBitFieldNb (NBPtr, BFTrdrdSdSc, 0xB); + MemNSetBitFieldNb (NBPtr, BFTrdrdSdDc, 0xB); + MemNSetBitFieldNb (NBPtr, BFTrdrdDd, 0xB); + + MemNSetBitFieldNb (NBPtr, BFTwrwrSdSc, 0xB); + MemNSetBitFieldNb (NBPtr, BFTwrwrSdDc, 0xB); + MemNSetBitFieldNb (NBPtr, BFTwrwrDd, 0xB); + + MemNSetBitFieldNb (NBPtr, BFWrOdtOnDuration, DEFAULT_WR_ODT_KB); + MemNSetBitFieldNb (NBPtr, BFRdOdtOnDuration, DEFAULT_RD_ODT_KB); + MemNSetBitFieldNb (NBPtr, BFWrOdtTrnOnDly, DEFAULT_RD_ODT_TRNONDLY_KB); + + // Tstag = BIOS: MAX(D18F2x204_dct[0]_mp[1:0][Trrd], CEIL(D18F2x204_dct[0]_mp[1:0][FourActWindow]/4)) + Tstag = MAX (MemNGetBitFieldNb (NBPtr, BFTrrd), (MemNGetBitFieldNb (NBPtr, BFFourActWindow) + 3) / 4); + for (i = 0; i < 4; i++) { + MemNSetBitFieldNb (NBPtr, BFTstag0 + i, Tstag); + } + + MemNSetBitFieldNb (NBPtr, BFTmrd, 4); + MemNSetBitFieldNb (NBPtr, BFFlushWrOnS3StpGnt, 1); + MemNSetBitFieldNb (NBPtr, BFFastSelfRefEntryDis, 0); + + return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function caps speed based on battery life check. + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + */ +VOID +MemNCapSpeedBatteryLifeKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + CONST UINT16 SupportedFreq[] = { + DDR2133_FREQUENCY, + DDR1866_FREQUENCY, + DDR1600_FREQUENCY, + DDR1333_FREQUENCY, + DDR1066_FREQUENCY, + DDR800_FREQUENCY, + DDR667_FREQUENCY + }; + + UINT32 FreqNumeratorInMHz; + UINT32 FreqDivisor; + UINT32 VoltageInuV; + UINT32 NBFreq; + UINT16 DdrFreq; + UINT16 j; + UINT8 Dct; + INT8 NbPs; + CPU_SPECIFIC_SERVICES *FamilySpecificServices; + + FamilySpecificServices = NULL; + GetCpuServicesOfSocket (NBPtr->MCTPtr->SocketId, (CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &(NBPtr->MemPtr->StdHeader)); + + + // Find the lowest supported NB Pstate + NBFreq = 0; + for (NbPs = 3; NbPs >= 0; NbPs--) { + if (FamilySpecificServices->GetNbPstateInfo (FamilySpecificServices, + NBPtr->MemPtr->PlatFormConfig, + &NBPtr->PciAddr, + (UINT32) NbPs, + &FreqNumeratorInMHz, + &FreqDivisor, + &VoltageInuV, + &(NBPtr->MemPtr->StdHeader))) { + if (MemNGetBitFieldNb (NBPtr, MemPstateBF[NbPs]) == 0) { + NBFreq = FreqNumeratorInMHz / FreqDivisor; + break; + } + } + } + + ASSERT (NBFreq > 0); + + // Pick Max MEMCLK that is less than or equal to NCLK + DdrFreq = DDR800_FREQUENCY; + for (j = 0; j < GET_SIZE_OF (SupportedFreq); j++) { + if (NBFreq >= ((UINT32) SupportedFreq[j]) && NBFreq <= ((UINT32) SupportedFreq[j] * 2)) { + DdrFreq = SupportedFreq[j]; + break; + } + } + ASSERT (j < GET_SIZE_OF (SupportedFreq)); + + // Cap MemClk frequency to lowest NCLK frequency + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.TargetSpeed > DdrFreq) { + NBPtr->DCTPtr->Timings.TargetSpeed = DdrFreq; + } + } + + // Initialize NbPsCtlReg + NBPtr->NbPsCtlReg = 0; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function retrieves the Max latency parameters + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * @param[in] *MinDlyPtr - Pointer to variable to store the Minimum Delay value + * @param[in] *MaxDlyPtr - Pointer to variable to store the Maximum Delay value + * @param[in] *DlyBiasPtr - Pointer to variable to store Delay Bias value + * @param[in] MaxRcvEnDly - Maximum receiver enable delay value + */ + +VOID +MemNGetMaxLatParamsKB ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT16 MaxRcvEnDly, + IN OUT UINT16 *MinDlyPtr, + IN OUT UINT16 *MaxDlyPtr, + IN OUT UINT16 *DlyBiasPtr + ) +{ + UINT32 N; + UINT32 T; + UINT32 P; + UINT32 MemClkPeriod; + + // 1. P = N = T = 0. + P = N = T = 0; + + // Get all sync components BKDG steps 3,4,6 + P = MemNTotalSyncComponentsKB (NBPtr); + + // 8. P = P + CEIL(MAX(D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] + + // D18F2x9C_x0000_0[3:0]0[7:5]_dct[1:0][RdDqsTime] PCLKs)) + 1 + P = P + (MaxRcvEnDly + 31) / 32 + 1; + + // 11. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs. + MemClkPeriod = 1000000 / ((NBPtr->MemPstate == MEMORY_PSTATE0) ? NBPtr->DCTPtr->Timings.Speed : DDR667_FREQUENCY); + N = ((((P * MemClkPeriod + 1) / 2) + T) * NBPtr->NBClkFreq + 999999) / 1000000; + + // Calculate a starting MaxRdLatency delay value with steps 5, 9, and 12 excluded + *MinDlyPtr = (UINT16) N; + + *MaxDlyPtr = 0x3FF; + + // Program D18F2x210_dct[0]_nbp[3:0][MaxRdLatency] = CEIL(current value + 1 NCLK + 1.5 MEMCLK + + // IF (NclkFreq/MemClkFreq < 2) THEN 1 MEMCLK ELSE 0 ENDIF) + N = 1; + P = 3 + (((NBPtr->NBClkFreq / ((NBPtr->MemPstate == MEMORY_PSTATE0) ? NBPtr->DCTPtr->Timings.Speed : DDR667_FREQUENCY)) < 2) ? 2 : 0); + N += (((P * MemClkPeriod + 1) / 2) * NBPtr->NBClkFreq + 999999) / 1000000; + *DlyBiasPtr = (UINT16) N; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function sets the maximum round-trip latency in the system from the processor to the DRAM + * devices and back. + * + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in] MaxRcvEnDly - Maximum receiver enable delay value + * + */ + +VOID +MemNSetMaxLatencyKB ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN UINT16 MaxRcvEnDly + ) +{ + UINT32 N; + UINT32 T; + UINT32 P; + UINT32 Px2; + UINT32 MemClkPeriod; + + AGESA_TESTPOINT (TpProcMemRcvrCalcLatency, &(NBPtr->MemPtr->StdHeader)); + + // + // Initial value for MaxRdLat used in training + // + N = 0x55; + + if (MaxRcvEnDly != 0xFFFF) { + // 1. P = N = T = 0. + P = N = T = 0; + + // Get all sync components BKDG steps 3,4,6 + P = MemNTotalSyncComponentsKB (NBPtr); + + // 5. P = P + 6 + P += 6; + + // 8. P = P + CEIL(MAX(D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] + + // D18F2x9C_x0000_0[3:0]0[6:5]_dct[1:0][RdDqsTime] PCLKs)) + 1 + P = P + (MaxRcvEnDly + 31) / 32 + 1; + + // 9. If (NclkFreq/MemClkFreq < 2) then P = P + 4.5 Else P = P + 2.5 + if ((NBPtr->NBClkFreq / NBPtr->DCTPtr->Timings.Speed) < 2) { + Px2 = P * 2 + 9; + } else { + Px2 = P * 2 + 5; + } + + // 10. T = T + 1050 ps + T += 1050; + + // 11. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs. + MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed; + N = ((((Px2 * MemClkPeriod + 3) / 4) + T) * NBPtr->NBClkFreq + 999999) / 1000000; + + // 12. D18F2x210_dct[1:0]_nbp[3:0][MaxRdLatency] = CEIL(N) + 1 + N = N + 1; + } + + NBPtr->DCTPtr->Timings.MaxRdLat = (UINT16) N; + IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRdLat: %03x\n", N); + MemNSetBitFieldNb (NBPtr, BFMaxLatency, N); +} + +/*----------------------------------------------------------------------------- + * + * + * This function set MaxRdLat after HW receiver enable training is completed + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return TRUE + * ---------------------------------------------------------------------------- + */ +BOOLEAN +MemNExitPhyAssistedTrainingKB ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN OUT VOID *OptParam + ) +{ + UINT8 Dct; + UINT8 ChipSel; + MEM_TECH_BLOCK *TechPtr; + + TechPtr = NBPtr->TechPtr; + + // Calculate Max Latency for both channels to prepare for position training + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB ; Dct++) { + IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); + NBPtr->SwitchDCT (NBPtr, Dct); + + // Reset DisAutoRefresh and ZqcsInterval for position training. + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1); + MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0); + MemNSetBitFieldNb (NBPtr, BFRxDqInsDly, 0); + } + + if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) { + NBPtr->SetMaxLatency (NBPtr, TechPtr->MaxDlyForMaxRdLat); + } + } + + return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); +} + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function gets the total of sync components for Max Read Latency calculation + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * @return Total in PCLKs + */ +UINT32 +STATIC +MemNTotalSyncComponentsKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT32 P; + + P = 0; + + // 3. If (D18F2x9C_x0000_0004_dct[1:0][AddrCmdSetup] = 0 & D18F2x9C_x0000_0004_dct[1:0][CsOdt- + // Setup] = 0 & D18F2x9C_x0000_0004_dct[1:0][CkeSetup] = 0) + // then P = P + 1 + // else P = P + 2 + if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) { + P += 1; + } else { + P += 2; + } + + // 4. P = P + (8 - D18F2x210_dct[1:0]_nbp[3:0][RdPtrInit]) + P = P + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit)); + + // 7. P = P + (2 * (D18F2x200_dct[1:0][Tcl] - 1 clocks)) + P = P + (2 * (MemNGetBitFieldNb (NBPtr, BFTcl) - 1)); + + return P; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function obtains the memory frequency in the current context + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ +UINT16 +MemNGetMemClkFreqInCurrentContextKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 Dct; + UINT16 MemClkSpeed; + + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + break; + } + } + + if (MemNGetBitFieldNb (NBPtr, MemPstateBF[MemNGetBitFieldNb (NBPtr, BFNbPsSel)]) == 0) { + MemClkSpeed = NBPtr->DCTPtr->Timings.Speed; + } else { + MemClkSpeed = MemNGetMemClkFreqUnb (NBPtr, (UINT8) MemNGetBitFieldNb (NBPtr, BFM1MemClkFreq)); + } + IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMemclk Freq: %d\n", MemClkSpeed); + + return MemClkSpeed; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function calculates and programs NB P-state dependent registers + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ + +VOID +MemNProgramNbPstateDependentRegistersKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 RdPtrInit; + UINT8 Dct; + UINT8 *DimmsPerChPtr; + UINT8 MaxSolderedDownDimmPerCh; + UINT32 MemClkSpeed; + + MemClkSpeed = NBPtr->GetMemClkFreqInCurrentContext (NBPtr); + + // IF (((NBCOF >= DdrRate) == FALSE) THEN + // RdPtrInit = 0010b + // ELSE IF (((NBCOF >= DdrRate) == TRUE) && (DdrRate == 667 || DdrRate == 800 || DdrRate == 1600))THEN + // RdPtrInit = 0110b + // ELSE IF (((NBCOF >= DdrRate) == TRUE) && (DdrRate == 1866 || DdrRate ==2133))THEN + // RdPtrInit = 0101b + // ELSE IF (((NBCOF >= DdrRate) == TRUE) && (DdrRate == 2400))THEN + // RdPtrInit = 0100b + // ENDIF + if (NBPtr->NBClkFreq < (UINT32) (MemClkSpeed * 2)) { + RdPtrInit = 2; + } else { + RdPtrInit = (MemClkSpeed < DDR1600_FREQUENCY) ? 6 : ((MemClkSpeed < DDR2400_FREQUENCY) ? 5 : 4); + } + MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit); + IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit); + + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + // Set ProcOdtAdv + // BIOS:IF(Solder-down DRAM || SODIMM) && DdrRate <= 1333) THEN 0 ELSE 1 ENDIF. + MaxSolderedDownDimmPerCh = GetMaxSolderedDownDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, + NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID); + DimmsPerChPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, + PSO_SOLDERED_DOWN_SODIMM_TYPE, + NBPtr->MCTPtr->SocketId, + NBPtr->ChannelPtr->ChannelID, + 0, NULL, NULL); + if (((DimmsPerChPtr != NULL) || (MaxSolderedDownDimmPerCh != 0) || (NBPtr->ChannelPtr->SODimmPresent != 0)) && + (NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY)) { + MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0); + } else { + MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000); + } + MemNSetBitFieldNb (NBPtr, BFDataTxFifoWrDly, 0); + if (NBPtr->DCTPtr->Timings.Speed >= DDR1600_FREQUENCY) { + MemNSetBitFieldNb (NBPtr, BFReducedLoop, (2 << 13)); + } + } + } + + IDS_OPTION_HOOK (IDS_NBPS_REG_OVERRIDE, NBPtr, &NBPtr->MemPtr->StdHeader); + MemFInitTableDrive (NBPtr, MTAfterNbPstateChange); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This is a general purpose function that executes before DRAM init + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ + +VOID +MemNBeforeDramInitKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + // c. Program DCT training specific configuration. + MemNConfigureDctTrainingKB (NBPtr); + // d. Program the remaining DCT registers not covered by an explicit sequence dependency. + MemNProgramNonSeqDependentRegistersKB (NBPtr); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function programs the memory controller for training + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ + +VOID +MemNConfigureDctTrainingKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 Dct; + + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + // + // 2.10.6.7 DCT Training Specific Configuration + // + MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 0); + MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1); + MemNSetBitFieldNb (NBPtr, BFForceAutoPchg, 0); + MemNSetBitFieldNb (NBPtr, BFDynPageCloseEn, 0); + MemNSetBitFieldNb (NBPtr, BFBankSwizzleMode, 0); + MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0); + MemNSetBitFieldNb (NBPtr, BFPowerDownEn, 0); + MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0); + MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 0); + MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 0); + MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, 0); + MemNSetBitFieldNb (NBPtr, BFBankSwap, 0); + MemNSetBitFieldNb (NBPtr, BFODTSEn, 0); + MemNSetBitFieldNb (NBPtr, BFCmdThrottleMode, 0); + MemNSetBitFieldNb (NBPtr, BFBwCapEn, 0); + MemNSetBitFieldNb (NBPtr, BFDramScrub, 0); + MemNSetBitFieldNb (NBPtr, BFScrubReDirEn, 0); + } + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function programs the remaining DCT registers not covered by + * an explicit sequence dependency. + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ + +VOID +MemNProgramNonSeqDependentRegistersKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 Dct; + + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + MemNSetBitFieldNb (NBPtr, BFDllCSRBiasTrim, 0x1000); + + IEM_INSERT_CODE (IEM_BEFORE_DRAM_INIT, IemBeforeDramInitOverrideKB, (NBPtr)); + } + } +} + + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function programs the memory controller for normal operation + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ + +VOID +MemNConfigureDctNormalKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 Dct; + BOOLEAN DllShutDownEn; + + DllShutDownEn = TRUE; + IDS_OPTION_HOOK (IDS_DLL_SHUT_DOWN, &DllShutDownEn, &(NBPtr->MemPtr->StdHeader)); + + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + // + // 2.10.6.7 DCT Training Specific Configuration + // + MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 1); + MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 0); + if (DllShutDownEn && NBPtr->IsSupported[SetDllShutDown]) { + MemNSetBitFieldNb (NBPtr, BFDisDllShutdownSR, 0); + } + MemNSetBitFieldNb (NBPtr , BFForceAutoPchg, 0); + MemNSetBitFieldNb (NBPtr , BFDynPageCloseEn, 0); + if (NBPtr->RefPtr->EnableBankSwizzle) { + MemNSetBitFieldNb (NBPtr, BFBankSwizzleMode, 1); + } + MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0x01F); + MemNPowerDownCtlKB (NBPtr); + MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 2); + MemNSetBitFieldNb (NBPtr, BFBankSwap, 1); + // + // Post Training values for BFRxMaxDurDllNoLock, BFTxMaxDurDllNoLock, + // and BFEnRxPadStandby are handled by Power savings code + // + // BFBwCapEn and BFODTSEn are handled by OnDimmThermal Code + // + } + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function modifies CS interleaving low address according to several conditions for KB. + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in,out] *LowBit - Pointer to low bit + * + */ + +BOOLEAN +MemNCSIntLvLowAddrAdjKB ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN OUT VOID *LowBit + ) +{ + UINT8 DctSelBankSwap; + + DctSelBankSwap = (UINT8) MemNGetBitFieldNb (NBPtr, BFDctSelBankSwap); + // + //D18F2x[5C:40]_dct[1:0][15:5] = BaseAddr[21:11] && + //D18F2x[6C:60]_dct[1:0][15:5] = AddrMask[21:11], so *LowBit needs to be added with 2. + // + *(UINT8 *) LowBit += 2; + + if (MemNGetBitFieldNb (NBPtr, BFBankSwap) == 1) { + if (DctSelBankSwap == 1) { + *(UINT8 *) LowBit = 5; + } else { + *(UINT8 *) LowBit = 6; + } + } + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function releases the NB P-state force. + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return TRUE + */ +BOOLEAN +MemNReleaseNbPstateKB ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN OUT VOID *OptParam + ) +{ + CPU_SPECIFIC_SERVICES *FamilySpecificServices; + GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &NBPtr->MemPtr->StdHeader); + + // 6. Restore the initial D18F5x170[SwNbPstateLoDis, NbPstateDisOnP0] values. + MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFF9FFF) | (NBPtr->NbPsCtlReg & 0x6000)); + // 7. Restore the initial D18F5x170[NbPstateThreshold, NbPstateHi] values. + MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFFF13F) | (NBPtr->NbPsCtlReg & 0x0EC0)); + // 8. Restore the initial D18F5x170[NbPstateLo] values. + MemNSetBitFieldNb (NBPtr, BFNbPstateLo, (NBPtr->NbPsCtlReg >> 3) & 3); + + // Clear NbPsSel to 0 + MemNSetBitFieldNb (NBPtr, BFNbPsSel, 0); + // Update TSC rate + FamilySpecificServices->GetTscRate (FamilySpecificServices, &NBPtr->MemPtr->TscRate, &NBPtr->MemPtr->StdHeader); + + if (MemNGetBitFieldNb (NBPtr, BFMemPsSel) != 0) { + MemNChangeMemPStateContextNb (NBPtr, 0); + } + + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function handles multiple stage of training when multiple Mem Pstate is enabled + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return TRUE + * + */ + +BOOLEAN +MemNMemPstateStageChangeKB ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN OUT VOID *OptParam + ) +{ + BOOLEAN RetVal; + TRN_DLY_TYPE AccessType; + UINT8 Dct; + UINT8 ChipSel; + UINT8 ByteLane; + UINT16 CsEnabled; + UINT16 TrnDly; + UINT8 Tcl; + + RetVal = FALSE; + + if (NBPtr->MemPstateStage == MEMORY_PSTATE_1ST_STAGE) { + MemNChangeMemPStateContextNb (NBPtr, 1); + // Load memory registers in M1 context from data saved in the heap + IDS_HDT_CONSOLE (MEM_FLOW, "\nLoad Training registers for M1 with DDR667 training result\n"); + for (Dct = 0; Dct < MAX_DCTS_PER_NODE_KB; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + // Save MemPstate 1 data in output data structures + LibAmdMemCopy (NBPtr->ChannelPtr->RcvEnDlysMemPs1, NBPtr->ChannelPtr->RcvEnDlys, (MAX_DIMMS * MAX_DELAYS) * 2, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->RdDqsDlysMemPs1, NBPtr->ChannelPtr->RdDqsDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->WrDqsDlysMemPs1, NBPtr->ChannelPtr->WrDqsDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->WrDatDlysMemPs1, NBPtr->ChannelPtr->WrDatDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->RdDqs2dDlysMemPs1, NBPtr->ChannelPtr->RdDqs2dDlys, MAX_DIMMS * MAX_NUMBER_LANES, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->RdDqsMinDlysMemPs1, NBPtr->ChannelPtr->RdDqsMinDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->RdDqsMaxDlysMemPs1, NBPtr->ChannelPtr->RdDqsMaxDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->WrDatMinDlysMemPs1, NBPtr->ChannelPtr->WrDatMinDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->WrDatMaxDlysMemPs1, NBPtr->ChannelPtr->WrDatMaxDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + LibAmdMemCopy (NBPtr->ChannelPtr->FailingBitMaskMemPs1, NBPtr->ChannelPtr->FailingBitMask, MAX_CS_PER_CHANNEL * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); + + CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled; + // Set Memory Pstate 1 training value into registers + for (AccessType = AccessRcvEnDly; AccessType <= AccessWrDqsDly; AccessType ++) { + for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL_KB; ChipSel = ChipSel + NBPtr->CsPerDelay) { + if ((CsEnabled & ((UINT16) ((NBPtr->CsPerDelay == 2)? 3 : 1) << ChipSel)) != 0) { + for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) { + TrnDly = (UINT16) GetTrainDlyFromHeapNb (NBPtr, AccessType, DIMM_BYTE_ACCESS (ChipSel / NBPtr->CsPerDelay, ByteLane)); + NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (ChipSel / NBPtr->CsPerDelay, ByteLane), TrnDly); + } + } + } + } + + if (NBPtr->RefPtr->EnablePowerDown) { + MemNSetTxpNb (NBPtr); + // + // BFPchgPDEnDelay = + // IF (D18F2xA8_dct[0][AggrPDEn]) THEN + // (D18F2x200_dct[0]_mp[1:0][Tcl] + 5 + + // CEIL((MAX(D18F2x9C_x0000_00[2A:10]_dct[0]_mp[1:0][DqsRcvEnGrossDelay]) + // + 0.5) / 2)) ELSE 00h ENDIF. + // + if (MemNGetBitFieldNb (NBPtr, BFAggrPDEn) == 1) { + Tcl = NBPtr->DCTPtr->Timings.CasL; + MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, Tcl + 5 + NBPtr->TechPtr->GetMinMaxGrossDly (NBPtr->TechPtr, AccessRcvEnDly, TRUE) / 2 + 1); + } else { + MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, 0); + } + MemNSetBitFieldNb (NBPtr, BFAggrPDDelay, 0x20); + } + MemNSetOtherTimingKB (NBPtr); + // Save timing data structure for memory Pstate 1 + LibAmdMemCopy (NBPtr->DCTPtr->TimingsMemPs1, &(NBPtr->DCTPtr->Timings), sizeof (CH_TIMING_STRUCT), &(NBPtr->MemPtr->StdHeader)); + + MemFInitTableDrive (NBPtr, MTAfterMemPstate1PartialTrn); + } + } + + // Switch back to M0 context + MemNChangeMemPStateContextNb (NBPtr, 0); + + // Load memory registers in M1 context from data saved in the heap + IDS_HDT_CONSOLE (MEM_FLOW, "\nGoing into training stage 2. Complete training at DDR667 is done.\n"); + NBPtr->MemPstateStage = MEMORY_PSTATE_2ND_STAGE; + } else if ((NBPtr->MemPstateStage == MEMORY_PSTATE_2ND_STAGE) && (NBPtr->DCTPtr->Timings.TargetSpeed == NBPtr->DCTPtr->Timings.Speed)) { + IDS_HDT_CONSOLE (MEM_FLOW, "\nGoing into training stage 3. Partial training at all frequencies is done.\n"); + NBPtr->MemPstateStage = MEMORY_PSTATE_3RD_STAGE; + RetVal = TRUE; + } else { + // MemPstate is disabled. Do not go through the MemPstate handling flow. + RetVal = TRUE; + } + + return RetVal; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function Sets Power Down options and enables Power Down + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + * The following registers are set: + * BFPowerDownMode BFPrtlChPDEnhEn + * BFTxp BFAggrPDDelay + * BFTxpDll BFAggrPDEn + * BFPchgPDEnDelay BFPowerDownEn + * + * NOTE: Delay values must be set before turning on the associated Enable bit + */ +VOID +MemNPowerDownCtlKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + UINT8 PowerDownMode; + CONST UINT32 PwrMngm1[] = {0, 0, 0x05050403, 0x05050403, 0x06060403, 0x07070504, 0x08080504, 0x0A0A0605, 0x0B0B0706}; + UINT8 i; + UINT16 Speed; + UINT8 Tcl; + + if (NBPtr->RefPtr->EnablePowerDown) { + // + // PowerDownMode + // + PowerDownMode = (UINT8) UserOptions.CfgPowerDownMode; + PowerDownMode = (!NBPtr->IsSupported[ChannelPDMode]) ? PowerDownMode : 0; + IDS_OPTION_HOOK (IDS_POWERDOWN_MODE, &PowerDownMode, &(NBPtr->MemPtr->StdHeader)); + if (PowerDownMode == 1) { + MemNSetBitFieldNb (NBPtr, BFPowerDownMode, 1); + } + // + // Txp + // + MemNSetTxpNb (NBPtr); + // + // PchgPDModeSel is set elswhere. + // + // Partial Channel Power Down + // + MemNSetBitFieldNb (NBPtr, BFPrtlChPDDynDly, 4); + MemNSetBitFieldNb (NBPtr, BFPrtlChPDEnhEn, 0); + // + // Aggressive PowerDown + // + MemNSetBitFieldNb (NBPtr, BFAggrPDDelay, 0x20); + MemNSetBitFieldNb (NBPtr, BFAggrPDEn, 1); + // + // BFPchgPDEnDelay = + // IF (D18F2xA8_dct[0][AggrPDEn]) THEN + // (D18F2x200_dct[0]_mp[1:0][Tcl] + 5 + + // CEIL((MAX(D18F2x9C_x0000_00[2A:10]_dct[0]_mp[1:0][DqsRcvEnGrossDelay]) + // + 0.5) / 2)) ELSE 00h ENDIF. + // + if (MemNGetBitFieldNb (NBPtr, BFAggrPDEn) == 1) { + Tcl = NBPtr->DCTPtr->Timings.CasL; + MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, Tcl + 5 + NBPtr->TechPtr->GetMinMaxGrossDly (NBPtr->TechPtr, AccessRcvEnDly, TRUE) / 2 + 1); + } else { + MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, 0); + } + + // Program DRAM Power Management 1 register + Speed = NBPtr->DCTPtr->Timings.Speed; + i = (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133)); + ASSERT ((i > 1) && (i < sizeof (PwrMngm1))); + MemNSetBitFieldNb (NBPtr, BFDramPwrMngm1Reg, PwrMngm1[i]); + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * Always set upper 2 bits of CKETri bitfield + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ +VOID +MemNBeforePlatformSpecKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + MemNSetBitFieldNb (NBPtr, BFCSMapCKE, 0x08040201); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function programs MaxRdLatency based on the seeded value of RxEnDly + * prior to DQS Receiver Enable Training + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return TRUE + * + */ + +BOOLEAN +MemNSetMaxRdLatBasedOnSeededRxEnDlyKB ( + IN OUT MEM_NB_BLOCK *NBPtr, + IN OUT VOID *OptParam + ) +{ + MEM_TECH_BLOCK *TechPtr; + UINT8 ChipSel; + + TechPtr = NBPtr->TechPtr; + + if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) { + NBPtr->SetMaxLatency (NBPtr, TechPtr->MaxDlyForMaxRdLat); + } + + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * + * This function uses calculated values from DCT.Timings structure to + * program its registers for KB + * + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * + */ + +VOID +MemNProgramCycTimingsKB ( + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + CONST CTENTRY TmgAdjTab[] = { + // BitField, Min, Max, Bias, Ratio_x2 + {BFTcl, 5, 14, 0, 2}, + {BFTrcd, 2, 19, 0, 2}, + {BFTrp, 2, 19, 0, 2}, + {BFTrtp, 4, 10, 0, 2}, + {BFTras, 8, 40, 0, 2}, + {BFTrc, 10, 56, 0, 2}, + {BFTwrDDR3, 5, 16, 0, 2}, + {BFTrrd, 4, 9, 0, 2}, + {BFTwtr, 4, 9, 0, 2}, + {BFFourActWindow, 6, 42, 0, 2} + }; + + DCT_STRUCT *DCTPtr; + UINT8 *MiniMaxTmg; + UINT8 *MiniMaxTrfc; + UINT8 Value8; + UINT8 ValFAW; + UINT8 ValTrrd; + UINT8 j; + UINT8 Tcwl; + UINT8 RdOdtTrnOnDly; + BIT_FIELD_NAME BitField; + MEM_PARAMETER_STRUCT *RefPtr; + + DCTPtr = NBPtr->DCTPtr; + RefPtr = NBPtr->RefPtr; + + ValFAW = 0; + ValTrrd = 0; + + //====================================================================== + // Program DRAM Timing values + //====================================================================== + // + MiniMaxTmg = &DCTPtr->Timings.CasL; + for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) { + BitField = TmgAdjTab[j].BitField; + + if (BitField == BFTrp) { + if (NBPtr->IsSupported[AdjustTrp]) { + MiniMaxTmg[j] ++; + if (MiniMaxTmg[j] < 5) { + MiniMaxTmg[j] = 5; + } + } + } + + if (MiniMaxTmg[j] < TmgAdjTab[j].Min) { + MiniMaxTmg[j] = TmgAdjTab[j].Min; + } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) { + MiniMaxTmg[j] = TmgAdjTab[j].Max; + } + + Value8 = (UINT8) MiniMaxTmg[j]; + + if (BitField == BFTwrDDR3) { + if ((Value8 > 8) && ((Value8 & 1) != 0)) { + Value8++; + } + } else if (BitField == BFTrrd) { + ValTrrd = Value8; + } else if (BitField == BFFourActWindow) { + ValFAW = Value8; + } + + MemNSetBitFieldNb (NBPtr, BitField, Value8); + } + + MiniMaxTrfc = &DCTPtr->Timings.Trfc0; + for (j = 0; j < 4; j++) { + if ((NBPtr->DCTPtr->Timings.DctDimmValid & (1 << j)) != 0) { + ASSERT (MiniMaxTrfc[j] <= 4); + MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]); + } + } + + Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2; + Tcwl = (Tcwl > 5) ? Tcwl : 5; + MemNSetBitFieldNb (NBPtr, BFTcwl, Tcwl); + + if (RefPtr->DramDoubleRefreshRate) { + MemNSetBitFieldNb (NBPtr, BFTref, 3); // 3.9 us + } else { + MemNSetBitFieldNb (NBPtr, BFTref, 2); // 7.8 us + } + + RdOdtTrnOnDly = (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0; + MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, RdOdtTrnOnDly); + NBPtr->FamilySpecificHook[ProgOdtControl] (NBPtr, NULL); + + // + // Program Tstag + // + if (NBPtr->MemPstate == 0) { + for (j = 0; j < 4; j++) { + MemNSetBitFieldNb (NBPtr, BFTstag0 + j, MAX (ValTrrd, (ValFAW + 3) / 4)); + } + } + + // + // Program Tmod + // + MemNSetBitFieldNb (NBPtr, BFTmod, (DCTPtr->Timings.Speed < DDR1866_FREQUENCY) ? 0x0C : + (DCTPtr->Timings.Speed > DDR1866_FREQUENCY) ? 0x10 : 0x0E); + // + // Program Tzqcs and Tzqoper + // + // Tzqcs max(64nCK, 80ns) + MemNSetBitFieldNb (NBPtr, BFTzqcs, MIN (6, (MAX (64, MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 80)) + 15) / 16)); + // Tzqoper max(256nCK, 320ns) + MemNSetBitFieldNb (NBPtr, BFTzqoper, MIN (0xC, (MAX (256, MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 320)) + 31) / 32)); + + // Program power management timing + MemNDramPowerMngTimingNb (NBPtr); +} |