7 * Common Northbridge Phy support
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/NB)
12 * @e \$Revision: 60556 $ @e \$Date: 2011-10-17 20:19:58 -0600 (Mon, 17 Oct 2011) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ***************************************************************************
48 *----------------------------------------------------------------------------
51 *----------------------------------------------------------------------------
64 #include "PlatformMemoryConfiguration.h"
65 #include "heapManager.h"
70 #define FILECODE PROC_MEM_NB_MNPHY_FILECODE
71 /*----------------------------------------------------------------------------
72 * DEFINITIONS AND MACROS
74 *----------------------------------------------------------------------------
78 /*----------------------------------------------------------------------------
79 * TYPEDEFS AND STRUCTURES
81 *----------------------------------------------------------------------------
83 /// Type of an entry for processing phy init compensation for client NB
85 BIT_FIELD_NAME IndexBitField; ///< Bit field on which the value is decided
86 BIT_FIELD_NAME StartTargetBitField; ///< First bit field to be modified
87 BIT_FIELD_NAME EndTargetBitField; ///< Last bit field to be modified
88 UINT16 ExtraValue; ///< Extra value needed to be written to bit field
89 CONST UINT16 (*TxPrePN)[3][5]; ///< Pointer to slew rate table
90 } PHY_COMP_INIT_CLIENTNB;
92 /*----------------------------------------------------------------------------
93 * PROTOTYPES OF LOCAL FUNCTIONS
95 *----------------------------------------------------------------------------
100 /*----------------------------------------------------------------------------
103 *----------------------------------------------------------------------------
105 /* -----------------------------------------------------------------------------*/
109 * This function gets a delay value a PCI register during training
111 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
112 * @param[in] TrnDly - type of delay to be set
113 * @param[in] DrbnVar - encoding of Dimm-Rank-Byte-Nibble to be accessed
114 * (use either DIMM_BYTE_ACCESS(dimm,byte) or CS_NBBL_ACCESS(cs,nibble) to use this encoding
121 IN OUT MEM_NB_BLOCK *NBPtr,
122 IN TRN_DLY_TYPE TrnDly,
126 return NBPtr->MemNcmnGetSetTrainDly (NBPtr, 0, TrnDly, DrbnVar, 0);
129 /* -----------------------------------------------------------------------------*/
133 * This function sets a delay value a PCI register during training
135 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
136 * @param[in] TrnDly - type of delay to be set
137 * @param[in] DrbnVar - encoding of Dimm-Rank-Byte-Nibble to be accessed
138 * (use either DIMM_BYTE_ACCESS(dimm,byte) or CS_NBBL_ACCESS(cs,nibble) to use this encoding
139 * @param[in] Field - Value to be programmed
145 IN OUT MEM_NB_BLOCK *NBPtr,
146 IN TRN_DLY_TYPE TrnDly,
151 NBPtr->MemNcmnGetSetTrainDly (NBPtr, 1, TrnDly, DrbnVar, Field);
154 /* -----------------------------------------------------------------------------*/
158 * This function executes prototypical Phy fence training function.
160 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
165 MemNPhyFenceTrainingNb (
166 IN OUT MEM_NB_BLOCK *NBPtr
169 NBPtr->MemPPhyFenceTrainingNb (NBPtr);
172 /* -----------------------------------------------------------------------------*/
176 * This function executes prototypical Phy fence training function.
178 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
183 MemNPhyFenceTrainingUnb (
184 IN OUT MEM_NB_BLOCK *NBPtr
187 UINT8 FenceThresholdTxDll;
188 UINT8 FenceThresholdRxDll;
189 UINT8 FenceThresholdTxPad;
192 // 1. Program D18F2x[1,0]9C_x0000_0008[FenceTrSel]=10b.
193 // 2. Perform phy fence training.
194 // 3. Write the calculated fence value to D18F2x[1,0]9C_x0000_000C[FenceThresholdTxDll].
195 MemNSetBitFieldNb (NBPtr, BFFenceTrSel, 2);
196 MAKE_TSEFO (NBPtr->NBRegTable, DCT_PHY_ACCESS, 0x0C, 30, 26, BFPhyFence);
197 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tFenceThresholdTxDll\n");
198 MemNTrainPhyFenceNb (NBPtr);
199 FenceThresholdTxDll = (UINT8) MemNGetBitFieldNb (NBPtr, BFPhyFence);
200 NBPtr->FamilySpecificHook[DetectMemPllError] (NBPtr, &FenceThresholdTxDll);
202 // 4. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]0F[AlwaysEnDllClks]=001b.
203 MemNSetBitFieldNb (NBPtr, BFAlwaysEnDllClks, 0x1000);
205 // 5. Program D18F2x[1,0]9C_x0000_0008[FenceTrSel]=01b.
206 // 6. Perform phy fence training.
207 // 7. Write the calculated fence value to D18F2x[1,0]9C_x0000_000C[FenceThresholdRxDll].
208 MemNSetBitFieldNb (NBPtr, BFFenceTrSel, 1);
209 MAKE_TSEFO (NBPtr->NBRegTable, DCT_PHY_ACCESS, 0x0C, 25, 21, BFPhyFence);
210 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFenceThresholdRxDll\n");
211 MemNTrainPhyFenceNb (NBPtr);
212 FenceThresholdRxDll = (UINT8) MemNGetBitFieldNb (NBPtr, BFPhyFence);
213 NBPtr->FamilySpecificHook[DetectMemPllError] (NBPtr, &FenceThresholdRxDll);
215 // 8. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]0F[AlwaysEnDllClks]=000b.
216 MemNSetBitFieldNb (NBPtr, BFAlwaysEnDllClks, 0x0000);
218 // 9. Program D18F2x[1,0]9C_x0000_0008[FenceTrSel]=11b.
219 // 10. Perform phy fence training.
220 // 11. Write the calculated fence value to D18F2x[1,0]9C_x0000_000C[FenceThresholdTxPad].
221 MemNSetBitFieldNb (NBPtr, BFFenceTrSel, 3);
222 MAKE_TSEFO (NBPtr->NBRegTable, DCT_PHY_ACCESS, 0x0C, 20, 16, BFPhyFence);
223 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFenceThresholdTxPad\n");
224 MemNTrainPhyFenceNb (NBPtr);
225 FenceThresholdTxPad = (UINT8) MemNGetBitFieldNb (NBPtr, BFPhyFence);
226 NBPtr->FamilySpecificHook[DetectMemPllError] (NBPtr, &FenceThresholdTxPad);
228 // Program Fence2 threshold for Clk, Cmd, and Addr
229 if (FenceThresholdTxPad < 16) {
230 MemNSetBitFieldNb (NBPtr, BFClkFence2, FenceThresholdTxPad | 0x10);
231 MemNSetBitFieldNb (NBPtr, BFCmdFence2, FenceThresholdTxPad | 0x10);
232 MemNSetBitFieldNb (NBPtr, BFAddrFence2, FenceThresholdTxPad | 0x10);
234 MemNSetBitFieldNb (NBPtr, BFClkFence2, 0);
235 MemNSetBitFieldNb (NBPtr, BFCmdFence2, 0);
236 MemNSetBitFieldNb (NBPtr, BFAddrFence2, 0);
239 // Program Fence2 threshold for data
241 if (FenceThresholdTxPad < 16) {
242 Fence2Data |= FenceThresholdTxPad | 0x10;
244 if (FenceThresholdRxDll < 16) {
245 Fence2Data |= (FenceThresholdRxDll | 0x10) << 10;
247 if (FenceThresholdTxDll < 16) {
248 Fence2Data |= (FenceThresholdTxDll | 0x10) << 5;
250 MemNSetBitFieldNb (NBPtr, BFDataFence2, Fence2Data);
251 NBPtr->FamilySpecificHook[ProgramFence2RxDll] (NBPtr, &Fence2Data);
253 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
254 // 18. If motherboard routing requires CS[7:6] to adopt address timings, e.g. 3 LRDIMMs/ch with CS[7:6]
255 // routed across all DIMM sockets, BIOS performs the following:
256 if (GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
257 NBPtr->MCTPtr->SocketId,
258 NBPtr->ChannelPtr->ChannelID) == 3) {
259 if (FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_NO_LRDIMM_CS67_ROUTING, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID, 0, NULL, NULL) == NULL) {
260 // A. Program D18F2xA8_dct[1:0][CSTimingMux67] = 1.
261 MemNSetBitFieldNb (NBPtr, BFCSTimingMux67, 1);
262 // B. Program D18F2x9C_x0D0F_8021_dct[1:0]:
263 // - DiffTimingEn = 1.
264 // - IF (D18F2x9C_x0000_0004_dct[1:0][AddrCmdFineDelay] >=
265 // D18F2x9C_x0D0F_E008_dct[1:0][FenceValue]) THEN Fence = 1 ELSE Fence = 0.
266 // - Delay = D18F2x9C_x0000_0004_dct[1:0][AddrCmdFineDelay].
268 MemNSetBitFieldNb (NBPtr, BFDiffTimingEn, 1);
269 MemNSetBitFieldNb (NBPtr, BFFence, (MemNGetBitFieldNb (NBPtr, BFAddrCmdFineDelay) >= MemNGetBitFieldNb (NBPtr, BFFenceValue)) ? 1 : 0);
270 MemNSetBitFieldNb (NBPtr, BFDelay, (MemNGetBitFieldNb (NBPtr, BFAddrCmdFineDelay)));
275 // 19. Reprogram F2x9C_04.
276 MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, MemNGetBitFieldNb (NBPtr, BFAddrTmgControl));
280 /* -----------------------------------------------------------------------------*/
284 * This function executes Phy fence training
286 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
291 MemNTrainPhyFenceNb (
292 IN OUT MEM_NB_BLOCK *NBPtr
299 if (MemNGetBitFieldNb (NBPtr, BFDisDramInterface)) {
303 // 1. BIOS first programs a seed value to the phase recovery
306 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tSeeds: ");
307 for (Byte = 0; Byte < MAX_BYTELANES_PER_CHANNEL; Byte++) {
308 // This includes ECC as byte 8
309 MemNSetTrainDlyNb (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (0, Byte), 19);
310 IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", 19);
313 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tPhyFenceTrEn = 1");
314 // 2. Set F2x[1, 0]9C_x08[PhyFenceTrEn]=1.
315 MemNSetBitFieldNb (NBPtr, BFPhyFenceTrEn, 1);
317 if (!NBPtr->IsSupported[UnifiedNbFence]) {
318 // 3. Wait 200 MEMCLKs.
319 MemNWaitXMemClksNb (NBPtr, 200);
321 // 3. Wait 2000 MEMCLKs.
322 MemNWaitXMemClksNb (NBPtr, 2000);
325 // 4. Clear F2x[1, 0]9C_x08[PhyFenceTrEn]=0.
326 MemNSetBitFieldNb (NBPtr, BFPhyFenceTrEn, 0);
328 // 5. BIOS reads the phase recovery engine registers
329 // F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52.
330 // 6. Calculate the average value of the fine delay and subtract 8.
333 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t PRE: ");
334 for (Byte = 0; Byte < MAX_BYTELANES_PER_CHANNEL; Byte++) {
336 // This includes ECC as byte 8. ECC Byte lane (8) is ignored by MemNGetTrainDlyNb function where
337 // ECC is not supported.
339 PREvalue = (UINT8) (0x1F & MemNGetTrainDlyNb (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (0, Byte)));
340 Avg = Avg + ((INT16) PREvalue);
341 IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", PREvalue);
343 Avg = ((Avg + 8) / 9); // round up
346 NBPtr->MemNPFenceAdjustNb (NBPtr, &Avg);
348 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tFence: %02x\n", Avg);
350 // 7. Write the value to F2x[1, 0]9C_x0C[PhyFence].
351 MemNSetBitFieldNb (NBPtr, BFPhyFence, Avg);
353 // 8. BIOS rewrites F2x[1, 0]9C_x04, DRAM Address/Command Timing Control
354 // Register delays for both channels. This forces the phy to recompute
357 MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, MemNGetBitFieldNb (NBPtr, BFAddrTmgControl));
360 /* -----------------------------------------------------------------------------*/
364 * This function initializes the DDR phy compensation logic
366 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
372 IN OUT MEM_NB_BLOCK *NBPtr
375 CONST UINT8 TableCompRiseSlew20x[] = {7, 3, 2, 2};
376 CONST UINT8 TableCompRiseSlew15x[] = {7, 7, 3, 2};
377 CONST UINT8 TableCompFallSlew20x[] = {7, 5, 3, 2};
378 CONST UINT8 TableCompFallSlew15x[] = {7, 7, 5, 3};
385 CurrDct = NBPtr->Dct;
386 CurrChannel = NBPtr->Channel;
387 if (NBPtr->IsSupported[CheckSlewWithMarginImprv]) {
388 if (NBPtr->MCTPtr->GangedMode == FALSE) {
389 for (i = 0; i < NBPtr->DctCount; i++) {
390 MemNSwitchDCTNb (NBPtr, i);
391 for (j = 0; j < NBPtr->ChannelCount; j++) {
392 NBPtr->SwitchChannel (NBPtr, j);
393 if ((NBPtr->ChannelPtr->Dimms == 4) && ((NBPtr->DCTPtr->Timings.Speed == DDR533_FREQUENCY) || (NBPtr->DCTPtr->Timings.Speed == DDR667_FREQUENCY))) {
398 MemNSwitchDCTNb (NBPtr, CurrDct);
399 NBPtr->SwitchChannel (NBPtr, CurrChannel);
403 // 1. BIOS disables the phy compensation register by programming F2x9C_x08[DisAutoComp]=1
404 // 2. BIOS waits 5 us for the disabling of the compensation engine to complete.
405 // DisAutoComp will be cleared after Dram init has completed
407 MemNSwitchDCTNb (NBPtr, 0);
408 MemNSetBitFieldNb (NBPtr, BFDisAutoComp, 1);
409 MemUWait10ns (500, NBPtr->MemPtr);
410 MemNSwitchDCTNb (NBPtr, CurrDct);
412 // 3. For each normalized driver strength code read from
413 // F2x[1, 0]9C_x00[AddrCmdDrvStren], program the
414 // corresponding 3 bit predriver code in F2x9C_x0A[D3Cmp1NCal, D3Cmp1PCal].
416 // 4. For each normalized driver strength code read from
417 // F2x[1, 0]9C_x00[DataDrvStren], program the corresponding
418 // 3 bit predriver code in F2x9C_x0A[D3Cmp0NCal, D3Cmp0PCal, D3Cmp2NCal,
421 j = (UINT8) MemNGetBitFieldNb (NBPtr, BFAddrCmdDrvStren);
422 i = (UINT8) MemNGetBitFieldNb (NBPtr, BFDataDrvStren);
424 MemNSwitchDCTNb (NBPtr, 0);
425 MemNSetBitFieldNb (NBPtr, BFD3Cmp1NCal, TableCompRiseSlew20x[j]);
426 MemNSetBitFieldNb (NBPtr, BFD3Cmp1PCal, TableCompFallSlew20x[j]);
428 if (NBPtr->IsSupported[CheckSlewWithMarginImprv]) {
429 MemNSetBitFieldNb (NBPtr, BFD3Cmp0NCal, (MarginImprv) ? 0 : TableCompRiseSlew15x[i]);
430 MemNSetBitFieldNb (NBPtr, BFD3Cmp0PCal, (MarginImprv) ? 0 : TableCompFallSlew15x[i]);
431 MemNSetBitFieldNb (NBPtr, BFD3Cmp2NCal, (MarginImprv) ? 0 : TableCompRiseSlew15x[i]);
432 MemNSetBitFieldNb (NBPtr, BFD3Cmp2PCal, (MarginImprv) ? 0 : TableCompFallSlew15x[i]);
434 if (NBPtr->IsSupported[CheckSlewWithoutMarginImprv]) {
436 MemNSetBitFieldNb (NBPtr, BFD3Cmp0NCal, TableCompRiseSlew15x[i]);
437 MemNSetBitFieldNb (NBPtr, BFD3Cmp0PCal, TableCompFallSlew15x[i]);
438 MemNSetBitFieldNb (NBPtr, BFD3Cmp2NCal, TableCompRiseSlew15x[i]);
439 MemNSetBitFieldNb (NBPtr, BFD3Cmp2PCal, TableCompFallSlew15x[i]);
441 MemNSwitchDCTNb (NBPtr, CurrDct);
444 /* -----------------------------------------------------------------------------*/
448 * This is a general purpose function that executes before DRAM training
450 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
455 MemNBeforeDQSTrainingNb (
456 IN OUT MEM_NB_BLOCK *NBPtr
464 MemTBeginTraining (NBPtr->TechPtr);
466 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
467 MemNSwitchDCTNb (NBPtr, Dct);
468 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
469 for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
470 if (MemNGetMCTSysAddrNb (NBPtr, ChipSel, &TestAddrRJ16)) {
472 RealAddr = MemUSetUpperFSbase (TestAddrRJ16, NBPtr->MemPtr);
474 MemUDummyCLRead (RealAddr);
476 MemNSetBitFieldNb (NBPtr, BFErr350, 0x8000);
477 MemUWait10ns (60, NBPtr->MemPtr); // Wait 300ns
478 MemNSetBitFieldNb (NBPtr, BFErr350, 0x0000);
479 MemUWait10ns (400, NBPtr->MemPtr); // Wait 2us
480 MemUProcIOClFlush (TestAddrRJ16, 1, NBPtr->MemPtr);
485 if (NBPtr->IsSupported[CheckEccDLLPwrDnConfig]) {
486 if (!NBPtr->MCTPtr->Status[SbEccDimms]) {
487 MemNSetBitFieldNb (NBPtr, BFEccDLLPwrDnConf, 0x0010);
489 if (NBPtr->DCTPtr->Timings.Dimmx4Present == 0) {
490 MemNSetBitFieldNb (NBPtr, BFEccDLLConf, 0x0080);
495 MemTEndTraining (NBPtr->TechPtr);
498 /*-----------------------------------------------------------------------------*/
501 * Returns the parameters for a requested delay value to be used in training
502 * The correct Min, Max and Mask are determined based on the type of Delay,
505 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
506 * @param[in] TrnDly - Type of delay
507 * @param[in,out] *Parms - Pointer to the TRN_DLY-PARMS struct
512 MemNGetTrainDlyParmsNb (
513 IN OUT MEM_NB_BLOCK *NBPtr,
514 IN TRN_DLY_TYPE TrnDly,
515 IN OUT TRN_DLY_PARMS *Parms
520 if (TrnDly == AccessWrDatDly) {
523 } else if (TrnDly == AccessRdDqsDly) {
524 if ( (NBPtr->IsSupported[CheckMaxRdDqsDlyPtr]) && (NBPtr->DCTPtr->Timings.Speed > DDR667_FREQUENCY) ) {
534 /*-----------------------------------------------------------------------------*/
537 * Returns the parameters for a requested delay value to be used in training
538 * The correct Min, Max and Mask are determined based on the type of Delay,
541 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
542 * @param[in] TrnDly - Type of delay
543 * @param[in,out] *Parms - Pointer to the TRN_DLY-PARMS struct
548 MemNGetTrainDlyParmsClientNb (
549 IN OUT MEM_NB_BLOCK *NBPtr,
550 IN TRN_DLY_TYPE TrnDly,
551 IN OUT TRN_DLY_PARMS *Parms
556 if (TrnDly == AccessWrDatDly) {
559 } else if (TrnDly == AccessRdDqsDly) {
564 /*-----------------------------------------------------------------------------*/
567 * Returns the parameters for a requested delay value to be used in training
568 * The correct Min, Max and Mask are determined based on the type of Delay,
571 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
572 * @param[in] TrnDly - Type of delay
573 * @param[in,out] *Parms - Pointer to the TRN_DLY-PARMS struct
578 MemNGetTrainDlyParmsUnb (
579 IN OUT MEM_NB_BLOCK *NBPtr,
580 IN TRN_DLY_TYPE TrnDly,
581 IN OUT TRN_DLY_PARMS *Parms
586 if ((TrnDly == AccessWrDatDly) || (TrnDly == AccessRdDqsDly)) {
591 /*----------------------------------------------------------------------------
594 *----------------------------------------------------------------------------
596 /* -----------------------------------------------------------------------------*/
600 * This function gets or set DQS timing during training.
602 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
603 * @param[in] TrnDly - type of delay to be set
604 * @param[in] DrbnVar - encoding of Dimm-Rank-Byte-Nibble to be accessed
605 * (use either DIMM_BYTE_ACCESS(dimm,byte) or CS_NBBL_ACCESS(cs,nibble) to use this encoding
606 * @param[in] Field - Value to be programmed
607 * @param[in] IsSet - Indicates if the function will set or get
609 * @return value read, if the function is used as a "get"
613 MemNcmnGetSetTrainDlyNb (
614 IN OUT MEM_NB_BLOCK *NBPtr,
616 IN TRN_DLY_TYPE TrnDly,
630 Dimm = DRBN_DIMM (DrbnVar);
631 Rank = DRBN_RANK (DrbnVar);
632 Byte = DRBN_BYTE (DrbnVar);
633 Nibble = DRBN_NBBL (DrbnVar);
636 ASSERT (Byte <= ECC_DLY);
674 Offset = 16 * (Byte % 2);
675 Index |= (Rank << 8);
676 Index |= (Nibble << 9);
682 if (NBPtr->IsSupported[DimmBasedOnSpeed]) {
683 if (NBPtr->DCTPtr->Timings.Speed < DDR800_FREQUENCY) {
684 // if DDR speed is below 800, use DIMM 0 delays for all DIMMs.
689 Index += (Dimm * 0x100);
699 // break is not being used here because AccessRdDqsDly and AccessWrDatDly also need
700 // to run AccessPhRecDly sequence.
703 Offset = 8 * (Byte % 4);
711 MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address);
712 MemNPollBitFieldNb (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, FALSE);
713 Value = MemNGetBitFieldNb (NBPtr, BFDctAddlDataReg);
715 if (TrnDly == AccessRdDqsDly) {
716 NBPtr->FamilySpecificHook[AdjustRdDqsDlyOffset] (NBPtr, &Offset);
720 if (TrnDly == AccessPhRecDly) {
721 Value = NBPtr->DctCachePtr->PhRecReg[Index & 0x03];
724 Value = ((UINT32)Field << Offset) | (Value & (~((UINT32) ((TrnDly == AccessRcvEnDly) ? 0x1FF : 0xFF) << Offset)));
725 MemNSetBitFieldNb (NBPtr, BFDctAddlDataReg, Value);
726 Address |= DCT_ACCESS_WRITE;
727 MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address);
728 MemNPollBitFieldNb (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, FALSE);
730 if (TrnDly == AccessPhRecDly) {
731 NBPtr->DctCachePtr->PhRecReg[Index & 0x03] = Value;
734 Value = (Value >> Offset) & (UINT32) ((TrnDly == AccessRcvEnDly) ? 0x1FF : 0xFF);
740 /* -----------------------------------------------------------------------------*/
743 * This function gets or set DQS timing during training.
745 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
746 * @param[in] IsSet - Indicates if the function will set or get
747 * @param[in] TrnDly - type of delay to be set
748 * @param[in] DrbnVar - encoding of Dimm-Rank-Byte-Nibble to be accessed
749 * (use either DIMM_BYTE_ACCESS(dimm,byte) or CS_NBBL_ACCESS(cs,nibble) to use this encoding
750 * @param[in] Field - Value to be programmed
752 * @return value read, if the function is used as a "get"
755 MemNcmnGetSetTrainDlyClientNb (
756 IN OUT MEM_NB_BLOCK *NBPtr,
758 IN TRN_DLY_TYPE TrnDly,
770 Dimm = DRBN_DIMM (DrbnVar);
771 Byte = DRBN_BYTE (DrbnVar);
774 ASSERT (Byte <= ECC_DLY);
777 // Llano does not support ECC delay, so:
782 // On read, redirect to byte 0 to correct fence averaging
820 Offset = 16 * (Byte % 2);
825 Index += (Dimm * 0x100);
826 // break is not being used here because AccessRdDqsDly and AccessWrDatDly also need
827 // to run AccessPhRecDly sequence.
830 Offset = 8 * (Byte % 4);
838 MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address);
839 Value = MemNGetBitFieldNb (NBPtr, BFDctAddlDataReg);
842 if (TrnDly == AccessPhRecDly) {
843 Value = NBPtr->DctCachePtr->PhRecReg[Index & 0x03];
846 Value = ((UINT32)Field << Offset) | (Value & (~((UINT32) ((TrnDly == AccessRcvEnDly) ? 0x1FF : 0xFF) << Offset)));
847 MemNSetBitFieldNb (NBPtr, BFDctAddlDataReg, Value);
848 Address |= DCT_ACCESS_WRITE;
849 MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address);
851 if (TrnDly == AccessPhRecDly) {
852 NBPtr->DctCachePtr->PhRecReg[Index & 0x03] = Value;
854 // Gross WrDatDly and WrDqsDly cannot be larger than 4
855 ASSERT (((TrnDly == AccessWrDatDly) || (TrnDly == AccessWrDqsDly)) ? (NBPtr->IsSupported[WLNegativeDelay] || (Field < 0xA0)) : TRUE);
857 Value = (Value >> Offset) & (UINT32) ((TrnDly == AccessRcvEnDly) ? 0x1FF : 0xFF);
862 /* -----------------------------------------------------------------------------*/
866 * This function gets or set DQS timing during training.
868 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
869 * @param[in] TrnDly - type of delay to be set
870 * @param[in] DrbnVar - encoding of Dimm-Rank-Byte-Nibble to be accessed
871 * (use either DIMM_BYTE_ACCESS(dimm,byte) or CS_NBBL_ACCESS(cs,nibble) to use this encoding
872 * @param[in] Field - Value to be programmed
873 * @param[in] IsSet - Indicates if the function will set or get
875 * @return value read, if the function is used as a "get"
879 MemNcmnGetSetTrainDlyUnb (
880 IN OUT MEM_NB_BLOCK *NBPtr,
882 IN TRN_DLY_TYPE TrnDly,
897 Dimm = DRBN_DIMM (DrbnVar);
898 Rank = DRBN_RANK (DrbnVar);
899 Byte = DRBN_BYTE (DrbnVar);
900 Nibble = DRBN_NBBL (DrbnVar);
901 DimmNibble = DRBN_DIMM_NBBL (DrbnVar);
904 ASSERT (Byte <= ECC_DLY);
905 if ((Byte == ECC_DLY) && !NBPtr->MCTPtr->Status[SbEccDimms]) {
906 // When ECC is not enabled
911 // On read, redirect to byte 0 to correct fence averaging
929 case AccessRdDqs__Dly:
955 Offset = 16 * (Byte % 2);
956 Index |= (Rank << 8);
957 Index |= (Nibble << 9);
964 if (NBPtr->IsSupported[DimmBasedOnSpeed]) {
965 if (NBPtr->DCTPtr->Timings.Speed < DDR800_FREQUENCY) {
966 // if DDR speed is below 800, use DIMM 0 delays for all DIMMs.
971 Index += (Dimm * 0x100);
981 // break is not being used here because AccessRdDqsDly and AccessWrDatDly also need
982 // to run AccessPhRecDly sequence.
985 Offset = 8 * (Byte % 4);
988 case AccessRdDqs__Dly:
989 Address = 0x0D0F0000;
990 Index += (DimmNibble >> 1) * 0x100;
992 Index = Index + Dimm;
993 Offset = 4 * ((DimmNibble & 0x01) * 2);
1001 MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address);
1002 MemNPollBitFieldNb (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, FALSE);
1003 Value = MemNGetBitFieldNb (NBPtr, BFDctAddlDataReg);
1004 if (TrnDly == AccessRdDqsDly) {
1005 NBPtr->FamilySpecificHook[AdjustRdDqsDlyOffset] (NBPtr, &Offset);
1009 if (TrnDly == AccessPhRecDly) {
1010 Value = NBPtr->DctCachePtr->PhRecReg[Index & 0x03];
1012 if (TrnDly != AccessRdDqs__Dly) {
1013 Value = ((UINT32)Field << Offset) | (Value & (~((UINT32) ((TrnDly == AccessRcvEnDly) ? 0x3FF : 0xFF) << Offset)));
1015 Value = ((UINT32)Field << Offset) | (Value & (~((UINT32) 0x1F << Offset)));
1017 MemNSetBitFieldNb (NBPtr, BFDctAddlDataReg, Value);
1018 Address |= DCT_ACCESS_WRITE;
1019 MemNSetBitFieldNb (NBPtr, BFDctAddlOffsetReg, Address);
1020 MemNPollBitFieldNb (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, FALSE);
1021 if (TrnDly == AccessPhRecDly) {
1022 NBPtr->DctCachePtr->PhRecReg[Index & 0x03] = Value;
1025 if (TrnDly != AccessRdDqs__Dly) {
1026 Value = (Value >> Offset) & (UINT32) ((TrnDly == AccessRcvEnDly) ? 0x3FF : 0xFF);
1028 Value = (Value >> Offset) & (UINT32) (0x1F);
1033 /* -----------------------------------------------------------------------------*/
1036 * This function initializes the training pattern.
1038 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1040 * @return AGESA_STATUS - Result
1041 * AGESA_SUCCESS - Training pattern is ready to use
1042 * AGESA_ERROR - Unable to initialize the pattern.
1046 MemNTrainingPatternInitNb (
1047 IN OUT MEM_NB_BLOCK *NBPtr
1050 MEM_TECH_BLOCK *TechPtr;
1051 ALLOCATE_HEAP_PARAMS AllocHeapParams;
1052 TRAIN_PATTERN TrainPattern;
1053 AGESA_STATUS Status;
1055 TechPtr = NBPtr->TechPtr;
1058 // Check the training type
1060 if (TechPtr->TrainingType == TRN_DQS_POSITION) {
1062 // DQS Position Training
1064 if (NBPtr->PosTrnPattern == POS_PATTERN_256B) {
1068 if (NBPtr->MCTPtr->Status[Sb128bitmode]) {
1069 TrainPattern = TestPatternJD256B;
1070 TechPtr->PatternLength = 64;
1072 TrainPattern = TestPatternJD256A;
1073 TechPtr->PatternLength = 32;
1077 // 72 bit pattern will be used if PosTrnPattern is not specified
1079 if (NBPtr->MCTPtr->Status[Sb128bitmode]) {
1080 TrainPattern = TestPatternJD1B;
1081 TechPtr->PatternLength = 18;
1083 TrainPattern = TestPatternJD1A;
1084 TechPtr->PatternLength = 9;
1087 } else if (TechPtr->TrainingType == TRN_MAX_READ_LATENCY) {
1089 // Max Read Latency Training
1091 TrainPattern = TestPatternML;
1092 TechPtr->PatternLength = (NBPtr->MCTPtr->Status[Sb128bitmode]) ? 6 : 3;
1095 // Error - TechPtr->Training Type must be set to one of the types handled in this function
1100 // Allocate training buffer
1102 AllocHeapParams.RequestedBufferSize = (TechPtr->PatternLength * 64 * 2) + 16;
1103 AllocHeapParams.BufferHandle = AMD_MEM_TRAIN_BUFFER_HANDLE;
1104 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
1105 Status = HeapAllocateBuffer (&AllocHeapParams, &NBPtr->MemPtr->StdHeader);
1106 ASSERT (Status == AGESA_SUCCESS);
1107 if (Status != AGESA_SUCCESS) {
1110 TechPtr->PatternBufPtr = AllocHeapParams.BufferPtr;
1111 AlignPointerTo16Byte (&TechPtr->PatternBufPtr);
1112 TechPtr->TestBufPtr = TechPtr->PatternBufPtr + (TechPtr->PatternLength * 64);
1114 // Prepare training pattern
1115 MemUFillTrainPattern (TrainPattern, TechPtr->PatternBufPtr, TechPtr->PatternLength * 64);
1120 /* -----------------------------------------------------------------------------*/
1123 * This function determined the settings for the Reliable Read/Write engine
1124 * for each specific type of training
1126 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1127 * @param[in] *OptParam - Pointer to an Enum of TRAINING_TYPE
1133 MemNSetupHwTrainingEngineUnb (
1134 IN OUT MEM_NB_BLOCK *NBPtr,
1138 TRAINING_TYPE TrnType;
1141 TrnType = *(TRAINING_TYPE*) OptParam;
1142 Rrw = &NBPtr->RrwSettings;
1146 Rrw->TgtBankAddressA = CPG_BANK_ADDRESS_A;
1147 Rrw->TgtRowAddressA = CPG_ROW_ADDRESS_A;
1148 Rrw->TgtColAddressA = CPG_COL_ADDRESS_A;
1149 Rrw->TgtBankAddressB = CPG_BANK_ADDRESS_B;
1150 Rrw->TgtRowAddressB = CPG_ROW_ADDRESS_B;
1151 Rrw->TgtColAddressB = CPG_COL_ADDRESS_B;
1152 Rrw->CompareMaskHigh = CPG_COMPARE_MASK_HI;
1153 Rrw->CompareMaskLow = CPG_COMPARE_MASK_LOW;
1154 Rrw->CompareMaskEcc = CPG_COMPARE_MASK_ECC;
1157 case TRN_RCVR_ENABLE:
1159 // Receiver Enable Training
1161 NBPtr->TechPtr->PatternLength = 192;
1163 case TRN_MAX_READ_LATENCY:
1165 // Max Read Latency Training
1167 Rrw->CmdTgt = CMD_TGT_A;
1168 NBPtr->TechPtr->PatternLength = 32;
1169 Rrw->DataPrbsSeed = PRBS_SEED_32;
1171 case TRN_DQS_POSITION:
1173 // Read/Write DQS Position training
1175 Rrw->CmdTgt = CMD_TGT_AB;
1176 NBPtr->TechPtr->PatternLength = 256;
1177 Rrw->DataPrbsSeed = PRBS_SEED_256;
1185 /* -----------------------------------------------------------------------------*/
1188 * This function finalizes the training pattern.
1190 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1191 * @param[in] Index - Index of Write Data Delay Value
1192 * @param[in,out] *Value - Write Data Delay Value
1193 * @return BOOLEAN - TRUE - Use the value returned.
1194 * FALSE - No more values in table.
1198 MemNGetApproximateWriteDatDelayNb (
1199 IN OUT MEM_NB_BLOCK *NBPtr,
1204 CONST UINT8 WriteDatDelayValue[] = {0x10, 0x4, 0x8, 0xC, 0x14, 0x18, 0x1C, 0x1F};
1205 if (Index < GET_SIZE_OF (WriteDatDelayValue)) {
1206 *Value = WriteDatDelayValue[Index];
1213 /* -----------------------------------------------------------------------------*/
1216 * This function finalizes the training pattern.
1218 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1220 * @return AGESA_STATUS - Result
1221 * AGESA_SUCCESS - Training pattern has been finalized.
1222 * AGESA_ERROR - Unable to initialize the pattern.
1226 MemNTrainingPatternFinalizeNb (
1227 IN OUT MEM_NB_BLOCK *NBPtr
1230 AGESA_STATUS Status;
1232 // Deallocate training buffer
1234 Status = HeapDeallocateBuffer (AMD_MEM_TRAIN_BUFFER_HANDLE, &NBPtr->MemPtr->StdHeader);
1235 ASSERT (Status == AGESA_SUCCESS);
1239 /* -----------------------------------------------------------------------------*/
1242 * This function returns the number of chipselects per channel.
1244 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1250 MemNCSPerChannelNb (
1251 IN OUT MEM_NB_BLOCK *NBPtr
1254 return MAX_CS_PER_CHANNEL;
1257 /* -----------------------------------------------------------------------------*/
1260 * This function returns the number of Chipselects controlled by each set
1261 * of Delay registers under current conditions.
1263 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1270 IN OUT MEM_NB_BLOCK *NBPtr
1273 return MAX_CS_PER_DELAY;
1276 /* -----------------------------------------------------------------------------*/
1279 * This function returns the minimum data eye width in 32nds of a UI for
1280 * the type of data eye(Rd/Wr) that is being trained. This value will
1281 * be the minimum number of consecutive delays that yield valid data.
1282 * Uses TechPtr->Direction to determine read or write.
1285 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1291 MemNMinDataEyeWidthNb (
1292 IN OUT MEM_NB_BLOCK *NBPtr
1297 UINT8 *MinRdWrDataeyePtr;
1299 MinRdWrDataeyePtr = FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MIN_RD_WR_DATAEYE_WIDTH, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID, 0,
1300 &(NBPtr->MCTPtr->LogicalCpuid), &(NBPtr->MemPtr->StdHeader));
1302 if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
1303 if (MinRdWrDataeyePtr != NULL) {
1304 MinRdDataeye = MinRdWrDataeyePtr[0];
1305 return MinRdDataeye;
1307 return MIN_RD_DATAEYE_WIDTH_NB;
1310 if (MinRdWrDataeyePtr != NULL) {
1311 MinWrDataeye = MinRdWrDataeyePtr[1];
1312 return MinWrDataeye;
1314 return MIN_WR_DATAEYE_WIDTH_NB;
1319 /* -----------------------------------------------------------------------------*/
1322 * This function programs the phy registers according to the desired phy VDDIO voltage level
1324 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1329 MemNPhyVoltageLevelNb (
1330 IN OUT MEM_NB_BLOCK *NBPtr
1333 BIT_FIELD_NAME BitField;
1334 BIT_FIELD_NAME BFEnd;
1338 BFValue = (UINT16) CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage) << 3;
1339 BFEnd = NBPtr->IsSupported[ProgramCsrComparator] ? BFCsrComparator : BFCmpVioLvl;
1341 for (BitField = BFDataRxVioLvl; BitField <= BFEnd; BitField++) {
1343 if (BitField == BFCsrComparator) {
1344 RegValue >>= (3 - 2);
1345 // Setting this bit in DCT0 adjusts the comparator for DCT0 and DCT1. Setting this bit in DCT1 has no effect.
1346 NBPtr->SwitchDCT (NBPtr, 0);
1347 MemNSetBitFieldNb (NBPtr, BitField, RegValue);
1349 } else if (BitField == BFCmpVioLvl) {
1350 RegValue <<= (14 - 3);
1351 // Must set this bit on DCT0 even when DCT0 has no memory
1352 NBPtr->SwitchDCT (NBPtr, 0);
1353 MemNSetBitFieldNb (NBPtr, BitField, RegValue);
1355 MemNBrdcstSetNb (NBPtr, BitField, RegValue);
1359 /* -----------------------------------------------------------------------------*/
1363 * This function adjusts Avg PRE value of Phy fence training according to specific CPU family.
1365 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1366 * @param[in,out] *Value16 - Pointer to the value that we want to adjust
1370 MemNPFenceAdjustUnb (
1371 IN OUT MEM_NB_BLOCK *NBPtr,
1372 IN OUT INT16 *Value16
1375 *Value16 += 2; //The Avg PRE value is subtracted by 6 only.
1378 /* -----------------------------------------------------------------------------*/
1382 * This function initializes the DDR phy compensation logic
1384 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1389 MemNInitPhyCompClientNb (
1390 IN OUT MEM_NB_BLOCK *NBPtr
1393 // Slew rate table array [x][y][z]
1394 // array[0]: slew rate for VDDIO 1.5V
1395 // array[1]: slew rate for VDDIO 1.35V
1396 // array[2]: slew rate for VDDIO 1.25V
1397 // array[x][y]: slew rate for a certain frequency
1398 // array[x][y][0]: frequency mask for current entry
1399 CONST STATIC UINT16 TxPrePNDataDqs[3][3][5] = {
1400 {{ (UINT16) DDR800, 0x924, 0x924, 0x924, 0x924},
1401 { (UINT16) (DDR1066 + DDR1333), 0xFF6, 0xFF6, 0xFF6, 0xFF6},
1402 { (UINT16) (DDR1600 + DDR1866), 0xFF6, 0xFF6, 0xFF6, 0xFF6}},
1403 {{ (UINT16) DDR800, 0xFF6, 0xB6D, 0xB6D, 0x924},
1404 { (UINT16) (DDR1066 + DDR1333), 0xFF6, 0xFF6, 0xFF6, 0xFF6},
1405 { (UINT16) (DDR1600 + DDR1866), 0xFF6, 0xFF6, 0xFF6, 0xFF6}},
1406 {{ (UINT16) DDR800, 0xFF6, 0xDAD, 0xDAD, 0x924},
1407 { (UINT16) (DDR1066 + DDR1333), 0xFF6, 0xFF6, 0xFF6, 0xFF6},
1408 { (UINT16) (DDR1600 + DDR1866), 0xFF6, 0xFF6, 0xFF6, 0xFF6}}
1410 CONST STATIC UINT16 TxPrePNCmdAddr[3][3][5] = {
1411 {{ (UINT16) DDR800, 0x492, 0x492, 0x492, 0x492},
1412 { (UINT16) (DDR1066 + DDR1333), 0x6DB, 0x6DB, 0x6DB, 0x6DB},
1413 { (UINT16) (DDR1600 + DDR1866), 0xB6D, 0xB6D, 0xB6D, 0xB6D}},
1414 {{ (UINT16) DDR800, 0x492, 0x492, 0x492, 0x492},
1415 { (UINT16) (DDR1066 + DDR1333), 0x924, 0x6DB, 0x6DB, 0x6DB},
1416 { (UINT16) (DDR1600 + DDR1866), 0xB6D, 0xB6D, 0x924, 0x924}},
1417 {{ (UINT16) DDR800, 0x492, 0x492, 0x492, 0x492},
1418 { (UINT16) (DDR1066 + DDR1333), 0xDAD, 0x924, 0x6DB, 0x492},
1419 { (UINT16) (DDR1600 + DDR1866), 0xFF6, 0xDAD, 0xB64, 0xB64}}
1421 CONST STATIC UINT16 TxPrePNClock[3][3][5] = {
1422 {{ (UINT16) DDR800, 0x924, 0x924, 0x924, 0x924},
1423 { (UINT16) (DDR1066 + DDR1333), 0xFF6, 0xFF6, 0xFF6, 0xB6D},
1424 { (UINT16) (DDR1600 + DDR1866), 0xFF6, 0xFF6, 0xFF6, 0xFF6}},
1425 {{ (UINT16) DDR800, 0xDAD, 0xDAD, 0x924, 0x924},
1426 { (UINT16) (DDR1066 + DDR1333), 0xFF6, 0xFF6, 0xFF6, 0xDAD},
1427 { (UINT16) (DDR1600 + DDR1866), 0xFF6, 0xFF6, 0xFF6, 0xDAD}},
1428 {{ (UINT16) DDR800, 0xDAD, 0xDAD, 0x924, 0x924},
1429 { (UINT16) (DDR1066 + DDR1333), 0xFF6, 0xFF6, 0xFF6, 0xFF6},
1430 { (UINT16) (DDR1600 + DDR1866), 0xFF6, 0xFF6, 0xFF6, 0xFF6}}
1433 CONST PHY_COMP_INIT_CLIENTNB PhyCompInitBitField[] = {
1434 // 3. Program TxPreP/TxPreN for Data and DQS according toTable 14 if VDDIO is 1.5V or Table 15 if 1.35V.
1435 // A. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]0[A,6]={0000b, TxPreP, TxPreN}.
1436 // B. Program D18F2x[1,0]9C_x0D0F_0[F,7:0]02={1000b, TxPreP, TxPreN}.
1437 {BFDqsDrvStren, BFDataByteTxPreDriverCal2Pad1, BFDataByteTxPreDriverCal2Pad1, 0, TxPrePNDataDqs},
1438 {BFDataDrvStren, BFDataByteTxPreDriverCal2Pad2, BFDataByteTxPreDriverCal2Pad2, 0, TxPrePNDataDqs},
1439 {BFDataDrvStren, BFDataByteTxPreDriverCal, BFDataByteTxPreDriverCal, 8, TxPrePNDataDqs},
1440 // 4. Program TxPreP/TxPreN for Cmd/Addr according toTable 16 if VDDIO is 1.5V or Table 17 if 1.35V.
1441 // A. Program D18F2x[1,0]9C_x0D0F_[C,8][1:0][12,0E,0A,06]={0000b, TxPreP, TxPreN}.
1442 // B. Program D18F2x[1,0]9C_x0D0F_[C,8][1:0]02={1000b, TxPreP, TxPreN}.
1443 {BFCsOdtDrvStren, BFCmdAddr0TxPreDriverCal2Pad1, BFCmdAddr0TxPreDriverCal2Pad2, 0, TxPrePNCmdAddr},
1444 {BFAddrCmdDrvStren, BFCmdAddr1TxPreDriverCal2Pad1, BFAddrTxPreDriverCal2Pad4, 0, TxPrePNCmdAddr},
1445 {BFCsOdtDrvStren, BFCmdAddr0TxPreDriverCalPad0, BFCmdAddr0TxPreDriverCalPad0, 8, TxPrePNCmdAddr},
1446 {BFCkeDrvStren, BFAddrTxPreDriverCalPad0, BFAddrTxPreDriverCalPad0, 8, TxPrePNCmdAddr},
1447 {BFAddrCmdDrvStren, BFCmdAddr1TxPreDriverCalPad0, BFCmdAddr1TxPreDriverCalPad0, 8, TxPrePNCmdAddr},
1448 // 5. Program TxPreP/TxPreN for Clock according toTable 18 if VDDIO is 1.5V or Table 19 if 1.35V.
1449 // A. Program D18F2x[1,0]9C_x0D0F_2[1:0]02={1000b, TxPreP, TxPreN}.
1450 {BFClkDrvStren, BFClock0TxPreDriverCalPad0, BFClock1TxPreDriverCalPad0, 8, TxPrePNClock}
1453 BIT_FIELD_NAME CurrentBitField;
1455 CONST UINT16 (*TxPrePNArray)[5];
1463 NBPtr->SwitchDCT (NBPtr, 0);
1464 // 1. Program D18F2x[1,0]9C_x0D0F_E003[DisAutoComp, DisablePreDriverCal] = {1b, 1b}.
1465 MemNSetBitFieldNb (NBPtr, BFDisablePredriverCal, 0x6000);
1466 NBPtr->SwitchDCT (NBPtr, Dct);
1468 SpeedMask = (UINT16) 1 << (NBPtr->DCTPtr->Timings.Speed / 66);
1469 Voltage = (UINT8) CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage);
1471 for (j = 0; j < GET_SIZE_OF (PhyCompInitBitField); j ++) {
1472 i = (UINT8) MemNGetBitFieldNb (NBPtr, PhyCompInitBitField[j].IndexBitField);
1473 TxPrePNArray = PhyCompInitBitField[j].TxPrePN[Voltage];
1474 for (k = 0; k < 3; k ++) {
1475 if ((TxPrePNArray[k][0] & SpeedMask) != 0) {
1476 for (CurrentBitField = PhyCompInitBitField[j].StartTargetBitField; CurrentBitField <= PhyCompInitBitField[j].EndTargetBitField; CurrentBitField ++) {
1477 MemNSetBitFieldNb (NBPtr, CurrentBitField, ((PhyCompInitBitField[j].ExtraValue << 12) | TxPrePNArray[k][i + 1]));
1485 NBPtr->FamilySpecificHook[ForceAutoComp] (NBPtr, NBPtr);
1488 /*-----------------------------------------------------------------------------
1491 * This function re-enable phy compensation.
1493 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1494 * @param[in,out] OptParam - Optional parameter
1497 * ----------------------------------------------------------------------------
1500 MemNReEnablePhyCompNb (
1501 IN OUT MEM_NB_BLOCK *NBPtr,
1502 IN OUT VOID *OptParam
1509 NBPtr->SwitchDCT (NBPtr, 0);
1510 // Clear DisableCal and set DisablePredriverCal
1511 MemNSetBitFieldNb (NBPtr, BFDisablePredriverCal, 0x2000);
1512 NBPtr->SwitchDCT (NBPtr, Dct);
1517 /*-----------------------------------------------------------------------------
1520 * This function calculates the value of WrDqDqsEarly and programs it into
1521 * the DCT and adds it to the WrDqsGrossDelay of each byte lane on each
1522 * DIMM of the channel.
1525 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1526 * @param[in,out] OptParam - Optional parameter
1529 * ----------------------------------------------------------------------------
1532 MemNCalcWrDqDqsEarlyUnb (
1533 IN OUT MEM_NB_BLOCK *NBPtr,
1534 IN OUT VOID *OptParam
1537 MEM_TECH_BLOCK *TechPtr;
1539 CH_DEF_STRUCT *ChannelPtr;
1542 UINT8 *WrDqsDlysPtr;
1545 ASSERT ((NBPtr->IsSupported[WLSeedAdjust]) && (NBPtr->IsSupported[WLNegativeDelay]));
1547 TechPtr = NBPtr->TechPtr;
1548 ChannelPtr = NBPtr->ChannelPtr;
1549 DCTPtr = NBPtr->DCTPtr;
1551 ASSERT (NBPtr != NULL);
1552 ASSERT (ChannelPtr != NULL);
1553 ASSERT (DCTPtr != NULL);
1556 // - The Critical Gross Delay (CGD) is the minimum GrossDly of all byte lanes and all DIMMs.
1557 // - If (CGD < 0) Then
1558 // - D18F2xA8_dct[1:0][WrDqDqsEarly] = ABS(CGD)
1559 // - WrDqsGrossDly = GrossDly + WrDqDqsEarly
1561 // - D18F2xA8_dct[1:0][WrDqDqsEarly] = 0.
1562 // - WrDqsGrossDly = GrossDly
1565 if (TechPtr->WLCriticalDelay < 0) {
1566 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCalculating WrDqDqsEarly, adjusting WrDqs.\n");
1567 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMin. Critical Delay: %x\n", TechPtr->WLCriticalDelay);
1568 // We've saved the entire negative delay value, so take the ABS and convert to GrossDly.
1569 WrDqDqsEarly = (UINT8) (0x00FF &((((ABS (TechPtr->WLCriticalDelay)) + 0x1F) / 0x20)));
1570 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tWrDqDqsEarly : %02x\n\n", WrDqDqsEarly);
1572 // Loop through All WrDqsDlys on all DIMMs
1574 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
1575 if ((NBPtr->MCTPtr->Status[SbLrdimms]) ? ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << Dimm)) != 0) :
1576 ((DCTPtr->Timings.CsEnabled & ((UINT16) 3 << (Dimm << 1))) != 0)) {
1578 // If LRDIMMs, only include the physical dimms, not logical Dimms
1580 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tDimm %x:", Dimm);
1581 WrDqsDlysPtr = &(ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ())]);
1582 for (ByteLane = 0; ByteLane < TechPtr->DlyTableWidth (); ByteLane++) {
1583 WrDqsDlysPtr[ByteLane] += (WrDqDqsEarly << 5);
1584 NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), WrDqsDlysPtr[ByteLane]);
1585 IDS_HDT_CONSOLE (MEM_FLOW, " %02x", WrDqsDlysPtr[ByteLane]);
1587 IDS_HDT_CONSOLE (MEM_FLOW, "\n");
1591 MemNSetBitFieldNb (NBPtr, BFWrDqDqsEarly, WrDqDqsEarly);
1595 /*-----------------------------------------------------------------------------
1598 * This function forces phy to M0 state
1600 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1601 * @param[in,out] *OptParam - Optional parameter
1603 * @return FALSE - always
1604 * ----------------------------------------------------------------------------
1607 MemNForcePhyToM0Unb (
1608 IN OUT MEM_NB_BLOCK *NBPtr,
1609 IN OUT VOID *OptParam
1612 // 1. Program D18F2x9C_x0D0F_E013_dct[1:0] = 0118h.
1613 MemNBrdcstSetNb (NBPtr, BFPllRegWaitTime, 0x118);
1614 // 2. Force the phy to M0 with the following sequence:
1615 // A. Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 190h. Restore the default PLL lock time.
1616 MemNBrdcstSetNb (NBPtr, BFPllLockTime, NBPtr->FreqChangeParam->PllLockTimeDefault);
1617 // B. For each DCT: Program D18F2x9C_x0000_000B_dct[1:0] = 80800000h.
1618 MemNBrdcstSetNb (NBPtr, BFDramPhyStatusReg, 0x80800000);
1619 NBPtr->SwitchDCT (NBPtr, 0);
1620 // C. Program D18F2x9C_x0D0F_E018_dct[0][PhyPSMasterChannel] = 0.
1621 MemNSetBitFieldNb (NBPtr, BFPhyPSMasterChannel, 0);
1622 // D. Program D18F2x9C_x0000_000B_dct[0] = 40000000h. CH0 only;
1623 MemNSetBitFieldNb (NBPtr, BFDramPhyStatusReg, 0x40000000);
1624 // E. For each DCT: Program D18F2x9C_x0000_000B_dct[1:0] = 80000000h.
1625 MemNBrdcstSetNb (NBPtr, BFDramPhyStatusReg, 0x80000000);
1630 /*-----------------------------------------------------------------------------
1633 * This function sets SkewMemClk before enabling MemClk
1635 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1636 * @param[in,out] *OptParam - Optional parameter
1638 * @return TRUE - always
1639 * ----------------------------------------------------------------------------
1642 MemNSetSkewMemClkUnb (
1643 IN OUT MEM_NB_BLOCK *NBPtr,
1644 IN OUT VOID *OptParam
1649 // SkewMemClk is set to 1 if all DCTs are enabled, else 0.
1650 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1651 MemNSwitchDCTNb (NBPtr, Dct);
1652 if (NBPtr->DCTPtr->Timings.DctMemSize == 0) {
1656 MemNSwitchDCTNb (NBPtr, 0);
1657 if (Dct == NBPtr->DctCount) {
1658 MemNSetBitFieldNb (NBPtr, BFSkewMemClk, 0x10);
1660 MemNSetBitFieldNb (NBPtr, BFSkewMemClk, 0);
1666 /* -----------------------------------------------------------------------------*/
1669 * This function masks the RdDqsDly Bit 0 before writing to register for UNB.
1671 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1672 * @param[in,out] *Offset - Bit offset of the field to be programmed
1677 MemNAdjustRdDqsDlyOffsetUnb (
1678 IN OUT MEM_NB_BLOCK *NBPtr,
1682 *(UINT16*) Offset = *(UINT16*) Offset + 1;
1686 /* -----------------------------------------------------------------------------*/
1690 * This function delays MEMCLK to prevent WrDqs skew due to negative PRE result.
1693 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1694 * @param[in,out] OptParam - Optional parameter
1697 * ----------------------------------------------------------------------------
1700 MemNCalcWrDqDqsEarlyClientNb (
1701 IN OUT MEM_NB_BLOCK *NBPtr,
1702 IN OUT VOID *OptParam
1705 MEM_TECH_BLOCK *TechPtr;
1707 CH_DEF_STRUCT *ChannelPtr;
1710 UINT8 *WrDqsDlysPtr;
1711 UINT8 NewClkDllDelay;
1712 UINT16 ClkDllFineDly;
1715 TechPtr = NBPtr->TechPtr;
1716 ChannelPtr = NBPtr->ChannelPtr;
1717 DCTPtr = NBPtr->DCTPtr;
1719 ASSERT (NBPtr != NULL);
1720 ASSERT (ChannelPtr != NULL);
1721 ASSERT (DCTPtr != NULL);
1723 if (NBPtr->IsSupported[WLNegativeDelay]) {
1724 if (TechPtr->WLCriticalDelay < 0) {
1725 NewClkDllDelay = (UINT8) ABS (TechPtr->WLCriticalDelay);
1727 // Prepare new delay for MEMCLK
1728 ClkDllFineDly = (UINT16) ((MemNGetBitFieldNb (NBPtr, BFPhyClkDllFine0) & 0xBF60) | NewClkDllDelay);
1730 // Program bit 7(FenceBit) = 1 if NewClkDllDelay >= > F2x9C[FenceThresholdTxPad], else 0.
1731 ClkDllFineDly |= (NewClkDllDelay >= MemNGetBitFieldNb (NBPtr, BFPhyFence)) ? 0x80 : 0;
1733 // Apply new delay to both chiplets
1734 MemNSetBitFieldNb (NBPtr, BFPhyClkDllFine0, ClkDllFineDly | 0x4000);
1735 MemNSetBitFieldNb (NBPtr, BFPhyClkDllFine0, ClkDllFineDly);
1736 MemNSetBitFieldNb (NBPtr, BFPhyClkDllFine1, ClkDllFineDly | 0x4000);
1737 MemNSetBitFieldNb (NBPtr, BFPhyClkDllFine1, ClkDllFineDly);
1738 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tShift MemClk, AddrCmd, CsOdt, Cke by %d to eliminate negative WL\n", NewClkDllDelay);
1741 // Adjust AddrCmd/CsOdt/Cke timing by amount MemClk was delayed
1743 AddrCmdTmg = MemNGetBitFieldNb (NBPtr, BFAddrTmgControl);
1744 AddrCmdTmg += (NewClkDllDelay << 16) | (NewClkDllDelay << 8) | NewClkDllDelay;
1745 AddrCmdTmg &= 0x003F3F3F;
1746 MemNSetBitFieldNb (NBPtr, BFAddrTmgControl, AddrCmdTmg);
1749 // Adjust all WrDqsDlys on all DIMMs of the current channel
1751 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
1752 if ((DCTPtr->Timings.CsEnabled & ((UINT16)3 << (Dimm << 1))) != 0) {
1753 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tCS%d\n\t\t\tWrDqs:", Dimm << 1);
1754 WrDqsDlysPtr = &(ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ())]);
1755 for (ByteLane = 0; ByteLane < 8; ByteLane++) {
1756 WrDqsDlysPtr[ByteLane] = (UINT8) (WrDqsDlysPtr[ByteLane] + NewClkDllDelay);
1757 NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), WrDqsDlysPtr[ByteLane]);
1758 IDS_HDT_CONSOLE (MEM_FLOW, " %02x", WrDqsDlysPtr[ByteLane]);
1760 IDS_HDT_CONSOLE (MEM_FLOW, "\n");
1768 /* -----------------------------------------------------------------------------*/
1772 * This function initializes RxEn Delays for RxEn seedless training
1775 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1776 * @param[in,out] OptParam - Optional parameter
1779 * ----------------------------------------------------------------------------
1782 MemNInitializeRxEnSeedlessTrainingUnb (
1783 IN OUT MEM_NB_BLOCK *NBPtr,
1784 IN OUT VOID *OptParam
1788 // Save original PRE based RxEnDly for RxEn Seedless training
1789 for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
1790 NBPtr->TechPtr->RxOrig[ByteLane] = NBPtr->ChannelPtr->RcvEnDlys[(NBPtr->TechPtr->ChipSel >> 1) * NBPtr->TechPtr->DlyTableWidth () + ByteLane];
1794 /*-----------------------------------------------------------------------------
1797 * This function checks each bytelane for no window error.
1800 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1801 * @param[in,out] OptParam - Optional parameter
1804 * ----------------------------------------------------------------------------
1807 MemNTrackRxEnSeedlessRdWrNoWindBLErrorUnb (
1808 IN OUT MEM_NB_BLOCK *NBPtr,
1809 IN OUT VOID *OptParam
1812 MemTTrackRxEnSeedlessRdWrNoWindBLError (NBPtr->TechPtr, OptParam);
1815 /*-----------------------------------------------------------------------------
1818 * This function checks each bytelane for small window error.
1821 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1822 * @param[in,out] OptParam - Optional parameter
1825 * ----------------------------------------------------------------------------
1828 MemNTrackRxEnSeedlessRdWrSmallWindBLErrorUnb (
1829 IN OUT MEM_NB_BLOCK *NBPtr,
1830 IN OUT VOID *OptParam
1833 MemTTrackRxEnSeedlessRdWrSmallWindBLError (NBPtr->TechPtr, OptParam);
1836 /*-----------------------------------------------------------------------------
1839 * This function initializes a ByteLaneError error.
1842 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1843 * @param[in,out] OptParam - Optional parameter
1846 * ----------------------------------------------------------------------------
1849 MemNInitialzeRxEnSeedlessByteLaneErrorUnb (
1850 IN OUT MEM_NB_BLOCK *NBPtr,
1851 IN OUT VOID *OptParam
1855 for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
1856 NBPtr->TechPtr->ByteLaneError[ByteLane] = FALSE; // All Bytelanes have no errors
1860 /* -----------------------------------------------------------------------------*/
1864 * This function sets phy power saving related settings in different MPstate context.
1867 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
1870 * ----------------------------------------------------------------------------
1873 MemNPhyPowerSavingMPstateUnb (
1874 IN OUT MEM_NB_BLOCK *NBPtr
1877 STATIC UINT8 Sequence[] = {8, 4, 3, 5, 2, 6, 1, 7, 0};
1881 UINT8 MaxRxStggrDly;
1882 UINT8 MinRcvEnGrossDly;
1883 UINT8 MinWrDatGrossDly;
1887 UINT8 MaxTxStggrDly;
1891 IDS_HDT_CONSOLE (MEM_FLOW, "Start Phy power saving setting for memory Pstate %d\n", NBPtr->MemPstate);
1892 // 4. Program D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][DllDisEarlyU] = 1b.
1893 // 5. Program D18F2x9C_x0D0F_0[F,8:0]13_dct[1:0][DllDisEarlyL] = 1b.
1894 // 6. D18F2x9C_x0D0F_0[F,7:0][53,13]_dct[1:0][RxDqsUDllPowerDown] = 1.
1895 MemNSetBitFieldNb (NBPtr, BFPhy0x0D0F0F13, MemNGetBitFieldNb (NBPtr, BFPhy0x0D0F0F13) | 0x83);
1896 // 7. D18F2x9C_x0D0F_812F_dct[1:0][PARTri] = ~D18F2x90_dct[1:0][ParEn].
1897 // 8. D18F2x9C_x0D0F_812F_dct[1:0][Add17Tri, Add16Tri] = {1b, 1b}
1898 if (NBPtr->MemPstate == MEMORY_PSTATE0) {
1899 MemNSetBitFieldNb (NBPtr, BFAddrCmdTri, MemNGetBitFieldNb (NBPtr, BFAddrCmdTri) | 0xA1);
1901 // 9. IF (DimmsPopulated == 1)&& ((D18F2x9C_x0000_0000_dct[1:0]_mp[1:0][CkeDrvStren]==010b) ||
1902 // (D18F2x9C_x0000_0000_dct[1:0]_mp[1:0][CkeDrvStren]==011b)) THEN THEN
1903 // program D18F2x9C_x0D0F_C0[40,00]_dct[1:0][LowPowerDrvStrengthEn] = 1
1904 // ELSE program D18F2x9C_x0D0F_C0[40,00]_dct[1:0][LowPowerDrvStrengthEn] = 0 ENDIF.
1905 if ((NBPtr->ChannelPtr->Dimms == 1) && ((MemNGetBitFieldNb (NBPtr, BFCkeDrvStren) == 2) || (MemNGetBitFieldNb (NBPtr, BFCkeDrvStren) == 3))) {
1906 MemNSetBitFieldNb (NBPtr, BFReserved00C, 0x100);
1908 // 10. Program D18F2x9C_x0D0F_0[F,7:0][50,10]_dct[1:0][EnRxPadStandby] = IF
1909 // (D18F2x94_dct[1:0][MemClkFreq] <= 800 MHz) THEN 1 ELSE 0 ENDIF.
1910 MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) ? 0x1000 : 0);
1911 // 11. Program D18F2x9C_x0000_000D_dct[1:0]_mp[1:0] as follows:
1912 // If (DDR rate < = 1600) TxMaxDurDllNoLock = RxMaxDurDllNoLock = 8h
1913 // else TxMaxDurDllNoLock = RxMaxDurDllNoLock = 7h.
1914 if (NBPtr->DCTPtr->Timings.Speed <= DDR1600_FREQUENCY) {
1915 MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 8);
1916 MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 8);
1918 MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 7);
1919 MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 7);
1921 // TxCPUpdPeriod = RxCPUpdPeriod = 011b.
1922 MemNSetBitFieldNb (NBPtr, BFTxCPUpdPeriod, 3);
1923 MemNSetBitFieldNb (NBPtr, BFRxCPUpdPeriod, 3);
1924 // TxDLLWakeupTime = RxDLLWakeupTime = 11b.
1925 MemNSetBitFieldNb (NBPtr, BFTxDLLWakeupTime, 3);
1926 MemNSetBitFieldNb (NBPtr, BFRxDLLWakeupTime, 3);
1928 if (NBPtr->IsSupported[DllStaggerEn]) {
1929 // 12. Program D18F2x9C_x0D0F_0[F,7:0][5C,1C]_dct[1:0] as follows.
1930 // Let Numlanes = 8. = 9 with ECC.
1931 NumLanes = (NBPtr->MCTPtr->Status[SbEccDimms] && NBPtr->IsSupported[EccByteTraining]) ? 9 : 8;
1932 // RxDllStggrEn = TxDllStggrEn = 1.
1933 for (i = 0; i < 9; i ++) {
1934 DllPower[i] = 0x8080;
1936 // If (DDR rate > = 1866) DllWakeTime = 1, Else DllWakeTime = 0.
1937 DllWakeTime = (NBPtr->DCTPtr->Timings.Speed >= DDR1866_FREQUENCY) ? 1 : 0;
1938 // Let MaxRxStggrDly = (Tcl*2) + MIN(DqsRcvEnGrossDelay for all byte lanes (see D18F2x9C_x0000_00[2A:10]_dct[1:0]_mp[1:0])) - 4.
1939 MinRcvEnGrossDly = NBPtr->TechPtr->GetMinMaxGrossDly (NBPtr->TechPtr, AccessRcvEnDly, FALSE);
1940 ASSERT ((NBPtr->DCTPtr->Timings.CasL * 2 + MinRcvEnGrossDly) >= 4);
1941 MaxRxStggrDly = NBPtr->DCTPtr->Timings.CasL * 2 + MinRcvEnGrossDly - 4;
1942 // Let (real) dRxStggrDly = (MaxRxStggrDly - DllWakeTime) / (Numlanes - 1).
1943 ASSERT (MaxRxStggrDly >= DllWakeTime);
1944 dRxStggrDly = (MaxRxStggrDly - DllWakeTime) / (NumLanes - 1);
1945 IDS_HDT_CONSOLE (MEM_FLOW, "\tMinimum RcvEnGrossDly: 0x%02x MaxRxStggrDly: 0x%02x dRxStggrDly: 0x%02x\n", MinRcvEnGrossDly, MaxRxStggrDly, dRxStggrDly);
1946 // For each byte lane in the ordered sequence {8, 4, 3, 5, 2, 6, 1, 7, 0}, program RxDllStggrDly[5:0] = an
1947 // increasing value, starting with 0 for the first byte lane in the sequence and increasing at a rate of dRxStggrDly
1948 // for each subsequent byte lane. Convert the real to integer by rounding down or using C (int) typecast after linearization.
1951 for (; i < 9; i ++) {
1952 DllPower[Sequence[i]] |= ((TempStggrDly & 0x3F) << 8);
1953 TempStggrDly = TempStggrDly + dRxStggrDly;
1956 // Let MaxTxStggrDly = (Tcwl*2) + MIN(MIN (WrDatGrossDly for all byte lanes (see
1957 // D18F2x9C_x0000_0[3:0]0[2:1]_dct[1:0]_mp[1:0])), MIN(DqsRcvEnGrossDelay for all byte lanes (see
1958 // D18F2x9C_x0000_00[2A:10]_dct[1:0]_mp[1:0])) - 4.
1959 Tcwl = (UINT8) MemNGetBitFieldNb (NBPtr, BFTcwl);
1960 MinWrDatGrossDly = NBPtr->TechPtr->GetMinMaxGrossDly (NBPtr->TechPtr, AccessWrDatDly, FALSE);
1961 MaxTxStggrDly = Tcwl * 2 + MIN (MinRcvEnGrossDly, MinWrDatGrossDly) - 4;
1962 // Let dTxStggrDly = (MaxTxStggrDly - DllWakeTime) / (Numlanes - 1).
1963 ASSERT (MaxTxStggrDly >= DllWakeTime);
1964 dTxStggrDly = (MaxTxStggrDly - DllWakeTime) / (NumLanes - 1);
1965 // For each byte lane in the ordered sequence {8, 4, 3, 5, 2, 6, 1, 7, 0}, program TxDllStggrDly[5:0] = an
1966 // increasing integer value, starting with 0 for the first byte lane in the sequence and increasing at a rate of
1967 // dTxStggrDly for each subsequent byte lane.
1968 IDS_HDT_CONSOLE (MEM_FLOW, "\tMinimum WrDatGrossDly: 0x%02x MaxTxStggrDly: 0x%02x dTxStggrDly: 0x%02x\n", MinWrDatGrossDly, MaxTxStggrDly, dTxStggrDly);
1971 for (; i < 9; i ++) {
1972 DllPower[Sequence[i]] |= (TempStggrDly & 0x3F);
1973 TempStggrDly = TempStggrDly + dTxStggrDly;
1976 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t\tByte Lane : ECC 07 06 05 04 03 02 01 00\n");
1977 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t\tDll Power : %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
1978 DllPower[8], DllPower[7], DllPower[6], DllPower[5], DllPower[4], DllPower[3], DllPower[2], DllPower[1], DllPower[0]);
1980 for (i = 0; i < NumLanes; i ++) {
1981 MemNSetBitFieldNb (NBPtr, BFDataByteDllPowerMgnByte0 + i, (MemNGetBitFieldNb (NBPtr, BFDataByteDllPowerMgnByte0 + i) & 0x4040) | DllPower[i]);
1984 // 13. Program D18F2x248_dct[1:0]_mp[1:0] and then D18F2x9C_x0D0F_0[F,7:0][53,13]_dct[1:0] as follows:
1985 // For M1 context program RxChMntClkEn=RxSsbMntClkEn=0.
1986 // For M0 context program RxChMntClkEn=RxSsbMntClkEn=1.
1987 if (NBPtr->MemPstate == MEMORY_PSTATE1) {
1988 MemNSetBitFieldNb (NBPtr, BFRxChMntClkEn, 0);
1989 MemNSetBitFieldNb (NBPtr, BFRxSsbMntClkEn, 0);
1991 MemNSetBitFieldNb (NBPtr, BFRxChMntClkEn, 1);
1992 MemNSetBitFieldNb (NBPtr, BFRxSsbMntClkEn, 0x100);
1995 IDS_OPTION_HOOK (IDS_PHY_DLL_STANDBY_CTRL, NBPtr, &NBPtr->MemPtr->StdHeader);
1998 /* -----------------------------------------------------------------------------*/
2001 * This function resets RxFifo pointer during Read DQS training
2003 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2004 * @param[in,out] *OptParam - Optional parameter
2010 MemNResetRxFifoPtrClientNb (
2011 IN OUT MEM_NB_BLOCK *NBPtr,
2012 IN OUT VOID *OptParam
2015 if (NBPtr->TechPtr->Direction == DQS_READ_DIR) {
2016 MemNSetBitFieldNb (NBPtr, BFRxPtrInitReq, 1);
2017 MemNPollBitFieldNb (NBPtr, BFRxPtrInitReq, 0, PCI_ACCESS_TIMEOUT, FALSE);
2022 /* -----------------------------------------------------------------------------*/
2024 * This function adjusts the Phase Mask based on ECC.
2027 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
2028 * @param[in,out] OptParam - Optional parameter
2031 * ----------------------------------------------------------------------------
2034 MemNAdjust2DPhaseMaskBasedOnEccUnb (
2035 IN OUT MEM_NB_BLOCK *NBPtr,
2036 IN OUT VOID *OptParam
2039 NBPtr->PhaseLaneMask = NBPtr->PhaseLaneMask & (UINT32) (NBPtr->MCTPtr->Status[SbEccDimms] ? 0x0FFFF : 0x3FFFF);