AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / 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: 60556 $ @e \$Date: 2011-10-17 20:19:58 -0600 (Mon, 17 Oct 2011) $
13  *
14  **/
15 /*****************************************************************************
16 *
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 *     * Redistributions of source code must retain the above copyright
23 *       notice, this list of conditions and the following disclaimer.
24 *     * Redistributions in binary form must reproduce the above copyright
25 *       notice, this list of conditions and the following disclaimer in the
26 *       documentation and/or other materials provided with the distribution.
27 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 *       its contributors may be used to endorse or promote products derived
29 *       from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * ***************************************************************************
43 *
44 */
45
46
47 /*
48  *----------------------------------------------------------------------------
49  *                                MODULES USED
50  *
51  *----------------------------------------------------------------------------
52  */
53
54
55
56 #include "AGESA.h"
57 #include "amdlib.h"
58 #include "Ids.h"
59 #include "mport.h"
60 #include "mm.h"
61 #include "mn.h"
62 #include "mt.h"
63 #include "mu.h"
64 #include "mftds.h"
65 #include "merrhdl.h"
66 #include "cpuFamilyTranslation.h"
67 #include "OptionMemory.h"
68 #include "PlatformMemoryConfiguration.h"
69 #include "Filecode.h"
70 CODE_GROUP (G1_PEICC)
71 RDATA_GROUP (G2_PEI)
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), 0,
307                                           &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
308       if (MemClkDisMap == NULL) {
309         MemClkDisMap = NBPtr->ChannelPtr->MemClkDisMap;
310       }
311
312       // Turn off the unused CS clocks
313       CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
314
315       if (NBPtr->IsSupported[CheckMemClkCSPresent]) {
316         if (NBPtr->ChannelPtr->RegDimmPresent != 0) {
317           // All DDR3 RDIMM use only one MEMCLOCK from edge finger to the register
318           // regardless of how many Ranks are on the DIMM (Single, Dual or Quad)
319           CsPresent = (CsPresent | (CsPresent >> 1)) & 0x5555;
320         }
321       }
322       for (i = 0; i < 8; i++) {
323         if ((CsPresent & MemClkDisMap[i]) == 0) {
324           MemClkDis |= (UINT8) (1 << i);
325         }
326       }
327       //Chiplet power down
328       for (RegIndex = 0; RegIndex < GET_SIZE_OF (ChipletPDRegs); RegIndex++) {
329         if ((NBPtr->Dct == 1) && (RegIndex >= 2)) {
330           Cs1 =  MemClkDisMap[ChipletPDClkDisMap[RegIndex + 2][0]];
331           Cs2 =  MemClkDisMap[ChipletPDClkDisMap[RegIndex + 2][1]];
332         } else {
333           Cs1 =  MemClkDisMap[ChipletPDClkDisMap[RegIndex][0]];
334           Cs2 =  MemClkDisMap[ChipletPDClkDisMap[RegIndex][1]];
335         }
336         if ((CsPresent & (UINT16) (Cs1 | Cs2)) == 0) {
337           MemNSetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex], (MemNGetBitFieldNb (NBPtr, ChipletPDRegs[RegIndex]) | 0x10));
338         }
339       }
340     }
341   }
342   MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
343
344   AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
345   NBPtr->MemNInitPhyComp (NBPtr);
346
347   MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
348
349   // Program DramTerm for DDR2
350   if ((MemNGetBitFieldNb (NBPtr, BFDdr3Mode)) == 0) {
351     MemNSetBitFieldNb (NBPtr, BFDramTerm, NBPtr->PsPtr->DramTerm);
352   } else {
353     // Dynamic Dynamic DramTerm for DDR3
354     // Dram Term for DDR3 may vary based on chip selects
355     MemNSetBitFieldNb (NBPtr, BFDramTermDyn, NBPtr->PsPtr->DynamicDramTerm);
356   }
357
358   MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
359
360   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
361 }
362
363 /* -----------------------------------------------------------------------------*/
364 /**
365  *
366  *
367  *   This function gets platform specific config/timing values from the interface layer and
368  *   programs them into DCT.
369  *
370  *
371  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
372  *
373  *     @return          TRUE - An Error value lower than AGESA_FATAL may have occurred
374  *     @return          FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred
375  */
376
377 BOOLEAN
378 MemNPlatformSpecUnb (
379   IN OUT   MEM_NB_BLOCK *NBPtr
380   )
381 {
382   UINT8 MemClkDis;
383   UINT8 i;
384   UINT8 MemoryAllClocks;
385   UINT8 *MemClkDisMap;
386   UINT16 CsPresent;
387
388   if (!MemNGetPlatformCfgNb (NBPtr)) {
389     IDS_ERROR_TRAP;
390   }
391
392   if (!NBPtr->PsPtr->MemPDoPs (NBPtr)) {
393     IDS_HDT_CONSOLE (MEM_FLOW, "\tDisable DCT%d due to unsupported DIMM configuration\n", NBPtr->Dct);
394     if (!NBPtr->MemPtr->ErrorHandling (NBPtr->MCTPtr, NBPtr->Dct, EXCLUDE_ALL_CHIPSEL, &NBPtr->MemPtr->StdHeader)) {
395       ASSERT (FALSE);
396     }
397     NBPtr->DisableDCT (NBPtr);
398   } else {
399
400     MemNProgramPlatformSpecNb (NBPtr);
401     MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODT, ALL_DIMMS);
402
403     //======================================================================
404     // Disable unused MemClk to save power
405     //======================================================================
406     //
407     MemClkDis = 0;
408     MemoryAllClocks = UserOptions.CfgMemoryAllClocksOn;
409     IDS_OPTION_HOOK (IDS_ALL_MEMORY_CLOCK, &MemoryAllClocks, &(NBPtr->MemPtr->StdHeader));
410     if (!MemoryAllClocks) {
411       // Special Jedec SPD diagnostic bit - "enable all clocks"
412       if (!NBPtr->MCTPtr->Status[SbDiagClks]) {
413         MemClkDisMap = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MEMCLK_DIS, NBPtr->MCTPtr->SocketId, NBPtr->Dct, 0,
414                                             &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
415         if (MemClkDisMap == NULL) {
416           MemClkDisMap = NBPtr->ChannelPtr->MemClkDisMap;
417         }
418
419         // Turn off unused clocks
420         CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
421
422         for (i = 0; i < 8; i++) {
423           if ((CsPresent & MemClkDisMap[i]) == 0) {
424             MemClkDis |= (UINT8) (1 << i);
425           }
426         }
427
428         // Turn off unused chiplets
429         for (i = 0; i < 3; i++) {
430           if (((MemClkDis >> (i * 2)) & 0x3) == 0x3) {
431             MemNSetBitFieldNb (NBPtr, BFPhyClkConfig0 + i, 0x0010);
432           }
433         }
434       }
435     }
436     MemNSetBitFieldNb (NBPtr, BFMemClkDis, MemClkDis);
437     MemFInitTableDrive (NBPtr, MTAfterPlatformSpec);
438   }
439
440   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
441 }
442
443 /* -----------------------------------------------------------------------------*/
444 /**
445  *
446  *
447  *   This function disables the DCT and mem clock
448  *
449  *
450  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
451  *
452  */
453
454 VOID
455 MemNDisableDCTNb (
456   IN OUT   MEM_NB_BLOCK *NBPtr
457   )
458 {
459   MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
460   MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
461   MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
462
463   // To maximize power savings when DisDramInterface=1b,
464   // all of the MemClkDis bits should also be set.
465   //
466   MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
467   MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
468 }
469
470 /* -----------------------------------------------------------------------------*/
471 /**
472  *
473  *
474  *   This function disables the DCT and mem clock for client NB
475  *
476  *
477  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
478  *
479  */
480
481 VOID
482 MemNDisableDCTClientNb (
483   IN OUT   MEM_NB_BLOCK *NBPtr
484   )
485 {
486   MemNSetBitFieldNb (NBPtr, BFCKETri, 0x03);
487   MemNSetBitFieldNb (NBPtr, BFODTTri, 0x0F);
488   MemNSetBitFieldNb (NBPtr, BFChipSelTri, 0xFF);
489
490   //Wait for 24 MEMCLKs
491   MemNWaitXMemClksNb (NBPtr, 24);
492
493   // To maximize power savings when DisDramInterface=1b,
494   // all of the MemClkDis bits should also be set.
495   //
496   MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
497
498   MemNSetBitFieldNb (NBPtr, BFDramPhyStatusReg, 0x80800000);
499
500   MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
501 }
502
503 /* -----------------------------------------------------------------------------*/
504 /**
505  *
506  *
507  *   This function disables the DCT and mem clock for UNB
508  *
509  *
510  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
511  *
512  */
513
514 VOID
515 MemNDisableDCTUnb (
516   IN OUT   MEM_NB_BLOCK *NBPtr
517   )
518 {
519   MemNSetBitFieldNb (NBPtr, BFExtendedParityEn, 0);
520   MemNSetBitFieldNb (NBPtr, BFParEn, 0);
521   MemNSetBitFieldNb (NBPtr, BFCKETri, 0x0F);
522
523   //Wait for 24 MEMCLKs
524   MemNWaitXMemClksNb (NBPtr, 24);
525
526   // To maximize power savings when DisDramInterface=1b,
527   // all of the MemClkDis bits should also be set.
528   //
529   MemNSetBitFieldNb (NBPtr, BFMemClkDis, 0xFF);
530
531   MemNSetBitFieldNb (NBPtr, BFDisDramInterface, 1);
532
533   if (NBPtr->Dct == 0) {
534     MemNSetBitFieldNb (NBPtr, BFPhyPSMasterChannel, 0x100);
535   }
536 }
537
538 /* -----------------------------------------------------------------------------*/
539 /**
540  *
541  *
542  *  This function initializes the DRAM devices on all DCTs at the same time
543  *
544  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
545  *
546  */
547
548 VOID
549 MemNStartupDCTNb (
550   IN OUT   MEM_NB_BLOCK *NBPtr
551   )
552 {
553   // 1. Ensure F2x[1, 0]9C_x08[DisAutoComp] = 1.
554   // 2. BIOS waits 5 us for the disabling of the compensation engine to complete.
555   // DisAutoComp is still being set since InitPhyComp
556
557   if (NBPtr->MCTPtr->NodeMemSize != 0) {
558     // Init MemClk frequency
559     MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
560
561
562     AGESA_TESTPOINT (TpProcMemBeforeDramInit, &(NBPtr->MemPtr->StdHeader));
563     NBPtr->MemNBeforeDramInitNb (NBPtr);
564     IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq: %d MHz\n", NBPtr->DCTPtr->Timings.Speed);
565     AGESA_TESTPOINT (TpProcMemDramInit, &(NBPtr->MemPtr->StdHeader));
566     NBPtr->FeatPtr->DramInit (NBPtr->TechPtr);
567   }
568
569   // 7. Program F2x[1, 0]9C_x08[DisAutoComp] = 0.
570   // 8. BIOS must wait 750 us for the phy compensation engine
571   //    to reinitialize.
572   // DisAutoComp will be cleared after DramEnabled turns to 1
573
574 }
575
576 /* -----------------------------------------------------------------------------*/
577 /**
578  *
579  *
580  *  This function initializes the DRAM devices on all DCTs at the same time
581  *
582  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
583  *
584  */
585
586 VOID
587 MemNStartupDCTUnb (
588   IN OUT   MEM_NB_BLOCK *NBPtr
589   )
590 {
591   UINT8 Dct;
592   UINT16 FinalPllLockTime;
593
594   if (NBPtr->MCTPtr->NodeMemSize != 0) {
595     // Update NB frequency for startup DDR speed
596     NBPtr->ChangeNbFrequency (NBPtr);
597
598     if (NBPtr->FamilySpecificHook[ForcePhyToM0] (NBPtr, NULL)) {
599       // Program D18F2x[1,0]9C_x0000_000B = 80000000h. #109999.
600       MemNBrdcstSetNb (NBPtr, BFDramPhyStatusReg, 0x80000000);
601
602       // Program D18F2x[1,0]9C_x0D0F_E013[PllRegWaitTime] = 0118h. #194060.
603       MemNBrdcstSetNb (NBPtr, BFPllRegWaitTime, 0x118);
604     }
605
606     // Phy Voltage Level Programming
607     MemNPhyVoltageLevelNb (NBPtr);
608
609     // Run frequency change sequence
610     MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
611     MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
612     NBPtr->FamilySpecificHook[SetSkewMemClk] (NBPtr, NULL);
613     NBPtr->ProgramNbPsDependentRegs (NBPtr);
614     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
615       MemNSwitchDCTNb (NBPtr, Dct);
616       if ((NBPtr->DCTPtr->Timings.DctMemSize != 0)) {
617         MemNSetBitFieldNb (NBPtr, BFMemClkFreqVal, 1);
618         MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, FALSE);
619       }
620     }
621     FinalPllLockTime = 0xF;
622     NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &FinalPllLockTime);
623     if (!NBPtr->IsSupported[CsrPhyPllPdEn]) {
624       // IF (D18F2x[1,0]9C_x0D0F_E00A[CsrPhySrPllPdMode]==0) THEN program
625       // D18F2x[1,0]9C_x0D0F_E006[PllLockTime] = 0Fh
626       MemNBrdcstSetNb (NBPtr, BFPllLockTime, FinalPllLockTime);
627     }
628
629     NBPtr->FamilySpecificHook[BeforePhyFenceTraining] (NBPtr, NBPtr);
630
631     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
632       MemNSwitchDCTNb (NBPtr, Dct);
633       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
634         IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
635
636         // Phy fence programming
637         AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
638         NBPtr->PhyFenceTraining (NBPtr);
639
640         // Phy compensation initialization
641         AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
642         NBPtr->MemNInitPhyComp (NBPtr);
643         MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
644       }
645     }
646
647     AGESA_TESTPOINT (TpProcMemBeforeDramInit, &(NBPtr->MemPtr->StdHeader));
648     NBPtr->MemNBeforeDramInitNb (NBPtr);
649
650     AGESA_TESTPOINT (TpProcMemDramInit, &(NBPtr->MemPtr->StdHeader));
651     IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq: %d MHz\n", NBPtr->DCTPtr->Timings.Speed);
652     NBPtr->FeatPtr->DramInit (NBPtr->TechPtr);
653   }
654 }
655
656 /* -----------------------------------------------------------------------------*/
657 /**
658  *
659  * MemNChangeFrequencyHy:
660  *
661  *  This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
662  *
663  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
664  *
665  */
666
667 VOID
668 MemNChangeFrequencyNb (
669   IN OUT   MEM_NB_BLOCK *NBPtr
670   )
671 {
672   MEM_TECH_BLOCK *TechPtr;
673   UINT8 Dct;
674   UINT8 ChipSel;
675
676   TechPtr = NBPtr->TechPtr;
677   if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
678     // #107421
679     MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
680   }
681
682   //Program F2x[1,0]90[EnterSelfRefresh]=1.
683   //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
684   MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
685   MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
686
687   //Program F2x9C_x08[DisAutoComp]=1
688   MemNSwitchDCTNb (NBPtr, 0);
689   MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 1);
690
691   //Program F2x[1, 0]94[MemClkFreqVal] = 0.
692   MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
693
694   //Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency.
695   MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
696
697   IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
698   //Program F2x[1, 0]94[MemClkFreqVal] = 1.
699   MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
700
701   //Wait until F2x[1, 0]94[FreqChgInProg]=0.
702   MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
703
704   if (NBPtr->IsSupported[CheckPhyFenceTraining]) {
705     //Perform Phy Fence retraining after frequency changed
706     AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
707     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
708       MemNSwitchDCTNb (NBPtr, Dct);
709       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
710         IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
711         AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
712         MemNPhyFenceTrainingNb (NBPtr);
713       }
714     }
715   }
716
717   //Program F2x9C_x08[DisAutoComp]=0
718   MemNSwitchDCTNb (NBPtr, 0);
719   MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
720
721   //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
722   //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
723   MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
724   MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
725
726   if (NBPtr->MCTPtr->Status[SbRegistered]) {
727     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
728       MemNSwitchDCTNb (NBPtr, Dct);
729       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
730         TechPtr->FreqChgCtrlWrd (TechPtr);
731       }
732     }
733   }
734
735   //wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns
736   MemNWaitXMemClksNb (NBPtr, 500);
737
738   if (NBPtr->IsSupported[CheckDisDllShutdownSR] && !(NBPtr->IsSupported[SetDllShutDown])) {
739     // #107421
740     MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
741   }
742
743   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
744     IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
745     MemNSwitchDCTNb (NBPtr, Dct);
746     if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
747
748       //9.Configure the DCT to send initialization MR commands:
749       //  BIOS must reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
750       //  Program F2x[1, 0]7C similar to step #2 in Pass 1 above for the new Dimm values.
751       TechPtr->AutoCycTiming (TechPtr);
752       if (!MemNPlatformSpecNb (NBPtr)) {
753         IDS_ERROR_TRAP;
754       }
755
756       for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
757         if (NBPtr->IsSupported[CheckGetMCTSysAddr]) {
758           if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
759             // if chip select present
760             TechPtr->SendAllMRCmds (TechPtr, ChipSel);
761             // NOTE: wait 512 clocks for DLL-relock
762             MemUWait10ns (50000, NBPtr->MemPtr);  // wait 500us
763           }
764         }
765         if (NBPtr->IsSupported[CheckSendAllMRCmds]) {
766           if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
767
768             // if chip select present
769             TechPtr->SendAllMRCmds (TechPtr, ChipSel);
770           }
771         }
772       }
773       if ((NBPtr->DCTPtr->Timings.Speed == DDR1600_FREQUENCY) && (NBPtr->IsSupported[CheckDllSpeedUp])) {
774         MemNSetBitFieldNb (NBPtr, BFPhy0x0D080F11, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D080F11) | 0x2000));
775         MemNSetBitFieldNb (NBPtr, BFPhy0x0D080F10, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D080F10) | 0x2000));
776         MemNSetBitFieldNb (NBPtr, BFPhy0x0D088F30, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D088F30) | 0x2000));
777         MemNSetBitFieldNb (NBPtr, BFPhy0x0D08C030, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D08C030) | 0x2000));
778         if (Dct == 0) {
779           MemNSetBitFieldNb (NBPtr, BFPhy0x0D082F30, (MemNGetBitFieldNb (NBPtr, BFPhy0x0D082F30) | 0x2000));
780         }
781         // NOTE: wait 512 clocks for DLL-relock
782         MemUWait10ns (50000, NBPtr->MemPtr);  // wait 500us
783       }
784     }
785   }
786   // Re-enable phy compensation since it had been disabled during InitPhyComp
787   MemNSwitchDCTNb (NBPtr, 0);
788   MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 0);
789
790   MemFInitTableDrive (NBPtr, MTAfterFreqChg);
791 }
792
793
794 /* -----------------------------------------------------------------------------*/
795 /**
796  *
797  *      This function ramp up frequency the next level if it have not reached
798  *      its TargetSpeed yet.
799  *
800  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
801  *
802  *     @return          TRUE -  No fatal error occurs.
803  *     @return          FALSE - Fatal error occurs.
804  */
805
806 BOOLEAN
807 MemNRampUpFrequencyNb (
808   IN OUT   MEM_NB_BLOCK *NBPtr
809   )
810 {
811   CONST UINT16 FreqList[] = {
812     DDR400_FREQUENCY,
813     DDR533_FREQUENCY,
814     DDR667_FREQUENCY,
815     DDR800_FREQUENCY,
816     DDR1066_FREQUENCY,
817     DDR1333_FREQUENCY,
818     DDR1600_FREQUENCY,
819     DDR1866_FREQUENCY
820   };
821   UINT8 Dct;
822   UINT8 i;
823   UINT16 NewSpeed;
824   DIE_STRUCT *MCTPtr;
825
826   MCTPtr = NBPtr->MCTPtr;
827
828   // Do not change frequency when it is already at TargetSpeed
829   if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
830     return TRUE;
831   }
832
833   // Find the next supported frequency level
834   NewSpeed = NBPtr->DCTPtr->Timings.TargetSpeed;
835   for (i = 0; i < (GET_SIZE_OF (FreqList) - 1); i++) {
836     if (NBPtr->DCTPtr->Timings.Speed == FreqList[i]) {
837       NewSpeed = FreqList[i + 1];
838       break;
839     }
840   }
841   ASSERT (i < (GET_SIZE_OF (FreqList) - 1));
842   ASSERT (NewSpeed <= NBPtr->DCTPtr->Timings.TargetSpeed);
843
844   // BIOS must program both DCTs to the same frequency.
845   IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq changed: %d MHz", NBPtr->DCTPtr->Timings.Speed);
846   for (Dct = 0; Dct < MCTPtr->DctCount; Dct++) {
847     NBPtr->SwitchDCT (NBPtr, Dct);
848     NBPtr->DCTPtr->Timings.Speed = NewSpeed;
849   }
850   IDS_HDT_CONSOLE (MEM_FLOW, " -> %d MHz", NewSpeed);
851
852   NBPtr->ChangeFrequency (NBPtr);
853
854   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
855 }
856
857 /* -----------------------------------------------------------------------------*/
858 /**
859  *
860  *      This function ramp up frequency to target frequency
861  *
862  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
863  *
864  *     @return          TRUE -  No fatal error occurs.
865  *     @return          FALSE - Fatal error occurs.
866  */
867
868 BOOLEAN
869 MemNRampUpFrequencyUnb (
870   IN OUT   MEM_NB_BLOCK *NBPtr
871   )
872 {
873   UINT8 Dct;
874   DIE_STRUCT *MCTPtr;
875
876   MCTPtr = NBPtr->MCTPtr;
877
878   // Do not change frequency when it is already at TargetSpeed
879   if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
880     return TRUE;
881   }
882
883   // BIOS must program both DCTs to the same frequency.
884   IDS_HDT_CONSOLE (MEM_FLOW, "\nMemClkFreq changed: %d MHz", NBPtr->DCTPtr->Timings.Speed);
885   for (Dct = 0; Dct < MCTPtr->DctCount; Dct++) {
886     NBPtr->SwitchDCT (NBPtr, Dct);
887     NBPtr->DCTPtr->Timings.Speed = NBPtr->DCTPtr->Timings.TargetSpeed;
888   }
889   IDS_HDT_CONSOLE (MEM_FLOW, " -> %d MHz", NBPtr->DCTPtr->Timings.TargetSpeed);
890
891   NBPtr->ChangeFrequency (NBPtr);
892
893   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
894 }
895
896 /* -----------------------------------------------------------------------------*/
897 /**
898  *
899  *
900  *      This function uses calculated values from DCT.Timings structure to
901  *      program its registers.
902  *
903  *
904  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
905  *
906  */
907
908 VOID
909 MemNProgramCycTimingsNb (
910   IN OUT   MEM_NB_BLOCK *NBPtr
911   )
912 {
913   CONST CTENTRY TmgAdjTab[] = {
914     // BitField, Min, Max, Bias, Ratio_x2
915     {BFTcl, 4, 12, 4, 2},
916     {BFTrcd, 5, 12, 5, 2},
917     {BFTrp, 5, 12, 5, 2},
918     {BFTrtp, 4, 7, 4, 2},
919     {BFTras, 15, 30, 15, 2},
920     {BFTrc, 11, 42, 11, 2},
921     {BFTwrDDR3, 5, 12, 4, 2},
922     {BFTrrd, 4, 7, 4, 2},
923     {BFTwtr, 4, 7, 4, 2},
924     {BFFourActWindow, 16, 32, 14, 1}
925   };
926
927   DCT_STRUCT *DCTPtr;
928   UINT8  *MiniMaxTmg;
929   UINT8  *MiniMaxTrfc;
930   UINT8  Value8;
931   UINT8  j;
932   BIT_FIELD_NAME BitField;
933
934   DCTPtr = NBPtr->DCTPtr;
935
936   //======================================================================
937   // Program turnaround timings to their max during DRAM init and training
938   //======================================================================
939   //
940   MemNSetBitFieldNb (NBPtr, BFNonSPD, 0x28FF);
941
942   MemNSetBitFieldNb (NBPtr, BFNonSPDHi, 0x2A);
943
944   //======================================================================
945   // Program DRAM Timing values
946   //======================================================================
947   //
948   MiniMaxTmg = &DCTPtr->Timings.CasL;
949   for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
950     BitField = TmgAdjTab[j].BitField;
951
952     if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
953       MiniMaxTmg[j] = TmgAdjTab[j].Min;
954     } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
955       MiniMaxTmg[j] = TmgAdjTab[j].Max;
956     }
957
958     Value8 = (UINT8) MiniMaxTmg[j];
959
960     if (BitField == BFTwrDDR3) {
961       Value8 = (Value8 == 10) ? 9 : (Value8 >= 11) ? 10 : Value8;
962     } else if (BitField == BFTrtp) {
963       Value8 = (DCTPtr->Timings.Speed <= DDR1066_FREQUENCY) ? 4 : (DCTPtr->Timings.Speed == DDR1333_FREQUENCY) ? 5 : 6;
964     }
965
966     Value8 = Value8 - TmgAdjTab[j].Bias;
967     Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
968
969     ASSERT ((BitField == BFTcl ) ? (Value8 <= 8) :
970             (BitField == BFTrcd) ? (Value8 <= 7) :
971             (BitField == BFTrp ) ? (Value8 <= 7) :
972             (BitField == BFTrtp) ? (Value8 <= 3) :
973             (BitField == BFTras) ? (Value8 <= 15) :
974             (BitField == BFTrc ) ? (Value8 <= 31) :
975             (BitField == BFTrrd) ? (Value8 <= 3) :
976             (BitField == BFTwtr) ? (Value8 <= 3) :
977             (BitField == BFTwrDDR3) ? ((Value8 >= 1) && (Value8 <= 6)) :
978             (BitField == BFFourActWindow) ? ((Value8 >= 1) && (Value8 <= 9)) : FALSE);
979     MemNSetBitFieldNb (NBPtr, BitField, Value8);
980   }
981
982   MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
983   for (j = 0; j < 4; j++) {
984     ASSERT (MiniMaxTrfc[j] <= 4);
985     MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
986   }
987
988   MemNSetBitFieldNb (NBPtr, BFTcwl, ((DCTPtr->Timings.Speed >= DDR800_FREQUENCY) ?
989                                      (NBPtr->GetMemClkFreqId (NBPtr, DCTPtr->Timings.Speed) - 3) : 0));
990
991   MemNSetBitFieldNb (NBPtr, BFTref, 2);      // 7.8 us
992
993   //======================================================================
994   // DRAM MRS Register, set ODT
995   //======================================================================
996   //
997   // DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
998   MemNSetBitFieldNb (NBPtr, BFDrvImpCtrl, 1);
999
1000   // burst length control
1001   if (NBPtr->MCTPtr->Status[Sb128bitmode]) {
1002     MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 2);
1003   }
1004
1005   // ASR=1, auto self refresh; SRT=0
1006   MemNSetBitFieldNb (NBPtr, BFASR, 1);
1007 }
1008
1009 /* -----------------------------------------------------------------------------*/
1010 /**
1011  *
1012  *
1013  *      This function uses calculated values from DCT.Timings structure to
1014  *      program its registers.
1015  *
1016  *
1017  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1018  *
1019  */
1020
1021 VOID
1022 MemNProgramCycTimingsClientNb (
1023   IN OUT   MEM_NB_BLOCK *NBPtr
1024   )
1025 {
1026   CONST CTENTRY TmgAdjTab[] = {
1027     // BitField, Min, Max, Bias, Ratio_x2
1028     {BFTcl, 5, 14, 4, 2},
1029     {BFTrcd, 5, 14, 5, 2},
1030     {BFTrp, 5, 14, 5, 2},
1031     {BFTrtp, 4, 8, 4, 2},
1032     {BFTras, 15, 36, 15, 2},
1033     {BFTrc, 20, 49, 11, 2},
1034     {BFTwrDDR3, 5, 16, 4, 2},
1035     {BFTrrd, 4, 8, 4, 2},
1036     {BFTwtr, 4, 8, 4, 2},
1037     {BFFourActWindow, 16, 40, 14, 1}
1038   };
1039
1040   DCT_STRUCT *DCTPtr;
1041   UINT8  *MiniMaxTmg;
1042   UINT8  *MiniMaxTrfc;
1043   UINT8  Value8;
1044   UINT8  j;
1045   UINT8  Tcwl;
1046   UINT8  Trcd;
1047   INT32  TCK_ps;
1048   BIT_FIELD_NAME BitField;
1049
1050   DCTPtr = NBPtr->DCTPtr;
1051
1052   //======================================================================
1053   // Program DRAM Timing values
1054   //======================================================================
1055   //
1056   MiniMaxTmg = &DCTPtr->Timings.CasL;
1057   for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
1058     BitField = TmgAdjTab[j].BitField;
1059
1060     if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
1061       MiniMaxTmg[j] = TmgAdjTab[j].Min;
1062     } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
1063       MiniMaxTmg[j] = TmgAdjTab[j].Max;
1064     }
1065
1066     Value8 = (UINT8) MiniMaxTmg[j];
1067
1068     if (BitField == BFTwrDDR3) {
1069       if (NBPtr->IsSupported[AdjustTwr]) {
1070         Value8 ++;
1071       }
1072       Value8 = (Value8 >= 10) ? (((Value8 + 1) / 2) + 4) : Value8;
1073     }
1074
1075     if ((BitField == BFTrc) && NBPtr->IsSupported[AdjustTrc]) {
1076       Value8 -= 5;
1077     }
1078
1079     Value8 = Value8 - TmgAdjTab[j].Bias;
1080     Value8 = (Value8 * TmgAdjTab[j].Ratio_x2) >> 1;
1081
1082     ASSERT ((BitField == BFTcl ) ? ((Value8 >= 1) && (Value8 <= 10)) :
1083             (BitField == BFTrcd) ? (Value8 <= 9) :
1084             (BitField == BFTrp ) ? (Value8 <= 9) :
1085             (BitField == BFTrtp) ? (Value8 <= 4) :
1086             (BitField == BFTras) ? (Value8 <= 21) :
1087             (BitField == BFTrc ) ? (NBPtr->IsSupported[AdjustTrc] ? ((Value8 >= 4) && (Value8 <= 38)) : ((Value8 >= 9) && (Value8 <= 38))) :
1088             (BitField == BFTrrd) ? (Value8 <= 4) :
1089             (BitField == BFTwtr) ? (Value8 <= 4) :
1090             (BitField == BFTwrDDR3) ? (Value8 <= 7) :
1091             (BitField == BFFourActWindow) ? ((Value8 >= 1) && (Value8 <= 13)) : FALSE);
1092     MemNSetBitFieldNb (NBPtr, BitField, Value8);
1093   }
1094
1095   MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
1096   for (j = 0; j < 4; j++) {
1097     ASSERT (MiniMaxTrfc[j] <= 5);
1098     MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
1099   }
1100
1101   Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
1102   MemNSetBitFieldNb (NBPtr, BFTcwl, ((Tcwl > 5) ? (Tcwl - 5) : 0));
1103
1104   MemNSetBitFieldNb (NBPtr, BFTref, 2);      // Tref = 7.8 us
1105
1106   // Skid buffer can only be programmed once before Dram init
1107   if (NBPtr->DCTPtr->Timings.Speed == DDR800_FREQUENCY) {
1108     TCK_ps = 1000500 / DCTPtr->Timings.TargetSpeed;
1109     Trcd = (UINT8) ((((1000 / 40) * (UINT32)DCTPtr->Timings.DIMMTrcd) + TCK_ps - 1) / TCK_ps);
1110     MemNSetBitFieldNb (NBPtr, BFDbeSkidBufDis, (Trcd > 10) ? 0 : 1);
1111   }
1112
1113   MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0);
1114
1115 }
1116
1117 /* -----------------------------------------------------------------------------*/
1118 /**
1119  *
1120  *
1121  *      This function uses calculated values from DCT.Timings structure to
1122  *      program its registers for UNB
1123  *
1124  *
1125  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1126  *
1127  */
1128
1129 VOID
1130 MemNProgramCycTimingsUnb (
1131   IN OUT   MEM_NB_BLOCK *NBPtr
1132   )
1133 {
1134   CONST CTENTRY TmgAdjTab[] = {
1135     // BitField, Min, Max, Bias, Ratio_x2
1136     {BFTcl, 5, 14, 0, 2},
1137     {BFTrcd, 2, 19, 0, 2},
1138     {BFTrp, 2, 19, 0, 2},
1139     {BFTrtp, 4, 10, 0, 2},
1140     {BFTras, 8, 40, 0, 2},
1141     {BFTrc, 10, 56, 0, 2},
1142     {BFTwrDDR3, 5, 16, 0, 2},
1143     {BFTrrd, 4, 9, 0, 2},
1144     {BFTwtr, 4, 9, 0, 2},
1145     {BFFourActWindow, 6, 42, 0, 2}
1146   };
1147
1148   DCT_STRUCT *DCTPtr;
1149   UINT8  *MiniMaxTmg;
1150   UINT8  *MiniMaxTrfc;
1151   UINT8  Value8;
1152   UINT8  j;
1153   UINT8  Tcwl;
1154   UINT8 RdOdtTrnOnDly;
1155   BIT_FIELD_NAME BitField;
1156
1157   DCTPtr = NBPtr->DCTPtr;
1158
1159   //======================================================================
1160   // Program DRAM Timing values
1161   //======================================================================
1162   //
1163   MiniMaxTmg = &DCTPtr->Timings.CasL;
1164   for (j = 0; j < GET_SIZE_OF (TmgAdjTab); j++) {
1165     BitField = TmgAdjTab[j].BitField;
1166
1167     if (BitField == BFTrp) {
1168       if (NBPtr->IsSupported[AdjustTrp]) {
1169         MiniMaxTmg[j] ++;
1170         if (MiniMaxTmg[j] < 5) {
1171           MiniMaxTmg[j] = 5;
1172         }
1173       }
1174     }
1175
1176     if (MiniMaxTmg[j] < TmgAdjTab[j].Min) {
1177       MiniMaxTmg[j] = TmgAdjTab[j].Min;
1178     } else if (MiniMaxTmg[j] > TmgAdjTab[j].Max) {
1179       MiniMaxTmg[j] = TmgAdjTab[j].Max;
1180     }
1181
1182     Value8 = (UINT8) MiniMaxTmg[j];
1183
1184     if (BitField == BFTwrDDR3) {
1185       if ((Value8 > 8) && ((Value8 & 1) != 0)) {
1186         ASSERT (FALSE);
1187       }
1188     }
1189
1190     MemNSetBitFieldNb (NBPtr, BitField, Value8);
1191   }
1192
1193   MiniMaxTrfc = &DCTPtr->Timings.Trfc0;
1194   for (j = 0; j < 4; j++) {
1195     if ((NBPtr->DCTPtr->Timings.DctDimmValid & (1 << j)) != 0) {
1196       ASSERT (MiniMaxTrfc[j] <= 4);
1197       MemNSetBitFieldNb (NBPtr, BFTrfc0 + j, MiniMaxTrfc[j]);
1198     }
1199   }
1200
1201   Tcwl = (UINT8) (DCTPtr->Timings.Speed / 133) + 2;
1202   MemNSetBitFieldNb (NBPtr, BFTcwl, ((Tcwl > 5) ? Tcwl : 5));
1203
1204   MemNSetBitFieldNb (NBPtr, BFTref, 2);      // 7.8 us
1205
1206   RdOdtTrnOnDly = (DCTPtr->Timings.CasL > Tcwl) ? (DCTPtr->Timings.CasL - Tcwl) : 0;
1207   MemNSetBitFieldNb (NBPtr, BFRdOdtTrnOnDly, RdOdtTrnOnDly);
1208   NBPtr->FamilySpecificHook[ProgOdtControl] (NBPtr, NULL);
1209
1210   //
1211   // Program Tmod
1212   //
1213   MemNSetBitFieldNb (NBPtr, BFTmod, (DCTPtr->Timings.Speed < DDR1866_FREQUENCY) ? 0x0C :
1214                                     (DCTPtr->Timings.Speed > DDR1866_FREQUENCY) ? 0x10 : 0x0E);
1215   //
1216   // Program Tzqcs and Tzqoper
1217   //
1218   // Tzqcs max(64nCK, 80ns)
1219   MemNSetBitFieldNb (NBPtr, BFTzqcs, MIN (6, (MAX (64, MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 80)) + 15) / 16));
1220   // Tzqoper max(256nCK, 320ns)
1221   MemNSetBitFieldNb (NBPtr, BFTzqoper, MIN (0xC, (MAX (256, MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 320)) + 31) / 32));
1222 }
1223
1224 /* -----------------------------------------------------------------------------*/
1225 /**
1226  *
1227  *
1228  *   This function gets platform specific settings for the current channel
1229  *
1230  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1231  *
1232  *     @return          TRUE - All platform types defined have initialized successfully
1233  *     @return          FALSE - At least one of the platform types gave not been initialized successfully
1234  */
1235
1236 BOOLEAN
1237 MemNGetPlatformCfgNb (
1238   IN OUT   MEM_NB_BLOCK *NBPtr
1239   )
1240 {
1241   UINT8 p;
1242
1243   for (p = 0; p < MAX_PLATFORM_TYPES; p++) {
1244     ASSERT (NBPtr->MemPtr->GetPlatformCfg[p] != NULL);
1245     if (NBPtr->MemPtr->GetPlatformCfg[p] (NBPtr->MemPtr, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr) == AGESA_SUCCESS) {
1246       break;
1247     }
1248   }
1249   return (p < MAX_PLATFORM_TYPES);
1250 }
1251
1252 /* -----------------------------------------------------------------------------*/
1253 /**
1254  *
1255  *
1256  *   This function retrieves the Max latency parameters
1257  *
1258  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1259  *
1260  *     @param[in]  *MinDlyPtr - Pointer to variable to store the Minimum Delay value
1261  *     @param[in]  *MaxDlyPtr - Pointer to variable to store the Maximum Delay value
1262  *     @param[in]  *DlyBiasPtr - Pointer to variable to store Delay Bias value
1263  *     @param[in]  MaxRcvEnDly - Maximum receiver enable delay value
1264  */
1265
1266 VOID
1267 MemNGetMaxLatParamsNb (
1268   IN OUT   MEM_NB_BLOCK *NBPtr,
1269   IN       UINT16 MaxRcvEnDly,
1270   IN OUT   UINT16 *MinDlyPtr,
1271   IN OUT   UINT16 *MaxDlyPtr,
1272   IN OUT   UINT16 *DlyBiasPtr
1273   )
1274 {
1275   *MinDlyPtr = (MemNTotalSyncComponentsNb (NBPtr) + (MaxRcvEnDly >> 5)) * 2;
1276   MemNQuarterMemClk2NClkNb (NBPtr, MinDlyPtr);
1277
1278   *MaxDlyPtr = 0x3FF;
1279
1280   *DlyBiasPtr = 4;
1281   MemNQuarterMemClk2NClkNb (NBPtr, DlyBiasPtr);   // 1 MEMCLK Margin
1282
1283   *DlyBiasPtr += 1;  // add 1 NCLK
1284 }
1285
1286 /* -----------------------------------------------------------------------------*/
1287 /**
1288  *
1289  *
1290  *   This function  sets the maximum round-trip latency in the system from the processor to the DRAM
1291  *   devices and back.
1292  *
1293  *
1294  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1295  *     @param[in]     MaxRcvEnDly - Maximum receiver enable delay value
1296  *
1297  */
1298
1299 VOID
1300 MemNSetMaxLatencyNb (
1301   IN OUT   MEM_NB_BLOCK *NBPtr,
1302   IN       UINT16 MaxRcvEnDly
1303   )
1304 {
1305   UINT16 SubTotal;
1306
1307   AGESA_TESTPOINT (TpProcMemRcvrCalcLatency, &(NBPtr->MemPtr->StdHeader));
1308
1309   SubTotal = 0xC8;    // init value for MaxRdLat used in training
1310
1311
1312   if (MaxRcvEnDly != 0xFFFF) {
1313     // Get all sync components BKDG steps 1-5
1314     SubTotal = MemNTotalSyncComponentsNb (NBPtr);
1315
1316     // Add the maximum (worst case) delay value of DqsRcvEnGrossDelay
1317     // that exists across all DIMMs and byte lanes.
1318     //
1319     SubTotal += MaxRcvEnDly >> 5;
1320
1321
1322     // Add 14.5 to the sub-total. 14.5 represents part of the processor
1323     // specific constant delay value in the DRAM clock domain.
1324     //
1325     SubTotal <<= 1;             // scale 1/2 MemClk to 1/4 MemClk
1326     SubTotal += 29;             // add 14.5 1/2 MemClk
1327
1328     // Convert the sub-total (in 1/2 MEMCLKs) to northbridge clocks (NCLKs)
1329     // as follows (assuming DDR400 and assuming that no P-state or link speed
1330     // changes have occurred).
1331     //
1332     MemNQuarterMemClk2NClkNb (NBPtr, &SubTotal);
1333
1334     // Add 2 NCLKs to the sub-total. 2 represents part of the processor
1335     // specific constant value in the northbridge clock domain.
1336     //
1337     SubTotal += 2;
1338   }
1339
1340   NBPtr->DCTPtr->Timings.MaxRdLat = SubTotal;
1341   // Program the F2x[1, 0]78[MaxRdLatency] register with the total delay value
1342   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRdLat: %03x\n", SubTotal);
1343   MemNSetBitFieldNb (NBPtr, BFMaxLatency, SubTotal);
1344 }
1345
1346 /* -----------------------------------------------------------------------------*/
1347 /**
1348  *
1349  *
1350  *   This function sends the ZQCL command
1351  *
1352  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1353  *
1354  */
1355
1356 VOID
1357 MemNSendZQCmdNb (
1358   IN OUT   MEM_NB_BLOCK *NBPtr
1359   )
1360 {
1361   // 1.Program MrsAddress[10]=1
1362   MemNSetBitFieldNb (NBPtr, BFMrsAddress, (UINT32)1 << 10);
1363
1364   // 2.Set SendZQCmd=1
1365   MemNSetBitFieldNb (NBPtr, BFSendZQCmd, 1);
1366
1367   // 3.Wait for SendZQCmd=0
1368   MemNPollBitFieldNb (NBPtr, BFSendZQCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
1369
1370   // 4.Wait 512 MEMCLKs
1371   MemNWaitXMemClksNb (NBPtr, 512);
1372 }
1373
1374
1375 /*----------------------------------------------------------------------------
1376  *                              LOCAL FUNCTIONS
1377  *
1378  *----------------------------------------------------------------------------
1379  */
1380
1381 /* -----------------------------------------------------------------------------*/
1382 /**
1383  *
1384  *
1385  *   This function is used to create the DRAM map
1386  *
1387  *
1388  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1389  */
1390
1391 VOID
1392 STATIC
1393 MemNAfterStitchMemNb (
1394   IN OUT   MEM_NB_BLOCK *NBPtr
1395   )
1396 {
1397   if (NBPtr->MCTPtr->GangedMode) {
1398     NBPtr->MCTPtr->NodeMemSize = NBPtr->DCTPtr->Timings.DctMemSize;
1399     NBPtr->MCTPtr->NodeSysLimit = NBPtr->MCTPtr->NodeMemSize - 1;
1400     NBPtr->MCTPtr->DctData[1].Timings.CsPresent = NBPtr->DCTPtr->Timings.CsPresent;
1401     NBPtr->MCTPtr->DctData[1].Timings.CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled;
1402     NBPtr->MCTPtr->DctData[1].Timings.DctMemSize = NBPtr->DCTPtr->Timings.DctMemSize;
1403   } else {
1404     // In unganged mode, add DCT0 and DCT1 to NodeMemSize
1405     NBPtr->MCTPtr->NodeMemSize += NBPtr->DCTPtr->Timings.DctMemSize;
1406     NBPtr->MCTPtr->NodeSysLimit = NBPtr->MCTPtr->NodeMemSize - 1;
1407   }
1408 }
1409
1410
1411 /* -----------------------------------------------------------------------------*/
1412 /**
1413  *
1414  *
1415  *       This function Return the binary value of tfaw associated with
1416  *       the index k
1417  *
1418  *     @param[in]     k value
1419  *
1420  *     @return       F[k], in Binary MHz.
1421  */
1422
1423 UINT8
1424 MemNGet1KTFawTkNb (
1425   IN       UINT8 k
1426   )
1427 {
1428   CONST UINT8 Tab1KTfawTK[] = {0, 8, 10, 13, 14, 19};
1429   ASSERT (k <= 5);
1430   return Tab1KTfawTK[k];
1431 }
1432
1433 /* -----------------------------------------------------------------------------*/
1434 /**
1435  *
1436  *
1437  *       This function Return the binary value of the 2KTFaw associated with
1438  *       the index k
1439  *
1440  *     @param[in]     k value
1441  *
1442  *     @return       2KTFaw converted based on k.
1443  */
1444
1445 UINT8
1446 MemNGet2KTFawTkNb (
1447   IN       UINT8 k
1448   )
1449 {
1450   CONST UINT8 Tab2KTfawTK[] = {0, 10, 14, 17, 18, 24};
1451   ASSERT (k <= 5);
1452   return Tab2KTfawTK[k];
1453 }
1454
1455 /* -----------------------------------------------------------------------------*/
1456 /**
1457  *
1458  *
1459  *   This function converts the sub-total (in 1/4 MEMCLKs) to northbridge clocks (NCLKs)
1460  *      (assuming DDR400 and assuming that no P-state or link speed
1461  *      changes have occurred).
1462  *
1463  *
1464  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1465  *     @param[in,out]   *SubTotalPtr - pointer to Sub-Total
1466  */
1467
1468 VOID
1469 STATIC
1470 MemNQuarterMemClk2NClkNb (
1471   IN OUT   MEM_NB_BLOCK *NBPtr,
1472   IN OUT   UINT16 *SubTotalPtr
1473   )
1474 {
1475   UINT32 NBFreq;
1476   UINT32 MemFreq;
1477
1478   // Multiply SubTotal by NB COF
1479   NBFreq = (MemNGetBitFieldNb (NBPtr, BFNbFid) + 4) * 200;
1480   // Divide SubTotal by 4 times current MemClk frequency
1481   MemFreq = NBPtr->DCTPtr->Timings.Speed * 4;
1482   *SubTotalPtr = (UINT16) (((NBFreq * (*SubTotalPtr)) + MemFreq - 1) / MemFreq);  // round up
1483 }
1484
1485 /* -----------------------------------------------------------------------------*/
1486 /**
1487  *
1488  *
1489  *   This function gets the total of sync components for Max Read Latency calculation
1490  *
1491  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1492  *
1493  *     @return      Total in 1/2 MEMCLKs
1494  */
1495
1496 UINT16
1497 MemNTotalSyncComponentsNb (
1498   IN OUT   MEM_NB_BLOCK *NBPtr
1499   )
1500 {
1501   UINT16 SubTotal;
1502
1503   // Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs UINTs.
1504   SubTotal = (UINT16) MemNGetBitFieldNb (NBPtr, BFTcl) + 1;
1505   if ((MemNGetBitFieldNb (NBPtr, BFDdr3Mode)) != 0) {
1506     SubTotal += 3;
1507   }
1508   SubTotal *= 2;
1509
1510   // If registered DIMMs are being used then add 1 MEMCLK to the sub-total.
1511   if ((MemNGetBitFieldNb (NBPtr, BFUnBuffDimm)) == 0) {
1512     SubTotal += 2;
1513   }
1514
1515   // If (F2x[1, 0]9C_x04[AddrCmdSetup] and F2x[1, 0]9C_x04[CsOdtSetup] and F2x[1, 0]9C_x04[Cke-Setup] = 0) then K = K + 1
1516   // If (F2x[1, 0]9C_x04[AddrCmdSetup] or F2x[1, 0]9C_x04[CsOdtSetup] or F2x[1, 0]9C_x04[CkeSetup] = 1) then K = K + 2
1517   if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) {
1518     SubTotal += 1;
1519   } else {
1520     SubTotal += 2;
1521   }
1522
1523   // If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
1524   // then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total.
1525   //
1526   SubTotal = SubTotal + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit));
1527
1528   return SubTotal;
1529 }
1530
1531 /* -----------------------------------------------------------------------------*/
1532 /**
1533  *
1534  *
1535  *   This function swaps bits for OnDimmMirror support
1536  *
1537  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1538  *
1539  */
1540
1541 VOID
1542 MemNSwapBitsNb (
1543   IN OUT   MEM_NB_BLOCK *NBPtr
1544   )
1545 {
1546   UINT8 ChipSel;
1547   UINT32 MRSReg;
1548
1549   ChipSel = (UINT8) MemNGetBitFieldNb (NBPtr, BFMrsChipSel);
1550   if ((ChipSel & 1) != 0) {
1551     MRSReg = MemNGetBitFieldNb (NBPtr, BFDramInitRegReg);
1552     if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
1553       MRSReg = (MRSReg & 0xFFFCFE07) | ((MRSReg&0x100A8) << 1) | ((MRSReg&0x20150) >> 1);
1554       MemNSetBitFieldNb (NBPtr, BFDramInitRegReg, MRSReg);
1555     }
1556   }
1557 }
1558
1559 /* -----------------------------------------------------------------------------*/
1560 /**
1561  *
1562  *
1563  *   This function swaps bits for OnDimmMirror support for Unb
1564  *
1565  *     Dimm Mirroring Requires that, during MRS command cycles, the following
1566  *     bits are swapped by software
1567  *
1568  *             A3 -> A4         A7 -> A8
1569  *             A4 -> A3         BA0 -> BA1
1570  *             A5 -> A6         BA1 -> BA0
1571  *             A6 -> A5
1572  *
1573  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1574  *
1575  */
1576
1577 VOID
1578 MemNSwapBitsUnb (
1579   IN OUT   MEM_NB_BLOCK *NBPtr
1580   )
1581 {
1582   UINT8 ChipSel;
1583   UINT32 MRSBank;
1584   UINT32 MRSAddr;
1585
1586   ChipSel = (UINT8) MemNGetBitFieldNb (NBPtr, BFMrsChipSel);
1587   if ((ChipSel & 1) != 0) {
1588     if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
1589       MRSBank = MemNGetBitFieldNb (NBPtr, BFMrsBank);
1590       MRSAddr = MemNGetBitFieldNb (NBPtr, BFMrsAddress);
1591
1592       IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d MR%d %05x swapped to ->",
1593                                                                     (ChipSel & 0x7),
1594                                                                     (MRSBank & 0x7),
1595                                                                     (MRSAddr & 0x3FFFF));
1596       //
1597       // Swap Mrs Bank bits 0 with 1
1598       MRSBank = (MRSBank & 0x0100) | ((MRSBank & 0x01) << 1) | ((MRSBank & 0x02) >> 1);
1599       //
1600       // Swap Mrs Address bits 3 with 4, 5 with 6, and 7 with 8
1601       MRSAddr = (MRSAddr & 0x03FE07) | ((MRSAddr&0x000A8) << 1) | ((MRSAddr&0x00150) >> 1);
1602       MemNSetBitFieldNb (NBPtr, BFMrsBank, MRSBank);
1603       MemNSetBitFieldNb (NBPtr, BFMrsAddress, MRSAddr);
1604     }
1605   }
1606 }
1607
1608 /* -----------------------------------------------------------------------------*/
1609 /**
1610  *
1611  *   Programs Address/command timings, driver strengths, and tri-state fields.
1612  *
1613  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1614  *
1615  */
1616 VOID
1617 MemNProgramPlatformSpecNb (
1618   IN OUT   MEM_NB_BLOCK *NBPtr
1619   )
1620 {
1621   CONST UINT8           PinType[3]  = {PSO_CKE_TRI, PSO_ODT_TRI,   PSO_CS_TRI};
1622   CONST UINT8           TabSize[3]  = {          2,           4,            8};
1623   CONST BIT_FIELD_NAME  BitField[3] = {   BFCKETri,    BFODTTri, BFChipSelTri};
1624   UINT8  *TabPtr;
1625   UINT8  i;
1626   UINT8  k;
1627   UINT8  Value;
1628   //===================================================================
1629   // Tristate unused CKE, ODT and chip select to save power
1630   //===================================================================
1631   //
1632   TabPtr = NULL;
1633   for (k = 0; k < sizeof (PinType); k++) {
1634     if (NBPtr->IsSupported[CheckFindPSOverideWithSocket]) {
1635       TabPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PinType[k], NBPtr->MCTPtr->SocketId, MemNGetSocketRelativeChannelNb (NBPtr, NBPtr->Dct, 0), 0,
1636                                     &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
1637     }
1638     if (NBPtr->IsSupported[CheckFindPSDct]) {
1639       TabPtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PinType[k], NBPtr->MCTPtr->SocketId, NBPtr->Dct, 0,
1640                                     &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
1641     }
1642     if (TabPtr == NULL) {
1643       switch (k) {
1644       case 0:
1645         TabPtr = NBPtr->ChannelPtr->CKETriMap;
1646         break;
1647       case 1:
1648         TabPtr = NBPtr->ChannelPtr->ODTTriMap;
1649         break;
1650       case 2:
1651         TabPtr = NBPtr->ChannelPtr->ChipSelTriMap;
1652         break;
1653       default:
1654         IDS_ERROR_TRAP;
1655       }
1656     }
1657     ASSERT (TabPtr != NULL);
1658
1659     Value = 0;
1660     for (i = 0; i < TabSize[k]; i++) {
1661       if ((NBPtr->DCTPtr->Timings.CsPresent & TabPtr[i]) == 0) {
1662         Value |= (UINT8) (1 << i);
1663       }
1664     }
1665
1666     if (PinType[k] == PSO_CS_TRI) {
1667       NBPtr->FamilySpecificHook[BeforeSetCsTri] (NBPtr, &Value);
1668     }
1669
1670     ASSERT (k < GET_SIZE_OF (BitField));
1671     MemNSetBitFieldNb (NBPtr, BitField[k], Value);
1672   }
1673   NBPtr->MemNBeforePlatformSpecNb (NBPtr);
1674
1675   //===================================================================
1676   // Program Address/Command timings and driver strength
1677   //===================================================================
1678   //
1679   MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ADDRTMG, ALL_DIMMS);
1680   MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_ODCCONTROL, ALL_DIMMS);
1681
1682   MemNSetBitFieldNb (NBPtr, BFSlowAccessMode, (NBPtr->ChannelPtr->SlowMode) ? 1 : 0);
1683   MemNSetBitFieldNb (NBPtr, BFODCControl, NBPtr->ChannelPtr->DctOdcCtl);
1684   MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, NBPtr->ChannelPtr->DctAddrTmg);
1685   NBPtr->FamilySpecificHook[SetDqsODT] (NBPtr, NBPtr);
1686
1687   if (NBPtr->IsSupported[CheckODTControls]) {
1688     MemNSetBitFieldNb (NBPtr, BFPhyRODTCSLow, NBPtr->ChannelPtr->PhyRODTCSLow);
1689     MemNSetBitFieldNb (NBPtr, BFPhyRODTCSHigh, NBPtr->ChannelPtr->PhyRODTCSHigh);
1690     MemNSetBitFieldNb (NBPtr, BFPhyWODTCSLow, NBPtr->ChannelPtr->PhyWODTCSLow);
1691     MemNSetBitFieldNb (NBPtr, BFPhyWODTCSHigh, NBPtr->ChannelPtr->PhyWODTCSHigh);
1692   }
1693 }
1694 /* -----------------------------------------------------------------------------*/
1695 /**
1696  *
1697  *
1698  *   This function gets the Trdrd value
1699  *
1700  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1701  *
1702  *     @return      Trdrd value
1703  */
1704
1705 UINT8
1706 MemNGetTrdrdNb (
1707   IN OUT   MEM_NB_BLOCK *NBPtr
1708   )
1709 {
1710   DCT_STRUCT *DCTPtr;
1711   INT8 Cgdd;
1712
1713   DCTPtr = NBPtr->DCTPtr;
1714
1715   // BIOS calculates Trdrd (in MEMCLKs) = CGDD / 2 + 3 clocks and programs F2x[1, 0]8C[Trdrd] with the
1716   // converted field value. BIOS rounds fractional values down.
1717   // The Critical Gross Delay Difference (CGDD) for Trdrd on any given byte lane is the largest F2x[1,
1718   // 0]9C_x[3:0][2B:10][DqsRcvEnGrossDelay] delay of any DIMM minus the F2x[1,
1719   // 0]9C_x[3:0][2B:10][DqsRcvEnGrossDelay] delay of any other DIMM.
1720
1721   Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessRcvEnDly, AccessRcvEnDly);
1722   DCTPtr->Timings.Trdrd = (Cgdd / 2) + 3;
1723
1724   // Transfer clk to reg definition, 2T is 00b, etc.
1725   DCTPtr->Timings.Trdrd -= 2;
1726   if (DCTPtr->Timings.Trdrd > 8) {
1727     DCTPtr->Timings.Trdrd = 8;
1728   }
1729
1730   return DCTPtr->Timings.Trdrd;
1731 }
1732
1733
1734 /* -----------------------------------------------------------------------------*/
1735 /**
1736  *
1737  *
1738  *   This function gets the Twrwr value
1739  *
1740  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1741  *
1742  *     @return      Twrwr value
1743  */
1744
1745 UINT8
1746 MemNGetTwrwrNb (
1747   IN OUT   MEM_NB_BLOCK *NBPtr
1748   )
1749 {
1750   DCT_STRUCT *DCTPtr;
1751   INT8 Cgdd;
1752
1753   DCTPtr = NBPtr->DCTPtr;
1754
1755   // Twrwr (in MEMCLKs) = CGDD / 2 + 3 clocks and programs F2x[1, 0]8C[Twrwr] with the
1756   // converted field value. BIOS rounds fractional values down.
1757   // On any given byte lane, the largest F2x[1, 0]9C_x[3:0][A, 7, 6, 0][2:1]:F2x[1, 0]9C_x[3:0][A, 7, 6,
1758   // 0]3[WrDatGrossDlyByte] delay of any DIMM minus the F2x[1, 0]9C_x[3:0][A, 7, 6, 0][2:1]:F2x[1,
1759   // 0]9C_x[3:0][A, 7, 6, 0]3[WrDatGrossDlyByte] delay of any other DIMM is equal to the Critical Gross
1760   // Delay Difference (CGDD) for Twrwr.
1761
1762   Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessWrDatDly, AccessWrDatDly);
1763   DCTPtr->Timings.Twrwr = (Cgdd / 2) + 3;
1764   NBPtr->TechPtr->AdjustTwrwr (NBPtr->TechPtr);
1765
1766   return DCTPtr->Timings.Twrwr;
1767 }
1768
1769 /* -----------------------------------------------------------------------------*/
1770 /**
1771  *
1772  *
1773  *   This function gets the Twrrd value. BIOS calculates Twrrd (in MEMCLKs) = CGDD / 2 - LD + 3 clocks and programs
1774  * F2x[1, 0]8C[Twrrd] with the converted field value. BIOS rounds fractional
1775  * values down.
1776  *
1777  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1778  *
1779  *     @return  Value to be programmed to Twrrd field
1780  *              pDCT->Timings.Twrrd updated
1781  */
1782
1783 UINT8
1784 MemNGetTwrrdNb (
1785   IN OUT   MEM_NB_BLOCK *NBPtr
1786   )
1787 {
1788   INT8 Cgdd;
1789   INT8 Ld;
1790   INT8 Twrrd;
1791   DCT_STRUCT *DCTPtr;
1792
1793   DCTPtr = NBPtr->DCTPtr;
1794
1795   //
1796   // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS
1797   // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive
1798   // value.
1799   // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1800   //
1801   Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1802
1803   // On any given byte lane, the largest WrDatGrossDlyByte delay of any DIMM
1804   // minus the DqsRcvEnGrossDelay delay of any other DIMM is
1805   // equal to the Critical Gross Delay Difference (CGDD) for Twrrd.
1806   Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessWrDatDly, AccessRcvEnDly);
1807   Twrrd = (Cgdd / 2) - Ld + 3;
1808   DCTPtr->Timings.Twrrd = (UINT8) ((Twrrd >= 0) ? Twrrd : 0);
1809   NBPtr->TechPtr->AdjustTwrrd (NBPtr->TechPtr);
1810
1811   return DCTPtr->Timings.Twrrd;
1812 }
1813
1814 /* -----------------------------------------------------------------------------*/
1815 /**
1816  *
1817  *
1818  *   This function gets the TrwtTO value
1819  *
1820  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1821  *
1822  *     @return  pDCT->Timings.TrwtTO updated
1823  */
1824
1825 UINT8
1826 MemNGetTrwtTONb (
1827   IN OUT   MEM_NB_BLOCK *NBPtr
1828   )
1829 {
1830   INT8 Cgdd;
1831   INT8 Ld;
1832   INT8 TrwtTO;
1833   DCT_STRUCT *DCTPtr;
1834
1835   DCTPtr = NBPtr->DCTPtr;
1836   //
1837   // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS
1838   // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive
1839   // value.
1840   // For DDR2, LD is always one clock (For DDR2, Tcwl is always Tcl minus 1).
1841   //
1842   Ld = NBPtr->TechPtr->GetLD (NBPtr->TechPtr);
1843
1844   // On any byte lane, the largest DqsRcvEnGrossDelay delay of any DIMM minus
1845   // the WrDatGrossDlyByte delay of any other DIMM is equal to the Critical Gross
1846   // Delay Difference (CGDD) for TrwtTO.
1847   Cgdd = MemNGetOptimalCGDDNb (NBPtr, AccessRcvEnDly, AccessWrDatDly);
1848   TrwtTO = (Cgdd / 2) + Ld + 3;
1849   TrwtTO -= 2;
1850   DCTPtr->Timings.TrwtTO = (UINT8) ((TrwtTO > 1) ? TrwtTO : 1);
1851
1852   return DCTPtr->Timings.TrwtTO;
1853 }
1854
1855 /* -----------------------------------------------------------------------------*/
1856 /**
1857  *
1858  *
1859  *   This function gets the TrwtWB value
1860  *
1861  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1862  *
1863  *     @return      TrwtWB value
1864  */
1865 UINT8
1866 MemNGetTrwtWBNb (
1867   IN OUT   MEM_NB_BLOCK *NBPtr
1868   )
1869 {
1870   DCT_STRUCT *DCTPtr;
1871
1872   DCTPtr = NBPtr->DCTPtr;
1873
1874   // TrwtWB ensures read-to-write data-bus turnaround.
1875   // This value should be one more than the programmed TrwtTO.
1876   return DCTPtr->Timings.TrwtWB = DCTPtr->Timings.TrwtTO;
1877 }
1878
1879 /* -----------------------------------------------------------------------------*/
1880 /**
1881  *
1882  *
1883  *   This function converts MemClk frequency in MHz to MemClkFreq value
1884  *
1885  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1886  *     @param[in]       Speed   - MemClk frequency in MHz
1887  *
1888  *     @return      MemClkFreq value
1889  */
1890 UINT8
1891 MemNGetMemClkFreqIdNb (
1892   IN OUT   MEM_NB_BLOCK *NBPtr,
1893   IN       UINT16 Speed
1894   )
1895 {
1896   return (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
1897 }
1898
1899 /* -----------------------------------------------------------------------------*/
1900 /**
1901  *
1902  *
1903  *   This function enables swapping interleaved region feature.
1904  *
1905  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1906  *     @param[in]   Base   - Swap interleaved region base [47:27]
1907  *     @param[in]   Limit   - Swap interleaved region limit [47:27]
1908  *
1909  */
1910 VOID
1911 MemNEnableSwapIntlvRgnNb (
1912   IN OUT   MEM_NB_BLOCK *NBPtr,
1913   IN       UINT32 Base,
1914   IN       UINT32 Limit
1915   )
1916 {
1917   UINT32 Size;
1918   UINT32 SizeOfAlign;
1919
1920   // Swapped interleaving region must be below 16G
1921   if (Limit < (1 << (34 - 27))) {
1922     // Adjust Base and Size to meet :
1923     // 1. The size of the swapped region must be less than or equal to the alignment of F2x10C[IntLvRegionBase].
1924     // 2. Entire UMA region is swapped with interleaving region.
1925     Size = Limit - Base;
1926     SizeOfAlign = (UINT32) 1 << LibAmdBitScanForward (Base);
1927     while (SizeOfAlign <= Size) {
1928       // In case of SizeOfAlign <= Size, UmaBase -= 128MB, SizeOfIntlvrgn += 128MB.
1929       Base -= 1;
1930       Size += 1;
1931       SizeOfAlign = (UINT32) 1 << LibAmdBitScanForward (Base);
1932     }
1933     MemNSetBitFieldNb (NBPtr, BFIntLvRgnBaseAddr, Base);
1934     MemNSetBitFieldNb (NBPtr, BFIntLvRgnLmtAddr, (Limit - 1));
1935     MemNSetBitFieldNb (NBPtr, BFIntLvRgnSize, Size);
1936     MemNSetBitFieldNb (NBPtr, BFIntLvRgnSwapEn, 1);
1937   }
1938 }
1939
1940 /* -----------------------------------------------------------------------------*/
1941 /**
1942  *
1943  *
1944  *   This function converts MemClk frequency in MHz to MemClkFreq value
1945  *
1946  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1947  *     @param[in]       Speed   - MemClk frequency in MHz
1948  *
1949  *     @return      MemClkFreq value
1950  */
1951 UINT8
1952 MemNGetMemClkFreqIdClientNb (
1953   IN OUT   MEM_NB_BLOCK *NBPtr,
1954   IN       UINT16 Speed
1955   )
1956 {
1957   return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1958 }
1959
1960 /* -----------------------------------------------------------------------------*/
1961 /**
1962  *
1963  *
1964  *   This function converts MemClk frequency in MHz to MemClkFreq value
1965  *
1966  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1967  *     @param[in]       Speed   - MemClk frequency in MHz
1968  *
1969  *     @return      MemClkFreq value
1970  */
1971 UINT8
1972 MemNGetMemClkFreqIdUnb (
1973   IN OUT   MEM_NB_BLOCK *NBPtr,
1974   IN       UINT16 Speed
1975   )
1976 {
1977   return (UINT8) ((Speed > DDR400_FREQUENCY) ? ((Speed / 33) - 6) : ((Speed == DDR400_FREQUENCY) ? 2 : (Speed / 55)));
1978 }
1979
1980 /* -----------------------------------------------------------------------------*/
1981 /**
1982  *
1983  *
1984  *   This function converts MemClkFreq Id value to MemClk frequency in MHz
1985  *
1986  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
1987  *     @param[in]       FreqId   - FreqId from Register
1988  *
1989  *     @return          MemClk frequency in MHz
1990  */
1991 UINT16
1992 MemNGetMemClkFreqUnb (
1993   IN OUT   MEM_NB_BLOCK *NBPtr,
1994   IN       UINT8 FreqId
1995   )
1996 {
1997   UINT16 MemClkFreq;
1998   if (FreqId > 2) {
1999     MemClkFreq = (FreqId == 14) ? 667 : (300 + ((FreqId - 3) * 33) + (FreqId - 3) / 3);
2000   } else if (FreqId == 2) {
2001     MemClkFreq = 200;
2002   } else {
2003     MemClkFreq = 50 + (50 * FreqId);
2004   }
2005   return MemClkFreq;
2006 }
2007
2008 /* -----------------------------------------------------------------------------*/
2009 /**
2010  *
2011  *  This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
2012  *  for client NB.
2013  *
2014  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2015  *
2016  */
2017
2018 VOID
2019 MemNChangeFrequencyClientNb (
2020   IN OUT   MEM_NB_BLOCK *NBPtr
2021   )
2022 {
2023   MEM_TECH_BLOCK *TechPtr;
2024   UINT8 Dct;
2025   UINT8 ChipSel;
2026   UINT16 FinalPllLockTime;
2027   BOOLEAN FrequencyChangeSuccess;
2028   UINT64  OrgMMIOCfgBase;
2029   UINT64  NewMMIOCfgBase;
2030
2031   TechPtr = NBPtr->TechPtr;
2032
2033   // Disable MMIO to prevent speculative DRAM reads during self refresh
2034   LibAmdMsrRead (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2035   NewMMIOCfgBase = OrgMMIOCfgBase & (~(BIT0));
2036   LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &NewMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2037
2038   MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
2039
2040   //Program F2x[1,0]90[EnterSelfRefresh]=1.
2041   //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
2042   MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
2043   MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2044
2045   if (NBPtr->ChangeNbFrequency (NBPtr)) {
2046     // Reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
2047     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2048       MemNSwitchDCTNb (NBPtr, Dct);
2049       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2050         TechPtr->AutoCycTiming (TechPtr);
2051         if (!MemNPlatformSpecUnb (NBPtr)) {
2052           IDS_ERROR_TRAP;
2053         }
2054       }
2055     }
2056
2057     // 1. Program PllLockTime to Family-specific value
2058     MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
2059
2060     // 2. Program D18F2x[1,0]94[MemClkFreqVal] = 0.
2061     MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
2062
2063     // 3. Program D18F2x[1,0]94[MemClkFreq] to the desired DRAM frequency.
2064     MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
2065
2066     // 4. Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
2067     // 5. Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
2068     // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0]. See 2.10.3.2.2.1 [DCT Transmit Fifo Schedule
2069     // Delay Programming].
2070     // 6. D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
2071     //                                                                         THEN 2 ELSE 3 ENDIF (Ontario)
2072     NBPtr->ProgramNbPsDependentRegs (NBPtr);
2073
2074     NBPtr->FamilySpecificHook[BeforeMemClkFreqVal] (NBPtr, NBPtr);
2075     IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
2076     // 7. Program D18F2x[1,0]94[MemClkFreqVal] = 1.
2077     MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 1);
2078     MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, TRUE);
2079     FinalPllLockTime = 0xF;
2080     NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &FinalPllLockTime);
2081
2082     // 8. IF (D18F2x[1,0]9C_x0D0F_E00A[CsrPhySrPllPdMode]==0) THEN program
2083     // D18F2x[1,0]9C_x0D0F_E006[PllLockTime] = 0Fh.
2084     if (!NBPtr->IsSupported[CsrPhyPllPdEn]) {
2085       MemNBrdcstSetNb (NBPtr, BFPllLockTime, FinalPllLockTime);
2086     }
2087
2088     FrequencyChangeSuccess = TRUE;
2089   } else {
2090     // If NB frequency cannot be updated, use the current speed as the target speed
2091     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2092       MemNSwitchDCTNb (NBPtr, Dct);
2093       NBPtr->DCTPtr->Timings.Speed = NBPtr->TechPtr->PrevSpeed;
2094       NBPtr->DCTPtr->Timings.TargetSpeed = NBPtr->TechPtr->PrevSpeed;
2095     }
2096     FrequencyChangeSuccess = FALSE;
2097   }
2098
2099   //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
2100   //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
2101   MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
2102   MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2103   MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
2104
2105   if (FrequencyChangeSuccess) {
2106     NBPtr->FamilySpecificHook[AfterMemClkFreqChg] (NBPtr, NULL);
2107
2108     // Perform Phy Fence training and Phy comp init after frequency change
2109     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2110       MemNSwitchDCTNb (NBPtr, Dct);
2111       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2112         IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2113
2114         // Phy fence programming
2115         AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
2116         NBPtr->PhyFenceTraining (NBPtr);
2117
2118         // Phy compensation initialization
2119         AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
2120         NBPtr->MemNInitPhyComp (NBPtr);
2121         MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
2122       }
2123     }
2124
2125     //======================================================================
2126     // Calculate and program DRAM Timings at new frequency
2127     //======================================================================
2128     //
2129     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2130       IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2131       MemNSwitchDCTNb (NBPtr, Dct);
2132       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2133         for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
2134           if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
2135             // if chip select present
2136             if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) {
2137               TechPtr->SendAllMRCmds (TechPtr, ChipSel);
2138             }
2139           }
2140         }
2141         // Wait 512 clocks for DLL-relock
2142         MemNWaitXMemClksNb (NBPtr, 512);
2143       }
2144     }
2145   }
2146
2147   // Restore MMIO setting
2148   LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2149
2150   MemFInitTableDrive (NBPtr, MTAfterFreqChg);
2151 }
2152
2153 /* -----------------------------------------------------------------------------*/
2154 /**
2155  *
2156  *  This function change MemClk frequency to the value that is specified by DCTPtr->Timings.Speed
2157  *  for UNB.
2158  *
2159  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2160  *
2161  */
2162
2163 VOID
2164 MemNChangeFrequencyUnb (
2165   IN OUT   MEM_NB_BLOCK *NBPtr
2166   )
2167 {
2168   MEM_TECH_BLOCK *TechPtr;
2169   UINT8 Dct;
2170   UINT8 ChipSel;
2171   UINT16 FinalPllLockTime;
2172   BOOLEAN FrequencyChangeSuccess;
2173   UINT64  OrgMMIOCfgBase;
2174   UINT64  NewMMIOCfgBase;
2175
2176   TechPtr = NBPtr->TechPtr;
2177
2178   // Disable MMIO to prevent speculative DRAM reads during self refresh
2179   LibAmdMsrRead (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2180   NewMMIOCfgBase = OrgMMIOCfgBase & (~(BIT0));
2181   LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &NewMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2182
2183   MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 1);
2184
2185   //Program F2x[1,0]90[EnterSelfRefresh]=1.
2186   //Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
2187   MemNBrdcstSetNb (NBPtr, BFEnterSelfRef, 1);
2188   MemNPollBitFieldNb (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2189
2190   if (NBPtr->ChangeNbFrequency (NBPtr)) {
2191     // Reprogram Twr, Tcwl, and Tcl based on the new MEMCLK frequency.
2192     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2193       MemNSwitchDCTNb (NBPtr, Dct);
2194       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2195         TechPtr->AutoCycTiming (TechPtr);
2196         if (!MemNPlatformSpecUnb (NBPtr)) {
2197           IDS_ERROR_TRAP;
2198         }
2199       }
2200     }
2201
2202     // 1. Program PllLockTime to Family-specific value
2203     MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
2204
2205     // 2. Program D18F2x[1,0]94[MemClkFreqVal] = 0.
2206     MemNBrdcstSetNb (NBPtr, BFMemClkFreqVal, 0);
2207
2208     // 3. Program D18F2x[1,0]94[MemClkFreq] to the desired DRAM frequency.
2209     MemNBrdcstSetNb (NBPtr, BFMemClkFreq, NBPtr->GetMemClkFreqId (NBPtr, NBPtr->DCTPtr->Timings.Speed));
2210
2211     // 4. Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
2212     // 5. Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
2213     // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0]. See 2.10.3.2.2.1 [DCT Transmit Fifo Schedule
2214     // Delay Programming].
2215     // 6. D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
2216     //                                                                         THEN 2 ELSE 3 ENDIF (Ontario)
2217     NBPtr->ProgramNbPsDependentRegs (NBPtr);
2218
2219     IDS_OPTION_HOOK (IDS_BEFORE_MEM_FREQ_CHG, NBPtr, &(NBPtr->MemPtr->StdHeader));
2220     // 7. Program D18F2x[1,0]94[MemClkFreqVal] = 1.
2221     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2222       MemNSwitchDCTNb (NBPtr, Dct);
2223       if ((NBPtr->DCTPtr->Timings.DctMemSize != 0)) {
2224         MemNSetBitFieldNb (NBPtr, BFMemClkFreqVal, 1);
2225         MemNPollBitFieldNb (NBPtr, BFFreqChgInProg, 0, PCI_ACCESS_TIMEOUT, FALSE);
2226       }
2227     }
2228     FinalPllLockTime = 0xF;
2229     NBPtr->FamilySpecificHook[AfterMemClkFreqVal] (NBPtr, &FinalPllLockTime);
2230
2231     // 8. IF (D18F2x[1,0]9C_x0D0F_E00A[CsrPhySrPllPdMode]==0) THEN program
2232     // D18F2x[1,0]9C_x0D0F_E006[PllLockTime] = 0Fh.
2233     if (!NBPtr->IsSupported[CsrPhyPllPdEn]) {
2234       MemNBrdcstSetNb (NBPtr, BFPllLockTime, FinalPllLockTime);
2235     }
2236
2237     FrequencyChangeSuccess = TRUE;
2238   } else {
2239     // If NB frequency cannot be updated, use the current speed as the target speed
2240     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2241       MemNSwitchDCTNb (NBPtr, Dct);
2242       NBPtr->DCTPtr->Timings.Speed = NBPtr->TechPtr->PrevSpeed;
2243       NBPtr->DCTPtr->Timings.TargetSpeed = NBPtr->TechPtr->PrevSpeed;
2244     }
2245     FrequencyChangeSuccess = FALSE;
2246   }
2247
2248   if (FrequencyChangeSuccess) {
2249     // Perform Phy Fence training and Phy comp init after frequency change
2250     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2251       MemNSwitchDCTNb (NBPtr, Dct);
2252       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2253         IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2254
2255         // Phy fence programming
2256         AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader));
2257         NBPtr->PhyFenceTraining (NBPtr);
2258
2259         // Phy compensation initialization
2260         AGESA_TESTPOINT (TPProcMemPhyCompensation, &(NBPtr->MemPtr->StdHeader));
2261         NBPtr->MemNInitPhyComp (NBPtr);
2262         MemProcessConditionalOverrides (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr, PSO_ACTION_SLEWRATE, ALL_DIMMS);
2263       }
2264     }
2265   }
2266
2267   //Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
2268   //Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
2269   MemNBrdcstSetNb (NBPtr, BFExitSelfRef, 1);
2270   MemNPollBitFieldNb (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE);
2271   if (NBPtr->IsSupported[SetDllShutDown]) {
2272     MemNBrdcstSetNb (NBPtr, BFDisDllShutdownSR, 0);
2273   }
2274
2275   if (FrequencyChangeSuccess) {
2276     NBPtr->FamilySpecificHook[AfterMemClkFreqChg] (NBPtr, NULL);
2277
2278     //======================================================================
2279     // Calculate and program DRAM Timings at new frequency
2280     //======================================================================
2281     //
2282     for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2283       IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
2284       MemNSwitchDCTNb (NBPtr, Dct);
2285       if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2286         for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) {
2287           if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
2288             // if chip select present
2289             if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) {
2290               TechPtr->SendAllMRCmds (TechPtr, ChipSel);
2291             }
2292           }
2293         }
2294         // Wait 512 clocks for DLL-relock
2295         MemNWaitXMemClksNb (NBPtr, 512);
2296       }
2297     }
2298   }
2299
2300   // Restore MMIO setting
2301   LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &OrgMMIOCfgBase, &(NBPtr->MemPtr->StdHeader));
2302
2303   MemFInitTableDrive (NBPtr, MTAfterFreqChg);
2304 }
2305
2306
2307 /* -----------------------------------------------------------------------------*/
2308 /**
2309  *
2310  *  This function calculates and programs NB P-state dependent registers
2311  *
2312  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2313  *
2314  */
2315
2316 VOID
2317 MemNProgramNbPstateDependentRegistersUnb (
2318   IN OUT   MEM_NB_BLOCK *NBPtr
2319   )
2320 {
2321   UINT8 RdPtrInit;
2322
2323   RdPtrInit = (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 6 : 4;
2324   MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit);
2325   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit);
2326
2327   MemFInitTableDrive (NBPtr, MTAfterNbPstateChange);
2328
2329   IDS_HDT_CONSOLE_DEBUG_CODE (
2330     RdPtrInit = (UINT8) MemNGetBitFieldNb (NBPtr, BFRdPtrInit);
2331   );
2332
2333   switch (RdPtrInit) {
2334   case 4:
2335     if (MemNGetBitFieldNb (NBPtr, BFNbPsSel) == 0) {
2336       MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 2);
2337     } else {
2338       MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
2339     }
2340     break;
2341   case 5:
2342     MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 1);
2343     break;
2344   case 6:
2345     MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 0);
2346     break;
2347   default:
2348     ASSERT (FALSE);
2349   }
2350
2351   NBPtr->FamilySpecificHook[OverrideDataTxFifoWrDly] (NBPtr, NBPtr);
2352   IDS_OPTION_HOOK (IDS_NBPS_REG_OVERRIDE, NBPtr, &NBPtr->MemPtr->StdHeader);
2353 }
2354
2355 /* -----------------------------------------------------------------------------*/
2356 CONST UINT8 PllDivTab[] = {0, 0, 0, 2, 3, 3, 2, 3};
2357 CONST UINT8 PllMultTab[] = {0, 0, 0, 16, 32, 40, 32, 56};
2358
2359 /**
2360  *
2361  *  This function calculates and programs NB P-state dependent registers
2362  *
2363  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2364  *
2365  */
2366
2367 VOID
2368 MemNProgramNbPstateDependentRegistersClientNb (
2369   IN OUT   MEM_NB_BLOCK *NBPtr
2370   )
2371 {
2372   UINT8 i;
2373   UINT8 Dct;
2374   UINT8 NclkFid;
2375   UINT16 MemClkDid;
2376   UINT8 PllMult;
2377   UINT8 NclkDiv;
2378   UINT8 RdPtrInitMin;
2379   UINT8 RdPtrInit;
2380   UINT32 NclkPeriod;
2381   UINT32 MemClkPeriod;
2382   INT32 PartialSum2x;
2383   INT32 PartialSumSlotI2x;
2384   INT32 RdPtrInitRmdr2x;
2385   INT32 TDataProp;
2386   UINT8 NbPstate;
2387   UINT8 SlowMode;
2388
2389   NclkFid = (UINT8) (MemNGetBitFieldNb (NBPtr, BFMainPllOpFreqId) + 0x10);  // NclkFid is in 100MHz
2390
2391   MemClkDid = PllDivTab[NBPtr->DCTPtr->Timings.Speed / 133];
2392   NBPtr->FamilySpecificHook[OverridePllDiv] (NBPtr, &MemClkDid);
2393   PllMult = PllMultTab[NBPtr->DCTPtr->Timings.Speed / 133];
2394   NBPtr->FamilySpecificHook[OverridePllMult] (NBPtr, &PllMult);
2395
2396   if (NBPtr->NbFreqChgState == 2) {
2397     MemNSetBitFieldNb (NBPtr, BFNbPsCsrAccSel, 1);
2398     MemNSetBitFieldNb (NBPtr, BFNbPsDbgEn, 1);
2399     NclkDiv = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPs1NclkDiv);
2400     // Divisors less than 8 are undefined.  Maybe the CPU does not support NB P-states.
2401     if (NclkDiv < 8) {
2402       // Set a dummy divisor to prevent divide by zero exception below.
2403       NclkDiv = 8;
2404     }
2405     NbPstate = 1;
2406   } else {
2407     NclkDiv = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPs0NclkDiv);
2408     NbPstate = 0;
2409   }
2410   NclkPeriod = (2500 * NclkDiv) / NclkFid;  // (1,000,000 * 0.25 * NclkDiv) / (NclkFid * 100MHz) = ps
2411   MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
2412   NBPtr->NBClkFreq = ((UINT32) NclkFid * 400) / NclkDiv;
2413
2414   IDS_HDT_CONSOLE (MEM_FLOW, "\n\tNB P%d  Freq: %dMHz\n", NbPstate, NBPtr->NBClkFreq);
2415   IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClk Freq: %dMHz\n", NBPtr->DCTPtr->Timings.Speed);
2416   // D18F2x[1,0]78[RdPtrInit] = IF (D18F2x[1,0]94[MemClkFreq] >= 667 MHz) THEN 7 ELSE 8 ENDIF (Llano)
2417   //                                                                      THEN 2 ELSE 3 ENDIF (Ontario)
2418   RdPtrInit = RdPtrInitMin = (NBPtr->DCTPtr->Timings.Speed >= DDR1333_FREQUENCY) ? NBPtr->FreqChangeParam->RdPtrInit667orHigher : NBPtr->FreqChangeParam->RdPtrInitLower667;
2419   NBPtr->FamilySpecificHook[AdjustRdPtrInit] (NBPtr, &RdPtrInit);
2420   MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit);
2421   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit);
2422
2423   // Program D18F2x[1,0]F4_x30[DbeGskFifoNumerator] and D18F2x[1,0]F4_x31[DbeGskFifoDenominator].
2424   MemNBrdcstSetNb (NBPtr, BFDbeGskFifoNumerator, NclkFid * MemClkDid * 16);
2425   MemNBrdcstSetNb (NBPtr, BFDbeGskFifoDenominator, PllMult * NclkDiv);
2426   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDbeGskFifoNumerator: %d\n", NclkFid * MemClkDid * 16);
2427   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDbeGskFifoDenominator: %d\n", PllMult * NclkDiv);
2428
2429   // Program D18F2x[1,0]F4_x32[DataTxFifoSchedDlyNegSlot1, DataTxFifoSchedDlySlot1,
2430   // DataTxFifoSchedDlyNegSlot0, DataTxFifoSchedDlySlot0].
2431   //   PartialSum = ((7 * NclkPeriod) + (1.5 * MemClkPeriod) + 520ps)*MemClkFrequency - tCWL -
2432   //   CmdSetup - PtrSeparation - 1. (Llano)
2433   //   PartialSum = ((5 * NclkPeriod) + MemClkPeriod) + 520ps)*MemClkFrequency - tCWL -
2434   //   CmdSetup - PtrSeparation - 1. (Ontario)
2435   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
2436     MemNSwitchDCTNb (NBPtr, Dct);
2437     if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
2438       PartialSum2x = NBPtr->FreqChangeParam->NclkPeriodMul2x * NclkPeriod;
2439       PartialSum2x += NBPtr->FreqChangeParam->MemClkPeriodMul2x * MemClkPeriod;
2440       PartialSum2x += 520 * 2;
2441
2442       // PtrSeparation = ((16 + RdPtrInitMin - D18F2x[1,0]78[RdPtrInit]) MOD 16)/2 + RdPtrInitRmdr
2443       // If (D18F2x[1,0]94[MemClkFreq] >= 800 MHz)
2444       // then RdPtrInitRmdr = (((4.5 * MemClkPeriod) - 990ps) MOD MemClkPeriod)/MemClkPeriod
2445       // else RdPtrInitRmdr = (((4.5 * MemClkPeriod) - 1466ps) MOD MemClkPeriod)/MemClkPeriod
2446       TDataProp = (NBPtr->DCTPtr->Timings.Speed >= DDR1600_FREQUENCY) ?
2447                   NBPtr->FreqChangeParam->TDataProp800orHigher : NBPtr->FreqChangeParam->TDataPropLower800;
2448       RdPtrInitRmdr2x = ((NBPtr->FreqChangeParam->SyncTimeMul4x * MemClkPeriod) / 2) - 2 * (TDataProp + 520);
2449       RdPtrInitRmdr2x %= MemClkPeriod;
2450       PartialSum2x -= ((16 + RdPtrInitMin - RdPtrInit) % 16) * MemClkPeriod + RdPtrInitRmdr2x;
2451
2452       // Convert PartialSum2x to PCLK
2453       PartialSum2x = (PartialSum2x + MemClkPeriod - 1) / MemClkPeriod;  // round-up here
2454       PartialSum2x -= 2 * (MemNGetBitFieldNb (NBPtr, BFTcwl) + 5);
2455       if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) {
2456         PartialSum2x -= 1;
2457       } else {
2458         PartialSum2x -= 2;
2459       }
2460       PartialSum2x -= 2;
2461
2462       // If PartialSumSlotN is positive:
2463       //   DataTxFifoSchedDlySlotN=CEIL(PartialSumSlotN).
2464       //   DataTxFifoSchedDlyNegSlotN=0.
2465       // Else if PartialSumSlotN is negative:
2466       //   DataTxFifoSchedDlySlotN=ABS(CEIL(PartialSumSlotN*MemClkPeriod/NclkPeriod)).
2467       //   DataTxFifoSchedDlyNegSlotN=1.
2468       for (i = 0; i < 2; i++) {
2469         PartialSumSlotI2x = PartialSum2x;
2470         SlowMode = (UINT8) MemNGetBitFieldNb (NBPtr, BFSlowAccessMode);
2471         if ((i == 0) && (SlowMode == 0)) {
2472           PartialSumSlotI2x += 2;
2473         }
2474         if (NBPtr->IsSupported[SchedDlySlot1Extra] && (i == 1) && (SlowMode != 0)) {
2475           PartialSumSlotI2x -= 2;
2476         }
2477         if (PartialSumSlotI2x > 0) {
2478           MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlyNegSlot0 + i, 0);
2479           MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlySlot0 + i, (PartialSumSlotI2x + 1) / 2);
2480           IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDataTxFifoSchedDlySlot%d: %d\n", i, (PartialSumSlotI2x + 1) / 2);
2481         } else {
2482           MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlyNegSlot0 + i, 1);
2483           PartialSumSlotI2x = ((-PartialSumSlotI2x) * MemClkPeriod) / (2 * NclkPeriod);
2484           MemNSetBitFieldNb (NBPtr, BFDataTxFifoSchedDlySlot0 + i, PartialSumSlotI2x);
2485           IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDataTxFifoSchedDlySlot%d: -%d\n", i, PartialSumSlotI2x);
2486         }
2487       }
2488
2489       // Set ProcOdtAdv
2490       if ((NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY) &&
2491           ((!(NBPtr->IsSupported[EnProcOdtAdvForUDIMM])) || (NBPtr->ChannelPtr->SODimmPresent != 0))) {
2492         MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0);
2493       } else {
2494         MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000);
2495       }
2496     }
2497   }
2498
2499   MemFInitTableDrive (NBPtr, MTAfterNbPstateChange);
2500   if (NBPtr->NbFreqChgState == 2) {
2501     MemNSetBitFieldNb (NBPtr, BFNbPsDbgEn, 0);
2502     MemNSetBitFieldNb (NBPtr, BFNbPsCsrAccSel, 0);
2503   }
2504 }
2505
2506 /* -----------------------------------------------------------------------------*/
2507 /**
2508  *
2509  *
2510  *   This function gets the total of sync components for Max Read Latency calculation
2511  *
2512  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2513  *
2514  *     @return      Total in ps
2515  */
2516
2517 UINT32
2518 MemNTotalSyncComponentsClientNb (
2519   IN OUT   MEM_NB_BLOCK *NBPtr
2520   )
2521 {
2522   UINT32 P;
2523   UINT32 T;
2524   UINT8  RdPtrInitMin;
2525   UINT8  RdPtrInit;
2526   UINT32 AddrTmgCtl;
2527   UINT8  DbeGskMemClkAlignMode;
2528   UINT32 MemClkPeriod;
2529
2530   // P = P + ((16 + RdPtrInitMin - D18F2x[1,0]78[RdPtrInit]) MOD 16)
2531   RdPtrInitMin = (NBPtr->DCTPtr->Timings.Speed >= DDR1333_FREQUENCY) ? NBPtr->FreqChangeParam->RdPtrInit667orHigher : NBPtr->FreqChangeParam->RdPtrInitLower667;
2532   RdPtrInit = (UINT8) MemNGetBitFieldNb (NBPtr, BFRdPtrInit);
2533   P = (16 + RdPtrInitMin - RdPtrInit) % 16;
2534
2535   // IF (AddrCmdSetup != CkeSetup) THEN P = P + 1
2536   AddrTmgCtl = MemNGetBitFieldNb (NBPtr, BFAddrTmgControl);
2537   if (((AddrTmgCtl >> 16) & 0x20) != (AddrTmgCtl & 0x20)) {
2538     P += 1;
2539   }
2540
2541   // IF (DbeGskMemClkAlignMode==01b || (DbeGskMemClkAlignMode==00b && !(AddrCmdSetup==CsOdtSetup==CkeSetup)))
2542   // THEN P = P + 1
2543   DbeGskMemClkAlignMode = (UINT8) MemNGetBitFieldNb (NBPtr, BFDbeGskMemClkAlignMode);
2544   if ((DbeGskMemClkAlignMode == 1) || ((DbeGskMemClkAlignMode == 0) &&
2545       !((((AddrTmgCtl >> 16) & 0x20) == (AddrTmgCtl & 0x20)) && (((AddrTmgCtl >> 8) & 0x20) == (AddrTmgCtl & 0x20))))) {
2546     P += 1;
2547   }
2548
2549   // IF (SlowAccessMode==1) THEN P = P + 2
2550   if (MemNGetBitFieldNb (NBPtr, BFSlowAccessMode) == 1) {
2551     P += 2;
2552   }
2553
2554   // P = P + 2
2555   P += 2;
2556   T = 0;
2557
2558   // If (AddrCmdSetup==0 && CsOdtSetup==0 && CkeSetup==0)
2559   // then P = P + 1
2560   // else P = P + 2
2561   if ((AddrTmgCtl & 0x0202020) == 0) {
2562     P += 1;
2563   } else {
2564     P += 2;
2565   }
2566
2567   // P = P + (2 * (D18F2x[1,0]88[Tcl] clocks - 1))
2568   P += 2 * (NBPtr->DCTPtr->Timings.CasL - 1);
2569
2570   // If (DisCutThroughMode==0)
2571   // then P = P + 3
2572   // else P = P + 7
2573   if (MemNGetBitFieldNb (NBPtr, BFDisCutThroughMode) == 0) {
2574     P += 3;
2575   } else {
2576     P += 7;
2577   }
2578
2579   MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed;
2580   return (((P * MemClkPeriod + 1) / 2) + T);
2581 }
2582
2583 /* -----------------------------------------------------------------------------*/
2584 /**
2585  *
2586  *
2587  *   This function sets up phy power saving for client NB
2588  *
2589  *
2590  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2591  *
2592  */
2593 VOID
2594 MemNPhyPowerSavingClientNb (
2595   IN OUT   MEM_NB_BLOCK *NBPtr
2596   )
2597 {
2598   // 4. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[DllDisEarlyU] = 1b.
2599   // 5. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[DllDisEarlyL] = 1b.
2600   // 6. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]13[7:4] = 1010b.
2601   MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13Bit0to7, 0xA3);
2602   // 7. Program D18F2x[1,0]9C_x0D0F_812F[7, 5, 0] = {1b, 1b, 1b} to disable unused PAR and A[17:16] pins.
2603   MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 0xA1);
2604   // 8. Program D18F2x[1,0]9C_x0D0F_C000[LowPowerDrvStrengthEn] = 1.
2605   if (!NBPtr->FamilySpecificHook[DisLowPwrDrvStr] (NBPtr, NULL)) {
2606     MemNSetBitFieldNb (NBPtr, BFReserved00C, 0x100);
2607   }
2608   // 9. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]10[EnRxPadStandby]= IF (D18F2x[1,0]94[MemClkFreq] <=
2609   //    800 MHz) THEN 1 ELSE 0 ENDIF.
2610   MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 0x1000 : 0);
2611   // 10. Program D18F2x[1,0]9C_x0000_000D as follows:
2612   //    TxMaxDurDllNoLock/RxMaxDurDllNoLock = 7h.
2613   MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 7);
2614   MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 7);
2615   //    TxCPUpdPeriod/RxCPUpdPeriod = 011b.
2616   MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 3);
2617   MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 3);
2618   //    TxDLLWakeupTime/RxDLLWakeupTime = 11b.
2619   MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 3);
2620   MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 3);
2621
2622   IDS_OPTION_HOOK (IDS_PHY_DLL_STANDBY_CTRL, NBPtr, &NBPtr->MemPtr->StdHeader);
2623 }
2624
2625 /* -----------------------------------------------------------------------------*/
2626 /**
2627  *
2628  *
2629  *   This function sets up phy power saving for UNB
2630  *
2631  *
2632  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2633  *
2634  */
2635 VOID
2636 MemNPhyPowerSavingUnb (
2637   IN OUT   MEM_NB_BLOCK *NBPtr
2638   )
2639 {
2640   UINT16 MixedX4AndX8Dimms;
2641
2642   // 4. Program D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][DllDisEarlyU] = 1b.
2643   // 5. Program D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][DllDisEarlyL] = 1b.
2644   MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13, MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) | 3);
2645   // 6. D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][RxDqsUDllPowerDown] = (D18F2x90_dct[1:0][X4Dimm]!=0).
2646   MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13, MemNGetBitFieldNb (NBPtr, BFX4Dimm) == 0 ? (MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) | 0x80) : (MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) & 0xFF7F));
2647   // 7. D18F2x9C_x0D0F_812F_dct[1:0][PARTri] = ~D18F2x90_dct[1:0][ParEn].
2648   MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFParEn) == 0 ? (MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 1) : (MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) & 0xFFFE));
2649   // 8. D18F2x9C_x0D0F_812F_dct[1:0][Add17Tri, Add16Tri] = {1b, 1b}
2650   MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 0xA0);
2651   // 9. IF (D18F2x94_dct[1:0][MemClkFreq] <= 800 MHz && ~(mixed channel of x4 and x8 DIMMs)) THEN
2652   //    Program D18F2x9C_x0D0F_0[F,8:0]10_dct[1:0][EnRxPadStandby] = 1.
2653   //    ELSE
2654   //    Program D18F2x9C_x0D0F_0[F,8:0]10_dct[1:0][EnRxPadStandby] = 0.
2655   //    ENDIF.
2656   MixedX4AndX8Dimms = NBPtr->DCTPtr->Timings.Dimmx4Present != 0 && NBPtr->DCTPtr->Timings.Dimmx8Present != 0;
2657   MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) && !MixedX4AndX8Dimms ? 0x1000 : 0);
2658   // 10. IF (~(mixed channel of x4 and x8 DIMMs)) THEN
2659   if (MixedX4AndX8Dimms == FALSE) {
2660   //    Program D18F2x9C_x0000_000D_dct[1:0] as follows:
2661   //    TxMaxDurDllNoLock = RxMaxDurDllNoLock = 7h.
2662     MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 7);
2663     MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 7);
2664   //    TxCPUpdPeriod = RxCPUpdPeriod = 011b.
2665     MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 3);
2666     MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 3);
2667   //    TxDLLWakeupTime = RxDLLWakeupTime = 11b.
2668     MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 3);
2669     MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 3);
2670   } else {
2671   //    ELSE
2672   //    Program D18F2x9C_x0000_000D_dct[1:0][TxMaxDurDllNoLock, RxMaxDurDllNoLock, TxCPUpdPeriod,
2673   //    RxCPUpdPeriod, TxDLLWakeupTime, RxDLLWakeupTime] = {0, 0, 0, 0, 0, 0}.
2674     MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 0);
2675     MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 0);
2676     MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 0);
2677     MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 0);
2678     MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 0);
2679     MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 0);
2680   }
2681   //  11. Program D18F2x9C_x0D0F_0[F,8:0]30_dct[1:0][PwrDn] to disable unused ECC byte lane.
2682   if (NBPtr->IsSupported[CheckEccDLLPwrDnConfig]) {
2683     if (!NBPtr->MCTPtr->Status[SbEccDimms]) {
2684       MemNSetBitFieldNb (NBPtr, BFEccDLLPwrDnConf, 0x0010);
2685     }
2686   }
2687
2688   //  12. Program D18F2x9C_x0D0F_0[F,8:0]04_dct[1:0][TriDM] = IF (LRDIMM & (D18F2x90_dct[1:0][X4Dimm] == 0)) THEN 1 ELSE 0.
2689   if (NBPtr->MCTPtr->Status[SbLrdimms]) {
2690     MemNSetBitFieldNb (NBPtr, BFDataByteDMConf, (MemNGetBitFieldNb (NBPtr, BFX4Dimm) == 0) ? 0x2000 : 0);
2691   }
2692
2693   IDS_OPTION_HOOK (IDS_PHY_DLL_STANDBY_CTRL, NBPtr, &NBPtr->MemPtr->StdHeader);
2694 }
2695
2696 /* -----------------------------------------------------------------------------*/
2697 /**
2698  *
2699  *
2700  *   This function overrides the ASR and SRT value in MRS command
2701  *
2702  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2703  *
2704  */
2705 VOID
2706 MemNSetASRSRTNb (
2707   IN OUT   MEM_NB_BLOCK *NBPtr
2708   )
2709 {
2710   UINT32 MrsAddress;
2711   UINT8 Dimm;
2712   UINT8 *SpdBufferPtr;
2713
2714   // Look for MR2
2715   if (NBPtr->GetBitField (NBPtr, BFMrsBank) == 2) {
2716     MrsAddress = NBPtr->GetBitField (NBPtr, BFMrsAddress);
2717     // Clear A6(ASR) and A7(SRT)
2718     MrsAddress &= (UINT32) ~0xC0;
2719     Dimm = (UINT8) (NBPtr->GetBitField (NBPtr, BFMrsChipSel) >> 1);
2720     // Make sure we access SPD of the second logical dimm of QR dimm correctly
2721     if ((Dimm >= 2) && ((NBPtr->ChannelPtr->DimmQrPresent & (UINT8) (1 << Dimm)) != 0)) {
2722       Dimm -= 2;
2723     }
2724     if (NBPtr->TechPtr->GetDimmSpdBuffer (NBPtr->TechPtr, &SpdBufferPtr, Dimm)) {
2725       // Bit 2 is ASR
2726       if (SpdBufferPtr[THERMAL_OPT] & 0x4) {
2727         // when ASR is 1, set SRT to 0
2728         MrsAddress |= 0x40;
2729       } else {
2730         // Set SRT based on bit on of thermal byte
2731         MrsAddress |= ((SpdBufferPtr[THERMAL_OPT] & 1) << 7);
2732       }
2733       NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
2734     }
2735   }
2736 }
2737
2738 /* -----------------------------------------------------------------------------*/
2739 /**
2740  *
2741  *   This function changes NB frequency as below:
2742  *     NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP0-DDRTarget
2743  *
2744  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2745  *
2746  */
2747
2748 BOOLEAN
2749 MemNChangeNbFrequencyNb (
2750   IN OUT   MEM_NB_BLOCK *NBPtr
2751   )
2752 {
2753   BOOLEAN Status;
2754
2755   Status = FALSE;
2756
2757   // State machine to change NB frequency and NB Pstate
2758   switch (NBPtr->NbFreqChgState) {
2759   case 0:
2760     // Starting up by not changing NB P state, but only updating NB frequency based on current MemClk frequency
2761     Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2762     ASSERT (Status);
2763
2764     if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
2765       // When MemClk has been ramped up to its max, transition to next state, which changes NBPstate to P1
2766       NBPtr->NbFreqChgState = 1;
2767       IDS_OPTION_HOOK (IDS_NB_PSTATE_DIDVID, NBPtr, &(NBPtr->MemPtr->StdHeader));
2768     }
2769     break;
2770
2771   case 1:
2772     // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P0
2773     MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2774
2775     // Next state would be to change NBPstate back to P0
2776     NBPtr->NbFreqChgState = 2;
2777
2778     // Update NB freq dependent registers
2779     NBPtr->ProgramNbPsDependentRegs (NBPtr);
2780
2781     // Change NB P-State to NBP1 for MaxRdLat training
2782     if (NBPtr->ChangeNbFrequencyWrap (NBPtr, 1)) {
2783       // Enable cut through mode for NB P1
2784       MemNBrdcstSetNb (NBPtr, BFDisCutThroughMode, 0);
2785
2786       // Return TRUE to repeat MaxRdLat training
2787       Status = TRUE;
2788
2789     } else {
2790       // If transition to NB-P1 fails, transition to exit state machine
2791       NBPtr->NbFreqChgState = 3;
2792     }
2793     break;
2794
2795   case 2:
2796     // Clear ForceCasToSlot0 after MaxRdLatency training is completed for NB-P1
2797     MemNBrdcstSetNb (NBPtr, BFForceCasToSlot0, 0);
2798
2799     // Change NB P-State back to NBP0
2800     Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2801     ASSERT (Status);
2802
2803     // Return FALSE to get out of MaxRdLat training loop
2804     Status = FALSE;
2805
2806     // Exit state machine
2807     NBPtr->NbFreqChgState = 3;
2808     break;
2809
2810   default:
2811     break;
2812   }
2813
2814   return Status;
2815 }
2816
2817 /*-----------------------------------------------------------------------------
2818  *
2819  *
2820  *     This function programs registers before phy fence training for CNB
2821  *
2822  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
2823  *     @param[in,out]  OptParam   - Optional parameter
2824  *
2825  *     @return    TRUE
2826  * ----------------------------------------------------------------------------
2827  */
2828 BOOLEAN
2829 MemNBeforePhyFenceTrainingClientNb (
2830   IN OUT   MEM_NB_BLOCK *NBPtr,
2831   IN OUT   VOID *OptParam
2832   )
2833 {
2834   IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClkAlign=0\n");
2835   MemNBrdcstSetNb (NBPtr, BFDbeGskMemClkAlignMode, 0);
2836
2837   IDS_HDT_CONSOLE (MEM_FLOW, "\tEnDramInit = 1 for both DCTs\n");
2838   MemNBrdcstSetNb (NBPtr, BFEnDramInit, 1);
2839
2840   return TRUE;
2841 }
2842
2843 /* -----------------------------------------------------------------------------*/
2844 /**
2845  *
2846  *   This function changes NB frequency foras below:
2847  *     NBP0-DDR800 -> NBP0-DDR1066 -> ... -> NBP0-DDRTarget -> NBP1-DDRTarget -> NBP2-DDRTarget -> NBP3-DDRTarget -> NBP0-DDRTarget
2848  *
2849  *
2850  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2851  *
2852  */
2853
2854 BOOLEAN
2855 MemNChangeNbFrequencyUnb (
2856   IN OUT   MEM_NB_BLOCK *NBPtr
2857   )
2858 {
2859   BOOLEAN Status;
2860
2861   Status = FALSE;
2862
2863   // State machine to change NB frequency and NB Pstate
2864   switch (NBPtr->NbFreqChgState) {
2865   case 0:
2866     // Do not change NB Pstate, just to save initial NB Pstate value
2867     Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2868     if (NBPtr->DCTPtr->Timings.Speed == NBPtr->DCTPtr->Timings.TargetSpeed) {
2869       // When MemClk has been ramped up to its max, transition to next state, which changes NBPstate to P1
2870       NBPtr->NbFreqChgState = 1;
2871       IDS_OPTION_HOOK (IDS_NB_PSTATE_DIDVID, NBPtr, &(NBPtr->MemPtr->StdHeader));
2872     }
2873     break;
2874
2875   case 1:
2876   case 2:
2877   case 3:
2878     // Change NB P-State to NBP1 for MaxRdLat training
2879     if (NBPtr->ChangeNbFrequencyWrap (NBPtr, NBPtr->NbFreqChgState)) {
2880       // Next state is to try all NBPstates
2881       NBPtr->NbFreqChgState++;
2882
2883       // Return TRUE to repeat MaxRdLat training
2884       Status = TRUE;
2885     } else {
2886       // If transition to any NBPs fails, transition to exit state machine
2887       NBPtr->NbFreqChgState = 4;
2888     }
2889     break;
2890
2891   case 4:
2892     // Change NB P-State back to NBP0
2893     Status = NBPtr->ChangeNbFrequencyWrap (NBPtr, 0);
2894     ASSERT (Status);
2895
2896     // Return FALSE to get out of MaxRdLat training loop
2897     Status = FALSE;
2898
2899     // Exit state machine
2900     NBPtr->NbFreqChgState = 5;
2901     break;
2902
2903   default:
2904     break;
2905   }
2906
2907   return Status;
2908 }
2909
2910
2911 /* -----------------------------------------------------------------------------*/
2912 /**
2913  *
2914  *
2915  *   This function gets "Dram Term" value from data structure
2916  *
2917  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2918  *     @param[in]       ChipSel  - Targeted chipsel
2919  *
2920  *     @return       Dram Term value
2921  */
2922 UINT8
2923 MemNGetDramTermNb (
2924   IN OUT   MEM_NB_BLOCK *NBPtr,
2925   IN       UINT8 ChipSel
2926   )
2927 {
2928   UINT8 DramTerm;
2929
2930   if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT16) (1 << (ChipSel >> 1)))) != 0) {
2931     DramTerm = NBPtr->PsPtr->QR_DramTerm;
2932   } else {
2933     DramTerm = NBPtr->PsPtr->DramTerm;
2934   }
2935
2936   return DramTerm;
2937 }
2938
2939 /* -----------------------------------------------------------------------------*/
2940 /**
2941  *
2942  *
2943  *   This function gets "Dram Term" value from data structure for Unb
2944  *
2945  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2946  *     @param[in]       ChipSel  - Targeted chipsel
2947  *
2948  *     @return       Dram Term value
2949  */
2950 UINT8
2951 MemNGetDramTermTblDrvNb (
2952   IN OUT   MEM_NB_BLOCK *NBPtr,
2953   IN       UINT8 ChipSel
2954   )
2955 {
2956   UINT8 RttNom;
2957   RttNom = NBPtr->PsPtr->RttNom[ChipSel];
2958   IDS_OPTION_HOOK (IDS_MEM_DRAM_TERM, &RttNom, &NBPtr->MemPtr->StdHeader);
2959   return RttNom;
2960 }
2961
2962 /* -----------------------------------------------------------------------------*/
2963 /**
2964  *
2965  *
2966  *   This function gets "Dynamic Dram Term" value from data structure
2967  *
2968  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2969  *     @param[in]       ChipSel  - Targeted chipsel
2970  *
2971  *     @return       Dynamic Dram Term value
2972  */
2973 UINT8
2974 MemNGetDynDramTermNb (
2975   IN OUT   MEM_NB_BLOCK *NBPtr,
2976   IN       UINT8 ChipSel
2977   )
2978 {
2979   return (NBPtr->PsPtr->DynamicDramTerm);
2980 }
2981
2982 /* -----------------------------------------------------------------------------*/
2983 /**
2984  *
2985  *
2986  *   This function gets "Dynamic Dram Term" value from data structure
2987  *
2988  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
2989  *     @param[in]       ChipSel  - Targeted chipsel
2990  *
2991  *     @return       Dynamic Dram Term value
2992  */
2993 UINT8
2994 MemNGetDynDramTermTblDrvNb (
2995   IN OUT   MEM_NB_BLOCK *NBPtr,
2996   IN       UINT8 ChipSel
2997   )
2998 {
2999   UINT8 RttWr;
3000   RttWr = NBPtr->PsPtr->RttWr[ChipSel];
3001   IDS_OPTION_HOOK (IDS_MEM_DYN_DRAM_TERM, &RttWr, &NBPtr->MemPtr->StdHeader);
3002   return RttWr;
3003 }
3004
3005 /* -----------------------------------------------------------------------------*/
3006 /**
3007  *
3008  *
3009  *   This function returns MR0[CL] value
3010  *
3011  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3012  *
3013  *     @return       MR0[CL] value
3014  */
3015 UINT32
3016 MemNGetMR0CLNb (
3017   IN OUT   MEM_NB_BLOCK *NBPtr
3018   )
3019 {
3020   UINT8 Tcl;
3021   UINT32 Value32;
3022
3023   Tcl = (UINT8) MemNGetBitFieldNb (NBPtr, BFTcl);
3024   Value32 = (UINT32) ((Tcl < 8) ? (Tcl << 4) : (((Tcl - 8) << 4) | 4));
3025
3026   return Value32;
3027 }
3028
3029 /* -----------------------------------------------------------------------------*/
3030 /**
3031  *
3032  *
3033  *   This function returns MR0[WR] value
3034  *
3035  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3036  *
3037  *     @return       MR0[WR] value
3038  */
3039 UINT32
3040 MemNGetMR0WRNb (
3041   IN OUT   MEM_NB_BLOCK *NBPtr
3042   )
3043 {
3044   UINT32 Value32;
3045
3046   Value32 = MemNGetBitFieldNb (NBPtr, BFTwrDDR3) << 9;
3047
3048   return Value32;
3049 }
3050
3051 /* -----------------------------------------------------------------------------*/
3052 /**
3053  *
3054  *
3055  *   This function returns MR0[WR] value
3056  *
3057  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3058  *
3059  *     @return       MR0[WR] value
3060  */
3061 UINT32
3062 MemNGetMR0WRTblDrvNb (
3063   IN OUT   MEM_NB_BLOCK *NBPtr
3064   )
3065 {
3066   return (UINT32) (NBPtr->PsPtr->MR0WR << 9);
3067 }
3068
3069 /* -----------------------------------------------------------------------------*/
3070 /**
3071  *
3072  *
3073  *   This function returns MR2[CWL] value
3074  *
3075  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3076  *
3077  *     @return       MR0[CWL] value
3078  */
3079 UINT32
3080 MemNGetMR2CWLNb (
3081   IN OUT   MEM_NB_BLOCK *NBPtr
3082   )
3083 {
3084   UINT32 Value32;
3085
3086   Value32 = MemNGetBitFieldNb (NBPtr, BFTcwl) << 3;
3087
3088   return Value32;
3089 }
3090
3091 /* -----------------------------------------------------------------------------*/
3092 /**
3093  *
3094  *   This function returns MR2[CWL] value for UNB
3095  *
3096  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3097  *
3098  *     @return       MR0[CWL] value
3099  */
3100 UINT32
3101 MemNGetMR2CWLUnb (
3102   IN OUT   MEM_NB_BLOCK *NBPtr
3103   )
3104 {
3105   UINT32 Value32;
3106
3107   Value32 = (MemNGetBitFieldNb (NBPtr, BFTcwl) - 5) << 3;
3108
3109   return Value32;
3110 }
3111
3112 /* -----------------------------------------------------------------------------*/
3113 /**
3114  *
3115  *   This function sets Txp and Txpdll
3116  *
3117  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3118  *
3119  *     @return       none
3120  */
3121 VOID
3122 MemNSetTxpNb (
3123   IN OUT   MEM_NB_BLOCK *NBPtr
3124   )
3125 {
3126   CONST UINT8 Txp[] = {0xFF, 0xFF, 3, 3, 4, 4, 5, 6, 7};
3127   CONST UINT8 Txpdll[] = {0xFF, 0xFF, 0xA, 0xA, 0xD, 0x10, 0x14, 0x17, 0x1A};
3128   UINT8 i;
3129   UINT8 TxpVal;
3130   UINT8 TxpdllVal;
3131   UINT16 Speed;
3132
3133   Speed = NBPtr->DCTPtr->Timings.Speed;
3134   i = (UINT8) ((Speed < DDR800_FREQUENCY) ? ((Speed / 66) - 3) : (Speed / 133));
3135   ASSERT (i < sizeof (Txp));
3136   ASSERT (i < sizeof (Txpdll));
3137
3138   TxpdllVal = Txpdll[i];
3139
3140   if ((NBPtr->MCTPtr->Status[SbLrdimms] || NBPtr->MCTPtr->Status[SbRegistered]) &&
3141       ((NBPtr->DCTPtr->Timings.Speed == DDR667_FREQUENCY) || (NBPtr->DCTPtr->Timings.Speed == DDR800_FREQUENCY)) &&
3142       (NBPtr->RefPtr->DDR3Voltage == VOLT1_25)) {
3143     TxpVal = 4;
3144   } else {
3145     TxpVal = Txp[i];
3146   }
3147
3148   if (TxpVal != 0xFF) {
3149     MemNSetBitFieldNb (NBPtr, BFTxp, TxpVal);
3150   }
3151   if (TxpdllVal != 0xFF) {
3152     NBPtr->FamilySpecificHook[AdjustTxpdll] (NBPtr, &TxpdllVal);
3153     MemNSetBitFieldNb (NBPtr, BFTxpdll, TxpdllVal);
3154   }
3155 }
3156
3157 /*-----------------------------------------------------------------------------
3158  *
3159  *
3160  *     This function adjust value of Txpdll to encoded value.
3161  *
3162  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
3163  *     @param[in,out]  OptParam   - Optional parameter
3164  *
3165  *     @return    TRUE
3166  * ----------------------------------------------------------------------------
3167  */
3168 BOOLEAN
3169 MemNAdjustTxpdllClientNb (
3170   IN OUT   MEM_NB_BLOCK *NBPtr,
3171   IN OUT   VOID *OptParam
3172   )
3173 {
3174   *(UINT8 *) OptParam -= 10;
3175   return TRUE;
3176 }
3177
3178 /* -----------------------------------------------------------------------------*/
3179 /**
3180  *
3181  *   This function is a wrapper to handle or switch NB Pstate for UNB
3182  *
3183  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3184  *     @param[in]  *NBPstate - NB Pstate
3185  *
3186  *     @return          TRUE - Succeed
3187  *     @return          FALSE - Fail
3188  */
3189
3190 BOOLEAN
3191 MemNChangeNbFrequencyWrapUnb (
3192   IN OUT   MEM_NB_BLOCK *NBPtr,
3193   IN       UINT32 NBPstate
3194   )
3195 {
3196   UINT8   TargetNbPs;
3197   UINT32  FreqNumeratorInMHz;
3198   UINT32  FreqDivisor;
3199   UINT32  VoltageInuV;
3200   UINT8   NbPstateMaxVal;
3201   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
3202
3203   if (NBPtr->NbFreqChgState == 0) {
3204     // While in state 0, keep NB Pstate at the highest supported
3205     TargetNbPs = 0;
3206     if (NBPtr->NbPsCtlReg == 0) {
3207       // Save NbPsCtl register on the first run
3208       NBPtr->NbPsCtlReg = MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg);
3209     } else {
3210       // Do not need to switch NB Pstate again if it is already at highest
3211       return TRUE;
3212     }
3213   } else if (NBPtr->NbFreqChgState < 4) {
3214     // While in other states, go to the next lower NB Pstate
3215     TargetNbPs = (UINT8) MemNGetBitFieldNb (NBPtr, BFCurNbPstate) + 1;
3216   } else {
3217     // When done with training, release NB Pstate force by restoring NbPsCtl register
3218     NBPtr->FamilySpecificHook[ReleaseNbPstate] (NBPtr, NBPtr);
3219     IDS_HDT_CONSOLE (MEM_FLOW, "\tRelease NB Pstate force\n");
3220     return TRUE;
3221   }
3222
3223   // Make sure target NB Pstate is enabled, else find next enabled NB Pstate
3224   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &NBPtr->MemPtr->StdHeader);
3225   for (; TargetNbPs < 4; TargetNbPs++) {
3226     if (FamilySpecificServices->GetNbPstateInfo (FamilySpecificServices,
3227                                                   NBPtr->MemPtr->PlatFormConfig,
3228                                                   &NBPtr->PciAddr,
3229                                                   (UINT32) TargetNbPs,
3230                                                   &FreqNumeratorInMHz,
3231                                                   &FreqDivisor,
3232                                                   &VoltageInuV,
3233                                                   &(NBPtr->MemPtr->StdHeader))) {
3234       // Record NCLK speed
3235       NBPtr->NBClkFreq = FreqNumeratorInMHz / FreqDivisor;
3236       break;
3237     }
3238   }
3239
3240   if (TargetNbPs < 4) {
3241     IDS_HDT_CONSOLE (MEM_FLOW, "\tNB P%d: %dMHz\n", TargetNbPs, NBPtr->NBClkFreq);
3242
3243     // 1.Program the configuration registers which contain multiple internal copies for each NB P-state. See
3244     //   D18F1x10C[NbPsSel].
3245     MemNSetBitFieldNb (NBPtr, BFNbPsSel, TargetNbPs);
3246
3247     // Check to see if NB P-states have been disabled.  @todo This should only be needed for
3248     // bring up, but must be included in any releases that occur before NB P-state operation
3249     // has been debugged/fixed.
3250     if ((NBPtr->NbPsCtlReg & 0x00000003) != 0) {
3251       // Set up RdPtrInit before transit to target NBPstate
3252       if (TargetNbPs > 0) {
3253         NBPtr->ProgramNbPsDependentRegs (NBPtr);
3254       }
3255       // 2.Program D18F5x170 to transition the NB P-state:
3256       //   NbPstateLo = NbPstateMaxVal. (HW requires an intermediate transition to low)
3257       //   SwNbPstateLoDis = NbPstateDisOnP0 = NbPstateThreshold = 0.
3258       NbPstateMaxVal = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPstateMaxVal);
3259       MemNSetBitFieldNb (NBPtr, BFNbPstateLo, NbPstateMaxVal);
3260       MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFF91FF);
3261
3262       // 3.Wait for D18F5x174[CurNbPstate] to equal NbPstateLo.
3263       MemNPollBitFieldNb (NBPtr, BFCurNbPstate, NbPstateMaxVal, PCI_ACCESS_TIMEOUT, TRUE);
3264
3265       // 4.Program D18F5x170 to force the NB P-state:
3266       //   NbPstateHi = target NB P-state.
3267       //   SwNbPstateLoDis = 1 (triggers the transition)
3268       MemNSetBitFieldNb (NBPtr, BFNbPstateHi, TargetNbPs);
3269       MemNSetBitFieldNb (NBPtr, BFSwNbPstateLoDis, 1);
3270
3271       // 5.Wait for D18F5x174[CurNbPstate] to equal the target NB P-state.
3272       MemNPollBitFieldNb (NBPtr, BFCurNbPstate, TargetNbPs, PCI_ACCESS_TIMEOUT, TRUE);
3273     }
3274
3275     // When NB frequency change succeeds, TSC rate may have changed.
3276     // We need to update TSC rate
3277     FamilySpecificServices->GetTscRate (FamilySpecificServices, &NBPtr->MemPtr->TscRate, &NBPtr->MemPtr->StdHeader);
3278   } else {
3279     // Cannot find a supported NB Pstate to switch to
3280     // Release NB Pstate force by restoring NbPsCtl register
3281     NBPtr->FamilySpecificHook[ReleaseNbPstate] (NBPtr, NBPtr);
3282     IDS_HDT_CONSOLE (MEM_FLOW, "\tRelease NB Pstate force\n");
3283     return FALSE;
3284   }
3285   return TRUE;
3286 }
3287
3288 /* -----------------------------------------------------------------------------*/
3289 /**
3290  *
3291  *
3292  *   This function sends an MRS command for Unb
3293  *
3294  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3295  *
3296  */
3297
3298 VOID
3299 MemNSendMrsCmdUnb (
3300   IN OUT   MEM_NB_BLOCK *NBPtr
3301   )
3302 {
3303   MemNSetASRSRTNb (NBPtr);
3304   MemNSwapBitsUnb (NBPtr);
3305
3306   IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d MR%d %05x\n",
3307               (MemNGetBitFieldNb (NBPtr, BFMrsChipSel) & 0x7),
3308               (MemNGetBitFieldNb (NBPtr, BFMrsBank) & 0x7),
3309               (MemNGetBitFieldNb (NBPtr, BFMrsAddress) & 0x3FFFF));
3310
3311   // 1.Set SendMrsCmd=1
3312   MemNSetBitFieldNb (NBPtr, BFSendMrsCmd, 1);
3313
3314   // 2.Wait for SendMrsCmd=0
3315   MemNPollBitFieldNb (NBPtr, BFSendMrsCmd, 0, PCI_ACCESS_TIMEOUT, FALSE);
3316 }
3317
3318 /* -----------------------------------------------------------------------------*/
3319 /**
3320  *
3321  *
3322  *   This function returns MR0[CL] value with table driven support
3323  *
3324  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
3325  *
3326  *     @return       MR0[CL] value
3327  */
3328 UINT32
3329 MemNGetMR0CLTblDrvNb (
3330   IN OUT   MEM_NB_BLOCK *NBPtr
3331   )
3332 {
3333   return (UINT32) ((NBPtr->PsPtr->MR0CL31 << 4) | (NBPtr->PsPtr->MR0CL0 << 2));
3334 }
3335
3336 /* -----------------------------------------------------------------------------*/
3337 /**
3338  *
3339  *
3340  *     This function performs MaxRdLat training for slot 1
3341  *
3342  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
3343  *     @param[in,out]  TestAddrRJ16 - Test address
3344  *
3345  *     @return    TRUE
3346  * ----------------------------------------------------------------------------
3347  */
3348 BOOLEAN
3349 MemNSlot1MaxRdLatTrainClientNb (
3350   IN OUT   MEM_NB_BLOCK *NBPtr,
3351   IN OUT   VOID *TestAddrRJ16
3352   )
3353 {
3354   UINT8  DummyBuffer[8];
3355   UINT16 MaxLatDly;
3356   UINT8  i;
3357
3358   // Perform slot1 specific training:
3359   // A.Program D18F2x[1,0]78[SlotSel]=1. Force read CAS to fifo slot1 for training.
3360   // B.Program D18F2x[1,0]78[MaxRdLatency] = TrainedMaxRdLatency. Set to last slot0 value that passed.
3361   // C.Read the DIMM test addresses.
3362   // D.Compare the values read against the pattern written.
3363
3364   IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tTrain Slot 1: \n");
3365   MemNSetBitFieldNb (NBPtr, BFSlotSel, 1);
3366
3367   MaxLatDly = (UINT16) (MemNGetBitFieldNb (NBPtr, BFMaxLatency) + 1);  // Add 1 to get back to the last passing value
3368   MemNSetBitFieldNb (NBPtr, BFMaxLatency, MaxLatDly);
3369
3370   for (i = 0; i < 100; i++) {
3371     IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDly %3x", MaxLatDly);
3372
3373     NBPtr->ReadPattern (NBPtr, DummyBuffer, *(UINT32*)TestAddrRJ16, 6);
3374
3375     if (NBPtr->CompareTestPattern (NBPtr, DummyBuffer, DummyBuffer, 6 * 64) == 0xFFFF) {
3376       IDS_HDT_CONSOLE (MEM_FLOW, "  P");
3377       break;
3378     }
3379     IDS_HDT_CONSOLE (MEM_FLOW, "\n");
3380   }
3381
3382   if (i < 100) {
3383     MemNSetBitFieldNb (NBPtr, BFSlot1ExtraClkEn, 0);
3384   } else {
3385     MemNSetBitFieldNb (NBPtr, BFSlot1ExtraClkEn, 1);
3386   }
3387
3388   MemNSetBitFieldNb (NBPtr, BFMaxSkipErrTrain, 0);
3389
3390   return TRUE;
3391 }
3392
3393
3394 /* -----------------------------------------------------------------------------*/
3395 /**
3396  *
3397  *
3398  *     This function programs dram power management timing related registers
3399  *
3400  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
3401  *
3402  *     @return    none
3403  * ----------------------------------------------------------------------------
3404  */
3405 VOID
3406 MemNDramPowerMngTimingNb (
3407   IN OUT   MEM_NB_BLOCK *NBPtr
3408   )
3409 {
3410   STATIC CONST UINT8 Tckesr[] = {4, 4, 5, 5, 6, 7, 2, 2};
3411   UINT8 Tck;
3412
3413   // These timings are based on DDR3 spec
3414   // Tcksrx = max(5 nCK, 10 ns)
3415   Tck = (UINT8) MAX (5, (MemUnsToMemClk (NBPtr->DCTPtr->Timings.Speed, 10)));
3416   MemNSetBitFieldNb (NBPtr, BFTcksrx, MIN (0xE, MAX (Tck, 2)));
3417
3418   // Tcksre = max(5 nCK, 10 ns)
3419   MemNSetBitFieldNb (NBPtr, BFTcksre, MIN (0x27, MAX (Tck, 5)));
3420
3421   // Tckesr = tCKE(min) + 1 nCK
3422   //                               tCKE(min)
3423   // DDR-800   7,5ns = 3nCk     max(3nCK, 7.5ns)   + 1 = 3nCK + 1nCK = 4nCK
3424   // DDR-1066  5.625ns = 3nCK   max(3nCK, 5.625ns) + 1 = 3nCL + 1nCK = 4nCK
3425   // DDR-1333  5.625ns = 4nCK   max(3nCK, 4nCK)    + 1 = 4nCK + 1nCK = 5nCK
3426   // DDR-1600  5ns = 4nCK       max(3nCK, 4nCK)    + 1 = 4nCK + 1nCK = 5nCK
3427   // DDR-1866  5ns = 5nCK       max(3nCK, 5nCK)    + 1 = 5nCK + 1nCK = 6nCK
3428   // DDR-2133  5ns = 6nCK       max(3nCK, 6nCK)    + 1 = 6nCK + 1nCK = 7nCK
3429   MemNSetBitFieldNb (NBPtr, BFTckesr, Tckesr[(NBPtr->DCTPtr->Timings.Speed / 133) - 3]);
3430
3431   // Tpd = tCKE(min)
3432   MemNSetBitFieldNb (NBPtr, BFTpd, Tckesr[(NBPtr->DCTPtr->Timings.Speed / 133) - 3] - 1);
3433 }
3434
3435 /* -----------------------------------------------------------------------------*/
3436 /**
3437  *
3438  *       The function resets Rcv Fifo
3439  *
3440  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
3441  *     @param[in]       Dummy - Dummy parameter
3442  *
3443  */
3444
3445 VOID
3446 MemTResetRcvFifoUnb (
3447   IN OUT   struct _MEM_TECH_BLOCK *TechPtr,
3448   IN       UINT8 Dummy
3449   )
3450 {
3451   // Program D18F2x9C_x0000_0050_dct[1:0]=00000000h
3452   MemNSetBitFieldNb (TechPtr->NBPtr, BFRstRcvFifo, 0);
3453 }