7 * Technology Software based DQS receiver enable training Recovery
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Proc/Recovery/Mem)
12 * @e \$Revision: 52180 $ @e \$Date: 2011-05-03 05:17:25 -0600 (Tue, 03 May 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"
67 #define FILECODE PROC_RECOVERY_MEM_TECH_MRTTSRC_FILECODE
68 /*----------------------------------------------------------------------------
69 * DEFINITIONS AND MACROS
71 *----------------------------------------------------------------------------
73 #define MAX_BYTELANES 8 /* Max Bytelanes per channel */
75 /*----------------------------------------------------------------------------
76 * TYPEDEFS AND STRUCTURES
78 *----------------------------------------------------------------------------
81 /*----------------------------------------------------------------------------
82 * PROTOTYPES OF LOCAL FUNCTIONS
84 *----------------------------------------------------------------------------
91 IN OUT MEM_TECH_BLOCK *TechPtr,
98 MemRecTLoadRcvrEnDly (
99 IN OUT MEM_TECH_BLOCK *TechPtr,
105 MemRecTSaveRcvrEnDly (
106 IN OUT MEM_TECH_BLOCK *TechPtr,
114 MemRecTCompare1ClPattern (
117 IN OUT AMD_CONFIG_PARAMS *StdHeader
120 /*----------------------------------------------------------------------------
123 *----------------------------------------------------------------------------
126 /* -----------------------------------------------------------------------------*/
129 * This function executes receiver enable training for BSP
131 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
136 MemRecTTrainRcvrEnSw (
137 IN OUT MEM_TECH_BLOCK *TechPtr
140 _16BYTE_ALIGN UINT8 PatternBuffer[3 * 64];
141 UINT8 TestBuffer[120];
142 UINT8 *PatternBufPtr[2];
150 MEM_DATA_STRUCT *MemPtr;
154 NBPtr = TechPtr->NBPtr;
155 MemPtr = NBPtr->MemPtr;
156 MCTPtr = NBPtr->MCTPtr;
158 AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader));
160 // Set environment settings before training
161 MemRecTBeginTraining (TechPtr);
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));
168 // Begin receiver enable training
169 MemRecTSetWrDatRdDqs (TechPtr, 0);
171 // there are four receiver pairs, loosely associated with chipselects.
172 Receiver = NBPtr->DimmToBeUsed << 1;
173 TechPtr->DqsRcvEnSaved = 0;
175 TestAddr[0] = NBPtr->GetSysAddrRec ();
176 TestAddr[1] = TestAddr[0] + BIGPAGE_X8;
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]);
182 // Sweep receiver enable delays
183 AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader));
184 for (RcvrEnDly = 0; RcvrEnDly < 0xFF; RcvrEnDly++) {
187 for (i = 0; i < 2; i++) {
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);
194 // Swap the test pointers such that even and odd steps alternate.
195 j = ((RcvrEnDly & 1) != 0) ? (i ^ 1) : i;
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);
207 if (MemRecTSaveRcvrEnDly (TechPtr, Receiver, RcvrEnDly, TestResult)) {
208 // if all bytelanes pass
211 } // End of delay sweep
213 if (RcvrEnDly == 0xFF) {
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);
220 MemRecTLoadRcvrEnDly (TechPtr, Receiver);
222 // Clear training bit when done
223 NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 0);
225 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRcvrEnDly: %03x\n", RcvrEnDly + 0x20);
227 // Set Max Latency for both channels
228 NBPtr->SetMaxLatency (NBPtr, RcvrEnDly + 0x20);
230 // Restore environment settings after training
231 MemRecTEndTraining (TechPtr);
234 /* -----------------------------------------------------------------------------*/
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.
241 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
242 * @param[in] WrDatDly - either 0 or 0x0F
247 MemRecTSetWrDatRdDqs (
248 IN OUT MEM_TECH_BLOCK *TechPtr,
258 NBPtr = TechPtr->NBPtr;
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);
271 /* -----------------------------------------------------------------------------*/
274 * This function programs DqsRcvEnDly to additional index for DQS receiver enabled training
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
284 MemRecTSetRcvrEnDly (
285 IN OUT MEM_TECH_BLOCK *TechPtr,
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);
299 /* -----------------------------------------------------------------------------*/
302 * This function compares test pattern with data in buffer and return a pass/fail bitmap
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.
309 * @return PASS - Bit map of results of comparison
314 MemRecTCompare1ClPattern (
317 IN OUT AMD_CONFIG_PARAMS *StdHeader
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
330 IDS_HDT_CONSOLE (MEM_FLOW, " %c", (Buffer[i] == Pattern[i]) ? 'P' : '.');
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]);
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]);
342 IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
348 /* -----------------------------------------------------------------------------*/
351 * This function saves passing DqsRcvEnDly values to the stack
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
358 * @return TRUE - All bytelanes pass
359 * @return FALSE - Some bytelanes fail
364 MemRecTSaveRcvrEnDly (
365 IN OUT MEM_TECH_BLOCK *TechPtr,
377 ASSERT (Receiver <= MAX_CS_PER_CHANNEL);
380 Saved = (UINT8) (TechPtr->DqsRcvEnSaved & Passed); //@todo - false passes filter (subject to be replaced with a better solution)
381 Dimm = Receiver >> 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);
393 TechPtr->DqsRcvEnSaved = Saved;
402 /* -----------------------------------------------------------------------------*/
405 * This function loads the DqsRcvEnDly from saved data and program to additional index
406 * for DQS receiver enabled training
408 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
409 * @param[in] Receiver - Current Chip select value
415 MemRecTLoadRcvrEnDly (
416 IN OUT MEM_TECH_BLOCK *TechPtr,
423 CH_DEF_STRUCT *ChannelPtr;
425 ASSERT (Receiver <= MAX_CS_PER_CHANNEL);
426 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
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]);