7 * Northbridge Phy support for Orochi
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/NB/OR)
12 * @e \$Revision: 58126 $ @e \$Date: 2011-08-21 23:38:29 -0600 (Sun, 21 Aug 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 *----------------------------------------------------------------------------
65 #include "OptionMemory.h" // need def for MEM_FEAT_BLOCK_NB
67 #include "cpuRegisters.h"
68 #include "PlatformMemoryConfiguration.h"
69 #include "F15PackageType.h"
75 #define FILECODE PROC_MEM_NB_OR_MNPHYOR_FILECODE
76 /*----------------------------------------------------------------------------
77 * DEFINITIONS AND MACROS
79 *----------------------------------------------------------------------------
84 /// The structure of TxPrePN tables
86 UINT32 Speed; ///< Applied memory speed
87 UINT16 TxPrePNVal[4]; ///< Table values
90 /// The entry of individual TxPrePN tables
92 UINT8 TxPrePNTblSize; ///< Total Table size
93 CONST TXPREPN_STRUCT *TxPrePNTblPtr; ///< Pointer to the table
96 /// Type of an entry for processing phy init compensation for Orochi
98 BIT_FIELD_NAME IndexBitField; ///< Bit field on which the value is decided
99 BIT_FIELD_NAME StartTargetBitField; ///< First bit field to be modified
100 BIT_FIELD_NAME EndTargetBitField; ///< Last bit field to be modified
101 UINT16 ExtraValue; ///< Extra value needed to be written to bit field
102 CONST TXPREPN_ENTRY *TxPrePN; ///< Pointer to slew rate table
104 /*----------------------------------------------------------------------------
105 * TYPEDEFS AND STRUCTURES
107 *----------------------------------------------------------------------------
110 /*----------------------------------------------------------------------------
111 * PROTOTYPES OF LOCAL FUNCTIONS
113 *----------------------------------------------------------------------------
118 /*----------------------------------------------------------------------------
121 *----------------------------------------------------------------------------
123 /* -----------------------------------------------------------------------------*/
126 /* -----------------------------------------------------------------------------*/
130 * This function initializes the DDR phy compensation logic
132 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
138 IN OUT MEM_NB_BLOCK *NBPtr
142 // Phy Predriver Calibration Codes for Data/DQS
144 CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV15Or[] = {
145 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V
146 {DDR667 + DDR800, {0x924, 0x924, 0x924, 0x924}},
147 {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}},
148 {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}
150 CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV135Or[] = {
151 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V
152 {DDR667 + DDR800, {0xFF6, 0xB6D, 0xB6D, 0x924}},
153 {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}},
154 {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}
156 CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV125Or[] = {
157 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V
158 {DDR667 + DDR800, {0xFF6, 0xDAD, 0xDAD, 0x924}},
159 {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}},
160 {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}
162 CONST STATIC TXPREPN_ENTRY TxPrePNDataDqsOr[] = {
163 {GET_SIZE_OF (TxPrePNDataDqsV15Or), (TXPREPN_STRUCT *)&TxPrePNDataDqsV15Or},
164 {GET_SIZE_OF (TxPrePNDataDqsV135Or), (TXPREPN_STRUCT *)&TxPrePNDataDqsV135Or},
165 {GET_SIZE_OF (TxPrePNDataDqsV125Or), (TXPREPN_STRUCT *)&TxPrePNDataDqsV125Or}
169 // Phy Predriver Calibration Codes for Data/DQS
171 CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV15OrB1[] = {
172 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V
173 {DDR667 + DDR800, {0xB6D, 0x6DB, 0x492, 0x492}},
174 {DDR1066 + DDR1333, {0xFFF, 0x924, 0x6DB, 0x6DB}},
175 {DDR1600 + DDR1866, {0xFFF, 0xFFF, 0xFFF, 0xB6D}}
177 CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV135OrB1[] = {
178 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V
179 {DDR667 + DDR800, {0xFFF, 0x924, 0x6DB, 0x492}},
180 {DDR1066 + DDR1333, {0xFFF, 0xDB6, 0xB6D, 0x6DB}},
181 {DDR1600 + DDR1866, {0xFFF, 0xFFF, 0xFFF, 0xDB6}}
183 CONST STATIC TXPREPN_STRUCT TxPrePNDataDqsV125OrB1[] = {
184 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V
185 {DDR667 + DDR800, {0xFFF, 0xB6D, 0x924, 0x6DB}},
186 {DDR1066 + DDR1333, {0xFFF, 0xFFF, 0xDB6, 0x924}},
187 {DDR1600 + DDR1866, {0xFFF, 0xFFF, 0xFFF, 0xFFF}}
189 CONST STATIC TXPREPN_ENTRY TxPrePNDataDqsOrB1[] = {
190 {GET_SIZE_OF (TxPrePNDataDqsV15OrB1), (TXPREPN_STRUCT *)&TxPrePNDataDqsV15OrB1},
191 {GET_SIZE_OF (TxPrePNDataDqsV135OrB1), (TXPREPN_STRUCT *)&TxPrePNDataDqsV135OrB1},
192 {GET_SIZE_OF (TxPrePNDataDqsV125OrB1), (TXPREPN_STRUCT *)&TxPrePNDataDqsV125OrB1}
196 // Phy Predriver Calibration Codes for Cmd/Addr
198 CONST STATIC TXPREPN_STRUCT TxPrePNCmdAddrV15Or[] = {
199 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V
200 {DDR667 + DDR800, {0x492, 0x492, 0x492, 0x492}},
201 {DDR1066 + DDR1333, {0x6DB, 0x6DB, 0x6DB, 0x6DB}},
202 {DDR1600 + DDR1866, {0xB6D, 0xB6D, 0xB6D, 0xB6D}}
204 CONST STATIC TXPREPN_STRUCT TxPrePNCmdAddrV135Or[] = {
205 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V
206 {DDR667 + DDR800, {0x492, 0x492, 0x492, 0x492}},
207 {DDR1066 + DDR1333, {0x924, 0x6DB, 0x6DB, 0x6DB}},
208 {DDR1600 + DDR1866, {0xB6D, 0xB6D, 0x924, 0x924}}
210 CONST STATIC TXPREPN_STRUCT TxPrePNCmdAddrV125Or[] = {
211 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V
212 {DDR667 + DDR800, {0x492, 0x492, 0x492, 0x492}},
213 {DDR1066 + DDR1333, {0xDAD, 0x924, 0x6DB, 0x492}},
214 {DDR1600 + DDR1866, {0xFF6, 0xDAD, 0xB64, 0xB64}}
216 CONST STATIC TXPREPN_ENTRY TxPrePNCmdAddrOr[] = {
217 {GET_SIZE_OF (TxPrePNCmdAddrV15Or), (TXPREPN_STRUCT *)&TxPrePNCmdAddrV15Or},
218 {GET_SIZE_OF (TxPrePNCmdAddrV135Or), (TXPREPN_STRUCT *)&TxPrePNCmdAddrV135Or},
219 {GET_SIZE_OF (TxPrePNCmdAddrV125Or), (TXPREPN_STRUCT *)&TxPrePNCmdAddrV125Or}
223 // Phy Predriver Calibration Codes for Clock
225 CONST STATIC TXPREPN_STRUCT TxPrePNClockV15Or[] = {
226 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.5V
227 {DDR667 + DDR800, {0x924, 0x924, 0x924, 0x924}},
228 {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xB6D}},
229 {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}
231 CONST STATIC TXPREPN_STRUCT TxPrePNClockV135Or[] = {
232 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.35V
233 {DDR667 + DDR800, {0xDAD, 0xDAD, 0x924, 0x924}},
234 {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xDAD}},
235 {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xDAD}}
237 CONST STATIC TXPREPN_STRUCT TxPrePNClockV125Or[] = {
238 //{TxPreP, TxPreN}[Speed][Drive Strength] at 1.25V
239 {DDR667 + DDR800, {0xDAD, 0xDAD, 0x924, 0x924}},
240 {DDR1066 + DDR1333, {0xFF6, 0xFF6, 0xFF6, 0xFF6}},
241 {DDR1600 + DDR1866, {0xFF6, 0xFF6, 0xFF6, 0xFF6}}
243 CONST STATIC TXPREPN_ENTRY TxPrePNClockOr[] = {
244 {GET_SIZE_OF (TxPrePNClockV15Or), (TXPREPN_STRUCT *)&TxPrePNClockV15Or},
245 {GET_SIZE_OF (TxPrePNClockV135Or), (TXPREPN_STRUCT *)&TxPrePNClockV135Or},
246 {GET_SIZE_OF (TxPrePNClockV125Or), (TXPREPN_STRUCT *)&TxPrePNClockV125Or}
250 // Tables to describe the relationship between drive strength bit fields, PreDriver Calibration bit fields and also
251 // the extra value that needs to be written to specific PreDriver bit fields
253 CONST PHY_COMP_INIT_NB PhyCompInitBitFieldOr[] = {
254 // 3. Program TxPreP/TxPreN for Data and DQS according toTable 46 if VDDIO is 1.5V or Table 47 if 1.35V.
255 // A. Program D18F2x9C_x0D0F_0[F,8:0]0[A,6]_dct[1:0]={0000b, TxPreP, TxPreN}.
256 // B. Program D18F2x9C_x0D0F_0[F,8:0]0[A,6]_dct[1:0]={0000b, TxPreP, TxPreN}.
257 {BFDqsDrvStren, BFDataByteTxPreDriverCal2Pad1, BFDataByteTxPreDriverCal2Pad1, 0, TxPrePNDataDqsOr},
258 {BFDataDrvStren, BFDataByteTxPreDriverCal2Pad2, BFDataByteTxPreDriverCal2Pad2, 0, TxPrePNDataDqsOr},
259 {BFDataDrvStren, BFDataByteTxPreDriverCal, BFDataByteTxPreDriverCal, 8, TxPrePNDataDqsOr},
260 // 4. Program TxPreP/TxPreN for Cmd/Addr according to Table 49 if VDDIO is 1.5V or Table 50 if 1.35V.
261 // A. Program D18F2x9C_x0D0F_[C,8][1:0][12,0E,0A,06]_dct[1:0]={0000b, TxPreP, TxPreN}.
262 // B. Program D18F2x9C_x0D0F_[C,8][1:0]02_dct[1:0]={1000b, TxPreP, TxPreN}.
263 {BFCsOdtDrvStren, BFCmdAddr0TxPreDriverCal2Pad1, BFCmdAddr0TxPreDriverCal2Pad2, 0, TxPrePNCmdAddrOr},
264 {BFAddrCmdDrvStren, BFCmdAddr1TxPreDriverCal2Pad1, BFAddrTxPreDriverCal2Pad4, 0, TxPrePNCmdAddrOr},
265 {BFCsOdtDrvStren, BFCmdAddr0TxPreDriverCalPad0, BFCmdAddr0TxPreDriverCalPad0, 8, TxPrePNCmdAddrOr},
266 {BFCkeDrvStren, BFAddrTxPreDriverCalPad0, BFAddrTxPreDriverCalPad0, 8, TxPrePNCmdAddrOr},
267 {BFAddrCmdDrvStren, BFCmdAddr1TxPreDriverCalPad0, BFCmdAddr1TxPreDriverCalPad0, 8, TxPrePNCmdAddrOr},
268 // 5. Program TxPreP/TxPreN for Clock according to Table 52 if VDDIO is 1.5V or Table 53 if 1.35V.
269 // A. Program D18F2x9C_x0D0F_2[2:0]02_dct[1:0]={1000b, TxPreP, TxPreN}.
270 {BFClkDrvStren, BFClock0TxPreDriverCalPad0, BFClock2TxPreDriverCalPad0, 8, TxPrePNClockOr}
273 BIT_FIELD_NAME CurrentBitField;
281 CONST TXPREPN_STRUCT *TblPtr;
284 NBPtr->SwitchDCT (NBPtr, 0);
285 // 1. Program D18F2x[1,0]9C_x0D0F_E003[DisAutoComp, DisablePreDriverCal] = {1b, 1b}.
286 MemNSetBitFieldNb (NBPtr, BFDisablePredriverCal, 0x6000);
287 NBPtr->SwitchDCT (NBPtr, Dct);
289 SpeedMask = (UINT16) 1 << (NBPtr->DCTPtr->Timings.Speed / 66);
290 Voltage = (UINT8) CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage);
292 for (j = 0; j < GET_SIZE_OF (PhyCompInitBitFieldOr); j ++) {
293 i = (UINT8) MemNGetBitFieldNb (NBPtr, PhyCompInitBitFieldOr[j].IndexBitField);
294 TblPtr = (PhyCompInitBitFieldOr[j].TxPrePN[Voltage]).TxPrePNTblPtr;
295 SizeOfTable = (PhyCompInitBitFieldOr[j].TxPrePN[Voltage]).TxPrePNTblSize;
297 // Uses different TxPrePNDataDqsOr table for OR B1 and later
298 if (((NBPtr->MCTPtr->LogicalCpuid.Revision & AMD_F15_OR_LT_B1) == 0) &&
299 (PhyCompInitBitFieldOr[j].TxPrePN == TxPrePNDataDqsOr)) {
300 ASSERT (Voltage < sizeof (TxPrePNDataDqsOrB1) / sizeof (TxPrePNDataDqsOrB1[0]));
301 TblPtr = TxPrePNDataDqsOrB1[Voltage].TxPrePNTblPtr;
302 SizeOfTable = TxPrePNDataDqsOrB1[Voltage].TxPrePNTblSize;
305 for (k = 0; k < SizeOfTable; k++, TblPtr++) {
306 if ((TblPtr->Speed & SpeedMask) != 0) {
307 for (CurrentBitField = PhyCompInitBitFieldOr[j].StartTargetBitField; CurrentBitField <= PhyCompInitBitFieldOr[j].EndTargetBitField; CurrentBitField ++) {
308 MemNSetBitFieldNb (NBPtr, CurrentBitField, ((PhyCompInitBitFieldOr[j].ExtraValue << 12) | TblPtr->TxPrePNVal[i]));
313 // Asserting if no table is found corresponding to current memory speed.
314 ASSERT (k < SizeOfTable);
318 /* -----------------------------------------------------------------------------*/
322 * This is a general purpose function that executes before DRAM training
324 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
329 MemNBeforeDQSTrainingOr (
330 IN OUT MEM_NB_BLOCK *NBPtr
336 for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) {
337 MemNSwitchDCTNb (NBPtr, Dct);
338 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
340 // 2.10.6.8.2 - BIOS should program D18F2x210_dct[1:0]_nbp[3:0][MaxRdLatency] to 55h.
342 MemNSetBitFieldNb (NBPtr, BFMaxLatency, 0x55);
344 MemNSetBitFieldNb (NBPtr, BFTraceModeEn, 0);
347 // DisDatMsk: Reset: 0. BIOS: IF (G34r1 || C32r1) THEN 1 ELSE 0 ENDIF.
348 PackageType = LibAmdGetPackageType (&(NBPtr->MemPtr->StdHeader));
349 if (PackageType != PACKAGE_TYPE_AM3r2) {
350 MemNSetBitFieldNb (NBPtr, BFDisDatMsk, 1);
354 /* -----------------------------------------------------------------------------*/
358 * This is a function that executes after DRAM training for Orochi
360 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
365 MemNAfterDQSTrainingOr (
366 IN OUT MEM_NB_BLOCK *NBPtr
373 BOOLEAN DllShutDownEn;
375 DllShutDownEn = TRUE;
376 IDS_OPTION_HOOK (IDS_DLL_SHUT_DOWN, &DllShutDownEn, &(NBPtr->MemPtr->StdHeader));
378 for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) {
379 MemNSwitchDCTNb (NBPtr, Dct);
380 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
382 // 2.10.6.6 DCT Training Specific Configuration
384 MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 1);
385 MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 0);
386 if (DllShutDownEn && NBPtr->IsSupported[SetDllShutDown]) {
387 MemNSetBitFieldNb (NBPtr, BFDisDllShutdownSR, 0);
389 MemNSetBitFieldNb (NBPtr , BFForceAutoPchg, 0);
390 MemNSetBitFieldNb (NBPtr , BFDynPageCloseEn, 0);
391 if (NBPtr->RefPtr->EnableBankSwizzle) {
392 MemNSetBitFieldNb (NBPtr, BFBankSwizzleMode, 1);
394 MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0x0F);
395 MemNPowerDownCtlOr (NBPtr);
396 MemNSetBitFieldNb (NBPtr, BFDisSimulRdWr, 0);
397 MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 2);
399 // Post Training values for BFRxMaxDurDllNoLock, BFTxMaxDurDllNoLock,
400 // and BFEnRxPadStandby are handled by Power savings code
402 // BFBwCapEn and BFODTSEn are handled by OnDimmThermal Code
404 // BFDctSelIntLvEn is programmed by Interleaving feature
406 // BFL3Scrub, BFDramScrub, and DramScrubReDirEn are programmed by ECC Feature code
409 MemNSetBitFieldNb (NBPtr, BFL3ScrbRedirDis, 0);
410 // Doing DataTxFifoWrDly override for NB PState 0
411 MemNDataTxFifoWrDlyOverrideOr (NBPtr, NBPtr);
416 // Synch RdDqs__Dly to RdDqsDly for S3 Save/Restore
418 for (Dct = 0; Dct < MAX_DCTS_PER_NODE_OR; Dct++) {
419 MemNSwitchDCTNb (NBPtr, Dct);
420 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
421 if (!(NBPtr->DctCachePtr->Is__x4)) {
422 // Only synch when 1D training has been performed or training with x8 DIMMs
423 for (Dimm = 0; Dimm < 4; Dimm++) {
424 for (Byte = 0; Byte < 9; Byte++) {
425 Dly = (UINT16) MemNGetTrainDlyNb (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, Byte));
426 MemNSetTrainDlyNb (NBPtr, AccessRdDqs__Dly, DIMM_NBBL_ACCESS (Dimm, Byte * 2), Dly);
427 MemNSetTrainDlyNb (NBPtr, AccessRdDqs__Dly, DIMM_NBBL_ACCESS (Dimm, (Byte * 2) + 1), Dly);
428 NBPtr->ChannelPtr->RdDqs__Dlys[(Dimm * MAX_NUMBER_LANES) + (Byte * 2)] = (UINT8) Dly;
429 NBPtr->ChannelPtr->RdDqs__Dlys[(Dimm * MAX_NUMBER_LANES) + (Byte * 2) + 1] = (UINT8) Dly;
436 /* -----------------------------------------------------------------------------*/
439 * This function overrides the seed for hardware based RcvEn training of Orochi.
441 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
442 * @param[in,out] *SeedPtr - Pointer to the seed value.
448 MemNOverrideRcvEnSeedOr (
449 IN OUT MEM_NB_BLOCK *NBPtr,
454 SeedPointer = (UINT16*) SeedPtr;
457 // Get seed value saved in PS block
459 *SeedPointer = NBPtr->PsPtr->HWRxENSeedVal;
460 *SeedPointer -= (0x20 * (UINT16) MemNGetBitFieldNb (NBPtr, BFWrDqDqsEarly));
464 /* -----------------------------------------------------------------------------*/
467 * This function overrides the seed for Pass N hardware based RcvEn training of Orochi.
469 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
470 * @param[in,out] *SeedTotal - Pointer to the SeedTotal
476 MemNOverrideRcvEnSeedPassNOr (
477 IN OUT MEM_NB_BLOCK *NBPtr,
478 IN OUT VOID *SeedTotal
481 UINT16 RegisterDelay;
482 UINT16 SeedTotalPreScaling;
484 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
486 NBPtr->TechPtr->GetDimmSpdBuffer (NBPtr->TechPtr, &SpdBufferPtr, (NBPtr->TechPtr->ChipSel >> 1));
487 RegisterDelay = 0x10 + (((SpdBufferPtr[67] & 1) == 0) ? (0x30 - (SpdBufferPtr[70] & 7)): 0x30);
488 } else if (NBPtr->MCTPtr->Status[SbRegistered]) {
490 RegisterDelay = ((NBPtr->ChannelPtr->CtrlWrd02[(NBPtr->TechPtr->ChipSel >> 1)] & BIT0) == 0) ? 0x20: 0x30;
495 if (NBPtr->TechPtr->PrevPassRcvEnDly[NBPtr->TechPtr->Bytelane] < (0x20 + RegisterDelay)) {
496 SeedTotalPreScaling = 0x20 + RegisterDelay;
498 SeedTotalPreScaling = NBPtr->TechPtr->PrevPassRcvEnDly[NBPtr->TechPtr->Bytelane] - 0x20 - RegisterDelay;
500 *(UINT16*) SeedTotal = ((UINT16) (((UINT32) SeedTotalPreScaling * NBPtr->DCTPtr->Timings.Speed) / NBPtr->TechPtr->PrevSpeed)) + RegisterDelay;
503 /* -----------------------------------------------------------------------------*/
506 * This function overrides the seed for write leveing training of Orochi.
508 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
509 * @param[in,out] *SeedPtr - Pointer to the seed value.
515 MemNOverrideWLSeedOr (
516 IN OUT MEM_NB_BLOCK *NBPtr,
521 CH_DEF_STRUCT *ChannelPtr;
524 MCTPtr = NBPtr->MCTPtr;
525 ChannelPtr = NBPtr->ChannelPtr;
526 RCW2 = ChannelPtr->CtrlWrd02[NBPtr->TechPtr->TargetDIMM];
529 // Get the default value of seed
531 if (ChannelPtr->SODimmPresent != 0) {
535 *(UINT8*) SeedPtr = 0x12;
538 // Get seed value saved in PS block
540 *(UINT8*) SeedPtr = NBPtr->PsPtr->WLSeedVal;
542 if (MCTPtr->Status[SbRegistered]) {
543 *(UINT8*) SeedPtr += ((RCW2 & BIT0) == 0) ? 0 : 0x10;
549 /* -----------------------------------------------------------------------------*/
552 * This function enables nibble based training for Write Levelization for Orochi.
554 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
555 * @param[in,out] *Dimm - Pointer to DIMM to be trained
561 MemNTrainWlPerNibbleOr (
562 IN OUT MEM_NB_BLOCK *NBPtr,
567 if ((NBPtr->ChannelPtr->Dimmx4Present & (1 << *(UINT16*) Dimm)) != 0) {
568 if (NBPtr->TechPtr->TrnNibble <= NIBBLE_1) {
569 //For x4 DIMMs, BIOS trains both nibbles of a byte lane by programming
570 //D18F2x9C_x0000_0008_dct[1:0][TrNibbleSel] to specify the nibble. BIOS repeats steps 3 through
571 //5 and uses the average of the trained values for the delay setting.
572 if (NBPtr->TechPtr->TrnNibble == NIBBLE_1) {
573 NBPtr->SetBitField (NBPtr, BFTrNibbleSel, NBPtr->TechPtr->TrnNibble);
577 IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrDqs: ");
578 for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8) ; ByteLane++) {
579 IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", NBPtr->TechPtr->WlNibbleDly[ByteLane]);
581 IDS_HDT_CONSOLE (MEM_FLOW, " <<< Nibble AVG\n\n");
588 /* -----------------------------------------------------------------------------*/
591 * This function adjusts the WL DQS Delay based on nibble traning results for Orochi.
593 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
594 * @param[in,out] *Delay - Pointer to Wr Dqs Delay
596 * @return FALSE - Supported
597 * @return TRUE - Not supported
600 MemNTrainWlPerNibbleAdjustWLDlyOr (
601 IN OUT MEM_NB_BLOCK *NBPtr,
605 MEM_TECH_BLOCK *TechPtr;
607 TechPtr = NBPtr->TechPtr;
608 Bytelane = TechPtr->Bytelane;
609 if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << TechPtr->TargetDIMM)) != 0) {
610 if (TechPtr->TrnNibble == NIBBLE_1) {
611 *(UINT8*) Delay = (TechPtr->WlNibbleDly[Bytelane] + *(UINT8*) Delay + 1) / 2;
612 if (Bytelane == (NBPtr->MCTPtr->Status[SbEccDimms] ? 8 : 7)) {
613 IDS_HDT_CONSOLE (MEM_FLOW, " <<< Nibble 1");
616 if (Bytelane == (NBPtr->MCTPtr->Status[SbEccDimms] ? 8 : 7)) {
617 IDS_HDT_CONSOLE (MEM_FLOW, " <<< Nibble 0");
620 TechPtr->WlNibbleDly[Bytelane] = *(UINT8*) Delay;
626 /* -----------------------------------------------------------------------------*/
629 * This function sets the correct seed for Nibble based Write Levelization.
631 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
632 * @param[in,out] *WrDqsDly - Pointer to WrDqs value
634 * @return FALSE - Supported
635 * @return TRUE - Not supported
639 MemNTrainWlPerNibbleSeedOr (
640 IN OUT MEM_NB_BLOCK *NBPtr,
641 IN OUT VOID *WrDqsDly
644 if (NBPtr->TechPtr->TrnNibble == NIBBLE_0) {
645 NBPtr->TechPtr->WlNibble0Seed[NBPtr->TechPtr->Bytelane] = *(UINT16*) WrDqsDly;
647 *(UINT16*) WrDqsDly = NBPtr->TechPtr->WlNibble0Seed[NBPtr->TechPtr->Bytelane];
651 /* -----------------------------------------------------------------------------*/
654 * This function initializes nibble based Receiver Enable Training for Orochi.
656 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
657 * @param[in,out] *OptParam - Optional paramater
659 * @return FALSE - Supported
660 * @return TRUE - Not supported
663 MemNInitPerNibbleTrnOr (
664 IN OUT MEM_NB_BLOCK *NBPtr,
665 IN OUT VOID *OptParam
668 // Program D18F2x9C_x0000_0008_dct[1:0][TrNibbleSel]=0
669 NBPtr->TechPtr->TrnNibble = NIBBLE_0;
670 NBPtr->SetBitField (NBPtr, BFTrNibbleSel, NIBBLE_0);
673 /* -----------------------------------------------------------------------------*/
676 * This function enables nibble based Receiver Enable Training for Orochi.
678 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
679 * @param[in,out] *ChipSel - Pointer to ChipSel to be trained
681 * @return FALSE - Supported
682 * @return TRUE - Not supported
686 MemNTrainRxEnPerNibbleOr (
687 IN OUT MEM_NB_BLOCK *NBPtr,
691 if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (*(UINT16*) ChipSel >> 1))) != 0) {
692 if (NBPtr->TechPtr->TrnNibble == NIBBLE_1) {
693 // For x4 DIMMs, BIOS trains both nibbles of a byte lane by programming
694 // D18F2x9C_x0000_0008_dct[1:0][TrNibbleSel] to specify the nibble. BIOS repeats steps 2 through
695 // 7 and uses the average of the trained values for the delay setting.
696 NBPtr->SetBitField (NBPtr, BFTrNibbleSel, NBPtr->TechPtr->TrnNibble);
703 /* -----------------------------------------------------------------------------*/
706 * This function adjusts the RxEn Delay based on nibble traning results for Orochi.
708 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
709 * @param[in,out] *RcvEnDly - Pointer to RcvEn Dqs Delay
711 * @return FALSE - Supported
712 * @return TRUE - Not supported
715 MemNTrainRxEnAdjustDlyPerNibbleOr (
716 IN OUT MEM_NB_BLOCK *NBPtr,
717 IN OUT VOID *RcvEnDly
720 MEM_TECH_BLOCK *TechPtr;
722 TechPtr = NBPtr->TechPtr;
723 Bytelane = TechPtr->Bytelane;
724 if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (TechPtr->ChipSel >> 1))) != 0) {
725 if (TechPtr->TrnNibble == NIBBLE_1) {
726 *(UINT16*) RcvEnDly = (TechPtr->RxEnNibbleDly[Bytelane] + *(UINT16*) RcvEnDly + 1) / 2;
727 if (Bytelane == (NBPtr->MCTPtr->Status[SbEccDimms] ? 8 : 7)) {
728 IDS_HDT_CONSOLE (MEM_FLOW, " <<< Nibble 1");
730 TechPtr->RxEnNibbleDly[Bytelane] = *(UINT16*) RcvEnDly;
733 if (Bytelane == (NBPtr->MCTPtr->Status[SbEccDimms] ? 8 : 7)) {
734 IDS_HDT_CONSOLE (MEM_FLOW, " <<< Nibble 0");
736 TechPtr->RxEnNibbleDly[Bytelane] = *(UINT16*) RcvEnDly;
743 /* -----------------------------------------------------------------------------*/
746 * This function calculates the average nibble based Receiver Enable Training for Orochi.
748 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
749 * @param[in,out] *OptParam - Optional parameter
751 * @return FALSE - Supported
752 * @return TRUE - Not supported
756 MemNTrainRxEnGetAvgDlyPerNibbleOr (
757 IN OUT MEM_NB_BLOCK *NBPtr,
758 IN OUT VOID *OptParam
762 if ((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (NBPtr->TechPtr->ChipSel >> 1))) != 0) {
763 if (NBPtr->TechPtr->TrnNibble == NIBBLE_1) {
764 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t RxEn: ");
765 for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8) ; ByteLane++) {
766 IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", NBPtr->TechPtr->RxEnNibbleDly[ByteLane]);
768 IDS_HDT_CONSOLE (MEM_FLOW, " <<< Nibble AVG\n\n");
778 /* -----------------------------------------------------------------------------*/
781 * This function returns false if nibble training is being used and nibble 1
784 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
785 * @param[in,out] *ChipSel - Pointer to ChipSel to be trained
787 * @return FALSE - Supported
788 * @return TRUE - Not supported
792 MemNTrainingNibbleZeroOr (
793 IN OUT MEM_NB_BLOCK *NBPtr,
797 if (((NBPtr->ChannelPtr->DimmNibbleAccess & (1 << (NBPtr->TechPtr->ChipSel >> 1))) != 0) &&
798 (NBPtr->TechPtr->TrnNibble == NIBBLE_1)) {
805 /* -----------------------------------------------------------------------------*/
809 * This function adjusts Avg PRE value of Phy fence training for OR.
811 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
812 * @param[in,out] *Value16 - Pointer to the value that we want to adjust
817 IN OUT MEM_NB_BLOCK *NBPtr,
818 IN OUT INT16 *Value16
821 *Value16 += 2; //The Avg PRE value is subtracted by 6 only.
827 /* -----------------------------------------------------------------------------*/
830 * This function adjusts WrDqsBias before seed scaling
832 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
833 * @param[in,out] *WrDqsBias - Pointer to WrDqsBias
835 * @return FALSE - Supported
836 * @return TRUE - Not supported
840 MemNAdjustWrDqsBeforeSeedScalingOr (
841 IN OUT MEM_NB_BLOCK *NBPtr,
842 IN OUT VOID *WrDqsBias
845 // Subtract (0x20 * WrDqDqsEarly) since it is a non-scalable component
846 * (INT16 *) WrDqsBias = (INT16) (0x20 * MemNGetBitFieldNb (NBPtr, BFWrDqDqsEarly));