BOOLEAN MemTSetDQSEccTmgsRDdr3 ( IN OUT MEM_TECH_BLOCK *TechPtr ) { UINT8 Dct; UINT8 Dimm; UINT8 i; UINT8 *WrDqsDly; UINT16 *RcvEnDly; UINT8 *RdDqsDly; UINT8 *WrDatDly; UINT8 EccByte; INT16 TempValue; MEM_NB_BLOCK *NBPtr; CH_DEF_STRUCT *ChannelPtr; EccByte = TechPtr->MaxByteLanes (); NBPtr = TechPtr->NBPtr; if (NBPtr->MCTPtr->NodeMemSize) { for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { NBPtr->SwitchDCT (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { ChannelPtr = NBPtr->ChannelPtr; for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) { if (NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16)3 << (Dimm * 2))) { i = Dimm * TechPtr->DlyTableWidth (); WrDqsDly = &ChannelPtr->WrDqsDlys[i]; RcvEnDly = &ChannelPtr->RcvEnDlys[i]; RdDqsDly = &ChannelPtr->RdDqsDlys[i]; WrDatDly = &ChannelPtr->WrDatDlys[i]; // Receiver DQS Enable: // Receiver DQS enable for ECC bytelane = Receiver DQS enable for bytelane 3 - // [write DQS for bytelane 3 - write DQS for ECC] TempValue = (INT16) RcvEnDly[3] - (INT16) (WrDqsDly[3] - WrDqsDly[EccByte]); if (TempValue < 0) { TempValue = 0; } RcvEnDly[EccByte] = (UINT16) TempValue; // Read DQS: // Read DQS for ECC bytelane = read DQS of byte lane 3 // RdDqsDly[EccByte] = RdDqsDly[3]; // Write Data: // Write Data for ECC bytelane = Write DQS for ECC + // [write data for bytelane 3 - Write DQS for bytelane 3] TempValue = (INT16) (WrDqsDly[EccByte] + (INT8) (WrDatDly[3] - WrDqsDly[3])); if (TempValue < 0) { TempValue = 0; } WrDatDly[EccByte] = (UINT8) TempValue; NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Dimm, EccByte), RcvEnDly[EccByte]); NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, EccByte), RdDqsDly[EccByte]); NBPtr->SetTrainDly (NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS (Dimm, EccByte), WrDatDly[EccByte]); } } } } } return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); }
VOID MemNTrainPhyFenceNb ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT8 Byte; INT16 Avg; UINT8 PREvalue; if (MemNGetBitFieldNb (NBPtr, BFDisDramInterface)) { return; } // 1. BIOS first programs a seed value to the phase recovery // engine registers. // IDS_HDT_CONSOLE (MEM_FLOW, "\t\tSeeds: "); for (Byte = 0; Byte < MAX_BYTELANES_PER_CHANNEL; Byte++) { // This includes ECC as byte 8 MemNSetTrainDlyNb (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (0, Byte), 19); IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", 19); } IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tPhyFenceTrEn = 1"); // 2. Set F2x[1, 0]9C_x08[PhyFenceTrEn]=1. MemNSetBitFieldNb (NBPtr, BFPhyFenceTrEn, 1); if (!NBPtr->IsSupported[UnifiedNbFence]) { // 3. Wait 200 MEMCLKs. MemNWaitXMemClksNb (NBPtr, 200); } else { // 3. Wait 2000 MEMCLKs. MemNWaitXMemClksNb (NBPtr, 2000); } // 4. Clear F2x[1, 0]9C_x08[PhyFenceTrEn]=0. MemNSetBitFieldNb (NBPtr, BFPhyFenceTrEn, 0); // 5. BIOS reads the phase recovery engine registers // F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52. // 6. Calculate the average value of the fine delay and subtract 8. // Avg = 0; IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t PRE: "); for (Byte = 0; Byte < MAX_BYTELANES_PER_CHANNEL; Byte++) { // // This includes ECC as byte 8. ECC Byte lane (8) is ignored by MemNGetTrainDlyNb function where // ECC is not supported. // PREvalue = (UINT8) (0x1F & MemNGetTrainDlyNb (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (0, Byte))); Avg = Avg + ((INT16) PREvalue); IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", PREvalue); } Avg = ((Avg + 8) / 9); // round up NBPtr->MemNPFenceAdjustNb (NBPtr, &Avg); IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFence: %02x\n", Avg); // 7. Write the value to F2x[1, 0]9C_x0C[PhyFence]. MemNSetBitFieldNb (NBPtr, BFPhyFence, Avg); // 8. BIOS rewrites F2x[1, 0]9C_x04, DRAM Address/Command Timing Control // Register delays for both channels. This forces the phy to recompute // the fence. // MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, MemNGetBitFieldNb (NBPtr, BFAddrTmgControl)); }
VOID MemNAfterDQSTrainingOr ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT8 Dct; UINT8 Dimm; UINT8 Byte; UINT16 Dly; BOOLEAN DllShutDownEn; DllShutDownEn = TRUE; IDS_OPTION_HOOK (IDS_DLL_SHUT_DOWN, &DllShutDownEn, &(NBPtr->MemPtr->StdHeader)); for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { // // 2.10.6.6 DCT Training Specific Configuration // MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 1); MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 0); if (DllShutDownEn && NBPtr->IsSupported[SetDllShutDown]) { MemNSetBitFieldNb (NBPtr, BFDisDllShutdownSR, 0); } MemNSetBitFieldNb (NBPtr , BFForceAutoPchg, 0); MemNSetBitFieldNb (NBPtr , BFDynPageCloseEn, 0); if (NBPtr->RefPtr->EnableBankSwizzle) { MemNSetBitFieldNb (NBPtr, BFBankSwizzleMode, 1); } MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0x0F); MemNPowerDownCtlOr (NBPtr); MemNSetBitFieldNb (NBPtr, BFDisSimulRdWr, 0); MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 2); // // Post Training values for BFRxMaxDurDllNoLock, BFTxMaxDurDllNoLock, // and BFEnRxPadStandby are handled by Power savings code // // BFBwCapEn and BFODTSEn are handled by OnDimmThermal Code // // BFDctSelIntLvEn is programmed by Interleaving feature // // BFL3Scrub, BFDramScrub, and DramScrubReDirEn are programmed by ECC Feature code // // MemNSetBitFieldNb (NBPtr, BFL3ScrbRedirDis, 0); // Doing DataTxFifoWrDly override for NB PState 0 MemNDataTxFifoWrDlyOverrideOr (NBPtr, NBPtr); } } // // Synch RdDqs__Dly to RdDqsDly for S3 Save/Restore // for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { if (!(NBPtr->DctCachePtr->Is__x4)) { // Only synch when 1D training has been performed or training with x8 DIMMs for (Dimm = 0; Dimm < 4; Dimm++) { for (Byte = 0; Byte < 9; Byte++) { Dly = (UINT16) MemNGetTrainDlyNb (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, Byte)); MemNSetTrainDlyNb (NBPtr, AccessRdDqs__Dly, DIMM_NBBL_ACCESS (Dimm, Byte * 2), Dly); MemNSetTrainDlyNb (NBPtr, AccessRdDqs__Dly, DIMM_NBBL_ACCESS (Dimm, (Byte * 2) + 1), Dly); NBPtr->ChannelPtr->RdDqs__Dlys[(Dimm * MAX_NUMBER_LANES) + (Byte * 2)] = (UINT8) Dly; NBPtr->ChannelPtr->RdDqs__Dlys[(Dimm * MAX_NUMBER_LANES) + (Byte * 2) + 1] = (UINT8) Dly; } } } } } }