32d6f2ce3ebbaf65bbb5b51a0b92a0359c3a5d5a
[coreboot.git] / src / vendorcode / amd / agesa / f14 / Proc / Mem / NB / mndct.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mndct.c
6  *
7  * Common Northbridge DCT support
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/NB)
12  * @e \$Revision: 38442 $ @e \$Date: 2010-09-24 06:39:57 +0800 (Fri, 24 Sep 2010) $
13  *
14  **/
15 /*
16  *****************************************************************************
17  *
18  * Copyright (c) 2011, Advanced Micro Devices, Inc.
19  * All rights reserved.
20  * 
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.
31  * 
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.
42  * 
43  * ***************************************************************************
44  *
45  */
46
47
48 /*
49  *----------------------------------------------------------------------------
50  *                                MODULES USED
51  *
52  *----------------------------------------------------------------------------
53  */
54
55
56
57 #include "AGESA.h"
58 #include "amdlib.h"
59 #include "Ids.h"
60 #include "mport.h"
61 #include "mm.h"
62 #include "mn.h"
63 #include "mt.h"
64 #include "mu.h"
65 #include "mftds.h"
66 #include "merrhdl.h"
67 #include "OptionMemory.h"
68 #include "PlatformMemoryConfiguration.h"
69 #include "Filecode.h"
70 CODE_GROUP (G1_PEICC)
71 RDATA_GROUP (G1_PEICC)
72
73 #define FILECODE PROC_MEM_NB_MNDCT_FILECODE
74 /*----------------------------------------------------------------------------
75  *                          DEFINITIONS AND MACROS
76  *
77  *----------------------------------------------------------------------------
78  */
79 #define UNUSED_CLK 4
80
81 /*----------------------------------------------------------------------------
82  *                           TYPEDEFS AND STRUCTURES
83  *
84  *----------------------------------------------------------------------------
85  */
86
87 /*----------------------------------------------------------------------------
88  *                        PROTOTYPES OF LOCAL FUNCTIONS
89  *
90  *----------------------------------------------------------------------------
91  */
92
93 VOID
94 STATIC
95 MemNAfterStitchMemNb (
96   IN OUT   MEM_NB_BLOCK *NBPtr
97   );
98
99 UINT8
100 MemNGet1KTFawTkNb (
101   IN       UINT8 k
102   );
103
104 UINT8
105 MemNGet2KTFawTkNb (
106   IN       UINT8 k
107   );
108
109 VOID
110 STATIC
111 MemNQuarterMemClk2NClkNb (
112   IN OUT   MEM_NB_BLOCK *NBPtr,
113   IN OUT   UINT16 *SubTotalPtr
114   );
115
116 /*----------------------------------------------------------------------------
117  *                            EXPORTED FUNCTIONS
118  *
119  *----------------------------------------------------------------------------
120  */
121
122 extern BUILD_OPT_CFG UserOptions;
123
124 /* -----------------------------------------------------------------------------*/
125 /**
126  *
127  *
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.
131  *
132  *
133  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
134  *
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
137  */
138
139 BOOLEAN
140 MemNStitchMemoryNb (
141   IN OUT   MEM_NB_BLOCK *NBPtr
142   )
143 {
144   BOOLEAN DSpareEn;
145   UINT32 NxtCSBase;
146   UINT32 CurCSBase;
147   UINT32 CsSize;
148   UINT32 BiggestBank;
149   UINT8 p;
150   UINT8 q;
151   UINT8 BiggestDimm;
152   MEM_PARAMETER_STRUCT *RefPtr;
153   DIE_STRUCT *MCTPtr;
154   DCT_STRUCT *DCTPtr;
155   RefPtr = NBPtr->RefPtr;
156   MCTPtr = NBPtr->MCTPtr;
157   DCTPtr = NBPtr->DCTPtr;
158   DSpareEn = FALSE;
159   if (NBPtr->IsSupported[SetSpareEn]) {
160     DSpareEn = FALSE;
161     if (RefPtr->GStatus[GsbEnDIMMSpareNW]) {
162       DSpareEn = TRUE;
163     }
164   }
165
166   DCTPtr->Timings.CsEnabled = 0;
167   NxtCSBase = 0;
168   for (p = 0; p < MAX_CS_PER_CHANNEL; p++) {
169     BiggestBank = 0;
170     BiggestDimm = 0;
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));
176           if (CsSize != 0) {
177             CsSize += ((UINT32)1 << 19);
178             CsSize &= 0xFFF80000;
179           }
180           if (CsSize > BiggestBank) {
181             BiggestBank = CsSize;
182             BiggestDimm = q;
183           }
184         }
185       }
186     }
187
188     if (BiggestBank != 0) {
189       CurCSBase = NxtCSBase;
190       if (NBPtr->IsSupported[CheckSpareEn]) {
191         if (DSpareEn) {
192           CurCSBase = ((UINT32)1 << BFSpare);
193           DSpareEn = FALSE;
194         } else {
195           CurCSBase |= ((UINT32)1 << BFCSEnable);
196           NxtCSBase += BiggestBank;
197         }
198       } else {
199         CurCSBase |= ((UINT32)1 << BFCSEnable);
200         NxtCSBase += BiggestBank;
201       }
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);
207           }
208         }
209       }
210       MemNSetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + BiggestDimm, CurCSBase);
211       DCTPtr->Timings.CsEnabled |= (1 << BiggestDimm);
212     }
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);
216     }
217   }
218
219   if (NxtCSBase != 0) {
220     DCTPtr->Timings.DctMemSize = NxtCSBase >> 8;    // Scale base address from [39:8] to [47:16]
221     MemNAfterStitchMemNb (NBPtr);
222   }
223
224   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
225 }
226
227 /* -----------------------------------------------------------------------------*/
228 /**
229  *
230  *
231  *   This function gets platform specific config/timing values from the interface layer and
232  *   programs them into DCT.
233  *
234  *
235  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
236  *
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
239  */
240
241 BOOLEAN
242 MemNPlatformSpecNb (
243   IN OUT   MEM_NB_BLOCK *NBPtr
244   )
245 {
246   CONST BIT_FIELD_NAME ChipletPDRegs[] = {
247   BFPhyClkConfig0,
248   BFPhyClkConfig3,
249   BFPhyClkConfig1,
250   BFPhyClkConfig2
251   };
252   CONST UINT8 ChipletPDClkDisMap[][2] = {
253   //F2[1, 0]x9C_x0D0F2030 -> F2x[1, 0]88[MemClkDis[1:0]]
254   {0, 1},
255   //F2[1, 0]x9C_x0D0F2330 -> F2x[1, 0]88[MemClkDis[7:6]]
256   {6, 7},
257   //F2x09C_x0D0F2130 -> F2x88[MemClkDis[5:4]]
258   {4, 5},
259   //F2x09C_x0D0F2230 -> F2x88[MemClkDis[3:2]]
260   {2, 3},
261   //F2x19C_x0D0F2130 -> F2x188[MemClkDis[5:2]]
262   {2, 5},
263   //F2x19C_x0D0F2230 -> F2x188[MemClkDis[4:3]]
264   {3, 4}
265   };
266
267   UINT8 MemClkDis;
268   UINT8 i;
269   UINT8 MemoryAllClocks;
270   UINT8 *MemClkDisMap;
271   UINT16 CsPresent;
272   UINT8 RegIndex;
273   UINT8 Cs1;
274   UINT8 Cs2;
275
276   if (!MemNGetPlatformCfgNb (NBPtr)) {
277     IDS_ERROR_TRAP;
278   }
279
280   if (!NBPtr->PsPtr->MemPDoPs (NBPtr)) {
281     IDS_ERROR_TRAP;
282   }
283   MemNProgramPlatformSpecNb (NBPtr);
284
285   MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODT, ALL_DIMMS);
286
287   if (NBPtr->MCTPtr->GangedMode) {
288     MemNSwitchDCTNb (NBPtr, 1);
289     if (!MemNGetPlatformCfgNb (NBPtr)) {
290       IDS_ERROR_TRAP;
291     }
292     MemNProgramPlatformSpecNb (NBPtr);
293     MemNSwitchDCTNb (NBPtr, 0);
294   }
295
296   //======================================================================
297   // Disable unused MemClk to save power
298   //======================================================================
299   //
300   MemClkDis = 0;
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;
309       }
310
311       // Turn off the unused CS clocks
312       CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
313
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;
319         }
320       }
321       for (i = 0; i < 8; i++) {
322         if ((CsPresent & MemClkDisMap[i]) == 0) {
323           MemClkDis |= (UINT8) (1 << i);
324         }
325       }
326       //Chiplet power down
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]];
331         } else {
332           Cs1 =  MemClkDisMap[ChipletPDClkDisMap[RegIndex][0]];
333           Cs2 =  MemClkDisMap[ChipletPDClkDisMap[RegIndex][1]];
334         }
335         if ((CsPresent & (UINT16) (Cs1 | Cs2)) == 0) {
336           MemNSetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex], (MemNGetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex]) | 0x10));
337         }
338       }
339     }
340   }
341   MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
342
343   AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
344   NBPtr->MemNInitPhyComp (NBPtr);
345
346   MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
347
348   // Program DramTerm for DDR2
349   if ((MemNGetBitFieldNb (NBPtr, BFDdr3Mode)) == 0) {
350     MemNSetBitFieldNb (NBPtr, BFDramTerm, NBPtr->PsPtr->DramTerm);
351   } else {
352     // Dynamic Dynamic DramTerm for DDR3
353     // Dram Term for DDR3 may vary based on chip selects
354     MemNSetBitFieldNb (NBPtr, BFDramTermDyn, NBPtr->PsPtr->DynamicDramTerm);
355   }
356
357   MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
358
359   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
360 }
361
362 /* -----------------------------------------------------------------------------*/
363 /**
364  *
365  *
366  *   This function gets platform specific config/timing values from the interface layer and
367  *   programs them into DCT.
368  *
369  *
370  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
371  *
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
374  */
375
376 BOOLEAN
377 MemNPlatformSpecUnb (
378   IN OUT   MEM_NB_BLOCK *NBPtr
379   )
380 {
381   UINT8 MemClkDis;
382   UINT8 i;
383   UINT8 MemoryAllClocks;
384   UINT8 *MemClkDisMap;
385   UINT16 CsPresent;
386
387   if (!MemNGetPlatformCfgNb (NBPtr)) {
388     IDS_ERROR_TRAP;
389   }
390
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);
395   } else {
396
397     MemNProgramPlatformSpecNb (NBPtr);
398     MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODT, ALL_DIMMS);
399
400     //======================================================================
401     // Disable unused MemClk to save power
402     //======================================================================
403     //
404     MemClkDis = 0;
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;
413         }
414
415         // Turn off unused clocks
416         CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
417
418         for (i = 0; i < 8; i++) {
419           if ((CsPresent & MemClkDisMap[i]) == 0) {
420             MemClkDis |= (UINT8) (1 << i);
421           }
422         }
423
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);
428           }
429         }
430       }
431     }
432     MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
433     MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
434   }
435
436   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
437 }
438
439 /* -----------------------------------------------------------------------------*/
440 /**
441  *
442  *
443  *   This function disables the DCT and mem clock
444  *
445  *
446  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
447  *
448  */
449
450 VOID
451 MemNDisableDCTNb (
452   IN OUT   MEM_NB_BLOCK *NBPtr
453   )
454 {
455   MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
456   MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
457   MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
458
459   // To maximize power savings when DisDramInterface=1b,
460   // all of the MemClkDis bits should also be set.
461   //
462   MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
463   MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
464 }
465
466 /* -----------------------------------------------------------------------------*/
467 /**
468  *
469  *
470  *   This function disables the DCT and mem clock for client NB
471  *
472  *
473  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
474  *
475  */
476
477 VOID
478 MemNDisableDCTClientNb (
479   IN OUT   MEM_NB_BLOCK *NBPtr
480   )
481 {
482   MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
483   MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
484   MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
485
486   //Wait for 24 MEMCLKs
487   MemNWaitXMemClksNb (NBPtr, 24);
488
489   // To maximize power savings when DisDramInterface=1b,
490   // all of the MemClkDis bits should also be set.
491   //
492   MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
493
494   MemNSetBitFieldNb (NBPtr, BFDramPhyStatusReg, 0x80800000);
495
496   MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
497 }
498
499 /* -----------------------------------------------------------------------------*/
500 /**
501  *
502  *
503  *  This function initializes the DRAM devices on all DCTs at the same time
504  *
505  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
506  *
507  */
508
509 VOID
510 MemNStartupDCTNb (
511   IN OUT   MEM_NB_BLOCK *NBPtr
512   )
513 {
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
517
518   if (NBPtr->MCTPtr->NodeMemSize != 0) {
519     // Init MemClk frequency
520     MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
521
522
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);
528   }
529
530   // 7. Program F2x[1, 0]9C_x08[DisAutoComp] = 0.
531   // 8. BIOS must wait 750 us for the phy compensation engine
532   //    to reinitialize.
533   // DisAutoComp will be cleared after DramEnabled turns to 1
534
535 }
536
537 /* -----------------------------------------------------------------------------*/
538 /**
539  *
540  *
541  *  This function initializes the DRAM devices on all DCTs at the same time
542  *
543  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
544  *
545  */
546
547 VOID
548 MemNStartupDCTUnb (
549   IN OUT   MEM_NB_BLOCK *NBPtr
550   )
551 {
552   UINT8 Dct;
553
554   if (NBPtr->MCTPtr->NodeMemSize != 0) {
555     // Update NB frequency for startup DDR speed
556     NBPtr->ChangeNbFrequency (NBPtr);
557
558     // Program D18F2x[1,0]9C_x0000_000B = 80000000h. #109999.
559     MemNBrdcstSetNb (NBPtr, BFDramPhyStatusReg, 0x80000000);
560
561     // Program D18F2x[1,0]9C_x0D0F_E013[PllRegWaitTime] = 0118h. #194060.
562     MemNBrdcstSetNb (NBPtr, BFPllRegWaitTime, 0x118);
563
564     // Phy Voltage Level Programming
565     MemNPhyVoltageLevelNb (NBPtr);
566
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);
575
576     NBPtr->FamilySpecificHook[BeforePhyFenceTraining] (NBPtr, NBPtr);
577
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);
582
583         // Phy fence programming
584         AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
585         NBPtr->PhyFenceTraining (NBPtr);
586
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);
591       }
592     }
593
594     AGESA_TESTPOINT (TpProcMemBeforeDramInit, &(NBPtr->MemPtr->StdHeader));
595     NBPtr->MemNBeforeDramInitNb (NBPtr);
596
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);
600   }
601 }
602
603 /* -----------------------------------------------------------------------------*/
604 /**
605  *
606  * MemNChangeFrequencyHy:
607  *
608  *  This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
609  *
610  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
611  *
612  */
613
614 VOID
615 MemNChangeFrequencyNb (
616   IN OUT   MEM_NB_BLOCK *NBPtr
617   )
618 {
619   MEM_TECH_BLOCK *TechPtr;
620   UINT8 Dct;
621   UINT8 ChipSel;
622   UINT32 Dummy;
623
624   TechPtr = NBPtr->TechPtr;
625   if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
626     // #107421
627     MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
628   }
629
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);
634
635   //Program F2x9C_x08[DisAutoComp]=1
636   MemNSwitchDCTNb (NBPtr, 0);
637   MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 1);
638
639   //Program F2x[1, 0]94[MemClkFreqVal] = 0.
640   MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
641
642   //Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency.
643   MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
644
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);
648
649   //Wait until F2x[1, 0]94[FreqChgInProg]=0.
650   MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
651
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);
661       }
662     }
663   }
664
665   //Program F2x9C_x08[DisAutoComp]=0
666   MemNSwitchDCTNb (NBPtr, 0);
667   MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
668
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);
673
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);
679       }
680     }
681   }
682
683   //wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns
684   MemNWaitXMemClksNb (NBPtr, 500);
685
686   if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
687     // #107421
688     MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
689   }
690
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) {
695
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)) {
701         IDS_ERROR_TRAP;
702       }
703
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
711           }
712         }
713         if (NBPtr->IsSupported[CheckSendAllMRCmds]) {
714           if (MemNGetMCTSysAddrNb (NBPtr, ChipSel, &Dummy)) {
715             // if chip select present
716             TechPtr->SendAllMRCmds (TechPtr, ChipSel);
717           }
718         }
719       }
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));
725         if (Dct == 0) {
726           MemNSetBitFieldNb (NBPtr, BFPhy0x0D082F30, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D082F30) | 0x2000));
727         }
728         // NOTE: wait 512 clocks for DLL-relock
729         MemUWait10ns (50000, NBPtr->MemPtr);  // wait 500us
730       }
731     }
732   }
733   // Re-enable phy compensation since it had been disabled during InitPhyComp
734   MemNSwitchDCTNb (NBPtr, 0);
735   MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
736 }
737
738
739 /* -----------------------------------------------------------------------------*/
740 /**
741  *
742  *      This function ramp up frequency the next level if it have not reached
743  *      its TargetSpeed yet.
744  *
745  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
746  *
747  *     @return          TRUE -  No fatal error occurs.
748  *     @return          FALSE - Fatal error occurs.
749  */
750
751 BOOLEAN
752 MemNRampUpFrequencyNb (
753   IN OUT   MEM_NB_BLOCK *NBPtr
754   )
755 {
756   CONST UINT16 FreqList[] = {
757     DDR400_FREQUENCY,
758     DDR533_FREQUENCY,
759     DDR667_FREQUENCY,
760     DDR800_FREQUENCY,
761     DDR1066_FREQUENCY,
762     DDR1333_FREQUENCY,
763     DDR1600_FREQUENCY,
764     DDR1866_FREQUENCY
765   };
766   UINT8 Dct;
767   UINT8 i;
768   UINT16 NewSpeed;
769   DIE_STRUCT *MCTPtr;
770
771   MCTPtr = NBPtr->MCTPtr;
772
773   // Do not change frequency when it is already at TargetSpeed
774   if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
775     return TRUE;
776   }
777
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];
783       break;
784     }
785   }
786   ASSERT (i < (GET_SIZE_OF (FreqList) - 1));
787   ASSERT (NewSpeed <= NBPtr->DCTPtr->Timings.TargetSpeed);
788
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;
794   }
795   IDS_HDT_CONSOLE (MEM_FLOW, " -> %d MHz", NewSpeed);
796
797   NBPtr->ChangeFrequency (NBPtr);
798
799   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
800 }
801
802 /* -----------------------------------------------------------------------------*/
803 /**
804  *
805  *
806  *      This function uses calculated values from DCT.Timings structure to
807  *      program its registers.
808  *
809  *
810  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
811  *
812  */
813
814 VOID
815 MemNProgramCycTimingsNb (
816   IN OUT   MEM_NB_BLOCK *NBPtr
817   )
818 {
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}
831   };
832
833   DCT_STRUCT *DCTPtr;
834   UINT8  *MiniMaxTmg;
835   UINT8  *MiniMaxTrfc;
836   UINT8  Value8;
837   UINT8  j;
838   BIT_FIELD_NAME BitField;
839
840   DCTPtr = NBPtr->DCTPtr;
841
842   //======================================================================
843   // Program turnaround timings to their max during DRAM init and training
844   //======================================================================
845   //
846   MemNSetBitFieldNb (NBPtr, BFNonSPD, 0x28FF);
847
848   MemNSetBitFieldNb (NBPtr, BFNonSPDHi, 0x2A);
849
850   //======================================================================
851   // Program DRAM Timing values
852   //======================================================================
853   //
854   MiniMaxTmg = &DCTPtr->Timings.CasL;
855   for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
856     BitField = TmgAdjTab[j].BitField;
857
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;
862     }
863
864     Value8 = (UINT8) MiniMaxTmg[j];
865
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;
870     }
871
872     Value8 = Value8 - TmgAdjTab[j].Bias;
873     Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
874
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);
886   }
887
888   MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
889   for (j = 0; j < 4; j++) {
890     ASSERT (MiniMaxTrfc[j] <= 4);
891     MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
892   }
893
894   MemNSetBitFieldNb (NBPtr, BFTcwl, ((DCTPtr->Timings.Speed >= DDR800_FREQUENCY) ?
895                                      (NBPtr->GetMemClkFreqId (NBPtr, DCTPtr->Timings.Speed) - 3) : 0));
896
897   MemNSetBitFieldNb (NBPtr, BFTref, 2);      // 7.8 us
898
899   //======================================================================
900   // DRAM MRS Register, set ODT
901   //======================================================================
902   //
903   // DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
904   MemNSetBitFieldNb (NBPtr, BFDrvImpCtrl, 1);
905
906   // burst length control
907   if (NBPtr->MCTPtr->Status[Sb128bitmode]) {
908     MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 2);
909   }
910
911   // ASR=1, auto self refresh; SRT=0
912   MemNSetBitFieldNb (NBPtr, BFASR, 1);
913 }
914
915 /* -----------------------------------------------------------------------------*/
916 /**
917  *
918  *
919  *      This function uses calculated values from DCT.Timings structure to
920  *      program its registers.
921  *
922  *
923  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
924  *
925  */
926
927 VOID
928 MemNProgramCycTimingsClientNb (
929   IN OUT   MEM_NB_BLOCK *NBPtr
930   )
931 {
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}
944   };
945
946   DCT_STRUCT *DCTPtr;
947   UINT8  *MiniMaxTmg;
948   UINT8  *MiniMaxTrfc;
949   UINT8  Value8;
950   UINT8  j;
951   UINT8  Tcwl;
952   UINT8  Trcd;
953   INT32  TCK_ps;
954   BIT_FIELD_NAME BitField;
955
956   DCTPtr = NBPtr->DCTPtr;
957
958   //======================================================================
959   // Program DRAM Timing values
960   //======================================================================
961   //
962   MiniMaxTmg = &DCTPtr->Timings.CasL;
963   for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
964     BitField = TmgAdjTab[j].BitField;
965
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;
970     }
971
972     Value8 = (UINT8) MiniMaxTmg[j];
973
974     if (BitField == BFTwrDDR3) {
975       if (NBPtr->IsSupported[AdjustTwr]) {
976         Value8 ++;
977       }
978       Value8 = (Value8 >= 10) ? (((Value8 + 1) / 2) + 4) : Value8;
979     }
980
981     Value8 = Value8 - TmgAdjTab[j].Bias;
982     Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
983
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);
995   }
996
997   MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
998   for (j = 0; j < 4; j++) {
999     ASSERT (MiniMaxTrfc[j] <= 5);
1000     MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
1001   }
1002
1003   Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
1004   MemNSetBitFieldNb (NBPtr, BFTcwl, ((Tcwl > 5) ? (Tcwl - 5) : 0));
1005
1006   MemNSetBitFieldNb (NBPtr, BFTref, 2);      // Tref = 7.8 us
1007
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);
1013   }
1014
1015   MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0);
1016
1017 }
1018
1019 /* -----------------------------------------------------------------------------*/
1020 /**
1021  *
1022  *
1023  *   This function gets platform specific settings for the current channel
1024  *
1025  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1026  *
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
1029  */
1030
1031 BOOLEAN
1032 MemNGetPlatformCfgNb (
1033   IN OUT   MEM_NB_BLOCK *NBPtr
1034   )
1035 {
1036   UINT8 p;
1037
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) {
1041       break;
1042     }
1043   }
1044   return (p < MAX_PLATFORM_TYPES);
1045 }
1046
1047 /* -----------------------------------------------------------------------------*/
1048 /**
1049  *
1050  *
1051  *   This function retrieves the Max latency parameters
1052  *
1053  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1054  *
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
1059  */
1060
1061 VOID
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
1068   )
1069 {
1070   *MinDlyPtr = (MemNTotalSyncComponentsNb (NBPtr) + (MaxRcvEnDly >> 5)) * 2;
1071   MemNQuarterMemClk2NClkNb (NBPtr, MinDlyPtr);
1072
1073   *MaxDlyPtr = 0x3FF;
1074
1075   *DlyBiasPtr = 4;
1076   MemNQuarterMemClk2NClkNb (NBPtr, DlyBiasPtr);   // 1 MEMCLK Margin
1077
1078   *DlyBiasPtr += 1;  // add 1 NCLK
1079 }
1080
1081 /* -----------------------------------------------------------------------------*/
1082 /**
1083  *
1084  *
1085  *   This function  sets the maximum round-trip latency in the system from the processor to the DRAM
1086  *   devices and back.
1087  *
1088  *
1089  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1090  *     @param[in]     MaxRcvEnDly - Maximum receiver enable delay value
1091  *
1092  */
1093
1094 VOID
1095 MemNSetMaxLatencyNb (
1096   IN OUT   MEM_NB_BLOCK *NBPtr,
1097   IN       UINT16 MaxRcvEnDly
1098   )
1099 {
1100   UINT16 SubTotal;
1101
1102   AGESA_TESTPOINT (TpProcMemRcvrCalcLatency, &(NBPtr->MemPtr->StdHeader));
1103
1104   SubTotal = 0xC8;    // init value for MaxRdLat used in training
1105
1106
1107   if (MaxRcvEnDly != 0xFFFF) {
1108     // Get all sync components BKDG steps 1-5
1109     SubTotal = MemNTotalSyncComponentsNb (NBPtr);
1110
1111     // Add the maximum (worst case) delay value of DqsRcvEnGrossDelay
1112     // that exists across all DIMMs and byte lanes.
1113     //
1114     SubTotal += MaxRcvEnDly >> 5;
1115
1116
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.
1119     //
1120     SubTotal <<= 1;             // scale 1/2 MemClk to 1/4 MemClk
1121     SubTotal += 29;             // add 14.5 1/2 MemClk
1122
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).
1126     //
1127     MemNQuarterMemClk2NClkNb (NBPtr, &SubTotal);
1128
1129     // Add 2 NCLKs to the sub-total. 2 represents part of the processor
1130     // specific constant value in the northbridge clock domain.
1131     //
1132     SubTotal += 2;
1133   }
1134
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);
1139 }
1140
1141 /* -----------------------------------------------------------------------------*/
1142 /**
1143  *
1144  *
1145  *   This function sends the ZQCL command
1146  *
1147  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1148  *
1149  */
1150
1151 VOID
1152 MemNSendZQCmdNb (
1153   IN OUT   MEM_NB_BLOCK *NBPtr
1154   )
1155 {
1156   // 1.Program MrsAddress[10]=1
1157   MemNSetBitFieldNb (NBPtr, BFMrsAddress, (UINT32)1 << 10);
1158
1159   // 2.Set SendZQCmd=1
1160   MemNSetBitFieldNb (NBPtr, BFSendZQCmd, 1);
1161
1162   // 3.Wait for SendZQCmd=0
1163   MemNPollBitFieldNb (NBPtr, BFSendZQCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
1164
1165   // 4.Wait 512 MEMCLKs
1166   MemNWaitXMemClksNb (NBPtr, 512);
1167 }
1168
1169
1170 /*----------------------------------------------------------------------------
1171  *                              LOCAL FUNCTIONS
1172  *
1173  *----------------------------------------------------------------------------
1174  */
1175
1176 /* -----------------------------------------------------------------------------*/
1177 /**
1178  *
1179  *
1180  *   This function is used to create the DRAM map
1181  *
1182  *
1183  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1184  */
1185
1186 VOID
1187 STATIC
1188 MemNAfterStitchMemNb (
1189   IN OUT   MEM_NB_BLOCK *NBPtr
1190   )
1191 {
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;
1198   } else {
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;
1202   }
1203 }
1204
1205
1206 /* -----------------------------------------------------------------------------*/
1207 /**
1208  *
1209  *
1210  *       This function Return the binary value of tfaw associated with
1211  *       the index k
1212  *
1213  *     @param[in]     k value
1214  *
1215  *     @return       F[k], in Binary MHz.
1216  */
1217
1218 UINT8
1219 MemNGet1KTFawTkNb (
1220   IN       UINT8 k
1221   )
1222 {
1223   CONST UINT8 Tab1KTfawTK[] = {0, 8, 10, 13, 14, 19};
1224   ASSERT (k <= 5);
1225   return Tab1KTfawTK[k];
1226 }
1227
1228 /* -----------------------------------------------------------------------------*/
1229 /**
1230  *
1231  *
1232  *       This function Return the binary value of the 2KTFaw associated with
1233  *       the index k
1234  *
1235  *     @param[in]     k value
1236  *
1237  *     @return       2KTFaw converted based on k.
1238  */
1239
1240 UINT8
1241 MemNGet2KTFawTkNb (
1242   IN       UINT8 k
1243   )
1244 {
1245   CONST UINT8 Tab2KTfawTK[] = {0, 10, 14, 17, 18, 24};
1246   ASSERT (k <= 5);
1247   return Tab2KTfawTK[k];
1248 }
1249
1250 /* -----------------------------------------------------------------------------*/
1251 /**
1252  *
1253  *
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).
1257  *
1258  *
1259  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1260  *     @param[in,out]   *SubTotalPtr - pointer to Sub-Total
1261  */
1262
1263 VOID
1264 STATIC
1265 MemNQuarterMemClk2NClkNb (
1266   IN OUT   MEM_NB_BLOCK *NBPtr,
1267   IN OUT   UINT16 *SubTotalPtr
1268   )
1269 {
1270   UINT32 NBFreq;
1271   UINT32 MemFreq;
1272
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
1278 }
1279
1280 /* -----------------------------------------------------------------------------*/
1281 /**
1282  *
1283  *
1284  *   This function gets the total of sync components for Max Read Latency calculation
1285  *
1286  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1287  *
1288  *     @return      Total in 1/2 MEMCLKs
1289  */
1290
1291 UINT16
1292 MemNTotalSyncComponentsNb (
1293   IN OUT   MEM_NB_BLOCK *NBPtr
1294   )
1295 {
1296   UINT16 SubTotal;
1297
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) {
1301     SubTotal += 3;
1302   }
1303   SubTotal *= 2;
1304
1305   // If registered DIMMs are being used then add 1 MEMCLK to the sub-total.
1306   if ((MemNGetBitFieldNb (NBPtr, BFUnBuffDimm)) == 0) {
1307     SubTotal += 2;
1308   }
1309
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) {
1313     SubTotal += 1;
1314   } else {
1315     SubTotal += 2;
1316   }
1317
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.
1320   //
1321   SubTotal = SubTotal + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit));
1322
1323   return SubTotal;
1324 }
1325
1326 /* -----------------------------------------------------------------------------*/
1327 /**
1328  *
1329  *
1330  *   This function swaps bits for OnDimmMirror support
1331  *
1332  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1333  *
1334  */
1335
1336 VOID
1337 MemNSwapBitsNb (
1338   IN OUT   MEM_NB_BLOCK *NBPtr
1339   )
1340 {
1341   UINT8 ChipSel;
1342   UINT32 MRSReg;
1343
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);
1350     }
1351   }
1352 }
1353
1354 /* -----------------------------------------------------------------------------*/
1355 /**
1356  *
1357  *
1358  *   This function swaps bits for OnDimmMirror support for Unb
1359  *
1360  *     Dimm Mirroring Requires that, during MRS command cycles, the following
1361  *     bits are swapped by software
1362  *
1363  *             A3 -> A4         A7 -> A8
1364  *             A4 -> A3         BA0 -> BA1
1365  *             A5 -> A6         BA1 -> BA0
1366  *             A6 -> A5
1367  *
1368  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1369  *
1370  */
1371
1372 VOID
1373 MemNSwapBitsUnb (
1374   IN OUT   MEM_NB_BLOCK *NBPtr
1375   )
1376 {
1377   UINT8 ChipSel;
1378   UINT32 MRSBank;
1379   UINT32 MRSAddr;
1380
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);
1386
1387       IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d MR%d %05x swapped to ->",
1388                                                                     (ChipSel & 0x7),
1389                                                                     (MRSBank & 0x7),
1390                                                                     (MRSAddr & 0x3FFFF));
1391       //
1392       // Swap Mrs Bank bits 0 with 1
1393       MRSBank = (MRSBank & 0x0100) | ((MRSBank & 0x01) << 1) | ((MRSBank & 0x02) >> 1);
1394       //
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);
1399     }
1400   }
1401 }
1402
1403 /* -----------------------------------------------------------------------------*/
1404 /**
1405  *
1406  *   Programs Address/command timings, driver strengths, and tri-state fields.
1407  *
1408  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1409  *
1410  */
1411 VOID
1412 MemNProgramPlatformSpecNb (
1413   IN OUT   MEM_NB_BLOCK *NBPtr
1414   )
1415 {
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};
1419   UINT8  *TabPtr;
1420   UINT8  i;
1421   UINT8  k;
1422   UINT8  Value;
1423   //===================================================================
1424   // Tristate unused CKE, ODT and chip select to save power
1425   //===================================================================
1426   //
1427   TabPtr = NULL;
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));
1431     }
1432     if (NBPtr->IsSupported[CheckFindPSDct]) {
1433       TabPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PinType[k], NBPtr->MCTPtr->SocketId, NBPtr->Dct);
1434     }
1435     if (TabPtr == NULL) {
1436       switch (k) {
1437       case 0:
1438         TabPtr = NBPtr->ChannelPtr->CKETriMap;
1439         break;
1440       case 1:
1441         TabPtr = NBPtr->ChannelPtr->ODTTriMap;
1442         break;
1443       case 2:
1444         TabPtr = NBPtr->ChannelPtr->ChipSelTriMap;
1445         break;
1446       default:
1447         IDS_ERROR_TRAP;
1448       }
1449     }
1450     ASSERT (TabPtr != NULL);
1451
1452     Value = 0;
1453     for (i = 0; i < TabSize[k]; i++) {
1454       if ((NBPtr->DCTPtr->Timings.CsPresent & TabPtr[i]) == 0) {
1455         Value |= (UINT8) (1 << i);
1456       }
1457     }
1458
1459     if (k == PSO_CS_TRI) {
1460       NBPtr->FamilySpecificHook[BeforeSetCsTri] (NBPtr, &Value);
1461     }
1462
1463     ASSERT (k < GET_SIZE_OF (BitField));
1464     MemNSetBitFieldNb (NBPtr, BitField[k], Value);
1465   }
1466   NBPtr->MemNBeforePlatformSpecNb (NBPtr);
1467
1468   //===================================================================
1469   // Program Address/Command timings and driver strength
1470   //===================================================================
1471   //
1472   MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ADDRTMG, ALL_DIMMS);
1473   MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODCCONTROL, ALL_DIMMS);
1474
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);
1479
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);
1485   }
1486 }
1487 /* -----------------------------------------------------------------------------*/
1488 /**
1489  *
1490  *
1491  *   This function gets the Trdrd value
1492  *
1493  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1494  *
1495  *     @return      Trdrd value
1496  */
1497
1498 UINT8
1499 MemNGetTrdrdNb (
1500   IN OUT   MEM_NB_BLOCK *NBPtr
1501   )
1502 {
1503   DCT_STRUCT *DCTPtr;
1504   INT8 Cgdd;
1505
1506   DCTPtr = NBPtr->DCTPtr;
1507
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.
1513
1514   Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessRcvEnDly, AccessRcvEnDly);
1515   DCTPtr->Timings.Trdrd = (Cgdd / 2) + 3;
1516
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;
1521   }
1522
1523   return DCTPtr->Timings.Trdrd;
1524 }
1525
1526
1527 /* -----------------------------------------------------------------------------*/
1528 /**
1529  *
1530  *
1531  *   This function gets the Twrwr value
1532  *
1533  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1534  *
1535  *     @return      Twrwr value
1536  */
1537
1538 UINT8
1539 MemNGetTwrwrNb (
1540   IN OUT   MEM_NB_BLOCK *NBPtr
1541   )
1542 {
1543   DCT_STRUCT *DCTPtr;
1544   INT8 Cgdd;
1545
1546   DCTPtr = NBPtr->DCTPtr;
1547
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.
1554
1555   Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessWrDatDly, AccessWrDatDly);
1556   DCTPtr->Timings.Twrwr = (Cgdd / 2) + 3;
1557   NBPtr->TechPtr->AdjustTwrwr (NBPtr->TechPtr);
1558
1559   return DCTPtr->Timings.Twrwr;
1560 }
1561
1562 /* -----------------------------------------------------------------------------*/
1563 /**
1564  *
1565  *
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
1568  * values down.
1569  *
1570  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1571  *
1572  *     @return  Value to be programmed to Twrrd field
1573  *              pDCT->Timings.Twrrd updated
1574  */
1575
1576 UINT8
1577 MemNGetTwrrdNb (
1578   IN OUT   MEM_NB_BLOCK *NBPtr
1579   )
1580 {
1581   INT8 Cgdd;
1582   INT8 Ld;
1583   INT8 Twrrd;
1584   DCT_STRUCT *DCTPtr;
1585
1586   DCTPtr = NBPtr->DCTPtr;
1587
1588   //
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
1591   // value.
1592   // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1593   //
1594   Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1595
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);
1603
1604   return DCTPtr->Timings.Twrrd;
1605 }
1606
1607 /* -----------------------------------------------------------------------------*/
1608 /**
1609  *
1610  *
1611  *   This function gets the TrwtTO value
1612  *
1613  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1614  *
1615  *     @return  pDCT->Timings.TrwtTO updated
1616  */
1617
1618 UINT8
1619 MemNGetTrwtTONb (
1620   IN OUT   MEM_NB_BLOCK *NBPtr
1621   )
1622 {
1623   INT8 Cgdd;
1624   INT8 Ld;
1625   INT8 TrwtTO;
1626   DCT_STRUCT *DCTPtr;
1627
1628   DCTPtr = NBPtr->DCTPtr;
1629   //
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
1632   // value.
1633   // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1634   //
1635   Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1636
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;
1642   TrwtTO -= 2;
1643   DCTPtr->Timings.TrwtTO = (UINT8) ((TrwtTO > 1) ? TrwtTO : 1);
1644
1645   return DCTPtr->Timings.TrwtTO;
1646 }
1647
1648 /* -----------------------------------------------------------------------------*/
1649 /**
1650  *
1651  *
1652  *   This function gets the TrwtWB value
1653  *
1654  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1655  *
1656  *     @return      TrwtWB value
1657  */
1658 UINT8
1659 MemNGetTrwtWBNb (
1660   IN OUT   MEM_NB_BLOCK *NBPtr
1661   )
1662 {
1663   DCT_STRUCT *DCTPtr;
1664
1665   DCTPtr = NBPtr->DCTPtr;
1666
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;
1670 }
1671
1672 /* -----------------------------------------------------------------------------*/
1673 /**
1674  *
1675  *
1676  *   This function converts MemClk frequency in MHz to MemClkFreq value
1677  *
1678  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1679  *     @param[in]       Speed   - MemClk frequency in MHz
1680  *
1681  *     @return      MemClkFreq value
1682  */
1683 UINT8
1684 MemNGetMemClkFreqIdNb (
1685   IN OUT   MEM_NB_BLOCK *NBPtr,
1686   IN       UINT16 Speed
1687   )
1688 {
1689   return (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
1690 }
1691
1692 /* -----------------------------------------------------------------------------*/
1693 /**
1694  *
1695  *
1696  *   This function enables swapping interleaved region feature.
1697  *
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]
1701  *
1702  */
1703 VOID
1704 MemNEnableSwapIntlvRgnNb (
1705   IN OUT   MEM_NB_BLOCK *NBPtr,
1706   IN       UINT32 Base,
1707   IN       UINT32 Limit
1708   )
1709 {
1710   UINT32 Size;
1711   UINT32 SizeOfAlign;
1712
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.
1722       Base -= 1;
1723       Size += 1;
1724       SizeOfAlign = (UINT32) 1 << LibAmdBitScanForward (Base);
1725     }
1726     MemNSetBitFieldNb (NBPtr, BFIntLvRgnBaseAddr, Base);
1727     MemNSetBitFieldNb (NBPtr, BFIntLvRgnLmtAddr, (Limit - 1));
1728     MemNSetBitFieldNb (NBPtr, BFIntLvRgnSize, Size);
1729     MemNSetBitFieldNb (NBPtr, BFIntLvRgnSwapEn, 1);
1730   }
1731 }
1732
1733 /* -----------------------------------------------------------------------------*/
1734 /**
1735  *
1736  *
1737  *   This function converts MemClk frequency in MHz to MemClkFreq value
1738  *
1739  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1740  *     @param[in]       Speed   - MemClk frequency in MHz
1741  *
1742  *     @return      MemClkFreq value
1743  */
1744 UINT8
1745 MemNGetMemClkFreqIdClientNb (
1746   IN OUT   MEM_NB_BLOCK *NBPtr,
1747   IN       UINT16 Speed
1748   )
1749 {
1750   return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1751 }
1752
1753 /* -----------------------------------------------------------------------------*/
1754 /**
1755  *
1756  *
1757  *   This function converts MemClk frequency in MHz to MemClkFreq value
1758  *
1759  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1760  *     @param[in]       Speed   - MemClk frequency in MHz
1761  *
1762  *     @return      MemClkFreq value
1763  */
1764 UINT8
1765 MemNGetMemClkFreqIdUnb (
1766   IN OUT   MEM_NB_BLOCK *NBPtr,
1767   IN       UINT16 Speed
1768   )
1769 {
1770   return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1771 }
1772
1773 /* -----------------------------------------------------------------------------*/
1774 /**
1775  *
1776  *
1777  *   This function converts MemClkFreq Id value to MemClk frequency in MHz
1778  *
1779  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1780  *     @param[in]       FreqId   - FreqId from Register
1781  *
1782  *     @return          MemClk frequency in MHz
1783  */
1784 UINT16
1785 MemNGetMemClkFreqUnb (
1786   IN OUT   MEM_NB_BLOCK *NBPtr,
1787   IN       UINT8 FreqId
1788   )
1789 {
1790   UINT16 MemClkFreq;
1791   if (FreqId > 2) {
1792     MemClkFreq = (FreqId == 14) ? 667 : (300 + ((FreqId - 3) * 33) + (FreqId - 3) / 3);
1793   } else if (FreqId == 2) {
1794     MemClkFreq = 200;
1795   } else {
1796     MemClkFreq = 50 + (50 * FreqId);
1797   }
1798   return MemClkFreq;
1799 }
1800
1801 /* -----------------------------------------------------------------------------*/
1802 /**
1803  *
1804  *  This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
1805  *  for client NB.
1806  *
1807  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1808  *
1809  */
1810
1811 VOID
1812 MemNChangeFrequencyUnb (
1813   IN OUT   MEM_NB_BLOCK *NBPtr
1814   )
1815 {
1816   MEM_TECH_BLOCK *TechPtr;
1817   UINT8 Dct;
1818   UINT8 ChipSel;
1819   UINT32 Dummy;
1820   BOOLEAN FrequencyChangeSuccess;
1821
1822   TechPtr = NBPtr->TechPtr;
1823
1824   MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
1825
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);
1830
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)) {
1838           IDS_ERROR_TRAP;
1839         }
1840       }
1841     }
1842
1843     // 1. Program PllLockTime to Family-specific value
1844     MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
1845
1846     // 2. Program D18F2x[1,0]94[MemClkFreqVal] = 0.
1847     MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
1848
1849     // 3. Program D18F2x[1,0]94[MemClkFreq] to the desired DRAM frequency.
1850     MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
1851
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);
1859
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);
1865
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);
1870
1871     FrequencyChangeSuccess = TRUE;
1872   } else {
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;
1878     }
1879     FrequencyChangeSuccess = FALSE;
1880   }
1881
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);
1887
1888   if (FrequencyChangeSuccess) {
1889     NBPtr->FamilySpecificHook[AfterMemClkFreqChg] (NBPtr, NULL);
1890
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);
1896
1897         // Phy fence programming
1898         AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
1899         NBPtr->PhyFenceTraining (NBPtr);
1900
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);
1905       }
1906     }
1907
1908     //======================================================================
1909     // Calculate and program DRAM Timings at new frequency
1910     //======================================================================
1911     //
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);
1921             }
1922           }
1923         }
1924         // Wait 512 clocks for DLL-relock
1925         MemNWaitXMemClksNb (NBPtr, 512);
1926       }
1927     }
1928   }
1929 }
1930
1931
1932 /* -----------------------------------------------------------------------------*/
1933 /**
1934  *
1935  *  This function calculates and programs NB P-state dependent registers
1936  *
1937  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1938  *
1939  */
1940
1941 VOID
1942 MemNProgramNbPstateDependentRegistersUnb (
1943   IN OUT   MEM_NB_BLOCK *NBPtr
1944   )
1945 {
1946   UINT8 RdPtrInit;
1947   UINT8 Dct;
1948
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);
1952
1953   switch (RdPtrInit) {
1954   case 4:
1955     if (MemNGetBitFieldNb (NBPtr, BFNbPsSel) == 0) {
1956       MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 2);
1957     } else {
1958       MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
1959     }
1960     break;
1961   case 5:
1962     MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
1963     break;
1964   case 6:
1965     MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 0);
1966     break;
1967   default:
1968     ASSERT (FALSE);
1969   }
1970
1971   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1972     MemNSwitchDCTNb (NBPtr, Dct);
1973     if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
1974       // Set ProcOdtAdv
1975       if (NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY) {
1976         MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0);
1977       } else {
1978         MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000);
1979       }
1980     }
1981   }
1982
1983   NBPtr->FamilySpecificHook[OverrideDataTxFifoWrDly] (NBPtr, NBPtr);
1984   IDS_OPTION_HOOK (IDS_NBPS_REG_OVERRIDE, NBPtr, &NBPtr->MemPtr->StdHeader);
1985 }
1986
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};
1990
1991 /**
1992  *
1993  *  This function calculates and programs NB P-state dependent registers
1994  *
1995  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1996  *
1997  */
1998
1999 VOID
2000 MemNProgramNbPstateDependentRegistersClientNb (
2001   IN OUT   MEM_NB_BLOCK *NBPtr
2002   )
2003 {
2004   UINT8 i;
2005   UINT8 Dct;
2006   UINT8 NclkFid;
2007   UINT16 MemClkDid;
2008   UINT8 PllMult;
2009   UINT8 NclkDiv;
2010   UINT8 RdPtrInitMin;
2011   UINT8 RdPtrInit;
2012   UINT32 NclkPeriod;
2013   UINT32 MemClkPeriod;
2014   INT32 PartialSum2x;
2015   INT32 PartialSumSlotI2x;
2016   INT32 RdPtrInitRmdr2x;
2017   INT32 TDataProp;
2018   UINT8 NbPstate;
2019   UINT8 SlowMode;
2020
2021   NclkFid = (UINT8) (MemNGetBitFieldNb (NBPtr, BFMainPllOpFreqId) + 0x10);  // NclkFid is in 100MHz
2022
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);
2027
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.
2033     if (NclkDiv < 8) {
2034       // Set a dummy divisor to prevent divide by zero exception below.
2035       NclkDiv = 8;
2036     }
2037     NbPstate = 1;
2038   } else {
2039     NclkDiv = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPs0NclkDiv);
2040     NbPstate = 0;
2041   }
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;
2045
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);
2053
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);
2059
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;
2072
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;
2082
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) {
2087         PartialSum2x -= 1;
2088       } else {
2089         PartialSum2x -= 2;
2090       }
2091       PartialSum2x -= 2;
2092
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;
2104         }
2105         if (NBPtr->IsSupported[SchedDlySlot1Extra] && (i == 1) && (SlowMode != 0)) {
2106           PartialSumSlotI2x -= 2;
2107         }
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);
2112         } else {
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);
2117         }
2118       }
2119
2120       // Set ProcOdtAdv
2121       if (NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY) {
2122         MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0);
2123       } else {
2124         MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000);
2125       }
2126     }
2127   }
2128
2129   MemFInitTableDrive (NBPtr, MTAfterNbPstateChange);
2130   if (NBPtr->NbFreqChgState == 2) {
2131     MemNSetBitFieldNb (NBPtr, BFNbPsDbgEn, 0);
2132     MemNSetBitFieldNb (NBPtr, BFNbPsCsrAccSel, 0);
2133   }
2134 }
2135
2136 /* -----------------------------------------------------------------------------*/
2137 /**
2138  *
2139  *
2140  *   This function gets the total of sync components for Max Read Latency calculation
2141  *
2142  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2143  *
2144  *     @return      Total in ps
2145  */
2146
2147 UINT32
2148 MemNTotalSyncComponentsClientNb (
2149   IN OUT   MEM_NB_BLOCK *NBPtr
2150   )
2151 {
2152   UINT32 P;
2153   UINT32 T;
2154   UINT8  RdPtrInitMin;
2155   UINT8  RdPtrInit;
2156   UINT32 AddrTmgCtl;
2157   UINT8  DbeGskMemClkAlignMode;
2158   UINT32 MemClkPeriod;
2159
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;
2164
2165   // IF (AddrCmdSetup != CkeSetup) THEN P = P + 1
2166   AddrTmgCtl = MemNGetBitFieldNb (NBPtr, BFAddrTmgControl);
2167   if (((AddrTmgCtl >> 16) & 0x20) != (AddrTmgCtl & 0x20)) {
2168     P += 1;
2169   }
2170
2171   // IF (DbeGskMemClkAlignMode==01b || (DbeGskMemClkAlignMode==00b && !(AddrCmdSetup==CsOdtSetup==CkeSetup)))
2172   // THEN P = P + 1
2173   DbeGskMemClkAlignMode = (UINT8) MemNGetBitFieldNb (NBPtr, BFDbeGskMemClkAlignMode);
2174   if ((DbeGskMemClkAlignMode == 1) || ((DbeGskMemClkAlignMode == 0) &&
2175       !((((AddrTmgCtl >> 16) & 0x20) == (AddrTmgCtl & 0x20)) && (((AddrTmgCtl >> 8) & 0x20) == (AddrTmgCtl & 0x20))))) {
2176     P += 1;
2177   }
2178
2179   // IF (SlowAccessMode==1) THEN P = P + 2
2180   if (MemNGetBitFieldNb (NBPtr, BFSlowAccessMode) == 1) {
2181     P += 2;
2182   }
2183
2184   // P = P + 2
2185   P += 2;
2186   T = 0;
2187
2188   // If (AddrCmdSetup==0 && CsOdtSetup==0 && CkeSetup==0)
2189   // then P = P + 1
2190   // else P = P + 2
2191   if ((AddrTmgCtl & 0x0202020) == 0) {
2192     P += 1;
2193   } else {
2194     P += 2;
2195   }
2196
2197   // P = P + (2 * (D18F2x[1,0]88[Tcl] clocks - 1))
2198   P += 2 * (NBPtr->DCTPtr->Timings.CasL - 1);
2199
2200   // If (DisCutThroughMode==0)
2201   // then P = P + 3
2202   // else P = P + 7
2203   if (MemNGetBitFieldNb (NBPtr, BFDisCutThroughMode) == 0) {
2204     P += 3;
2205   } else {
2206     P += 7;
2207   }
2208
2209   MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
2210   return (((P * MemClkPeriod + 1) / 2) + T);
2211 }
2212
2213 /* -----------------------------------------------------------------------------*/
2214 /**
2215  *
2216  *
2217  *   This function sets up phy power saving for client NB
2218  *
2219  *
2220  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2221  *
2222  */
2223 VOID
2224 MemNPhyPowerSavingClientNb (
2225   IN OUT   MEM_NB_BLOCK *NBPtr
2226   )
2227 {
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);
2237   }
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);
2251
2252   IDS_OPTION_HOOK (IDS_PHY_DLL_STANDBY_CTRL, NBPtr, &NBPtr->MemPtr->StdHeader);
2253 }
2254
2255 /* -----------------------------------------------------------------------------*/
2256 /**
2257  *
2258  *
2259  *   This function overrides the ASR and SRT value in MRS command
2260  *
2261  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2262  *
2263  */
2264 VOID
2265 MemNSetASRSRTNb (
2266   IN OUT   MEM_NB_BLOCK *NBPtr
2267   )
2268 {
2269   UINT32 MrsAddress;
2270   UINT8 Dimm;
2271   UINT8 *SpdBufferPtr;
2272
2273   // Look for MR2
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)) {
2281       Dimm -= 2;
2282     }
2283     if (NBPtr->TechPtr->GetDimmSpdBuffer (NBPtr->TechPtr, &SpdBufferPtr, Dimm)) {
2284       // Bit 2 is ASR
2285       if (SpdBufferPtr[THERMAL_OPT] & 0x4) {
2286         // when ASR is 1, set SRT to 0
2287         MrsAddress |= 0x40;
2288       } else {
2289         // Set SRT based on bit on of thermal byte
2290         MrsAddress |= ((SpdBufferPtr[THERMAL_OPT] & 1) << 7);
2291       }
2292       NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
2293     }
2294   }
2295 }
2296
2297 /* -----------------------------------------------------------------------------*/
2298 /**
2299  *
2300  *   This function changes NB frequency as below:
2301  *     NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP0-DDRTarget
2302  *
2303  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2304  *
2305  */
2306
2307 BOOLEAN
2308 MemNChangeNbFrequencyNb (
2309   IN OUT   MEM_NB_BLOCK *NBPtr
2310   )
2311 {
2312   BOOLEAN Status;
2313
2314   Status = FALSE;
2315
2316   // State machine to change NB frequency and NB Pstate
2317   switch (NBPtr->NbFreqChgState) {
2318   case 0:
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));
2325     }
2326     break;
2327
2328   case 1:
2329     // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P0
2330     MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2331
2332     // Next state would be to change NBPstate back to P0
2333     NBPtr->NbFreqChgState = 2;
2334
2335     // Update NB freq dependent registers
2336     NBPtr->ProgramNbPsDependentRegs (NBPtr);
2337
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);
2342
2343       // Return TRUE to repeat MaxRdLat training
2344       Status = TRUE;
2345
2346     } else {
2347       // If transition to NB-P1 fails, transition to exit state machine
2348       NBPtr->NbFreqChgState = 3;
2349     }
2350     break;
2351
2352   case 2:
2353     // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P1
2354     MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2355
2356     // Change NB P-State back to NBP0
2357     Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2358     ASSERT (Status);
2359
2360     // Return FALSE to get out of MaxRdLat training loop
2361     Status = FALSE;
2362
2363     // Exit state machine
2364     NBPtr->NbFreqChgState = 3;
2365     break;
2366
2367   default:
2368     break;
2369   }
2370
2371   return Status;
2372 }
2373
2374 /*-----------------------------------------------------------------------------
2375  *
2376  *
2377  *     This function programs registers before phy fence training for CNB
2378  *
2379  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
2380  *     @param[in,out]  OptParam   - Optional parameter
2381  *
2382  *     @return    TRUE
2383  * ----------------------------------------------------------------------------
2384  */
2385 BOOLEAN
2386 MemNBeforePhyFenceTrainingClientNb (
2387   IN OUT   MEM_NB_BLOCK *NBPtr,
2388   IN OUT   VOID *OptParam
2389   )
2390 {
2391   IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClkAlign=0\n");
2392   MemNBrdcstSetNb (NBPtr, BFDbeGskMemClkAlignMode, 0);
2393
2394   IDS_HDT_CONSOLE (MEM_FLOW, "\tEnDramInit = 1 for both DCTs\n");
2395   MemNBrdcstSetNb (NBPtr, BFEnDramInit, 1);
2396
2397   return TRUE;
2398 }
2399
2400 /* -----------------------------------------------------------------------------*/
2401 /**
2402  *
2403  *   This function changes NB frequency foras below:
2404  *     NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP2-DDRTarget -> NBP3-DDRTarget -> NBP0-DDRTarget
2405  *
2406  *
2407  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2408  *
2409  */
2410
2411 BOOLEAN
2412 MemNChangeNbFrequencyUnb (
2413   IN OUT   MEM_NB_BLOCK *NBPtr
2414   )
2415 {
2416   BOOLEAN Status;
2417
2418   Status = FALSE;
2419
2420   // State machine to change NB frequency and NB Pstate
2421   switch (NBPtr->NbFreqChgState) {
2422   case 0:
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));
2429     }
2430     break;
2431
2432   case 1:
2433   case 2:
2434   case 3:
2435     // Change NB P-State to NBP1 for MaxRdLat training
2436     if (NBPtr->ChangeNbFrequencyWrap (NBPtr, NBPtr->NbFreqChgState)) {
2437       NBPtr->ProgramNbPsDependentRegs (NBPtr);
2438
2439       // Next state is to try all NBPstates
2440       NBPtr->NbFreqChgState++;
2441
2442       // Return TRUE to repeat MaxRdLat training
2443       Status = TRUE;
2444     } else {
2445       // If transition to any NBPs fails, transition to exit state machine
2446       NBPtr->NbFreqChgState = 4;
2447     }
2448     break;
2449
2450   case 4:
2451     // Change NB P-State back to NBP0
2452     Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2453     ASSERT (Status);
2454
2455     // Return FALSE to get out of MaxRdLat training loop
2456     Status = FALSE;
2457
2458     // Exit state machine
2459     NBPtr->NbFreqChgState = 5;
2460     break;
2461
2462   default:
2463     break;
2464   }
2465
2466   return Status;
2467 }
2468
2469
2470 /* -----------------------------------------------------------------------------*/
2471 /**
2472  *
2473  *
2474  *   This function gets "Dram Term" value from data structure
2475  *
2476  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2477  *     @param[in]       ChipSel  - Targeted chipsel
2478  *
2479  *     @return       Dram Term value
2480  */
2481 UINT8
2482 MemNGetDramTermNb (
2483   IN OUT   MEM_NB_BLOCK *NBPtr,
2484   IN       UINT8 ChipSel
2485   )
2486 {
2487   UINT8 DramTerm;
2488
2489   if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT16) (1 << (ChipSel >> 1)))) != 0) {
2490     DramTerm = NBPtr->PsPtr->QR_DramTerm;
2491   } else {
2492     DramTerm = NBPtr->PsPtr->DramTerm;
2493   }
2494
2495   return DramTerm;
2496 }
2497
2498 /* -----------------------------------------------------------------------------*/
2499 /**
2500  *
2501  *
2502  *   This function gets "Dynamic Dram Term" value from data structure
2503  *
2504  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2505  *     @param[in]       ChipSel  - Targeted chipsel
2506  *
2507  *     @return       Dynamic Dram Term value
2508  */
2509 UINT8
2510 MemNGetDynDramTermNb (
2511   IN OUT   MEM_NB_BLOCK *NBPtr,
2512   IN       UINT8 ChipSel
2513   )
2514 {
2515   return (NBPtr->PsPtr->DynamicDramTerm);
2516 }
2517
2518 /* -----------------------------------------------------------------------------*/
2519 /**
2520  *
2521  *
2522  *   This function returns MR0[CL] value
2523  *
2524  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2525  *
2526  *     @return       MR0[CL] value
2527  */
2528 UINT32
2529 MemNGetMR0CLNb (
2530   IN OUT   MEM_NB_BLOCK *NBPtr
2531   )
2532 {
2533   UINT8 Tcl;
2534   UINT32 Value32;
2535
2536   Tcl = (UINT8) MemNGetBitFieldNb (NBPtr, BFTcl);
2537   Value32 = (UINT32) ((Tcl < 8) ? (Tcl << 4) : (((Tcl - 8) << 4) | 4));
2538
2539   return Value32;
2540 }
2541
2542 /* -----------------------------------------------------------------------------*/
2543 /**
2544  *
2545  *
2546  *   This function returns MR0[WR] value
2547  *
2548  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2549  *
2550  *     @return       MR0[WR] value
2551  */
2552 UINT32
2553 MemNGetMR0WRNb (
2554   IN OUT   MEM_NB_BLOCK *NBPtr
2555   )
2556 {
2557   UINT32 Value32;
2558
2559   Value32 = MemNGetBitFieldNb (NBPtr, BFTwrDDR3) << 9;
2560
2561   return Value32;
2562 }
2563
2564 /* -----------------------------------------------------------------------------*/
2565 /**
2566  *
2567  *
2568  *   This function returns MR2[CWL] value
2569  *
2570  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2571  *
2572  *     @return       MR0[CWL] value
2573  */
2574 UINT32
2575 MemNGetMR2CWLNb (
2576   IN OUT   MEM_NB_BLOCK *NBPtr
2577   )
2578 {
2579   UINT32 Value32;
2580
2581   Value32 = MemNGetBitFieldNb (NBPtr, BFTcwl) << 3;
2582
2583   return Value32;
2584 }
2585
2586 /* -----------------------------------------------------------------------------*/
2587 /**
2588  *
2589  *
2590  *   This function sets Txp and Txpdll
2591  *
2592  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2593  *
2594  *     @return       none
2595  */
2596 VOID
2597 MemNSetTxpNb (
2598   IN OUT   MEM_NB_BLOCK *NBPtr
2599   )
2600 {
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};
2603   UINT8 i;
2604   UINT8 TxpVal;
2605   UINT8 TxpdllVal;
2606   UINT16 Speed;
2607
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));
2612
2613   TxpdllVal = Txpdll[i];
2614
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)) {
2618     TxpVal = 4;
2619   } else {
2620     TxpVal = Txp[i];
2621   }
2622
2623   if (TxpVal != 0xFF) {
2624     MemNSetBitFieldNb (NBPtr, BFTxp, TxpVal);
2625   }
2626   if (TxpdllVal != 0xFF) {
2627     NBPtr->FamilySpecificHook[AdjustTxpdll] (NBPtr, &TxpdllVal);
2628     MemNSetBitFieldNb (NBPtr, BFTxpdll, TxpdllVal);
2629   }
2630 }
2631
2632 /*-----------------------------------------------------------------------------
2633  *
2634  *
2635  *     This function adjust value of Txpdll to encoded value.
2636  *
2637  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
2638  *     @param[in,out]  OptParam   - Optional parameter
2639  *
2640  *     @return    TRUE
2641  * ----------------------------------------------------------------------------
2642  */
2643 BOOLEAN
2644 MemNAdjustTxpdllClientNb (
2645   IN OUT   MEM_NB_BLOCK *NBPtr,
2646   IN OUT   VOID *OptParam
2647   )
2648 {
2649   *(UINT8 *) OptParam -= 10;
2650   return TRUE;
2651 }