blob: e789fcf065b8522e15ff9bf12448efa16c18b33b [file] [log] [blame]
/**
* @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: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
*
**/
/*****************************************************************************
*
* Copyright (c) 2011, 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"
#define FILECODE PROC_MEM_TECH_DDR3_MTSDI3_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
VOID
STATIC
MemTEMRS33 (
IN OUT MEM_TECH_BLOCK *TechPtr
);
VOID
STATIC
MemTMRS3 (
IN OUT MEM_TECH_BLOCK *TechPtr
);
/*----------------------------------------------------------------------------
* 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;
UINT32 Dummy;
MEM_DATA_STRUCT *MemPtr;
DIE_STRUCT *MCTPtr;
MEM_NB_BLOCK *NBPtr;
NBPtr = TechPtr->NBPtr;
MemPtr = NBPtr->MemPtr;
MCTPtr = NBPtr->MCTPtr;
IDS_HDT_CONSOLE ("!\nStart Dram Init\n");
// 3.Program F2x[1,0]7C[EnDramInit]=1
IDS_HDT_CONSOLE ("\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 ("!\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 ("!\tDct %d\n", Dct);
// The following steps are performed with registered DIMMs only and
// must be done for each chip select pair:
if (MCTPtr->Status[SbRegistered]) {
MemTDramControlRegInit3 (TechPtr);
}
for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
if (NBPtr->GetSysAddr (NBPtr, ChipSel, &Dummy)) {
IDS_HDT_CONSOLE ("!\t\tCS %d\n", ChipSel);
// if chip select present
MemTSendAllMRCmds3 (TechPtr, ChipSel);
// NOTE: wait 512 clocks for DLL-relock
MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
if (!MCTPtr->Status[SbRegistered]) {
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
//
if (!MCTPtr->Status[SbRegistered]) {
for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
NBPtr->SwitchDCT (NBPtr, Dct);
if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
IDS_HDT_CONSOLE ("!\tDct %d\n", Dct);
for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
if (NBPtr->GetSysAddr (NBPtr, ChipSel, &Dummy)) {
IDS_HDT_CONSOLE ("!\t\tCS %d\n", ChipSel);
// if chip select present
MemTSendAllMRCmds3 (TechPtr, ChipSel);
// NOTE: wait 512 clocks for DLL-relock
MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
}
}
}
}
}
IDS_HDT_CONSOLE ("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]
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);
}
// program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
// Different CS may have different RTT.
//
if (NBPtr->MCTPtr->Status[SbRegistered]) {
//
// Registered Dimms
//
if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT16) (1 << (ChipSel >> 1)))) != 0) {
Value8 = NBPtr->PsPtr->QR_DramTerm;
} else {
Value8 = NBPtr->PsPtr->DramTerm;
}
} else {
//
// Unbuffered Dimms
//
Value8 = NBPtr->PsPtr->DramTerm;
}
//
// 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->PsPtr->DynamicDramTerm;
}
}
}
//
// 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->GetBitField (NBPtr, BFQoff) != 0) {
MrsAddress |= ((UINT16) 1 << 12);
}
// program MrsAddress[11]=TDQS:
// based on F2x[1,0]94[RDqsEn]
if (NBPtr->GetBitField (NBPtr, BFRDqsEn) != 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):
// based on F2x[1,0]84[Tcwl]
MrsAddress = NBPtr->GetBitField (NBPtr, BFTcwl) << 3;
// program MrsAddress[6]=auto self refresh method (ASR):
// based on F2x[1,0]84[ASR]
// program MrsAddress[7]=self refresh temperature range (SRT):
// based on F2x[1,0]84[ASR and SRT]
MrsAddress |= NBPtr->GetBitField (NBPtr, BFASR) << 6;
MrsAddress |= NBPtr->GetBitField (NBPtr, BFSRT) << 7;
// program MrsAddress[10:9]=dynamic termination during writes (RTT_WR):
// based on F2x[1,0]84[DramTermDyn]
DramTermDyn = (UINT8) NBPtr->GetBitField (NBPtr, BFDramTermDyn);
// 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
STATIC
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
STATIC
MemTMRS3 (
IN OUT MEM_TECH_BLOCK *TechPtr
)
{
UINT32 MrsAddress;
MEM_NB_BLOCK *NBPtr;
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
// (CL):based on F2x[1,0]88[Tcl]
// -- F2x88[3:0] to MrsAddress[6:4,2]=xxx0b --
MrsAddress |= NBPtr->GetBitField (NBPtr, BFTcl) << 4;
// program MrsAddress[11:9]=write recovery for auto-precharge
// (WR):based on F2x[1,0]84[Twr]
MrsAddress |= NBPtr->GetBitField (NBPtr, BFTwrDDR3) << 9;
// program MrsAddress[12] (PPD):based on F2x[1,0]84[PChgPDModeSel]
MrsAddress |= NBPtr->GetBitField (NBPtr, BFPchgPDModeSel) << 12;
// program MrsAddress[8]=1 (DLL):DLL reset
MrsAddress |= (UINT32) 1 << 8;
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);
NBPtr->SendMrsCmd (NBPtr);
// 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b
MemTEMRS33 (TechPtr);
NBPtr->SendMrsCmd (NBPtr);
// 15.Send EMRS(1).
MemTEMRS13 (TechPtr, FALSE, (ChipSel >> 1));
NBPtr->SendMrsCmd (NBPtr);
// 16.Send MRS with MrsAddress[8]=1(reset the DLL)
MemTMRS3 (TechPtr);
NBPtr->SendMrsCmd (NBPtr);
}