blob: bda316a1bf90d90c9ca9f00376580dcbfda94c82 [file] [log] [blame]
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001/* $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: 38442 $ @e \$Date: 2010-09-24 06:39:57 +0800 (Fri, 24 Sep 2010) $
13 *
14 **/
15/*
16 *****************************************************************************
17 *
18 * Copyright (c) 2011, Advanced Micro Devices, Inc.
19 * All rights reserved.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100020 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000021 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100028 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
Frank Vibrans2b4c8312011-02-14 18:30:54 +000030 * from this software without specific prior written permission.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100031 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000032 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100042 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000043 * ***************************************************************************
44 *
45 */
46
47/*
48 *----------------------------------------------------------------------------
49 * MODULES USED
50 *
51 *----------------------------------------------------------------------------
52 */
53
54
55
56#include "AGESA.h"
57#include "AdvancedApi.h"
58#include "Ids.h"
59#include "mm.h"
60#include "mn.h"
61#include "mu.h"
62#include "mt.h"
63#include "merrhdl.h"
64#include "Filecode.h"
65CODE_GROUP (G1_PEICC)
66RDATA_GROUP (G1_PEICC)
67
68#define FILECODE PROC_MEM_TECH_MTTOPTSRC_FILECODE
69/*----------------------------------------------------------------------------
70 * DEFINITIONS AND MACROS
71 *
72 *----------------------------------------------------------------------------
73 */
74
75/*----------------------------------------------------------------------------
76 * TYPEDEFS AND STRUCTURES
77 *
78 *----------------------------------------------------------------------------
79 */
80
81/*----------------------------------------------------------------------------
82 * PROTOTYPES OF LOCAL FUNCTIONS
83 *
84 *----------------------------------------------------------------------------
85 */
86
87BOOLEAN
88STATIC
89MemTDqsTrainOptRcvrEnSw (
90 IN OUT MEM_TECH_BLOCK *TechPtr,
91 IN UINT8 Pass
92 );
93
94BOOLEAN
95MemTNewRevTrainingSupport (
96 IN OUT MEM_TECH_BLOCK *TechPtr
97 )
98{
99 return TRUE;
100}
101
102/*----------------------------------------------------------------------------
103 * EXPORTED FUNCTIONS
104 *
105 *----------------------------------------------------------------------------
106 */
107
108/* -----------------------------------------------------------------------------*/
109/**
110 *
111 * This function executes first pass of receiver enable training for all dies
112 *
113 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
114 *
115 * @return TRUE - No fatal error occurs.
116 * @return FALSE - Fatal error occurs.
117 */
118
119BOOLEAN
120MemTTrainOptRcvrEnSwPass1 (
121 IN OUT MEM_TECH_BLOCK *TechPtr
122 )
123{
124 return MemTDqsTrainOptRcvrEnSw (TechPtr, 1);
125}
126
127/*----------------------------------------------------------------------------
128 * LOCAL FUNCTIONS
129 *
130 *----------------------------------------------------------------------------
131 */
132
133/* -----------------------------------------------------------------------------*/
134/**
135 *
136 * This function executes receiver enable training for a specific die
137 *
138 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
139 * @param[in] Pass - Pass of the receiver training
140 *
141 * @return TRUE - No fatal error occurs.
142 * @return FALSE - Fatal error occurs.
143 */
144BOOLEAN
145STATIC
146MemTDqsTrainOptRcvrEnSw (
147 IN OUT MEM_TECH_BLOCK *TechPtr,
148 IN UINT8 Pass
149 )
150{
151 _16BYTE_ALIGN UINT8 PatternBuffer[6 * 64];
152 UINT8 TestBuffer[256];
153 UINT8 *PatternBufPtr[6];
154 UINT8 *TempPtr;
155 UINT32 TestAddrRJ16[4];
156 UINT32 TempAddrRJ16;
157 UINT32 RealAddr;
158 UINT16 CurTest[4];
159 UINT8 Dct;
160 UINT8 Receiver;
161 UINT8 i;
162 UINT8 TimesFail;
163 UINT8 TimesRetrain;
164 UINT16 RcvrEnDly;
165 UINT16 MaxRcvrEnDly;
166 UINT16 RcvrEnDlyLimit;
167 UINT16 MaxDelayCha;
168 BOOLEAN IsDualRank;
169 BOOLEAN S0En;
170 BOOLEAN S1En;
171
172
173 MEM_DATA_STRUCT *MemPtr;
174 DIE_STRUCT *MCTPtr;
175 DCT_STRUCT *DCTPtr;
176 MEM_NB_BLOCK *NBPtr;
177
178 NBPtr = TechPtr->NBPtr;
179 MemPtr = NBPtr->MemPtr;
180 MCTPtr = NBPtr->MCTPtr;
181 TechPtr->TrainingType = TRN_RCVR_ENABLE;
182
183
184 TempAddrRJ16 = 0;
185 TempPtr = NULL;
186 MaxDelayCha = 0;
187 TimesRetrain = DEFAULT_TRAINING_TIMES;
188 IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader);
189
190 IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Optimized SW RxEn training\n");
191 // Set environment settings before training
192 MemTBeginTraining (TechPtr);
193
194 PatternBufPtr[0] = PatternBufPtr[2] = PatternBuffer;
195 // These two patterns used for first Test Address
196 MemUFillTrainPattern (TestPattern0, PatternBufPtr[0], 64);
197 // Second Cacheline used for Dummy Read is the inverse of
198 // the first so that is is not mistaken for the real read
199 MemUFillTrainPattern (TestPattern1, PatternBufPtr[0] + 64, 64);
200 PatternBufPtr[1] = PatternBufPtr[3] = PatternBufPtr[0] + 128;
201 // These two patterns used for second Test Address
202 MemUFillTrainPattern (TestPattern1, PatternBufPtr[1], 64);
203 // Second Cacheline used for Dummy Read is the inverse of
204 // the first so that is is not mistaken for the real read
205 MemUFillTrainPattern (TestPattern0, PatternBufPtr[1] + 64, 64);
206
207 // Fill pattern for flush after every sweep
208 PatternBufPtr[4] = PatternBufPtr[0] + 256;
209 MemUFillTrainPattern (TestPattern3, PatternBufPtr[4], 64);
210
211 // Fill pattern for initial dummy read
212 PatternBufPtr[5] = PatternBufPtr[0] + 320;
213 MemUFillTrainPattern (TestPattern4, PatternBufPtr[5], 64);
214
215
216 // Begin receiver enable training
217 AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader));
218 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
219 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
220 NBPtr->SwitchDCT (NBPtr, Dct);
221 DCTPtr = NBPtr->DCTPtr;
222
223 // Set training bit
224 NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 1);
225
226 // Relax Max Latency before training
227 NBPtr->SetMaxLatency (NBPtr, 0xFFFF);
228
229 if (Pass == FIRST_PASS) {
230 TechPtr->InitDQSPos4RcvrEn (TechPtr);
231 }
232
233 // there are four receiver pairs, loosely associated with chipselects.
234 Receiver = DCTPtr->Timings.CsEnabled ? 0 : 8;
235 for (; Receiver < 8; Receiver += 2) {
236 S0En = NBPtr->GetSysAddr (NBPtr, Receiver, &TestAddrRJ16[0]);
237 S1En = NBPtr->GetSysAddr (NBPtr, Receiver + 1, &TestAddrRJ16[2]);
238 if (S0En) {
239 TestAddrRJ16[1] = TestAddrRJ16[0] + BIGPAGE_X8_RJ16;
240 }
241 if (S1En) {
242 TestAddrRJ16[3] = TestAddrRJ16[2] + BIGPAGE_X8_RJ16;
243 }
244 if (S0En && S1En) {
245 IsDualRank = TRUE;
246 } else {
247 IsDualRank = FALSE;
248 }
249 if (S0En || S1En) {
250 IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", Receiver);
251
252 RcvrEnDlyLimit = 0x1FF; // @attention - limit depends on proc type
253 TechPtr->DqsRcvEnSaved = 0;
254 RcvrEnDly = RcvrEnDlyLimit;
255 RealAddr = 0;
256
257 TechPtr->GetFirstPassVal = FALSE;
258 TechPtr->DqsRcvEnFirstPassVal = 0;
259 TechPtr->RevertPassVal = FALSE;
260 TechPtr->InitializeVariablesOpt (TechPtr);
261
262 // Write the test patterns
263 AGESA_TESTPOINT (TpProcMemRcvrWritePattern, &(MemPtr->StdHeader));
264 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to addresses: ");
265 for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
266 RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
267 // One cacheline of data to be tested and one of dummy data
268 MemUWriteCachelines (RealAddr, PatternBufPtr[i], 2);
269 // This is dummy data with a different pattern used for the first dummy read.
270 MemUWriteCachelines (RealAddr + 128, PatternBufPtr[5], 1);
271 IDS_HDT_CONSOLE (MEM_FLOW, " %04x0000 ", TestAddrRJ16[i]);
272 }
273 IDS_HDT_CONSOLE (MEM_FLOW, "\n");
274
275 // Sweep receiver enable delays
276 AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader));
277 TimesFail = 0;
278 ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain)
279 {
280 TechPtr->LoadInitialRcvrEnDlyOpt (TechPtr, Receiver);
281 while (!TechPtr->CheckRcvrEnDlyLimitOpt (TechPtr)) {
282 AGESA_TESTPOINT (TpProcMemRcvrSetDelay, &(MemPtr->StdHeader));
283 TechPtr->SetRcvrEnDlyOpt (TechPtr, Receiver, RcvrEnDly);
284 // Read and compare the first beat of data
285 for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) {
286 AGESA_TESTPOINT (TpProcMemRcvrReadPattern, &(MemPtr->StdHeader));
287 RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr);
288 //
289 // Issue dummy cacheline reads
290 //
291 MemUReadCachelines (TestBuffer + 128, RealAddr + 128, 1);
292 MemUReadCachelines (TestBuffer, RealAddr, 1);
293 MemUProcIOClFlush (TestAddrRJ16[i], 2, MemPtr);
294 //
295 // Perform actual read which will be compared
296 //
297 MemUReadCachelines (TestBuffer + 64, RealAddr + 64, 1);
298 AGESA_TESTPOINT (TpProcMemRcvrTestPattern, &(MemPtr->StdHeader));
299 CurTest[i] = TechPtr->Compare1ClPatternOpt (TechPtr, TestBuffer + 64 , PatternBufPtr[i] + 64, i, Receiver, S1En);
300 // Due to speculative execution during MemUReadCachelines, we must
301 // flush one more cache line than we read.
302 MemUProcIOClFlush (TestAddrRJ16[i], 4, MemPtr);
303 TechPtr->ResetDCTWrPtr (TechPtr, Receiver);
304
305 //
306 // Swap the test pointers such that even and odd steps alternate.
307 //
308 if ((i % 2) == 0) {
309 TempPtr = PatternBufPtr[i];
310 PatternBufPtr[i] = PatternBufPtr[i + 1];
311
312 TempAddrRJ16 = TestAddrRJ16[i];
313 TestAddrRJ16[i] = TestAddrRJ16[i + 1];
314 } else {
315 PatternBufPtr[i] = TempPtr;
316 TestAddrRJ16[i] = TempAddrRJ16;
317 }
318 }
319 } // End of delay sweep
320 ERROR_HANDLE_RETRAIN_END (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, TRUE), TimesFail)
321 }
322
323 if (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, FALSE)) {
324 return FALSE;
325 }
326
327 TechPtr->LoadRcvrEnDlyOpt (TechPtr, Receiver); // set final delays
328 //
329 // Flush AA and 55 patterns by reading a dummy pattern to fill in FIFO
330 //
331 // Aquire a new FSBase, based on the last test address that we stored.
332 RealAddr = MemUSetUpperFSbase (TempAddrRJ16, MemPtr);
333 ASSERT (RealAddr != 0);
334 MemUWriteCachelines (RealAddr, PatternBufPtr[4], 1);
335 MemUWriteCachelines (RealAddr + 64, PatternBufPtr[4], 1);
336 MemUReadCachelines (TestBuffer, RealAddr, 2);
337 // Due to speculative execution during MemUReadCachelines, we must
338 // flush one more cache line than we read.
339 MemUProcIOClFlush (TempAddrRJ16, 3, MemPtr);
340 }
341 } // End while Receiver < 8
342
343 // Clear training bit when done
344 NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 0);
345
346 // Set Max Latency for both channels
347 MaxRcvrEnDly = TechPtr->GetMaxValueOpt (TechPtr);
348 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRcvrEnDly: %03x\n", MaxRcvrEnDly);
349 if (MCTPtr->GangedMode) {
350 if (Dct == 0) {
351 MaxDelayCha = MaxRcvrEnDly;
352 } else if (MaxRcvrEnDly > MaxDelayCha) {
353 NBPtr->SwitchDCT (NBPtr, 0);
354 NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
355 }
356 } else {
357 NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly);
358 }
359 TechPtr->ResetDCTWrPtr (TechPtr, 6);
360 }
361
362 // Restore environment settings after training
363 MemTEndTraining (TechPtr);
364 IDS_HDT_CONSOLE (MEM_FLOW, "End Optimized SW RxEn training\n\n");
365 return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
366}
367
368/*-----------------------------------------------------------------------------
369 *
370 * This function saves passing DqsRcvEnDly values to the stack
371 *
372 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
373 * @param[in] Receiver - Current Chip select value
374 * @param[in] RcvEnDly - receiver enable delay to be saved
375 * @param[in] cmpResultRank0 - compare result for Rank 0
376 * @param[in] cmpResultRank0 - compare result for Rank 1
377 *
378 * @retval TRUE - All bytelanes pass
379 * FALSE - Some bytelanes fail
380 * ----------------------------------------------------------------------------
381 */
382
383BOOLEAN
384MemTSaveRcvrEnDlyByteFilterOpt (
385 IN OUT MEM_TECH_BLOCK *TechPtr,
386 IN UINT8 Receiver,
387 IN UINT16 RcvEnDly,
388 IN UINT16 CmpResultRank0,
389 IN UINT16 CmpResultRank1
390 )
391{
392 UINT8 i;
393 UINT8 Passed;
394 UINT8 Dimm;
395 CH_DEF_STRUCT *ChannelPtr;
396
397 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
398 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
399
400 Passed = (UINT8) ((CmpResultRank0 & CmpResultRank1) & 0xFF);
401
402 Dimm = Receiver >> 1;
403
404 if (TechPtr->GetFirstPassVal && (RcvEnDly - TechPtr->DqsRcvEnFirstPassVal) >= 0x30) {
405 for (i = 0; i < 8; i++) {
406 ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + i] = TechPtr->DqsRcvEnFirstPassVal + NEW_RECEIVER_FINAL_OFFSETVALUE;
407 }
408 TechPtr->DqsRcvEnSaved = 0xFF;
409 }
410
411 if (Passed == 0xFF) {
412 if (!TechPtr->GetFirstPassVal) {
413 TechPtr->DqsRcvEnFirstPassVal = RcvEnDly;
414 TechPtr->GetFirstPassVal = TRUE;
415 }
416 return TRUE;
417 } else {
418 TechPtr->DqsRcvEnFirstPassVal = 0;
419
420 // We have got first passing value, but later, we meet with glitch
421 if (TechPtr->GetFirstPassVal) {
422 TechPtr->DqsRcvEnFirstPassVal = 0xFF;
423 TechPtr->GetFirstPassVal = FALSE;
424 }
425 return FALSE;
426 }
427}