7 * Technology Phy assisted write levelization for recovery DDR3
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Proc/Recovery/Mem)
12 * @e \$Revision: 50454 $ @e \$Date: 2011-04-10 21:20:37 -0600 (Sun, 10 Apr 2011) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ***************************************************************************
47 *----------------------------------------------------------------------------
50 *----------------------------------------------------------------------------
56 #include "OptionMemory.h"
57 #include "PlatformMemoryConfiguration.h"
68 #define FILECODE PROC_RECOVERY_MEM_TECH_DDR3_MRTTWL3_FILECODE
69 /*----------------------------------------------------------------------------
70 * DEFINITIONS AND MACROS
72 *----------------------------------------------------------------------------
74 #define MAX_BYTELANES 8 /* Max Bytelanes per channel */
76 /*----------------------------------------------------------------------------
77 * TYPEDEFS AND STRUCTURES
79 *----------------------------------------------------------------------------
82 /*----------------------------------------------------------------------------
83 * PROTOTYPES OF LOCAL FUNCTIONS
85 *----------------------------------------------------------------------------
90 MemRecTPrepareDIMMs3 (
91 IN OUT MEM_TECH_BLOCK *TechPtr,
98 IN OUT MEM_TECH_BLOCK *TechPtr
103 MemRecTBeginWLTrain3 (
104 IN OUT MEM_TECH_BLOCK *TechPtr
107 /*----------------------------------------------------------------------------
110 *----------------------------------------------------------------------------
113 /* -----------------------------------------------------------------------------*/
116 * This function executed hardware based write levelization for a specific die
118 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
123 MemRecTTrainDQSWriteHw3 (
124 IN OUT MEM_TECH_BLOCK *TechPtr
129 NBPtr = TechPtr->NBPtr;
131 IDS_HDT_CONSOLE (MEM_STATUS, "\nStart write leveling\n");
132 // Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1.
133 NBPtr->SetBitField (NBPtr, BFDisAutoRefresh, 1);
134 // Disable ZQ calibration short command by configuring F2x[1, 0]94[ZqcsInterval] = 00b.
135 NBPtr->SetBitField (NBPtr, BFZqcsInterval, 0);
137 // 1. Specify the target Dimm that is to be trained by programming
138 // F2x[1, 0]9C_x08[TrDimmSel].
139 IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", NBPtr->DimmToBeUsed << 1);
140 NBPtr->SetBitField (NBPtr, BFTrDimmSel, NBPtr->DimmToBeUsed);
142 // 2. Prepare the DIMMs for write levelization using DDR3-defined
144 MemRecTPrepareDIMMs3 (TechPtr, TRUE);
146 // 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
147 // satisfy DDR3-defined internal DRAM timing.
148 MemRecUWait10ns (10, NBPtr->MemPtr);
150 // 4. Configure the processor's DDR phy for write levelization training:
151 MemRecTProcConfig3 (TechPtr);
153 // 5. Begin write levelization training
154 MemRecTBeginWLTrain3 (TechPtr);
156 // 6. Configure DRAM Phy Control Register so that the phy stops driving write levelization ODT.
157 // Program WrLvOdtEn=0
158 NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 0);
160 // Wait 10 MEMCLKs to allow for ODT signal settling.
161 MemRecUWait10ns (3, NBPtr->MemPtr);
163 // 7. Program the target Dimm back to normal operation
164 MemRecTPrepareDIMMs3 (TechPtr, FALSE);
166 // 13.Program F2x[1, 0]8C[DisAutoRefresh] = 0.
167 NBPtr->SetBitField (NBPtr, BFDisAutoRefresh, 0);
168 // 14.Program F2x[1, 0]94[ZqcsInterval] to the proper interval for the current memory configuration.
169 NBPtr->SetBitField (NBPtr, BFZqcsInterval, 2);
171 IDS_HDT_CONSOLE (MEM_FLOW, "End write leveling\n\n");
174 /*----------------------------------------------------------------------------
177 *----------------------------------------------------------------------------
180 /* -----------------------------------------------------------------------------*/
183 * This function prepares the DIMMS for Write Levelization
185 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
186 * @param[in] Wl - Indicates if WL mode should be enabled
192 MemRecTPrepareDIMMs3 (
193 IN OUT MEM_TECH_BLOCK *TechPtr,
200 NBPtr = TechPtr->NBPtr;
202 AGESA_TESTPOINT (TpProcMemWlPrepDimms, &(NBPtr->MemPtr->StdHeader));
204 for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
205 // Set Dram ODT based on current mode.
206 if ((NBPtr->DCTPtr->Timings.CsPresent & (UINT16) 1 << ChipSel) != 0) {
208 NBPtr->SetDramOdtRec (NBPtr, WRITE_LEVELING_MODE, ChipSel, (NBPtr->DimmToBeUsed << 1));
210 NBPtr->SetDramOdtRec (NBPtr, MISSION_MODE, ChipSel, (NBPtr->DimmToBeUsed << 1));
213 NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
215 // Set MR1 to F2x7C[MrsAddress], F2x7C[MrsBank]=1
216 MemRecTEMRS13 (TechPtr);
219 if ((ChipSel >> 1) == NBPtr->DimmToBeUsed) {
220 NBPtr->SetBitField (NBPtr, BFLevel, 1);
222 NBPtr->SetBitField (NBPtr, BFMrsQoff, 1);
227 NBPtr->SendMrsCmd (NBPtr);
229 // Set MR2 to F2x7C[MrsAddress], F2x7C[MrsBank]=1
230 MemRecTEMRS23 (TechPtr);
232 NBPtr->SendMrsCmd (NBPtr);
237 /* -----------------------------------------------------------------------------*/
240 * This function configures the DIMMS for Write Levelization
242 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
249 IN OUT MEM_TECH_BLOCK *TechPtr
253 CH_DEF_STRUCT *ChannelPtr;
260 NBPtr = TechPtr->NBPtr;
261 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
263 Dimm = NBPtr->DimmToBeUsed;
265 // Program WrLvOdtEn=1
266 NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 1);
268 // Wait 10 MEMCLKs to allow for ODT signal settling.
269 MemRecUWait10ns (3, NBPtr->MemPtr);
271 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Byte: 00 01 02 03 04 05 06 07 ECC\n");
272 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSeeds: ");
273 // Program an initialization Value to registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to set
274 // the gross and fine delay for all the byte lane fields. If the target frequency is different than 400MHz,
275 // BIOS must execute two training passes for each Dimm. For pass 1 at a 400MHz MEMCLK frequency,
276 // use an initial total delay Value of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined
280 if (ChannelPtr->RegDimmPresent != 0) {
282 } else if (ChannelPtr->SODimmPresent != 0) {
288 // Get platform override seed
289 Seed = (UINT8 *) MemRecFindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_WL_SEED, NBPtr->MCTPtr->SocketId, ChannelPtr->ChannelID, Dimm);
291 IDS_HDT_CONSOLE (MEM_FLOW, "Seeds: ");
292 for (ByteLane = 0; ByteLane < 8; ByteLane++) {
293 // This includes ECC as byte 8
294 CurrentSeed = ((Seed != NULL) ? Seed[ByteLane] : DefaultSeed);
295 NBPtr->SetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), CurrentSeed);
296 ChannelPtr->WrDqsDlys[Dimm * MAX_BYTELANES + ByteLane] = CurrentSeed;
297 IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", CurrentSeed);
299 IDS_HDT_CONSOLE (MEM_FLOW, "\n");
301 // Program F2x[1, 0]9C_x08[WrtLvTrMode]=0 for phy assisted training.
303 // Program F2x[1, 0]9C_x08[TrNibbleSel]=0
305 IDS_HDT_CONSOLE (MEM_FLOW, "\n");
308 /* -----------------------------------------------------------------------------*/
311 * This function begins WL training for a specific DIMM
313 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
319 MemRecTBeginWLTrain3 (
320 IN OUT MEM_TECH_BLOCK *TechPtr
329 NBPtr = TechPtr->NBPtr;
331 Dimm = NBPtr->DimmToBeUsed;
332 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrtLvTrEn = 1\n");
333 // Program F2x[1, 0]9C_x08[WrtLlTrEn]=1.
334 NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 1);
336 // Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs.
337 MemRecUWait10ns (50, NBPtr->MemPtr);
339 // Program F2x[1, 0]9C_x08[WrtLlTrEn]=0.
340 NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 0);
342 // Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to get the gross and fine Delay settings
343 // for the target Dimm and save these values.
344 IDS_HDT_CONSOLE (MEM_FLOW, " PRE WrDqs\n");
345 for (ByteLane = 0; ByteLane < 8; ByteLane++) {
346 // This includes ECC as byte 8
347 Seed = NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_BYTELANES) + ByteLane];
348 Delay = (UINT8)NBPtr->GetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane));
349 IDS_HDT_CONSOLE (MEM_FLOW, " %02x ", Delay);
350 if (((Seed >> 5) == 0) && ((Delay >> 5) == 3)) {
352 // If seed has gross delay of 0 and PRE has gross delay of 3,
353 // then round the total delay of TxDqs to 0.
357 NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), Delay);
358 NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_BYTELANES) + ByteLane] = Delay;
359 IDS_HDT_CONSOLE (MEM_FLOW, " %02x\n", Delay);
362 IDS_HDT_CONSOLE_DEBUG_CODE (
363 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tWrDqs: ");
364 for (ByteLane = 0; ByteLane < 8; ByteLane++) {
365 IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", NBPtr->ChannelPtr->WrDqsDlys[ByteLane]);
367 IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");