UINT32 STATIC MemNGetODTDelaysTN ( IN OUT MEM_NB_BLOCK *NBPtr ) { INT8 Ld; UINT32 ODTDelays; // // The BIOS must additionally configure the ODT pattern // and the ODT switching delays. // // Program F2x[1, 0]9C_x83 DRAM Phy ODT Assertion Control Register based on Burst length. // -Read the Burst Length from F2x[1, 0]84[BurstCtrl]. // -Value of 2, BL = 4 else assume BL=8. // -Initialize ODTDelays based on BL value // -WrOdtOnDuration [14:12] = BL / 2 + 1 // -WrOdtTrnOnDly [10:8] = 0 // -RdOdtOnDuration [6:4] = BL / 2 + 1 // ODTDelays = (MemNGetBitFieldNb (NBPtr, BFBurstCtrl) == 2) ? 0x00003030 : 0x00005050; // RdOdtTrnOnDly [3:0] < (CL-CWL) or (CL-CWL - 1) // See BKDG F2x[1, 0]9C_x83 DRAM Phy ODT Assertion Control Register [3:0] Ld = ((INT8)MemNGetBitFieldNb (NBPtr, BFTcl) + 1) - ((INT8)MemNGetBitFieldNb (NBPtr, BFTcwl) + 5); if (Ld < 0) { Ld = 0; } if (Ld > 7) { Ld = 7; } ODTDelays += Ld; return ODTDelays; }
BOOLEAN MemNFinalizeMctDA ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT8 Dct; MEM_DATA_STRUCT *MemPtr; S_UINT64 SMsr; MemPtr = NBPtr->MemPtr; MemNSetBitFieldNb (NBPtr, BFAdapPrefMissRatio, 1); MemNSetBitFieldNb (NBPtr, BFAdapPrefPosStep, 0); MemNSetBitFieldNb (NBPtr, BFAdapPrefNegStep, 0); MemNSetBitFieldNb (NBPtr, BFCohPrefPrbLmt, 1); // Recommended settings for F2x11C MemNSetBitFieldNb (NBPtr, BFMctWrLimit, 16); MemNSetBitFieldNb (NBPtr, BFPrefCpuDis, 0); MemNSetBitFieldNb (NBPtr, BFPrefIoDis, 0); MemNSetBitFieldNb (NBPtr, BFFlushWrOnStpGnt, 1); // For power saving for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { NBPtr->SwitchDCT (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { if (NBPtr->ChannelPtr->Dimmx4Present == 0) { MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) | 0x80)); } if (!NBPtr->MCTPtr->Status[SbEccDimms]) { MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0830, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0830) | 0x10)); } MemNSetBitFieldNb (NBPtr, BFPhy0x0D07812F, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D07812F) | 0x01)); } } if (NBPtr->Node == BSP_DIE) { if (!NBPtr->ClToNbFlag) { LibAmdMsrRead (BU_CFG2, (UINT64 *)&SMsr, &MemPtr->StdHeader); SMsr.lo &= ~((UINT32)1 << 15); // ClLinesToNbDis LibAmdMsrWrite (BU_CFG2, (UINT64 *)&SMsr, &MemPtr->StdHeader); } LibAmdMsrRead (BU_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader); SMsr.hi &= ~((UINT32)1 << (48 - 32)); // WbEnhWsbDis LibAmdMsrWrite (BU_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader); } return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); }
/** * * Check if bitfields of all enabled DCTs on a die have the expected value. Ignore * DCTs that are disabled. * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in] FieldName - Bit Field name * @param[in] Field - Value to be checked * * @return TRUE - All enabled DCTs have the expected value on the bitfield. * @return FALSE - Not all enabled DCTs have the expected value on the bitfield. * * ---------------------------------------------------------------------------- */ BOOLEAN MemNBrdcstCheckON ( IN OUT MEM_NB_BLOCK *NBPtr, IN BIT_FIELD_NAME FieldName, IN UINT32 Field ) { if (MemNGetBitFieldNb (NBPtr, FieldName) != Field) { return FALSE; } return TRUE; }
BOOLEAN MemNOverrideRcvEnSeedOr ( IN OUT MEM_NB_BLOCK *NBPtr, IN OUT VOID *SeedPtr ) { UINT16 *SeedPointer; SeedPointer = (UINT16*) SeedPtr; // // Get seed value saved in PS block // *SeedPointer = NBPtr->PsPtr->HWRxENSeedVal; *SeedPointer -= (0x20 * (UINT16) MemNGetBitFieldNb (NBPtr, BFWrDqDqsEarly)); return TRUE; }
BOOLEAN MemNFinalizeMctC32 ( IN OUT MEM_NB_BLOCK *NBPtr ) { MEM_DATA_STRUCT *MemPtr; S_UINT64 SMsr; UINT16 Speed; UINT32 ExtMctCfgLoRegVal; MemPtr = NBPtr->MemPtr; Speed = NBPtr->DCTPtr->Timings.Speed; MemNSetBitFieldNb (NBPtr, BFMctCfgHiReg, (!NBPtr->Ganged) ? 0x2CE00F60 : 0x2CE00F40); ExtMctCfgLoRegVal = MemNGetBitFieldNb (NBPtr, BFExtMctCfgLoReg); ExtMctCfgLoRegVal |= (NBPtr->Ganged) ? 0x0FC00001 : 0x0FC01001; ExtMctCfgLoRegVal &= 0x0FFFFFFF; if (Speed == DDR667_FREQUENCY) { ExtMctCfgLoRegVal |= 0x40000000; } else if (Speed == DDR800_FREQUENCY) { ExtMctCfgLoRegVal |= 0x50000000; } else if (Speed == DDR1066_FREQUENCY) { ExtMctCfgLoRegVal |= 0x60000000; } else if (Speed == DDR1333_FREQUENCY) { ExtMctCfgLoRegVal |= 0x80000000; } else { ExtMctCfgLoRegVal |= 0x90000000; } MemNSetBitFieldNb (NBPtr, BFExtMctCfgLoReg, ExtMctCfgLoRegVal); if (NBPtr->Node == BSP_DIE) { if (!NBPtr->ClToNbFlag) { LibAmdMsrRead (BU_CFG2, (UINT64 *)&SMsr, &MemPtr->StdHeader); SMsr.lo &= ~((UINT32)1 << 15); // ClLinesToNbDis LibAmdMsrWrite (BU_CFG2, (UINT64 *)&SMsr, &MemPtr->StdHeader); } LibAmdMsrRead (BU_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader); SMsr.hi &= ~((UINT32)1 << (48 - 32)); // WbEnhWsbDis LibAmdMsrWrite (BU_CFG, (UINT64 *)&SMsr, &MemPtr->StdHeader); } return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); }
/** * * Check if bitfields of all enabled DCTs on a die have the expected value. Ignore * DCTs that are disabled. * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in] FieldName - Bit Field name * @param[in] Field - Value to be checked * * @return TRUE - All enabled DCTs have the expected value on the bitfield. * @return FALSE - Not all enabled DCTs have the expected value on the bitfield. * * ---------------------------------------------------------------------------- */ BOOLEAN MemNBrdcstCheckNb ( IN OUT MEM_NB_BLOCK *NBPtr, IN BIT_FIELD_NAME FieldName, IN UINT32 Field ) { UINT8 Dct; UINT8 CurrentDCT; Dct = NBPtr->Dct; for (CurrentDCT = 0; CurrentDCT < NBPtr->DctCount; CurrentDCT++) { MemNSwitchDCTNb (NBPtr, CurrentDCT); if ((NBPtr->DCTPtr->Timings.DctMemSize != 0) && !((CurrentDCT == 1) && NBPtr->Ganged)) { if (MemNGetBitFieldNb (NBPtr, FieldName) != Field) { MemNSwitchDCTNb (NBPtr, Dct); return FALSE; } } } MemNSwitchDCTNb (NBPtr, Dct); return TRUE; }
VOID MemNSetOtherTimingTN ( IN OUT MEM_NB_BLOCK *NBPtr ) { INT8 ROD; INT8 WOD; INT8 LD; INT8 WrEarlyx2; INT8 CDDTrdrdSdDc; INT8 CDDTrdrdDd; INT8 CDDTwrwrDd; INT8 CDDTwrwrSdDc; INT8 CDDTrwtTO; INT8 CDDTwrrd; UINT8 TrdrdSdDc; UINT8 TrdrdDd; UINT8 TwrwrSdDc; UINT8 TwrwrDd; UINT8 TrdrdSdSc; UINT8 TwrwrSdSc; UINT8 Twrrd; UINT8 TrwtTO; BOOLEAN PerRankTimingEn; CH_DEF_STRUCT *ChannelPtr; ChannelPtr = NBPtr->ChannelPtr; PerRankTimingEn = (BOOLEAN) (MemNGetBitFieldNb (NBPtr, BFPerRankTimingEn)); // // Latency Difference (LD) = Tcl - Tcwl // LD = (INT8) (MemNGetBitFieldNb (NBPtr, BFTcl)) - (INT8) (MemNGetBitFieldNb (NBPtr, BFTcwl)); // // Read ODT Delay (ROD) = MAX ( 0, (RdOdtOnDuration - 6)) + MAX ( 0, (RdOdtTrnOnDly - LD)) // ROD = MAX (0, (INT8) (MemNGetBitFieldNb (NBPtr, BFRdOdtOnDuration) - 6)) + MAX ( 0, (INT8) (MemNGetBitFieldNb (NBPtr, BFRdOdtTrnOnDly) - LD)); // // Write ODT Delay (WOD) = MAX (0, (WrOdtOnDuration - 6)) // WOD = MAX (0, (INT8) (MemNGetBitFieldNb (NBPtr, BFWrOdtOnDuration) - 6)); // // WrEarly = ABS (WrDqDqsEarly) / 2 // WrEarlyx2 = (INT8) MemNGetBitFieldNb (NBPtr, BFWrDqDqsEarly); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tLD: %d ROD: %d WOD: %d WrEarlyx2: %d\n\n", LD, ROD, WOD, WrEarlyx2); // // Read to Read Timing (TrdrdSdSc, TrdrdScDc, TrdrdDd) // // TrdrdSdSc = 1. // TrdrdSdDc (in MEMCLKs) = MAX(TrdrdSdSc, 3 + (IF (D18F2xA8_dct[1:0][PerRankTimingEn]) // THEN CEIL(CDDTrdrdSdDc / 2 ) ELSE 0 ENDIF)). // TrdrdDd = MAX(TrdrdSdDc, CEIL(MAX(ROD + 3, CDDTrdrdDd/2 + 3.5))) // TrdrdSdSc = 1; CDDTrdrdSdDc = (INT8) MemNCalcCDDNb (NBPtr, AccessRcvEnDly, AccessRcvEnDly, TRUE, FALSE); TrdrdSdDc = MAX (0, PerRankTimingEn ? (3 + (CDDTrdrdSdDc + 1) / 2) : 3); TrdrdSdDc = MAX (TrdrdSdSc, TrdrdSdDc); CDDTrdrdDd = (INT8) MemNCalcCDDNb (NBPtr, AccessRcvEnDly, AccessRcvEnDly, FALSE, TRUE); TrdrdDd = MAX (ROD + 3, (CDDTrdrdDd + 7 + 1) / 2); TrdrdDd = MAX (TrdrdSdDc, TrdrdDd); MemNSetBitFieldNb (NBPtr, BFTrdrdDd, (UINT32) TrdrdDd); MemNSetBitFieldNb (NBPtr, BFTrdrdSdDc, (UINT32) TrdrdSdDc); MemNSetBitFieldNb (NBPtr, BFTrdrdSdSc, (UINT32) TrdrdSdSc); // // Write to Write Timing (TwrwrSdSc, TwrwrScDc, TwrwrDd) // // TwrwrSdSc = 1. // TwrwrSdDc = CEIL(MAX(WOD + 3, CDDTwrwrSdDc / 2 + // (IF (D18F2xA8_dct[1:0][PerRankTimingEn]) THEN 3.5 ELSE 3 ENDIF))). // // TwrwrDd = CEIL (MAX (WOD + 3, CDDTwrwrDd / 2 + 3.5)) // TwrwrSdSc <= TwrwrSdDc <= TwrwrDd // TwrwrSdSc = 1; CDDTwrwrSdDc = (INT8) MemNCalcCDDNb (NBPtr, AccessWrDqsDly, AccessWrDqsDly, TRUE, FALSE); TwrwrSdDc = (UINT8) MAX (WOD + 3, (CDDTwrwrSdDc + (PerRankTimingEn ? 7 : 6) + 1 ) / 2); CDDTwrwrDd = (INT8) MemNCalcCDDNb (NBPtr, AccessWrDqsDly, AccessWrDqsDly, FALSE, TRUE); TwrwrDd = (UINT8) MAX ((UINT8) (WOD + 3), (CDDTwrwrDd + 7 + 1) / 2); TwrwrSdDc = (TwrwrSdSc <= TwrwrSdDc) ? TwrwrSdDc : TwrwrSdSc; TwrwrDd = (TwrwrSdDc <= TwrwrDd) ? TwrwrDd : TwrwrSdDc; MemNSetBitFieldNb (NBPtr, BFTwrwrDd, (UINT32) TwrwrDd); MemNSetBitFieldNb (NBPtr, BFTwrwrSdDc, (UINT32) TwrwrSdDc); MemNSetBitFieldNb (NBPtr, BFTwrwrSdSc, (UINT32) TwrwrSdSc); // // Write to Read DIMM Termination Turn-around // // Twrrd = MAX ( 1, CEIL (MAX (WOD, (CDDTwrrd / 2) + 0.5 - WrEarly) - LD + 3)) // CDDTwrrd = (INT8) MemNCalcCDDNb (NBPtr, AccessWrDqsDly, AccessRcvEnDly, TRUE, TRUE); Twrrd = MAX (1, MAX (WOD, (CDDTwrrd + 1 - WrEarlyx2 + 1) / 2) - LD + 3); MemNSetBitFieldNb (NBPtr, BFTwrrd, (UINT32) Twrrd); // // Read to Write Turnaround for Data, DQS Contention // // TrwtTO = CEIL (MAX (ROD, (CDDTrwtTO / 2) - 0.5 + WrEarly) + LD + 3) // CDDTrwtTO = (INT8) MemNCalcCDDNb (NBPtr, AccessRcvEnDly, AccessWrDqsDly, TRUE, TRUE); TrwtTO = MAX ((ChannelPtr->Dimms == 1 ? 0 : ROD) , (CDDTrwtTO - 1 + WrEarlyx2 + 1) / 2) + LD + 3; MemNSetBitFieldNb (NBPtr, BFTrwtTO, (UINT32) TrwtTO); // // Read to Write Turnaround for opportunistic Write Bursting // // TrwtWB = TrwtTO + 1 // MemNSetBitFieldNb (NBPtr, BFTrwtWB, (UINT32) TrwtTO + 1); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t TrdrdSdSc : %02x\n", TrdrdSdSc); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCDDTrdrdSdDc : %02x TrdrdSdDc : %02x\n", CDDTrdrdSdDc, TrdrdSdDc); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCDDTrdrdDd : %02x TrdrdDd : %02x\n\n", CDDTrdrdDd, TrdrdDd); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t TwrwrSdSc : %02x\n", TwrwrSdSc); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCDDTwrwrSdDc : %02x TwrwrSdDc : %02x\n", CDDTwrwrSdDc, TwrwrSdDc ); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCDDTwrwrDd : %02x TwrwrDd : %02x\n\n", CDDTwrwrDd, TwrwrDd); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t TrwtWB : %02x\n", TrwtTO + 1); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCDDTwrrd : %02x Twrrd : %02x\n", (UINT8) CDDTwrrd, (UINT8) Twrrd ); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCDDTrwtTO : %02x TrwtTO : %02x\n\n", (UINT8) CDDTrwtTO, (UINT8) TrwtTO ); }
UINT32 MemNcmnGetSetTrainDlyUnb ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 IsSet, IN TRN_DLY_TYPE TrnDly, IN DRBN DrbnVar, IN UINT16 Field ) { UINT16 Index; UINT16 Offset; UINT32 Value; UINT32 Address; UINT8 Dimm; UINT8 Rank; UINT8 Byte; UINT8 Nibble; UINT8 DimmNibble; Dimm = DRBN_DIMM (DrbnVar); Rank = DRBN_RANK (DrbnVar); Byte = DRBN_BYTE (DrbnVar); Nibble = DRBN_NBBL (DrbnVar); DimmNibble = DRBN_DIMM_NBBL (DrbnVar); ASSERT (Dimm < (NBPtr->CsPerChannel / NBPtr->CsPerDelay)); ASSERT (Byte <= ECC_DLY); if ((Byte == ECC_DLY) && (!NBPtr->MCTPtr->Status[SbEccDimms] || !NBPtr->IsSupported[EccByteTraining])) { // When ECC is not enabled if (IsSet) { // On write, ignore return 0; } else { // On read, redirect to byte 0 to correct fence averaging Byte = 0; } } switch (TrnDly) { case AccessRcvEnDly: Index = 0x10; break; case AccessWrDqsDly: Index = 0x30; break; case AccessWrDatDly: Index = 0x01; break; case AccessRdDqsDly: Index = 0x05; break; case AccessRdDqs2dDly: Index = 0x00; break; case AccessPhRecDly: Index = 0x50; break; default: Index = 0; IDS_ERROR_TRAP; } switch (TrnDly) { case AccessRcvEnDly: case AccessWrDqsDly: Index += (Dimm * 3); if (Byte & 0x04) { // if byte 4,5,6,7 Index += 0x10; } if (Byte & 0x02) { // if byte 2,3,6,7 Index++; } if (Byte > 7) { Index += 2; } Offset = 16 * (Byte % 2); Index |= (Rank << 8); Index |= (Nibble << 9); Address = Index; break; case AccessRdDqsDly: case AccessWrDatDly: if (NBPtr->IsSupported[DimmBasedOnSpeed]) { if (NBPtr->DCTPtr->Timings.Speed < DDR800_FREQUENCY) { // if DDR speed is below 800, use DIMM 0 delays for all DIMMs. Dimm = 0; } } Index += (Dimm * 0x100); if (Nibble) { if (Rank) { Index += 0xA0; } else { Index += 0x70; } } else if (Rank) { Index += 0x60; } // break is not being used here because AccessRdDqsDly and AccessWrDatDly also need // to run AccessPhRecDly sequence. case AccessPhRecDly: Index += (Byte / 4); Offset = 8 * (Byte % 4); Address = Index; break; case AccessRdDqs2dDly: Address = 0x0D0F0000; Index += (DimmNibble >> 1) * 0x100; Index += 0x20; Index = Index + Dimm; Offset = 4 * ((DimmNibble & 0x01) * 2); Address += Index; break; default: Offset = 0; IDS_ERROR_TRAP; Address = Index; } MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address); MemNPollBitFieldNb (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, FALSE); Value = MemNGetBitFieldNb (NBPtr, BFDctAddlDataReg); if (TrnDly == AccessRdDqsDly) { NBPtr->FamilySpecificHook[AdjustRdDqsDlyOffset] (NBPtr, &Offset); } if (IsSet) { if (TrnDly == AccessPhRecDly) { Value = NBPtr->DctCachePtr->PhRecReg[Index & 0x03]; } if (TrnDly != AccessRdDqs2dDly) { Value = ((UINT32)Field << Offset) | (Value & (~((UINT32) ((TrnDly == AccessRcvEnDly) ? 0x3FF : 0xFF) << Offset))); } else { Value = ((UINT32)Field << Offset) | (Value & (~((UINT32) 0x1F << Offset))); } ASSERT (!NBPtr->IsSupported[ScrubberEn]); // Phy CSR write is not allowed after scrubber is enabled MemNSetBitFieldNb (NBPtr, BFDctAddlDataReg, Value); Address |= DCT_ACCESS_WRITE; MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address); MemNPollBitFieldNb (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, FALSE); if (TrnDly == AccessPhRecDly) { NBPtr->DctCachePtr->PhRecReg[Index & 0x03] = Value; } } else { if (TrnDly != AccessRdDqs2dDly) { Value = (Value >> Offset) & (UINT32) ((TrnDly == AccessRcvEnDly) ? 0x3FF : 0xFF); } else {
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 MemNPhyFenceTrainingUnb ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT8 FenceThresholdTxDll; UINT8 FenceThresholdRxDll; UINT8 FenceThresholdTxPad; UINT16 Fence2Data; MemNSetBitFieldNb (NBPtr, BFDataFence2, 0); MemNSetBitFieldNb (NBPtr, BFFence2, 0); // 1. Program D18F2x[1,0]9C_x0000_0008[FenceTrSel]=10b. // 2. Perform phy fence training. // 3. Write the calculated fence value to D18F2x[1,0]9C_x0000_000C[FenceThresholdTxDll]. MemNSetBitFieldNb (NBPtr, BFFenceTrSel, 2); MAKE_TSEFO (NBPtr->NBRegTable, DCT_PHY_ACCESS, 0x0C, 30, 26, BFPhyFence); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tFenceThresholdTxDll\n"); MemNTrainPhyFenceNb (NBPtr); FenceThresholdTxDll = (UINT8) MemNGetBitFieldNb (NBPtr, BFPhyFence); NBPtr->FamilySpecificHook[DetectMemPllError] (NBPtr, &FenceThresholdTxDll); // 4. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]0F[AlwaysEnDllClks]=001b. MemNSetBitFieldNb (NBPtr, BFAlwaysEnDllClks, 0x1000); // 5. Program D18F2x[1,0]9C_x0000_0008[FenceTrSel]=01b. // 6. Perform phy fence training. // 7. Write the calculated fence value to D18F2x[1,0]9C_x0000_000C[FenceThresholdRxDll]. MemNSetBitFieldNb (NBPtr, BFFenceTrSel, 1); MAKE_TSEFO (NBPtr->NBRegTable, DCT_PHY_ACCESS, 0x0C, 25, 21, BFPhyFence); IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFenceThresholdRxDll\n"); MemNTrainPhyFenceNb (NBPtr); FenceThresholdRxDll = (UINT8) MemNGetBitFieldNb (NBPtr, BFPhyFence); NBPtr->FamilySpecificHook[DetectMemPllError] (NBPtr, &FenceThresholdRxDll); // 8. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]0F[AlwaysEnDllClks]=000b. MemNSetBitFieldNb (NBPtr, BFAlwaysEnDllClks, 0x0000); // 9. Program D18F2x[1,0]9C_x0000_0008[FenceTrSel]=11b. // 10. Perform phy fence training. // 11. Write the calculated fence value to D18F2x[1,0]9C_x0000_000C[FenceThresholdTxPad]. MemNSetBitFieldNb (NBPtr, BFFenceTrSel, 3); MAKE_TSEFO (NBPtr->NBRegTable, DCT_PHY_ACCESS, 0x0C, 20, 16, BFPhyFence); IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFenceThresholdTxPad\n"); MemNTrainPhyFenceNb (NBPtr); FenceThresholdTxPad = (UINT8) MemNGetBitFieldNb (NBPtr, BFPhyFence); NBPtr->FamilySpecificHook[DetectMemPllError] (NBPtr, &FenceThresholdTxPad); // Program Fence2 threshold for Clk, Cmd, and Addr if (FenceThresholdTxPad < 16) { MemNSetBitFieldNb (NBPtr, BFClkFence2, FenceThresholdTxPad | 0x10); MemNSetBitFieldNb (NBPtr, BFCmdFence2, FenceThresholdTxPad | 0x10); MemNSetBitFieldNb (NBPtr, BFAddrFence2, FenceThresholdTxPad | 0x10); } else { MemNSetBitFieldNb (NBPtr, BFClkFence2, 0); MemNSetBitFieldNb (NBPtr, BFCmdFence2, 0); MemNSetBitFieldNb (NBPtr, BFAddrFence2, 0); } // Program Fence2 threshold for data Fence2Data = 0; if (FenceThresholdTxPad < 16) { Fence2Data |= FenceThresholdTxPad | 0x10; } if (FenceThresholdRxDll < 16) { Fence2Data |= (FenceThresholdRxDll | 0x10) << 10; } if (FenceThresholdTxDll < 16) { Fence2Data |= (FenceThresholdTxDll | 0x10) << 5; } MemNSetBitFieldNb (NBPtr, BFDataFence2, Fence2Data); NBPtr->FamilySpecificHook[ProgramFence2RxDll] (NBPtr, &Fence2Data); if (NBPtr->MCTPtr->Status[SbLrdimms]) { // 18. If motherboard routing requires CS[7:6] to adopt address timings, e.g. 3 LRDIMMs/ch with CS[7:6] // routed across all DIMM sockets, BIOS performs the following: if (FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_NO_LRDIMM_CS67_ROUTING, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID, 0, NULL, NULL) != NULL) { // A. Program D18F2xA8_dct[1:0][CSTimingMux67] = 1. MemNSetBitFieldNb (NBPtr, BFCSTimingMux67, 1); // B. Program D18F2x9C_x0D0F_8021_dct[1:0]: // - DiffTimingEn = 1. // - IF (D18F2x9C_x0000_0004_dct[1:0][AddrCmdFineDelay] >= // D18F2x9C_x0D0F_E008_dct[1:0][FenceValue]) THEN Fence = 1 ELSE Fence = 0. // - Delay = D18F2x9C_x0000_0004_dct[1:0][AddrCmdFineDelay]. // MemNSetBitFieldNb (NBPtr, BFDiffTimingEn, 1); MemNSetBitFieldNb (NBPtr, BFFence, (MemNGetBitFieldNb (NBPtr, BFAddrCmdFineDelay) >= MemNGetBitFieldNb (NBPtr, BFFenceValue)) ? 1 : 0); MemNSetBitFieldNb (NBPtr, BFDelay, (MemNGetBitFieldNb (NBPtr, BFAddrCmdFineDelay))); } } // 19. Reprogram F2x9C_04. MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, MemNGetBitFieldNb (NBPtr, BFAddrTmgControl)); }
VOID MemNInitPhyCompHy ( IN OUT MEM_NB_BLOCK *NBPtr ) { CONST UINT8 TableCompRiseSlew20x[] = {7, 3, 2, 2}; CONST UINT8 TableCompRiseSlew15x[] = {7, 7, 3, 2}; CONST UINT8 TableCompFallSlew20x[] = {7, 5, 3, 2}; CONST UINT8 TableCompFallSlew15x[] = {7, 7, 5, 3}; UINT8 i; UINT8 j; UINT8 CurrDct; UINT8 MaxDimmsPerChannel; UINT8 *DimmsPerChPtr; CurrDct = NBPtr->Dct; // // Get Platform Information // DimmsPerChPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MAX_DIMMS, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID); if (DimmsPerChPtr != NULL) { MaxDimmsPerChannel = *DimmsPerChPtr; } else { MaxDimmsPerChannel = 2; } // 1. BIOS disables the phy compensation register by programming F2x9C_x08[DisAutoComp]=1 // 2. BIOS waits 5 us for the disabling of the compensation engine to complete. // DisAutoComp will be cleared after Dram init has completed // MemNSwitchDCTNb (NBPtr, 0); MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 1); MemUWait10ns (500, NBPtr->MemPtr); MemNSwitchDCTNb (NBPtr, CurrDct); // 3. For each normalized driver strength code read from // F2x[1, 0]9C_x00[AddrCmdDrvStren], program the // corresponding 3 bit predriver code in F2x9C_x0A[D3Cmp1NCal, D3Cmp1PCal]. // // 4. For each normalized driver strength code read from // F2x[1, 0]9C_x00[DataDrvStren], program the corresponding // 3 bit predriver code in F2x9C_x0A[D3Cmp0NCal, D3Cmp0PCal, D3Cmp2NCal, // D3Cmp2PCal]. // j = (UINT8) MemNGetBitFieldNb (NBPtr, BFAddrCmdDrvStren); i = (UINT8) MemNGetBitFieldNb (NBPtr, BFDataDrvStren); MemNSwitchDCTNb (NBPtr, 0); ASSERT (j <= 3); MemNSetBitFieldNb (NBPtr, BFD3Cmp1NCal, TableCompRiseSlew20x[j]); MemNSetBitFieldNb (NBPtr, BFD3Cmp1PCal, TableCompFallSlew20x[j]); ASSERT (i <= 3); MemNSetBitFieldNb (NBPtr, BFD3Cmp0NCal, TableCompRiseSlew15x[i]); MemNSetBitFieldNb (NBPtr, BFD3Cmp0PCal, TableCompFallSlew15x[i]); MemNSetBitFieldNb (NBPtr, BFD3Cmp2NCal, TableCompRiseSlew15x[i]); MemNSetBitFieldNb (NBPtr, BFD3Cmp2PCal, TableCompFallSlew15x[i]); // // Special Case for certain configs // // 3DPCH Fully populated. if ((MaxDimmsPerChannel == 3) && (NBPtr->ChannelPtr->Dimms == 3)) { MemNSetBitFieldNb (NBPtr, BFD3Cmp0NCal, 3); MemNSetBitFieldNb (NBPtr, BFD3Cmp0PCal, 5); MemNSetBitFieldNb (NBPtr, BFD3Cmp2NCal, 3); MemNSetBitFieldNb (NBPtr, BFD3Cmp2PCal, 5); } MemNSwitchDCTNb (NBPtr, CurrDct); }
/** * * * This function defines the DDR3 initialization flow * when only DDR3 DIMMs are present in the system * * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK * * @return AGESA_STATUS * - AGESA_FATAL * - AGESA_CRITICAL * - AGESA_SUCCESS */ AGESA_STATUS MemMD3FlowKV ( IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr ) { UINT8 Dct; MEM_NB_BLOCK *NBPtr; MEM_DATA_STRUCT *MemPtr; ID_INFO CallOutIdInfo; INT8 MemPstate; UINT8 LowestMemPstate; UINT8 PmuImage; BOOLEAN ErrorRecovery; BOOLEAN IgnoreErr; NBPtr = &MemMainPtr->NBPtr[BSP_DIE]; MemPtr = MemMainPtr->MemPtr; ErrorRecovery = TRUE; IgnoreErr = FALSE; IDS_HDT_CONSOLE (MEM_FLOW, "DDR3 Mode\n"); //---------------------------------------------------------------- // Defines DDR3 registers //---------------------------------------------------------------- MemNInitNBRegTableD3KV (NBPtr); //---------------------------------------------------------------- // Clock and power gate unsued channels //---------------------------------------------------------------- MemNClockAndPowerGateUnusedDctKV (NBPtr); //---------------------------------------------------------------- // Set DDR3 mode //---------------------------------------------------------------- MemNSetDdrModeD3KV (NBPtr); //---------------------------------------------------------------- // Enable PHY Calibration //---------------------------------------------------------------- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctDimmValid != 0) { MemNEnablePhyCalibrationKV (NBPtr); } } //---------------------------------------------------------------- // Low voltage DDR3 //---------------------------------------------------------------- // Levelize DDR3 voltage based on socket, as each socket has its own voltage for dimms. AGESA_TESTPOINT (TpProcMemLvDdr3, &(MemMainPtr->MemPtr->StdHeader)); if (!MemFeatMain.LvDDR3 (MemMainPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // Find the maximum speed that all DCTs are capable running at //---------------------------------------------------------------- if (!MemTSPDGetTargetSpeed3 (NBPtr->TechPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // Adjust memClkFreq based on MaxDdrRate //---------------------------------------------------------------- MemNAdjustDdrSpeed3Unb (NBPtr); //------------------------------------------------ // Finalize target frequency //------------------------------------------------ if (!MemMLvDdr3PerformanceEnhFinalize (MemMainPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // Program DCT address map //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "DCT addr map\n"); for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctDimmValid == 0) { MemNDisableDctKV (NBPtr); } else { IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCS Addr Map\n"); if (MemTSPDSetBanks3 (NBPtr->TechPtr)) { if (MemNStitchMemoryNb (NBPtr)) { if (NBPtr->DCTPtr->Timings.CsEnabled == 0) { MemNDisableDctKV (NBPtr); } else { IDS_HDT_CONSOLE (MEM_FLOW, "\t\tAuto Cfg\n"); MemNAutoConfigKV (NBPtr); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tTraining Cfg\n"); MemNConfigureDctForTrainingD3KV (NBPtr); } } } } } IDS_OPTION_HOOK (IDS_BEFORE_DRAM_INIT, NBPtr, &(MemMainPtr->MemPtr->StdHeader)); //---------------------------------------------------------------- // Init Phy mode //---------------------------------------------------------------- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); // 1. Program D18F2x9C_x0002_0099_dct[3:0][PmuReset,PmuStall] = 1,1. // 2. Program D18F2x9C_x0002_000E_dct[3:0][PhyDisable]=0. Tester_mode=0. MemNPmuResetNb (NBPtr); // 3. According to the type of DRAM attached, program D18F2x9C_x00FFF04A_dct[3:0][MajorMode], // D18F2x9C_x0002_000E_dct[3:0][G5_Mode], and D18F2x9C_x0002_0098_dct[3:0][CalG5D3]. // D18F2x9C_x0[3,1:0][F,7:0]1_[F,B:0]04A_dct[3:0]. MemNSetPhyDdrModeKV (NBPtr, DRAM_TYPE_DDR3_KV); // Work-around for CPU A0/A1, PhyReceiverPowerMode if ((NBPtr->MCTPtr->LogicalCpuid.Revision & AMD_F15_KV_A0) != 0) { MemNPrePhyReceiverLowPowerKV (NBPtr); } } } //---------------------------------------------------------------- // Temporary buffer for DRAM CAD Bus Configuration //---------------------------------------------------------------- if (!MemNInitDramCadBusConfigKV (NBPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // Program Mem Pstate dependent registers //---------------------------------------------------------------- IEM_SKIP_CODE (IEM_EARLY_DCT_CONFIG) { // PMU required M1 settings regardless Memory Pstate disabled. LowestMemPstate = 1; } for (MemPstate = LowestMemPstate; MemPstate >= 0; MemPstate--) { // When memory pstate is enabled, this loop will goes through M1 first then M0 // Otherwise, this loop only goes through M0. MemNSwitchMemPstateKV (NBPtr, MemPstate); // By default, start up speed is DDR667 for M1 // For M0, we need to set speed to highest possible frequency if (MemPstate == 0) { for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); NBPtr->DCTPtr->Timings.Speed = NBPtr->DCTPtr->Timings.TargetSpeed; } } IDS_HDT_CONSOLE (MEM_FLOW, "MemClkFreq = %d MHz\n", NBPtr->DCTPtr->Timings.Speed); // Program SPD timings and frequency dependent settings for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { IDS_HDT_CONSOLE (MEM_FLOW, "\t\tSPD timings\n"); if (MemTAutoCycTiming3 (NBPtr->TechPtr)) { IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMemPs Reg\n"); MemNProgramMemPstateRegD3KV (NBPtr, MemPstate); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tPlatform Spec\n"); if (MemNPlatformSpecKV (NBPtr)) { MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0); // 7. Program default CAD bus values. // 8. Program default data bus values. IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCAD Data Bus Cfg\n"); MemNProgramCadDataBusD3KV (NBPtr); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tPredriver\n"); MemNPredriverInitKV (NBPtr); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMode Register initialization\n"); MemNModeRegisterInitializationKV (NBPtr); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDRAM PHY Power Savings\n"); MemNDramPhyPowerSavingsKV (NBPtr); } } } } MemFInitTableDrive (NBPtr, MTBeforeDInit); } //---------------------------------------------------------------- // Program Phy //---------------------------------------------------------------- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); // 4. Program general phy static configuration. See 2.10.7.3.1. MemNPhyGenCfgKV (NBPtr); // 5. Phy Voltage Level Programming. See 2.10.7.3.2. MemNPhyVoltageLevelKV (NBPtr); // 6. Program DRAM channel frequency. See 2.10.7.3.3. MemNProgramChannelFreqKV (NBPtr, DRAM_TYPE_DDR3_KV); // Step 7 and 8 are done in MemPs dependent section // 9. Program FIFO pointer init values. See 2.10.7.3.6. MemNPhyFifoConfigD3KV (NBPtr); } } IEM_INSERT_CODE (IEM_EARLY_DEVICE_INIT, IemEarlyDeviceInitD3KV, (NBPtr)); //------------------------------------------------ // Callout before Dram Init //------------------------------------------------ AGESA_TESTPOINT (TpProcMemBeforeAgesaHookBeforeDramInit, &(MemMainPtr->MemPtr->StdHeader)); CallOutIdInfo.IdField.SocketId = NBPtr->MCTPtr->SocketId; CallOutIdInfo.IdField.ModuleId = NBPtr->MCTPtr->DieId; //------------------------------------------------------------------------ // Callout to Platform BIOS to set the VDDP/VDDR voltage based upon Bit 21 // ProductIdentification Register (Dev18Fun3x1FC) //------------------------------------------------------------------------ if (MemNGetBitFieldNb (NBPtr, BFVddpVddrLowVoltSupp)) { MemMainPtr->MemPtr->ParameterListPtr->VddpVddrVoltage.Voltage = VOLT0_95; MemMainPtr->MemPtr->ParameterListPtr->VddpVddrVoltage.IsValid = TRUE; NBPtr->DCTPtr->Timings.TargetSpeed = DDR1600_FREQUENCY; } else { MemMainPtr->MemPtr->ParameterListPtr->VddpVddrVoltage.IsValid = FALSE; } IDS_HDT_CONSOLE (MEM_FLOW, "\nCalling out to Platform BIOS on Socket %d, Module %d...\n", CallOutIdInfo.IdField.SocketId, CallOutIdInfo.IdField.ModuleId); AgesaHookBeforeDramInit ((UINTN) CallOutIdInfo.IdInformation, MemMainPtr->MemPtr); NBPtr[BSP_DIE].FamilySpecificHook[AmpVoltageDisp] (&NBPtr[BSP_DIE], NULL); IDS_HDT_CONSOLE (MEM_FLOW, "\nVDDIO = 1.%dV\n", (NBPtr->RefPtr->DDR3Voltage == VOLT1_5) ? 5 : (NBPtr->RefPtr->DDR3Voltage == VOLT1_35) ? 35 : (NBPtr->RefPtr->DDR3Voltage == VOLT1_25) ? 25 : 999); AGESA_TESTPOINT (TpProcMemAfterAgesaHookBeforeDramInit, &(NBPtr->MemPtr->StdHeader)); //---------------------------------------------------------------------------- // Deassert MemResetL //---------------------------------------------------------------------------- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { // Deassert Procedure: // MemResetL = 0 // Go to LP2 // Go to PS0 MemNSetBitFieldNb (NBPtr, BFMemResetL, 0); MemNSetBitFieldNb (NBPtr, RegPwrStateCmd, 4); MemNSetBitFieldNb (NBPtr, RegPwrStateCmd, 0); } } MemUWait10ns (20000, NBPtr->MemPtr); //---------------------------------------------------------------------------- // Program PMU SRAM Message Block, Initiate PMU based Dram init and training //---------------------------------------------------------------------------- for (PmuImage = 0; PmuImage < MemNNumberOfPmuFirmwareImageKV (NBPtr); ++PmuImage) { NBPtr->PmuFirmwareImage = PmuImage; NBPtr->FeatPtr->LoadPmuFirmware (NBPtr); for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { IDS_HDT_CONSOLE (MEM_STATUS, "Dct %d\n", Dct); IDS_HDT_CONSOLE (MEM_FLOW, "Initialize the PMU SRAM Message Block buffer\n"); if (MemNInitPmuSramMsgBlockKV (NBPtr) == FALSE) { IDS_HDT_CONSOLE (MEM_FLOW, "\tNot able to initialize the PMU SRAM Message Block buffer\n"); // Not able to initialize the PMU SRAM Message Block buffer. Log an event. PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_PMU_SRAM_MSG_BLOCK, 0, 0, 0, 0, &(MemMainPtr->MemPtr->StdHeader)); return AGESA_FATAL; } for (MemPstate = LowestMemPstate; MemPstate >= 0; MemPstate--) { // When memory pstate is enabled, this loop will goes through M1 first then M0 // Otherwise, this loop only goes through M0. MemNSwitchMemPstateKV (NBPtr, MemPstate); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tPMU MemPs Reg\n"); MemNPopulatePmuSramTimingsD3KV (NBPtr); } MemNPopulatePmuSramConfigD3KV (NBPtr); MemNSetPmuSequenceControlKV (NBPtr); if (MemNWritePmuSramMsgBlockKV (NBPtr) == FALSE) { IDS_HDT_CONSOLE (MEM_FLOW, "\tNot able to load the PMU SRAM Message Block in to DMEM\n"); // Not able to load the PMU SRAM Message Block in to DMEM. Log an event. PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_LOCATE_FOR_PMU_SRAM_MSG_BLOCK, 0, 0, 0, 0, &(MemMainPtr->MemPtr->StdHeader)); return AGESA_FATAL; } // Query for the calibrate completion. MemNPendOnPhyCalibrateCompletionKV (NBPtr); // Set calibration rate. MemNStartPmuNb (NBPtr); } } for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); if (MemNPendOnPmuCompletionNb (NBPtr) == FALSE) { PutEventLog (AGESA_FATAL, MEM_ERROR_PMU_TRAINING, 0, 0, 0, 0, &(MemMainPtr->MemPtr->StdHeader)); AGESA_TESTPOINT (TpProcMemPmuFailed, &(MemMainPtr->MemPtr->StdHeader)); IDS_OPTION_HOOK (IDS_MEM_ERROR_RECOVERY, &ErrorRecovery, &(MemMainPtr->MemPtr->StdHeader)); if (ErrorRecovery) { IDS_HDT_CONSOLE (MEM_FLOW, "Chipselects that PMU failed training %x\n",MemNGetBitFieldNb (NBPtr, PmuTestFail)); NBPtr->DCTPtr->Timings.CsTrainFail = (UINT16) MemNGetBitFieldNb (NBPtr, PmuTestFail); NBPtr->MCTPtr->ChannelTrainFail |= (UINT32)1 << Dct; } else { IDS_OPTION_HOOK (IDS_MEM_IGNORE_ERROR, &IgnoreErr, &(MemMainPtr->MemPtr->StdHeader)); if (!(IgnoreErr)) { return AGESA_FATAL; } } } MemNRateOfPhyCalibrateKV (NBPtr); } } } //---------------------------------------------------------------- // De-allocate the PMU SRAM Message Block buffer. //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "De-allocate PMU SRAM Message Block buffer\n"); if (MemNPostPmuSramMsgBlockKV (NBPtr) == FALSE) { IDS_HDT_CONSOLE (MEM_FLOW, "\tNot able to free the PMU SRAM Message Block buffer\n"); // Not able to free the PMU SRAM Message Block buffer. Log an event. PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_DEALLOCATE_FOR_PMU_SRAM_MSG_BLOCK, 0, 0, 0, 0, &(MemMainPtr->MemPtr->StdHeader)); return AGESA_FATAL; } //---------------------------------------------------------------- // De-allocate temporary buffer for DRAM CAD Bus Configuration //---------------------------------------------------------------- if (!MemNPostDramCadBusConfigKV (NBPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // Disable chipselects that failed training //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDIMM Excludes\n"); MemNDimmExcludesKV (NBPtr); //---------------------------------------------------------------- // Synchronize Channels //---------------------------------------------------------------- MemNSyncChannelInitKV (NBPtr); //---------------------------------------------------------------- // Train MaxRdLatency //---------------------------------------------------------------- IEM_SKIP_CODE (IEM_LATE_DCT_CONFIG) { NBPtr->TechPtr->FindMaxDlyForMaxRdLat = MemTFindMaxRcvrEnDlyTrainedByPmuByte; NBPtr->TechPtr->ResetDCTWrPtr = MemNResetRcvFifoKV; MemTTrainMaxLatency (NBPtr->TechPtr); // The fourth loop will restore the Northbridge P-State control register // to the original value. for (NBPtr->NbFreqChgState = 1; NBPtr->NbFreqChgState <= 4; NBPtr->NbFreqChgState++) { if (!MemNChangeNbFrequencyWrapUnb (NBPtr, NBPtr->NbFreqChgState) || (NBPtr->NbFreqChgState == 4)) { break; } MemTTrainMaxLatency (NBPtr->TechPtr); } } //---------------------------------------------------------------- // Set MajorMode //---------------------------------------------------------------- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); // Work-around for CPU A0/A1, PhyReceiverPowerMode if ((NBPtr->MCTPtr->LogicalCpuid.Revision & AMD_F15_KV_A0) != 0) { MemNPostPhyReceiverLowPowerKV (NBPtr); } } //---------------------------------------------------------------- // Configure DCT for normal operation //---------------------------------------------------------------- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMission mode cfg\n"); MemNConfigureDctNormalD3KV (NBPtr); //---------------------------------------------------------------- // Program turnaround timings //---------------------------------------------------------------- for (MemPstate = LowestMemPstate; MemPstate >= 0; MemPstate--) { MemNSwitchMemPstateKV (NBPtr, MemPstate); MemNProgramTurnaroundTimingsD3KV (NBPtr); //---------------------------------------------------------------- // After Mem Pstate1 Partial Training Table values //---------------------------------------------------------------- MemFInitTableDrive (NBPtr, MTAfterMemPstate1PartialTrn); } } } IEM_INSERT_CODE (IEM_LATE_DCT_CONFIG, IemLateDctConfigD3KV, (NBPtr)); for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { IDS_HDT_CONSOLE (MEM_FLOW, "\t\tAdditional DRAM PHY Power Savings\n"); MemNAddlDramPhyPowerSavingsKV (NBPtr); } } //---------------------------------------------------------------- // Initialize Channels interleave address bit. //---------------------------------------------------------------- MemNInitChannelIntlvAddressBitKV (NBPtr); //---------------------------------------------------------------- // Assign physical address ranges for DCTs and node. Also, enable channel interleaving. //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "\t\tHT mem map\n"); if (!NBPtr->FeatPtr->InterleaveChannels (NBPtr)) { MemNHtMemMapKV (NBPtr); } //---------------------------------------------------- // If there is no dimm on the system, do fatal exit //---------------------------------------------------- if (NBPtr->RefPtr->SysLimit == 0) { PutEventLog (AGESA_FATAL, MEM_ERROR_NO_DIMM_FOUND_ON_SYSTEM, 0, 0, 0, 0, &(MemMainPtr->MemPtr->StdHeader)); return AGESA_FATAL; } //---------------------------------------------------------------- // CpuMemTyping //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMem typing\n"); MemNCPUMemTypingNb (NBPtr); IDS_OPTION_HOOK (IDS_BEFORE_DQS_TRAINING, MemMainPtr, &(MemMainPtr->MemPtr->StdHeader)); //---------------------------------------------------------------- // After Training Table values //---------------------------------------------------------------- MemFInitTableDrive (NBPtr, MTAfterTrn); //---------------------------------------------------------------- // Interleave banks //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "\t\tBank Intlv\n"); if (NBPtr->FeatPtr->InterleaveBanks (NBPtr)) { if (NBPtr->MCTPtr->ErrCode == AGESA_FATAL) { return AGESA_FATAL; } } //---------------------------------------------------------------- // After Programming Interleave registers //---------------------------------------------------------------- MemFInitTableDrive (NBPtr, MTAfterInterleave); //---------------------------------------------------------------- // Memory Clear //---------------------------------------------------------------- AGESA_TESTPOINT (TpProcMemMemClr, &(MemMainPtr->MemPtr->StdHeader)); if (!MemFeatMain.MemClr (MemMainPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // ECC //---------------------------------------------------------------- if (!MemFeatMain.InitEcc (MemMainPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // C6 and ACP Engine Storage Allocation //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "\t\tC6 and ACP Engine Storage\n"); MemNAllocateC6AndAcpEngineStorageKV (NBPtr); //---------------------------------------------------------------- // UMA Allocation & UMAMemTyping //---------------------------------------------------------------- AGESA_TESTPOINT (TpProcMemUMAMemTyping, &(MemMainPtr->MemPtr->StdHeader)); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tUMA Alloc\n"); if (!MemFeatMain.UmaAllocation (MemMainPtr)) { return AGESA_FATAL; } //---------------------------------------------------------------- // OnDimm Thermal //---------------------------------------------------------------- if (NBPtr->FeatPtr->OnDimmThermal (NBPtr)) { if (NBPtr->MCTPtr->ErrCode == AGESA_FATAL) { return AGESA_FATAL; } } //---------------------------------------------------------------- // Finalize MCT //---------------------------------------------------------------- MemNFinalizeMctKV (NBPtr); MemFInitTableDrive (NBPtr, MTAfterFinalizeMCT); //---------------------------------------------------------------- // Memory Context Save //---------------------------------------------------------------- MemFeatMain.MemSave (MemMainPtr); //---------------------------------------------------------------- // Memory DMI support //---------------------------------------------------------------- if (!MemFeatMain.MemDmi (MemMainPtr)) { return AGESA_CRITICAL; } //---------------------------------------------------------------- // Memory CRAT support //---------------------------------------------------------------- if (!MemFeatMain.MemCrat (MemMainPtr)) { return AGESA_CRITICAL; } //---------------------------------------------------------------- // Save memory S3 data //---------------------------------------------------------------- IDS_HDT_CONSOLE (MEM_FLOW, "\t\tS3 Save\n"); if (!MemMS3Save (MemMainPtr)) { return AGESA_CRITICAL; } //---------------------------------------------------------------- // Switch back to DCT 0 before sending control back //---------------------------------------------------------------- MemNSwitchDCTNb (NBPtr, 0); return AGESA_SUCCESS; }
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); } } }
VOID MemNInitPhyCompOr ( IN OUT MEM_NB_BLOCK *NBPtr ) { // // Phy Predriver Calibration Codes for Data/DQS // CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV15Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V {DDR667 + DDR800, {0x924, 0x924, 0x924, 0x924}}, {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}, {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}} }; CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV135Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V {DDR667 + DDR800, {0xFF6, 0xB6D, 0xB6D, 0x924}}, {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}, {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}} }; CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV125Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V {DDR667 + DDR800, {0xFF6, 0xDAD, 0xDAD, 0x924}}, {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}, {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}} }; CONST STATIC TXPREPN_ENTRY TxPrePNDataDqsOr[] = { {GET_SIZE_OF (TxPrePNDataDqsV15Or), (TXPREPN_STRUCT *)&TxPrePNDataDqsV15Or}, {GET_SIZE_OF (TxPrePNDataDqsV135Or), (TXPREPN_STRUCT *)&TxPrePNDataDqsV135Or}, {GET_SIZE_OF (TxPrePNDataDqsV125Or), (TXPREPN_STRUCT *)&TxPrePNDataDqsV125Or} }; // // Phy Predriver Calibration Codes for Data/DQS // CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV15OrB1[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V {DDR667 + DDR800, {0xB6D, 0x6DB, 0x492, 0x492}}, {DDR1066 + DDR1333, {0xFFF, 0x924, 0x6DB, 0x6DB}}, {DDR1600 + DDR1866, {0xFFF, 0xFFF, 0xFFF, 0xB6D}} }; CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV135OrB1[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V {DDR667 + DDR800, {0xFFF, 0x924, 0x6DB, 0x492}}, {DDR1066 + DDR1333, {0xFFF, 0xDB6, 0xB6D, 0x6DB}}, {DDR1600 + DDR1866, {0xFFF, 0xFFF, 0xFFF, 0xDB6}} }; CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV125OrB1[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V {DDR667 + DDR800, {0xFFF, 0xB6D, 0x924, 0x6DB}}, {DDR1066 + DDR1333, {0xFFF, 0xFFF, 0xDB6, 0x924}}, {DDR1600 + DDR1866, {0xFFF, 0xFFF, 0xFFF, 0xFFF}} }; CONST STATIC TXPREPN_ENTRY TxPrePNDataDqsOrB1[] = { {GET_SIZE_OF (TxPrePNDataDqsV15OrB1), (TXPREPN_STRUCT *)&TxPrePNDataDqsV15OrB1}, {GET_SIZE_OF (TxPrePNDataDqsV135OrB1), (TXPREPN_STRUCT *)&TxPrePNDataDqsV135OrB1}, {GET_SIZE_OF (TxPrePNDataDqsV125OrB1), (TXPREPN_STRUCT *)&TxPrePNDataDqsV125OrB1} }; // // Phy Predriver Calibration Codes for Cmd/Addr // CONST STATIC TXPREPN_STRUCT TxPrePNCmdAddrV15Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V {DDR667 + DDR800, {0x492, 0x492, 0x492, 0x492}}, {DDR1066 + DDR1333, {0x6DB, 0x6DB, 0x6DB, 0x6DB}}, {DDR1600 + DDR1866, {0xB6D, 0xB6D, 0xB6D, 0xB6D}} }; CONST STATIC TXPREPN_STRUCT TxPrePNCmdAddrV135Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V {DDR667 + DDR800, {0x492, 0x492, 0x492, 0x492}}, {DDR1066 + DDR1333, {0x924, 0x6DB, 0x6DB, 0x6DB}}, {DDR1600 + DDR1866, {0xB6D, 0xB6D, 0x924, 0x924}} }; CONST STATIC TXPREPN_STRUCT TxPrePNCmdAddrV125Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V {DDR667 + DDR800, {0x492, 0x492, 0x492, 0x492}}, {DDR1066 + DDR1333, {0xDAD, 0x924, 0x6DB, 0x492}}, {DDR1600 + DDR1866, {0xFF6, 0xDAD, 0xB64, 0xB64}} }; CONST STATIC TXPREPN_ENTRY TxPrePNCmdAddrOr[] = { {GET_SIZE_OF (TxPrePNCmdAddrV15Or), (TXPREPN_STRUCT *)&TxPrePNCmdAddrV15Or}, {GET_SIZE_OF (TxPrePNCmdAddrV135Or), (TXPREPN_STRUCT *)&TxPrePNCmdAddrV135Or}, {GET_SIZE_OF (TxPrePNCmdAddrV125Or), (TXPREPN_STRUCT *)&TxPrePNCmdAddrV125Or} }; // // Phy Predriver Calibration Codes for Clock // CONST STATIC TXPREPN_STRUCT TxPrePNClockV15Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V {DDR667 + DDR800, {0x924, 0x924, 0x924, 0x924}}, {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xB6D}}, {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}} }; CONST STATIC TXPREPN_STRUCT TxPrePNClockV135Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V {DDR667 + DDR800, {0xDAD, 0xDAD, 0x924, 0x924}}, {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xDAD}}, {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xDAD}} }; CONST STATIC TXPREPN_STRUCT TxPrePNClockV125Or[] = { //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V {DDR667 + DDR800, {0xDAD, 0xDAD, 0x924, 0x924}}, {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}, {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}} }; CONST STATIC TXPREPN_ENTRY TxPrePNClockOr[] = { {GET_SIZE_OF (TxPrePNClockV15Or), (TXPREPN_STRUCT *)&TxPrePNClockV15Or}, {GET_SIZE_OF (TxPrePNClockV135Or), (TXPREPN_STRUCT *)&TxPrePNClockV135Or}, {GET_SIZE_OF (TxPrePNClockV125Or), (TXPREPN_STRUCT *)&TxPrePNClockV125Or} }; // // Tables to describe the relationship between drive strength bit fields, PreDriver Calibration bit fields and also // the extra value that needs to be written to specific PreDriver bit fields // CONST PHY_COMP_INIT_NB PhyCompInitBitFieldOr[] = { // 3. Program TxPreP/TxPreN for Data and DQS according toTable 46 if VDDIO is 1.5V or Table 47 if 1.35V. // A. Program D18F2x9C_x0D0F_0[F,8:0]0[A,6]_dct[1:0]={0000b, TxPreP, TxPreN}. // B. Program D18F2x9C_x0D0F_0[F,8:0]0[A,6]_dct[1:0]={0000b, TxPreP, TxPreN}. {BFDqsDrvStren, BFDataByteTxPreDriverCal2Pad1, BFDataByteTxPreDriverCal2Pad1, 0, TxPrePNDataDqsOr}, {BFDataDrvStren, BFDataByteTxPreDriverCal2Pad2, BFDataByteTxPreDriverCal2Pad2, 0, TxPrePNDataDqsOr}, {BFDataDrvStren, BFDataByteTxPreDriverCal, BFDataByteTxPreDriverCal, 8, TxPrePNDataDqsOr}, // 4. Program TxPreP/TxPreN for Cmd/Addr according to Table 49 if VDDIO is 1.5V or Table 50 if 1.35V. // A. Program D18F2x9C_x0D0F_[C,8][1:0][12,0E,0A,06]_dct[1:0]={0000b, TxPreP, TxPreN}. // B. Program D18F2x9C_x0D0F_[C,8][1:0]02_dct[1:0]={1000b, TxPreP, TxPreN}. {BFCsOdtDrvStren, BFCmdAddr0TxPreDriverCal2Pad1, BFCmdAddr0TxPreDriverCal2Pad2, 0, TxPrePNCmdAddrOr}, {BFAddrCmdDrvStren, BFCmdAddr1TxPreDriverCal2Pad1, BFAddrTxPreDriverCal2Pad4, 0, TxPrePNCmdAddrOr}, {BFCsOdtDrvStren, BFCmdAddr0TxPreDriverCalPad0, BFCmdAddr0TxPreDriverCalPad0, 8, TxPrePNCmdAddrOr}, {BFCkeDrvStren, BFAddrTxPreDriverCalPad0, BFAddrTxPreDriverCalPad0, 8, TxPrePNCmdAddrOr}, {BFAddrCmdDrvStren, BFCmdAddr1TxPreDriverCalPad0, BFCmdAddr1TxPreDriverCalPad0, 8, TxPrePNCmdAddrOr}, // 5. Program TxPreP/TxPreN for Clock according to Table 52 if VDDIO is 1.5V or Table 53 if 1.35V. // A. Program D18F2x9C_x0D0F_2[2:0]02_dct[1:0]={1000b, TxPreP, TxPreN}. {BFClkDrvStren, BFClock0TxPreDriverCalPad0, BFClock2TxPreDriverCalPad0, 8, TxPrePNClockOr} }; BIT_FIELD_NAME CurrentBitField; UINT16 SpeedMask; UINT8 SizeOfTable; UINT8 Voltage; UINT8 i; UINT8 j; UINT8 k; UINT8 Dct; CONST TXPREPN_STRUCT *TblPtr; Dct = NBPtr->Dct; NBPtr->SwitchDCT (NBPtr, 0); // 1. Program D18F2x[1,0]9C_x0D0F_E003[DisAutoComp, DisablePreDriverCal] = {1b, 1b}. MemNSetBitFieldNb (NBPtr, BFDisablePredriverCal, 0x6000); NBPtr->SwitchDCT (NBPtr, Dct); SpeedMask = (UINT16) 1 << (NBPtr->DCTPtr->Timings.Speed / 66); Voltage = (UINT8) CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage); for (j = 0; j < GET_SIZE_OF (PhyCompInitBitFieldOr); j ++) { i = (UINT8) MemNGetBitFieldNb (NBPtr, PhyCompInitBitFieldOr[j].IndexBitField); TblPtr = (PhyCompInitBitFieldOr[j].TxPrePN[Voltage]).TxPrePNTblPtr; SizeOfTable = (PhyCompInitBitFieldOr[j].TxPrePN[Voltage]).TxPrePNTblSize; // Uses different TxPrePNDataDqsOr table for OR B1 and later if (((NBPtr->MCTPtr->LogicalCpuid.Revision & AMD_F15_OR_LT_B1) == 0) && (PhyCompInitBitFieldOr[j].TxPrePN == TxPrePNDataDqsOr)) { ASSERT (Voltage < sizeof (TxPrePNDataDqsOrB1) / sizeof (TxPrePNDataDqsOrB1[0])); TblPtr = TxPrePNDataDqsOrB1[Voltage].TxPrePNTblPtr; SizeOfTable = TxPrePNDataDqsOrB1[Voltage].TxPrePNTblSize; } for (k = 0; k < SizeOfTable; k++, TblPtr++) { if ((TblPtr->Speed & SpeedMask) != 0) { for (CurrentBitField = PhyCompInitBitFieldOr[j].StartTargetBitField; CurrentBitField <= PhyCompInitBitFieldOr[j].EndTargetBitField; CurrentBitField ++) { MemNSetBitFieldNb (NBPtr, CurrentBitField, ((PhyCompInitBitFieldOr[j].ExtraValue << 12) | TblPtr->TxPrePNVal[i])); } break; } } // Asserting if no table is found corresponding to current memory speed. ASSERT (k < SizeOfTable); } }
/** * * Poll a bitfield. If the bitfield does not get set to the target value within * specified microseconds, it times out. * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in] FieldName - Bit Field name * @param[in] Field - Value to be set * @param[in] MicroSecond - Number of microsecond to wait * @param[in] IfBroadCast - Need to broadcast to both DCT or not * * ---------------------------------------------------------------------------- */ VOID MemNPollBitFieldNb ( IN OUT MEM_NB_BLOCK *NBPtr, IN BIT_FIELD_NAME FieldName, IN UINT32 Field, IN UINT32 MicroSecond, IN BOOLEAN IfBroadCast ) { UINT8 ExcludeDCT; UINT16 ExcludeChipSelMask; UINT32 EventInfo; UINT64 InitTSC; UINT64 CurrentTSC; UINT64 TimeOut; AGESA_STATUS EventClass; MEM_DATA_STRUCT *MemPtr; DIE_STRUCT *MCTPtr; BOOLEAN TimeoutEn; MemPtr = NBPtr->MemPtr; MCTPtr = NBPtr->MCTPtr; ExcludeDCT = EXCLUDE_ALL_DCT; ExcludeChipSelMask = EXCLUDE_ALL_CHIPSEL; TimeoutEn = TRUE; IDS_TIMEOUT_CTL (&TimeoutEn); CurrentTSC = 0; LibAmdMsrRead (TSC, &InitTSC, &MemPtr->StdHeader); TimeOut = InitTSC + ((UINT64) MicroSecond * 1600); while ((CurrentTSC < TimeOut) || !TimeoutEn) { if (IfBroadCast) { if (NBPtr->BrdcstCheck (NBPtr, FieldName, Field)) { break; } } else { if (MemNGetBitFieldNb (NBPtr, FieldName) == Field) { break; } } LibAmdMsrRead (TSC, &CurrentTSC, &MemPtr->StdHeader); } if ((CurrentTSC >= TimeOut) && TimeoutEn) { // Default event class // If different event class is needed in one entry, override it. EventClass = AGESA_ERROR; switch (FieldName) { case BFDramEnabled: EventInfo = MEM_ERROR_DRAM_ENABLED_TIME_OUT; break; case BFDctAccessDone: EventInfo = MEM_ERROR_DCT_ACCESS_DONE_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFSendCtrlWord: EventInfo = MEM_ERROR_SEND_CTRL_WORD_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFPrefDramTrainMode: EventInfo = MEM_ERROR_PREF_DRAM_TRAIN_MODE_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFEnterSelfRef: EventInfo = MEM_ERROR_ENTER_SELF_REF_TIME_OUT; break; case BFFreqChgInProg: EventInfo = MEM_ERROR_FREQ_CHG_IN_PROG_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFExitSelfRef: EventInfo = MEM_ERROR_EXIT_SELF_REF_TIME_OUT; break; case BFSendMrsCmd: EventInfo = MEM_ERROR_SEND_MRS_CMD_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFSendZQCmd: EventInfo = MEM_ERROR_SEND_ZQ_CMD_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFDctExtraAccessDone: EventInfo = MEM_ERROR_DCT_EXTRA_ACCESS_DONE_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFMemClrBusy: EventInfo = MEM_ERROR_MEM_CLR_BUSY_TIME_OUT; break; case BFMemCleared: EventInfo = MEM_ERROR_MEM_CLEARED_TIME_OUT; break; case BFFlushWr: EventInfo = MEM_ERROR_FLUSH_WR_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; default: EventClass = 0; EventInfo = 0; IDS_ERROR_TRAP; } PutEventLog (EventClass, EventInfo, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &MemPtr->StdHeader); SetMemError (EventClass, MCTPtr); MemPtr->ErrorHandling (MCTPtr, ExcludeDCT, ExcludeChipSelMask, &MemPtr->StdHeader); } }