AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Recovery / Mem / Tech / mrttsrc.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mrttsrc.c
6  *
7  * Technology Software based DQS receiver enable training Recovery
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Proc/Recovery/Mem)
12  * @e \$Revision: 52180 $ @e \$Date: 2011-05-03 05:17:25 -0600 (Tue, 03 May 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 "amdlib.h"
58 #include "Ids.h"
59 #include "mm.h"
60 #include "mn.h"
61 #include "mru.h"
62 #include "mt.h"
63 #include "Filecode.h"
64 CODE_GROUP (G2_PEI)
65 RDATA_GROUP (G2_PEI)
66
67 #define FILECODE PROC_RECOVERY_MEM_TECH_MRTTSRC_FILECODE
68 /*----------------------------------------------------------------------------
69  *                          DEFINITIONS AND MACROS
70  *
71  *----------------------------------------------------------------------------
72  */
73 #define MAX_BYTELANES 8             /* Max Bytelanes per channel */
74
75 /*----------------------------------------------------------------------------
76  *                           TYPEDEFS AND STRUCTURES
77  *
78  *----------------------------------------------------------------------------
79  */
80
81 /*----------------------------------------------------------------------------
82  *                        PROTOTYPES OF LOCAL FUNCTIONS
83  *
84  *----------------------------------------------------------------------------
85  */
86
87
88 VOID
89 STATIC
90 MemRecTSetRcvrEnDly (
91   IN OUT   MEM_TECH_BLOCK *TechPtr,
92   IN       UINT8 Receiver,
93   IN       UINT16 RcvEnDly
94   );
95
96 VOID
97 STATIC
98 MemRecTLoadRcvrEnDly (
99   IN OUT   MEM_TECH_BLOCK *TechPtr,
100   IN       UINT8 Receiver
101   );
102
103 BOOLEAN
104 STATIC
105 MemRecTSaveRcvrEnDly (
106   IN OUT   MEM_TECH_BLOCK *TechPtr,
107   IN       UINT8 Receiver,
108   IN       UINT16 RcvEnDly,
109   IN       UINT8 CmpResult
110   );
111
112 UINT8
113 STATIC
114 MemRecTCompare1ClPattern (
115   IN       UINT8 Buffer[],
116   IN       UINT8 Pattern[],
117   IN OUT   AMD_CONFIG_PARAMS *StdHeader
118   );
119
120 /*----------------------------------------------------------------------------
121  *                            EXPORTED FUNCTIONS
122  *
123  *----------------------------------------------------------------------------
124  */
125
126 /* -----------------------------------------------------------------------------*/
127 /**
128  *
129  *      This function executes receiver enable training for BSP
130  *
131  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
132  *
133  */
134
135 VOID
136 MemRecTTrainRcvrEnSw (
137   IN OUT   MEM_TECH_BLOCK *TechPtr
138   )
139 {
140   _16BYTE_ALIGN  UINT8  PatternBuffer[3 * 64];
141   UINT8  TestBuffer[120];
142   UINT8  *PatternBufPtr[2];
143   UINT32 TestAddr[4];
144   UINT8  TestResult;
145   UINT8 Receiver;
146   UINT8 i;
147   UINT8 j;
148   UINT16 RcvrEnDly;
149
150   MEM_DATA_STRUCT *MemPtr;
151   DIE_STRUCT *MCTPtr;
152   MEM_NB_BLOCK  *NBPtr;
153
154   NBPtr = TechPtr->NBPtr;
155   MemPtr = NBPtr->MemPtr;
156   MCTPtr = NBPtr->MCTPtr;
157
158   AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader));
159
160   // Set environment settings before training
161   MemRecTBeginTraining (TechPtr);
162
163   PatternBufPtr[0] = PatternBuffer;
164   MemRecUFillTrainPattern (TestPattern0, PatternBufPtr[0], 64, &(MemPtr->StdHeader));
165   PatternBufPtr[1] = PatternBufPtr[0] + 128;
166   MemRecUFillTrainPattern (TestPattern1, PatternBufPtr[1], 64, &(MemPtr->StdHeader));
167
168   // Begin receiver enable training
169   MemRecTSetWrDatRdDqs (TechPtr, 0);
170
171   // there are four receiver pairs, loosely associated with chipselects.
172   Receiver = NBPtr->DimmToBeUsed << 1;
173   TechPtr->DqsRcvEnSaved = 0;
174
175   TestAddr[0] = NBPtr->GetSysAddrRec ();
176   TestAddr[1] = TestAddr[0] + BIGPAGE_X8;
177
178   IDS_HDT_CONSOLE (MEM_FLOW, "\tDct %d\n", NBPtr->Dct);
179   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCS %d\n", Receiver);
180   IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to addresses:  %04x0000\n", TestAddr[0]);
181
182   // Sweep receiver enable delays
183   AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader));
184   for (RcvrEnDly = 0; RcvrEnDly < 0xFF; RcvrEnDly++) {
185
186     TestResult = 0xFF;
187     for (i = 0; i < 2; i++) {
188
189       // Set RcvrEn delay for all byte lanes
190       AGESA_TESTPOINT (TpProcMemRcvrSetDelay, &(MemPtr->StdHeader));
191       MemRecTSetRcvrEnDly (TechPtr, Receiver, RcvrEnDly);
192       IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDly %3x", RcvrEnDly);
193
194       // Swap the test pointers such that even and odd steps alternate.
195       j = ((RcvrEnDly & 1) != 0) ? (i ^ 1) : i;
196
197       // Write, read and compare the first beat of data
198       AGESA_TESTPOINT (TpProcMemRcvrWritePattern, &(MemPtr->StdHeader));
199       MemRecUWrite1CL (TestAddr[j], PatternBufPtr[j]);
200       AGESA_TESTPOINT (TpProcMemRcvrReadPattern, &(MemPtr->StdHeader));
201       MemRecURead1CL (TestBuffer, TestAddr[j]);
202       AGESA_TESTPOINT (TpProcMemRcvrTestPattern, &(MemPtr->StdHeader));
203       TestResult &= MemRecTCompare1ClPattern (TestBuffer, PatternBufPtr[j], &(MemPtr->StdHeader));
204       MemRecUProcIOClFlush (TestAddr[j], MemPtr);
205     }
206
207     if (MemRecTSaveRcvrEnDly (TechPtr, Receiver, RcvrEnDly, TestResult)) {
208       // if all bytelanes pass
209       break;
210     }
211   }   // End of delay sweep
212
213   if (RcvrEnDly == 0xFF) {
214     // no passing window
215     // LibAmdEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_NO_PASSING_WINDOW, 0, NBPtr->Dct, NBPtr->Channel, 0);   //@attention commented out since it is not defined in recovery code
216     SetMemRecError (AGESA_ERROR, MCTPtr);
217   }
218
219   // set final delays
220   MemRecTLoadRcvrEnDly (TechPtr, Receiver);
221
222   // Clear training bit when done
223   NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 0);
224
225   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRcvrEnDly: %03x\n", RcvrEnDly + 0x20);
226
227   // Set Max Latency for both channels
228   NBPtr->SetMaxLatency (NBPtr, RcvrEnDly + 0x20);
229
230   // Restore environment settings after training
231   MemRecTEndTraining (TechPtr);
232 }
233
234 /* -----------------------------------------------------------------------------*/
235 /**
236  *
237  *      If WrDatDly is 0, this function sets the DQS Positions in preparation
238  *      for Receiver Enable Training. (Write Position is no delay, Read Position is 1.5 Memclock delay).
239  *      Otherwise it will set WrDat and RdDqs to center of data eye.
240  *
241  *     @param[in,out]   *TechPtr - Pointer to the MEM_TECH_BLOCK
242  *     @param[in]       WrDatDly - either 0 or 0x0F
243  *
244  */
245
246 VOID
247 MemRecTSetWrDatRdDqs (
248   IN OUT   MEM_TECH_BLOCK *TechPtr,
249   IN       UINT8 WrDatDly
250   )
251 {
252   UINT8 ByteLane;
253   UINT8 Dimm;
254   UINT8 WrDqs;
255   UINT8 RdDqs;
256   MEM_NB_BLOCK  *NBPtr;
257
258   NBPtr = TechPtr->NBPtr;
259
260   Dimm = NBPtr->DimmToBeUsed;
261   IDS_HDT_CONSOLE (MEM_FLOW, "\nWrDat RdDqs\n");
262   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
263     WrDqs = NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_BYTELANES) + ByteLane];
264     NBPtr->SetTrainDly (NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), WrDqs + WrDatDly);
265     RdDqs = (WrDatDly == 0) ? 0x2F : 0x012;
266     NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), RdDqs);
267     IDS_HDT_CONSOLE (MEM_FLOW, "  %02x  %02x\n\n", WrDqs + WrDatDly, RdDqs);
268   }
269 }
270
271 /* -----------------------------------------------------------------------------*/
272 /**
273  *
274  *  This function programs DqsRcvEnDly to additional index for DQS receiver enabled training
275  *
276  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
277  *     @param[in]       Receiver  - Current Chip select value
278  *     @param[in]       RcvEnDly  - receiver enable delay to be saved
279  *
280  */
281
282 VOID
283 STATIC
284 MemRecTSetRcvrEnDly (
285   IN OUT   MEM_TECH_BLOCK *TechPtr,
286   IN       UINT8 Receiver,
287   IN       UINT16 RcvEnDly
288   )
289 {
290   UINT8 ByteLane;
291
292   ASSERT (Receiver <= MAX_CS_PER_CHANNEL);
293   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
294     TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, ByteLane), RcvEnDly);
295   }
296 }
297
298
299 /* -----------------------------------------------------------------------------*/
300 /**
301  *
302  *       This function compares test pattern with data in buffer and return a pass/fail bitmap
303  *       for 8 Bytes
304  *
305  *     @param[in]       Buffer[]  -  Buffer data from DRAM (Measured data from DRAM) to compare
306  *     @param[in]       Pattern[]  - Pattern (Expected data in ROM/CACHE) to compare against
307  *     @param[in,out] StdHeader - The Pointer of AGESA Header.
308  *
309  *     @return  PASS - Bit map of results of comparison
310  */
311
312 UINT8
313 STATIC
314 MemRecTCompare1ClPattern (
315   IN       UINT8 Buffer[],
316   IN       UINT8 Pattern[],
317   IN OUT   AMD_CONFIG_PARAMS *StdHeader
318   )
319 {
320   UINT8 i;
321   UINT8 Pass;
322
323   Pass = 0xFF;
324   IDS_HDT_CONSOLE (MEM_FLOW, " -");
325   for (i = 0; i < 8; i++) {
326     if (Buffer[i] != Pattern[i]) {
327       // if bytelane n fails
328       Pass &= ~((UINT16) 1 << (i % 8));    // clear bit n
329     }
330     IDS_HDT_CONSOLE (MEM_FLOW, "  %c", (Buffer[i] == Pattern[i]) ? 'P' : '.');
331   }
332
333   IDS_HDT_CONSOLE_DEBUG_CODE (
334     IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t        -");
335     for (i = 0; i < 8; i++) {
336       IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Buffer[i]);
337     }
338     IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t        -");
339     for (i = 0; i < 8; i++) {
340       IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Pattern[i]);
341     }
342     IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
343   );
344
345   return Pass;
346 }
347
348 /* -----------------------------------------------------------------------------*/
349 /**
350  *
351  *  This function saves passing DqsRcvEnDly values to the stack
352  *
353  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
354  *     @param[in]       Receiver  - Current Chip select value
355  *     @param[in]       RcvEnDly  - receiver enable delay to be saved
356  *     @param[in]       CmpResult - compare result for Rank 0
357  *
358  *     @return  TRUE - All bytelanes pass
359  *     @return  FALSE - Some bytelanes fail
360  */
361
362 BOOLEAN
363 STATIC
364 MemRecTSaveRcvrEnDly (
365   IN OUT   MEM_TECH_BLOCK *TechPtr,
366   IN       UINT8 Receiver,
367   IN       UINT16 RcvEnDly,
368   IN       UINT8 CmpResult
369   )
370 {
371   UINT8 i;
372   UINT8 Passed;
373   UINT8 Saved;
374   UINT8 Mask;
375   UINT8 Dimm;
376
377   ASSERT (Receiver <= MAX_CS_PER_CHANNEL);
378
379   Passed = CmpResult;
380   Saved = (UINT8) (TechPtr->DqsRcvEnSaved & Passed); //@todo - false passes filter (subject to be replaced with a better solution)
381   Dimm = Receiver >> 1;
382   Mask = 1;
383   for (i = 0; i < 8; i++) {
384     if ((Passed & Mask) != 0) {
385       if ((Saved & Mask) == 0) {
386         TechPtr->NBPtr->ChannelPtr->RcvEnDlys[Dimm * MAX_BYTELANES + i] = (UINT8) (RcvEnDly + 0x20);
387         IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tBL %d = %02x", i, RcvEnDly + 0x20);
388       }
389       Saved |= Mask;
390     }
391     Mask <<= 1;
392   }
393   TechPtr->DqsRcvEnSaved = Saved;
394
395   if (Saved == 0xFF) {
396     return TRUE;
397   } else {
398     return FALSE;
399   }
400 }
401
402 /* -----------------------------------------------------------------------------*/
403 /**
404  *
405  *  This function loads the DqsRcvEnDly from saved data and program to additional index
406  *  for DQS receiver enabled training
407  *
408  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
409  *     @param[in]       Receiver  - Current Chip select value
410  *
411  */
412
413 VOID
414 STATIC
415 MemRecTLoadRcvrEnDly (
416   IN OUT   MEM_TECH_BLOCK *TechPtr,
417   IN       UINT8 Receiver
418   )
419 {
420   UINT8 i;
421   UINT8 Dimm;
422   UINT16 Saved;
423   CH_DEF_STRUCT *ChannelPtr;
424
425   ASSERT (Receiver <= MAX_CS_PER_CHANNEL);
426   ChannelPtr = TechPtr->NBPtr->ChannelPtr;
427
428   Dimm = Receiver >> 1;
429   Saved = TechPtr->DqsRcvEnSaved;
430   for (i = 0; i < 8; i++) {
431     if ((Saved & 1) != 0) {
432       TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, i),
433       ChannelPtr->RcvEnDlys[Dimm * MAX_BYTELANES + i]);
434     }
435     Saved >>= 1;
436   }
437 }