blob: 6ce925694c9b6f539ab916aaf18a294522284a65 [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* mtsdi3.c
*
* Technology Software DRAM Init for DDR3
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: (Mem/Tech/DDR3)
* @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 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 "Ids.h"
#include "mm.h"
#include "mn.h"
#include "mu.h"
#include "mt.h"
#include "mt3.h"
#include "mtsdi3.h"
#include "mtrci3.h"
#include "merrhdl.h"
#include "Filecode.h"
CODE_GROUP (G1_PEICC)
RDATA_GROUP (G2_PEI)
#define FILECODE PROC_MEM_TECH_DDR3_MTSDI3_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* EXPORTED FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/* -----------------------------------------------------------------------------*/
/**
*
* This function initiates software DRAM init for both DCTs
* at the same time.
*
* @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
*
*/
BOOLEAN
MemTDramInitSw3 (
IN OUT MEM_TECH_BLOCK *TechPtr
)
{
UINT8 Dct;
UINT8 ChipSel;
MEM_DATA_STRUCT *MemPtr;
DIE_STRUCT *MCTPtr;
MEM_NB_BLOCK *NBPtr;
NBPtr = TechPtr->NBPtr;
MemPtr = NBPtr->MemPtr;
MCTPtr = NBPtr->MCTPtr;
IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Dram Init\n");
// 3.Program F2x[1,0]7C[EnDramInit]=1
IDS_HDT_CONSOLE (MEM_FLOW, "\tEnDramInit = 1 for both DCTs\n");
NBPtr->BrdcstSet (NBPtr, BFEnDramInit, 1);
NBPtr->PollBitField (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, TRUE);
// 4.wait 200us
MemUWait10ns (20000, MemPtr);
// 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1.
NBPtr->BrdcstSet (NBPtr, BFDeassertMemRstX, 1);
// 6.wait 500us
MemUWait10ns (50000, MemPtr);
// Do Phy Fence training before sending MRS commands
if (!NBPtr->IsSupported[FenceTrnBeforeDramInit]) {
AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
NBPtr->SwitchDCT (NBPtr, Dct);
if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
NBPtr->PhyFenceTraining (NBPtr);
}
}
}
// 7.NOP or deselect & take CKE high
NBPtr->BrdcstSet (NBPtr, BFAssertCke, 1);
// 8.wait 360ns
MemUWait10ns (36, MemPtr);
// The following steps are performed once for each channel with unbuffered DIMMs
// and once for each chip select on registered DIMMs:
for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
NBPtr->SwitchDCT (NBPtr, Dct);
if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
// Enable Dram Parity if appropriate.
NBPtr->FamilySpecificHook[EnableParityAfterMemRst] (NBPtr, NULL);
// The following steps are performed with registered DIMMs only and
// must be done for each chip select pair:
if (MCTPtr->Status[SbRegistered]) {
MemTDramControlRegInit3 (TechPtr);
}
// Initialize LRDIMM's register
TechPtr->TechnologySpecificHook[LrdimmControlRegInit] (TechPtr, NULL);
for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel);
// if chip select present
if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) {
MemTSendAllMRCmds3 (TechPtr, ChipSel);
}
// NOTE: wait 512 clocks for DLL-relock
MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
if (!(MCTPtr->Status[SbRegistered] || MCTPtr->Status[SbLrdimms])) {
break;
}
}
}
// 17.Send two ZQCL commands (to even then odd chip select)
NBPtr->sendZQCmd (NBPtr);
NBPtr->sendZQCmd (NBPtr);
}
}
// 18.Program F2x[1,0]7C[EnDramInit]=0
NBPtr->BrdcstSet (NBPtr, BFEnDramInit, 0);
NBPtr->PollBitField (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, TRUE);
//
// For Unbuffered Dimms, Issue MRS for remaining CS without EnDramInit
//
NBPtr->FamilySpecificHook[SendMrsCmdsPerCs] (NBPtr, NBPtr);
IDS_HDT_CONSOLE (MEM_FLOW, "End Dram Init\n\n");
return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
}
/* -----------------------------------------------------------------------------*/
/**
*
* This function calculates the EMRS1 value
*
* @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
* @param[in] Wl - Indicates if WL mode should be enabled
* @param[in] TargetDIMM - DIMM target for WL
*/
VOID
MemTEMRS13 (
IN OUT MEM_TECH_BLOCK *TechPtr,
IN BOOLEAN Wl,
IN UINT8 TargetDIMM
)
{
UINT16 MrsAddress;
UINT8 MaxDimmPerCH;
UINT8 ChipSel;
UINT8 Value8;
MEM_NB_BLOCK *NBPtr;
NBPtr = TechPtr->NBPtr;
MaxDimmPerCH = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
NBPtr->MCTPtr->SocketId,
NBPtr->ChannelPtr->ChannelID);
ChipSel = (UINT8) (0x0FF & NBPtr->GetBitField (NBPtr, BFMrsChipSel));
// BA2=0,BA1=0,BA0=1
NBPtr->SetBitField (NBPtr, BFMrsBank, 1);
MrsAddress = 0;
// program MrsAddress[5,1]=output driver impedance control (DIC):
// based on F2x[1,0]84[DrvImpCtrl]
if (!(NBPtr->IsSupported[CheckDrvImpCtrl])) {
Value8 = (UINT8)NBPtr->GetBitField (NBPtr, BFDrvImpCtrl);
if ((Value8 & ((UINT8) 1 << 1)) != 0) {
MrsAddress |= ((UINT16) 1 << 5);
}
if ((Value8 & ((UINT8) 1 << 0)) != 0) {
MrsAddress |= ((UINT16) 1 << 1);
}
} else {
MrsAddress |= ((UINT16) 1 << 1);
}
// program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
// Different CS may have different RTT.
//
Value8 = NBPtr->MemNGetDramTerm (NBPtr, ChipSel);
//
// If Write Leveling this DIMM
//
if (Wl) {
if ((ChipSel >> 1) == TargetDIMM) {
// Program MrsAddress[7] = 1 for Write leveling enable
MrsAddress |= ((UINT16) 1 << 7);
if (ChipSel & 1) {
// Output buffer disabled, MrsAddress[7] (Qoff = 1)
MrsAddress |= ((UINT16) 1 << 12);
}
// Set Rtt_Nom = Rtt_Wr if there are 2 or more dimms
if ((NBPtr->ChannelPtr->DimmQrPresent != 0) || (NBPtr->ChannelPtr->Dimms >= 2)) {
Value8 = NBPtr->MemNGetDynDramTerm (NBPtr, ChipSel);
} else if (NBPtr->IsSupported[WlRttNomFor1of3Cfg] && (MaxDimmPerCH == 3)) {
// For some family, set Rtt_Nom = Rtt_Wr in one of three DIMMs per channel configurations
Value8 = NBPtr->MemNGetDynDramTerm (NBPtr, ChipSel);
}
}
}
//
// Turn off Rtt_Nom (DramTerm=0) for certain CS in certain configs.
//
// All odd CS for 4 Dimm Systems
if (MaxDimmPerCH == 4) {
if (ChipSel & 0x01) {
Value8 = 0;
}
// CS 1 and 5 for 3 Dimm configs
} else if (MaxDimmPerCH == 3) {
if ((ChipSel == 1) || (ChipSel == 5)) {
Value8 = 0;
}
}
// All odd CS of any QR Dimms
if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT8) (1 << (ChipSel >> 1)))) != 0) {
if (ChipSel & 0x01) {
Value8 = 0;
}
}
if ((Value8 & ((UINT8) 1 << 2)) != 0) {
MrsAddress |= ((UINT16) 1 << 9);
}
if ((Value8 & ((UINT8) 1 << 1)) != 0) {
MrsAddress |= ((UINT16) 1 << 6);
}
if ((Value8 & ((UINT8) 1 << 0)) != 0) {
MrsAddress |= ((UINT16) 1 << 2);
}
// program MrsAddress[12]=output disable (QOFF):
// based on F2x[1,0]84[Qoff]
if (!NBPtr->IsSupported[CheckQoff]) {
if (NBPtr->GetBitField (NBPtr, BFQoff) != 0) {
MrsAddress |= ((UINT16) 1 << 12);
}
}
// program MrsAddress[11]=TDQS:
// based on F2x[1,0]94[RDqsEn]
if ((NBPtr->DCTPtr->Timings.Dimmx4Present != 0) && (NBPtr->DCTPtr->Timings.Dimmx8Present != 0)) {
if (!(NBPtr->IsSupported[SetTDqsForx8DimmOnly]) || ((NBPtr->DCTPtr->Timings.Dimmx8Present & ((UINT8) 1 << (ChipSel >> 1))) != 0)) {
MrsAddress |= ((UINT16) 1 << 11);
}
}
NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
}
/* -----------------------------------------------------------------------------*/
/**
*
* This function calculates the EMRS2 value
*
* @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
*
*/
VOID
MemTEMRS23 (
IN OUT MEM_TECH_BLOCK *TechPtr
)
{
UINT32 MrsAddress;
UINT8 DramTermDyn;
UINT8 MaxDimmPerCH;
UINT8 ChipSel;
MEM_NB_BLOCK *NBPtr;
NBPtr = TechPtr->NBPtr;
MaxDimmPerCH = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID );
ChipSel = (UINT8) (0x0FF & NBPtr->GetBitField (NBPtr, BFMrsChipSel));
// BA2=0,BA1=1,BA0=0
NBPtr->SetBitField (NBPtr, BFMrsBank, 2);
// program MrsAddress[5:3]=CAS write latency (CWL):
MrsAddress = NBPtr->MemNGetMR2CWL (NBPtr);
// program MrsAddress[6]=auto self refresh method (ASR):
// program MrsAddress[7]=self refresh temperature range (SRT):
MrsAddress |= 1 << 6;
MrsAddress &= ( ~ (1 << 7));
// program MrsAddress[10:9]=dynamic termination during writes (RTT_WR):
DramTermDyn = NBPtr->MemNGetDynDramTerm (NBPtr, ChipSel);
// Special Case for 1 DR Unbuffered Dimm in 3 Dimm/Ch
if (!(NBPtr->MCTPtr->Status[SbRegistered])) {
if (MaxDimmPerCH == 3) {
if (NBPtr->ChannelPtr->Dimms == 1) {
if ((NBPtr->ChannelPtr->DimmDrPresent & ((UINT8) (1 << (ChipSel >> 1)))) != 0) {
DramTermDyn = 1;
}
}
}
}
MrsAddress |= (UINT16) DramTermDyn << 9;
NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
}
/* -----------------------------------------------------------------------------*/
/**
*
* This function calculates the EMRS3 value
*
* @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
*
*/
VOID
MemTEMRS33 (
IN OUT MEM_TECH_BLOCK *TechPtr
)
{
MEM_NB_BLOCK *NBPtr;
NBPtr = TechPtr->NBPtr;
// BA2=0,BA1=1,BA0=1
NBPtr->SetBitField (NBPtr, BFMrsBank, 3);
// program MrsAddress[1:0]=multi purpose register address location
// (MPR Location):based on F2x[1,0]84[MprLoc]
// program MrsAddress[2]=multi purpose register
// (MPR):based on F2x[1,0]84[MprEn]
NBPtr->SetBitField (NBPtr, BFMrsAddress, (NBPtr->GetBitField (NBPtr, BFDramMRSReg) >> 24) & 0x0007);
}
/* -----------------------------------------------------------------------------*/
/**
*
* This sets MRS value
*
* @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
*
*/
VOID
MemTMRS3 (
IN OUT MEM_TECH_BLOCK *TechPtr
)
{
UINT32 MrsAddress;
MEM_NB_BLOCK *NBPtr;
UINT32 Ppd;
NBPtr = TechPtr->NBPtr;
// BA2=0,BA1=0,BA0=0
NBPtr->SetBitField (NBPtr, BFMrsBank, 0);
// program MrsAddress[1:0]=burst length and control method
// (BL):based on F2x[1,0]84[BurstCtrl]
MrsAddress = NBPtr->GetBitField (NBPtr, BFBurstCtrl);
// program MrsAddress[3]=1 (BT):interleaved
MrsAddress |= (UINT16) 1 << 3;
// program MrsAddress[6:4,2]=read CAS latency
MrsAddress |= NBPtr->MemNGetMR0CL (NBPtr);
// program MrsAddress[11:9]=write recovery for auto-precharge
MrsAddress |= NBPtr->MemNGetMR0WR (NBPtr);
// program MrsAddress[12] (PPD):based on F2x[1,0]84[PChgPDModeSel]
Ppd = NBPtr->GetBitField (NBPtr, BFPchgPDModeSel);
NBPtr->FamilySpecificHook[MR0_PPD] (NBPtr, &Ppd);
IDS_OPTION_HOOK (IDS_MEM_MR0, &Ppd, &TechPtr->NBPtr->MemPtr->StdHeader);
MrsAddress |= Ppd << 12;
// program MrsAddress[8]=1 (DLL):DLL reset
MrsAddress |= (UINT32) 1 << 8;
// During memory initialization, the value sent to MR0 is saved for S3 resume
NBPtr->MemNSaveMR0 (NBPtr, MrsAddress);
NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
}
/* -----------------------------------------------------------------------------*/
/**
*
* This send all MR commands to a rank in sequence 2-3-1-0
*
* @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
* @param[in] ChipSel - Target Chip Select
*/
VOID
MemTSendAllMRCmds3 (
IN OUT MEM_TECH_BLOCK *TechPtr,
IN UINT8 ChipSel
)
{
MEM_NB_BLOCK *NBPtr;
NBPtr = TechPtr->NBPtr;
NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
// 13.Send EMRS(2)
MemTEMRS23 (TechPtr);
AGESA_TESTPOINT (TpProcMemSendMRS2, &(NBPtr->MemPtr->StdHeader));
NBPtr->SendMrsCmd (NBPtr);
// 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b
MemTEMRS33 (TechPtr);
AGESA_TESTPOINT (TpProcMemSendMRS3, &(NBPtr->MemPtr->StdHeader));
NBPtr->SendMrsCmd (NBPtr);
// 15.Send EMRS(1).
MemTEMRS13 (TechPtr, FALSE, (ChipSel >> 1));
AGESA_TESTPOINT (TpProcMemSendMRS1, &(NBPtr->MemPtr->StdHeader));
NBPtr->SendMrsCmd (NBPtr);
// 16.Send MRS with MrsAddress[8]=1(reset the DLL)
MemTMRS3 (TechPtr);
AGESA_TESTPOINT (TpProcMemSendMRS0, &(NBPtr->MemPtr->StdHeader));
NBPtr->SendMrsCmd (NBPtr);
}