BOOLEAN MemNWritePmuSramMsgBlockKV ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT16 i; UINT16 *ImagePtr; LOCATE_HEAP_PTR LocHeap; LocHeap.BufferHandle = AMD_MEM_PMU_SRAM_MSG_BLOCK_HANDLE; if (HeapLocateBuffer (&LocHeap, &(NBPtr->MemPtr->StdHeader)) != AGESA_SUCCESS) { return FALSE; // Could not locate heap for PMU SRAM Message BLock. } ImagePtr = (UINT16 *) LocHeap.BufferPtr; MemNSetBitFieldNb (NBPtr, BFPmuReset, 0); // Write the word to D18F2x[B,0]9C_x0005_[27FF:0800]_dct[3:0] (using the broadcast port for all phys at // D18F2xB98_dct[MaxDctMstr:0], and using the autoincrement feature). IDS_HDT_CONSOLE (MEM_FLOW, "\t\tStart writing PMU SRAM Message Block...\n"); MemNSetBitFieldNb (NBPtr, RegDctAddlOffset, PMU_FIRMWARE_SRAM_START | DCT_ACCESS_WRITE | DCT_OFFSET_AUTO_INC_EN); for (i = 0; i < sizeof (PMU_SRAM_MSG_BLOCK_KV) / sizeof (ImagePtr[0]); i++) { MemNSetBitFieldNb (NBPtr, RegDctAddlData, ImagePtr[i]); IDS_HDT_CONSOLE (MEM_SETREG, "~F2_9C_%x = %04x\n", PMU_FIRMWARE_SRAM_START + i, ImagePtr[i]); } IDS_HDT_CONSOLE (MEM_FLOW, "\t\tEnd writing PMU SRAM Message Block!\n"); MemNSetBitFieldNb (NBPtr, RegDctAddlOffset, 0); return TRUE; }
VOID MemNBeforeDQSTrainingOr ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT8 Dct; UINT32 PackageType; for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) { MemNSwitchDCTNb (NBPtr, Dct); if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { // // 2.10.6.8.2 - BIOS should program D18F2x210_dct[1:0]_nbp[3:0][MaxRdLatency] to 55h. // MemNSetBitFieldNb (NBPtr, BFMaxLatency, 0x55); } MemNSetBitFieldNb (NBPtr, BFTraceModeEn, 0); } // DisDatMsk: Reset: 0. BIOS: IF (G34r1 || C32r1) THEN 1 ELSE 0 ENDIF. PackageType = LibAmdGetPackageType (&(NBPtr->MemPtr->StdHeader)); if (PackageType != PACKAGE_TYPE_AM3r2) { MemNSetBitFieldNb (NBPtr, BFDisDatMsk, 1); } }
VOID STATIC MemNSetOtherTimingDR ( IN OUT MEM_NB_BLOCK *NBPtr ) { MemNSetBitFieldNb (NBPtr, BFTrdrd, MemNGetTrdrdNb (NBPtr)); MemNSetBitFieldNb (NBPtr, BFTwrwr, MemNGetTwrwrNb (NBPtr)); MemNSetBitFieldNb (NBPtr, BFTwrrd, MemNGetTwrrdNb (NBPtr)); MemNSetBitFieldNb (NBPtr, BFTrwtTO, MemNGetTrwtTONb (NBPtr)); MemNSetBitFieldNb (NBPtr, BFTrwtWB, MemNGetTrwtWBNb (NBPtr)); }
BOOLEAN MemNFinalizeMctDr ( IN OUT MEM_NB_BLOCK *NBPtr ) { 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); 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); }
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); }
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); }
BOOLEAN MemNResetRxFifoPtrON ( IN OUT MEM_NB_BLOCK *NBPtr, IN OUT VOID *OptParam ) { if (NBPtr->TechPtr->Direction == DQS_READ_DIR) { MemNSetBitFieldNb (NBPtr, BFRxPtrInitReq, 1); MemNPollBitFieldNb (NBPtr, BFRxPtrInitReq, 0, PCI_ACCESS_TIMEOUT, FALSE); } return TRUE; }
VOID STATIC MemNCleanupDctRegsNb ( IN OUT MEM_NB_BLOCK *NBPtr ) { BIT_FIELD_NAME BitField; for (BitField = BFCSBaseAddr0Reg; BitField <= BFCSBaseAddr7Reg; BitField++) { MemNSetBitFieldNb (NBPtr, BitField, 0); } }
VOID STATIC MemNPowerDownCtlDR ( IN OUT MEM_NB_BLOCK *NBPtr ) { MEM_PARAMETER_STRUCT *RefPtr; UINT8 PowerDownMode; RefPtr = NBPtr->RefPtr; // we can't enable powerdown mode when doing WL if (RefPtr->EnablePowerDown) { MemNSetBitFieldNb (NBPtr, BFPowerDownEn, 1); PowerDownMode = (UINT8) UserOptions.CfgPowerDownMode; IDS_OPTION_HOOK (IDS_POWERDOWN_MODE, &PowerDownMode, &(NBPtr->MemPtr->StdHeader)); if (PowerDownMode) { MemNSetBitFieldNb (NBPtr, BFPowerDownMode, 1); } } }
/** * Perform Slew Rate Platform Override * * @param[in] NBPtr - Pointer to Current NBBlock * @param[in] Buffer - Pointer to the Action Command Data (w/o Type and Len) * * @return BOOLEAN - TRUE : Action was performed * FALSE: Action was not performed * * ---------------------------------------------------------------------------- */ BOOLEAN STATIC MemPSODoActionSlewRate ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ) { BOOLEAN Result; CH_DEF_STRUCT *ChannelPtr; UINT32 Speed; UINT16 DimmConfig; Result = FALSE; ChannelPtr = NBPtr->ChannelPtr; Speed = ((UINT32) 1 << (NBPtr->DCTPtr->Timings.Speed / 66)); DimmConfig = *(UINT16 *) &(Buffer[4]); if ((Speed & ((UINT32 *) Buffer)[0]) != 0) { if (MemCheckRankType (ChannelPtr, DimmConfig)) { MemNSetBitFieldNb (NBPtr, BFD3Cmp0NCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp0NCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp0PCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp0PCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp1NCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp1NCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp1PCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp1PCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp2NCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp2NCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp2PCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp2PCal ); Result = TRUE; IDS_HDT_CONSOLE (MEM_FLOW, " Platform Override: Slew Rate:%08x\n", *(UINT32 *) &(Buffer[6])); } } return Result; }
VOID MemNAfterDQSTrainingON ( IN OUT MEM_NB_BLOCK *NBPtr ) { if (NBPtr->DCTPtr->Timings.Speed <= DDR1066_FREQUENCY) { MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 1); } MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 0); MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 2); MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 0x1000 : 0); MemNSetBitFieldNb (NBPtr, BFPrefCpuDis, 0); MemNSetBitFieldNb (NBPtr, BFDctWrLimit, 0x1C); MemNSetBitFieldNb (NBPtr, BFDramTrainPdbDis, 1); MemNSetBitFieldNb (NBPtr, BFEnCpuSerRdBehindNpIoWr, 0); }
/** * * Set bitfields of all enabled DCTs on a die to a 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 set * * ---------------------------------------------------------------------------- */ VOID MemNBrdcstSetNb ( 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)) { MemNSetBitFieldNb (NBPtr, FieldName, Field); } } MemNSwitchDCTNb (NBPtr, Dct); }
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); }
/** * * This function programs the Data Pattern that will be sent and compared * against. * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in] *PatternIndexPtr - Pointer to a generic index used to * determine which pattern to program. * * @return BOOLEAN * TRUE * */ BOOLEAN STATIC MemFRdWr2DProgramDataPatternML ( IN OUT MEM_NB_BLOCK *NBPtr, IN VOID* PatternIndexPtr ) { UINT8 SeedCount; UINT32 PrbsSeed; CONST STATIC UINT32 CmdStreamLenTbl[4] = {13, 61, 127, 251}; ASSERT (NBPtr != 0); ASSERT (PatternIndexPtr != NULL); SeedCount = *(UINT8*)PatternIndexPtr; ASSERT (SeedCount <= (NBPtr->MaxSeedCount - 1)); MemNSetBitFieldNb (NBPtr, BFCmdStreamLen, CmdStreamLenTbl[SeedCount]); PrbsSeed = 0x7EA05; switch (SeedCount) { case 0: MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x01); PrbsSeed = 0x7FFFF; break; case 1: MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x04); MemNSetBitFieldNb (NBPtr, BFXorPatOvr, 0xFF); PrbsSeed = 0x7EA05; break; case 2: MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x03); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern0, 0x55555549); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern1, 0x55555555); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern2, 0x55555555); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern3, 0x55555555); break; case 3: MemNSetBitFieldNb (NBPtr, BFDataPatGenSel, 0x03); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern0, 0xA5A5A55A); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern1, 0xA5A5A5A5); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern2, 0xA5A5A5A5); MemNSetBitFieldNb (NBPtr, BFDramUserDataPattern3, 0xA5A5A5A5); break; default: ASSERT (FALSE); } ASSERT (PrbsSeed != 0); // // Program the PRBS Seed // NBPtr->SetBitField (NBPtr, BFDataPrbsSeed, PrbsSeed); 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 ); }
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); }
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; }
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); } }
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; } } } } } }