diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f15/Proc/Recovery/Mem/Tech/DDR3/mrttwl3.c')
-rw-r--r-- | src/vendorcode/amd/agesa/f15/Proc/Recovery/Mem/Tech/DDR3/mrttwl3.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f15/Proc/Recovery/Mem/Tech/DDR3/mrttwl3.c b/src/vendorcode/amd/agesa/f15/Proc/Recovery/Mem/Tech/DDR3/mrttwl3.c new file mode 100644 index 0000000000..f2ceb2cbb6 --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/Recovery/Mem/Tech/DDR3/mrttwl3.c @@ -0,0 +1,369 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mrttwl3.c + * + * Technology Phy assisted write levelization for recovery DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Proc/Recovery/Mem) + * @e \$Revision: 50454 $ @e \$Date: 2011-04-10 21:20:37 -0600 (Sun, 10 Apr 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 "OptionMemory.h" +#include "PlatformMemoryConfiguration.h" +#include "Ids.h" +#include "mm.h" +#include "mn.h" +#include "mru.h" +#include "mt.h" +#include "mrt3.h" +#include "Filecode.h" +CODE_GROUP (G2_PEI) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_RECOVERY_MEM_TECH_DDR3_MRTTWL3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ +#define MAX_BYTELANES 8 /* Max Bytelanes per channel */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +VOID +STATIC +MemRecTPrepareDIMMs3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN BOOLEAN Wl + ); + +VOID +STATIC +MemRecTProcConfig3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +VOID +STATIC +MemRecTBeginWLTrain3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function executed hardware based write levelization for a specific die + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +MemRecTTrainDQSWriteHw3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + IDS_HDT_CONSOLE (MEM_STATUS, "\nStart write leveling\n"); + // Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1. + NBPtr->SetBitField (NBPtr, BFDisAutoRefresh, 1); + // Disable ZQ calibration short command by configuring F2x[1, 0]94[ZqcsInterval] = 00b. + NBPtr->SetBitField (NBPtr, BFZqcsInterval, 0); + + // 1. Specify the target Dimm that is to be trained by programming + // F2x[1, 0]9C_x08[TrDimmSel]. + IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", NBPtr->DimmToBeUsed << 1); + NBPtr->SetBitField (NBPtr, BFTrDimmSel, NBPtr->DimmToBeUsed); + + // 2. Prepare the DIMMs for write levelization using DDR3-defined + // MR commands. + MemRecTPrepareDIMMs3 (TechPtr, TRUE); + + // 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to + // satisfy DDR3-defined internal DRAM timing. + MemRecUWait10ns (10, NBPtr->MemPtr); + + // 4. Configure the processor's DDR phy for write levelization training: + MemRecTProcConfig3 (TechPtr); + + // 5. Begin write levelization training + MemRecTBeginWLTrain3 (TechPtr); + + // 6. Configure DRAM Phy Control Register so that the phy stops driving write levelization ODT. + // Program WrLvOdtEn=0 + NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 0); + + // Wait 10 MEMCLKs to allow for ODT signal settling. + MemRecUWait10ns (3, NBPtr->MemPtr); + + // 7. Program the target Dimm back to normal operation + MemRecTPrepareDIMMs3 (TechPtr, FALSE); + + // 13.Program F2x[1, 0]8C[DisAutoRefresh] = 0. + NBPtr->SetBitField (NBPtr, BFDisAutoRefresh, 0); + // 14.Program F2x[1, 0]94[ZqcsInterval] to the proper interval for the current memory configuration. + NBPtr->SetBitField (NBPtr, BFZqcsInterval, 2); + + IDS_HDT_CONSOLE (MEM_FLOW, "End write leveling\n\n"); +} + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function prepares the DIMMS for Write Levelization + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Wl - Indicates if WL mode should be enabled + * + */ + +VOID +STATIC +MemRecTPrepareDIMMs3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN BOOLEAN Wl + ) +{ + UINT8 ChipSel; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + AGESA_TESTPOINT (TpProcMemWlPrepDimms, &(NBPtr->MemPtr->StdHeader)); + + for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) { + // Set Dram ODT based on current mode. + if ((NBPtr->DCTPtr->Timings.CsPresent & (UINT16) 1 << ChipSel) != 0) { + if (Wl) { + NBPtr->SetDramOdtRec (NBPtr, WRITE_LEVELING_MODE, ChipSel, (NBPtr->DimmToBeUsed << 1)); + } else { + NBPtr->SetDramOdtRec (NBPtr, MISSION_MODE, ChipSel, (NBPtr->DimmToBeUsed << 1)); + } + + NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel); + + // Set MR1 to F2x7C[MrsAddress], F2x7C[MrsBank]=1 + MemRecTEMRS13 (TechPtr); + // Program Level + if (Wl) { + if ((ChipSel >> 1) == NBPtr->DimmToBeUsed) { + NBPtr->SetBitField (NBPtr, BFLevel, 1); + if (ChipSel & 1) { + NBPtr->SetBitField (NBPtr, BFMrsQoff, 1); + } + } + } + // Send command + NBPtr->SendMrsCmd (NBPtr); + + // Set MR2 to F2x7C[MrsAddress], F2x7C[MrsBank]=1 + MemRecTEMRS23 (TechPtr); + // Send command + NBPtr->SendMrsCmd (NBPtr); + } + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function configures the DIMMS for Write Levelization + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +STATIC +MemRecTProcConfig3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + MEM_NB_BLOCK *NBPtr; + CH_DEF_STRUCT *ChannelPtr; + UINT8 ByteLane; + UINT8 *Seed; + UINT8 DefaultSeed; + UINT8 CurrentSeed; + UINT8 Dimm; + + NBPtr = TechPtr->NBPtr; + ChannelPtr = TechPtr->NBPtr->ChannelPtr; + + Dimm = NBPtr->DimmToBeUsed; + + // Program WrLvOdtEn=1 + NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 1); + + // Wait 10 MEMCLKs to allow for ODT signal settling. + MemRecUWait10ns (3, NBPtr->MemPtr); + + IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); + IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSeeds: "); + // Program an initialization Value to registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to set + // the gross and fine delay for all the byte lane fields. If the target frequency is different than 400MHz, + // BIOS must execute two training passes for each Dimm. For pass 1 at a 400MHz MEMCLK frequency, + // use an initial total delay Value of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined + // by design. + + // Get default seed + if (ChannelPtr->RegDimmPresent != 0) { + DefaultSeed = 0x41; + } else if (ChannelPtr->SODimmPresent != 0) { + DefaultSeed = 0x12; + } else { + DefaultSeed = 0x1A; + } + + // Get platform override seed + Seed = (UINT8 *) MemRecFindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_WL_SEED, NBPtr->MCTPtr->SocketId, ChannelPtr->ChannelID, Dimm); + + IDS_HDT_CONSOLE (MEM_FLOW, "Seeds: "); + for (ByteLane = 0; ByteLane < 8; ByteLane++) { + // This includes ECC as byte 8 + CurrentSeed = ((Seed != NULL) ? Seed[ByteLane] : DefaultSeed); + NBPtr->SetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), CurrentSeed); + ChannelPtr->WrDqsDlys[Dimm * MAX_BYTELANES + ByteLane] = CurrentSeed; + IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", CurrentSeed); + } + IDS_HDT_CONSOLE (MEM_FLOW, "\n"); + + // Program F2x[1, 0]9C_x08[WrtLvTrMode]=0 for phy assisted training. + + // Program F2x[1, 0]9C_x08[TrNibbleSel]=0 + + IDS_HDT_CONSOLE (MEM_FLOW, "\n"); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function begins WL training for a specific DIMM + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +STATIC +MemRecTBeginWLTrain3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + MEM_NB_BLOCK *NBPtr; + UINT8 ByteLane; + UINT8 Seed; + UINT8 Delay; + UINT8 Dimm; + + NBPtr = TechPtr->NBPtr; + + Dimm = NBPtr->DimmToBeUsed; + IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrtLvTrEn = 1\n"); + // Program F2x[1, 0]9C_x08[WrtLlTrEn]=1. + NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 1); + + // Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. + MemRecUWait10ns (50, NBPtr->MemPtr); + + // Program F2x[1, 0]9C_x08[WrtLlTrEn]=0. + NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 0); + + // Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to get the gross and fine Delay settings + // for the target Dimm and save these values. + IDS_HDT_CONSOLE (MEM_FLOW, " PRE WrDqs\n"); + for (ByteLane = 0; ByteLane < 8; ByteLane++) { + // This includes ECC as byte 8 + Seed = NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_BYTELANES) + ByteLane]; + Delay = (UINT8)NBPtr->GetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane)); + IDS_HDT_CONSOLE (MEM_FLOW, " %02x ", Delay); + if (((Seed >> 5) == 0) && ((Delay >> 5) == 3)) { + + // If seed has gross delay of 0 and PRE has gross delay of 3, + // then round the total delay of TxDqs to 0. + Delay = 0; + } + + NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), Delay); + NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_BYTELANES) + ByteLane] = Delay; + IDS_HDT_CONSOLE (MEM_FLOW, " %02x\n", Delay); + } + + IDS_HDT_CONSOLE_DEBUG_CODE ( + IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tWrDqs: "); + for (ByteLane = 0; ByteLane < 8; ByteLane++) { + IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", NBPtr->ChannelPtr->WrDqsDlys[ByteLane]); + } + IDS_HDT_CONSOLE (MEM_FLOW, "\n\n"); + ); +} |