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 {