AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Recovery / Mem / Tech / DDR3 / mrttwl3.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mrttwl3.c
6  *
7  * Technology Phy assisted write levelization for recovery DDR3
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Proc/Recovery/Mem)
12  * @e \$Revision: 50454 $ @e \$Date: 2011-04-10 21:20:37 -0600 (Sun, 10 Apr 2011) $
13  *
14  **/
15 /*****************************************************************************
16 *
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
19 *
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.
30 *
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.
41 *
42 * ***************************************************************************
43 *
44 */
45
46 /*
47  *----------------------------------------------------------------------------
48  *                                MODULES USED
49  *
50  *----------------------------------------------------------------------------
51  */
52
53
54
55 #include "AGESA.h"
56 #include "OptionMemory.h"
57 #include "PlatformMemoryConfiguration.h"
58 #include "Ids.h"
59 #include "mm.h"
60 #include "mn.h"
61 #include "mru.h"
62 #include "mt.h"
63 #include "mrt3.h"
64 #include "Filecode.h"
65 CODE_GROUP (G2_PEI)
66 RDATA_GROUP (G2_PEI)
67
68 #define FILECODE PROC_RECOVERY_MEM_TECH_DDR3_MRTTWL3_FILECODE
69 /*----------------------------------------------------------------------------
70  *                          DEFINITIONS AND MACROS
71  *
72  *----------------------------------------------------------------------------
73  */
74 #define MAX_BYTELANES 8             /* Max Bytelanes per channel */
75
76 /*----------------------------------------------------------------------------
77  *                           TYPEDEFS AND STRUCTURES
78  *
79  *----------------------------------------------------------------------------
80  */
81
82 /*----------------------------------------------------------------------------
83  *                        PROTOTYPES OF LOCAL FUNCTIONS
84  *
85  *----------------------------------------------------------------------------
86  */
87
88 VOID
89 STATIC
90 MemRecTPrepareDIMMs3 (
91   IN OUT   MEM_TECH_BLOCK *TechPtr,
92   IN       BOOLEAN Wl
93   );
94
95 VOID
96 STATIC
97 MemRecTProcConfig3 (
98   IN OUT   MEM_TECH_BLOCK *TechPtr
99   );
100
101 VOID
102 STATIC
103 MemRecTBeginWLTrain3 (
104   IN OUT   MEM_TECH_BLOCK *TechPtr
105   );
106
107 /*----------------------------------------------------------------------------
108  *                            EXPORTED FUNCTIONS
109  *
110  *----------------------------------------------------------------------------
111  */
112
113 /* -----------------------------------------------------------------------------*/
114 /**
115  *
116  *      This function executed hardware based write levelization for a specific die
117  *
118  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
119  *
120  */
121
122 VOID
123 MemRecTTrainDQSWriteHw3 (
124   IN OUT   MEM_TECH_BLOCK *TechPtr
125   )
126 {
127   MEM_NB_BLOCK  *NBPtr;
128
129   NBPtr = TechPtr->NBPtr;
130
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);
136
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);
141
142   // 2. Prepare the DIMMs for write levelization using DDR3-defined
143   // MR commands.
144   MemRecTPrepareDIMMs3 (TechPtr, TRUE);
145
146   // 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
147   //     satisfy DDR3-defined internal DRAM timing.
148   MemRecUWait10ns (10, NBPtr->MemPtr);
149
150   // 4. Configure the processor's DDR phy for write levelization training:
151   MemRecTProcConfig3 (TechPtr);
152
153   // 5. Begin write levelization training
154   MemRecTBeginWLTrain3 (TechPtr);
155
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);
159
160   // Wait 10 MEMCLKs to allow for ODT signal settling.
161   MemRecUWait10ns (3, NBPtr->MemPtr);
162
163   // 7. Program the target Dimm back to normal operation
164   MemRecTPrepareDIMMs3 (TechPtr, FALSE);
165
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);
170
171   IDS_HDT_CONSOLE (MEM_FLOW, "End write leveling\n\n");
172 }
173
174 /*----------------------------------------------------------------------------
175  *                              LOCAL FUNCTIONS
176  *
177  *----------------------------------------------------------------------------
178  */
179
180 /* -----------------------------------------------------------------------------*/
181 /**
182  *
183  *      This function prepares the DIMMS for Write Levelization
184  *
185  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
186  *     @param[in] Wl - Indicates if WL mode should be enabled
187  *
188  */
189
190 VOID
191 STATIC
192 MemRecTPrepareDIMMs3 (
193   IN OUT   MEM_TECH_BLOCK *TechPtr,
194   IN       BOOLEAN Wl
195   )
196 {
197   UINT8 ChipSel;
198   MEM_NB_BLOCK  *NBPtr;
199
200   NBPtr = TechPtr->NBPtr;
201
202   AGESA_TESTPOINT (TpProcMemWlPrepDimms, &(NBPtr->MemPtr->StdHeader));
203
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) {
207       if (Wl) {
208         NBPtr->SetDramOdtRec (NBPtr, WRITE_LEVELING_MODE, ChipSel, (NBPtr->DimmToBeUsed << 1));
209       } else {
210         NBPtr->SetDramOdtRec (NBPtr, MISSION_MODE, ChipSel, (NBPtr->DimmToBeUsed << 1));
211       }
212
213       NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
214
215       // Set MR1 to F2x7C[MrsAddress], F2x7C[MrsBank]=1
216       MemRecTEMRS13 (TechPtr);
217       // Program Level
218       if (Wl) {
219         if ((ChipSel >> 1) == NBPtr->DimmToBeUsed) {
220           NBPtr->SetBitField (NBPtr, BFLevel, 1);
221           if (ChipSel & 1) {
222             NBPtr->SetBitField (NBPtr, BFMrsQoff, 1);
223           }
224         }
225       }
226       // Send command
227       NBPtr->SendMrsCmd (NBPtr);
228
229       // Set MR2 to F2x7C[MrsAddress], F2x7C[MrsBank]=1
230       MemRecTEMRS23 (TechPtr);
231       // Send command
232       NBPtr->SendMrsCmd (NBPtr);
233     }
234   }
235 }
236
237 /* -----------------------------------------------------------------------------*/
238 /**
239  *
240  *      This function configures the DIMMS for Write Levelization
241  *
242  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
243  *
244  */
245
246 VOID
247 STATIC
248 MemRecTProcConfig3 (
249   IN OUT   MEM_TECH_BLOCK *TechPtr
250   )
251 {
252   MEM_NB_BLOCK *NBPtr;
253   CH_DEF_STRUCT *ChannelPtr;
254   UINT8 ByteLane;
255   UINT8 *Seed;
256   UINT8 DefaultSeed;
257   UINT8 CurrentSeed;
258   UINT8 Dimm;
259
260   NBPtr = TechPtr->NBPtr;
261   ChannelPtr = TechPtr->NBPtr->ChannelPtr;
262
263   Dimm = NBPtr->DimmToBeUsed;
264
265   // Program WrLvOdtEn=1
266   NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 1);
267
268   // Wait 10 MEMCLKs to allow for ODT signal settling.
269   MemRecUWait10ns (3, NBPtr->MemPtr);
270
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
277   //  by design.
278
279   //  Get default seed
280   if (ChannelPtr->RegDimmPresent != 0) {
281     DefaultSeed = 0x41;
282   } else if (ChannelPtr->SODimmPresent != 0) {
283     DefaultSeed = 0x12;
284   } else {
285     DefaultSeed = 0x1A;
286   }
287
288   //  Get platform override seed
289   Seed = (UINT8 *) MemRecFindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_WL_SEED, NBPtr->MCTPtr->SocketId, ChannelPtr->ChannelID, Dimm);
290
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);
298   }
299   IDS_HDT_CONSOLE (MEM_FLOW, "\n");
300
301   // Program F2x[1, 0]9C_x08[WrtLvTrMode]=0 for phy assisted training.
302
303   // Program F2x[1, 0]9C_x08[TrNibbleSel]=0
304
305   IDS_HDT_CONSOLE (MEM_FLOW, "\n");
306 }
307
308 /* -----------------------------------------------------------------------------*/
309 /**
310  *
311  *      This function begins WL training for a specific DIMM
312  *
313  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
314  *
315  */
316
317 VOID
318 STATIC
319 MemRecTBeginWLTrain3 (
320   IN OUT   MEM_TECH_BLOCK *TechPtr
321   )
322 {
323   MEM_NB_BLOCK *NBPtr;
324   UINT8 ByteLane;
325   UINT8 Seed;
326   UINT8 Delay;
327   UINT8 Dimm;
328
329   NBPtr = TechPtr->NBPtr;
330
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);
335
336   //  Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs.
337   MemRecUWait10ns (50, NBPtr->MemPtr);
338
339   //  Program F2x[1, 0]9C_x08[WrtLlTrEn]=0.
340   NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 0);
341
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)) {
351
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.
354       Delay = 0;
355     }
356
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);
360   }
361
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]);
366     }
367     IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
368   );
369 }