7 * Technology Dimm Based Training
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/Tech)
12 * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 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 *----------------------------------------------------------------------------
60 #include "GeneralServices.h"
61 #include "heapManager.h"
66 #define FILECODE PROC_MEM_TECH_MTTDIMBT_FILECODE
68 /*----------------------------------------------------------------------------
69 * DEFINITIONS AND MACROS
71 *----------------------------------------------------------------------------
74 /*----------------------------------------------------------------------------
75 * TYPEDEFS AND STRUCTURES
77 *----------------------------------------------------------------------------
80 /*----------------------------------------------------------------------------
81 * PROTOTYPES OF LOCAL FUNCTIONS
83 *----------------------------------------------------------------------------
88 MemTInitDqsPos4RcvrEnByte (
89 IN OUT MEM_TECH_BLOCK *TechPtr
94 MemTSetRcvrEnDlyByte (
95 IN OUT MEM_TECH_BLOCK *TechPtr,
102 MemTLoadRcvrEnDlyByte (
103 IN OUT MEM_TECH_BLOCK *TechPtr,
109 MemTSaveRcvrEnDlyByte (
110 IN OUT MEM_TECH_BLOCK *TechPtr,
113 IN UINT16 CmpResultRank0,
114 IN UINT16 CmpResultRank1
119 MemTResetDctWrPtrByte (
120 IN OUT MEM_TECH_BLOCK *TechPtr,
126 MemTCompare1ClPatternByte (
127 IN OUT MEM_TECH_BLOCK *TechPtr,
134 MemTSkipChipSelPass1Byte (
135 IN OUT MEM_TECH_BLOCK *TechPtr,
136 IN OUT UINT8 *ChipSelPtr
141 MemTSkipChipSelPass2Byte (
142 IN OUT MEM_TECH_BLOCK *TechPtr,
143 IN OUT UINT8 *ChipSelPtr
148 MemTMaxByteLanesByte ( VOID );
152 MemTDlyTableWidthByte ( VOID );
156 MemTSetDqsDelayCsrByte (
157 IN OUT MEM_TECH_BLOCK *TechPtr,
164 MemTDqsWindowSaveByte (
165 IN OUT MEM_TECH_BLOCK *TechPtr,
173 MemTFindMaxRcvrEnDlyByte (
174 IN OUT MEM_TECH_BLOCK *TechPtr,
180 MemTCompare1ClPatternOptByte (
181 IN OUT MEM_TECH_BLOCK *TechPtr,
191 MemTLoadRcvrEnDlyOptByte (
192 IN OUT MEM_TECH_BLOCK *TechPtr,
198 MemTSetRcvrEnDlyOptByte (
199 IN OUT MEM_TECH_BLOCK *TechPtr,
206 MemTLoadInitialRcvEnDlyOptByte (
207 IN OUT MEM_TECH_BLOCK *TechPtr,
213 MemTFindMinMaxGrossDlyByte (
214 IN OUT MEM_TECH_BLOCK *TechPtr,
215 IN TRN_DLY_TYPE TrnDlyType,
218 /*----------------------------------------------------------------------------
221 *----------------------------------------------------------------------------
225 /* -----------------------------------------------------------------------------*/
228 * This function enables byte based training if called
230 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
235 MemTDimmByteTrainInit (
236 IN OUT MEM_TECH_BLOCK *TechPtr
244 ALLOCATE_HEAP_PARAMS AllocHeapParams;
247 NBPtr = TechPtr->NBPtr;
248 MCTPtr = NBPtr->MCTPtr;
250 TechPtr->InitDQSPos4RcvrEn = MemTInitDqsPos4RcvrEnByte;
251 TechPtr->SetRcvrEnDly = MemTSetRcvrEnDlyByte;
252 TechPtr->LoadRcvrEnDly = MemTLoadRcvrEnDlyByte;
253 TechPtr->SaveRcvrEnDly = MemTSaveRcvrEnDlyByte;
254 TechPtr->SaveRcvrEnDlyFilter = MemTSaveRcvrEnDlyByteFilterOpt;
255 TechPtr->ResetDCTWrPtr = MemTResetDctWrPtrByte;
256 TechPtr->Compare1ClPattern = MemTCompare1ClPatternByte;
257 TechPtr->SkipChipSelPass1 = MemTSkipChipSelPass1Byte;
258 TechPtr->SkipChipSelPass2 = MemTSkipChipSelPass2Byte;
259 TechPtr->MaxByteLanes = MemTMaxByteLanesByte;
260 TechPtr->DlyTableWidth = MemTDlyTableWidthByte;
261 TechPtr->SetDQSDelayCSR = MemTSetDqsDelayCsrByte;
262 TechPtr->DQSWindowSave = MemTDqsWindowSaveByte;
263 TechPtr->FindMaxDlyForMaxRdLat = MemTFindMaxRcvrEnDlyByte;
264 TechPtr->Compare1ClPatternOpt = MemTCompare1ClPatternOptByte;
265 TechPtr->LoadRcvrEnDlyOpt = MemTLoadRcvrEnDlyOptByte;
266 TechPtr->SetRcvrEnDlyOpt = MemTSetRcvrEnDlyOptByte;
267 TechPtr->InitializeVariablesOpt = MemTInitializeVariablesOptByte;
268 TechPtr->GetMaxValueOpt = MemTGetMaxValueOptByte;
269 TechPtr->SetSweepErrorOpt = MemTSetSweepErrorOptByte;
270 TechPtr->CheckRcvrEnDlyLimitOpt = MemTCheckRcvrEnDlyLimitOptByte;
271 TechPtr->LoadInitialRcvrEnDlyOpt = MemTLoadInitialRcvEnDlyOptByte;
272 TechPtr->GetMinMaxGrossDly = MemTFindMinMaxGrossDlyByte;
273 // Dynamically allocate buffers for storing trained timings.
274 DctCount = MCTPtr->DctCount;
275 ChannelCount = MCTPtr->DctData[0].ChannelCount;
276 AllocHeapParams.RequestedBufferSize = ((DctCount * ChannelCount) *
277 ((MAX_DIMMS * MAX_DELAYS * NUMBER_OF_DELAY_TABLES) +
278 (MAX_DELAYS * MAX_CS_PER_CHANNEL * NUMBER_OF_FAILURE_MASK_TABLES) +
279 (MAX_DIMMS * MAX_NUMBER_LANES)
283 if (NBPtr->MemPstateStage == MEMORY_PSTATE_1ST_STAGE) {
284 AllocHeapParams.RequestedBufferSize *= 2;
287 AllocHeapParams.BufferHandle = GENERATE_MEM_HANDLE (ALLOC_TRN_DATA_HANDLE, MCTPtr->NodeId, 0, 0);
288 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
289 if (HeapAllocateBuffer (&AllocHeapParams, &NBPtr->MemPtr->StdHeader) == AGESA_SUCCESS) {
290 for (Dct = 0; Dct < DctCount; Dct++) {
291 for (Channel = 0; Channel < ChannelCount; Channel++) {
292 MCTPtr->DctData[Dct].ChData[Channel].RowCount = MAX_DIMMS;
293 MCTPtr->DctData[Dct].ChData[Channel].ColumnCount = MAX_DELAYS;
295 MCTPtr->DctData[Dct].ChData[Channel].RcvEnDlys = (UINT16 *) AllocHeapParams.BufferPtr;
296 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS) * 2;
297 MCTPtr->DctData[Dct].ChData[Channel].WrDqsDlys = AllocHeapParams.BufferPtr;
298 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
299 MCTPtr->DctData[Dct].ChData[Channel].RdDqsDlys = AllocHeapParams.BufferPtr;
300 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
301 MCTPtr->DctData[Dct].ChData[Channel].WrDatDlys = AllocHeapParams.BufferPtr;
302 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
303 MCTPtr->DctData[Dct].ChData[Channel].RdDqs__Dlys = AllocHeapParams.BufferPtr;
304 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_NUMBER_LANES);
305 MCTPtr->DctData[Dct].ChData[Channel].RdDqsMinDlys = AllocHeapParams.BufferPtr;
306 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
307 MCTPtr->DctData[Dct].ChData[Channel].RdDqsMaxDlys = AllocHeapParams.BufferPtr;
308 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
309 MCTPtr->DctData[Dct].ChData[Channel].WrDatMinDlys = AllocHeapParams.BufferPtr;
310 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
311 MCTPtr->DctData[Dct].ChData[Channel].WrDatMaxDlys = AllocHeapParams.BufferPtr;
312 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
313 MCTPtr->DctData[Dct].ChData[Channel].FailingBitMask = AllocHeapParams.BufferPtr;
314 AllocHeapParams.BufferPtr += (MAX_CS_PER_CHANNEL * MAX_DELAYS);
315 if (NBPtr->MemPstateStage == MEMORY_PSTATE_1ST_STAGE) {
316 MCTPtr->DctData[Dct].ChData[Channel].RcvEnDlysMemPs1 = (UINT16 *) AllocHeapParams.BufferPtr;
317 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS) * 2;
318 MCTPtr->DctData[Dct].ChData[Channel].WrDqsDlysMemPs1 = AllocHeapParams.BufferPtr;
319 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
320 MCTPtr->DctData[Dct].ChData[Channel].RdDqsDlysMemPs1 = AllocHeapParams.BufferPtr;
321 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
322 MCTPtr->DctData[Dct].ChData[Channel].WrDatDlysMemPs1 = AllocHeapParams.BufferPtr;
323 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
324 MCTPtr->DctData[Dct].ChData[Channel].RdDqs__DlysMemPs1 = AllocHeapParams.BufferPtr;
325 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_NUMBER_LANES);
326 MCTPtr->DctData[Dct].ChData[Channel].RdDqsMinDlysMemPs1 = AllocHeapParams.BufferPtr;
327 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
328 MCTPtr->DctData[Dct].ChData[Channel].RdDqsMaxDlysMemPs1 = AllocHeapParams.BufferPtr;
329 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
330 MCTPtr->DctData[Dct].ChData[Channel].WrDatMinDlysMemPs1 = AllocHeapParams.BufferPtr;
331 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
332 MCTPtr->DctData[Dct].ChData[Channel].WrDatMaxDlysMemPs1 = AllocHeapParams.BufferPtr;
333 AllocHeapParams.BufferPtr += (MAX_DIMMS * MAX_DELAYS);
334 MCTPtr->DctData[Dct].ChData[Channel].FailingBitMaskMemPs1 = AllocHeapParams.BufferPtr;
335 AllocHeapParams.BufferPtr += (MAX_CS_PER_CHANNEL * MAX_DELAYS);
341 PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_DYN_STORING_OF_TRAINED_TIMINGS, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
342 SetMemError (AGESA_FATAL, MCTPtr);
343 ASSERT(FALSE); // Could not dynamically allocate buffers for storing trained timings
348 /* -----------------------------------------------------------------------------*/
351 * This function initializes the DQS Positions in preparation for Receiver Enable Training.
352 * Write Position is no delay, Read Position is 1/2 Memclock delay
354 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
360 MemTInitDqsPos4RcvrEnByte (
361 IN OUT MEM_TECH_BLOCK *TechPtr
368 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
369 for (ByteLane = 0; ByteLane < MAX_DELAYS; ByteLane++) {
370 WrDqs = TechPtr->NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_DELAYS) + ByteLane];
371 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), WrDqs);
372 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), 0x3F);
377 /* -----------------------------------------------------------------------------*/
380 * This function programs DqsRcvEnDly to additional index for DQS receiver enabled training
382 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
383 * @param[in] Receiver - Current Chip select value
384 * @param[in] RcvEnDly - receiver enable delay to be saved
389 MemTSetRcvrEnDlyByte (
390 IN OUT MEM_TECH_BLOCK *TechPtr,
397 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
398 for (ByteLane = 0; ByteLane < MAX_BYTELANES; ByteLane++) {
399 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, ByteLane), RcvEnDly);
403 /* -----------------------------------------------------------------------------*/
406 * This function loads the DqsRcvEnDly from saved data and program to additional index
407 * for DQS receiver enabled training
409 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
410 * @param[in] Receiver - Current Chip select value
416 MemTLoadRcvrEnDlyByte (
417 IN OUT MEM_TECH_BLOCK *TechPtr,
424 CH_DEF_STRUCT *ChannelPtr;
426 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
427 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
429 Dimm = Receiver >> 1;
430 Saved = TechPtr->DqsRcvEnSaved;
431 for (i = 0; i < MAX_BYTELANES; i++) {
433 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, i),
434 ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i]);
440 /* -----------------------------------------------------------------------------*/
443 * This function saves passing DqsRcvEnDly values to the stack
445 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
446 * @param[in] Receiver - Current Chip select value
447 * @param[in] RcvEnDly - receiver enable delay to be saved
448 * @param[in] CmpResultRank0 - compare result for Rank 0
449 * @param[in] CmpResultRank1 - compare result for Rank 1
451 * @return TRUE - All bytelanes pass
452 * @return FALSE - Some bytelanes fail
457 MemTSaveRcvrEnDlyByte (
458 IN OUT MEM_TECH_BLOCK *TechPtr,
461 IN UINT16 CmpResultRank0,
462 IN UINT16 CmpResultRank1
470 CH_DEF_STRUCT *ChannelPtr;
472 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
473 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
475 Passed = (UINT8) ((CmpResultRank0 & CmpResultRank1) & 0xFF);
477 Saved = (UINT8) (TechPtr->DqsRcvEnSaved & Passed); //@attention - false passes filter (subject to be replaced with a better solution)
478 Dimm = Receiver >> 1;
480 for (i = 0; i < MAX_BYTELANES; i++) {
482 if (!(Saved & Mask)) {
483 ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i] = RcvEnDly + 0x20; // @attention -1 pass only
484 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tBL %d = %02x", i, RcvEnDly + 0x20);
490 TechPtr->DqsRcvEnSaved = Saved;
499 /* -----------------------------------------------------------------------------*/
502 * This function performs a filtering functionality and saves passing DqsRcvEnDly
503 * values to the stack
505 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
506 * @param[in] Receiver - Current Chip select value
507 * @param[in] RcvEnDly - receiver enable delay to be saved
508 * @param[in] CmpResultRank0 - compare result for Rank 0
509 * @param[in] CmpResultRank1 - compare result for Rank 1
511 * @return TRUE - All bytelanes pass
512 * @return FALSE - Some bytelanes fail
516 MemTSaveRcvrEnDlyByteFilter (
517 IN OUT MEM_TECH_BLOCK *TechPtr,
520 IN UINT16 CmpResultRank0,
521 IN UINT16 CmpResultRank1
530 CH_DEF_STRUCT *ChannelPtr;
531 MEM_DCT_CACHE *DctCachePtr;
533 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
534 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
535 DctCachePtr = TechPtr->NBPtr->DctCachePtr;
537 MaxFilterDly = TechPtr->MaxFilterDly;
538 Passed = (UINT8) ((CmpResultRank0 & CmpResultRank1) & 0xFF);
540 Dimm = Receiver >> 1;
541 Saved = (UINT8) TechPtr->DqsRcvEnSaved;
543 for (i = 0; i < MAX_BYTELANES; i++) {
544 if ((Passed & Mask) != 0) {
545 DctCachePtr->RcvEnDlyCounts [i] += 1;
546 if ((Saved & Mask) == 0) {
547 ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i] = RcvEnDly + 0x20;
549 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tBL %d = %02x", i, RcvEnDly + 0x20);
552 if (DctCachePtr->RcvEnDlyCounts [i] <= MaxFilterDly) {
553 DctCachePtr->RcvEnDlyCounts [i] = 0;
560 //-----------------------
561 TechPtr->DqsRcvEnSaved = (UINT16) Saved;
564 for (i = 0; i < MAX_BYTELANES; i++) {
565 if (DctCachePtr->RcvEnDlyCounts [i] >= MaxFilterDly) {
566 Saved |= (UINT8) 1 << i;
577 /* -----------------------------------------------------------------------------*/
580 * This function compares test pattern with data in buffer and return a pass/fail bitmap
583 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
584 * @param[in] Buffer[] - Buffer data from DRAM (Measured data from DRAM) to compare
585 * @param[in] Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against
587 * @return PASS - Bit map of results of comparison
592 MemTCompare1ClPatternByte (
593 IN OUT MEM_TECH_BLOCK *TechPtr,
603 MCTPtr = TechPtr->NBPtr->MCTPtr;
604 if (MCTPtr->GangedMode && MCTPtr->Dct) {
611 IDS_HDT_CONSOLE (MEM_FLOW, " -");
612 for (i = 0; i < 8; i++) {
613 if (Buffer[j] != Pattern[j]) {
614 // if bytelane n fails
615 Pass &= ~((UINT16)1 << (j % 8)); // clear bit n
617 IDS_HDT_CONSOLE (MEM_FLOW, " %c", (Buffer[j] == Pattern[j]) ? 'P' : '.');
621 IDS_HDT_CONSOLE_DEBUG_CODE (
622 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t -");
623 for (i = 0, j -= 8; i < 8; i++, j++) {
624 IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Buffer[j]);
626 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t -");
627 for (i = 0, j -= 8; i < 8; i++, j++) {
628 IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Pattern[j]);
630 IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
636 /* -----------------------------------------------------------------------------*/
639 * The function resets the DCT input buffer write pointer.
641 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
642 * @param[in] Receiver - Chip select
648 MemTResetDctWrPtrByte (
649 IN OUT MEM_TECH_BLOCK *TechPtr,
656 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
657 for (i = 0; i < MAX_BYTELANES; i++) {
658 RcvEnDly = (UINT16) TechPtr->NBPtr->GetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver / 2, i));
659 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver / 2, i), RcvEnDly);
663 /* -----------------------------------------------------------------------------*/
666 * This function skips odd chip select if training at 800MT or above.
668 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
669 * @param[in] *ChipSelPtr - Pointer to variable contains Chip select index
675 MemTSkipChipSelPass1Byte (
676 IN OUT MEM_TECH_BLOCK *TechPtr,
677 IN OUT UINT8 *ChipSelPtr
682 NBPtr = TechPtr->NBPtr;
683 // if the even chip select failed training, need to set CsTrainFail for odd chip select if present.
684 if (NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ((*ChipSelPtr) + 1))) {
685 if (NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16)1 << *ChipSelPtr)) {
686 NBPtr->DCTPtr->Timings.CsTrainFail |= (UINT16)1 << ((*ChipSelPtr) + 1);
687 if (!NBPtr->MemPtr->ErrorHandling (NBPtr->MCTPtr, NBPtr->Dct, NBPtr->DCTPtr->Timings.CsTrainFail, &NBPtr->MemPtr->StdHeader)) {
695 /* -----------------------------------------------------------------------------*/
698 * MemTSkipChipSelPass2Byte:
700 * This function skips odd chip select if training at 800MT or above.
702 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
703 * @param[in,out] *ChipSelPtr - Pointer to variable contains Chip select index
709 MemTSkipChipSelPass2Byte (
710 IN OUT MEM_TECH_BLOCK *TechPtr,
711 IN OUT UINT8 *ChipSelPtr
714 if (*ChipSelPtr & 1) {
715 *ChipSelPtr = MAX_CS_PER_CHANNEL; // skip all successions
719 /* -----------------------------------------------------------------------------*/
722 * This function determines the maximum number of byte lanes
724 * @return Max number of Bytelanes
729 MemTMaxByteLanesByte ( VOID )
731 return MAX_BYTELANES;
734 /* -----------------------------------------------------------------------------*/
737 * This function determines the width of the delay tables (eg. RcvEnDlys, WrDqsDlys,...)
739 * @return Delay table width in bytes
744 MemTDlyTableWidthByte ( VOID )
749 /* -----------------------------------------------------------------------------*/
752 * This function writes the Delay value to a certain byte lane
754 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
755 * @param[in] ByteLane - Bytelane number being targeted
756 * @param[in] Dly - Delay value
762 MemTSetDqsDelayCsrByte (
763 IN OUT MEM_TECH_BLOCK *TechPtr,
771 ASSERT (ByteLane <= MAX_BYTELANES);
773 if (!(TechPtr->DqsRdWrPosSaved & ((UINT8)1 << ByteLane))) {
774 Dimm = (TechPtr->ChipSel >> 1);
776 if (TechPtr->Direction == DQS_WRITE_DIR) {
777 Dly = Dly + ((UINT8) TechPtr->NBPtr->ChannelPtr->WrDqsDlys[(Dimm * MAX_DELAYS) + ByteLane]);
778 Reg = AccessWrDatDly;
780 Reg = AccessRdDqsDly;
783 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, Reg, DIMM_BYTE_ACCESS (Dimm, ByteLane), Dly);
787 /* -----------------------------------------------------------------------------*/
790 * This function programs the trained DQS delay for the specified byte lane
791 * and stores its DQS window for reference.
793 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
794 * @param[in] ByteLane - Bytelane number being targeted
795 * @param[in] DlyMin - Minimum delay value
796 * @param[in] DlyMax- Maximum delay value
802 MemTDqsWindowSaveByte (
803 IN OUT MEM_TECH_BLOCK *TechPtr,
811 CH_DEF_STRUCT *ChanPtr;
813 ASSERT (ByteLane <= MAX_BYTELANES);
814 ChanPtr = TechPtr->NBPtr->ChannelPtr;
816 DqsDelay = ((DlyMin + DlyMax + 1) / 2) & 0x3F;
817 MemTSetDqsDelayCsrByte (TechPtr, ByteLane, DqsDelay);
818 TechPtr->DqsRdWrPosSaved |= (UINT8)1 << ByteLane;
819 TechPtr->DqsRdWrPosSaved |= 0xFF00;
821 Dimm = (TechPtr->ChipSel / 2) * MAX_DELAYS + ByteLane;
822 if (TechPtr->Direction == DQS_READ_DIR) {
823 ChanPtr->RdDqsDlys[Dimm] = DqsDelay;
825 ChanPtr->WrDatDlys[Dimm] = DqsDelay + ChanPtr->WrDqsDlys[Dimm];
828 if (TechPtr->Direction == DQS_READ_DIR) {
829 ChanPtr->RdDqsMinDlys[ByteLane] = DlyMin;
830 ChanPtr->RdDqsMaxDlys[ByteLane] = DlyMax;
832 ChanPtr->WrDatMinDlys[ByteLane] = DlyMin;
833 ChanPtr->WrDatMaxDlys[ByteLane] = DlyMax;
839 /* -----------------------------------------------------------------------------*/
842 * This function finds the DIMM that has the largest receiver enable delay.
844 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
845 * @param[out] *ChipSel - Pointer to the Chip select that has the largest receiver enable delay.
847 * @return TRUE - A chip select can be found.
848 * @return FALSE - A chip select cannot be found.
853 MemTFindMaxRcvrEnDlyByte (
854 IN OUT MEM_TECH_BLOCK *TechPtr,
866 CH_DEF_STRUCT *ChannelPtr;
868 NBPtr = TechPtr->NBPtr;
869 ChannelPtr = NBPtr->ChannelPtr;
874 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
875 if ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << (Dimm << 1))) != 0) {
876 if ((NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16) 3 << (Dimm << 1))) == 0) {
877 // Only choose the dimm that does not fail training
878 for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
879 RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + ByteLane];
880 if (RcvEnDly > MaxDly) {
890 if (NBPtr->MCTPtr->Status[Sb128bitmode] != 0) {
891 //The RcvrEnDlys of DCT1 DIMMs should also be considered while ganging.
892 NBPtr->SwitchDCT (NBPtr, 1);
893 ChannelPtr = NBPtr->ChannelPtr;
894 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
895 for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
896 RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + ByteLane];
897 if (RcvEnDly > MaxDly) {
903 NBPtr->SwitchDCT (NBPtr, 0);
906 TechPtr->MaxDlyForMaxRdLat = MaxDly;
907 *ChipSel = (MaxDlyDimm * 2);
911 /* -----------------------------------------------------------------------------*/
914 * This function finds the DIMM that has the largest receiver enable delay + Read DQS Delay.
916 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
917 * @param[out] *ChipSel - Pointer to the Chip select that has the largest receiver enable delay
920 * @return TRUE - A chip select can be found.
921 * @return FALSE - A chip select cannot be found.
925 MemTFindMaxRcvrEnDlyRdDqsDlyByte (
926 IN OUT MEM_TECH_BLOCK *TechPtr,
940 CH_DEF_STRUCT *ChannelPtr;
942 NBPtr = TechPtr->NBPtr;
943 ChannelPtr = NBPtr->ChannelPtr;
948 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
949 if ((NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16) 3 << (Dimm << 1))) == 0) {
950 // Only choose the dimm that does not fail training
951 for (ByteLane = 0; ByteLane < MAX_BYTELANES; ByteLane++) {
952 RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + ByteLane];
953 // Before Dqs Position Training, this value is 0. So the maximum value for
954 // RdDqsDly needs to be added later when calculating the MaxRdLatency value
955 // after RcvEnDly training but before DQS Position Training.
956 RdDqsDly = ChannelPtr->RdDqsDlys[Dimm * MAX_DELAYS + ByteLane];
957 TotalDly = RcvEnDly + (RdDqsDly >> 1);
958 if (TotalDly > MaxDly) {
967 TechPtr->MaxDlyForMaxRdLat = MaxDly;
968 *ChipSel = (MaxDlyDimm * 2);
972 /* -----------------------------------------------------------------------------*/
975 * This function finds the DIMM that has the largest receiver enable delay + Read DQS Delay for UNB
977 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
978 * @param[out] *ChipSel - Pointer to the Chip select that has the largest receiver enable delay
981 * @return TRUE - A chip select can be found.
982 * @return FALSE - A chip select cannot be found.
986 MemTFindMaxRcvrEnDlyRdDqsDlyByteUnb (
987 IN OUT MEM_TECH_BLOCK *TechPtr,
1000 MEM_NB_BLOCK *NBPtr;
1001 CH_DEF_STRUCT *ChannelPtr;
1003 NBPtr = TechPtr->NBPtr;
1004 ChannelPtr = NBPtr->ChannelPtr;
1009 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
1010 if ((NBPtr->DCTPtr->Timings.CsTrainFail & ((UINT16) 3 << (Dimm << 1))) == 0) {
1011 // Only choose the dimm that does not fail training
1012 for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
1013 RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + ByteLane];
1014 // Before Dqs Position Training, this value is 0. So the maximum value for
1015 // RdDqsDly needs to be added later when calculating the MaxRdLatency value
1016 // after RcvEnDly training but before DQS Position Training.
1017 RdDqsDly = ChannelPtr->RdDqsDlys[Dimm * MAX_DELAYS + ByteLane];
1018 TotalDly = RcvEnDly + RdDqsDly;
1019 if (TotalDly > MaxDly) {
1028 TechPtr->MaxDlyForMaxRdLat = MaxDly;
1029 *ChipSel = (MaxDlyDimm * 2);
1033 /* -----------------------------------------------------------------------------*/
1036 * This function finds the minimum or maximum gross dly among all the bytes.
1038 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1039 * @param[in] TrnDlyType - Target Dly type
1040 * @param[in] IfMax - If this is for maximum value or minimum
1042 * @return minimum gross dly
1046 MemTFindMinMaxGrossDlyByte (
1047 IN OUT MEM_TECH_BLOCK *TechPtr,
1048 IN TRN_DLY_TYPE TrnDlyType,
1055 UINT8 MinMaxGrossDly;
1057 MEM_NB_BLOCK *NBPtr;
1059 NBPtr = TechPtr->NBPtr;
1060 CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
1061 MinMaxGrossDly = IfMax ? 0 : 0xFF;
1063 for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
1064 if ((CsEnabled & (UINT16) (3 << (i << 1))) != 0) {
1065 for (ByteLane = 0; ByteLane < ((NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8); ByteLane++) {
1066 TrnDly = (UINT8) (GetTrainDlyFromHeapNb (NBPtr, TrnDlyType, DIMM_BYTE_ACCESS (i, ByteLane)) >> 5);
1067 if ((IfMax && (TrnDly > MinMaxGrossDly)) || (!IfMax && (TrnDly < MinMaxGrossDly))) {
1068 MinMaxGrossDly = TrnDly;
1074 return MinMaxGrossDly;
1077 /* -----------------------------------------------------------------------------*/
1080 * This function compares test pattern with data in buffer and return a pass/fail bitmap
1081 * for 8 Bytes for optimized receiver enable training
1083 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1084 * @param[in] Buffer[] - Buffer data from DRAM (Measured data from DRAM) to compare
1085 * @param[in] Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against
1086 * @param[in] Side - current side being targeted
1087 * @param[in] Receiver - Current receiver value
1088 * @param[in] Side1En - Indicates if the second side of the DIMM is being used
1089 * @return PASS - Bit map of results of comparison
1094 MemTCompare1ClPatternOptByte (
1095 IN OUT MEM_TECH_BLOCK *TechPtr,
1107 CH_DEF_STRUCT *ChannelPtr;
1109 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
1110 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
1111 MCTPtr = TechPtr->NBPtr->MCTPtr;
1113 if (MCTPtr->GangedMode && MCTPtr->Dct) {
1120 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDelay[BL] -");
1121 for (i = 0; i < 8; i++) {
1122 IDS_HDT_CONSOLE (MEM_FLOW, " %02x", TechPtr->RcvrEnDlyOpt[i] & 0xFF);
1123 if (Buffer[j] != Pattern[j]) {
1124 // if bytelane n fails
1125 Pass &= ~((UINT16)1 << (j % 8)); // clear bit n
1126 TechPtr->DqsRcvEnFirstPassValOpt[i] = 0;
1127 TechPtr->GetFirstPassValOpt[i] = FALSE;
1128 TechPtr->IncBy1ForNextCountOpt[i] = FALSE;
1129 TechPtr->DqsRcvEnSavedOpt[i] = FALSE;
1130 if (TechPtr->FilterStatusOpt[i] != DONE_FILTER) {
1131 if (Side == ((Side1En ? 4 : 2) - 1)) {
1132 TechPtr->RcvrEnDlyOpt[i] += FILTER_FIRST_STAGE_COUNT;
1136 if (TechPtr->FilterSidePassCountOpt[i] == ((Side1En ? 4 : 2) - 1)) {
1137 //Only apply filter if all sides have passed
1138 if (TechPtr->FilterStatusOpt[i] != DONE_FILTER) {
1139 if (TechPtr->GetFirstPassValOpt[i] == FALSE) {
1140 // This is the first Pass, mark the start of filter check
1141 TechPtr->DqsRcvEnFirstPassValOpt[i] = TechPtr->RcvrEnDlyOpt[i];
1142 TechPtr->GetFirstPassValOpt[i] = TRUE;
1143 TechPtr->IncBy1ForNextCountOpt[i] = FALSE;
1144 TechPtr->RcvrEnDlyOpt[i]++;
1146 if ((TechPtr->RcvrEnDlyOpt[i] - TechPtr->DqsRcvEnFirstPassValOpt[i]) < FILTER_WINDOW_SIZE) {
1147 if (TechPtr->IncBy1ForNextCountOpt[i] == FALSE) {
1148 TechPtr->RcvrEnDlyOpt[i] += FILTER_SECOND_STAGE_COUNT;
1149 TechPtr->IncBy1ForNextCountOpt[i] = TRUE;
1151 TechPtr->RcvrEnDlyOpt[i]++;
1152 TechPtr->IncBy1ForNextCountOpt[i] = FALSE;
1155 // End sweep and add offset to first pass
1156 TechPtr->MaxRcvrEnDlyBlOpt[i] = TechPtr->DqsRcvEnFirstPassValOpt[i];
1157 TechPtr->RcvrEnDlyOpt[i] = TechPtr->DqsRcvEnFirstPassValOpt[i] + FILTER_OFFSET_VALUE;
1158 TechPtr->FilterStatusOpt[i] = DONE_FILTER;
1159 TechPtr->FilterCountOpt++;
1163 TechPtr->FilterSidePassCountOpt[i]++;
1166 if (TechPtr->GetFirstPassValOpt[i] == FALSE) {
1167 if (Side == ((Side1En ? 4 : 2) - 1)) {
1168 TechPtr->RcvrEnDlyOpt[i] += FILTER_FIRST_STAGE_COUNT;
1171 TechPtr->FilterSidePassCountOpt[i]++;
1173 TechPtr->DqsRcvEnSavedOpt[i] = TRUE;
1174 ChannelPtr->RcvEnDlys[(Receiver >> 1) * MAX_DELAYS + i] = TechPtr->RcvrEnDlyOpt[i];
1176 if (Side == ((Side1En ? 4 : 2) - 1)) {
1177 TechPtr->FilterSidePassCountOpt[i] = 0;
1179 if (TechPtr->RcvrEnDlyOpt[i] >= TechPtr->RcvrEnDlyLimitOpt[i]) {
1180 TechPtr->FilterCountOpt++;
1186 IDS_HDT_CONSOLE_DEBUG_CODE (
1187 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tPass/Fail -");
1188 for (i = 0, j -= 8; i < 8; i++, j++) {
1189 IDS_HDT_CONSOLE (MEM_FLOW, " %c", (Buffer[j] == Pattern[j]) ? 'P' : '.');
1191 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Measured -");
1192 for (i = 0, j -= 8; i < 8; i++, j++) {
1193 IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Buffer[j]);
1195 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Expected -");
1196 for (i = 0, j -= 8; i < 8; i++, j++) {
1197 IDS_HDT_CONSOLE (MEM_FLOW, " %02x", Pattern[j]);
1199 IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
1204 /*-----------------------------------------------------------------------------
1206 * This function initializes variables for optimized training.
1208 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1210 * ----------------------------------------------------------------------------
1213 MemTInitializeVariablesOptByte (
1214 IN OUT MEM_TECH_BLOCK *TechPtr
1218 for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
1219 TechPtr->RcvrEnDlyLimitOpt[ByteLane] = FILTER_MAX_REC_EN_DLY_VALUE; // @attention - limit depends on proc type
1220 TechPtr->DqsRcvEnSavedOpt[ByteLane] = FALSE;
1221 TechPtr->RcvrEnDlyOpt[ByteLane] = FILTER_NEW_RECEIVER_START_VALUE;
1222 TechPtr->GetFirstPassValOpt[ByteLane] = FALSE;
1223 TechPtr->DqsRcvEnFirstPassValOpt[ByteLane] = 0;
1224 TechPtr->RevertPassValOpt[ByteLane] = FALSE;
1225 TechPtr->MaxRcvrEnDlyBlOpt[ByteLane] = 0;
1226 TechPtr->FilterStatusOpt[ByteLane] = START_FILTER;
1227 TechPtr->FilterCountOpt = 0;
1228 TechPtr->FilterSidePassCountOpt[ByteLane] = 0;
1229 TechPtr->IncBy1ForNextCountOpt[ByteLane] = FALSE;
1233 /* -----------------------------------------------------------------------------*/
1236 * This function loads the DqsRcvEnDly from saved data and program to additional index
1237 * for optimized DQS receiver enabled training
1239 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1240 * @param[in] Receiver - Current Chip select value
1246 MemTLoadRcvrEnDlyOptByte (
1247 IN OUT MEM_TECH_BLOCK *TechPtr,
1253 CH_DEF_STRUCT *ChannelPtr;
1255 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
1256 ChannelPtr = TechPtr->NBPtr->ChannelPtr;
1258 Dimm = Receiver >> 1;
1259 for (i = 0; i < 8; i++) {
1260 if (TechPtr->DqsRcvEnSavedOpt[i]) {
1261 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, i),
1262 ChannelPtr->RcvEnDlys[Dimm * MAX_DELAYS + i]);
1267 /* -----------------------------------------------------------------------------*/
1270 * This function programs DqsRcvEnDly to additional index for DQS receiver enabled training
1272 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1273 * @param[in] Receiver - Current Chip select value
1274 * @param[in] RcvEnDly - receiver enable delay to be saved
1279 MemTSetRcvrEnDlyOptByte (
1280 IN OUT MEM_TECH_BLOCK *TechPtr,
1287 ASSERT (Receiver < MAX_CS_PER_CHANNEL);
1289 for (ByteLane = 0; ByteLane < 8; ByteLane++) {
1290 if (TechPtr->FilterStatusOpt[ByteLane] != DONE_FILTER) {
1291 TechPtr->NBPtr->SetTrainDly (TechPtr->NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Receiver >> 1, ByteLane), TechPtr->RcvrEnDlyOpt[ByteLane]);
1295 /*-----------------------------------------------------------------------------
1297 * This sets any Errors generated from Dly sweep
1299 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1300 * @param[in] DCT - current DCT
1301 * @param[in] Receiver - current receiver
1303 * @return FALSE - Fatal error occurs.
1304 * @return TRUE - No fatal error occurs.
1305 * ----------------------------------------------------------------------------
1308 MemTSetSweepErrorOptByte (
1309 IN OUT MEM_TECH_BLOCK *TechPtr,
1312 IN BOOLEAN ErrorCheck
1316 MEM_DATA_STRUCT *MemPtr;
1319 MEM_NB_BLOCK *NBPtr;
1321 NBPtr = TechPtr->NBPtr;
1322 MemPtr = NBPtr->MemPtr;
1323 MCTPtr = NBPtr->MCTPtr;
1324 DCTPtr = NBPtr->DCTPtr;
1325 for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
1326 if (TechPtr->RcvrEnDlyOpt[ByteLane] == TechPtr->RcvrEnDlyLimitOpt[ByteLane]) {
1327 // no passing window
1331 PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_NO_PASSING_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, ByteLane, &NBPtr->MemPtr->StdHeader);
1332 SetMemError (AGESA_ERROR, MCTPtr);
1334 if (TechPtr->RcvrEnDlyOpt[ByteLane] > (TechPtr->RcvrEnDlyLimitOpt[ByteLane] - 1)) {
1335 // passing window too narrow, too far delayed
1339 PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_VALUE_TOO_LARGE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, ByteLane, &NBPtr->MemPtr->StdHeader);
1340 SetMemError (AGESA_ERROR, MCTPtr);
1341 DCTPtr->Timings.CsTrainFail |= (UINT16) (3 << Receiver) & DCTPtr->Timings.CsPresent;
1342 MCTPtr->ChannelTrainFail |= (UINT32)1 << Dct;
1343 if (!NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, DCTPtr->Timings.CsTrainFail, &MemPtr->StdHeader)) {
1352 /*-----------------------------------------------------------------------------
1354 * This function determines the maximum receiver delay value
1356 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1358 * @retval MaxRcvrValue - Maximum receiver delay value for all bytelanes
1359 * ----------------------------------------------------------------------------
1363 MemTGetMaxValueOptByte (
1364 IN OUT MEM_TECH_BLOCK *TechPtr
1368 UINT16 MaxRcvrValue;
1370 for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
1371 if (TechPtr->MaxRcvrEnDlyBlOpt[ByteLane] > MaxRcvrValue) {
1372 MaxRcvrValue = TechPtr->MaxRcvrEnDlyBlOpt[ByteLane];
1375 MaxRcvrValue += FILTER_OFFSET_VALUE;
1376 return MaxRcvrValue;
1378 /*-----------------------------------------------------------------------------
1380 * This function determines if the sweep loop should complete.
1382 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1384 * @retval TRUE - All bytelanes pass
1385 * FALSE - Some bytelanes fail
1386 * ----------------------------------------------------------------------------
1390 MemTCheckRcvrEnDlyLimitOptByte (
1391 IN OUT MEM_TECH_BLOCK *TechPtr
1394 if (TechPtr->FilterCountOpt >= (UINT16)MAX_CS_PER_CHANNEL) {
1401 /* -----------------------------------------------------------------------------*/
1404 * This function load the result of write levelization training into RcvrEnDlyOpt,
1405 * using it as the initial value for Receiver DQS training.
1407 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1408 * @param[in] Receiver - Current Chip select value
1412 MemTLoadInitialRcvEnDlyOptByte (
1413 IN OUT MEM_TECH_BLOCK *TechPtr,
1418 MEM_NB_BLOCK *NBPtr;
1420 NBPtr = TechPtr->NBPtr;
1421 for (ByteLane = 0; ByteLane < MAX_BYTELANES_PER_CHANNEL; ByteLane++) {
1422 TechPtr->RcvrEnDlyOpt[ByteLane] = NBPtr->ChannelPtr->WrDqsDlys[((Receiver >> 1) * TechPtr->DlyTableWidth ()) + ByteLane];