blob: 5283ecd363197069e6dc0bcfa5b695068d71fc53 [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* mndctOr.c
*
* Northbridge DCT support for Orochi
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: (Mem/NB/OR)
* @e \$Revision: 60556 $ @e \$Date: 2011-10-17 20:19:58 -0600 (Mon, 17 Oct 2011) $
*
**/
/*****************************************************************************
*
* Copyright (C) 2012 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" // need def for MEM_FEAT_BLOCK_NB
#include "mnor.h"
#include "merrhdl.h"
#include "cpuFamRegisters.h"
#include "GeneralServices.h"
#include "cpuFamilyTranslation.h"
#include "cpuCommonF15Utilities.h"
#include "F15PackageType.h"
#include "Filecode.h"
CODE_GROUP (G3_DXE)
RDATA_GROUP (G3_DXE)
#define FILECODE PROC_MEM_NB_OR_MNDCTOR_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
#define UNUSED_CLK 4
#define MAX_RD_DQS_DLY 0x1F
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
UINT32
STATIC
MemNTotalSyncComponentsOr (
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
MemNAutoConfigOr (
IN OUT MEM_NB_BLOCK *NBPtr
)
{
UINT8 i;
UINT8 NumDimmslots;
DIE_STRUCT *MCTPtr;
DCT_STRUCT *DCTPtr;
MEM_PARAMETER_STRUCT *RefPtr;
MEM_PS_BLOCK * PsPtr;
BOOLEAN ExtraAddrBits;
BOOLEAN RankMultEn;
UINT8 ROOD;
RefPtr = NBPtr->RefPtr;
MCTPtr = NBPtr->MCTPtr;
DCTPtr = NBPtr->DCTPtr;
PsPtr = NBPtr->PsPtr;
ExtraAddrBits = FALSE;
RankMultEn = FALSE;
ROOD = DEFAULT_RD_ODT_OR;
//
// Check for Extra Address bit requirement for LRDIMMs
//
if (MCTPtr->Status[SbLrdimms]) {
for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
if (PsPtr->LrdimmRowAddrBits[i] > 16) {
ExtraAddrBits = TRUE;
}
if (NBPtr->ChannelPtr->LrDimmRankMult[i] > 1) {
RankMultEn = TRUE;
}
}
}
NumDimmslots = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration,
MCTPtr->SocketId,
NBPtr->ChannelPtr->ChannelID);
//
//======================================================================
// Build Dram Config Lo Register Value
//======================================================================
//
// Disable Parity Prior to Dram init
//
MemNSetBitFieldNb (NBPtr, BFParEn, 0);
//
// LRDIMMS Extended Parity
//
MemNSetBitFieldNb (NBPtr, BFExtendedParityEn, 0);
//
// X4Dimm
//
MemNSetBitFieldNb (NBPtr, BFX4Dimm, NBPtr->ChannelPtr->DimmNibbleAccess & 0xF);
//
// UnBuffDimm
//
if (!(MCTPtr->Status[SbRegistered] || MCTPtr->Status[SbLrdimms])) {
MemNSetBitFieldNb (NBPtr, BFUnBuffDimm, 1);
}
//
// DimmEccEn
//
if (MCTPtr->Status[SbEccDimms]) {
MemNSetBitFieldNb (NBPtr, BFDimmEccEn, 1);
}
//
// PendRefPayback, StatgRefEn, TStag[0:4]
//
MemNSetBitFieldNb (NBPtr, BFPendRefPaybackS3En, 1);
MemNSetBitFieldNb (NBPtr, BFStagRefEn, 1);
for (i = 0; i < 4; i++) {
MemNSetBitFieldNb (NBPtr, BFTstag0 + i, 0x14);
}
//
//======================================================================
// Build Dram Config Hi Register Value
//======================================================================
//
//
// MemClkFreq
//
MemNSetBitFieldNb (NBPtr, BFMemClkFreq, MemNGetMemClkFreqIdUnb (NBPtr, DCTPtr->Timings.Speed));
//
// FourRankRDimm0 , FourRankRDimm1 ( Reset Values are 0)
//
//======================================================================
// Build Dram MRS Register Value (Not used for MRS command)
//======================================================================
//
// PchgPDModeSel - This is done here so that the value can be used by
// MR0 function
//
if (NBPtr->IsSupported[PchgPDMode]) {
MemNSetBitFieldNb (NBPtr, BFPchgPDModeSel, 1);
}
MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 0);
//======================================================================
// Build Dram Config Misc Register Value
//======================================================================
//
//
// LRDIMMs CSMux45 and CSMux67
//
if (MCTPtr->Status[SbLrdimms]) {
if (NumDimmslots == 3) {
MemNSetBitFieldNb (NBPtr, BFCSMux45, 0);
MemNSetBitFieldNb (NBPtr, BFCSMux67, ExtraAddrBits ? 1 : 0);
} else if (NumDimmslots <= 2) {
MemNSetBitFieldNb (NBPtr, BFCSMux45, (PsPtr->LrdimmRowAddrBits[0] > 16) ? 1 : 0);
MemNSetBitFieldNb (NBPtr, BFCSMux67, (PsPtr->LrdimmRowAddrBits[1] > 16) ? 1 : 0);
}
}
//
// LrDimmMrsCtrl
//
MemNSetBitFieldNb (NBPtr, BFLrDimmMrsCtrl, RankMultEn ? 1 : 0);
//
// BFLrDimmEnhRefEn
//
MemNSetBitFieldNb (NBPtr, BFLrDimmEnhRefEn, RankMultEn ? 1 : 0);
//
// SubMemclkRegDly
//
MemNSetBitFieldNb (NBPtr, BFSubMemclkRegDly, (MCTPtr->Status[SbRegistered] || MCTPtr->Status[SbLrdimms])? 1 : 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);
if (NBPtr->MCTPtr->Status[SbLrdimms]) {
ROOD = ROOD + (UINT8) (MemNCalBufDatDelaySkewOr (NBPtr, GetBufDatDlySkew));
}
MemNSetBitFieldNb (NBPtr, BFWrOdtOnDuration, DEFAULT_WR_ODT_OR);
MemNSetBitFieldNb (NBPtr, BFRdOdtOnDuration, ROOD);
MemNSetBitFieldNb (NBPtr, BFWrOdtTrnOnDly, 0);
MemNSetBitFieldNb (NBPtr, BFTmrd, (NBPtr->MCTPtr->Status[SbLrdimms] ? 6 : 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
MemNCapSpeedBatteryLifeOr (
IN OUT MEM_NB_BLOCK *NBPtr
)
{
CONST UINT16 SupportedFreq[] = {
DDR1866_FREQUENCY,
DDR1600_FREQUENCY,
DDR1333_FREQUENCY,
DDR1066_FREQUENCY,
DDR800_FREQUENCY,
DDR667_FREQUENCY
};
UINT32 FreqNumeratorInMHz;
UINT32 FreqDivisor;
UINT32 VoltageInuV;
UINT32 NBFreq;
UINT16 DdrFreq;
UINT16 j;
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))) {
NBFreq = FreqNumeratorInMHz / FreqDivisor;
break;
}
}
ASSERT (NBFreq > 0);
// Pick Max MEMCLK that is less than or equal to (NCLK / 2)
DdrFreq = DDR800_FREQUENCY;
for (j = 0; j < GET_SIZE_OF (SupportedFreq); j++) {
if (NBFreq >= ((UINT32) 2 * SupportedFreq[j])) {
DdrFreq = SupportedFreq[j];
break;
}
}
// Cap MemClk frequency to lowest NCLK frequency
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
MemNGetMaxLatParamsOr (
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,7
P = MemNTotalSyncComponentsOr (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))
P = P + (MaxRcvEnDly + 31) / 32;
// 10. T = T + 800 ps
T += 800;
// 11. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs.
MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
N = ((((P * MemClkPeriod + 1) / 2) + T) * NBPtr->NBClkFreq + 999999) / 1000000;
// 13. D18F2x210_dct[1:0]_nbp[3:0][MaxRdLatency] = CEIL(N) - 1
N = N - 1;
// Calculate a starting MaxRdLatency delay value with steps 5, 9, and 12 excluded
*MinDlyPtr = (UINT16) N;
*MaxDlyPtr = 0x3FF;
// Left edge of MaxRdLat will be added with 1 NCLK and 3 PCLK
N = 1;
P = 3;
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
MemNSetMaxLatencyOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT16 MaxRcvEnDly
)
{
UINT32 N;
UINT32 T;
UINT32 P;
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,7
P = MemNTotalSyncComponentsOr (NBPtr);
// 5. P = P + 5
P += 5;
// 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))
P = P + ((MaxRcvEnDly + MAX_RD_DQS_DLY) + 31) / 32;
// 9. P = P + 5
P += 5;
// 10. T = T + 800 ps
T += 800;
// 11. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs.
MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
N = ((((P * MemClkPeriod + 1) / 2) + T) * NBPtr->NBClkFreq + 999999) / 1000000;
// 12. N = N - 1. See step 9.
N = N - 1;
// 13. 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
MemNExitPhyAssistedTrainingOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN OUT VOID *OptParam
)
{
UINT8 Dct;
UINT8 ChipSel;
MEM_TECH_BLOCK *TechPtr;
TechPtr = NBPtr->TechPtr;
MemNReEnablePhyCompNb (NBPtr, NULL);
// Calculate Max Latency for both channels to prepare for position training
for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
NBPtr->SwitchDCT (NBPtr, Dct);
//
// For Orochi, we need to reset DisAutoRefresh and ZqcsInterval for
// Position training.
//
if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1);
MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0);
}
if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) {
NBPtr->SetMaxLatency (NBPtr, TechPtr->MaxDlyForMaxRdLat);
}
}
return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
}
/*-----------------------------------------------------------------------------
*
* This function send control words after MEMCLK frequency change
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in,out] OptParam - Optional parameter
*
* @return TRUE
* ----------------------------------------------------------------------------
*/
BOOLEAN
MemNAfterMemClkFreqChgOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN OUT VOID *OptParam
)
{
UINT8 Dct;
MEM_TECH_BLOCK *TechPtr;
TechPtr = NBPtr->TechPtr;
// Reprogram the DIMMs' buffers right after MEMCLK frequency change
if (!(TechPtr->TechnologySpecificHook[LrdimmFreqChgCtrlWrd] (TechPtr, NULL))) {
if (NBPtr->MCTPtr->Status[SbRegistered]) {
for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
MemNSwitchDCTNb (NBPtr, Dct);
if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
TechPtr->FreqChgCtrlWrd (TechPtr);
}
}
}
}
return TRUE;
}
/*-----------------------------------------------------------------------------
*
* This function modifies CS tri-state bit map
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in,out] CsTriBitmap - Bitmap of chipselects to be tristated
*
* @return TRUE
* ----------------------------------------------------------------------------
*/
BOOLEAN
MemNBeforeSetCsTriOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN OUT VOID *CsTriBitmap
)
{
//
// The tri-state of CS[7:4] for LrDIMM should be determined by
// D18F2xA8_dct[1:0][CsMux45]/[CsMux67]
if (NBPtr->MCTPtr->Status[SbLrdimms]) {
if (MemNGetBitFieldNb (NBPtr, BFCSMux45) == 1) {
*(UINT8*) CsTriBitmap &= 0xCF;
}
if (MemNGetBitFieldNb (NBPtr, BFCSMux67) == 1) {
*(UINT8*) CsTriBitmap &= 0x3F;
}
}
return TRUE;
}
/*----------------------------------------------------------------------------
* 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
MemNTotalSyncComponentsOr (
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]) + 1
P = P + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit)) + 1;
// 6. If (D18F2xA8_dct[1:0][SubMemclkRegDly] = 0 & D18F2x90_dct[1:0][UnbuffDimm] = 0)
// then P = P + 2
if ((MemNGetBitFieldNb (NBPtr, BFSubMemclkRegDly) == 0) && (MemNGetBitFieldNb (NBPtr, BFUnBuffDimm) == 0)) {
P += 2;
}
// 7. P = P + (2 * (D18F2x200_dct[1:0][Tcl] - 1 clocks))
P = P + (2 * (MemNGetBitFieldNb (NBPtr, BFTcl) - 1));
return P;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function is used to calculate BufDatDelay and BufDatDelaySkew value.
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in] GetDelay - Get either BufDatDly or BufDatDlySkew value
*
* @return BufDatDly or BufDatDlySkew value
*/
UINT32
MemNCalBufDatDelaySkewOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 GetDelay
)
{
UINT8 SpdOffset;
UINT8 Dimm;
UINT8 i;
UINT8 j;
UINT32 MinModuleDly;
UINT32 MaxModuleDly;
UINT8 SyncDelay;
UINT32 SmallestModuleDly;
UINT32 LargestModuleDly;
UINT32 BufDatDly;
UINT32 BufDatDlySkew;
MEM_TECH_BLOCK *TechPtr;
UINT8 *SpdBufferPtr;
TechPtr = NBPtr->TechPtr;
i = 0;
j = 0;
SmallestModuleDly = 0;
LargestModuleDly = 0;
SyncDelay = 0;
BufDatDly = 0;
BufDatDlySkew = 0;
MinModuleDly = 0xFF;
MaxModuleDly = 0;
SpdOffset = (UINT8) (2 * CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage));
for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
if (TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, Dimm)) {
if ((SpdBufferPtr[90 + SpdOffset] & 0x7F) < (UINT8) MinModuleDly) {
MinModuleDly = SpdBufferPtr[90 + SpdOffset] & 0x7F;
i = Dimm;
}
if ((SpdBufferPtr[91 + SpdOffset] & 0x7F) > (UINT8) MaxModuleDly) {
MaxModuleDly = SpdBufferPtr[91 + SpdOffset] & 0x7F;
j = Dimm;
}
}
}
if (!(MinModuleDly >= 0x3C && MinModuleDly <= 0x58)) {
IDS_HDT_CONSOLE (MEM_FLOW, "\tMinModuleDly out of range (0x3C - 0x58): %02x\n", MinModuleDly);
}
if (!(MaxModuleDly >= 0x3C && MaxModuleDly <= 0x58)) {
IDS_HDT_CONSOLE (MEM_FLOW, "\tMaxModuleDly out of range (0x3C - 0x58): %02x\n", MaxModuleDly);
}
//
//Calculate BufDatDly
//
//SmallestModuleDelay = MinimumModuleDelay * .000125 us * 400 MHz * 0x40.
//MinimumModuleDelay is the minimum SPD module delay across all DIMMs on a channel.
//
SmallestModuleDly = (UINT32) (MinModuleDly * 125 * 400 * 0x40 / 1000000);
//
//SyncDelay = (F0RC2[AddrCmdPrelaunch] ? 0x30 - (2*F1RC12[QCAPrelaunchDelay]) : 0x20) + 0x10.
//SyncDelay is calculated from the SPD values of the MinimumModuleDelay DIMM.
//
TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, i);
SyncDelay = (UINT8) ((((SpdBufferPtr[67] & 0x01) == 1) ? (0x30 - 2 * (SpdBufferPtr[70] & 0x07)) : 0x20) + 0x10);
//
//BufDatDelay = FLOOR((((SmallestModuleDelay - SynchDelay) * (MemClkFreq/400 MHz)) + SynchDelay)/0x40).
//
BufDatDly = (((SmallestModuleDly - SyncDelay) * NBPtr->DCTPtr->Timings.Speed / 400) + SyncDelay) / 0x40;
if (GetDelay == GetBufDatDly) {
return BufDatDly;
}
//
//Calculate BufDatDlySkew
//
//LargestModuleDelay = MaximumModuleDelay * .000125 us * 400 MHz * 0x40.
//MaximumModuleDelay is the maximum SPD module delay across all DIMMs on a channel.
//
LargestModuleDly = (UINT32) (MaxModuleDly * 125 * 400 * 0x40 / 1000000);
//
//SyncDelay = (F0RC2[AddrCmdPrelaunch] ? 0x30 - (2*F1RC12[QCAPrelaunchDelay]) : 0x20) + 0x10.
//SyncDelay is calculated from the SPD values of the MaximumModuleDelay DIMM.
//
TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, j);
SyncDelay = (UINT8) ((((SpdBufferPtr[67] & 0x01) == 1) ? (0x30 - 2 * (SpdBufferPtr[70] & 0x07)) : 0x20) + 0x10);
//
//BufDatDelaySkew = FLOOR((((LargestModuleDelay - SynchDelay) * (MemClkFreq/400 MHz)) + SynchDelay)/0x40) - BufDatDelay.
//
BufDatDlySkew = ((((((LargestModuleDly - SyncDelay) * NBPtr->DCTPtr->Timings.Speed + 200) / 400) + SyncDelay) - (BufDatDly * 0x40) + 0x20) / 0x40);
return BufDatDlySkew ;
}
/*-----------------------------------------------------------------------------
*
* This function Enables parity on both DCTs if Parity is supported.
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in,out] *OptParam - Unused
*
* @return TRUE
* ----------------------------------------------------------------------------
*/
BOOLEAN
MemNEnableParityAfterMemRstOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN OUT VOID *OptParam
)
{
DIE_STRUCT *MCTPtr;
MEM_PS_BLOCK * PsPtr;
UINT8 i;
MCTPtr = NBPtr->MCTPtr;
PsPtr = NBPtr->PsPtr;
if (NBPtr->MCTPtr->Status[SbParDimms]) {
//
// SbParDimms should be set for all DDR3 RDIMMS
// Cannot turn off ParEn for DDR3
//
MemNSetBitFieldNb (NBPtr, BFParEn, 1);
//
// LRDIMMS Extended Parity
//
if (MCTPtr->Status[SbLrdimms]) {
for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
if (PsPtr->LrdimmRowAddrBits[i] > 16) {
MemNSetBitFieldNb (NBPtr, BFExtendedParityEn, 1);
break;
}
}
}
}
return TRUE;
}
/*-----------------------------------------------------------------------------
*
*
* This function calculates RdOdtTrnOnDly and RdOdtOnDuration when LrDimms
* are present
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in,out] *OptParam - Not Used
*
* @return TRUE - always
* ----------------------------------------------------------------------------
*/
BOOLEAN
MemNProgOdtControlOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN OUT VOID *OptParam
)
{
DCT_STRUCT *DCTPtr;
UINT8 Tcwl;
UINT8 RdOdtTrnOnDly;
UINT8 RdOdtOnDuration;
DCTPtr = NBPtr->DCTPtr;
Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
RdOdtTrnOnDly = (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0;
RdOdtOnDuration = 6;
if (NBPtr->MCTPtr->Status[SbLrdimms]) {
RdOdtTrnOnDly = RdOdtTrnOnDly + (UINT8) MemNCalBufDatDelaySkewOr (NBPtr, GetBufDatDly);
RdOdtOnDuration = RdOdtOnDuration + (UINT8) MemNCalBufDatDelaySkewOr (NBPtr, GetBufDatDlySkew);
}
MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, RdOdtTrnOnDly);
MemNSetBitFieldNb (NBPtr, BFRdOdtOnDuration, RdOdtOnDuration);
IDS_HDT_CONSOLE (MEM_FLOW,"\n\t\t\tRdOdtTrnOnDly = %x",RdOdtTrnOnDly);
IDS_HDT_CONSOLE (MEM_FLOW,"\n\t\t\tRdOdtOnDuration = %x\n",RdOdtOnDuration);
return TRUE;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This is a general purpose function that executes before DRAM init
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
*
*/
VOID
MemNBeforeDramInitOr (
IN OUT MEM_NB_BLOCK *NBPtr
)
{
UINT8 Dct;
for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) {
MemNSwitchDCTNb (NBPtr, Dct);
if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
//
// 2.10.6.6 DCT Training Specific Configuration
//
MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 0);
MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1);
MemNSetBitFieldNb (NBPtr, BFDisDllShutdownSR, 1);
MemNSetBitFieldNb (NBPtr, BFForceAutoPchg, 0);
MemNSetBitFieldNb (NBPtr, BFDynPageCloseEn, 0);
MemNSetBitFieldNb (NBPtr, BFBankSwizzleMode, 0);
MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0);
MemNSetBitFieldNb (NBPtr, BFPowerDownEn, 0);
MemNSetBitFieldNb (NBPtr, BFDisSimulRdWr, 0);
MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0);
MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 0);
MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 0);
MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, 0);
MemNSetBitFieldNb (NBPtr, BFBwCapEn, 0);
MemNSetBitFieldNb (NBPtr, BFODTSEn, 0);
MemNSetBitFieldNb (NBPtr, BFDctSelIntLvEn, 0);
MemNSetBitFieldNb (NBPtr, BFL3Scrub, 0);
MemNSetBitFieldNb (NBPtr, BFDramScrub, 0);
MemNSetBitFieldNb (NBPtr, BFScrubReDirEn, 0);
MemNSetBitFieldNb (NBPtr, BFL3ScrbRedirDis, 1);
}
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* 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
MemNReleaseNbPstateOr (
IN OUT MEM_NB_BLOCK *NBPtr,
IN OUT VOID *OptParam
)
{
// 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));
return TRUE;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* 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
MemNPowerDownCtlOr (
IN OUT MEM_NB_BLOCK *NBPtr
)
{
UINT8 PowerDownMode;
UINT8 Tmod;
CONST UINT32 PwrMngm1[] = {0, 0, 0x05050403, 0x05050403, 0x06060403, 0x07070504, 0x08080504, 0x0A0A0605, 0x0B0B0706};
UINT8 i;
UINT16 Speed;
UINT32 PackageType;
if (NBPtr->RefPtr->EnablePowerDown) {
PackageType = LibAmdGetPackageType (&(NBPtr->MemPtr->StdHeader));
//
// 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.
//
Tmod = (UINT8) MemNGetBitFieldNb (NBPtr, BFTmod);
//
// Partial Channel Power Down
//
MemNSetBitFieldNb (NBPtr, BFPrtlChPDDynDly, 2);
MemNSetBitFieldNb (NBPtr, BFPrtlChPDEnhEn, 1);
//
// Aggressive PowerDown
// PchgPDEnDelay: IF (D18F2xA8_dct[1:0][AggrPDEn]) THEN 1 ELSE 0 ENDIF.
//
MemNSetBitFieldNb (NBPtr, BFAggrPDDelay, 0);
if (PackageType != PACKAGE_TYPE_AM3r2) {
MemNSetBitFieldNb (NBPtr, BFAggrPDEn, 1);
MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, 1);
}
// 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]);
}
}