7 * Common Northbridge DCT support
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/NB)
12 * @e \$Revision: 38442 $ @e \$Date: 2010-09-24 06:39:57 +0800 (Fri, 24 Sep 2010) $
16 *****************************************************************************
18 * Copyright (c) 2011, Advanced Micro Devices, Inc.
19 * All rights reserved.
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
30 * from this software without specific prior written permission.
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 * ***************************************************************************
49 *----------------------------------------------------------------------------
52 *----------------------------------------------------------------------------
67 #include "OptionMemory.h"
68 #include "PlatformMemoryConfiguration.h"
71 RDATA_GROUP (G1_PEICC)
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));
307 if (MemClkDisMap == NULL) {
308 MemClkDisMap = NBPtr->ChannelPtr->MemClkDisMap;
311 // Turn off the unused CS clocks
312 CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
314 if (NBPtr->IsSupported[CheckMemClkCSPresent]) {
315 if (NBPtr->ChannelPtr->RegDimmPresent != 0) {
316 // All DDR3 RDIMM use only one MEMCLOCK from edge finger to the register
317 // regardless of how many Ranks are on the DIMM (Single, Dual or Quad)
318 CsPresent = (CsPresent | (CsPresent >> 1)) & 0x5555;
321 for (i = 0; i < 8; i++) {
322 if ((CsPresent & MemClkDisMap[i]) == 0) {
323 MemClkDis |= (UINT8) (1 << i);
327 for (RegIndex = 0; RegIndex < GET_SIZE_OF (ChipletPDRegs); RegIndex++) {
328 if ((NBPtr->Dct == 1) && (RegIndex >= 2)) {
329 Cs1 = MemClkDisMap[ChipletPDClkDisMap[RegIndex + 2][0]];
330 Cs2 = MemClkDisMap[ChipletPDClkDisMap[RegIndex + 2][1]];
332 Cs1 = MemClkDisMap[ChipletPDClkDisMap[RegIndex][0]];
333 Cs2 = MemClkDisMap[ChipletPDClkDisMap[RegIndex][1]];
335 if ((CsPresent & (UINT16) (Cs1 | Cs2)) == 0) {
336 MemNSetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex], (MemNGetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex]) | 0x10));
341 MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
343 AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
344 NBPtr->MemNInitPhyComp (NBPtr);
346 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
348 // Program DramTerm for DDR2
349 if ((MemNGetBitFieldNb (NBPtr, BFDdr3Mode)) == 0) {
350 MemNSetBitFieldNb (NBPtr, BFDramTerm, NBPtr->PsPtr->DramTerm);
352 // Dynamic Dynamic DramTerm for DDR3
353 // Dram Term for DDR3 may vary based on chip selects
354 MemNSetBitFieldNb (NBPtr, BFDramTermDyn, NBPtr->PsPtr->DynamicDramTerm);
357 MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
359 return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
362 /* -----------------------------------------------------------------------------*/
366 * This function gets platform specific config/timing values from the interface layer and
367 * programs them into DCT.
370 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
372 * @return TRUE - An Error value lower than AGESA_FATAL may have occurred
373 * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
377 MemNPlatformSpecUnb (
378 IN OUT MEM_NB_BLOCK *NBPtr
383 UINT8 MemoryAllClocks;
387 if (!MemNGetPlatformCfgNb (NBPtr)) {
391 if (!NBPtr->PsPtr->MemPDoPs (NBPtr)) {
392 IDS_HDT_CONSOLE (MEM_FLOW, "\tDisable DCT%d due to unsupported DIMM configuration\n", NBPtr->Dct);
393 NBPtr->MemPtr->ErrorHandling (NBPtr->MCTPtr, NBPtr->Dct, EXCLUDE_ALL_CHIPSEL, &NBPtr->MemPtr->StdHeader);
394 NBPtr->DisableDCT (NBPtr);
397 MemNProgramPlatformSpecNb (NBPtr);
398 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODT, ALL_DIMMS);
400 //======================================================================
401 // Disable unused MemClk to save power
402 //======================================================================
405 MemoryAllClocks = UserOptions.CfgMemoryAllClocksOn;
406 IDS_OPTION_HOOK (IDS_ALL_MEMORY_CLOCK, &MemoryAllClocks, &(NBPtr->MemPtr->StdHeader));
407 if (!MemoryAllClocks) {
408 // Special Jedec SPD diagnostic bit - "enable all clocks"
409 if (!NBPtr->MCTPtr->Status[SbDiagClks]) {
410 MemClkDisMap = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MEMCLK_DIS, NBPtr->MCTPtr->SocketId, NBPtr->Dct);
411 if (MemClkDisMap == NULL) {
412 MemClkDisMap = NBPtr->ChannelPtr->MemClkDisMap;
415 // Turn off unused clocks
416 CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
418 for (i = 0; i < 8; i++) {
419 if ((CsPresent & MemClkDisMap[i]) == 0) {
420 MemClkDis |= (UINT8) (1 << i);
424 // Turn off unused chiplets
425 for (i = 0; i < 3; i++) {
426 if (((MemClkDis >> (i * 2)) & 0x3) == 0x3) {
427 MemNSetBitFieldNb (NBPtr, BFPhyClkConfig0 + i, 0x0010);
432 MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
433 MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
436 return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
439 /* -----------------------------------------------------------------------------*/
443 * This function disables the DCT and mem clock
446 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
452 IN OUT MEM_NB_BLOCK *NBPtr
455 MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
456 MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
457 MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
459 // To maximize power savings when DisDramInterface=1b,
460 // all of the MemClkDis bits should also be set.
462 MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
463 MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
466 /* -----------------------------------------------------------------------------*/
470 * This function disables the DCT and mem clock for client NB
473 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
478 MemNDisableDCTClientNb (
479 IN OUT MEM_NB_BLOCK *NBPtr
482 MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
483 MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
484 MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
486 //Wait for 24 MEMCLKs
487 MemNWaitXMemClksNb (NBPtr, 24);
489 // To maximize power savings when DisDramInterface=1b,
490 // all of the MemClkDis bits should also be set.
492 MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
494 MemNSetBitFieldNb (NBPtr, BFDramPhyStatusReg, 0x80800000);
496 MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
499 /* -----------------------------------------------------------------------------*/
503 * This function initializes the DRAM devices on all DCTs at the same time
505 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
511 IN OUT MEM_NB_BLOCK *NBPtr
514 // 1. Ensure F2x[1, 0]9C_x08[DisAutoComp] = 1.
515 // 2. BIOS waits 5 us for the disabling of the compensation engine to complete.
516 // DisAutoComp is still being set since InitPhyComp
518 if (NBPtr->MCTPtr->NodeMemSize != 0) {
519 // Init MemClk frequency
520 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
523 AGESA_TESTPOINT (TpProcMemBeforeDramInit, &(NBPtr->MemPtr->StdHeader));
524 NBPtr->MemNBeforeDramInitNb (NBPtr);
525 IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq: %d MHz\n", NBPtr->DCTPtr->Timings.Speed);
526 AGESA_TESTPOINT (TpProcMemDramInit, &(NBPtr->MemPtr->StdHeader));
527 NBPtr->FeatPtr->DramInit (NBPtr->TechPtr);
530 // 7. Program F2x[1, 0]9C_x08[DisAutoComp] = 0.
531 // 8. BIOS must wait 750 us for the phy compensation engine
533 // DisAutoComp will be cleared after DramEnabled turns to 1
537 /* -----------------------------------------------------------------------------*/
541 * This function initializes the DRAM devices on all DCTs at the same time
543 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
549 IN OUT MEM_NB_BLOCK *NBPtr
554 if (NBPtr->MCTPtr->NodeMemSize != 0) {
555 // Update NB frequency for startup DDR speed
556 NBPtr->ChangeNbFrequency (NBPtr);
558 // Program D18F2x[1,0]9C_x0000_000B = 80000000h. #109999.
559 MemNBrdcstSetNb (NBPtr, BFDramPhyStatusReg, 0x80000000);
561 // Program D18F2x[1,0]9C_x0D0F_E013[PllRegWaitTime] = 0118h. #194060.
562 MemNBrdcstSetNb (NBPtr, BFPllRegWaitTime, 0x118);
564 // Phy Voltage Level Programming
565 MemNPhyVoltageLevelNb (NBPtr);
567 // Run frequency change sequence
568 MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
569 MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
570 NBPtr->ProgramNbPsDependentRegs (NBPtr);
571 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
572 MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
573 NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &Dct);
574 MemNBrdcstSetNb (NBPtr, BFPllLockTime, 0x000F);
576 NBPtr->FamilySpecificHook[BeforePhyFenceTraining] (NBPtr, NBPtr);
578 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
579 MemNSwitchDCTNb (NBPtr, Dct);
580 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
581 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
583 // Phy fence programming
584 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
585 NBPtr->PhyFenceTraining (NBPtr);
587 // Phy compensation initialization
588 AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
589 NBPtr->MemNInitPhyComp (NBPtr);
590 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
594 AGESA_TESTPOINT (TpProcMemBeforeDramInit, &(NBPtr->MemPtr->StdHeader));
595 NBPtr->MemNBeforeDramInitNb (NBPtr);
597 AGESA_TESTPOINT (TpProcMemDramInit, &(NBPtr->MemPtr->StdHeader));
598 IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq: %d MHz\n", NBPtr->DCTPtr->Timings.Speed);
599 NBPtr->FeatPtr->DramInit (NBPtr->TechPtr);
603 /* -----------------------------------------------------------------------------*/
606 * MemNChangeFrequencyHy:
608 * This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
610 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
615 MemNChangeFrequencyNb (
616 IN OUT MEM_NB_BLOCK *NBPtr
619 MEM_TECH_BLOCK *TechPtr;
624 TechPtr = NBPtr->TechPtr;
625 if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
627 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
630 //Program F2x[1,0]90[EnterSelfRefresh]=1.
631 //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
632 MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
633 MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
635 //Program F2x9C_x08[DisAutoComp]=1
636 MemNSwitchDCTNb (NBPtr, 0);
637 MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 1);
639 //Program F2x[1, 0]94[MemClkFreqVal] = 0.
640 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
642 //Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency.
643 MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
645 IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
646 //Program F2x[1, 0]94[MemClkFreqVal] = 1.
647 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
649 //Wait until F2x[1, 0]94[FreqChgInProg]=0.
650 MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
652 if (NBPtr->IsSupported[CheckPhyFenceTraining]) {
653 //Perform Phy Fence retraining after frequency changed
654 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
655 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
656 MemNSwitchDCTNb (NBPtr, Dct);
657 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
658 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
659 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
660 MemNPhyFenceTrainingNb (NBPtr);
665 //Program F2x9C_x08[DisAutoComp]=0
666 MemNSwitchDCTNb (NBPtr, 0);
667 MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
669 //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
670 //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
671 MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
672 MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
674 if (NBPtr->MCTPtr->Status[SbRegistered]) {
675 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
676 MemNSwitchDCTNb (NBPtr, Dct);
677 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
678 TechPtr->FreqChgCtrlWrd (TechPtr);
683 //wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns
684 MemNWaitXMemClksNb (NBPtr, 500);
686 if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
688 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
691 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
692 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
693 MemNSwitchDCTNb (NBPtr, Dct);
694 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
696 //9.Configure the DCT to send initialization MR commands:
697 // BIOS must reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
698 // Program F2x[1, 0]7C similar to step #2 in Pass 1 above for the new Dimm values.
699 TechPtr->AutoCycTiming (TechPtr);
700 if (!MemNPlatformSpecNb (NBPtr)) {
704 for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
705 if (NBPtr->IsSupported[CheckGetMCTSysAddr]) {
706 if (MemNGetMCTSysAddrNb (NBPtr, ChipSel, &Dummy)) {
707 // if chip select present
708 TechPtr->SendAllMRCmds (TechPtr, ChipSel);
709 // NOTE: wait 512 clocks for DLL-relock
710 MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
713 if (NBPtr->IsSupported[CheckSendAllMRCmds]) {
714 if (MemNGetMCTSysAddrNb (NBPtr, ChipSel, &Dummy)) {
715 // if chip select present
716 TechPtr->SendAllMRCmds (TechPtr, ChipSel);
720 if ((NBPtr->DCTPtr->Timings.Speed == DDR1600_FREQUENCY) && (NBPtr->IsSupported[CheckDllSpeedUp])) {
721 MemNSetBitFieldNb (NBPtr, BFPhy0x0D080F11, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D080F11) | 0x2000));
722 MemNSetBitFieldNb (NBPtr, BFPhy0x0D080F10, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D080F10) | 0x2000));
723 MemNSetBitFieldNb (NBPtr, BFPhy0x0D088F30, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D088F30) | 0x2000));
724 MemNSetBitFieldNb (NBPtr, BFPhy0x0D08C030, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D08C030) | 0x2000));
726 MemNSetBitFieldNb (NBPtr, BFPhy0x0D082F30, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D082F30) | 0x2000));
728 // NOTE: wait 512 clocks for DLL-relock
729 MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us
733 // Re-enable phy compensation since it had been disabled during InitPhyComp
734 MemNSwitchDCTNb (NBPtr, 0);
735 MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
739 /* -----------------------------------------------------------------------------*/
742 * This function ramp up frequency the next level if it have not reached
743 * its TargetSpeed yet.
745 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
747 * @return TRUE - No fatal error occurs.
748 * @return FALSE - Fatal error occurs.
752 MemNRampUpFrequencyNb (
753 IN OUT MEM_NB_BLOCK *NBPtr
756 CONST UINT16 FreqList[] = {
771 MCTPtr = NBPtr->MCTPtr;
773 // Do not change frequency when it is already at TargetSpeed
774 if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
778 // Find the next supported frequency level
779 NewSpeed = NBPtr->DCTPtr->Timings.TargetSpeed;
780 for (i = 0; i < (GET_SIZE_OF (FreqList) - 1); i++) {
781 if (NBPtr->DCTPtr->Timings.Speed == FreqList[i]) {
782 NewSpeed = FreqList[i + 1];
786 ASSERT (i < (GET_SIZE_OF (FreqList) - 1));
787 ASSERT (NewSpeed <= NBPtr->DCTPtr->Timings.TargetSpeed);
789 // BIOS must program both DCTs to the same frequency.
790 IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq changed: %d MHz", NBPtr->DCTPtr->Timings.Speed);
791 for (Dct = 0; Dct < MCTPtr->DctCount; Dct++) {
792 NBPtr->SwitchDCT (NBPtr, Dct);
793 NBPtr->DCTPtr->Timings.Speed = NewSpeed;
795 IDS_HDT_CONSOLE (MEM_FLOW, " -> %d MHz", NewSpeed);
797 NBPtr->ChangeFrequency (NBPtr);
799 return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
802 /* -----------------------------------------------------------------------------*/
806 * This function uses calculated values from DCT.Timings structure to
807 * program its registers.
810 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
815 MemNProgramCycTimingsNb (
816 IN OUT MEM_NB_BLOCK *NBPtr
819 CONST CTENTRY TmgAdjTab[] = {
820 // BitField, Min, Max, Bias, Ratio_x2
821 {BFTcl, 4, 12, 4, 2},
822 {BFTrcd, 5, 12, 5, 2},
823 {BFTrp, 5, 12, 5, 2},
824 {BFTrtp, 4, 7, 4, 2},
825 {BFTras, 15, 30, 15, 2},
826 {BFTrc, 11, 42, 11, 2},
827 {BFTwrDDR3, 5, 12, 4, 2},
828 {BFTrrd, 4, 7, 4, 2},
829 {BFTwtr, 4, 7, 4, 2},
830 {BFFourActWindow, 16, 32, 14, 1}
838 BIT_FIELD_NAME BitField;
840 DCTPtr = NBPtr->DCTPtr;
842 //======================================================================
843 // Program turnaround timings to their max during DRAM init and training
844 //======================================================================
846 MemNSetBitFieldNb (NBPtr, BFNonSPD, 0x28FF);
848 MemNSetBitFieldNb (NBPtr, BFNonSPDHi, 0x2A);
850 //======================================================================
851 // Program DRAM Timing values
852 //======================================================================
854 MiniMaxTmg = &DCTPtr->Timings.CasL;
855 for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
856 BitField = TmgAdjTab[j].BitField;
858 if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
859 MiniMaxTmg[j] = TmgAdjTab[j].Min;
860 } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
861 MiniMaxTmg[j] = TmgAdjTab[j].Max;
864 Value8 = (UINT8) MiniMaxTmg[j];
866 if (BitField == BFTwrDDR3) {
867 Value8 = (Value8 == 10) ? 9 : (Value8 >= 11) ? 10 : Value8;
868 } else if (BitField == BFTrtp) {
869 Value8 = (DCTPtr->Timings.Speed <= DDR1066_FREQUENCY) ? 4 : (DCTPtr->Timings.Speed == DDR1333_FREQUENCY) ? 5 : 6;
872 Value8 = Value8 - TmgAdjTab[j].Bias;
873 Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
875 ASSERT ((BitField == BFTcl ) ? (Value8 <= 8) :
876 (BitField == BFTrcd) ? (Value8 <= 7) :
877 (BitField == BFTrp ) ? (Value8 <= 7) :
878 (BitField == BFTrtp) ? (Value8 <= 3) :
879 (BitField == BFTras) ? (Value8 <= 15) :
880 (BitField == BFTrc ) ? (Value8 <= 31) :
881 (BitField == BFTrrd) ? (Value8 <= 3) :
882 (BitField == BFTwtr) ? (Value8 <= 3) :
883 (BitField == BFTwrDDR3) ? ((Value8 >= 1) && (Value8 <= 6)) :
884 (BitField == BFFourActWindow) ? ((Value8 >= 1) && (Value8 <= 9)) : FALSE);
885 MemNSetBitFieldNb (NBPtr, BitField, Value8);
888 MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
889 for (j = 0; j < 4; j++) {
890 ASSERT (MiniMaxTrfc[j] <= 4);
891 MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
894 MemNSetBitFieldNb (NBPtr, BFTcwl, ((DCTPtr->Timings.Speed >= DDR800_FREQUENCY) ?
895 (NBPtr->GetMemClkFreqId (NBPtr, DCTPtr->Timings.Speed) - 3) : 0));
897 MemNSetBitFieldNb (NBPtr, BFTref, 2); // 7.8 us
899 //======================================================================
900 // DRAM MRS Register, set ODT
901 //======================================================================
903 // DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
904 MemNSetBitFieldNb (NBPtr, BFDrvImpCtrl, 1);
906 // burst length control
907 if (NBPtr->MCTPtr->Status[Sb128bitmode]) {
908 MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 2);
911 // ASR=1, auto self refresh; SRT=0
912 MemNSetBitFieldNb (NBPtr, BFASR, 1);
915 /* -----------------------------------------------------------------------------*/
919 * This function uses calculated values from DCT.Timings structure to
920 * program its registers.
923 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
928 MemNProgramCycTimingsClientNb (
929 IN OUT MEM_NB_BLOCK *NBPtr
932 CONST CTENTRY TmgAdjTab[] = {
933 // BitField, Min, Max, Bias, Ratio_x2
934 {BFTcl, 5, 14, 4, 2},
935 {BFTrcd, 5, 14, 5, 2},
936 {BFTrp, 5, 14, 5, 2},
937 {BFTrtp, 4, 8, 4, 2},
938 {BFTras, 15, 36, 15, 2},
939 {BFTrc, 20, 49, 11, 2},
940 {BFTwrDDR3, 5, 16, 4, 2},
941 {BFTrrd, 4, 8, 4, 2},
942 {BFTwtr, 4, 8, 4, 2},
943 {BFFourActWindow, 16, 40, 14, 1}
954 BIT_FIELD_NAME BitField;
956 DCTPtr = NBPtr->DCTPtr;
958 //======================================================================
959 // Program DRAM Timing values
960 //======================================================================
962 MiniMaxTmg = &DCTPtr->Timings.CasL;
963 for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
964 BitField = TmgAdjTab[j].BitField;
966 if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
967 MiniMaxTmg[j] = TmgAdjTab[j].Min;
968 } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
969 MiniMaxTmg[j] = TmgAdjTab[j].Max;
972 Value8 = (UINT8) MiniMaxTmg[j];
974 if (BitField == BFTwrDDR3) {
975 if (NBPtr->IsSupported[AdjustTwr]) {
978 Value8 = (Value8 >= 10) ? (((Value8 + 1) / 2) + 4) : Value8;
981 Value8 = Value8 - TmgAdjTab[j].Bias;
982 Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
984 ASSERT ((BitField == BFTcl ) ? ((Value8 >= 1) && (Value8 <= 10)) :
985 (BitField == BFTrcd) ? (Value8 <= 9) :
986 (BitField == BFTrp ) ? (Value8 <= 9) :
987 (BitField == BFTrtp) ? (Value8 <= 4) :
988 (BitField == BFTras) ? (Value8 <= 21) :
989 (BitField == BFTrc ) ? ((Value8 >= 9) && (Value8 <= 38)) :
990 (BitField == BFTrrd) ? (Value8 <= 4) :
991 (BitField == BFTwtr) ? (Value8 <= 4) :
992 (BitField == BFTwrDDR3) ? (Value8 <= 7) :
993 (BitField == BFFourActWindow) ? ((Value8 >= 1) && (Value8 <= 13)) : FALSE);
994 MemNSetBitFieldNb (NBPtr, BitField, Value8);
997 MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
998 for (j = 0; j < 4; j++) {
999 ASSERT (MiniMaxTrfc[j] <= 5);
1000 MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
1003 Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
1004 MemNSetBitFieldNb (NBPtr, BFTcwl, ((Tcwl > 5) ? (Tcwl - 5) : 0));
1006 MemNSetBitFieldNb (NBPtr, BFTref, 2); // Tref = 7.8 us
1008 // Skid buffer can only be programmed once before Dram init
1009 if (NBPtr->DCTPtr->Timings.Speed == DDR800_FREQUENCY) {
1010 TCK_ps = 1000500 / DCTPtr->Timings.TargetSpeed;
1011 Trcd = (UINT8) ((((1000 / 40) * (UINT32)DCTPtr->Timings.DIMMTrcd) + TCK_ps - 1) / TCK_ps);
1012 MemNSetBitFieldNb (NBPtr, BFDbeSkidBufDis, (Trcd > 10) ? 0 : 1);
1015 MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0);
1019 /* -----------------------------------------------------------------------------*/
1023 * This function gets platform specific settings for the current channel
1025 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1027 * @return TRUE - All platform types defined have initialized successfully
1028 * @return FALSE - At least one of the platform types gave not been initialized successfully
1032 MemNGetPlatformCfgNb (
1033 IN OUT MEM_NB_BLOCK *NBPtr
1038 for (p = 0; p < MAX_PLATFORM_TYPES; p++) {
1039 ASSERT (NBPtr->MemPtr->GetPlatformCfg[p] != NULL);
1040 if (NBPtr->MemPtr->GetPlatformCfg[p] (NBPtr->MemPtr, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr) == AGESA_SUCCESS) {
1044 return (p < MAX_PLATFORM_TYPES);
1047 /* -----------------------------------------------------------------------------*/
1051 * This function retrieves the Max latency parameters
1053 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1055 * @param[in] *MinDlyPtr - Pointer to variable to store the Minimum Delay value
1056 * @param[in] *MaxDlyPtr - Pointer to variable to store the Maximum Delay value
1057 * @param[in] *DlyBiasPtr - Pointer to variable to store Delay Bias value
1058 * @param[in] MaxRcvEnDly - Maximum receiver enable delay value
1062 MemNGetMaxLatParamsNb (
1063 IN OUT MEM_NB_BLOCK *NBPtr,
1064 IN UINT16 MaxRcvEnDly,
1065 IN OUT UINT16 *MinDlyPtr,
1066 IN OUT UINT16 *MaxDlyPtr,
1067 IN OUT UINT16 *DlyBiasPtr
1070 *MinDlyPtr = (MemNTotalSyncComponentsNb (NBPtr) + (MaxRcvEnDly >> 5)) * 2;
1071 MemNQuarterMemClk2NClkNb (NBPtr, MinDlyPtr);
1076 MemNQuarterMemClk2NClkNb (NBPtr, DlyBiasPtr); // 1 MEMCLK Margin
1078 *DlyBiasPtr += 1; // add 1 NCLK
1081 /* -----------------------------------------------------------------------------*/
1085 * This function sets the maximum round-trip latency in the system from the processor to the DRAM
1089 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1090 * @param[in] MaxRcvEnDly - Maximum receiver enable delay value
1095 MemNSetMaxLatencyNb (
1096 IN OUT MEM_NB_BLOCK *NBPtr,
1097 IN UINT16 MaxRcvEnDly
1102 AGESA_TESTPOINT (TpProcMemRcvrCalcLatency, &(NBPtr->MemPtr->StdHeader));
1104 SubTotal = 0xC8; // init value for MaxRdLat used in training
1107 if (MaxRcvEnDly != 0xFFFF) {
1108 // Get all sync components BKDG steps 1-5
1109 SubTotal = MemNTotalSyncComponentsNb (NBPtr);
1111 // Add the maximum (worst case) delay value of DqsRcvEnGrossDelay
1112 // that exists across all DIMMs and byte lanes.
1114 SubTotal += MaxRcvEnDly >> 5;
1117 // Add 14.5 to the sub-total. 14.5 represents part of the processor
1118 // specific constant delay value in the DRAM clock domain.
1120 SubTotal <<= 1; // scale 1/2 MemClk to 1/4 MemClk
1121 SubTotal += 29; // add 14.5 1/2 MemClk
1123 // Convert the sub-total (in 1/2 MEMCLKs) to northbridge clocks (NCLKs)
1124 // as follows (assuming DDR400 and assuming that no P-state or link speed
1125 // changes have occurred).
1127 MemNQuarterMemClk2NClkNb (NBPtr, &SubTotal);
1129 // Add 2 NCLKs to the sub-total. 2 represents part of the processor
1130 // specific constant value in the northbridge clock domain.
1135 NBPtr->DCTPtr->Timings.MaxRdLat = SubTotal;
1136 // Program the F2x[1, 0]78[MaxRdLatency] register with the total delay value
1137 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRdLat: %03x\n", SubTotal);
1138 MemNSetBitFieldNb (NBPtr, BFMaxLatency, SubTotal);
1141 /* -----------------------------------------------------------------------------*/
1145 * This function sends the ZQCL command
1147 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1153 IN OUT MEM_NB_BLOCK *NBPtr
1156 // 1.Program MrsAddress[10]=1
1157 MemNSetBitFieldNb (NBPtr, BFMrsAddress, (UINT32)1 << 10);
1159 // 2.Set SendZQCmd=1
1160 MemNSetBitFieldNb (NBPtr, BFSendZQCmd, 1);
1162 // 3.Wait for SendZQCmd=0
1163 MemNPollBitFieldNb (NBPtr, BFSendZQCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
1165 // 4.Wait 512 MEMCLKs
1166 MemNWaitXMemClksNb (NBPtr, 512);
1170 /*----------------------------------------------------------------------------
1173 *----------------------------------------------------------------------------
1176 /* -----------------------------------------------------------------------------*/
1180 * This function is used to create the DRAM map
1183 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1188 MemNAfterStitchMemNb (
1189 IN OUT MEM_NB_BLOCK *NBPtr
1192 if (NBPtr->MCTPtr->GangedMode) {
1193 NBPtr->MCTPtr->NodeMemSize = NBPtr->DCTPtr->Timings.DctMemSize;
1194 NBPtr->MCTPtr->NodeSysLimit = NBPtr->MCTPtr->NodeMemSize - 1;
1195 NBPtr->MCTPtr->DctData[1].Timings.CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
1196 NBPtr->MCTPtr->DctData[1].Timings.CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
1197 NBPtr->MCTPtr->DctData[1].Timings.DctMemSize = NBPtr->DCTPtr->Timings.DctMemSize;
1199 // In unganged mode, add DCT0 and DCT1 to NodeMemSize
1200 NBPtr->MCTPtr->NodeMemSize += NBPtr->DCTPtr->Timings.DctMemSize;
1201 NBPtr->MCTPtr->NodeSysLimit = NBPtr->MCTPtr->NodeMemSize - 1;
1206 /* -----------------------------------------------------------------------------*/
1210 * This function Return the binary value of tfaw associated with
1213 * @param[in] k value
1215 * @return F[k], in Binary MHz.
1223 CONST UINT8 Tab1KTfawTK[] = {0, 8, 10, 13, 14, 19};
1225 return Tab1KTfawTK[k];
1228 /* -----------------------------------------------------------------------------*/
1232 * This function Return the binary value of the 2KTFaw associated with
1235 * @param[in] k value
1237 * @return 2KTFaw converted based on k.
1245 CONST UINT8 Tab2KTfawTK[] = {0, 10, 14, 17, 18, 24};
1247 return Tab2KTfawTK[k];
1250 /* -----------------------------------------------------------------------------*/
1254 * This function converts the sub-total (in 1/4 MEMCLKs) to northbridge clocks (NCLKs)
1255 * (assuming DDR400 and assuming that no P-state or link speed
1256 * changes have occurred).
1259 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1260 * @param[in,out] *SubTotalPtr - pointer to Sub-Total
1265 MemNQuarterMemClk2NClkNb (
1266 IN OUT MEM_NB_BLOCK *NBPtr,
1267 IN OUT UINT16 *SubTotalPtr
1273 // Multiply SubTotal by NB COF
1274 NBFreq = (MemNGetBitFieldNb (NBPtr, BFNbFid) + 4) * 200;
1275 // Divide SubTotal by 4 times current MemClk frequency
1276 MemFreq = NBPtr->DCTPtr->Timings.Speed * 4;
1277 *SubTotalPtr = (UINT16) (((NBFreq * (*SubTotalPtr)) + MemFreq - 1) / MemFreq); // round up
1280 /* -----------------------------------------------------------------------------*/
1284 * This function gets the total of sync components for Max Read Latency calculation
1286 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1288 * @return Total in 1/2 MEMCLKs
1292 MemNTotalSyncComponentsNb (
1293 IN OUT MEM_NB_BLOCK *NBPtr
1298 // Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs UINTs.
1299 SubTotal = (UINT16) MemNGetBitFieldNb (NBPtr, BFTcl) + 1;
1300 if ((MemNGetBitFieldNb (NBPtr, BFDdr3Mode)) != 0) {
1305 // If registered DIMMs are being used then add 1 MEMCLK to the sub-total.
1306 if ((MemNGetBitFieldNb (NBPtr, BFUnBuffDimm)) == 0) {
1310 // 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
1311 // 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
1312 if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) {
1318 // If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
1319 // then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total.
1321 SubTotal = SubTotal + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit));
1326 /* -----------------------------------------------------------------------------*/
1330 * This function swaps bits for OnDimmMirror support
1332 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1338 IN OUT MEM_NB_BLOCK *NBPtr
1344 ChipSel = (UINT8) MemNGetBitFieldNb (NBPtr, BFMrsChipSel);
1345 if ((ChipSel & 1) != 0) {
1346 MRSReg = MemNGetBitFieldNb (NBPtr, BFDramInitRegReg);
1347 if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
1348 MRSReg = (MRSReg & 0xFFFCFE07) | ((MRSReg&0x100A8) << 1) | ((MRSReg&0x20150) >> 1);
1349 MemNSetBitFieldNb (NBPtr, BFDramInitRegReg, MRSReg);
1354 /* -----------------------------------------------------------------------------*/
1358 * This function swaps bits for OnDimmMirror support for Unb
1360 * Dimm Mirroring Requires that, during MRS command cycles, the following
1361 * bits are swapped by software
1364 * A4 -> A3 BA0 -> BA1
1365 * A5 -> A6 BA1 -> BA0
1368 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1374 IN OUT MEM_NB_BLOCK *NBPtr
1381 ChipSel = (UINT8) MemNGetBitFieldNb (NBPtr, BFMrsChipSel);
1382 if ((ChipSel & 1) != 0) {
1383 if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
1384 MRSBank = MemNGetBitFieldNb (NBPtr, BFMrsBank);
1385 MRSAddr = MemNGetBitFieldNb (NBPtr, BFMrsAddress);
1387 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d MR%d %05x swapped to ->",
1390 (MRSAddr & 0x3FFFF));
1392 // Swap Mrs Bank bits 0 with 1
1393 MRSBank = (MRSBank & 0x0100) | ((MRSBank & 0x01) << 1) | ((MRSBank & 0x02) >> 1);
1395 // Swap Mrs Address bits 3 with 4, 5 with 6, and 7 with 8
1396 MRSAddr = (MRSAddr & 0x03FE07) | ((MRSAddr&0x000A8) << 1) | ((MRSAddr&0x00150) >> 1);
1397 MemNSetBitFieldNb (NBPtr, BFMrsBank, MRSBank);
1398 MemNSetBitFieldNb (NBPtr, BFMrsAddress, MRSAddr);
1403 /* -----------------------------------------------------------------------------*/
1406 * Programs Address/command timings, driver strengths, and tri-state fields.
1408 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1412 MemNProgramPlatformSpecNb (
1413 IN OUT MEM_NB_BLOCK *NBPtr
1416 CONST UINT8 PinType[3] = {PSO_CKE_TRI, PSO_ODT_TRI, PSO_CS_TRI};
1417 CONST UINT8 TabSize[3] = { 2, 4, 8};
1418 CONST BIT_FIELD_NAME BitField[3] = { BFCKETri, BFODTTri, BFChipSelTri};
1423 //===================================================================
1424 // Tristate unused CKE, ODT and chip select to save power
1425 //===================================================================
1428 for (k = 0; k < sizeof (PinType); k++) {
1429 if (NBPtr->IsSupported[CheckFindPSOverideWithSocket]) {
1430 TabPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PinType[k], NBPtr->MCTPtr->SocketId, MemNGetSocketRelativeChannelNb (NBPtr, NBPtr->Dct, 0));
1432 if (NBPtr->IsSupported[CheckFindPSDct]) {
1433 TabPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PinType[k], NBPtr->MCTPtr->SocketId, NBPtr->Dct);
1435 if (TabPtr == NULL) {
1438 TabPtr = NBPtr->ChannelPtr->CKETriMap;
1441 TabPtr = NBPtr->ChannelPtr->ODTTriMap;
1444 TabPtr = NBPtr->ChannelPtr->ChipSelTriMap;
1450 ASSERT (TabPtr != NULL);
1453 for (i = 0; i < TabSize[k]; i++) {
1454 if ((NBPtr->DCTPtr->Timings.CsPresent & TabPtr[i]) == 0) {
1455 Value |= (UINT8) (1 << i);
1459 if (k == PSO_CS_TRI) {
1460 NBPtr->FamilySpecificHook[BeforeSetCsTri] (NBPtr, &Value);
1463 ASSERT (k < GET_SIZE_OF (BitField));
1464 MemNSetBitFieldNb (NBPtr, BitField[k], Value);
1466 NBPtr->MemNBeforePlatformSpecNb (NBPtr);
1468 //===================================================================
1469 // Program Address/Command timings and driver strength
1470 //===================================================================
1472 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ADDRTMG, ALL_DIMMS);
1473 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODCCONTROL, ALL_DIMMS);
1475 MemNSetBitFieldNb (NBPtr, BFSlowAccessMode, (NBPtr->ChannelPtr->SlowMode) ? 1 : 0);
1476 MemNSetBitFieldNb (NBPtr, BFODCControl, NBPtr->ChannelPtr->DctOdcCtl);
1477 MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, NBPtr->ChannelPtr->DctAddrTmg);
1478 NBPtr->FamilySpecificHook[SetDqsODT] (NBPtr, NBPtr);
1480 if (NBPtr->IsSupported[CheckODTControls]) {
1481 MemNSetBitFieldNb (NBPtr, BFPhyRODTCSLow, NBPtr->ChannelPtr->PhyRODTCSLow);
1482 MemNSetBitFieldNb (NBPtr, BFPhyRODTCSHigh, NBPtr->ChannelPtr->PhyRODTCSHigh);
1483 MemNSetBitFieldNb (NBPtr, BFPhyWODTCSLow, NBPtr->ChannelPtr->PhyWODTCSLow);
1484 MemNSetBitFieldNb (NBPtr, BFPhyWODTCSHigh, NBPtr->ChannelPtr->PhyWODTCSHigh);
1487 /* -----------------------------------------------------------------------------*/
1491 * This function gets the Trdrd value
1493 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1495 * @return Trdrd value
1500 IN OUT MEM_NB_BLOCK *NBPtr
1506 DCTPtr = NBPtr->DCTPtr;
1508 // BIOS calculates Trdrd (in MEMCLKs) = CGDD / 2 + 3 clocks and programs F2x[1, 0]8C[Trdrd] with the
1509 // converted field value. BIOS rounds fractional values down.
1510 // The Critical Gross Delay Difference (CGDD) for Trdrd on any given byte lane is the largest F2x[1,
1511 // 0]9C_x[3:0][2B:10][DqsRcvEnGrossDelay] delay of any DIMM minus the F2x[1,
1512 // 0]9C_x[3:0][2B:10][DqsRcvEnGrossDelay] delay of any other DIMM.
1514 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessRcvEnDly, AccessRcvEnDly);
1515 DCTPtr->Timings.Trdrd = (Cgdd / 2) + 3;
1517 // Transfer clk to reg definition, 2T is 00b, etc.
1518 DCTPtr->Timings.Trdrd -= 2;
1519 if (DCTPtr->Timings.Trdrd > 8) {
1520 DCTPtr->Timings.Trdrd = 8;
1523 return DCTPtr->Timings.Trdrd;
1527 /* -----------------------------------------------------------------------------*/
1531 * This function gets the Twrwr value
1533 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1535 * @return Twrwr value
1540 IN OUT MEM_NB_BLOCK *NBPtr
1546 DCTPtr = NBPtr->DCTPtr;
1548 // Twrwr (in MEMCLKs) = CGDD / 2 + 3 clocks and programs F2x[1, 0]8C[Twrwr] with the
1549 // converted field value. BIOS rounds fractional values down.
1550 // 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,
1551 // 0]3[WrDatGrossDlyByte] delay of any DIMM minus the F2x[1, 0]9C_x[3:0][A, 7, 6, 0][2:1]:F2x[1,
1552 // 0]9C_x[3:0][A, 7, 6, 0]3[WrDatGrossDlyByte] delay of any other DIMM is equal to the Critical Gross
1553 // Delay Difference (CGDD) for Twrwr.
1555 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessWrDatDly, AccessWrDatDly);
1556 DCTPtr->Timings.Twrwr = (Cgdd / 2) + 3;
1557 NBPtr->TechPtr->AdjustTwrwr (NBPtr->TechPtr);
1559 return DCTPtr->Timings.Twrwr;
1562 /* -----------------------------------------------------------------------------*/
1566 * This function gets the Twrrd value. BIOS calculates Twrrd (in MEMCLKs) = CGDD / 2 - LD + 3 clocks and programs
1567 * F2x[1, 0]8C[Twrrd] with the converted field value. BIOS rounds fractional
1570 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1572 * @return Value to be programmed to Twrrd field
1573 * pDCT->Timings.Twrrd updated
1578 IN OUT MEM_NB_BLOCK *NBPtr
1586 DCTPtr = NBPtr->DCTPtr;
1589 // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS
1590 // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive
1592 // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1594 Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1596 // On any given byte lane, the largest WrDatGrossDlyByte delay of any DIMM
1597 // minus the DqsRcvEnGrossDelay delay of any other DIMM is
1598 // equal to the Critical Gross Delay Difference (CGDD) for Twrrd.
1599 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessWrDatDly, AccessRcvEnDly);
1600 Twrrd = (Cgdd / 2) - Ld + 3;
1601 DCTPtr->Timings.Twrrd = (UINT8) ((Twrrd >= 0) ? Twrrd : 0);
1602 NBPtr->TechPtr->AdjustTwrrd (NBPtr->TechPtr);
1604 return DCTPtr->Timings.Twrrd;
1607 /* -----------------------------------------------------------------------------*/
1611 * This function gets the TrwtTO value
1613 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1615 * @return pDCT->Timings.TrwtTO updated
1620 IN OUT MEM_NB_BLOCK *NBPtr
1628 DCTPtr = NBPtr->DCTPtr;
1630 // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS
1631 // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive
1633 // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1635 Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1637 // On any byte lane, the largest DqsRcvEnGrossDelay delay of any DIMM minus
1638 // the WrDatGrossDlyByte delay of any other DIMM is equal to the Critical Gross
1639 // Delay Difference (CGDD) for TrwtTO.
1640 Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessRcvEnDly, AccessWrDatDly);
1641 TrwtTO = (Cgdd / 2) + Ld + 3;
1643 DCTPtr->Timings.TrwtTO = (UINT8) ((TrwtTO > 1) ? TrwtTO : 1);
1645 return DCTPtr->Timings.TrwtTO;
1648 /* -----------------------------------------------------------------------------*/
1652 * This function gets the TrwtWB value
1654 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1656 * @return TrwtWB value
1660 IN OUT MEM_NB_BLOCK *NBPtr
1665 DCTPtr = NBPtr->DCTPtr;
1667 // TrwtWB ensures read-to-write data-bus turnaround.
1668 // This value should be one more than the programmed TrwtTO.
1669 return DCTPtr->Timings.TrwtWB = DCTPtr->Timings.TrwtTO;
1672 /* -----------------------------------------------------------------------------*/
1676 * This function converts MemClk frequency in MHz to MemClkFreq value
1678 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1679 * @param[in] Speed - MemClk frequency in MHz
1681 * @return MemClkFreq value
1684 MemNGetMemClkFreqIdNb (
1685 IN OUT MEM_NB_BLOCK *NBPtr,
1689 return (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
1692 /* -----------------------------------------------------------------------------*/
1696 * This function enables swapping interleaved region feature.
1698 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1699 * @param[in] Base - Swap interleaved region base [47:27]
1700 * @param[in] Limit - Swap interleaved region limit [47:27]
1704 MemNEnableSwapIntlvRgnNb (
1705 IN OUT MEM_NB_BLOCK *NBPtr,
1713 // Swapped interleaving region must be below 16G
1714 if (Limit < (1 << (34 - 27))) {
1715 // Adjust Base and Size to meet :
1716 // 1. The size of the swapped region must be less than or equal to the alignment of F2x10C[IntLvRegionBase].
1717 // 2. Entire UMA region is swapped with interleaving region.
1718 Size = Limit - Base;
1719 SizeOfAlign = (UINT32) 1 << LibAmdBitScanForward (Base);
1720 while (SizeOfAlign <= Size) {
1721 // In case of SizeOfAlign <= Size, UmaBase -= 128MB, SizeOfIntlvrgn += 128MB.
1724 SizeOfAlign = (UINT32) 1 << LibAmdBitScanForward (Base);
1726 MemNSetBitFieldNb (NBPtr, BFIntLvRgnBaseAddr, Base);
1727 MemNSetBitFieldNb (NBPtr, BFIntLvRgnLmtAddr, (Limit - 1));
1728 MemNSetBitFieldNb (NBPtr, BFIntLvRgnSize, Size);
1729 MemNSetBitFieldNb (NBPtr, BFIntLvRgnSwapEn, 1);
1733 /* -----------------------------------------------------------------------------*/
1737 * This function converts MemClk frequency in MHz to MemClkFreq value
1739 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1740 * @param[in] Speed - MemClk frequency in MHz
1742 * @return MemClkFreq value
1745 MemNGetMemClkFreqIdClientNb (
1746 IN OUT MEM_NB_BLOCK *NBPtr,
1750 return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1753 /* -----------------------------------------------------------------------------*/
1757 * This function converts MemClk frequency in MHz to MemClkFreq value
1759 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1760 * @param[in] Speed - MemClk frequency in MHz
1762 * @return MemClkFreq value
1765 MemNGetMemClkFreqIdUnb (
1766 IN OUT MEM_NB_BLOCK *NBPtr,
1770 return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1773 /* -----------------------------------------------------------------------------*/
1777 * This function converts MemClkFreq Id value to MemClk frequency in MHz
1779 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1780 * @param[in] FreqId - FreqId from Register
1782 * @return MemClk frequency in MHz
1785 MemNGetMemClkFreqUnb (
1786 IN OUT MEM_NB_BLOCK *NBPtr,
1792 MemClkFreq = (FreqId == 14) ? 667 : (300 + ((FreqId - 3) * 33) + (FreqId - 3) / 3);
1793 } else if (FreqId == 2) {
1796 MemClkFreq = 50 + (50 * FreqId);
1801 /* -----------------------------------------------------------------------------*/
1804 * This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
1807 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1812 MemNChangeFrequencyUnb (
1813 IN OUT MEM_NB_BLOCK *NBPtr
1816 MEM_TECH_BLOCK *TechPtr;
1820 BOOLEAN FrequencyChangeSuccess;
1822 TechPtr = NBPtr->TechPtr;
1824 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
1826 //Program F2x[1,0]90[EnterSelfRefresh]=1.
1827 //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
1828 MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
1829 MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1831 if (NBPtr->ChangeNbFrequency (NBPtr)) {
1832 // Reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
1833 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1834 MemNSwitchDCTNb (NBPtr, Dct);
1835 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
1836 TechPtr->AutoCycTiming (TechPtr);
1837 if (!MemNPlatformSpecUnb (NBPtr)) {
1843 // 1. Program PllLockTime to Family-specific value
1844 MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
1846 // 2. Program D18F2x[1,0]94[MemClkFreqVal] = 0.
1847 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
1849 // 3. Program D18F2x[1,0]94[MemClkFreq] to the desired DRAM frequency.
1850 MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
1852 // 4. Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
1853 // 5. Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
1854 // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0]. See 2.10.3.2.2.1 [DCT Transmit Fifo Schedule
1855 // Delay Programming].
1856 // 6. D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
1857 // THEN 2 ELSE 3 ENDIF (Ontario)
1858 NBPtr->ProgramNbPsDependentRegs (NBPtr);
1860 IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
1861 // 7. Program D18F2x[1,0]94[MemClkFreqVal] = 1.
1862 MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
1863 MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
1864 NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &Dct);
1866 // 8. IF (D18F2x[1,0]9C_x0D0F_E00A[CsrPhySrPllPdMode]==0) THEN program
1867 // D18F2x[1,0]9C_x0D0F_E006[PllLockTime] = 0Fh.
1868 // (CsrPhySrPllPdMode is kept 0 before training)
1869 MemNBrdcstSetNb (NBPtr, BFPllLockTime, 0x000F);
1871 FrequencyChangeSuccess = TRUE;
1873 // If NB frequency cannot be updated, use the current speed as the target speed
1874 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1875 MemNSwitchDCTNb (NBPtr, Dct);
1876 NBPtr->DCTPtr->Timings.Speed = NBPtr->TechPtr->PrevSpeed;
1877 NBPtr->DCTPtr->Timings.TargetSpeed = NBPtr->TechPtr->PrevSpeed;
1879 FrequencyChangeSuccess = FALSE;
1882 //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
1883 //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
1884 MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
1885 MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
1886 MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
1888 if (FrequencyChangeSuccess) {
1889 NBPtr->FamilySpecificHook[AfterMemClkFreqChg] (NBPtr, NULL);
1891 // Perform Phy Fence training and Phy comp init after frequency change
1892 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1893 MemNSwitchDCTNb (NBPtr, Dct);
1894 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
1895 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
1897 // Phy fence programming
1898 AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
1899 NBPtr->PhyFenceTraining (NBPtr);
1901 // Phy compensation initialization
1902 AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
1903 NBPtr->MemNInitPhyComp (NBPtr);
1904 MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
1908 //======================================================================
1909 // Calculate and program DRAM Timings at new frequency
1910 //======================================================================
1912 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1913 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
1914 MemNSwitchDCTNb (NBPtr, Dct);
1915 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
1916 for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
1917 if (MemNGetMCTSysAddrNb (NBPtr, ChipSel, &Dummy)) {
1918 // if chip select present
1919 if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) {
1920 TechPtr->SendAllMRCmds (TechPtr, ChipSel);
1924 // Wait 512 clocks for DLL-relock
1925 MemNWaitXMemClksNb (NBPtr, 512);
1932 /* -----------------------------------------------------------------------------*/
1935 * This function calculates and programs NB P-state dependent registers
1937 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1942 MemNProgramNbPstateDependentRegistersUnb (
1943 IN OUT MEM_NB_BLOCK *NBPtr
1949 RdPtrInit = (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 6 : 5;
1950 MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit);
1951 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit);
1953 switch (RdPtrInit) {
1955 if (MemNGetBitFieldNb (NBPtr, BFNbPsSel) == 0) {
1956 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 2);
1958 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
1962 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
1965 MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 0);
1971 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1972 MemNSwitchDCTNb (NBPtr, Dct);
1973 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
1975 if (NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY) {
1976 MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0);
1978 MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000);
1983 NBPtr->FamilySpecificHook[OverrideDataTxFifoWrDly] (NBPtr, NBPtr);
1984 IDS_OPTION_HOOK (IDS_NBPS_REG_OVERRIDE, NBPtr, &NBPtr->MemPtr->StdHeader);
1987 /* -----------------------------------------------------------------------------*/
1988 CONST UINT8 PllDivTab[] = {0, 0, 0, 2, 3, 3, 2, 3};
1989 CONST UINT8 PllMultTab[] = {0, 0, 0, 16, 32, 40, 32, 56};
1993 * This function calculates and programs NB P-state dependent registers
1995 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2000 MemNProgramNbPstateDependentRegistersClientNb (
2001 IN OUT MEM_NB_BLOCK *NBPtr
2013 UINT32 MemClkPeriod;
2015 INT32 PartialSumSlotI2x;
2016 INT32 RdPtrInitRmdr2x;
2021 NclkFid = (UINT8) (MemNGetBitFieldNb (NBPtr, BFMainPllOpFreqId) + 0x10); // NclkFid is in 100MHz
2023 MemClkDid = PllDivTab[NBPtr->DCTPtr->Timings.Speed / 133];
2024 NBPtr->FamilySpecificHook[OverridePllDiv] (NBPtr, &MemClkDid);
2025 PllMult = PllMultTab[NBPtr->DCTPtr->Timings.Speed / 133];
2026 NBPtr->FamilySpecificHook[OverridePllMult] (NBPtr, &PllMult);
2028 if (NBPtr->NbFreqChgState == 2) {
2029 MemNSetBitFieldNb (NBPtr, BFNbPsCsrAccSel, 1);
2030 MemNSetBitFieldNb (NBPtr, BFNbPsDbgEn, 1);
2031 NclkDiv = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPs1NclkDiv);
2032 // Divisors less than 8 are undefined. Maybe the CPU does not support NB P-states.
2034 // Set a dummy divisor to prevent divide by zero exception below.
2039 NclkDiv = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPs0NclkDiv);
2042 NclkPeriod = (2500 * NclkDiv) / NclkFid; // (1,000,000 * 0.25 * NclkDiv) / (NclkFid * 100MHz) = ps
2043 MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
2044 NBPtr->NBClkFreq = ((UINT32) NclkFid * 400) / NclkDiv;
2046 IDS_HDT_CONSOLE (MEM_FLOW, "\n\tNB P%d Freq: %dMHz\n", NbPstate, NBPtr->NBClkFreq);
2047 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClk Freq: %dMHz\n", NBPtr->DCTPtr->Timings.Speed);
2048 // D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
2049 // THEN 2 ELSE 3 ENDIF (Ontario)
2050 RdPtrInit = RdPtrInitMin = (NBPtr->DCTPtr->Timings.Speed >= DDR1333_FREQUENCY) ? NBPtr->FreqChangeParam->RdPtrInit667orHigher : NBPtr->FreqChangeParam->RdPtrInitLower667;
2051 MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit);
2052 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit);
2054 // Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
2055 MemNBrdcstSetNb (NBPtr, BFDbeGskFifoNumerator, NclkFid * MemClkDid * 16);
2056 MemNBrdcstSetNb (NBPtr, BFDbeGskFifoDenominator, PllMult * NclkDiv);
2057 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDbeGskFifoNumerator: %d\n", NclkFid * MemClkDid * 16);
2058 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDbeGskFifoDenominator: %d\n", PllMult * NclkDiv);
2060 // Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
2061 // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0].
2062 // PartialSum = ((7 * NclkPeriod) + (1.5 * MemClkPeriod) + 520ps)*MemClkFrequency - tCWL -
2063 // CmdSetup - PtrSeparation - 1. (Llano)
2064 // PartialSum = ((5 * NclkPeriod) + MemClkPeriod) + 520ps)*MemClkFrequency - tCWL -
2065 // CmdSetup - PtrSeparation - 1. (Ontario)
2066 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2067 MemNSwitchDCTNb (NBPtr, Dct);
2068 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2069 PartialSum2x = NBPtr->FreqChangeParam->NclkPeriodMul2x * NclkPeriod;
2070 PartialSum2x += NBPtr->FreqChangeParam->MemClkPeriodMul2x * MemClkPeriod;
2071 PartialSum2x += 520 * 2;
2073 // PtrSeparation = ((16 + RdPtrInitMin - D18F2x[1,0]78[RdPtrInit]) MOD 16)/2 + RdPtrInitRmdr
2074 // If (D18F2x[1,0]94[MemClkFreq] >= 800 MHz)
2075 // then RdPtrInitRmdr = (((4.5 * MemClkPeriod) - 990ps) MOD MemClkPeriod)/MemClkPeriod
2076 // else RdPtrInitRmdr = (((4.5 * MemClkPeriod) - 1466ps) MOD MemClkPeriod)/MemClkPeriod
2077 TDataProp = (NBPtr->DCTPtr->Timings.Speed >= DDR1600_FREQUENCY) ?
2078 NBPtr->FreqChangeParam->TDataProp800orHigher : NBPtr->FreqChangeParam->TDataPropLower800;
2079 RdPtrInitRmdr2x = ((NBPtr->FreqChangeParam->SyncTimeMul4x * MemClkPeriod) / 2) - 2 * (TDataProp + 520);
2080 RdPtrInitRmdr2x %= MemClkPeriod;
2081 PartialSum2x -= ((16 + RdPtrInitMin - RdPtrInit) % 16) * MemClkPeriod + RdPtrInitRmdr2x;
2083 // Convert PartialSum2x to PCLK
2084 PartialSum2x = (PartialSum2x + MemClkPeriod - 1) / MemClkPeriod; // round-up here
2085 PartialSum2x -= 2 * (MemNGetBitFieldNb (NBPtr, BFTcwl) + 5);
2086 if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) {
2093 // If PartialSumSlotN is positive:
2094 // DataTxFifoSchedDlySlotN=CEIL(PartialSumSlotN).
2095 // DataTxFifoSchedDlyNegSlotN=0.
2096 // Else if PartialSumSlotN is negative:
2097 // DataTxFifoSchedDlySlotN=ABS(CEIL(PartialSumSlotN*MemClkPeriod/NclkPeriod)).
2098 // DataTxFifoSchedDlyNegSlotN=1.
2099 for (i = 0; i < 2; i++) {
2100 PartialSumSlotI2x = PartialSum2x;
2101 SlowMode = (UINT8) MemNGetBitFieldNb (NBPtr, BFSlowAccessMode);
2102 if ((i == 0) && (SlowMode == 0)) {
2103 PartialSumSlotI2x += 2;
2105 if (NBPtr->IsSupported[SchedDlySlot1Extra] && (i == 1) && (SlowMode != 0)) {
2106 PartialSumSlotI2x -= 2;
2108 if (PartialSumSlotI2x > 0) {
2109 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlyNegSlot0 + i, 0);
2110 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlySlot0 + i, (PartialSumSlotI2x + 1) / 2);
2111 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDataTxFifoSchedDlySlot%d: %d\n", i, (PartialSumSlotI2x + 1) / 2);
2113 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlyNegSlot0 + i, 1);
2114 PartialSumSlotI2x = ((-PartialSumSlotI2x) * MemClkPeriod) / (2 * NclkPeriod);
2115 MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlySlot0 + i, PartialSumSlotI2x);
2116 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDataTxFifoSchedDlySlot%d: -%d\n", i, PartialSumSlotI2x);
2121 if (NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY) {
2122 MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0);
2124 MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000);
2129 MemFInitTableDrive (NBPtr, MTAfterNbPstateChange);
2130 if (NBPtr->NbFreqChgState == 2) {
2131 MemNSetBitFieldNb (NBPtr, BFNbPsDbgEn, 0);
2132 MemNSetBitFieldNb (NBPtr, BFNbPsCsrAccSel, 0);
2136 /* -----------------------------------------------------------------------------*/
2140 * This function gets the total of sync components for Max Read Latency calculation
2142 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2144 * @return Total in ps
2148 MemNTotalSyncComponentsClientNb (
2149 IN OUT MEM_NB_BLOCK *NBPtr
2157 UINT8 DbeGskMemClkAlignMode;
2158 UINT32 MemClkPeriod;
2160 // P = P + ((16 + RdPtrInitMin - D18F2x[1,0]78[RdPtrInit]) MOD 16)
2161 RdPtrInitMin = (NBPtr->DCTPtr->Timings.Speed >= DDR1333_FREQUENCY) ? NBPtr->FreqChangeParam->RdPtrInit667orHigher : NBPtr->FreqChangeParam->RdPtrInitLower667;
2162 RdPtrInit = (UINT8) MemNGetBitFieldNb (NBPtr, BFRdPtrInit);
2163 P = (16 + RdPtrInitMin - RdPtrInit) % 16;
2165 // IF (AddrCmdSetup != CkeSetup) THEN P = P + 1
2166 AddrTmgCtl = MemNGetBitFieldNb (NBPtr, BFAddrTmgControl);
2167 if (((AddrTmgCtl >> 16) & 0x20) != (AddrTmgCtl & 0x20)) {
2171 // IF (DbeGskMemClkAlignMode==01b || (DbeGskMemClkAlignMode==00b && !(AddrCmdSetup==CsOdtSetup==CkeSetup)))
2173 DbeGskMemClkAlignMode = (UINT8) MemNGetBitFieldNb (NBPtr, BFDbeGskMemClkAlignMode);
2174 if ((DbeGskMemClkAlignMode == 1) || ((DbeGskMemClkAlignMode == 0) &&
2175 !((((AddrTmgCtl >> 16) & 0x20) == (AddrTmgCtl & 0x20)) && (((AddrTmgCtl >> 8) & 0x20) == (AddrTmgCtl & 0x20))))) {
2179 // IF (SlowAccessMode==1) THEN P = P + 2
2180 if (MemNGetBitFieldNb (NBPtr, BFSlowAccessMode) == 1) {
2188 // If (AddrCmdSetup==0 && CsOdtSetup==0 && CkeSetup==0)
2191 if ((AddrTmgCtl & 0x0202020) == 0) {
2197 // P = P + (2 * (D18F2x[1,0]88[Tcl] clocks - 1))
2198 P += 2 * (NBPtr->DCTPtr->Timings.CasL - 1);
2200 // If (DisCutThroughMode==0)
2203 if (MemNGetBitFieldNb (NBPtr, BFDisCutThroughMode) == 0) {
2209 MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
2210 return (((P * MemClkPeriod + 1) / 2) + T);
2213 /* -----------------------------------------------------------------------------*/
2217 * This function sets up phy power saving for client NB
2220 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2224 MemNPhyPowerSavingClientNb (
2225 IN OUT MEM_NB_BLOCK *NBPtr
2228 // 4. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[DllDisEarlyU] = 1b.
2229 // 5. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[DllDisEarlyL] = 1b.
2230 // 6. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[7:4] = 1010b.
2231 MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13Bit0to7, 0xA3);
2232 // 7. Program D18F2x[1,0]9C_x0D0F_812F[7, 5, 0] = {1b, 1b, 1b} to disable unused PAR and A[17:16] pins.
2233 MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 0xA1);
2234 // 8. Program D18F2x[1,0]9C_x0D0F_C000[LowPowerDrvStrengthEn] = 1.
2235 if (!NBPtr->FamilySpecificHook[DisLowPwrDrvStr] (NBPtr, NULL)) {
2236 MemNSetBitFieldNb (NBPtr, BFLowPowerDrvStrengthEn, 0x100);
2238 // 9. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]10[EnRxPadStandby]= IF (D18F2x[1,0]94[MemClkFreq] <=
2239 // 800 MHz) THEN 1 ELSE 0 ENDIF.
2240 MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 0x1000 : 0);
2241 // 10. Program D18F2x[1,0]9C_x0000_000D as follows:
2242 // TxMaxDurDllNoLock/RxMaxDurDllNoLock = 7h.
2243 MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 7);
2244 MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 7);
2245 // TxCPUpdPeriod/RxCPUpdPeriod = 011b.
2246 MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 3);
2247 MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 3);
2248 // TxDLLWakeupTime/RxDLLWakeupTime = 11b.
2249 MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 3);
2250 MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 3);
2252 IDS_OPTION_HOOK (IDS_PHY_DLL_STANDBY_CTRL, NBPtr, &NBPtr->MemPtr->StdHeader);
2255 /* -----------------------------------------------------------------------------*/
2259 * This function overrides the ASR and SRT value in MRS command
2261 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2266 IN OUT MEM_NB_BLOCK *NBPtr
2271 UINT8 *SpdBufferPtr;
2274 if (NBPtr->GetBitField (NBPtr, BFMrsBank) == 2) {
2275 MrsAddress = NBPtr->GetBitField (NBPtr, BFMrsAddress);
2276 // Clear A6(ASR) and A7(SRT)
2277 MrsAddress &= (UINT32) ~0xC0;
2278 Dimm = (UINT8) (NBPtr->GetBitField (NBPtr, BFMrsChipSel) >> 1);
2279 // Make sure we access SPD of the second logical dimm of QR dimm correctly
2280 if ((Dimm >= 2) && ((NBPtr->ChannelPtr->DimmQrPresent & (UINT8) (1 << Dimm)) != 0)) {
2283 if (NBPtr->TechPtr->GetDimmSpdBuffer (NBPtr->TechPtr, &SpdBufferPtr, Dimm)) {
2285 if (SpdBufferPtr[THERMAL_OPT] & 0x4) {
2286 // when ASR is 1, set SRT to 0
2289 // Set SRT based on bit on of thermal byte
2290 MrsAddress |= ((SpdBufferPtr[THERMAL_OPT] & 1) << 7);
2292 NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
2297 /* -----------------------------------------------------------------------------*/
2300 * This function changes NB frequency as below:
2301 * NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP0-DDRTarget
2303 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2308 MemNChangeNbFrequencyNb (
2309 IN OUT MEM_NB_BLOCK *NBPtr
2316 // State machine to change NB frequency and NB Pstate
2317 switch (NBPtr->NbFreqChgState) {
2319 // Starting up by not changing NB P state, but only updating NB frequency based on current MemClk frequency
2320 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2321 if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
2322 // When MemClk has been ramped up to its max, transition to next state, which changes NBPstate to P1
2323 NBPtr->NbFreqChgState = 1;
2324 IDS_OPTION_HOOK (IDS_NB_PSTATE_DIDVID, NBPtr, &(NBPtr->MemPtr->StdHeader));
2329 // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P0
2330 MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2332 // Next state would be to change NBPstate back to P0
2333 NBPtr->NbFreqChgState = 2;
2335 // Update NB freq dependent registers
2336 NBPtr->ProgramNbPsDependentRegs (NBPtr);
2338 // Change NB P-State to NBP1 for MaxRdLat training
2339 if (NBPtr->ChangeNbFrequencyWrap (NBPtr, 1)) {
2340 // Enable cut through mode for NB P1
2341 MemNBrdcstSetNb (NBPtr, BFDisCutThroughMode, 0);
2343 // Return TRUE to repeat MaxRdLat training
2347 // If transition to NB-P1 fails, transition to exit state machine
2348 NBPtr->NbFreqChgState = 3;
2353 // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P1
2354 MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2356 // Change NB P-State back to NBP0
2357 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2360 // Return FALSE to get out of MaxRdLat training loop
2363 // Exit state machine
2364 NBPtr->NbFreqChgState = 3;
2374 /*-----------------------------------------------------------------------------
2377 * This function programs registers before phy fence training for CNB
2379 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2380 * @param[in,out] OptParam - Optional parameter
2383 * ----------------------------------------------------------------------------
2386 MemNBeforePhyFenceTrainingClientNb (
2387 IN OUT MEM_NB_BLOCK *NBPtr,
2388 IN OUT VOID *OptParam
2391 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClkAlign=0\n");
2392 MemNBrdcstSetNb (NBPtr, BFDbeGskMemClkAlignMode, 0);
2394 IDS_HDT_CONSOLE (MEM_FLOW, "\tEnDramInit = 1 for both DCTs\n");
2395 MemNBrdcstSetNb (NBPtr, BFEnDramInit, 1);
2400 /* -----------------------------------------------------------------------------*/
2403 * This function changes NB frequency foras below:
2404 * NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP2-DDRTarget -> NBP3-DDRTarget -> NBP0-DDRTarget
2407 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2412 MemNChangeNbFrequencyUnb (
2413 IN OUT MEM_NB_BLOCK *NBPtr
2420 // State machine to change NB frequency and NB Pstate
2421 switch (NBPtr->NbFreqChgState) {
2423 // Starting up by not changing NB P state, but only updating NB frequency based on current MemClk frequency
2424 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2425 if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
2426 // When MemClk has been ramped up to its max, transition to next state, which changes NBPstate to P1
2427 NBPtr->NbFreqChgState = 1;
2428 IDS_OPTION_HOOK (IDS_NB_PSTATE_DIDVID, NBPtr, &(NBPtr->MemPtr->StdHeader));
2435 // Change NB P-State to NBP1 for MaxRdLat training
2436 if (NBPtr->ChangeNbFrequencyWrap (NBPtr, NBPtr->NbFreqChgState)) {
2437 NBPtr->ProgramNbPsDependentRegs (NBPtr);
2439 // Next state is to try all NBPstates
2440 NBPtr->NbFreqChgState++;
2442 // Return TRUE to repeat MaxRdLat training
2445 // If transition to any NBPs fails, transition to exit state machine
2446 NBPtr->NbFreqChgState = 4;
2451 // Change NB P-State back to NBP0
2452 Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2455 // Return FALSE to get out of MaxRdLat training loop
2458 // Exit state machine
2459 NBPtr->NbFreqChgState = 5;
2470 /* -----------------------------------------------------------------------------*/
2474 * This function gets "Dram Term" value from data structure
2476 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2477 * @param[in] ChipSel - Targeted chipsel
2479 * @return Dram Term value
2483 IN OUT MEM_NB_BLOCK *NBPtr,
2489 if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT16) (1 << (ChipSel >> 1)))) != 0) {
2490 DramTerm = NBPtr->PsPtr->QR_DramTerm;
2492 DramTerm = NBPtr->PsPtr->DramTerm;
2498 /* -----------------------------------------------------------------------------*/
2502 * This function gets "Dynamic Dram Term" value from data structure
2504 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2505 * @param[in] ChipSel - Targeted chipsel
2507 * @return Dynamic Dram Term value
2510 MemNGetDynDramTermNb (
2511 IN OUT MEM_NB_BLOCK *NBPtr,
2515 return (NBPtr->PsPtr->DynamicDramTerm);
2518 /* -----------------------------------------------------------------------------*/
2522 * This function returns MR0[CL] value
2524 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2526 * @return MR0[CL] value
2530 IN OUT MEM_NB_BLOCK *NBPtr
2536 Tcl = (UINT8) MemNGetBitFieldNb (NBPtr, BFTcl);
2537 Value32 = (UINT32) ((Tcl < 8) ? (Tcl << 4) : (((Tcl - 8) << 4) | 4));
2542 /* -----------------------------------------------------------------------------*/
2546 * This function returns MR0[WR] value
2548 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2550 * @return MR0[WR] value
2554 IN OUT MEM_NB_BLOCK *NBPtr
2559 Value32 = MemNGetBitFieldNb (NBPtr, BFTwrDDR3) << 9;
2564 /* -----------------------------------------------------------------------------*/
2568 * This function returns MR2[CWL] value
2570 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2572 * @return MR0[CWL] value
2576 IN OUT MEM_NB_BLOCK *NBPtr
2581 Value32 = MemNGetBitFieldNb (NBPtr, BFTcwl) << 3;
2586 /* -----------------------------------------------------------------------------*/
2590 * This function sets Txp and Txpdll
2592 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2598 IN OUT MEM_NB_BLOCK *NBPtr
2601 CONST UINT8 Txp[] = {0xFF, 0xFF, 3, 3, 4, 4, 5, 6, 7};
2602 CONST UINT8 Txpdll[] = {0xFF, 0xFF, 0xA, 0xA, 0xD, 0x10, 0x14, 0x17, 0x1A};
2608 Speed = NBPtr->DCTPtr->Timings.Speed;
2609 i = (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
2610 ASSERT (i < sizeof (Txp));
2611 ASSERT (i < sizeof (Txpdll));
2613 TxpdllVal = Txpdll[i];
2615 if ((NBPtr->MCTPtr->Status[SbLrdimms] || NBPtr->MCTPtr->Status[SbRegistered]) &&
2616 ((NBPtr->DCTPtr->Timings.Speed == DDR667_FREQUENCY) || (NBPtr->DCTPtr->Timings.Speed == DDR800_FREQUENCY)) &&
2617 (NBPtr->RefPtr->DDR3Voltage == VOLT1_25)) {
2623 if (TxpVal != 0xFF) {
2624 MemNSetBitFieldNb (NBPtr, BFTxp, TxpVal);
2626 if (TxpdllVal != 0xFF) {
2627 NBPtr->FamilySpecificHook[AdjustTxpdll] (NBPtr, &TxpdllVal);
2628 MemNSetBitFieldNb (NBPtr, BFTxpdll, TxpdllVal);
2632 /*-----------------------------------------------------------------------------
2635 * This function adjust value of Txpdll to encoded value.
2637 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2638 * @param[in,out] OptParam - Optional parameter
2641 * ----------------------------------------------------------------------------
2644 MemNAdjustTxpdllClientNb (
2645 IN OUT MEM_NB_BLOCK *NBPtr,
2646 IN OUT VOID *OptParam
2649 *(UINT8 *) OptParam -= 10;