AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Tech / mttoptsrc.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mttoptsrc.c
6  *
7  * New Technology Software based DQS receiver enable training
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/Tech)
12  * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 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 "AdvancedApi.h"
57 #include "Ids.h"
58 #include "mm.h"
59 #include "mn.h"
60 #include "mu.h"
61 #include "mt.h"
62 #include "merrhdl.h"
63 #include "Filecode.h"
64 CODE_GROUP (G1_PEICC)
65 RDATA_GROUP (G2_PEI)
66
67 #define FILECODE PROC_MEM_TECH_MTTOPTSRC_FILECODE
68 /*----------------------------------------------------------------------------
69  *                          DEFINITIONS AND MACROS
70  *
71  *----------------------------------------------------------------------------
72  */
73
74 /*----------------------------------------------------------------------------
75  *                           TYPEDEFS AND STRUCTURES
76  *
77  *----------------------------------------------------------------------------
78  */
79
80 /*----------------------------------------------------------------------------
81  *                        PROTOTYPES OF LOCAL FUNCTIONS
82  *
83  *----------------------------------------------------------------------------
84  */
85
86 BOOLEAN
87 STATIC
88 MemTDqsTrainOptRcvrEnSw (
89   IN OUT   MEM_TECH_BLOCK *TechPtr,
90   IN       UINT8 Pass
91   );
92
93 BOOLEAN
94 MemTNewRevTrainingSupport (
95   IN OUT   MEM_TECH_BLOCK *TechPtr
96   )
97 {
98   return TRUE;
99 }
100
101 /*----------------------------------------------------------------------------
102  *                            EXPORTED FUNCTIONS
103  *
104  *----------------------------------------------------------------------------
105  */
106
107 /* -----------------------------------------------------------------------------*/
108 /**
109  *
110  *      This function executes first pass of receiver enable training for all dies
111  *
112  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
113  *
114  *     @return          TRUE -  No fatal error occurs.
115  *     @return          FALSE - Fatal error occurs.
116  */
117
118 BOOLEAN
119 MemTTrainOptRcvrEnSwPass1 (
120   IN OUT   MEM_TECH_BLOCK *TechPtr
121   )
122 {
123   return MemTDqsTrainOptRcvrEnSw (TechPtr, 1);
124 }
125
126 /*----------------------------------------------------------------------------
127  *                              LOCAL FUNCTIONS
128  *
129  *----------------------------------------------------------------------------
130  */
131
132 /* -----------------------------------------------------------------------------*/
133 /**
134  *
135  *      This function executes receiver enable training for a specific die
136  *
137  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
138  *     @param[in]  Pass - Pass of the receiver training
139  *
140  *     @return          TRUE -  No fatal error occurs.
141  *     @return          FALSE - Fatal error occurs.
142  */
143 BOOLEAN
144 STATIC
145 MemTDqsTrainOptRcvrEnSw (
146   IN OUT   MEM_TECH_BLOCK *TechPtr,
147   IN       UINT8 Pass
148   )
149 {
150   _16BYTE_ALIGN  UINT8  PatternBuffer[6 * 64];
151   UINT8  TestBuffer[256];
152   UINT8  *PatternBufPtr[6];
153   UINT8  *TempPtr;
154   UINT32 TestAddrRJ16[4];
155   UINT32 TempAddrRJ16;
156   UINT32 RealAddr;
157   UINT16 CurTest[4];
158   UINT8 Dct;
159   UINT8 Receiver;
160   UINT8 i;
161   UINT8 TimesFail;
162   UINT8 TimesRetrain;
163   UINT16 RcvrEnDly;
164   UINT16 MaxRcvrEnDly;
165   UINT16 RcvrEnDlyLimit;
166   UINT16 MaxDelayCha;
167   BOOLEAN IsDualRank;
168   BOOLEAN S0En;
169   BOOLEAN S1En;
170
171
172   MEM_DATA_STRUCT *MemPtr;
173   DIE_STRUCT *MCTPtr;
174   DCT_STRUCT *DCTPtr;
175   MEM_NB_BLOCK  *NBPtr;
176
177   NBPtr = TechPtr->NBPtr;
178   MemPtr = NBPtr->MemPtr;
179   MCTPtr = NBPtr->MCTPtr;
180   TechPtr->TrainingType = TRN_RCVR_ENABLE;
181
182
183   TempAddrRJ16 = 0;
184   TempPtr = NULL;
185   MaxDelayCha = 0;
186   TimesRetrain = DEFAULT_TRAINING_TIMES;
187   IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader);
188
189   IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Optimized SW RxEn training\n");
190   // Set environment settings before training
191   MemTBeginTraining (TechPtr);
192
193   PatternBufPtr[0] = PatternBufPtr[2] = PatternBuffer;
194   // These two patterns used for first Test Address
195   MemUFillTrainPattern (TestPattern0, PatternBufPtr[0], 64);
196   // Second Cacheline used for Dummy Read is the inverse of
197   //  the first so that is is not mistaken for the real read
198   MemUFillTrainPattern (TestPattern1, PatternBufPtr[0] + 64, 64);
199   PatternBufPtr[1] = PatternBufPtr[3] = PatternBufPtr[0] + 128;
200   // These two patterns used for second Test Address
201   MemUFillTrainPattern (TestPattern1, PatternBufPtr[1], 64);
202   // Second Cacheline used for Dummy Read is the inverse of
203   //  the first so that is is not mistaken for the real read
204   MemUFillTrainPattern (TestPattern0, PatternBufPtr[1] + 64, 64);
205
206   // Fill pattern for flush after every sweep
207   PatternBufPtr[4] = PatternBufPtr[0] + 256;
208   MemUFillTrainPattern (TestPattern3, PatternBufPtr[4], 64);
209
210   // Fill pattern for initial dummy read
211   PatternBufPtr[5] = PatternBufPtr[0] + 320;
212   MemUFillTrainPattern (TestPattern4, PatternBufPtr[5], 64);
213
214
215   // Begin receiver enable training
216   AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader));
217   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
218     IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
219     NBPtr->SwitchDCT (NBPtr, Dct);
220     DCTPtr = NBPtr->DCTPtr;
221
222     // Set training bit
223     NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 1);
224
225     // Relax Max Latency before training
226     NBPtr->SetMaxLatency (NBPtr, 0xFFFF);
227
228     if (Pass == FIRST_PASS) {
229       TechPtr->InitDQSPos4RcvrEn (TechPtr);
230     }
231
232     // there are four receiver pairs, loosely associated with chipselects.
233     Receiver = DCTPtr->Timings.CsEnabled ? 0 : 8;
234     for (; Receiver < 8; Receiver += 2) {
235       S0En = NBPtr->GetSysAddr (NBPtr, Receiver, &TestAddrRJ16[0]);
236       S1En = NBPtr->GetSysAddr (NBPtr, Receiver + 1, &TestAddrRJ16[2]);
237       if (S0En) {
238         TestAddrRJ16[1] = TestAddrRJ16[0] + BIGPAGE_X8_RJ16;
239       }
240       if (S1En) {
241         TestAddrRJ16[3] = TestAddrRJ16[2] + BIGPAGE_X8_RJ16;
242       }
243       if (S0En && S1En) {
244         IsDualRank = TRUE;
245       } else {
246         IsDualRank = FALSE;
247       }
248       if (S0En || S1En) {
249         IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", Receiver);
250
251         RcvrEnDlyLimit = 0x1FF;      // @attention - limit depends on proc type
252         TechPtr->DqsRcvEnSaved = 0;
253         RcvrEnDly = RcvrEnDlyLimit;
254         RealAddr = 0;
255
256         TechPtr->GetFirstPassVal = FALSE;
257         TechPtr->DqsRcvEnFirstPassVal = 0;
258         TechPtr->RevertPassVal = FALSE;
259         TechPtr->InitializeVariablesOpt (TechPtr);
260
261         // Write the test patterns
262         AGESA_TESTPOINT (TpProcMemRcvrWritePattern, &(MemPtr->StdHeader));
263         IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to addresses: ");
264         for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
265           RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
266           // One cacheline of data to be tested and one of dummy data
267           MemUWriteCachelines (RealAddr, PatternBufPtr[i], 2);
268           // This is dummy data with a different pattern used for the first dummy read.
269           MemUWriteCachelines (RealAddr + 128, PatternBufPtr[5], 1);
270           IDS_HDT_CONSOLE (MEM_FLOW, " %04x0000 ", TestAddrRJ16[i]);
271         }
272         IDS_HDT_CONSOLE (MEM_FLOW, "\n");
273
274         // Sweep receiver enable delays
275         AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader));
276         TimesFail = 0;
277         ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain)
278         {
279           TechPtr->LoadInitialRcvrEnDlyOpt (TechPtr, Receiver);
280           while (!TechPtr->CheckRcvrEnDlyLimitOpt (TechPtr)) {
281             AGESA_TESTPOINT (TpProcMemRcvrSetDelay, &(MemPtr->StdHeader));
282             TechPtr->SetRcvrEnDlyOpt (TechPtr, Receiver, RcvrEnDly);
283             // Read and compare the first beat of data
284             for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
285               AGESA_TESTPOINT (TpProcMemRcvrReadPattern, &(MemPtr->StdHeader));
286               RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
287               //
288               // Issue dummy cacheline reads
289               //
290 #if 0 //KR make OPT DQS Receiver Enable training happy
291               MemUReadCachelines (TestBuffer + 128, RealAddr + 128, 1);
292               MemUReadCachelines (TestBuffer, RealAddr, 1);
293 #endif
294               MemUProcIOClFlush (TestAddrRJ16[i], 2, MemPtr);
295               //
296               // Perform actual read which will be compared
297               //
298               MemUReadCachelines (TestBuffer + 64, RealAddr + 64, 1);
299               AGESA_TESTPOINT (TpProcMemRcvrTestPattern, &(MemPtr->StdHeader));
300               CurTest[i] = TechPtr->Compare1ClPatternOpt (TechPtr, TestBuffer + 64 , PatternBufPtr[i] + 64, i, Receiver, S1En);
301               // Due to speculative execution during MemUReadCachelines, we must
302               //  flush one more cache line than we read.
303               MemUProcIOClFlush (TestAddrRJ16[i], 4, MemPtr);
304               TechPtr->ResetDCTWrPtr (TechPtr, Receiver);
305
306               //
307               // Swap the test pointers such that even and odd steps alternate.
308               //
309               if ((i % 2) == 0) {
310                 TempPtr = PatternBufPtr[i];
311                 PatternBufPtr[i] = PatternBufPtr[i + 1];
312
313                 TempAddrRJ16 = TestAddrRJ16[i];
314                 TestAddrRJ16[i] = TestAddrRJ16[i + 1];
315               } else {
316                 PatternBufPtr[i] = TempPtr;
317                 TestAddrRJ16[i] = TempAddrRJ16;
318               }
319             }
320           }   // End of delay sweep
321           ERROR_HANDLE_RETRAIN_END (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, TRUE), TimesFail)
322         }
323
324         if (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, FALSE)) {
325           return FALSE;
326         }
327
328         TechPtr->LoadRcvrEnDlyOpt (TechPtr, Receiver);     // set final delays
329         //
330         // Flush AA and 55 patterns by reading a dummy pattern to fill in FIFO
331         //
332         // Aquire a new FSBase, based on the last test address that we stored.
333         RealAddr = MemUSetUpperFSbase (TempAddrRJ16, MemPtr);
334         ASSERT (RealAddr != 0);
335         MemUWriteCachelines (RealAddr, PatternBufPtr[4], 1);
336         MemUWriteCachelines (RealAddr + 64, PatternBufPtr[4], 1);
337         MemUReadCachelines (TestBuffer, RealAddr, 2);
338         // Due to speculative execution during MemUReadCachelines, we must
339         //  flush one more cache line than we read.
340         MemUProcIOClFlush (TempAddrRJ16, 3, MemPtr);
341       }
342     }   // End while Receiver < 8
343
344     // Clear training bit when done
345     NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 0);
346
347     // Set Max Latency for both channels
348     MaxRcvrEnDly = TechPtr->GetMaxValueOpt (TechPtr);
349     IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRcvrEnDly: %03x\n", MaxRcvrEnDly);
350     if (MCTPtr->GangedMode) {
351       if (Dct == 0) {
352         MaxDelayCha = MaxRcvrEnDly;
353       } else if (MaxRcvrEnDly > MaxDelayCha) {
354         NBPtr->SwitchDCT (NBPtr, 0);
355         NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
356       }
357     } else {
358       NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
359     }
360     TechPtr->ResetDCTWrPtr (TechPtr, 6);
361   }
362
363   // Restore environment settings after training
364   MemTEndTraining (TechPtr);
365   IDS_HDT_CONSOLE (MEM_FLOW, "End Optimized SW RxEn training\n\n");
366   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
367 }
368
369 /*-----------------------------------------------------------------------------
370  *
371  *  This function saves passing DqsRcvEnDly values to the stack
372  *
373  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
374  *     @param[in]       Receiver  - Current Chip select value
375  *     @param[in]       RcvEnDly  - receiver enable delay to be saved
376  *     @param[in]       cmpResultRank0 - compare result for Rank 0
377  *     @param[in]       cmpResultRank0 - compare result for Rank 1
378  *
379  *     @retval  TRUE - All bytelanes pass
380  *              FALSE - Some bytelanes fail
381  * ----------------------------------------------------------------------------
382  */
383
384 BOOLEAN
385 MemTSaveRcvrEnDlyByteFilterOpt (
386   IN OUT   MEM_TECH_BLOCK *TechPtr,
387   IN       UINT8 Receiver,
388   IN       UINT16 RcvEnDly,
389   IN       UINT16 CmpResultRank0,
390   IN       UINT16 CmpResultRank1
391   )
392 {
393   UINT8 i;
394   UINT8 Passed;
395   UINT8 Dimm;
396   CH_DEF_STRUCT *ChannelPtr;
397
398   ASSERT (Receiver < MAX_CS_PER_CHANNEL);
399   ChannelPtr = TechPtr->NBPtr->ChannelPtr;
400
401   Passed = (UINT8) ((CmpResultRank0 & CmpResultRank1) & 0xFF);
402
403   Dimm = Receiver >> 1;
404
405   if (TechPtr->GetFirstPassVal && (RcvEnDly - TechPtr->DqsRcvEnFirstPassVal) >= 0x30) {
406     for (i = 0; i < 8; i++) {
407       ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + i] = TechPtr->DqsRcvEnFirstPassVal + NEW_RECEIVER_FINAL_OFFSETVALUE;
408     }
409     TechPtr->DqsRcvEnSaved = 0xFF;
410   }
411
412   if (Passed == 0xFF) {
413     if (!TechPtr->GetFirstPassVal) {
414       TechPtr->DqsRcvEnFirstPassVal = RcvEnDly;
415       TechPtr->GetFirstPassVal = TRUE;
416     }
417     return TRUE;
418   } else {
419     TechPtr->DqsRcvEnFirstPassVal = 0;
420
421     // We have got first passing value, but later, we meet with glitch
422     if (TechPtr->GetFirstPassVal) {
423       TechPtr->DqsRcvEnFirstPassVal = 0xFF;
424       TechPtr->GetFirstPassVal = FALSE;
425     }
426     return FALSE;
427   }
428 }