VOID MemNBeforeDQSTrainingHy ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT8 Dct; UINT8 ChipSel; UINT32 TestAddrRJ16; UINT32 RealAddr; MemTBeginTraining (NBPtr->TechPtr); for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) { if (MemNGetMCTSysAddrNb (NBPtr, ChipSel, &TestAddrRJ16)) { RealAddr = MemUSetUpperFSbase (TestAddrRJ16, NBPtr->MemPtr); MemUDummyCLRead (RealAddr); MemNSetBitFieldNb (NBPtr, BFErr350, 0x8000); MemUWait10ns (60, NBPtr->MemPtr); // Wait 300ns MemNSetBitFieldNb (NBPtr, BFErr350, 0x0000); MemUWait10ns (400, NBPtr->MemPtr); // Wait 2us MemUProcIOClFlush (TestAddrRJ16, 1, NBPtr->MemPtr); break; } } } if (NBPtr->IsSupported[CheckEccDLLPwrDnConfig]) { if (!NBPtr->MCTPtr->Status[SbEccDimms]) { MemNSetBitFieldNb (NBPtr, BFEccDLLPwrDnConf, 0x0010); } if (NBPtr->DCTPtr->Timings.Dimmx4Present == 0) { MemNSetBitFieldNb (NBPtr, BFEccDLLConf, 0x0080); } } } MemTEndTraining (NBPtr->TechPtr); MemNSetBitFieldNb (NBPtr, BFDisDatMsk, 1); }
VOID MemNBeforeDQSTrainingON ( IN OUT MEM_NB_BLOCK *NBPtr ) { MemTBeginTraining (NBPtr->TechPtr); MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1); MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0); MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 0); MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 0); MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, 0); MemNSetBitFieldNb (NBPtr, BFPrefCpuDis, 1); MemNSetBitFieldNb (NBPtr, BFDctWrLimit, 0x1F); MemNSetBitFieldNb (NBPtr, BFEnCpuSerRdBehindNpIoWr, 1); MemNSetBitFieldNb (NBPtr, BFDbeGskMemClkAlignMode, 0); MemNSetBitFieldNb (NBPtr, BFMaxLatency, 0x12); MemNSetBitFieldNb (NBPtr, BFTraceModeEn, 0); // Enable cut through mode for NB P0 MemNSetBitFieldNb (NBPtr, BFDisCutThroughMode, 0); MemTEndTraining (NBPtr->TechPtr); }
/** * * This function executes receiver enable training for a specific die * * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK * @param[in] Pass - Pass of the receiver training * * @return TRUE - No fatal error occurs. * @return FALSE - Fatal error occurs. */ BOOLEAN STATIC MemTDqsTrainOptRcvrEnSw ( IN OUT MEM_TECH_BLOCK *TechPtr, IN UINT8 Pass ) { _16BYTE_ALIGN UINT8 PatternBuffer[6 * 64]; UINT8 TestBuffer[256]; UINT8 *PatternBufPtr[6]; UINT8 *TempPtr; UINT32 TestAddrRJ16[4]; UINT32 TempAddrRJ16; UINT32 RealAddr; UINT16 CurTest[4]; UINT8 Dct; UINT8 Receiver; UINT8 i; UINT8 TimesFail; UINT8 TimesRetrain; UINT16 RcvrEnDly; UINT16 MaxRcvrEnDly; UINT16 RcvrEnDlyLimit; UINT16 MaxDelayCha; BOOLEAN IsDualRank; BOOLEAN S0En; BOOLEAN S1En; MEM_DATA_STRUCT *MemPtr; DIE_STRUCT *MCTPtr; DCT_STRUCT *DCTPtr; MEM_NB_BLOCK *NBPtr; NBPtr = TechPtr->NBPtr; MemPtr = NBPtr->MemPtr; MCTPtr = NBPtr->MCTPtr; TechPtr->TrainingType = TRN_RCVR_ENABLE; TempAddrRJ16 = 0; TempPtr = NULL; MaxDelayCha = 0; TimesRetrain = DEFAULT_TRAINING_TIMES; IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader); IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Optimized SW RxEn training\n"); // Set environment settings before training MemTBeginTraining (TechPtr); PatternBufPtr[0] = PatternBufPtr[2] = PatternBuffer; // These two patterns used for first Test Address MemUFillTrainPattern (TestPattern0, PatternBufPtr[0], 64); // Second Cacheline used for Dummy Read is the inverse of // the first so that is is not mistaken for the real read MemUFillTrainPattern (TestPattern1, PatternBufPtr[0] + 64, 64); PatternBufPtr[1] = PatternBufPtr[3] = PatternBufPtr[0] + 128; // These two patterns used for second Test Address MemUFillTrainPattern (TestPattern1, PatternBufPtr[1], 64); // Second Cacheline used for Dummy Read is the inverse of // the first so that is is not mistaken for the real read MemUFillTrainPattern (TestPattern0, PatternBufPtr[1] + 64, 64); // Fill pattern for flush after every sweep PatternBufPtr[4] = PatternBufPtr[0] + 256; MemUFillTrainPattern (TestPattern3, PatternBufPtr[4], 64); // Fill pattern for initial dummy read PatternBufPtr[5] = PatternBufPtr[0] + 320; MemUFillTrainPattern (TestPattern4, PatternBufPtr[5], 64); // Begin receiver enable training AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader)); for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); NBPtr->SwitchDCT (NBPtr, Dct); DCTPtr = NBPtr->DCTPtr; // Set training bit NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 1); // Relax Max Latency before training NBPtr->SetMaxLatency (NBPtr, 0xFFFF); if (Pass == FIRST_PASS) { TechPtr->InitDQSPos4RcvrEn (TechPtr); } // there are four receiver pairs, loosely associated with chipselects. Receiver = DCTPtr->Timings.CsEnabled ? 0 : 8; for (; Receiver < 8; Receiver += 2) { S0En = NBPtr->GetSysAddr (NBPtr, Receiver, &TestAddrRJ16[0]); S1En = NBPtr->GetSysAddr (NBPtr, Receiver + 1, &TestAddrRJ16[2]); if (S0En) { TestAddrRJ16[1] = TestAddrRJ16[0] + BIGPAGE_X8_RJ16; } if (S1En) { TestAddrRJ16[3] = TestAddrRJ16[2] + BIGPAGE_X8_RJ16; } if (S0En && S1En) { IsDualRank = TRUE; } else { IsDualRank = FALSE; } if (S0En || S1En) { IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", Receiver); RcvrEnDlyLimit = 0x1FF; // @attention - limit depends on proc type TechPtr->DqsRcvEnSaved = 0; RcvrEnDly = RcvrEnDlyLimit; RealAddr = 0; TechPtr->GetFirstPassVal = FALSE; TechPtr->DqsRcvEnFirstPassVal = 0; TechPtr->RevertPassVal = FALSE; TechPtr->InitializeVariablesOpt (TechPtr); // Write the test patterns AGESA_TESTPOINT (TpProcMemRcvrWritePattern, &(MemPtr->StdHeader)); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to addresses: "); for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) { RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr); // One cacheline of data to be tested and one of dummy data MemUWriteCachelines (RealAddr, PatternBufPtr[i], 2); // This is dummy data with a different pattern used for the first dummy read. MemUWriteCachelines (RealAddr + 128, PatternBufPtr[5], 1); IDS_HDT_CONSOLE (MEM_FLOW, " %04x0000 ", TestAddrRJ16[i]); } IDS_HDT_CONSOLE (MEM_FLOW, "\n"); // Sweep receiver enable delays AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader)); TimesFail = 0; ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain) { TechPtr->LoadInitialRcvrEnDlyOpt (TechPtr, Receiver); while (!TechPtr->CheckRcvrEnDlyLimitOpt (TechPtr)) { AGESA_TESTPOINT (TpProcMemRcvrSetDelay, &(MemPtr->StdHeader)); TechPtr->SetRcvrEnDlyOpt (TechPtr, Receiver, RcvrEnDly); // Read and compare the first beat of data for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) { AGESA_TESTPOINT (TpProcMemRcvrReadPattern, &(MemPtr->StdHeader)); RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr); // // Issue dummy cacheline reads // MemUReadCachelines (TestBuffer + 128, RealAddr + 128, 1); MemUReadCachelines (TestBuffer, RealAddr, 1); MemUProcIOClFlush (TestAddrRJ16[i], 2, MemPtr); // // Perform actual read which will be compared // MemUReadCachelines (TestBuffer + 64, RealAddr + 64, 1); AGESA_TESTPOINT (TpProcMemRcvrTestPattern, &(MemPtr->StdHeader)); CurTest[i] = TechPtr->Compare1ClPatternOpt (TechPtr, TestBuffer + 64 , PatternBufPtr[i] + 64, i, Receiver, S1En); // Due to speculative execution during MemUReadCachelines, we must // flush one more cache line than we read. MemUProcIOClFlush (TestAddrRJ16[i], 4, MemPtr); TechPtr->ResetDCTWrPtr (TechPtr, Receiver); // // Swap the test pointers such that even and odd steps alternate. // if ((i % 2) == 0) { TempPtr = PatternBufPtr[i]; PatternBufPtr[i] = PatternBufPtr[i + 1]; TempAddrRJ16 = TestAddrRJ16[i]; TestAddrRJ16[i] = TestAddrRJ16[i + 1]; } else { PatternBufPtr[i] = TempPtr; TestAddrRJ16[i] = TempAddrRJ16; } } } // End of delay sweep ERROR_HANDLE_RETRAIN_END (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, TRUE), TimesFail) } if (!TechPtr->SetSweepErrorOpt (TechPtr, Receiver, Dct, FALSE)) { return FALSE; } TechPtr->LoadRcvrEnDlyOpt (TechPtr, Receiver); // set final delays // // Flush AA and 55 patterns by reading a dummy pattern to fill in FIFO // // Aquire a new FSBase, based on the last test address that we stored. RealAddr = MemUSetUpperFSbase (TempAddrRJ16, MemPtr); ASSERT (RealAddr != 0); MemUWriteCachelines (RealAddr, PatternBufPtr[4], 1); MemUWriteCachelines (RealAddr + 64, PatternBufPtr[4], 1); MemUReadCachelines (TestBuffer, RealAddr, 2); // Due to speculative execution during MemUReadCachelines, we must // flush one more cache line than we read. MemUProcIOClFlush (TempAddrRJ16, 3, MemPtr); } } // End while Receiver < 8
BOOLEAN STATIC MemTTrainDQSRdWrEdgeDetect ( IN OUT MEM_TECH_BLOCK *TechPtr ) { MEM_DATA_STRUCT *MemPtr; MEM_NB_BLOCK *NBPtr; UINT8 WrDqDelay; UINT8 Dct; UINT8 CSPerChannel; UINT8 CsPerDelay; UINT8 ChipSel; UINT8 i; BOOLEAN Status; UINT8 TimesFail; UINT8 TimesRetrain; NBPtr = TechPtr->NBPtr; MemPtr = NBPtr->MemPtr; TimesRetrain = DEFAULT_TRAINING_TIMES; IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader); // // Set environment settings before training // IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Read/Write Data Eye Edge Detection.\n"); MemTBeginTraining (TechPtr); // // Do Rd DQS /Wr Data Position training for all Dcts/Chipselects // for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); NBPtr->SwitchDCT (NBPtr, Dct); // // Chip Select Loop // CSPerChannel = NBPtr->CSPerChannel (NBPtr); CsPerDelay = NBPtr->CSPerDelay (NBPtr); for (ChipSel = 0; ChipSel < CSPerChannel; ChipSel = ChipSel + CsPerDelay ) { // // Init Bit Error Masks // LibAmdMemFill (&NBPtr->ChannelPtr->FailingBitMask[ (ChipSel * MAX_BYTELANES_PER_CHANNEL) ], 0xFF, (MAX_BYTELANES_PER_CHANNEL * CsPerDelay), &MemPtr->StdHeader); if ((NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16) 1 << ChipSel)) != 0) { TechPtr->ChipSel = ChipSel; IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tIncrease WrDat, Train RdDqs:\n"); TechPtr->DqsRdWrPosSaved = 0; // // Use a list of Approximate Write Data delay values and train Read DQS Position for // each until a valid Data eye is found. // Status = FALSE; TimesFail = 0; ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain) { i = 0; while (NBPtr->GetApproximateWriteDatDelay (NBPtr, i, &WrDqDelay)) { TechPtr->SmallDqsPosWindow = FALSE; // // Set Write Delay approximation // TechPtr->Direction = DQS_WRITE_DIR; IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tWrite Delay: %02x", WrDqDelay); MemTSetDQSDelayAllCSR (TechPtr, WrDqDelay); // // Attempt Read Training // TechPtr->Direction = DQS_READ_DIR; if (MemTTrainDQSEdgeDetect (TechPtr)) { // // If Read DQS Training was successful, Train Write Data (DQ) Position // TechPtr->DqsRdWrPosSaved = 0; IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tTrain WrDat:\n\n"); TechPtr->Direction = DQS_WRITE_DIR; Status = MemTTrainDQSEdgeDetect (TechPtr); break; } i++; } ERROR_HANDLE_RETRAIN_END ((Status == FALSE), TimesFail) } // // If we went through the table, Fail. // if (Status == FALSE) { // On training failure, check and record whether training fails due to small window or no window if (TechPtr->SmallDqsPosWindow) { NBPtr->MCTPtr->ErrStatus[EsbSmallDqs] = TRUE; } else { NBPtr->MCTPtr->ErrStatus[EsbNoDqsPos] = TRUE; } SetMemError (AGESA_ERROR, NBPtr->MCTPtr); if (TechPtr->Direction == DQS_READ_DIR) { PutEventLog (AGESA_ERROR, MEM_ERROR_NO_DQS_POS_RD_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader); } else { PutEventLog (AGESA_ERROR, MEM_ERROR_NO_DQS_POS_WR_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader); } NBPtr->DCTPtr->Timings.CsTrainFail |= (UINT16)1 << ChipSel; // If the even chip select failed training always fail the odd, if present. if ((ChipSel & 0x01) == 0) { if (NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << (ChipSel + 1))) { NBPtr->DCTPtr->Timings.CsTrainFail |= (UINT16)1 << (ChipSel + 1); } } NBPtr->MemPtr->ErrorHandling (NBPtr->MCTPtr, NBPtr->Dct, NBPtr->DCTPtr->Timings.CsTrainFail, &NBPtr->MemPtr->StdHeader); } } else {
/** * * This function executes receiver enable training for a specific die * * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK * @param[in] Pass - Pass of the receiver training * * @return TRUE - No fatal error occurs. * @return FALSE - Fatal error occurs. */ BOOLEAN STATIC MemTDqsTrainRcvrEnSw ( IN OUT MEM_TECH_BLOCK *TechPtr, IN UINT8 Pass ) { _16BYTE_ALIGN UINT8 PatternBuffer[3 * 64]; UINT8 TestBuffer[120]; UINT8 *PatternBufPtr[4]; UINT8 *TempPtr; UINT32 TestAddrRJ16[4]; UINT32 TempAddrRJ16; UINT32 RealAddr; UINT16 CurTest[4]; UINT8 Dct; UINT8 Receiver; UINT8 i; UINT8 TimesFail; UINT8 TimesRetrain; UINT16 RcvrEnDly; UINT16 MaxRcvrEnDly; UINT16 RcvrEnDlyLimit; UINT16 MaxDelayCha; BOOLEAN IsDualRank; BOOLEAN S0En; BOOLEAN S1En; UINT8 MaxFilterDly; MEM_DATA_STRUCT *MemPtr; DIE_STRUCT *MCTPtr; DCT_STRUCT *DCTPtr; MEM_NB_BLOCK *NBPtr; NBPtr = TechPtr->NBPtr; MemPtr = NBPtr->MemPtr; MCTPtr = NBPtr->MCTPtr; TempAddrRJ16 = 0; TempPtr = NULL; MaxDelayCha = 0; MaxFilterDly = TechPtr->MaxFilterDly; RcvrEnDlyLimit = NBPtr->RcvrEnDlyLimit; TimesRetrain = DEFAULT_TRAINING_TIMES; IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader); IDS_HDT_CONSOLE ("!\nStart SW RxEn training\n"); // Set environment settings before training MemTBeginTraining (TechPtr); PatternBufPtr[0] = PatternBufPtr[2] = PatternBuffer; MemUFillTrainPattern (TestPattern0, PatternBufPtr[0], 64); PatternBufPtr[1] = PatternBufPtr[3] = PatternBufPtr[0] + 128; MemUFillTrainPattern (TestPattern1, PatternBufPtr[1], 64); // Begin receiver enable training AGESA_TESTPOINT (TpProcMemReceiverEnableTraining, &(MemPtr->StdHeader)); MaxRcvrEnDly = 0; for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { IDS_HDT_CONSOLE ("!\tDct %d\n", Dct); NBPtr->SwitchDCT (NBPtr, Dct); DCTPtr = NBPtr->DCTPtr; // Set training bit NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 1); // Relax Max Latency before training NBPtr->SetMaxLatency (NBPtr, 0xFFFF); if (Pass == FIRST_PASS) { TechPtr->InitDQSPos4RcvrEn (TechPtr); } // there are four receiver pairs, loosely associated with chipselects. Receiver = DCTPtr->Timings.CsEnabled ? 0 : 8; for (; Receiver < 8; Receiver += 2) { TechPtr->DqsRcvEnSaved = 0; RcvrEnDly = RcvrEnDlyLimit; S0En = NBPtr->GetSysAddr (NBPtr, Receiver, &TestAddrRJ16[0]); S1En = NBPtr->GetSysAddr (NBPtr, Receiver + 1, &TestAddrRJ16[2]); if (S0En) { TestAddrRJ16[1] = TestAddrRJ16[0] + BIGPAGE_X8_RJ16; } if (S1En) { TestAddrRJ16[3] = TestAddrRJ16[2] + BIGPAGE_X8_RJ16; } if (S0En && S1En) { IsDualRank = TRUE; } else { IsDualRank = FALSE; } if (S0En || S1En) { IDS_HDT_CONSOLE ("!\t\tCS %d\n", Receiver); // Write the test patterns AGESA_TESTPOINT (TpProcMemRcvrWritePattern, &(MemPtr->StdHeader)); IDS_HDT_CONSOLE ("\t\t\tWrite to addresses: "); for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) { RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr); MemUWriteCachelines (RealAddr, PatternBufPtr[i], 1); IDS_HDT_CONSOLE (" %04lx0000 ", TestAddrRJ16[i]); } IDS_HDT_CONSOLE ("\n"); // Initialize RcvrEnDly value and other DCT stored values // MCTPtr->DqsRcvEnPass = Pass ? 0xFF : 0; // Sweep receiver enable delays AGESA_TESTPOINT (TpProcMemRcvrStartSweep, &(MemPtr->StdHeader)); TimesFail = 0; ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain) { for (RcvrEnDly = 0; RcvrEnDly < RcvrEnDlyLimit; RcvrEnDly++) { AGESA_TESTPOINT (TpProcMemRcvrSetDelay, &(MemPtr->StdHeader)); TechPtr->SetRcvrEnDly (TechPtr, Receiver, RcvrEnDly); IDS_HDT_CONSOLE ("\t\t\tDly %3x", RcvrEnDly); // Read and compare the first beat of data for (i = (S0En ? 0 : 2); i < (S1En ? 4 : 2); i++) { AGESA_TESTPOINT (TpProcMemRcvrReadPattern, &(MemPtr->StdHeader)); RealAddr = MemUSetUpperFSbase (TestAddrRJ16[i], MemPtr); MemUReadCachelines (TestBuffer, RealAddr, 1); AGESA_TESTPOINT (TpProcMemRcvrTestPattern, &(MemPtr->StdHeader)); CurTest[i] = TechPtr->Compare1ClPattern (TechPtr, TestBuffer, PatternBufPtr[i]); // Due to speculative execution during MemUReadCachelines, we must // flush one more cache line than we read. MemUProcIOClFlush (TestAddrRJ16[i], 2, MemPtr); TechPtr->ResetDCTWrPtr (TechPtr, Receiver); // // Swap the test pointers such that even and odd steps alternate. // if ((i % 2) == 0) { TempPtr = PatternBufPtr[i]; PatternBufPtr[i] = PatternBufPtr[i + 1]; TempAddrRJ16 = TestAddrRJ16[i]; TestAddrRJ16[i] = TestAddrRJ16[i + 1]; } else { PatternBufPtr[i] = TempPtr; TestAddrRJ16[i] = TempAddrRJ16; } } if (TechPtr->SaveRcvrEnDly (TechPtr, Receiver, RcvrEnDly, S0En ? (CurTest[0] & CurTest[1]) : 0xFFFF, S1En ? (CurTest[2] & CurTest[3]) : 0xFFFF)) { // if all bytelanes pass if (MaxRcvrEnDly < (RcvrEnDly - MaxFilterDly)) { MaxRcvrEnDly = RcvrEnDly - MaxFilterDly; } break; } } // End of delay sweep ERROR_HANDLE_RETRAIN_END ((RcvrEnDly > (RcvrEnDlyLimit - 1)), TimesFail) } if (RcvrEnDly == RcvrEnDlyLimit) { // no passing window PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_NO_PASSING_WINDOW_EQUAL_LIMIT, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader); SetMemError (AGESA_ERROR, MCTPtr); } if (RcvrEnDly > (RcvrEnDlyLimit - 1)) { // passing window too narrow, too far delayed PutEventLog (AGESA_ERROR, MEM_ERROR_RCVR_EN_VALUE_TOO_LARGE_LIMIT_LESS_ONE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader); SetMemError (AGESA_ERROR, MCTPtr); DCTPtr->Timings.CsTrainFail |= DCTPtr->Timings.CsPresent & (UINT16) (3 << Receiver); MCTPtr->ChannelTrainFail |= (UINT32)1 << Dct; if (!NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, DCTPtr->Timings.CsTrainFail, &NBPtr->MemPtr->StdHeader)) { return FALSE; } } } TechPtr->LoadRcvrEnDly (TechPtr, Receiver); // set final delays } // End while Receiver < 8 // Clear training bit when done NBPtr->SetBitField (NBPtr, BFDqsRcvEnTrain, 0); // Set Max Latency for both channels MaxRcvrEnDly += 0x20; // @attention - IDS_HDT_CONSOLE ("\t\tMaxRcvrEnDly: %03x\n", MaxRcvrEnDly); if (MCTPtr->GangedMode) { if (Dct == 0) { MaxDelayCha = MaxRcvrEnDly; } else if (MaxRcvrEnDly > MaxDelayCha) { NBPtr->SwitchDCT (NBPtr, 0); NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly); } } else { NBPtr->SetMaxLatency (NBPtr, MaxRcvrEnDly); } TechPtr->ResetDCTWrPtr (TechPtr, 6); }
BOOLEAN MemTTrainMaxLatency ( IN OUT MEM_TECH_BLOCK *TechPtr ) { UINT32 TestAddrRJ16; UINT8 Dct; UINT8 ChipSel; UINT8 *PatternBufPtr; UINT8 *TestBufferPtr; UINT8 CurrentNbPstate; UINT16 CalcMaxLatDly; UINT16 MaxLatDly; UINT16 MaxLatLimit; UINT16 Margin; UINT16 CurTest; UINT16 _CL_; UINT8 TimesFail; UINT8 TimesRetrain; UINT16 i; MEM_DATA_STRUCT *MemPtr; DIE_STRUCT *MCTPtr; MEM_NB_BLOCK *NBPtr; NBPtr = TechPtr->NBPtr; MCTPtr = NBPtr->MCTPtr; MemPtr = NBPtr->MemPtr; TechPtr->TrainingType = TRN_MAX_READ_LATENCY; TimesRetrain = DEFAULT_TRAINING_TIMES; IDS_OPTION_HOOK (IDS_MEM_RETRAIN_TIMES, &TimesRetrain, &MemPtr->StdHeader); IDS_HDT_CONSOLE (MEM_STATUS, "\nStart MaxRdLat training\n"); // Set environment settings before training AGESA_TESTPOINT (TpProcMemMaxRdLatencyTraining, &(MemPtr->StdHeader)); MemTBeginTraining (TechPtr); // // Initialize the Training Pattern // if (AGESA_SUCCESS != NBPtr->TrainingPatternInit (NBPtr)) { return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL); } TechPtr->PatternLength = (MCTPtr->Status[Sb128bitmode]) ? 6 : 3; // // Setup hardware training engine (if applicable) // NBPtr->FamilySpecificHook[SetupHwTrainingEngine] (NBPtr, &TechPtr->TrainingType); MaxLatDly = 0; _CL_ = TechPtr->PatternLength; PatternBufPtr = TechPtr->PatternBufPtr; TestBufferPtr = TechPtr->TestBufPtr; // // Begin max latency training // for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { if (MCTPtr->Status[Sb128bitmode] && (Dct != 0)) { break; } IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); NBPtr->SwitchDCT (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) { TechPtr->ChipSel = ChipSel; if (NBPtr->GetSysAddr (NBPtr, ChipSel, &TestAddrRJ16)) { IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrite to address: %04x0000\n", TestAddrRJ16); // Write the test patterns AGESA_TESTPOINT (TpProcMemMaxRdLatWritePattern, &(MemPtr->StdHeader)); NBPtr->WritePattern (NBPtr, TestAddrRJ16, PatternBufPtr, _CL_); // Sweep max latency delays NBPtr->getMaxLatParams (NBPtr, TechPtr->MaxDlyForMaxRdLat, &CalcMaxLatDly, &MaxLatLimit, &Margin); AGESA_TESTPOINT (TpProcMemMaxRdLatStartSweep, &(MemPtr->StdHeader)); TimesFail = 0; ERROR_HANDLE_RETRAIN_BEGIN (TimesFail, TimesRetrain) { MaxLatDly = CalcMaxLatDly; for (i = 0; i < (MaxLatLimit - CalcMaxLatDly); i++) { NBPtr->SetBitField (NBPtr, BFMaxLatency, MaxLatDly); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDly %3x", MaxLatDly); TechPtr->ResetDCTWrPtr (TechPtr, 6); AGESA_TESTPOINT (TpProcMemMaxRdLatReadPattern, &(MemPtr->StdHeader)); NBPtr->ReadPattern (NBPtr, TestBufferPtr, TestAddrRJ16, _CL_); AGESA_TESTPOINT (TpProcMemMaxRdLatTestPattern, &(MemPtr->StdHeader)); CurTest = NBPtr->CompareTestPattern (NBPtr, TestBufferPtr, PatternBufPtr, _CL_ * 64); NBPtr->FlushPattern (NBPtr, TestAddrRJ16, _CL_); if (NBPtr->IsSupported[ReverseMaxRdLatTrain]) { // Reverse training decrements MaxLatDly whenever the test passes // and uses the last passing MaxLatDly as left edge if (CurTest == 0xFFFF) { IDS_HDT_CONSOLE (MEM_FLOW, " P"); if (MaxLatDly == 0) { break; } else { MaxLatDly--; } } } else { // Traditional training increments MaxLatDly until the test passes // and uses it as left edge if (CurTest == 0xFFFF) { IDS_HDT_CONSOLE (MEM_FLOW, " P"); break; } else { MaxLatDly++; } } IDS_HDT_CONSOLE (MEM_FLOW, "\n"); } // End of delay sweep ERROR_HANDLE_RETRAIN_END ((MaxLatDly >= MaxLatLimit), TimesFail) } AGESA_TESTPOINT (TpProcMemMaxRdLatSetDelay, &(MemPtr->StdHeader)); if (MaxLatDly >= MaxLatLimit) { PutEventLog (AGESA_ERROR, MEM_ERROR_MAX_LAT_NO_WINDOW, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader); SetMemError (AGESA_ERROR, MCTPtr); NBPtr->DCTPtr->Timings.CsTrainFail |= NBPtr->DCTPtr->Timings.CsPresent; MCTPtr->ChannelTrainFail |= (UINT32)1 << Dct; if (!NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, EXCLUDE_ALL_CHIPSEL, &NBPtr->MemPtr->StdHeader)) { ASSERT (FALSE); return FALSE; } } else { NBPtr->FamilySpecificHook[AddlMaxRdLatTrain] (NBPtr, &TestAddrRJ16); MaxLatDly = MaxLatDly + Margin; if (NBPtr->IsSupported[ReverseMaxRdLatTrain]) { MaxLatDly++; // Add 1 to get back to the last passing value } // Set final delays CurrentNbPstate = (UINT8) MemNGetBitFieldNb (NBPtr, BFCurNbPstate); ASSERT (CurrentNbPstate <= 3); NBPtr->ChannelPtr->DctMaxRdLat [CurrentNbPstate] = MaxLatDly; NBPtr->SetBitField (NBPtr, BFMaxLatency, MaxLatDly); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tFinal MaxRdLat: %03x\n", MaxLatDly); } } }