7 * Common Northbridge DCT support
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/NB)
12 * @e \$Revision: 60556 $ @e \$Date: 2011-10-17 20:19:58 -0600 (Mon, 17 Oct 2011) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ***************************************************************************
48 *----------------------------------------------------------------------------
51 *----------------------------------------------------------------------------
66 #include "cpuFamilyTranslation.h"
67 #include "OptionMemory.h"
68 #include "PlatformMemoryConfiguration.h"
73 #define FILECODE PROC_MEM_NB_MNDCT_FILECODE
74 /*----------------------------------------------------------------------------
75 * DEFINITIONS AND MACROS
77 *----------------------------------------------------------------------------
81 /*----------------------------------------------------------------------------
82 * TYPEDEFS AND STRUCTURES
84 *----------------------------------------------------------------------------
87 /*----------------------------------------------------------------------------
88 * PROTOTYPES OF LOCAL FUNCTIONS
90 *----------------------------------------------------------------------------
95 MemNAfterStitchMemNb (
96 IN OUT MEM_NB_BLOCK *NBPtr
111 MemNQuarterMemClk2NClkNb (
112 IN OUT MEM_NB_BLOCK *NBPtr,
113 IN OUT UINT16 *SubTotalPtr
116 /*----------------------------------------------------------------------------
119 *----------------------------------------------------------------------------
122 extern BUILD_OPT_CFG UserOptions;
124 /* -----------------------------------------------------------------------------*/
128 * This function combines all the memory into a contiguous map.
129 * Requires that Mask values for each bank be programmed first and that
130 * the chip-select population indicator is correctly set.
133 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
135 * @return TRUE - An Error value lower than AGESA_FATAL may have occurred
136 * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
141 IN OUT MEM_NB_BLOCK *NBPtr
152 MEM_PARAMETER_STRUCT *RefPtr;
155 RefPtr = NBPtr->RefPtr;
156 MCTPtr = NBPtr->MCTPtr;
157 DCTPtr = NBPtr->DCTPtr;
159 if (NBPtr->IsSupported[SetSpareEn]) {
161 if (RefPtr->GStatus[GsbEnDIMMSpareNW]) {
166 DCTPtr->Timings.CsEnabled = 0;
168 for (p = 0; p < MAX_CS_PER_CHANNEL; p++) {
171 for (q = 0; q < MAX_CS_PER_CHANNEL; q++) {
172 if (((DCTPtr->Timings.CsPresent & ~DCTPtr->Timings.CsTestFail) & ((UINT16)1 << q)) != 0) {
173 if ((MemNGetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + q) & 7) == 0) {
174 // (CSEnable|Spare==1)bank is not enabled yet
175 CsSize = MemNGetBitFieldNb (NBPtr, BFCSMask0Reg + (q >> 1));
177 CsSize += ((UINT32)1 << 19);
178 CsSize &= 0xFFF80000;
180 if (CsSize > BiggestBank) {
181 BiggestBank = CsSize;
188 if (BiggestBank != 0) {
189 CurCSBase = NxtCSBase;
190 if (NBPtr->IsSupported[CheckSpareEn]) {
192 CurCSBase = ((UINT32)1 << BFSpare);
195 CurCSBase |= ((UINT32)1 << BFCSEnable);
196 NxtCSBase += BiggestBank;
199 CurCSBase |= ((UINT32)1 << BFCSEnable);
200 NxtCSBase += BiggestBank;
202 if ((BiggestDimm & 1) != 0) {
203 if (!(MCTPtr->Status[SbLrdimms])) {
204 // For LRDIMMS, On Dimm Mirroring is enabled after SDI
205 if ((DCTPtr->Timings.DimmMirrorPresent & (1 << (BiggestDimm >> 1))) != 0) {
206 CurCSBase |= ((UINT32)1 << BFOnDimmMirror);
210 MemNSetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + BiggestDimm, CurCSBase);
211 DCTPtr->Timings.CsEnabled |= (1 << BiggestDimm);
213 if ((DCTPtr->Timings.CsTestFail & ((UINT16)1 << p)) != 0) {
214 IDS_HDT_CONSOLE (MEM_FLOW, "Node %d Dct %d exclude CS %d\n", NBPtr->Node, NBPtr->Dct, p);
215 MemNSetBitFieldNb (NBPtr, (BFCSBaseAddr0Reg + p), (UINT32)1 << BFTestFail);
219 if (NxtCSBase != 0) {
220 DCTPtr->Timings.DctMemSize = NxtCSBase >> 8; // Scale base address from [39:8] to [47:16]
221 MemNAfterStitchMemNb (NBPtr);
224 return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
227 /* -----------------------------------------------------------------------------*/
231 * This function gets platform specific config/timing values from the interface layer and
232 * programs them into DCT.
235 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
237 * @return TRUE - An Error value lower than AGESA_FATAL may have occurred
238 * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
243 IN OUT MEM_NB_BLOCK *NBPtr
246 CONST BIT_FIELD_NAME ChipletPDRegs[] = {
252 CONST UINT8 ChipletPDClkDisMap[][2] = {
253 //F2[1, 0]x9C_x0D0F2030 -> F2x[1, 0]88[MemClkDis[1:0]]
255 //F2[1, 0]x9C_x0D0F2330 -> F2x[1, 0]88[MemClkDis[7:6]]
257 //F2x09C_x0D0F2130 -> F2x88[MemClkDis[5:4]]
259 //F2x09C_x0D0F2230 -> F2x88[MemClkDis[3:2]]
261 //F2x19C_x0D0F2130 -> F2x188[MemClkDis[5:2]]
263 //F2x19C_x0D0F2230 -> F2x188[MemClkDis[4:3]]
269 UINT8 MemoryAllClocks;
276 if (!MemNGetPlatformCfgNb (NBPtr)) {
280 if (!NBPtr->PsPtr->MemPDoPs (NBPtr)) {
283 MemNProgramPlatformSpecNb (NBPtr);
285 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODT, ALL_DIMMS);
287 if (NBPtr->MCTPtr->GangedMode) {
288 MemNSwitchDCTNb (NBPtr, 1);
289 if (!MemNGetPlatformCfgNb (NBPtr)) {
292 MemNProgramPlatformSpecNb (NBPtr);
293 MemNSwitchDCTNb (NBPtr, 0);
296 //======================================================================
297 // Disable unused MemClk to save power
298 //======================================================================
301 MemoryAllClocks = UserOptions.CfgMemoryAllClocksOn;
302 IDS_OPTION_HOOK (IDS_ALL_MEMORY_CLOCK, &MemoryAllClocks, &(NBPtr->MemPtr->StdHeader));
303 if (!MemoryAllClocks) {
304 // Special Jedec SPD diagnostic bit - "enable all clocks"
305 if (!NBPtr->MCTPtr->Status[SbDiagClks]) {
306 MemClkDisMap = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MEMCLK_DIS, NBPtr->MCTPtr->SocketId, MemNGetSocketRelativeChannelNb (NBPtr, NBPtr->Dct, 0), 0,
307 &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
308 if (MemClkDisMap == NULL) {
309 MemClkDisMap = NBPtr->ChannelPtr->MemClkDisMap;
312 // Turn off the unused CS clocks
313 CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
315 if (NBPtr->IsSupported[CheckMemClkCSPresent]) {
316 if (NBPtr->ChannelPtr->RegDimmPresent != 0) {
317 // All DDR3 RDIMM use only one MEMCLOCK from edge finger to the register
318 // regardless of how many Ranks are on the DIMM (Single, Dual or Quad)
319 CsPresent = (CsPresent | (CsPresent >> 1)) & 0x5555;
322 for (i = 0; i < 8; i++) {
323 if ((CsPresent & MemClkDisMap[i]) == 0) {
324 MemClkDis |= (UINT8) (1 << i);
328 for (RegIndex = 0; RegIndex < GET_SIZE_OF (ChipletPDRegs); RegIndex++) {
329 if ((NBPtr->Dct == 1) && (RegIndex >= 2)) {
330 Cs1 = MemClkDisMap[ChipletPDClkDisMap[RegIndex + 2][0]];
331 Cs2 = MemClkDisMap[ChipletPDClkDisMap[RegIndex + 2][1]];
333 Cs1 = MemClkDisMap[ChipletPDClkDisMap[RegIndex][0]];
334 Cs2 = MemClkDisMap[ChipletPDClkDisMap[RegIndex][1]];
336 if ((CsPresent & (UINT16) (Cs1 | Cs2)) == 0) {
337 MemNSetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex], (MemNGetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex]) | 0x10));
342 MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
344 AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
345 NBPtr->MemNInitPhyComp (NBPtr);
347 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
349 // Program DramTerm for DDR2
350 if ((MemNGetBitFieldNb (NBPtr, BFDdr3Mode)) == 0) {
351 MemNSetBitFieldNb (NBPtr, BFDramTerm, NBPtr->PsPtr->DramTerm);
353 // Dynamic Dynamic DramTerm for DDR3
354 // Dram Term for DDR3 may vary based on chip selects
355 MemNSetBitFieldNb (NBPtr, BFDramTermDyn, NBPtr->PsPtr->DynamicDramTerm);
358 MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
360 return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
363 /* -----------------------------------------------------------------------------*/
367 * This function gets platform specific config/timing values from the interface layer and
368 * programs them into DCT.
371 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
373 * @return TRUE - An Error value lower than AGESA_FATAL may have occurred
374 * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
378 MemNPlatformSpecUnb (
379 IN OUT MEM_NB_BLOCK *NBPtr
384 UINT8 MemoryAllClocks;
388 if (!MemNGetPlatformCfgNb (NBPtr)) {
392 if (!NBPtr->PsPtr->MemPDoPs (NBPtr)) {
393 IDS_HDT_CONSOLE (MEM_FLOW, "\tDisable DCT%d due to unsupported DIMM configuration\n", NBPtr->Dct);
394 if (!NBPtr->MemPtr->ErrorHandling (NBPtr->MCTPtr, NBPtr->Dct, EXCLUDE_ALL_CHIPSEL, &NBPtr->MemPtr->StdHeader)) {
397 NBPtr->DisableDCT (NBPtr);
400 MemNProgramPlatformSpecNb (NBPtr);
401 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODT, ALL_DIMMS);
403 //======================================================================
404 // Disable unused MemClk to save power
405 //======================================================================
408 MemoryAllClocks = UserOptions.CfgMemoryAllClocksOn;
409 IDS_OPTION_HOOK (IDS_ALL_MEMORY_CLOCK, &MemoryAllClocks, &(NBPtr->MemPtr->StdHeader));
410 if (!MemoryAllClocks) {
411 // Special Jedec SPD diagnostic bit - "enable all clocks"
412 if (!NBPtr->MCTPtr->Status[SbDiagClks]) {
413 MemClkDisMap = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MEMCLK_DIS, NBPtr->MCTPtr->SocketId, NBPtr->Dct, 0,
414 &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
415 if (MemClkDisMap == NULL) {
416 MemClkDisMap = NBPtr->ChannelPtr->MemClkDisMap;
419 // Turn off unused clocks
420 CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
422 for (i = 0; i < 8; i++) {
423 if ((CsPresent & MemClkDisMap[i]) == 0) {
424 MemClkDis |= (UINT8) (1 << i);
428 // Turn off unused chiplets
429 for (i = 0; i < 3; i++) {
430 if (((MemClkDis >> (i * 2)) & 0x3) == 0x3) {
431 MemNSetBitFieldNb (NBPtr, BFPhyClkConfig0 + i, 0x0010);
436 MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
437 MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
440 return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
443 /* -----------------------------------------------------------------------------*/
447 * This function disables the DCT and mem clock
450 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
456 IN OUT MEM_NB_BLOCK *NBPtr
459 MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
460 MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
461 MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
463 // To maximize power savings when DisDramInterface=1b,
464 // all of the MemClkDis bits should also be set.
466 MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
467 MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
470 /* -----------------------------------------------------------------------------*/
474 * This function disables the DCT and mem clock for client NB
477 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
482 MemNDisableDCTClientNb (
483 IN OUT MEM_NB_BLOCK *NBPtr
486 MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
487 MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
488 MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
490 //Wait for 24 MEMCLKs
491 MemNWaitXMemClksNb (NBPtr, 24);
493 // To maximize power savings when DisDramInterface=1b,
494 // all of the MemClkDis bits should also be set.
496 MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
498 MemNSetBitFieldNb (NBPtr, BFDramPhyStatusReg, 0x80800000);
500 MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
503 /* -----------------------------------------------------------------------------*/
507 * This function disables the DCT and mem clock for UNB
510 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
516 IN OUT MEM_NB_BLOCK *NBPtr
519 MemNSetBitFieldNb (NBPtr, BFExtendedParityEn, 0);
520 MemNSetBitFieldNb (NBPtr, BFParEn, 0);
521 MemNSetBitFieldNb (NBPtr, BFCKETri, 0x0F);
523 //Wait for 24 MEMCLKs
524 MemNWaitXMemClksNb (NBPtr, 24);
526 // To maximize power savings when DisDramInterface=1b,
527 // all of the MemClkDis bits should also be set.
529 MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
531 MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
533 if (NBPtr->Dct == 0) {
534 MemNSetBitFieldNb (NBPtr, BFPhyPSMasterChannel, 0x100);
538 /* -----------------------------------------------------------------------------*/
542 * This function initializes the DRAM devices on all DCTs at the same time
544 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
550 IN OUT MEM_NB_BLOCK *NBPtr
553 // 1. Ensure F2x[1, 0]9C_x08[DisAutoComp] = 1.
554 // 2. BIOS waits 5 us for the disabling of the compensation engine to complete.
555 // DisAutoComp is still being set since InitPhyComp
557 if (NBPtr->MCTPtr->NodeMemSize != 0) {
558 // Init MemClk frequency
559 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
562 AGESA_TESTPOINT (TpProcMemBeforeDramInit, &(NBPtr->MemPtr->StdHeader));
563 NBPtr->MemNBeforeDramInitNb (NBPtr);
564 IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq: %d MHz\n", NBPtr->DCTPtr->Timings.Speed);
565 AGESA_TESTPOINT (TpProcMemDramInit, &(NBPtr->MemPtr->StdHeader));
566 NBPtr->FeatPtr->DramInit (NBPtr->TechPtr);
569 // 7. Program F2x[1, 0]9C_x08[DisAutoComp] = 0.
570 // 8. BIOS must wait 750 us for the phy compensation engine
572 // DisAutoComp will be cleared after DramEnabled turns to 1
576 /* -----------------------------------------------------------------------------*/
580 * This function initializes the DRAM devices on all DCTs at the same time
582 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
588 IN OUT MEM_NB_BLOCK *NBPtr
592 UINT16 FinalPllLockTime;
594 if (NBPtr->MCTPtr->NodeMemSize != 0) {
595 // Update NB frequency for startup DDR speed
596 NBPtr->ChangeNbFrequency (NBPtr);
598 if (NBPtr->FamilySpecificHook[ForcePhyToM0] (NBPtr, NULL)) {
599 // Program D18F2x[1,0]9C_x0000_000B = 80000000h. #109999.
600 MemNBrdcstSetNb (NBPtr, BFDramPhyStatusReg, 0x80000000);
602 // Program D18F2x[1,0]9C_x0D0F_E013[PllRegWaitTime] = 0118h. #194060.
603 MemNBrdcstSetNb (NBPtr, BFPllRegWaitTime, 0x118);
606 // Phy Voltage Level Programming
607 MemNPhyVoltageLevelNb (NBPtr);
609 // Run frequency change sequence
610 MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
611 MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
612 NBPtr->FamilySpecificHook[SetSkewMemClk] (NBPtr, NULL);
613 NBPtr->ProgramNbPsDependentRegs (NBPtr);
614 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
615 MemNSwitchDCTNb (NBPtr, Dct);
616 if ((NBPtr->DCTPtr->Timings.DctMemSize != 0)) {
617 MemNSetBitFieldNb (NBPtr, BFMemClkFreqVal, 1);
618 MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, FALSE);
621 FinalPllLockTime = 0xF;
622 NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &FinalPllLockTime);
623 if (!NBPtr->IsSupported[CsrPhyPllPdEn]) {
624 // IF (D18F2x[1,0]9C_x0D0F_E00A[CsrPhySrPllPdMode]==0) THEN program
625 // D18F2x[1,0]9C_x0D0F_E006[PllLockTime] = 0Fh
626 MemNBrdcstSetNb (NBPtr, BFPllLockTime, FinalPllLockTime);
629 NBPtr->FamilySpecificHook[BeforePhyFenceTraining] (NBPtr, NBPtr);
631 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
632 MemNSwitchDCTNb (NBPtr, Dct);
633 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
634 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
636 // Phy fence programming
637 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
638 NBPtr->PhyFenceTraining (NBPtr);
640 // Phy compensation initialization
641 AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
642 NBPtr->MemNInitPhyComp (NBPtr);
643 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
647 AGESA_TESTPOINT (TpProcMemBeforeDramInit, &(NBPtr->MemPtr->StdHeader));
648 NBPtr->MemNBeforeDramInitNb (NBPtr);
650 AGESA_TESTPOINT (TpProcMemDramInit, &(NBPtr->MemPtr->StdHeader));
651 IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq: %d MHz\n", NBPtr->DCTPtr->Timings.Speed);
652 NBPtr->FeatPtr->DramInit (NBPtr->TechPtr);
656 /* -----------------------------------------------------------------------------*/
659 * MemNChangeFrequencyHy:
661 * This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
663 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
668 MemNChangeFrequencyNb (
669 IN OUT MEM_NB_BLOCK *NBPtr
672 MEM_TECH_BLOCK *TechPtr;
676 TechPtr = NBPtr->TechPtr;
677 if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
679 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
682 //Program F2x[1,0]90[EnterSelfRefresh]=1.
683 //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
684 MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
685 MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
687 //Program F2x9C_x08[DisAutoComp]=1
688 MemNSwitchDCTNb (NBPtr, 0);
689 MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 1);
691 //Program F2x[1, 0]94[MemClkFreqVal] = 0.
692 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
694 //Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency.
695 MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
697 IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
698 //Program F2x[1, 0]94[MemClkFreqVal] = 1.
699 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
701 //Wait until F2x[1, 0]94[FreqChgInProg]=0.
702 MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
704 if (NBPtr->IsSupported[CheckPhyFenceTraining]) {
705 //Perform Phy Fence retraining after frequency changed
706 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
707 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
708 MemNSwitchDCTNb (NBPtr, Dct);
709 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
710 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
711 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
712 MemNPhyFenceTrainingNb (NBPtr);
717 //Program F2x9C_x08[DisAutoComp]=0
718 MemNSwitchDCTNb (NBPtr, 0);
719 MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
721 //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
722 //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
723 MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
724 MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
726 if (NBPtr->MCTPtr->Status[SbRegistered]) {
727 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
728 MemNSwitchDCTNb (NBPtr, Dct);
729 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
730 TechPtr->FreqChgCtrlWrd (TechPtr);
735 //wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns
736 MemNWaitXMemClksNb (NBPtr, 500);
738 if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
740 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
743 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
744 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
745 MemNSwitchDCTNb (NBPtr, Dct);
746 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
748 //9.Configure the DCT to send initialization MR commands:
749 // BIOS must reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
750 // Program F2x[1, 0]7C similar to step #2 in Pass 1 above for the new Dimm values.
751 TechPtr->AutoCycTiming (TechPtr);
752 if (!MemNPlatformSpecNb (NBPtr)) {
756 for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
757 if (NBPtr->IsSupported[CheckGetMCTSysAddr]) {
758 if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
759 // if chip select present
760 TechPtr->SendAllMRCmds (TechPtr, ChipSel);
761 // NOTE: wait 512 clocks for DLL-relock
762 MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
765 if (NBPtr->IsSupported[CheckSendAllMRCmds]) {
766 if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
768 // if chip select present
769 TechPtr->SendAllMRCmds (TechPtr, ChipSel);
773 if ((NBPtr->DCTPtr->Timings.Speed == DDR1600_FREQUENCY) && (NBPtr->IsSupported[CheckDllSpeedUp])) {
774 MemNSetBitFieldNb (NBPtr, BFPhy0x0D080F11, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D080F11) | 0x2000));
775 MemNSetBitFieldNb (NBPtr, BFPhy0x0D080F10, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D080F10) | 0x2000));
776 MemNSetBitFieldNb (NBPtr, BFPhy0x0D088F30, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D088F30) | 0x2000));
777 MemNSetBitFieldNb (NBPtr, BFPhy0x0D08C030, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D08C030) | 0x2000));
779 MemNSetBitFieldNb (NBPtr, BFPhy0x0D082F30, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D082F30) | 0x2000));
781 // NOTE: wait 512 clocks for DLL-relock
782 MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
786 // Re-enable phy compensation since it had been disabled during InitPhyComp
787 MemNSwitchDCTNb (NBPtr, 0);
788 MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
790 MemFInitTableDrive (NBPtr, MTAfterFreqChg);
794 /* -----------------------------------------------------------------------------*/
797 * This function ramp up frequency the next level if it have not reached
798 * its TargetSpeed yet.
800 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
802 * @return TRUE - No fatal error occurs.
803 * @return FALSE - Fatal error occurs.
807 MemNRampUpFrequencyNb (
808 IN OUT MEM_NB_BLOCK *NBPtr
811 CONST UINT16 FreqList[] = {
826 MCTPtr = NBPtr->MCTPtr;
828 // Do not change frequency when it is already at TargetSpeed
829 if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
833 // Find the next supported frequency level
834 NewSpeed = NBPtr->DCTPtr->Timings.TargetSpeed;
835 for (i = 0; i < (GET_SIZE_OF (FreqList) - 1); i++) {
836 if (NBPtr->DCTPtr->Timings.Speed == FreqList[i]) {
837 NewSpeed = FreqList[i + 1];
841 ASSERT (i < (GET_SIZE_OF (FreqList) - 1));
842 ASSERT (NewSpeed <= NBPtr->DCTPtr->Timings.TargetSpeed);
844 // BIOS must program both DCTs to the same frequency.
845 IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq changed: %d MHz", NBPtr->DCTPtr->Timings.Speed);
846 for (Dct = 0; Dct < MCTPtr->DctCount; Dct++) {
847 NBPtr->SwitchDCT (NBPtr, Dct);
848 NBPtr->DCTPtr->Timings.Speed = NewSpeed;
850 IDS_HDT_CONSOLE (MEM_FLOW, " -> %d MHz", NewSpeed);
852 NBPtr->ChangeFrequency (NBPtr);
854 return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
857 /* -----------------------------------------------------------------------------*/
860 * This function ramp up frequency to target frequency
862 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
864 * @return TRUE - No fatal error occurs.
865 * @return FALSE - Fatal error occurs.
869 MemNRampUpFrequencyUnb (
870 IN OUT MEM_NB_BLOCK *NBPtr
876 MCTPtr = NBPtr->MCTPtr;
878 // Do not change frequency when it is already at TargetSpeed
879 if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
883 // BIOS must program both DCTs to the same frequency.
884 IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq changed: %d MHz", NBPtr->DCTPtr->Timings.Speed);
885 for (Dct = 0; Dct < MCTPtr->DctCount; Dct++) {
886 NBPtr->SwitchDCT (NBPtr, Dct);
887 NBPtr->DCTPtr->Timings.Speed = NBPtr->DCTPtr->Timings.TargetSpeed;
889 IDS_HDT_CONSOLE (MEM_FLOW, " -> %d MHz", NBPtr->DCTPtr->Timings.TargetSpeed);
891 NBPtr->ChangeFrequency (NBPtr);
893 return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
896 /* -----------------------------------------------------------------------------*/
900 * This function uses calculated values from DCT.Timings structure to
901 * program its registers.
904 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
909 MemNProgramCycTimingsNb (
910 IN OUT MEM_NB_BLOCK *NBPtr
913 CONST CTENTRY TmgAdjTab[] = {
914 // BitField, Min, Max, Bias, Ratio_x2
915 {BFTcl, 4, 12, 4, 2},
916 {BFTrcd, 5, 12, 5, 2},
917 {BFTrp, 5, 12, 5, 2},
918 {BFTrtp, 4, 7, 4, 2},
919 {BFTras, 15, 30, 15, 2},
920 {BFTrc, 11, 42, 11, 2},
921 {BFTwrDDR3, 5, 12, 4, 2},
922 {BFTrrd, 4, 7, 4, 2},
923 {BFTwtr, 4, 7, 4, 2},
924 {BFFourActWindow, 16, 32, 14, 1}
932 BIT_FIELD_NAME BitField;
934 DCTPtr = NBPtr->DCTPtr;
936 //======================================================================
937 // Program turnaround timings to their max during DRAM init and training
938 //======================================================================
940 MemNSetBitFieldNb (NBPtr, BFNonSPD, 0x28FF);
942 MemNSetBitFieldNb (NBPtr, BFNonSPDHi, 0x2A);
944 //======================================================================
945 // Program DRAM Timing values
946 //======================================================================
948 MiniMaxTmg = &DCTPtr->Timings.CasL;
949 for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
950 BitField = TmgAdjTab[j].BitField;
952 if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
953 MiniMaxTmg[j] = TmgAdjTab[j].Min;
954 } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
955 MiniMaxTmg[j] = TmgAdjTab[j].Max;
958 Value8 = (UINT8) MiniMaxTmg[j];
960 if (BitField == BFTwrDDR3) {
961 Value8 = (Value8 == 10) ? 9 : (Value8 >= 11) ? 10 : Value8;
962 } else if (BitField == BFTrtp) {
963 Value8 = (DCTPtr->Timings.Speed <= DDR1066_FREQUENCY) ? 4 : (DCTPtr->Timings.Speed == DDR1333_FREQUENCY) ? 5 : 6;
966 Value8 = Value8 - TmgAdjTab[j].Bias;
967 Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
969 ASSERT ((BitField == BFTcl ) ? (Value8 <= 8) :
970 (BitField == BFTrcd) ? (Value8 <= 7) :
971 (BitField == BFTrp ) ? (Value8 <= 7) :
972 (BitField == BFTrtp) ? (Value8 <= 3) :
973 (BitField == BFTras) ? (Value8 <= 15) :
974 (BitField == BFTrc ) ? (Value8 <= 31) :
975 (BitField == BFTrrd) ? (Value8 <= 3) :
976 (BitField == BFTwtr) ? (Value8 <= 3) :
977 (BitField == BFTwrDDR3) ? ((Value8 >= 1) && (Value8 <= 6)) :
978 (BitField == BFFourActWindow) ? ((Value8 >= 1) && (Value8 <= 9)) : FALSE);
979 MemNSetBitFieldNb (NBPtr, BitField, Value8);
982 MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
983 for (j = 0; j < 4; j++) {
984 ASSERT (MiniMaxTrfc[j] <= 4);
985 MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
988 MemNSetBitFieldNb (NBPtr, BFTcwl, ((DCTPtr->Timings.Speed >= DDR800_FREQUENCY) ?
989 (NBPtr->GetMemClkFreqId (NBPtr, DCTPtr->Timings.Speed) - 3) : 0));
991 MemNSetBitFieldNb (NBPtr, BFTref, 2); // 7.8 us
993 //======================================================================
994 // DRAM MRS Register, set ODT
995 //======================================================================
997 // DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
998 MemNSetBitFieldNb (NBPtr, BFDrvImpCtrl, 1);
1000 // burst length control
1001 if (NBPtr->MCTPtr->Status[Sb128bitmode]) {
1002 MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 2);
1005 // ASR=1, auto self refresh; SRT=0
1006 MemNSetBitFieldNb (NBPtr, BFASR, 1);
1009 /* -----------------------------------------------------------------------------*/
1013 * This function uses calculated values from DCT.Timings structure to
1014 * program its registers.
1017 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1022 MemNProgramCycTimingsClientNb (
1023 IN OUT MEM_NB_BLOCK *NBPtr
1026 CONST CTENTRY TmgAdjTab[] = {
1027 // BitField, Min, Max, Bias, Ratio_x2
1028 {BFTcl, 5, 14, 4, 2},
1029 {BFTrcd, 5, 14, 5, 2},
1030 {BFTrp, 5, 14, 5, 2},
1031 {BFTrtp, 4, 8, 4, 2},
1032 {BFTras, 15, 36, 15, 2},
1033 {BFTrc, 20, 49, 11, 2},
1034 {BFTwrDDR3, 5, 16, 4, 2},
1035 {BFTrrd, 4, 8, 4, 2},
1036 {BFTwtr, 4, 8, 4, 2},
1037 {BFFourActWindow, 16, 40, 14, 1}
1048 BIT_FIELD_NAME BitField;
1050 DCTPtr = NBPtr->DCTPtr;
1052 //======================================================================
1053 // Program DRAM Timing values
1054 //======================================================================
1056 MiniMaxTmg = &DCTPtr->Timings.CasL;
1057 for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
1058 BitField = TmgAdjTab[j].BitField;
1060 if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
1061 MiniMaxTmg[j] = TmgAdjTab[j].Min;
1062 } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
1063 MiniMaxTmg[j] = TmgAdjTab[j].Max;
1066 Value8 = (UINT8) MiniMaxTmg[j];
1068 if (BitField == BFTwrDDR3) {
1069 if (NBPtr->IsSupported[AdjustTwr]) {
1072 Value8 = (Value8 >= 10) ? (((Value8 + 1) / 2) + 4) : Value8;
1075 if ((BitField == BFTrc) && NBPtr->IsSupported[AdjustTrc]) {
1079 Value8 = Value8 - TmgAdjTab[j].Bias;
1080 Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
1082 ASSERT ((BitField == BFTcl ) ? ((Value8 >= 1) && (Value8 <= 10)) :
1083 (BitField == BFTrcd) ? (Value8 <= 9) :
1084 (BitField == BFTrp ) ? (Value8 <= 9) :
1085 (BitField == BFTrtp) ? (Value8 <= 4) :
1086 (BitField == BFTras) ? (Value8 <= 21) :
1087 (BitField == BFTrc ) ? (NBPtr->IsSupported[AdjustTrc] ? ((Value8 >= 4) && (Value8 <= 38)) : ((Value8 >= 9) && (Value8 <= 38))) :
1088 (BitField == BFTrrd) ? (Value8 <= 4) :
1089 (BitField == BFTwtr) ? (Value8 <= 4) :
1090 (BitField == BFTwrDDR3) ? (Value8 <= 7) :
1091 (BitField == BFFourActWindow) ? ((Value8 >= 1) && (Value8 <= 13)) : FALSE);
1092 MemNSetBitFieldNb (NBPtr, BitField, Value8);
1095 MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
1096 for (j = 0; j < 4; j++) {
1097 ASSERT (MiniMaxTrfc[j] <= 5);
1098 MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
1101 Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
1102 MemNSetBitFieldNb (NBPtr, BFTcwl, ((Tcwl > 5) ? (Tcwl - 5) : 0));
1104 MemNSetBitFieldNb (NBPtr, BFTref, 2); // Tref = 7.8 us
1106 // Skid buffer can only be programmed once before Dram init
1107 if (NBPtr->DCTPtr->Timings.Speed == DDR800_FREQUENCY) {
1108 TCK_ps = 1000500 / DCTPtr->Timings.TargetSpeed;
1109 Trcd = (UINT8) ((((1000 / 40) * (UINT32)DCTPtr->Timings.DIMMTrcd) + TCK_ps - 1) / TCK_ps);
1110 MemNSetBitFieldNb (NBPtr, BFDbeSkidBufDis, (Trcd > 10) ? 0 : 1);
1113 MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0);
1117 /* -----------------------------------------------------------------------------*/
1121 * This function uses calculated values from DCT.Timings structure to
1122 * program its registers for UNB
1125 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1130 MemNProgramCycTimingsUnb (
1131 IN OUT MEM_NB_BLOCK *NBPtr
1134 CONST CTENTRY TmgAdjTab[] = {
1135 // BitField, Min, Max, Bias, Ratio_x2
1136 {BFTcl, 5, 14, 0, 2},
1137 {BFTrcd, 2, 19, 0, 2},
1138 {BFTrp, 2, 19, 0, 2},
1139 {BFTrtp, 4, 10, 0, 2},
1140 {BFTras, 8, 40, 0, 2},
1141 {BFTrc, 10, 56, 0, 2},
1142 {BFTwrDDR3, 5, 16, 0, 2},
1143 {BFTrrd, 4, 9, 0, 2},
1144 {BFTwtr, 4, 9, 0, 2},
1145 {BFFourActWindow, 6, 42, 0, 2}
1154 UINT8 RdOdtTrnOnDly;
1155 BIT_FIELD_NAME BitField;
1157 DCTPtr = NBPtr->DCTPtr;
1159 //======================================================================
1160 // Program DRAM Timing values
1161 //======================================================================
1163 MiniMaxTmg = &DCTPtr->Timings.CasL;
1164 for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
1165 BitField = TmgAdjTab[j].BitField;
1167 if (BitField == BFTrp) {
1168 if (NBPtr->IsSupported[AdjustTrp]) {
1170 if (MiniMaxTmg[j] < 5) {
1176 if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
1177 MiniMaxTmg[j] = TmgAdjTab[j].Min;
1178 } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
1179 MiniMaxTmg[j] = TmgAdjTab[j].Max;
1182 Value8 = (UINT8) MiniMaxTmg[j];
1184 if (BitField == BFTwrDDR3) {
1185 if ((Value8 > 8) && ((Value8 & 1) != 0)) {
1190 MemNSetBitFieldNb (NBPtr, BitField, Value8);
1193 MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
1194 for (j = 0; j < 4; j++) {
1195 if ((NBPtr->DCTPtr->Timings.DctDimmValid & (1 << j)) != 0) {
1196 ASSERT (MiniMaxTrfc[j] <= 4);
1197 MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
1201 Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
1202 MemNSetBitFieldNb (NBPtr, BFTcwl, ((Tcwl > 5) ? Tcwl : 5));
1204 MemNSetBitFieldNb (NBPtr, BFTref, 2); // 7.8 us
1206 RdOdtTrnOnDly = (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0;
1207 MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, RdOdtTrnOnDly);
1208 NBPtr->FamilySpecificHook[ProgOdtControl] (NBPtr, NULL);
1213 MemNSetBitFieldNb (NBPtr, BFTmod, (DCTPtr->Timings.Speed < DDR1866_FREQUENCY) ? 0x0C :
1214 (DCTPtr->Timings.Speed > DDR1866_FREQUENCY) ? 0x10 : 0x0E);
1216 // Program Tzqcs and Tzqoper
1218 // Tzqcs max(64nCK, 80ns)
1219 MemNSetBitFieldNb (NBPtr, BFTzqcs, MIN (6, (MAX (64, MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 80)) + 15) / 16));
1220 // Tzqoper max(256nCK, 320ns)
1221 MemNSetBitFieldNb (NBPtr, BFTzqoper, MIN (0xC, (MAX (256, MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 320)) + 31) / 32));
1224 /* -----------------------------------------------------------------------------*/
1228 * This function gets platform specific settings for the current channel
1230 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1232 * @return TRUE - All platform types defined have initialized successfully
1233 * @return FALSE - At least one of the platform types gave not been initialized successfully
1237 MemNGetPlatformCfgNb (
1238 IN OUT MEM_NB_BLOCK *NBPtr
1243 for (p = 0; p < MAX_PLATFORM_TYPES; p++) {
1244 ASSERT (NBPtr->MemPtr->GetPlatformCfg[p] != NULL);
1245 if (NBPtr->MemPtr->GetPlatformCfg[p] (NBPtr->MemPtr, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr) == AGESA_SUCCESS) {
1249 return (p < MAX_PLATFORM_TYPES);
1252 /* -----------------------------------------------------------------------------*/
1256 * This function retrieves the Max latency parameters
1258 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1260 * @param[in] *MinDlyPtr - Pointer to variable to store the Minimum Delay value
1261 * @param[in] *MaxDlyPtr - Pointer to variable to store the Maximum Delay value
1262 * @param[in] *DlyBiasPtr - Pointer to variable to store Delay Bias value
1263 * @param[in] MaxRcvEnDly - Maximum receiver enable delay value
1267 MemNGetMaxLatParamsNb (
1268 IN OUT MEM_NB_BLOCK *NBPtr,
1269 IN UINT16 MaxRcvEnDly,
1270 IN OUT UINT16 *MinDlyPtr,
1271 IN OUT UINT16 *MaxDlyPtr,
1272 IN OUT UINT16 *DlyBiasPtr
1275 *MinDlyPtr = (MemNTotalSyncComponentsNb (NBPtr) + (MaxRcvEnDly >> 5)) * 2;
1276 MemNQuarterMemClk2NClkNb (NBPtr, MinDlyPtr);
1281 MemNQuarterMemClk2NClkNb (NBPtr, DlyBiasPtr); // 1 MEMCLK Margin
1283 *DlyBiasPtr += 1; // add 1 NCLK
1286 /* -----------------------------------------------------------------------------*/
1290 * This function sets the maximum round-trip latency in the system from the processor to the DRAM
1294 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1295 * @param[in] MaxRcvEnDly - Maximum receiver enable delay value
1300 MemNSetMaxLatencyNb (
1301 IN OUT MEM_NB_BLOCK *NBPtr,
1302 IN UINT16 MaxRcvEnDly
1307 AGESA_TESTPOINT (TpProcMemRcvrCalcLatency, &(NBPtr->MemPtr->StdHeader));
1309 SubTotal = 0xC8; // init value for MaxRdLat used in training
1312 if (MaxRcvEnDly != 0xFFFF) {
1313 // Get all sync components BKDG steps 1-5
1314 SubTotal = MemNTotalSyncComponentsNb (NBPtr);
1316 // Add the maximum (worst case) delay value of DqsRcvEnGrossDelay
1317 // that exists across all DIMMs and byte lanes.
1319 SubTotal += MaxRcvEnDly >> 5;
1322 // Add 14.5 to the sub-total. 14.5 represents part of the processor
1323 // specific constant delay value in the DRAM clock domain.
1325 SubTotal <<= 1; // scale 1/2 MemClk to 1/4 MemClk
1326 SubTotal += 29; // add 14.5 1/2 MemClk
1328 // Convert the sub-total (in 1/2 MEMCLKs) to northbridge clocks (NCLKs)
1329 // as follows (assuming DDR400 and assuming that no P-state or link speed
1330 // changes have occurred).
1332 MemNQuarterMemClk2NClkNb (NBPtr, &SubTotal);
1334 // Add 2 NCLKs to the sub-total. 2 represents part of the processor
1335 // specific constant value in the northbridge clock domain.
1340 NBPtr->DCTPtr->Timings.MaxRdLat = SubTotal;
1341 // Program the F2x[1, 0]78[MaxRdLatency] register with the total delay value
1342 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRdLat: %03x\n", SubTotal);
1343 MemNSetBitFieldNb (NBPtr, BFMaxLatency, SubTotal);
1346 /* -----------------------------------------------------------------------------*/
1350 * This function sends the ZQCL command
1352 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1358 IN OUT MEM_NB_BLOCK *NBPtr
1361 // 1.Program MrsAddress[10]=1
1362 MemNSetBitFieldNb (NBPtr, BFMrsAddress, (UINT32)1 << 10);
1364 // 2.Set SendZQCmd=1
1365 MemNSetBitFieldNb (NBPtr, BFSendZQCmd, 1);
1367 // 3.Wait for SendZQCmd=0
1368 MemNPollBitFieldNb (NBPtr, BFSendZQCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
1370 // 4.Wait 512 MEMCLKs
1371 MemNWaitXMemClksNb (NBPtr, 512);
1375 /*----------------------------------------------------------------------------
1378 *----------------------------------------------------------------------------
1381 /* -----------------------------------------------------------------------------*/
1385 * This function is used to create the DRAM map
1388 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1393 MemNAfterStitchMemNb (
1394 IN OUT MEM_NB_BLOCK *NBPtr
1397 if (NBPtr->MCTPtr->GangedMode) {
1398 NBPtr->MCTPtr->NodeMemSize = NBPtr->DCTPtr->Timings.DctMemSize;
1399 NBPtr->MCTPtr->NodeSysLimit = NBPtr->MCTPtr->NodeMemSize - 1;
1400 NBPtr->MCTPtr->DctData[1].Timings.CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
1401 NBPtr->MCTPtr->DctData[1].Timings.CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
1402 NBPtr->MCTPtr->DctData[1].Timings.DctMemSize = NBPtr->DCTPtr->Timings.DctMemSize;
1404 // In unganged mode, add DCT0 and DCT1 to NodeMemSize
1405 NBPtr->MCTPtr->NodeMemSize += NBPtr->DCTPtr->Timings.DctMemSize;
1406 NBPtr->MCTPtr->NodeSysLimit = NBPtr->MCTPtr->NodeMemSize - 1;
1411 /* -----------------------------------------------------------------------------*/
1415 * This function Return the binary value of tfaw associated with
1418 * @param[in] k value
1420 * @return F[k], in Binary MHz.
1428 CONST UINT8 Tab1KTfawTK[] = {0, 8, 10, 13, 14, 19};
1430 return Tab1KTfawTK[k];
1433 /* -----------------------------------------------------------------------------*/
1437 * This function Return the binary value of the 2KTFaw associated with
1440 * @param[in] k value
1442 * @return 2KTFaw converted based on k.
1450 CONST UINT8 Tab2KTfawTK[] = {0, 10, 14, 17, 18, 24};
1452 return Tab2KTfawTK[k];
1455 /* -----------------------------------------------------------------------------*/
1459 * This function converts the sub-total (in 1/4 MEMCLKs) to northbridge clocks (NCLKs)
1460 * (assuming DDR400 and assuming that no P-state or link speed
1461 * changes have occurred).
1464 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1465 * @param[in,out] *SubTotalPtr - pointer to Sub-Total
1470 MemNQuarterMemClk2NClkNb (
1471 IN OUT MEM_NB_BLOCK *NBPtr,
1472 IN OUT UINT16 *SubTotalPtr
1478 // Multiply SubTotal by NB COF
1479 NBFreq = (MemNGetBitFieldNb (NBPtr, BFNbFid) + 4) * 200;
1480 // Divide SubTotal by 4 times current MemClk frequency
1481 MemFreq = NBPtr->DCTPtr->Timings.Speed * 4;
1482 *SubTotalPtr = (UINT16) (((NBFreq * (*SubTotalPtr)) + MemFreq - 1) / MemFreq); // round up
1485 /* -----------------------------------------------------------------------------*/
1489 * This function gets the total of sync components for Max Read Latency calculation
1491 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1493 * @return Total in 1/2 MEMCLKs
1497 MemNTotalSyncComponentsNb (
1498 IN OUT MEM_NB_BLOCK *NBPtr
1503 // Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs UINTs.
1504 SubTotal = (UINT16) MemNGetBitFieldNb (NBPtr, BFTcl) + 1;
1505 if ((MemNGetBitFieldNb (NBPtr, BFDdr3Mode)) != 0) {
1510 // If registered DIMMs are being used then add 1 MEMCLK to the sub-total.
1511 if ((MemNGetBitFieldNb (NBPtr, BFUnBuffDimm)) == 0) {
1515 // If (F2x[1, 0]9C_x04[AddrCmdSetup] and F2x[1, 0]9C_x04[CsOdtSetup] and F2x[1, 0]9C_x04[Cke-Setup] = 0) then K = K + 1
1516 // If (F2x[1, 0]9C_x04[AddrCmdSetup] or F2x[1, 0]9C_x04[CsOdtSetup] or F2x[1, 0]9C_x04[CkeSetup] = 1) then K = K + 2
1517 if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) {
1523 // If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
1524 // then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total.
1526 SubTotal = SubTotal + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit));
1531 /* -----------------------------------------------------------------------------*/
1535 * This function swaps bits for OnDimmMirror support
1537 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1543 IN OUT MEM_NB_BLOCK *NBPtr
1549 ChipSel = (UINT8) MemNGetBitFieldNb (NBPtr, BFMrsChipSel);
1550 if ((ChipSel & 1) != 0) {
1551 MRSReg = MemNGetBitFieldNb (NBPtr, BFDramInitRegReg);
1552 if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
1553 MRSReg = (MRSReg & 0xFFFCFE07) | ((MRSReg&0x100A8) << 1) | ((MRSReg&0x20150) >> 1);
1554 MemNSetBitFieldNb (NBPtr, BFDramInitRegReg, MRSReg);
1559 /* -----------------------------------------------------------------------------*/
1563 * This function swaps bits for OnDimmMirror support for Unb
1565 * Dimm Mirroring Requires that, during MRS command cycles, the following
1566 * bits are swapped by software
1569 * A4 -> A3 BA0 -> BA1
1570 * A5 -> A6 BA1 -> BA0
1573 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1579 IN OUT MEM_NB_BLOCK *NBPtr
1586 ChipSel = (UINT8) MemNGetBitFieldNb (NBPtr, BFMrsChipSel);
1587 if ((ChipSel & 1) != 0) {
1588 if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
1589 MRSBank = MemNGetBitFieldNb (NBPtr, BFMrsBank);
1590 MRSAddr = MemNGetBitFieldNb (NBPtr, BFMrsAddress);
1592 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d MR%d %05x swapped to ->",
1595 (MRSAddr & 0x3FFFF));
1597 // Swap Mrs Bank bits 0 with 1
1598 MRSBank = (MRSBank & 0x0100) | ((MRSBank & 0x01) << 1) | ((MRSBank & 0x02) >> 1);
1600 // Swap Mrs Address bits 3 with 4, 5 with 6, and 7 with 8
1601 MRSAddr = (MRSAddr & 0x03FE07) | ((MRSAddr&0x000A8) << 1) | ((MRSAddr&0x00150) >> 1);
1602 MemNSetBitFieldNb (NBPtr, BFMrsBank, MRSBank);
1603 MemNSetBitFieldNb (NBPtr, BFMrsAddress, MRSAddr);
1608 /* -----------------------------------------------------------------------------*/
1611 * Programs Address/command timings, driver strengths, and tri-state fields.
1613 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1617 MemNProgramPlatformSpecNb (
1618 IN OUT MEM_NB_BLOCK *NBPtr
1621 CONST UINT8 PinType[3] = {PSO_CKE_TRI, PSO_ODT_TRI, PSO_CS_TRI};
1622 CONST UINT8 TabSize[3] = { 2, 4, 8};
1623 CONST BIT_FIELD_NAME BitField[3] = { BFCKETri, BFODTTri, BFChipSelTri};
1628 //===================================================================
1629 // Tristate unused CKE, ODT and chip select to save power
1630 //===================================================================
1633 for (k = 0; k < sizeof (PinType); k++) {
1634 if (NBPtr->IsSupported[CheckFindPSOverideWithSocket]) {
1635 TabPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PinType[k], NBPtr->MCTPtr->SocketId, MemNGetSocketRelativeChannelNb (NBPtr, NBPtr->Dct, 0), 0,
1636 &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
1638 if (NBPtr->IsSupported[CheckFindPSDct]) {
1639 TabPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PinType[k], NBPtr->MCTPtr->SocketId, NBPtr->Dct, 0,
1640 &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
1642 if (TabPtr == NULL) {
1645 TabPtr = NBPtr->ChannelPtr->CKETriMap;
1648 TabPtr = NBPtr->ChannelPtr->ODTTriMap;
1651 TabPtr = NBPtr->ChannelPtr->ChipSelTriMap;
1657 ASSERT (TabPtr != NULL);
1660 for (i = 0; i < TabSize[k]; i++) {
1661 if ((NBPtr->DCTPtr->Timings.CsPresent & TabPtr[i]) == 0) {
1662 Value |= (UINT8) (1 << i);
1666 if (PinType[k] == PSO_CS_TRI) {
1667 NBPtr->FamilySpecificHook[BeforeSetCsTri] (NBPtr, &Value);
1670 ASSERT (k < GET_SIZE_OF (BitField));
1671 MemNSetBitFieldNb (NBPtr, BitField[k], Value);
1673 NBPtr->MemNBeforePlatformSpecNb (NBPtr);
1675 //===================================================================
1676 // Program Address/Command timings and driver strength
1677 //===================================================================
1679 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ADDRTMG, ALL_DIMMS);
1680 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODCCONTROL, ALL_DIMMS);
1682 MemNSetBitFieldNb (NBPtr, BFSlowAccessMode, (NBPtr->ChannelPtr->SlowMode) ? 1 : 0);
1683 MemNSetBitFieldNb (NBPtr, BFODCControl, NBPtr->ChannelPtr->DctOdcCtl);
1684 MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, NBPtr->ChannelPtr->DctAddrTmg);
1685 NBPtr->FamilySpecificHook[SetDqsODT] (NBPtr, NBPtr);
1687 if (NBPtr->IsSupported[CheckODTControls]) {
1688 MemNSetBitFieldNb (NBPtr, BFPhyRODTCSLow, NBPtr->ChannelPtr->PhyRODTCSLow);
1689 MemNSetBitFieldNb (NBPtr, BFPhyRODTCSHigh, NBPtr->ChannelPtr->PhyRODTCSHigh);
1690 MemNSetBitFieldNb (NBPtr, BFPhyWODTCSLow, NBPtr->ChannelPtr->PhyWODTCSLow);
1691 MemNSetBitFieldNb (NBPtr, BFPhyWODTCSHigh, NBPtr->ChannelPtr->PhyWODTCSHigh);
1694 /* -----------------------------------------------------------------------------*/
1698 * This function gets the Trdrd value
1700 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1702 * @return Trdrd value
1707 IN OUT MEM_NB_BLOCK *NBPtr
1713 DCTPtr = NBPtr->DCTPtr;
1715 // BIOS calculates Trdrd (in MEMCLKs) = CGDD / 2 + 3 clocks and programs F2x[1, 0]8C[Trdrd] with the
1716 // converted field value. BIOS rounds fractional values down.
1717 // The Critical Gross Delay Difference (CGDD) for Trdrd on any given byte lane is the largest F2x[1,
1718 // 0]9C_x[3:0][2B:10][DqsRcvEnGrossDelay] delay of any DIMM minus the F2x[1,
1719 // 0]9C_x[3:0][2B:10][DqsRcvEnGrossDelay] delay of any other DIMM.
1721 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessRcvEnDly, AccessRcvEnDly);
1722 DCTPtr->Timings.Trdrd = (Cgdd / 2) + 3;
1724 // Transfer clk to reg definition, 2T is 00b, etc.
1725 DCTPtr->Timings.Trdrd -= 2;
1726 if (DCTPtr->Timings.Trdrd > 8) {
1727 DCTPtr->Timings.Trdrd = 8;
1730 return DCTPtr->Timings.Trdrd;
1734 /* -----------------------------------------------------------------------------*/
1738 * This function gets the Twrwr value
1740 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1742 * @return Twrwr value
1747 IN OUT MEM_NB_BLOCK *NBPtr
1753 DCTPtr = NBPtr->DCTPtr;
1755 // Twrwr (in MEMCLKs) = CGDD / 2 + 3 clocks and programs F2x[1, 0]8C[Twrwr] with the
1756 // converted field value. BIOS rounds fractional values down.
1757 // On any given byte lane, the largest F2x[1, 0]9C_x[3:0][A, 7, 6, 0][2:1]:F2x[1, 0]9C_x[3:0][A, 7, 6,
1758 // 0]3[WrDatGrossDlyByte] delay of any DIMM minus the F2x[1, 0]9C_x[3:0][A, 7, 6, 0][2:1]:F2x[1,
1759 // 0]9C_x[3:0][A, 7, 6, 0]3[WrDatGrossDlyByte] delay of any other DIMM is equal to the Critical Gross
1760 // Delay Difference (CGDD) for Twrwr.
1762 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessWrDatDly, AccessWrDatDly);
1763 DCTPtr->Timings.Twrwr = (Cgdd / 2) + 3;
1764 NBPtr->TechPtr->AdjustTwrwr (NBPtr->TechPtr);
1766 return DCTPtr->Timings.Twrwr;
1769 /* -----------------------------------------------------------------------------*/
1773 * This function gets the Twrrd value. BIOS calculates Twrrd (in MEMCLKs) = CGDD / 2 - LD + 3 clocks and programs
1774 * F2x[1, 0]8C[Twrrd] with the converted field value. BIOS rounds fractional
1777 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1779 * @return Value to be programmed to Twrrd field
1780 * pDCT->Timings.Twrrd updated
1785 IN OUT MEM_NB_BLOCK *NBPtr
1793 DCTPtr = NBPtr->DCTPtr;
1796 // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS
1797 // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive
1799 // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1801 Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1803 // On any given byte lane, the largest WrDatGrossDlyByte delay of any DIMM
1804 // minus the DqsRcvEnGrossDelay delay of any other DIMM is
1805 // equal to the Critical Gross Delay Difference (CGDD) for Twrrd.
1806 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessWrDatDly, AccessRcvEnDly);
1807 Twrrd = (Cgdd / 2) - Ld + 3;
1808 DCTPtr->Timings.Twrrd = (UINT8) ((Twrrd >= 0) ? Twrrd : 0);
1809 NBPtr->TechPtr->AdjustTwrrd (NBPtr->TechPtr);
1811 return DCTPtr->Timings.Twrrd;
1814 /* -----------------------------------------------------------------------------*/
1818 * This function gets the TrwtTO value
1820 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1822 * @return pDCT->Timings.TrwtTO updated
1827 IN OUT MEM_NB_BLOCK *NBPtr
1835 DCTPtr = NBPtr->DCTPtr;
1837 // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS
1838 // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive
1840 // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1842 Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1844 // On any byte lane, the largest DqsRcvEnGrossDelay delay of any DIMM minus
1845 // the WrDatGrossDlyByte delay of any other DIMM is equal to the Critical Gross
1846 // Delay Difference (CGDD) for TrwtTO.
1847 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessRcvEnDly, AccessWrDatDly);
1848 TrwtTO = (Cgdd / 2) + Ld + 3;
1850 DCTPtr->Timings.TrwtTO = (UINT8) ((TrwtTO > 1) ? TrwtTO : 1);
1852 return DCTPtr->Timings.TrwtTO;
1855 /* -----------------------------------------------------------------------------*/
1859 * This function gets the TrwtWB value
1861 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1863 * @return TrwtWB value
1867 IN OUT MEM_NB_BLOCK *NBPtr
1872 DCTPtr = NBPtr->DCTPtr;
1874 // TrwtWB ensures read-to-write data-bus turnaround.
1875 // This value should be one more than the programmed TrwtTO.
1876 return DCTPtr->Timings.TrwtWB = DCTPtr->Timings.TrwtTO;
1879 /* -----------------------------------------------------------------------------*/
1883 * This function converts MemClk frequency in MHz to MemClkFreq value
1885 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1886 * @param[in] Speed - MemClk frequency in MHz
1888 * @return MemClkFreq value
1891 MemNGetMemClkFreqIdNb (
1892 IN OUT MEM_NB_BLOCK *NBPtr,
1896 return (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
1899 /* -----------------------------------------------------------------------------*/
1903 * This function enables swapping interleaved region feature.
1905 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1906 * @param[in] Base - Swap interleaved region base [47:27]
1907 * @param[in] Limit - Swap interleaved region limit [47:27]
1911 MemNEnableSwapIntlvRgnNb (
1912 IN OUT MEM_NB_BLOCK *NBPtr,
1920 // Swapped interleaving region must be below 16G
1921 if (Limit < (1 << (34 - 27))) {
1922 // Adjust Base and Size to meet :
1923 // 1. The size of the swapped region must be less than or equal to the alignment of F2x10C[IntLvRegionBase].
1924 // 2. Entire UMA region is swapped with interleaving region.
1925 Size = Limit - Base;
1926 SizeOfAlign = (UINT32) 1 << LibAmdBitScanForward (Base);
1927 while (SizeOfAlign <= Size) {
1928 // In case of SizeOfAlign <= Size, UmaBase -= 128MB, SizeOfIntlvrgn += 128MB.
1931 SizeOfAlign = (UINT32) 1 << LibAmdBitScanForward (Base);
1933 MemNSetBitFieldNb (NBPtr, BFIntLvRgnBaseAddr, Base);
1934 MemNSetBitFieldNb (NBPtr, BFIntLvRgnLmtAddr, (Limit - 1));
1935 MemNSetBitFieldNb (NBPtr, BFIntLvRgnSize, Size);
1936 MemNSetBitFieldNb (NBPtr, BFIntLvRgnSwapEn, 1);
1940 /* -----------------------------------------------------------------------------*/
1944 * This function converts MemClk frequency in MHz to MemClkFreq value
1946 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1947 * @param[in] Speed - MemClk frequency in MHz
1949 * @return MemClkFreq value
1952 MemNGetMemClkFreqIdClientNb (
1953 IN OUT MEM_NB_BLOCK *NBPtr,
1957 return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1960 /* -----------------------------------------------------------------------------*/
1964 * This function converts MemClk frequency in MHz to MemClkFreq value
1966 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1967 * @param[in] Speed - MemClk frequency in MHz
1969 * @return MemClkFreq value
1972 MemNGetMemClkFreqIdUnb (
1973 IN OUT MEM_NB_BLOCK *NBPtr,
1977 return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1980 /* -----------------------------------------------------------------------------*/
1984 * This function converts MemClkFreq Id value to MemClk frequency in MHz
1986 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1987 * @param[in] FreqId - FreqId from Register
1989 * @return MemClk frequency in MHz
1992 MemNGetMemClkFreqUnb (
1993 IN OUT MEM_NB_BLOCK *NBPtr,
1999 MemClkFreq = (FreqId == 14) ? 667 : (300 + ((FreqId - 3) * 33) + (FreqId - 3) / 3);
2000 } else if (FreqId == 2) {
2003 MemClkFreq = 50 + (50 * FreqId);
2008 /* -----------------------------------------------------------------------------*/
2011 * This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
2014 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2019 MemNChangeFrequencyClientNb (
2020 IN OUT MEM_NB_BLOCK *NBPtr
2023 MEM_TECH_BLOCK *TechPtr;
2026 UINT16 FinalPllLockTime;
2027 BOOLEAN FrequencyChangeSuccess;
2028 UINT64 OrgMMIOCfgBase;
2029 UINT64 NewMMIOCfgBase;
2031 TechPtr = NBPtr->TechPtr;
2033 // Disable MMIO to prevent speculative DRAM reads during self refresh
2034 LibAmdMsrRead (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2035 NewMMIOCfgBase = OrgMMIOCfgBase & (~(BIT0));
2036 LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &NewMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2038 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
2040 //Program F2x[1,0]90[EnterSelfRefresh]=1.
2041 //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
2042 MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
2043 MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2045 if (NBPtr->ChangeNbFrequency (NBPtr)) {
2046 // Reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
2047 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2048 MemNSwitchDCTNb (NBPtr, Dct);
2049 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2050 TechPtr->AutoCycTiming (TechPtr);
2051 if (!MemNPlatformSpecUnb (NBPtr)) {
2057 // 1. Program PllLockTime to Family-specific value
2058 MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
2060 // 2. Program D18F2x[1,0]94[MemClkFreqVal] = 0.
2061 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
2063 // 3. Program D18F2x[1,0]94[MemClkFreq] to the desired DRAM frequency.
2064 MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
2066 // 4. Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
2067 // 5. Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
2068 // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0]. See 2.10.3.2.2.1 [DCT Transmit Fifo Schedule
2069 // Delay Programming].
2070 // 6. D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
2071 // THEN 2 ELSE 3 ENDIF (Ontario)
2072 NBPtr->ProgramNbPsDependentRegs (NBPtr);
2074 NBPtr->FamilySpecificHook[BeforeMemClkFreqVal] (NBPtr, NBPtr);
2075 IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
2076 // 7. Program D18F2x[1,0]94[MemClkFreqVal] = 1.
2077 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
2078 MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
2079 FinalPllLockTime = 0xF;
2080 NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &FinalPllLockTime);
2082 // 8. IF (D18F2x[1,0]9C_x0D0F_E00A[CsrPhySrPllPdMode]==0) THEN program
2083 // D18F2x[1,0]9C_x0D0F_E006[PllLockTime] = 0Fh.
2084 if (!NBPtr->IsSupported[CsrPhyPllPdEn]) {
2085 MemNBrdcstSetNb (NBPtr, BFPllLockTime, FinalPllLockTime);
2088 FrequencyChangeSuccess = TRUE;
2090 // If NB frequency cannot be updated, use the current speed as the target speed
2091 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2092 MemNSwitchDCTNb (NBPtr, Dct);
2093 NBPtr->DCTPtr->Timings.Speed = NBPtr->TechPtr->PrevSpeed;
2094 NBPtr->DCTPtr->Timings.TargetSpeed = NBPtr->TechPtr->PrevSpeed;
2096 FrequencyChangeSuccess = FALSE;
2099 //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
2100 //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
2101 MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
2102 MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2103 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
2105 if (FrequencyChangeSuccess) {
2106 NBPtr->FamilySpecificHook[AfterMemClkFreqChg] (NBPtr, NULL);
2108 // Perform Phy Fence training and Phy comp init after frequency change
2109 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2110 MemNSwitchDCTNb (NBPtr, Dct);
2111 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2112 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2114 // Phy fence programming
2115 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
2116 NBPtr->PhyFenceTraining (NBPtr);
2118 // Phy compensation initialization
2119 AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
2120 NBPtr->MemNInitPhyComp (NBPtr);
2121 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
2125 //======================================================================
2126 // Calculate and program DRAM Timings at new frequency
2127 //======================================================================
2129 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2130 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2131 MemNSwitchDCTNb (NBPtr, Dct);
2132 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2133 for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
2134 if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
2135 // if chip select present
2136 if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) {
2137 TechPtr->SendAllMRCmds (TechPtr, ChipSel);
2141 // Wait 512 clocks for DLL-relock
2142 MemNWaitXMemClksNb (NBPtr, 512);
2147 // Restore MMIO setting
2148 LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2150 MemFInitTableDrive (NBPtr, MTAfterFreqChg);
2153 /* -----------------------------------------------------------------------------*/
2156 * This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
2159 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2164 MemNChangeFrequencyUnb (
2165 IN OUT MEM_NB_BLOCK *NBPtr
2168 MEM_TECH_BLOCK *TechPtr;
2171 UINT16 FinalPllLockTime;
2172 BOOLEAN FrequencyChangeSuccess;
2173 UINT64 OrgMMIOCfgBase;
2174 UINT64 NewMMIOCfgBase;
2176 TechPtr = NBPtr->TechPtr;
2178 // Disable MMIO to prevent speculative DRAM reads during self refresh
2179 LibAmdMsrRead (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2180 NewMMIOCfgBase = OrgMMIOCfgBase & (~(BIT0));
2181 LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &NewMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2183 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
2185 //Program F2x[1,0]90[EnterSelfRefresh]=1.
2186 //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
2187 MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
2188 MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2190 if (NBPtr->ChangeNbFrequency (NBPtr)) {
2191 // Reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
2192 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2193 MemNSwitchDCTNb (NBPtr, Dct);
2194 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2195 TechPtr->AutoCycTiming (TechPtr);
2196 if (!MemNPlatformSpecUnb (NBPtr)) {
2202 // 1. Program PllLockTime to Family-specific value
2203 MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
2205 // 2. Program D18F2x[1,0]94[MemClkFreqVal] = 0.
2206 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
2208 // 3. Program D18F2x[1,0]94[MemClkFreq] to the desired DRAM frequency.
2209 MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
2211 // 4. Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
2212 // 5. Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
2213 // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0]. See 2.10.3.2.2.1 [DCT Transmit Fifo Schedule
2214 // Delay Programming].
2215 // 6. D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
2216 // THEN 2 ELSE 3 ENDIF (Ontario)
2217 NBPtr->ProgramNbPsDependentRegs (NBPtr);
2219 IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
2220 // 7. Program D18F2x[1,0]94[MemClkFreqVal] = 1.
2221 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2222 MemNSwitchDCTNb (NBPtr, Dct);
2223 if ((NBPtr->DCTPtr->Timings.DctMemSize != 0)) {
2224 MemNSetBitFieldNb (NBPtr, BFMemClkFreqVal, 1);
2225 MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, FALSE);
2228 FinalPllLockTime = 0xF;
2229 NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &FinalPllLockTime);
2231 // 8. IF (D18F2x[1,0]9C_x0D0F_E00A[CsrPhySrPllPdMode]==0) THEN program
2232 // D18F2x[1,0]9C_x0D0F_E006[PllLockTime] = 0Fh.
2233 if (!NBPtr->IsSupported[CsrPhyPllPdEn]) {
2234 MemNBrdcstSetNb (NBPtr, BFPllLockTime, FinalPllLockTime);
2237 FrequencyChangeSuccess = TRUE;
2239 // If NB frequency cannot be updated, use the current speed as the target speed
2240 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2241 MemNSwitchDCTNb (NBPtr, Dct);
2242 NBPtr->DCTPtr->Timings.Speed = NBPtr->TechPtr->PrevSpeed;
2243 NBPtr->DCTPtr->Timings.TargetSpeed = NBPtr->TechPtr->PrevSpeed;
2245 FrequencyChangeSuccess = FALSE;
2248 if (FrequencyChangeSuccess) {
2249 // Perform Phy Fence training and Phy comp init after frequency change
2250 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2251 MemNSwitchDCTNb (NBPtr, Dct);
2252 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2253 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2255 // Phy fence programming
2256 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
2257 NBPtr->PhyFenceTraining (NBPtr);
2259 // Phy compensation initialization
2260 AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
2261 NBPtr->MemNInitPhyComp (NBPtr);
2262 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
2267 //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
2268 //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
2269 MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
2270 MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2271 if (NBPtr->IsSupported[SetDllShutDown]) {
2272 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
2275 if (FrequencyChangeSuccess) {
2276 NBPtr->FamilySpecificHook[AfterMemClkFreqChg] (NBPtr, NULL);
2278 //======================================================================
2279 // Calculate and program DRAM Timings at new frequency
2280 //======================================================================
2282 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2283 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2284 MemNSwitchDCTNb (NBPtr, Dct);
2285 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2286 for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
2287 if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
2288 // if chip select present
2289 if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) {
2290 TechPtr->SendAllMRCmds (TechPtr, ChipSel);
2294 // Wait 512 clocks for DLL-relock
2295 MemNWaitXMemClksNb (NBPtr, 512);
2300 // Restore MMIO setting
2301 LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2303 MemFInitTableDrive (NBPtr, MTAfterFreqChg);
2307 /* -----------------------------------------------------------------------------*/
2310 * This function calculates and programs NB P-state dependent registers
2312 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2317 MemNProgramNbPstateDependentRegistersUnb (
2318 IN OUT MEM_NB_BLOCK *NBPtr
2323 RdPtrInit = (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 6 : 4;
2324 MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit);
2325 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit);
2327 MemFInitTableDrive (NBPtr, MTAfterNbPstateChange);
2329 IDS_HDT_CONSOLE_DEBUG_CODE (
2330 RdPtrInit = (UINT8) MemNGetBitFieldNb (NBPtr, BFRdPtrInit);
2333 switch (RdPtrInit) {
2335 if (MemNGetBitFieldNb (NBPtr, BFNbPsSel) == 0) {
2336 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 2);
2338 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
2342 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
2345 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 0);
2351 NBPtr->FamilySpecificHook[OverrideDataTxFifoWrDly] (NBPtr, NBPtr);
2352 IDS_OPTION_HOOK (IDS_NBPS_REG_OVERRIDE, NBPtr, &NBPtr->MemPtr->StdHeader);
2355 /* -----------------------------------------------------------------------------*/
2356 CONST UINT8 PllDivTab[] = {0, 0, 0, 2, 3, 3, 2, 3};
2357 CONST UINT8 PllMultTab[] = {0, 0, 0, 16, 32, 40, 32, 56};
2361 * This function calculates and programs NB P-state dependent registers
2363 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2368 MemNProgramNbPstateDependentRegistersClientNb (
2369 IN OUT MEM_NB_BLOCK *NBPtr
2381 UINT32 MemClkPeriod;
2383 INT32 PartialSumSlotI2x;
2384 INT32 RdPtrInitRmdr2x;
2389 NclkFid = (UINT8) (MemNGetBitFieldNb (NBPtr, BFMainPllOpFreqId) + 0x10); // NclkFid is in 100MHz
2391 MemClkDid = PllDivTab[NBPtr->DCTPtr->Timings.Speed / 133];
2392 NBPtr->FamilySpecificHook[OverridePllDiv] (NBPtr, &MemClkDid);
2393 PllMult = PllMultTab[NBPtr->DCTPtr->Timings.Speed / 133];
2394 NBPtr->FamilySpecificHook[OverridePllMult] (NBPtr, &PllMult);
2396 if (NBPtr->NbFreqChgState == 2) {
2397 MemNSetBitFieldNb (NBPtr, BFNbPsCsrAccSel, 1);
2398 MemNSetBitFieldNb (NBPtr, BFNbPsDbgEn, 1);
2399 NclkDiv = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPs1NclkDiv);
2400 // Divisors less than 8 are undefined. Maybe the CPU does not support NB P-states.
2402 // Set a dummy divisor to prevent divide by zero exception below.
2407 NclkDiv = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPs0NclkDiv);
2410 NclkPeriod = (2500 * NclkDiv) / NclkFid; // (1,000,000 * 0.25 * NclkDiv) / (NclkFid * 100MHz) = ps
2411 MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
2412 NBPtr->NBClkFreq = ((UINT32) NclkFid * 400) / NclkDiv;
2414 IDS_HDT_CONSOLE (MEM_FLOW, "\n\tNB P%d Freq: %dMHz\n", NbPstate, NBPtr->NBClkFreq);
2415 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClk Freq: %dMHz\n", NBPtr->DCTPtr->Timings.Speed);
2416 // D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
2417 // THEN 2 ELSE 3 ENDIF (Ontario)
2418 RdPtrInit = RdPtrInitMin = (NBPtr->DCTPtr->Timings.Speed >= DDR1333_FREQUENCY) ? NBPtr->FreqChangeParam->RdPtrInit667orHigher : NBPtr->FreqChangeParam->RdPtrInitLower667;
2419 NBPtr->FamilySpecificHook[AdjustRdPtrInit] (NBPtr, &RdPtrInit);
2420 MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit);
2421 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit);
2423 // Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
2424 MemNBrdcstSetNb (NBPtr, BFDbeGskFifoNumerator, NclkFid * MemClkDid * 16);
2425 MemNBrdcstSetNb (NBPtr, BFDbeGskFifoDenominator, PllMult * NclkDiv);
2426 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDbeGskFifoNumerator: %d\n", NclkFid * MemClkDid * 16);
2427 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDbeGskFifoDenominator: %d\n", PllMult * NclkDiv);
2429 // Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
2430 // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0].
2431 // PartialSum = ((7 * NclkPeriod) + (1.5 * MemClkPeriod) + 520ps)*MemClkFrequency - tCWL -
2432 // CmdSetup - PtrSeparation - 1. (Llano)
2433 // PartialSum = ((5 * NclkPeriod) + MemClkPeriod) + 520ps)*MemClkFrequency - tCWL -
2434 // CmdSetup - PtrSeparation - 1. (Ontario)
2435 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2436 MemNSwitchDCTNb (NBPtr, Dct);
2437 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2438 PartialSum2x = NBPtr->FreqChangeParam->NclkPeriodMul2x * NclkPeriod;
2439 PartialSum2x += NBPtr->FreqChangeParam->MemClkPeriodMul2x * MemClkPeriod;
2440 PartialSum2x += 520 * 2;
2442 // PtrSeparation = ((16 + RdPtrInitMin - D18F2x[1,0]78[RdPtrInit]) MOD 16)/2 + RdPtrInitRmdr
2443 // If (D18F2x[1,0]94[MemClkFreq] >= 800 MHz)
2444 // then RdPtrInitRmdr = (((4.5 * MemClkPeriod) - 990ps) MOD MemClkPeriod)/MemClkPeriod
2445 // else RdPtrInitRmdr = (((4.5 * MemClkPeriod) - 1466ps) MOD MemClkPeriod)/MemClkPeriod
2446 TDataProp = (NBPtr->DCTPtr->Timings.Speed >= DDR1600_FREQUENCY) ?
2447 NBPtr->FreqChangeParam->TDataProp800orHigher : NBPtr->FreqChangeParam->TDataPropLower800;
2448 RdPtrInitRmdr2x = ((NBPtr->FreqChangeParam->SyncTimeMul4x * MemClkPeriod) / 2) - 2 * (TDataProp + 520);
2449 RdPtrInitRmdr2x %= MemClkPeriod;
2450 PartialSum2x -= ((16 + RdPtrInitMin - RdPtrInit) % 16) * MemClkPeriod + RdPtrInitRmdr2x;
2452 // Convert PartialSum2x to PCLK
2453 PartialSum2x = (PartialSum2x + MemClkPeriod - 1) / MemClkPeriod; // round-up here
2454 PartialSum2x -= 2 * (MemNGetBitFieldNb (NBPtr, BFTcwl) + 5);
2455 if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) {
2462 // If PartialSumSlotN is positive:
2463 // DataTxFifoSchedDlySlotN=CEIL(PartialSumSlotN).
2464 // DataTxFifoSchedDlyNegSlotN=0.
2465 // Else if PartialSumSlotN is negative:
2466 // DataTxFifoSchedDlySlotN=ABS(CEIL(PartialSumSlotN*MemClkPeriod/NclkPeriod)).
2467 // DataTxFifoSchedDlyNegSlotN=1.
2468 for (i = 0; i < 2; i++) {
2469 PartialSumSlotI2x = PartialSum2x;
2470 SlowMode = (UINT8) MemNGetBitFieldNb (NBPtr, BFSlowAccessMode);
2471 if ((i == 0) && (SlowMode == 0)) {
2472 PartialSumSlotI2x += 2;
2474 if (NBPtr->IsSupported[SchedDlySlot1Extra] && (i == 1) && (SlowMode != 0)) {
2475 PartialSumSlotI2x -= 2;
2477 if (PartialSumSlotI2x > 0) {
2478 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlyNegSlot0 + i, 0);
2479 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlySlot0 + i, (PartialSumSlotI2x + 1) / 2);
2480 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDataTxFifoSchedDlySlot%d: %d\n", i, (PartialSumSlotI2x + 1) / 2);
2482 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlyNegSlot0 + i, 1);
2483 PartialSumSlotI2x = ((-PartialSumSlotI2x) * MemClkPeriod) / (2 * NclkPeriod);
2484 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlySlot0 + i, PartialSumSlotI2x);
2485 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDataTxFifoSchedDlySlot%d: -%d\n", i, PartialSumSlotI2x);
2490 if ((NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY) &&
2491 ((!(NBPtr->IsSupported[EnProcOdtAdvForUDIMM])) || (NBPtr->ChannelPtr->SODimmPresent != 0))) {
2492 MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0);
2494 MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000);
2499 MemFInitTableDrive (NBPtr, MTAfterNbPstateChange);
2500 if (NBPtr->NbFreqChgState == 2) {
2501 MemNSetBitFieldNb (NBPtr, BFNbPsDbgEn, 0);
2502 MemNSetBitFieldNb (NBPtr, BFNbPsCsrAccSel, 0);
2506 /* -----------------------------------------------------------------------------*/
2510 * This function gets the total of sync components for Max Read Latency calculation
2512 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2514 * @return Total in ps
2518 MemNTotalSyncComponentsClientNb (
2519 IN OUT MEM_NB_BLOCK *NBPtr
2527 UINT8 DbeGskMemClkAlignMode;
2528 UINT32 MemClkPeriod;
2530 // P = P + ((16 + RdPtrInitMin - D18F2x[1,0]78[RdPtrInit]) MOD 16)
2531 RdPtrInitMin = (NBPtr->DCTPtr->Timings.Speed >= DDR1333_FREQUENCY) ? NBPtr->FreqChangeParam->RdPtrInit667orHigher : NBPtr->FreqChangeParam->RdPtrInitLower667;
2532 RdPtrInit = (UINT8) MemNGetBitFieldNb (NBPtr, BFRdPtrInit);
2533 P = (16 + RdPtrInitMin - RdPtrInit) % 16;
2535 // IF (AddrCmdSetup != CkeSetup) THEN P = P + 1
2536 AddrTmgCtl = MemNGetBitFieldNb (NBPtr, BFAddrTmgControl);
2537 if (((AddrTmgCtl >> 16) & 0x20) != (AddrTmgCtl & 0x20)) {
2541 // IF (DbeGskMemClkAlignMode==01b || (DbeGskMemClkAlignMode==00b && !(AddrCmdSetup==CsOdtSetup==CkeSetup)))
2543 DbeGskMemClkAlignMode = (UINT8) MemNGetBitFieldNb (NBPtr, BFDbeGskMemClkAlignMode);
2544 if ((DbeGskMemClkAlignMode == 1) || ((DbeGskMemClkAlignMode == 0) &&
2545 !((((AddrTmgCtl >> 16) & 0x20) == (AddrTmgCtl & 0x20)) && (((AddrTmgCtl >> 8) & 0x20) == (AddrTmgCtl & 0x20))))) {
2549 // IF (SlowAccessMode==1) THEN P = P + 2
2550 if (MemNGetBitFieldNb (NBPtr, BFSlowAccessMode) == 1) {
2558 // If (AddrCmdSetup==0 && CsOdtSetup==0 && CkeSetup==0)
2561 if ((AddrTmgCtl & 0x0202020) == 0) {
2567 // P = P + (2 * (D18F2x[1,0]88[Tcl] clocks - 1))
2568 P += 2 * (NBPtr->DCTPtr->Timings.CasL - 1);
2570 // If (DisCutThroughMode==0)
2573 if (MemNGetBitFieldNb (NBPtr, BFDisCutThroughMode) == 0) {
2579 MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
2580 return (((P * MemClkPeriod + 1) / 2) + T);
2583 /* -----------------------------------------------------------------------------*/
2587 * This function sets up phy power saving for client NB
2590 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2594 MemNPhyPowerSavingClientNb (
2595 IN OUT MEM_NB_BLOCK *NBPtr
2598 // 4. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[DllDisEarlyU] = 1b.
2599 // 5. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[DllDisEarlyL] = 1b.
2600 // 6. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[7:4] = 1010b.
2601 MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13Bit0to7, 0xA3);
2602 // 7. Program D18F2x[1,0]9C_x0D0F_812F[7, 5, 0] = {1b, 1b, 1b} to disable unused PAR and A[17:16] pins.
2603 MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 0xA1);
2604 // 8. Program D18F2x[1,0]9C_x0D0F_C000[LowPowerDrvStrengthEn] = 1.
2605 if (!NBPtr->FamilySpecificHook[DisLowPwrDrvStr] (NBPtr, NULL)) {
2606 MemNSetBitFieldNb (NBPtr, BFReserved00C, 0x100);
2608 // 9. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]10[EnRxPadStandby]= IF (D18F2x[1,0]94[MemClkFreq] <=
2609 // 800 MHz) THEN 1 ELSE 0 ENDIF.
2610 MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 0x1000 : 0);
2611 // 10. Program D18F2x[1,0]9C_x0000_000D as follows:
2612 // TxMaxDurDllNoLock/RxMaxDurDllNoLock = 7h.
2613 MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 7);
2614 MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 7);
2615 // TxCPUpdPeriod/RxCPUpdPeriod = 011b.
2616 MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 3);
2617 MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 3);
2618 // TxDLLWakeupTime/RxDLLWakeupTime = 11b.
2619 MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 3);
2620 MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 3);
2622 IDS_OPTION_HOOK (IDS_PHY_DLL_STANDBY_CTRL, NBPtr, &NBPtr->MemPtr->StdHeader);
2625 /* -----------------------------------------------------------------------------*/
2629 * This function sets up phy power saving for UNB
2632 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2636 MemNPhyPowerSavingUnb (
2637 IN OUT MEM_NB_BLOCK *NBPtr
2640 UINT16 MixedX4AndX8Dimms;
2642 // 4. Program D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][DllDisEarlyU] = 1b.
2643 // 5. Program D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][DllDisEarlyL] = 1b.
2644 MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13, MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) | 3);
2645 // 6. D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][RxDqsUDllPowerDown] = (D18F2x90_dct[1:0][X4Dimm]!=0).
2646 MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13, MemNGetBitFieldNb (NBPtr, BFX4Dimm) == 0 ? (MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) | 0x80) : (MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) & 0xFF7F));
2647 // 7. D18F2x9C_x0D0F_812F_dct[1:0][PARTri] = ~D18F2x90_dct[1:0][ParEn].
2648 MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFParEn) == 0 ? (MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 1) : (MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) & 0xFFFE));
2649 // 8. D18F2x9C_x0D0F_812F_dct[1:0][Add17Tri, Add16Tri] = {1b, 1b}
2650 MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 0xA0);
2651 // 9. IF (D18F2x94_dct[1:0][MemClkFreq] <= 800 MHz && ~(mixed channel of x4 and x8 DIMMs)) THEN
2652 // Program D18F2x9C_x0D0F_0[F,8:0]10_dct[1:0][EnRxPadStandby] = 1.
2654 // Program D18F2x9C_x0D0F_0[F,8:0]10_dct[1:0][EnRxPadStandby] = 0.
2656 MixedX4AndX8Dimms = NBPtr->DCTPtr->Timings.Dimmx4Present != 0 && NBPtr->DCTPtr->Timings.Dimmx8Present != 0;
2657 MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) && !MixedX4AndX8Dimms ? 0x1000 : 0);
2658 // 10. IF (~(mixed channel of x4 and x8 DIMMs)) THEN
2659 if (MixedX4AndX8Dimms == FALSE) {
2660 // Program D18F2x9C_x0000_000D_dct[1:0] as follows:
2661 // TxMaxDurDllNoLock = RxMaxDurDllNoLock = 7h.
2662 MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 7);
2663 MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 7);
2664 // TxCPUpdPeriod = RxCPUpdPeriod = 011b.
2665 MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 3);
2666 MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 3);
2667 // TxDLLWakeupTime = RxDLLWakeupTime = 11b.
2668 MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 3);
2669 MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 3);
2672 // Program D18F2x9C_x0000_000D_dct[1:0][TxMaxDurDllNoLock, RxMaxDurDllNoLock, TxCPUpdPeriod,
2673 // RxCPUpdPeriod, TxDLLWakeupTime, RxDLLWakeupTime] = {0, 0, 0, 0, 0, 0}.
2674 MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 0);
2675 MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 0);
2676 MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 0);
2677 MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 0);
2678 MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 0);
2679 MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 0);
2681 // 11. Program D18F2x9C_x0D0F_0[F,8:0]30_dct[1:0][PwrDn] to disable unused ECC byte lane.
2682 if (NBPtr->IsSupported[CheckEccDLLPwrDnConfig]) {
2683 if (!NBPtr->MCTPtr->Status[SbEccDimms]) {
2684 MemNSetBitFieldNb (NBPtr, BFEccDLLPwrDnConf, 0x0010);
2688 // 12. Program D18F2x9C_x0D0F_0[F,8:0]04_dct[1:0][TriDM] = IF (LRDIMM & (D18F2x90_dct[1:0][X4Dimm] == 0)) THEN 1 ELSE 0.
2689 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
2690 MemNSetBitFieldNb (NBPtr, BFDataByteDMConf, (MemNGetBitFieldNb (NBPtr, BFX4Dimm) == 0) ? 0x2000 : 0);
2693 IDS_OPTION_HOOK (IDS_PHY_DLL_STANDBY_CTRL, NBPtr, &NBPtr->MemPtr->StdHeader);
2696 /* -----------------------------------------------------------------------------*/
2700 * This function overrides the ASR and SRT value in MRS command
2702 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2707 IN OUT MEM_NB_BLOCK *NBPtr
2712 UINT8 *SpdBufferPtr;
2715 if (NBPtr->GetBitField (NBPtr, BFMrsBank) == 2) {
2716 MrsAddress = NBPtr->GetBitField (NBPtr, BFMrsAddress);
2717 // Clear A6(ASR) and A7(SRT)
2718 MrsAddress &= (UINT32) ~0xC0;
2719 Dimm = (UINT8) (NBPtr->GetBitField (NBPtr, BFMrsChipSel) >> 1);
2720 // Make sure we access SPD of the second logical dimm of QR dimm correctly
2721 if ((Dimm >= 2) && ((NBPtr->ChannelPtr->DimmQrPresent & (UINT8) (1 << Dimm)) != 0)) {
2724 if (NBPtr->TechPtr->GetDimmSpdBuffer (NBPtr->TechPtr, &SpdBufferPtr, Dimm)) {
2726 if (SpdBufferPtr[THERMAL_OPT] & 0x4) {
2727 // when ASR is 1, set SRT to 0
2730 // Set SRT based on bit on of thermal byte
2731 MrsAddress |= ((SpdBufferPtr[THERMAL_OPT] & 1) << 7);
2733 NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
2738 /* -----------------------------------------------------------------------------*/
2741 * This function changes NB frequency as below:
2742 * NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP0-DDRTarget
2744 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2749 MemNChangeNbFrequencyNb (
2750 IN OUT MEM_NB_BLOCK *NBPtr
2757 // State machine to change NB frequency and NB Pstate
2758 switch (NBPtr->NbFreqChgState) {
2760 // Starting up by not changing NB P state, but only updating NB frequency based on current MemClk frequency
2761 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2764 if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
2765 // When MemClk has been ramped up to its max, transition to next state, which changes NBPstate to P1
2766 NBPtr->NbFreqChgState = 1;
2767 IDS_OPTION_HOOK (IDS_NB_PSTATE_DIDVID, NBPtr, &(NBPtr->MemPtr->StdHeader));
2772 // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P0
2773 MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2775 // Next state would be to change NBPstate back to P0
2776 NBPtr->NbFreqChgState = 2;
2778 // Update NB freq dependent registers
2779 NBPtr->ProgramNbPsDependentRegs (NBPtr);
2781 // Change NB P-State to NBP1 for MaxRdLat training
2782 if (NBPtr->ChangeNbFrequencyWrap (NBPtr, 1)) {
2783 // Enable cut through mode for NB P1
2784 MemNBrdcstSetNb (NBPtr, BFDisCutThroughMode, 0);
2786 // Return TRUE to repeat MaxRdLat training
2790 // If transition to NB-P1 fails, transition to exit state machine
2791 NBPtr->NbFreqChgState = 3;
2796 // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P1
2797 MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2799 // Change NB P-State back to NBP0
2800 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2803 // Return FALSE to get out of MaxRdLat training loop
2806 // Exit state machine
2807 NBPtr->NbFreqChgState = 3;
2817 /*-----------------------------------------------------------------------------
2820 * This function programs registers before phy fence training for CNB
2822 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2823 * @param[in,out] OptParam - Optional parameter
2826 * ----------------------------------------------------------------------------
2829 MemNBeforePhyFenceTrainingClientNb (
2830 IN OUT MEM_NB_BLOCK *NBPtr,
2831 IN OUT VOID *OptParam
2834 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClkAlign=0\n");
2835 MemNBrdcstSetNb (NBPtr, BFDbeGskMemClkAlignMode, 0);
2837 IDS_HDT_CONSOLE (MEM_FLOW, "\tEnDramInit = 1 for both DCTs\n");
2838 MemNBrdcstSetNb (NBPtr, BFEnDramInit, 1);
2843 /* -----------------------------------------------------------------------------*/
2846 * This function changes NB frequency foras below:
2847 * NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP2-DDRTarget -> NBP3-DDRTarget -> NBP0-DDRTarget
2850 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2855 MemNChangeNbFrequencyUnb (
2856 IN OUT MEM_NB_BLOCK *NBPtr
2863 // State machine to change NB frequency and NB Pstate
2864 switch (NBPtr->NbFreqChgState) {
2866 // Do not change NB Pstate, just to save initial NB Pstate value
2867 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2868 if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
2869 // When MemClk has been ramped up to its max, transition to next state, which changes NBPstate to P1
2870 NBPtr->NbFreqChgState = 1;
2871 IDS_OPTION_HOOK (IDS_NB_PSTATE_DIDVID, NBPtr, &(NBPtr->MemPtr->StdHeader));
2878 // Change NB P-State to NBP1 for MaxRdLat training
2879 if (NBPtr->ChangeNbFrequencyWrap (NBPtr, NBPtr->NbFreqChgState)) {
2880 // Next state is to try all NBPstates
2881 NBPtr->NbFreqChgState++;
2883 // Return TRUE to repeat MaxRdLat training
2886 // If transition to any NBPs fails, transition to exit state machine
2887 NBPtr->NbFreqChgState = 4;
2892 // Change NB P-State back to NBP0
2893 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2896 // Return FALSE to get out of MaxRdLat training loop
2899 // Exit state machine
2900 NBPtr->NbFreqChgState = 5;
2911 /* -----------------------------------------------------------------------------*/
2915 * This function gets "Dram Term" value from data structure
2917 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2918 * @param[in] ChipSel - Targeted chipsel
2920 * @return Dram Term value
2924 IN OUT MEM_NB_BLOCK *NBPtr,
2930 if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT16) (1 << (ChipSel >> 1)))) != 0) {
2931 DramTerm = NBPtr->PsPtr->QR_DramTerm;
2933 DramTerm = NBPtr->PsPtr->DramTerm;
2939 /* -----------------------------------------------------------------------------*/
2943 * This function gets "Dram Term" value from data structure for Unb
2945 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2946 * @param[in] ChipSel - Targeted chipsel
2948 * @return Dram Term value
2951 MemNGetDramTermTblDrvNb (
2952 IN OUT MEM_NB_BLOCK *NBPtr,
2957 RttNom = NBPtr->PsPtr->RttNom[ChipSel];
2958 IDS_OPTION_HOOK (IDS_MEM_DRAM_TERM, &RttNom, &NBPtr->MemPtr->StdHeader);
2962 /* -----------------------------------------------------------------------------*/
2966 * This function gets "Dynamic Dram Term" value from data structure
2968 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2969 * @param[in] ChipSel - Targeted chipsel
2971 * @return Dynamic Dram Term value
2974 MemNGetDynDramTermNb (
2975 IN OUT MEM_NB_BLOCK *NBPtr,
2979 return (NBPtr->PsPtr->DynamicDramTerm);
2982 /* -----------------------------------------------------------------------------*/
2986 * This function gets "Dynamic Dram Term" value from data structure
2988 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2989 * @param[in] ChipSel - Targeted chipsel
2991 * @return Dynamic Dram Term value
2994 MemNGetDynDramTermTblDrvNb (
2995 IN OUT MEM_NB_BLOCK *NBPtr,
3000 RttWr = NBPtr->PsPtr->RttWr[ChipSel];
3001 IDS_OPTION_HOOK (IDS_MEM_DYN_DRAM_TERM, &RttWr, &NBPtr->MemPtr->StdHeader);
3005 /* -----------------------------------------------------------------------------*/
3009 * This function returns MR0[CL] value
3011 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3013 * @return MR0[CL] value
3017 IN OUT MEM_NB_BLOCK *NBPtr
3023 Tcl = (UINT8) MemNGetBitFieldNb (NBPtr, BFTcl);
3024 Value32 = (UINT32) ((Tcl < 8) ? (Tcl << 4) : (((Tcl - 8) << 4) | 4));
3029 /* -----------------------------------------------------------------------------*/
3033 * This function returns MR0[WR] value
3035 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3037 * @return MR0[WR] value
3041 IN OUT MEM_NB_BLOCK *NBPtr
3046 Value32 = MemNGetBitFieldNb (NBPtr, BFTwrDDR3) << 9;
3051 /* -----------------------------------------------------------------------------*/
3055 * This function returns MR0[WR] value
3057 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3059 * @return MR0[WR] value
3062 MemNGetMR0WRTblDrvNb (
3063 IN OUT MEM_NB_BLOCK *NBPtr
3066 return (UINT32) (NBPtr->PsPtr->MR0WR << 9);
3069 /* -----------------------------------------------------------------------------*/
3073 * This function returns MR2[CWL] value
3075 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3077 * @return MR0[CWL] value
3081 IN OUT MEM_NB_BLOCK *NBPtr
3086 Value32 = MemNGetBitFieldNb (NBPtr, BFTcwl) << 3;
3091 /* -----------------------------------------------------------------------------*/
3094 * This function returns MR2[CWL] value for UNB
3096 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3098 * @return MR0[CWL] value
3102 IN OUT MEM_NB_BLOCK *NBPtr
3107 Value32 = (MemNGetBitFieldNb (NBPtr, BFTcwl) - 5) << 3;
3112 /* -----------------------------------------------------------------------------*/
3115 * This function sets Txp and Txpdll
3117 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3123 IN OUT MEM_NB_BLOCK *NBPtr
3126 CONST UINT8 Txp[] = {0xFF, 0xFF, 3, 3, 4, 4, 5, 6, 7};
3127 CONST UINT8 Txpdll[] = {0xFF, 0xFF, 0xA, 0xA, 0xD, 0x10, 0x14, 0x17, 0x1A};
3133 Speed = NBPtr->DCTPtr->Timings.Speed;
3134 i = (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
3135 ASSERT (i < sizeof (Txp));
3136 ASSERT (i < sizeof (Txpdll));
3138 TxpdllVal = Txpdll[i];
3140 if ((NBPtr->MCTPtr->Status[SbLrdimms] || NBPtr->MCTPtr->Status[SbRegistered]) &&
3141 ((NBPtr->DCTPtr->Timings.Speed == DDR667_FREQUENCY) || (NBPtr->DCTPtr->Timings.Speed == DDR800_FREQUENCY)) &&
3142 (NBPtr->RefPtr->DDR3Voltage == VOLT1_25)) {
3148 if (TxpVal != 0xFF) {
3149 MemNSetBitFieldNb (NBPtr, BFTxp, TxpVal);
3151 if (TxpdllVal != 0xFF) {
3152 NBPtr->FamilySpecificHook[AdjustTxpdll] (NBPtr, &TxpdllVal);
3153 MemNSetBitFieldNb (NBPtr, BFTxpdll, TxpdllVal);
3157 /*-----------------------------------------------------------------------------
3160 * This function adjust value of Txpdll to encoded value.
3162 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3163 * @param[in,out] OptParam - Optional parameter
3166 * ----------------------------------------------------------------------------
3169 MemNAdjustTxpdllClientNb (
3170 IN OUT MEM_NB_BLOCK *NBPtr,
3171 IN OUT VOID *OptParam
3174 *(UINT8 *) OptParam -= 10;
3178 /* -----------------------------------------------------------------------------*/
3181 * This function is a wrapper to handle or switch NB Pstate for UNB
3183 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3184 * @param[in] *NBPstate - NB Pstate
3186 * @return TRUE - Succeed
3187 * @return FALSE - Fail
3191 MemNChangeNbFrequencyWrapUnb (
3192 IN OUT MEM_NB_BLOCK *NBPtr,
3197 UINT32 FreqNumeratorInMHz;
3200 UINT8 NbPstateMaxVal;
3201 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
3203 if (NBPtr->NbFreqChgState == 0) {
3204 // While in state 0, keep NB Pstate at the highest supported
3206 if (NBPtr->NbPsCtlReg == 0) {
3207 // Save NbPsCtl register on the first run
3208 NBPtr->NbPsCtlReg = MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg);
3210 // Do not need to switch NB Pstate again if it is already at highest
3213 } else if (NBPtr->NbFreqChgState < 4) {
3214 // While in other states, go to the next lower NB Pstate
3215 TargetNbPs = (UINT8) MemNGetBitFieldNb (NBPtr, BFCurNbPstate) + 1;
3217 // When done with training, release NB Pstate force by restoring NbPsCtl register
3218 NBPtr->FamilySpecificHook[ReleaseNbPstate] (NBPtr, NBPtr);
3219 IDS_HDT_CONSOLE (MEM_FLOW, "\tRelease NB Pstate force\n");
3223 // Make sure target NB Pstate is enabled, else find next enabled NB Pstate
3224 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &NBPtr->MemPtr->StdHeader);
3225 for (; TargetNbPs < 4; TargetNbPs++) {
3226 if (FamilySpecificServices->GetNbPstateInfo (FamilySpecificServices,
3227 NBPtr->MemPtr->PlatFormConfig,
3229 (UINT32) TargetNbPs,
3230 &FreqNumeratorInMHz,
3233 &(NBPtr->MemPtr->StdHeader))) {
3234 // Record NCLK speed
3235 NBPtr->NBClkFreq = FreqNumeratorInMHz / FreqDivisor;
3240 if (TargetNbPs < 4) {
3241 IDS_HDT_CONSOLE (MEM_FLOW, "\tNB P%d: %dMHz\n", TargetNbPs, NBPtr->NBClkFreq);
3243 // 1.Program the configuration registers which contain multiple internal copies for each NB P-state. See
3244 // D18F1x10C[NbPsSel].
3245 MemNSetBitFieldNb (NBPtr, BFNbPsSel, TargetNbPs);
3247 // Check to see if NB P-states have been disabled. @todo This should only be needed for
3248 // bring up, but must be included in any releases that occur before NB P-state operation
3249 // has been debugged/fixed.
3250 if ((NBPtr->NbPsCtlReg & 0x00000003) != 0) {
3251 // Set up RdPtrInit before transit to target NBPstate
3252 if (TargetNbPs > 0) {
3253 NBPtr->ProgramNbPsDependentRegs (NBPtr);
3255 // 2.Program D18F5x170 to transition the NB P-state:
3256 // NbPstateLo = NbPstateMaxVal. (HW requires an intermediate transition to low)
3257 // SwNbPstateLoDis = NbPstateDisOnP0 = NbPstateThreshold = 0.
3258 NbPstateMaxVal = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPstateMaxVal);
3259 MemNSetBitFieldNb (NBPtr, BFNbPstateLo, NbPstateMaxVal);
3260 MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFF91FF);
3262 // 3.Wait for D18F5x174[CurNbPstate] to equal NbPstateLo.
3263 MemNPollBitFieldNb (NBPtr, BFCurNbPstate, NbPstateMaxVal, PCI_ACCESS_TIMEOUT, TRUE);
3265 // 4.Program D18F5x170 to force the NB P-state:
3266 // NbPstateHi = target NB P-state.
3267 // SwNbPstateLoDis = 1 (triggers the transition)
3268 MemNSetBitFieldNb (NBPtr, BFNbPstateHi, TargetNbPs);
3269 MemNSetBitFieldNb (NBPtr, BFSwNbPstateLoDis, 1);
3271 // 5.Wait for D18F5x174[CurNbPstate] to equal the target NB P-state.
3272 MemNPollBitFieldNb (NBPtr, BFCurNbPstate, TargetNbPs, PCI_ACCESS_TIMEOUT, TRUE);
3275 // When NB frequency change succeeds, TSC rate may have changed.
3276 // We need to update TSC rate
3277 FamilySpecificServices->GetTscRate (FamilySpecificServices, &NBPtr->MemPtr->TscRate, &NBPtr->MemPtr->StdHeader);
3279 // Cannot find a supported NB Pstate to switch to
3280 // Release NB Pstate force by restoring NbPsCtl register
3281 NBPtr->FamilySpecificHook[ReleaseNbPstate] (NBPtr, NBPtr);
3282 IDS_HDT_CONSOLE (MEM_FLOW, "\tRelease NB Pstate force\n");
3288 /* -----------------------------------------------------------------------------*/
3292 * This function sends an MRS command for Unb
3294 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3300 IN OUT MEM_NB_BLOCK *NBPtr
3303 MemNSetASRSRTNb (NBPtr);
3304 MemNSwapBitsUnb (NBPtr);
3306 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d MR%d %05x\n",
3307 (MemNGetBitFieldNb (NBPtr, BFMrsChipSel) & 0x7),
3308 (MemNGetBitFieldNb (NBPtr, BFMrsBank) & 0x7),
3309 (MemNGetBitFieldNb (NBPtr, BFMrsAddress) & 0x3FFFF));
3311 // 1.Set SendMrsCmd=1
3312 MemNSetBitFieldNb (NBPtr, BFSendMrsCmd, 1);
3314 // 2.Wait for SendMrsCmd=0
3315 MemNPollBitFieldNb (NBPtr, BFSendMrsCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
3318 /* -----------------------------------------------------------------------------*/
3322 * This function returns MR0[CL] value with table driven support
3324 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3326 * @return MR0[CL] value
3329 MemNGetMR0CLTblDrvNb (
3330 IN OUT MEM_NB_BLOCK *NBPtr
3333 return (UINT32) ((NBPtr->PsPtr->MR0CL31 << 4) | (NBPtr->PsPtr->MR0CL0 << 2));
3336 /* -----------------------------------------------------------------------------*/
3340 * This function performs MaxRdLat training for slot 1
3342 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3343 * @param[in,out] TestAddrRJ16 - Test address
3346 * ----------------------------------------------------------------------------
3349 MemNSlot1MaxRdLatTrainClientNb (
3350 IN OUT MEM_NB_BLOCK *NBPtr,
3351 IN OUT VOID *TestAddrRJ16
3354 UINT8 DummyBuffer[8];
3358 // Perform slot1 specific training:
3359 // A.Program D18F2x[1,0]78[SlotSel]=1. Force read CAS to fifo slot1 for training.
3360 // B.Program D18F2x[1,0]78[MaxRdLatency] = TrainedMaxRdLatency. Set to last slot0 value that passed.
3361 // C.Read the DIMM test addresses.
3362 // D.Compare the values read against the pattern written.
3364 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tTrain Slot 1: \n");
3365 MemNSetBitFieldNb (NBPtr, BFSlotSel, 1);
3367 MaxLatDly = (UINT16) (MemNGetBitFieldNb (NBPtr, BFMaxLatency) + 1); // Add 1 to get back to the last passing value
3368 MemNSetBitFieldNb (NBPtr, BFMaxLatency, MaxLatDly);
3370 for (i = 0; i < 100; i++) {
3371 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDly %3x", MaxLatDly);
3373 NBPtr->ReadPattern (NBPtr, DummyBuffer, *(UINT32*)TestAddrRJ16, 6);
3375 if (NBPtr->CompareTestPattern (NBPtr, DummyBuffer, DummyBuffer, 6 * 64) == 0xFFFF) {
3376 IDS_HDT_CONSOLE (MEM_FLOW, " P");
3379 IDS_HDT_CONSOLE (MEM_FLOW, "\n");
3383 MemNSetBitFieldNb (NBPtr, BFSlot1ExtraClkEn, 0);
3385 MemNSetBitFieldNb (NBPtr, BFSlot1ExtraClkEn, 1);
3388 MemNSetBitFieldNb (NBPtr, BFMaxSkipErrTrain, 0);
3394 /* -----------------------------------------------------------------------------*/
3398 * This function programs dram power management timing related registers
3400 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
3403 * ----------------------------------------------------------------------------
3406 MemNDramPowerMngTimingNb (
3407 IN OUT MEM_NB_BLOCK *NBPtr
3410 STATIC CONST UINT8 Tckesr[] = {4, 4, 5, 5, 6, 7, 2, 2};
3413 // These timings are based on DDR3 spec
3414 // Tcksrx = max(5 nCK, 10 ns)
3415 Tck = (UINT8) MAX (5, (MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 10)));
3416 MemNSetBitFieldNb (NBPtr, BFTcksrx, MIN (0xE, MAX (Tck, 2)));
3418 // Tcksre = max(5 nCK, 10 ns)
3419 MemNSetBitFieldNb (NBPtr, BFTcksre, MIN (0x27, MAX (Tck, 5)));
3421 // Tckesr = tCKE(min) + 1 nCK
3423 // DDR-800 7,5ns = 3nCk max(3nCK, 7.5ns) + 1 = 3nCK + 1nCK = 4nCK
3424 // DDR-1066 5.625ns = 3nCK max(3nCK, 5.625ns) + 1 = 3nCL + 1nCK = 4nCK
3425 // DDR-1333 5.625ns = 4nCK max(3nCK, 4nCK) + 1 = 4nCK + 1nCK = 5nCK
3426 // DDR-1600 5ns = 4nCK max(3nCK, 4nCK) + 1 = 4nCK + 1nCK = 5nCK
3427 // DDR-1866 5ns = 5nCK max(3nCK, 5nCK) + 1 = 5nCK + 1nCK = 6nCK
3428 // DDR-2133 5ns = 6nCK max(3nCK, 6nCK) + 1 = 6nCK + 1nCK = 7nCK
3429 MemNSetBitFieldNb (NBPtr, BFTckesr, Tckesr[(NBPtr->DCTPtr->Timings.Speed / 133) - 3]);
3432 MemNSetBitFieldNb (NBPtr, BFTpd, Tckesr[(NBPtr->DCTPtr->Timings.Speed / 133) - 3] - 1);
3435 /* -----------------------------------------------------------------------------*/
3438 * The function resets Rcv Fifo
3440 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
3441 * @param[in] Dummy - Dummy parameter
3446 MemTResetRcvFifoUnb (
3447 IN OUT struct _MEM_TECH_BLOCK *TechPtr,
3451 // Program D18F2x9C_x0000_0050_dct[1:0]=00000000h
3452 MemNSetBitFieldNb (TechPtr->NBPtr, BFRstRcvFifo, 0);