AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Tech / DDR2 / mtspd2.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mtspd2.c
6  *
7  * Technology SPD supporting functions for DDR2
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/Tech/DDR2)
12  * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 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  *                                MODULES USED
49  *
50  *----------------------------------------------------------------------------
51  */
52
53
54
55 #include "AGESA.h"
56 #include "AdvancedApi.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 "mt2.h"
65 #include "mtspd2.h"
66 #include "mftds.h"
67 #include "GeneralServices.h"
68 #include "Filecode.h"
69 CODE_GROUP (G1_PEICC)
70 RDATA_GROUP (G2_PEI)
71
72 #define FILECODE PROC_MEM_TECH_DDR2_MTSPD2_FILECODE
73
74 /*----------------------------------------------------------------------------
75  *                          DEFINITIONS AND MACROS
76  *
77  *----------------------------------------------------------------------------
78  */
79
80 /*----------------------------------------------------------------------------
81  *                           TYPEDEFS AND STRUCTURES
82  *
83  *----------------------------------------------------------------------------
84  */
85
86 /*----------------------------------------------------------------------------
87  *                        PROTOTYPES OF LOCAL FUNCTIONS
88  *
89  *----------------------------------------------------------------------------
90  */
91
92 UINT8
93 STATIC
94 MemTSPDGetTCL2 (
95   IN OUT   MEM_TECH_BLOCK *TechPtr
96   );
97
98 BOOLEAN
99 STATIC
100 MemTSysCapability2 (
101   IN OUT   MEM_TECH_BLOCK *TechPtr,
102   IN       UINT8 k,
103   IN       UINT16 j
104   );
105
106 BOOLEAN
107 STATIC
108 MemTDimmSupports2 (
109   IN OUT   MEM_TECH_BLOCK *TechPtr,
110   IN       UINT8 k,
111   IN       UINT8 j,
112   IN       UINT8 i
113   );
114
115 UINT8
116 STATIC
117 MemTGetTk2 (
118   IN       UINT8 k
119   );
120
121 UINT8
122 STATIC
123 MemTGetBankAddr2 (
124   IN       UINT8 k
125   );
126
127 /*----------------------------------------------------------------------------
128  *                            EXPORTED FUNCTIONS
129  *
130  *----------------------------------------------------------------------------
131  */
132
133 extern BUILD_OPT_CFG UserOptions;
134
135 /* -----------------------------------------------------------------------------*/
136 /**
137  *
138  *   This function sets the DRAM mode
139  *
140  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
141  *
142  *     @return  TRUE - indicates that the DRAM mode is set to DDR2
143  */
144
145 BOOLEAN
146 MemTSetDramMode2 (
147   IN OUT   MEM_TECH_BLOCK *TechPtr
148   )
149 {
150   TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFLegacyBiosMode, 0);
151   return TRUE;
152 }
153
154 /* -----------------------------------------------------------------------------*/
155 /**
156  *
157  *   This function determines if DIMMs are present. It checks checksum and interrogates the SPDs
158  *
159  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
160  *
161  *     @return  TRUE - indicates that a FATAL error has not occurred
162  *     @return  FALSE - indicates that a FATAL error has occurred
163  */
164
165 BOOLEAN
166 MemTDIMMPresence2 (
167   IN OUT   MEM_TECH_BLOCK *TechPtr
168   )
169 {
170   UINT8 *SpdBufferPtr;
171   MEM_PARAMETER_STRUCT *RefPtr;
172   DIE_STRUCT *MCTPtr;
173   DCT_STRUCT *DCTPtr;
174   CH_DEF_STRUCT *ChannelPtr;
175   MEM_NB_BLOCK *NBPtr;
176   UINT16 Checksum;
177   UINT16 Value16;
178   UINT8 Dct;
179   UINT8 Channel;
180   UINT8 i;
181   UINT8 ByteNum;
182   UINT8 Devwidth;
183   UINT8 Value8;
184   UINT8 MaxDimms;
185   UINT8 DimmSlots;
186   UINT16 DimmMask;
187   BOOLEAN SPDCtrl;
188
189   NBPtr = TechPtr->NBPtr;
190   RefPtr = NBPtr->RefPtr;
191   MCTPtr = NBPtr->MCTPtr;
192
193   SPDCtrl = UserOptions.CfgIgnoreSpdChecksum;
194
195   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
196     NBPtr->SwitchDCT (NBPtr, Dct);
197     DCTPtr = NBPtr->DCTPtr;
198     for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
199       NBPtr->SwitchChannel (NBPtr, Channel);
200       ChannelPtr = NBPtr->ChannelPtr;
201       ChannelPtr->DimmQrPresent = 0;
202
203       //  Get the maximum number of DIMMs
204       DimmSlots = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration,
205                                          MCTPtr->SocketId,
206                                          NBPtr->GetSocketRelativeChannel (NBPtr, Dct, Channel)
207                                         );
208       MaxDimms = MAX_DIMMS_PER_CHANNEL;
209       for (i = 0; i < MaxDimms; i++) {
210         //  Bitmask representing dimm #i.
211         DimmMask = (UINT16)1 << i;
212
213         if ((ChannelPtr->DimmQrPresent & DimmMask) || (i < DimmSlots)) {
214           if (MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, i)) {
215             MCTPtr->DimmPresent |= DimmMask;
216
217             //  Start by computing checksum for this SPD
218             Checksum = 0;
219             for (ByteNum = 0; ByteNum < SPD_CHECKSUM; ByteNum++) {
220               Checksum = Checksum + (UINT16) SpdBufferPtr[ByteNum];
221             }
222             //  Check for valid checksum value
223             AGESA_TESTPOINT (TpProcMemSPDChecking, &(NBPtr->MemPtr->StdHeader));
224
225             if (SpdBufferPtr[SPD_TYPE] == JED_DDR2_SDRAM) {
226               ChannelPtr->ChDimmValid |= DimmMask;
227               MCTPtr->DimmValid |= DimmMask;
228             } else {
229               // Current socket is set up to only support DDR2 dimms.
230               IDS_ERROR_TRAP;
231             }
232             if ((SpdBufferPtr[SPD_CHECKSUM] != (UINT8)Checksum) && !SPDCtrl) {
233               //
234               // if NV_SPDCHK_RESTRT is set to 0,
235               // cannot ignore faulty SPD checksum
236               //
237               //  Indicate checksum error
238               ChannelPtr->DimmSpdCse |= DimmMask;
239               PutEventLog (AGESA_ERROR, MEM_ERROR_CHECKSUM_NV_SPDCHK_RESTRT_ERROR, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
240               SetMemError (AGESA_ERROR, MCTPtr);
241             }
242
243             //  Check module type information.
244             if (SpdBufferPtr[SPD_DIMM_TYPE] & JED_REG_ADC_MSK) {
245               ChannelPtr->RegDimmPresent |= DimmMask;
246               MCTPtr->RegDimmPresent |= DimmMask;
247             }
248
249             if (SpdBufferPtr[SPD_DIMM_TYPE] & JED_SODIMM) {
250               ChannelPtr->SODimmPresent |= DimmMask;
251             }
252
253             //  Check error correction type
254             if (SpdBufferPtr[SPD_EDC_TYPE] & JED_ECC) {
255               MCTPtr->DimmEccPresent |= DimmMask;  //  Dimm has ECC
256             }
257             if (SpdBufferPtr[SPD_EDC_TYPE] & JED_ADRC_PAR) {
258               MCTPtr->DimmParPresent |= DimmMask;  //  Dimm has parity
259             }
260
261             //  Get the Dimm width data
262             Devwidth = SpdBufferPtr[SPD_DEV_WIDTH] & 0xFE;
263             if (Devwidth == 4) {
264               ChannelPtr->Dimmx4Present |= DimmMask;   //  Dimm has parity
265             } else if (Devwidth == 8) {
266               ChannelPtr->Dimmx8Present |= DimmMask;   //  Dimm has parity
267             } else if (Devwidth == 16) {
268               ChannelPtr->Dimmx16Present |= DimmMask;  //  Dimm has parity
269             }
270
271             //  Determine the page size.
272             //       page_size = 2^COLBITS * Devwidth/8
273             //
274             Value16 = (((UINT16)1 << SpdBufferPtr[SPD_COL_SZ]) * Devwidth) / 8;
275             if (!(Value16 >> 11)) {
276               DCTPtr->Timings.DIMM1KPage |= DimmMask;
277             }
278
279             //  Check for 'analysis probe installed'
280             if (SpdBufferPtr[SPD_ATTRIB] & JED_PROBE_MSK) {
281               MCTPtr->Status[SbDiagClks] = TRUE;
282             }
283
284             //  Determine the geometry of the DIMM module
285             if (SpdBufferPtr[SPD_DM_BANKS] & SP_DPL_BIT) {
286               ChannelPtr->DimmPlPresent |= DimmMask;   //  Dimm is planar
287             }
288
289             //  specify the number of ranks
290             Value8 = (SpdBufferPtr[SPD_DM_BANKS] & 0x07) + 1;
291             if (Value8 > 2) {
292               if (ChannelPtr->DimmQrPresent == 0) {
293                 // if any DIMMs are QR,
294                 // we have to make two passes through DIMMs
295                 //
296                 MaxDimms = MaxDimms << 1;
297               }
298
299               if (i < DimmSlots) {
300                 ChannelPtr->DimmQrPresent |= DimmMask;
301                 ChannelPtr->DimmQrPresent |= (DimmMask << 2);
302               }
303               Value8 = 2;
304             } else if (Value8 == 2) {
305               ChannelPtr->DimmDrPresent |= DimmMask;   //  Dual rank dimms
306             }
307
308             //  Calculate bus loading per Channel
309             if (Devwidth == 16) {
310               Devwidth = 4;
311             } else if (Devwidth == 4) {
312               Devwidth = 16;
313             }
314             //  double Addr bus load value for dual rank DIMMs
315             if (Value8 == 2) {
316               Devwidth = Devwidth << 1;
317             }
318
319             ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
320             ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
321             ChannelPtr->Dimms++;
322
323             //  Now examine the dimm packaging dates
324             Value8 = SpdBufferPtr[SPD_MAN_DATE_YR];
325             if (Value8 < M_YEAR_06) {
326               ChannelPtr->DimmYr06 |= DimmMask;    //  Built before end of 2006
327               ChannelPtr->DimmWk2406 |= DimmMask;  //  Built before end of week 24,2006
328             } else if (Value8 == M_YEAR_06) {
329               ChannelPtr->DimmYr06 |= DimmMask;    //  Built before end of 2006
330               if (SpdBufferPtr[SPD_MAN_DATE_WK] <= M_WEEK_24) {
331                 ChannelPtr->DimmWk2406 |= DimmMask;  //  Built before end of week 24,2006
332               }
333             }
334           } // if DIMM present
335         } // Quadrank
336       } // Dimm loop
337
338       if (Channel == 0) {
339         DCTPtr->Timings.DctDimmValid = ChannelPtr->ChDimmValid;
340         DCTPtr->Timings.DimmSpdCse = ChannelPtr->DimmSpdCse;
341         DCTPtr->Timings.DimmQrPresent = ChannelPtr->DimmQrPresent;
342         DCTPtr->Timings.DimmDrPresent = ChannelPtr->DimmDrPresent;
343         DCTPtr->Timings.Dimmx4Present = ChannelPtr->Dimmx4Present;
344         DCTPtr->Timings.Dimmx8Present = ChannelPtr->Dimmx8Present;
345         DCTPtr->Timings.Dimmx16Present = ChannelPtr->Dimmx16Present;
346       }
347       if ((Channel != 1) || (Dct != 1)) {
348         MCTPtr->DimmPresent <<= 8;
349         MCTPtr->DimmValid <<= 8;
350         MCTPtr->RegDimmPresent <<= 8;
351         MCTPtr->DimmEccPresent <<= 8;
352         MCTPtr->DimmParPresent <<= 8;
353       }
354     } // Channel loop
355   } // DCT loop
356
357
358   //  If we have DIMMs, some further general characteristics checking
359   if (MCTPtr->DimmValid) {
360     //  If there are registered dimms, all the dimms must be registered
361     if (MCTPtr->RegDimmPresent == MCTPtr->DimmValid) {
362       //  All dimms registered
363       MCTPtr->Status[SbRegistered] = TRUE;
364     } else if (MCTPtr->RegDimmPresent) {
365       //  We have an illegal DIMM mismatch
366       PutEventLog (AGESA_FATAL, MEM_ERROR_MODULE_TYPE_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
367       SetMemError (AGESA_FATAL, MCTPtr);
368     }
369
370     //  check the ECC capability of the DIMMs
371     if (MCTPtr->DimmEccPresent == MCTPtr->DimmValid) {
372       MCTPtr->Status[SbEccDimms] = TRUE;  //  All dimms ECC capable
373     }
374
375     //  check the parity capability of the DIMMs
376     if (MCTPtr->DimmParPresent == MCTPtr->DimmValid) {
377       MCTPtr->Status[SbParDimms] = TRUE;  //  All dimms parity capable
378     }
379   } else {
380   }
381
382   NBPtr->SwitchDCT (NBPtr, 0);
383   NBPtr->SwitchChannel (NBPtr, 0);
384   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
385 }
386
387
388 /* -----------------------------------------------------------------------------*/
389 /**
390  *
391  *   This function finds the best T and CL primary timing parameter pair, per Mfg.,for the given
392  *   set of DIMMs, and store into DIE_STRUCT(.Speed and .Casl).
393  *   See "Global relationship between index values and item values" for definition of
394  *   CAS latency index (j) and Frequency index (k).
395  *
396  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
397  *
398  *     @return  TRUE - indicates that a FATAL error has not occurred
399  *     @return  FALSE - indicates that a FATAL error has occurred
400  */
401
402 BOOLEAN
403 MemTSPDGetTargetSpeed2 (
404   IN OUT   MEM_TECH_BLOCK *TechPtr
405   )
406 {
407   CONST UINT16 SpeedCvt[] = {
408     DDR400_FREQUENCY,
409     DDR533_FREQUENCY,
410     DDR667_FREQUENCY,
411     DDR800_FREQUENCY,
412     DDR1066_FREQUENCY
413   };
414   INT8 i;
415   INT8 j;
416   INT8 k;
417   INT8 Dct;
418   INT8 Channel;
419   UINT8 T1min;
420   UINT8 CL1min;
421   BOOLEAN IsSupported;
422   MEM_NB_BLOCK *NBPtr;
423   DIE_STRUCT *MCTPtr;
424   DCT_STRUCT *DCTPtr;
425   CH_DEF_STRUCT *ChannelPtr;
426
427   NBPtr = TechPtr->NBPtr;
428   MCTPtr = TechPtr->NBPtr->MCTPtr;
429
430   CL1min = 0xFF;
431   T1min = 0xFF;
432
433   // For DDR2, run SyncTargetSpeed first to get frequency limit into DCTPtr->Timings.Speed
434   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
435     NBPtr->SwitchDCT (NBPtr, Dct);
436     NBPtr->DCTPtr->Timings.TargetSpeed = 16;  // initialized with big number
437   }
438   NBPtr->SyncTargetSpeed (NBPtr);
439
440   // Find target frequency and Tcl
441   for (k = K_MAX; k >= K_MIN; k--) {
442     for (j = J_MIN; j <= J_MAX; j++) {
443       if (MemTSysCapability2 (TechPtr, k, j)) {
444         IsSupported = TRUE;
445         for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
446           NBPtr->SwitchDCT (NBPtr, Dct);
447           for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
448             NBPtr->SwitchChannel (NBPtr, Channel);
449             ChannelPtr = NBPtr->ChannelPtr;
450             for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
451               if (ChannelPtr->ChDimmValid & ((UINT8)1 << i)) {
452                 if (!MemTDimmSupports2 (TechPtr, k, j, i)) {
453                   IsSupported = FALSE;
454                   Dct = NBPtr->DctCount;
455                   Channel = NBPtr->ChannelCount;
456                   break;
457                 }
458               }
459             }
460           }
461         }
462
463         if (IsSupported) {
464           T1min = k;
465           CL1min = j;
466           //  Kill the loops...
467           k = K_MIN - 1;
468           j = J_MAX + 1;
469         }
470       }
471     }
472   }
473
474   if (T1min == 0xFF) {
475     //  Failsafe values, running in minimum mode
476     PutEventLog (AGESA_FATAL, MEM_ERROR_MISMATCH_DIMM_CLOCKS, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
477     PutEventLog (AGESA_FATAL, MEM_ERROR_MINIMUM_MODE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
478     SetMemError (AGESA_ERROR, MCTPtr);
479
480     T1min = T_DEF;
481     CL1min = CL_DEF;
482   }
483
484   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
485     NBPtr->SwitchDCT (NBPtr, Dct);
486     DCTPtr = NBPtr->DCTPtr;
487     DCTPtr->Timings.TargetSpeed = SpeedCvt[T1min - 1];
488   }
489
490   // Ensure the target speed can be applied to all channels of the current node
491   NBPtr->SyncTargetSpeed (NBPtr);
492
493   // Set the start-up frequency
494   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
495     NBPtr->SwitchDCT (NBPtr, Dct);
496     DCTPtr = NBPtr->DCTPtr;
497     DCTPtr->Timings.Speed = DCTPtr->Timings.TargetSpeed;
498     DCTPtr->Timings.CasL = CL1min + 2;  // Convert to clocks
499   }
500
501   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
502 }
503
504 /* -----------------------------------------------------------------------------*/
505 /**
506  *
507  *   This function check the symmetry of DIMM pairs (DIMM on Channel A matching with
508  *   DIMM on Channel B), the overall DIMM population, and determine the width mode:
509  *   64-bit, 64-bit muxed, 128-bit.
510  *
511  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
512  *
513  *     @return  TRUE - indicates that a FATAL error has not occurred
514  *     @return  FALSE - indicates that a FATAL error has occurred
515  */
516
517 BOOLEAN
518 MemTSPDCalcWidth2 (
519   IN OUT   MEM_TECH_BLOCK *TechPtr
520   )
521 {
522   UINT8 *SpdBufferAPtr;
523   UINT8 *SpdBufferBPtr;
524   MEM_NB_BLOCK *NBPtr;
525   DIE_STRUCT *MCTPtr;
526   DCT_STRUCT *DCTPtr;
527   UINT8 i;
528   UINT16 DimmMask;
529   UINT8 UngangMode;
530
531   NBPtr = TechPtr->NBPtr;
532   MCTPtr = NBPtr->MCTPtr;
533   DCTPtr = NBPtr->DCTPtr;
534
535   UngangMode = UserOptions.CfgMemoryModeUnganged;
536   IDS_OPTION_HOOK (IDS_GANGING_MODE, &UngangMode, &(NBPtr->MemPtr->StdHeader));
537
538   //  Check symmetry of channel A and channel B dimms for 128-bit mode
539   //  capability.
540   //
541   AGESA_TESTPOINT (TpProcMemModeChecking, &(NBPtr->MemPtr->StdHeader));
542   i = 0;
543   if (MCTPtr->DctData[0].Timings.DctDimmValid == MCTPtr->DctData[1].Timings.DctDimmValid) {
544     for (; i < MAX_DIMMS_PER_CHANNEL; i++) {
545       DimmMask = (UINT16)1 << i;
546       if (DCTPtr->Timings.DctDimmValid & DimmMask) {
547         NBPtr->SwitchDCT (NBPtr, 0);
548         MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferAPtr, i);
549         NBPtr->SwitchDCT (NBPtr, 1);
550         MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferBPtr, i);
551
552         if ((SpdBufferAPtr[SPD_ROW_SZ]&0x1F) != (SpdBufferBPtr[SPD_ROW_SZ]&0x1F)) {
553           break;
554         }
555
556         if ((SpdBufferAPtr[SPD_COL_SZ]&0x1F) != (SpdBufferBPtr[SPD_COL_SZ]&0x1F)) {
557           break;
558         }
559
560         if (SpdBufferAPtr[SPD_BANK_SZ] != SpdBufferBPtr[SPD_BANK_SZ]) {
561           break;
562         }
563
564         if ((SpdBufferAPtr[SPD_DEV_WIDTH]&0x7F) != (SpdBufferBPtr[SPD_DEV_WIDTH]&0x7F)) {
565           break;
566         }
567
568         if ((SpdBufferAPtr[SPD_DM_BANKS]&0x07) != (SpdBufferBPtr[SPD_DM_BANKS]&0x07)) {
569           break;
570         }
571       }
572     }
573   }
574   if (i < MAX_DIMMS_PER_CHANNEL) {
575     PutEventLog (AGESA_ALERT, MEM_ALERT_ORG_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
576     SetMemError (AGESA_ALERT, MCTPtr);
577   } else if (!UngangMode) {
578     NBPtr->Ganged = TRUE;
579     MCTPtr->GangedMode = TRUE;
580     MCTPtr->Status[Sb128bitmode] = TRUE;
581     NBPtr->SetBitField (NBPtr, BFDctGangEn, 1);
582   }
583
584   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
585 }
586
587
588 /* -----------------------------------------------------------------------------*/
589 /**
590  *
591  *       Initialize DCT Timing registers as per DIMM SPD.
592  *       For primary timing (T, CL) use best case T value.
593  *       For secondary timing params., use most aggressive settings
594  *           of slowest DIMM.
595  *
596  *   Note:
597  *   There are three components to determining "maximum frequency": SPD component,
598  *   Bus load component, and "Preset" max frequency component.
599  *   The SPD component is a function of the min cycle time specified by each DIMM,
600  *   and the interaction of cycle times from all DIMMs in conjunction with CAS
601  *   latency.  The SPD component only applies when user timing mode is 'Auto'.
602  *
603  *   The Bus load component is a limiting factor determined by electrical
604  *   characteristics on the bus as a result of varying number of device loads.  The
605  *   Bus load component is specific to each platform but may also be a function of
606  *   other factors.  The bus load component only applies when user timing mode is
607  * ' Auto'.
608  *
609  *   The Preset component is subdivided into three items and is the minimum of
610  *   the set: Silicon revision, user limit setting when user timing mode is 'Auto' and
611  *   memclock mode is 'Limit', OEM build specification of the maximum frequency.
612  *   The Preset component only applies when user timing mode is 'Auto'.
613
614  *
615  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
616  *
617  *     @return  TRUE - indicates that a FATAL error has not occurred
618  *     @return  FALSE - indicates that a FATAL error has occurred
619  */
620
621 BOOLEAN
622 MemTAutoCycTiming2 (
623   IN OUT   MEM_TECH_BLOCK *TechPtr
624   )
625 {
626   CONST UINT8 SpdIndexes[] = {
627     SPD_TRCD,
628     SPD_TRP,
629     SPD_TRTP,
630     SPD_TRAS,
631     SPD_TRC,
632     SPD_TWR,
633     SPD_TRRD,
634     SPD_TWTR
635   };
636   CONST UINT8 Multiples[] = {10, 10, 10, 40, 40, 10, 10, 10};
637
638   CONST UINT8 Tab1KTfawTK[] = {8, 10, 13, 14, 0, 20};
639   CONST UINT8 Tab2KTfawTK[] = {10, 14, 17, 18, 0, 24};
640   CONST UINT8 TabDefTrcK[]  = {0x41, 0x3C, 0x3C, 0x3A, 0, 0x3A};
641
642   UINT8 MiniMaxTmg[GET_SIZE_OF (SpdIndexes)];
643   UINT8 MiniMaxTrfc[4];
644
645   DIE_STRUCT *MCTPtr;
646   DCT_STRUCT *DCTPtr;
647   MEM_NB_BLOCK *NBPtr;
648   UINT16 DimmMask;
649   UINT16 Value16;
650   UINT16 Tk40;
651   UINT8 i;
652   UINT8 j;
653   UINT8 Value8;
654   UINT8 Temp8;
655   UINT8  *StatTmgPtr;
656   UINT16 *StatDimmTmgPtr;
657   BOOLEAN   Is1066;
658   UINT8 *SpdBufferPtr;
659
660   NBPtr = TechPtr->NBPtr;
661   MCTPtr = NBPtr->MCTPtr;
662   DCTPtr = NBPtr->DCTPtr;
663
664   // initialize mini-max arrays
665   for (j = 0; j < GET_SIZE_OF (MiniMaxTmg); j++) {
666     MiniMaxTmg[j] = 0;
667   }
668   for (j = 0; j < GET_SIZE_OF (MiniMaxTrfc); j++) {
669     MiniMaxTrfc[j] = 0;
670   }
671
672   // ======================================================================
673   //  Get primary timing (CAS Latency and Cycle Time)
674   // ======================================================================
675   //  Get OEM specific load variant max
676   //
677
678   //======================================================================
679   // Gather all DIMM mini-max values for cycle timing data
680   //======================================================================
681   //
682   DimmMask = 1;
683   for (i = 0; i < (MAX_CS_PER_CHANNEL / 2); i++) {
684     if (DCTPtr->Timings.DctDimmValid & DimmMask) {
685       MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, i);
686       for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
687         Value8 = SpdBufferPtr[SpdIndexes[j]];
688         if (SpdIndexes[j] == SPD_TRC) {
689           if (Value8 == 0 || Value8 == 0xFF) {
690             PutEventLog (AGESA_WARNING, MEM_WARNING_NO_SPDTRC_FOUND, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, i, &NBPtr->MemPtr->StdHeader);
691             SetMemError (AGESA_WARNING, MCTPtr);
692             Value8 = TabDefTrcK[(DCTPtr->Timings.Speed / 66) - 3];
693           }
694         }
695         if (MiniMaxTmg[j] < Value8) {
696           MiniMaxTmg[j] = Value8;
697         }
698       }
699
700       //  get Trfc0 - Trfc3 values
701       Value8 = SpdBufferPtr[SPD_BANK_SZ];
702       Temp8 = (Value8 << 3) | (Value8 >> 5);
703       Value8 = SpdBufferPtr[SPD_DEV_WIDTH];
704       ASSERT (LibAmdBitScanReverse ((UINT32)Value8) <= 4);
705       Temp8 >>= 4 - LibAmdBitScanReverse ((UINT32)Value8);
706       Value8 = LibAmdBitScanReverse ((UINT32)Temp8);
707       if (MiniMaxTrfc[i] < Value8) {
708         MiniMaxTrfc[i] = Value8;
709       }
710     }
711     DimmMask <<= 1;
712   }
713
714   // ======================================================================
715   //  Convert  DRAM CycleTiming values and store into DCT structure
716   // ======================================================================
717   //
718   Tk40 = 40000 / DCTPtr->Timings.Speed;
719   if (DCTPtr->Timings.Speed == DDR1066_FREQUENCY) {
720     Is1066 = TRUE;
721   } else {
722     Is1066 = FALSE;
723   }
724   //   Notes:
725   //   1. All secondary time values given in SPDs are in binary with UINTs of ns.
726   //   2. Some time values are scaled by four, in order to have least count of 0.25 ns
727   //      (more accuracy).  JEDEC SPD spec. shows which ones are x1 and x4.
728   //   3. Internally to this SW, cycle time, Tk, is scaled by 10 to affect a
729   //      least count of 0.1 ns (more accuracy).
730   //   4. SPD values not scaled are multiplied by 10 and then divided by 10T to find
731   //      equivalent minimum number of bus clocks (a remainder causes round-up of clocks).
732   //   5. SPD values that are prescaled by 4 are multiplied by 10 and then divided by 40T to find
733   //      equivalent minimum number of bus clocks (a remainder causes round-up of clocks).
734   //
735   StatDimmTmgPtr = &DCTPtr->Timings.DIMMTrcd;
736   StatTmgPtr = &DCTPtr->Timings.Trcd;
737   for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
738     Value16 = (UINT16)MiniMaxTmg[j] * Multiples[j];
739     StatDimmTmgPtr[j] = Value16;
740
741     MiniMaxTmg[j] = (UINT8) ((Value16 + Tk40 - 1) / Tk40);
742     if (SpdIndexes[j] == SPD_TRTP) {
743       MiniMaxTmg[j] = (DCTPtr->Timings.Speed <= DDR533_FREQUENCY) ? 2 : 3;   // based on BL of 32 bytes
744     }
745
746     StatTmgPtr[j] = MiniMaxTmg[j];
747   }
748   DCTPtr->Timings.Trfc0 = MiniMaxTrfc[0];
749   DCTPtr->Timings.Trfc1 = MiniMaxTrfc[1];
750   DCTPtr->Timings.Trfc2 = MiniMaxTrfc[2];
751   DCTPtr->Timings.Trfc3 = MiniMaxTrfc[3];
752
753   DCTPtr->Timings.CasL = MemTSPDGetTCL2 (TechPtr);
754
755   if (DCTPtr->Timings.DIMM1KPage) {
756     DCTPtr->Timings.Tfaw = Tab1KTfawTK[(DCTPtr->Timings.Speed / 66) - 3];
757   } else {
758     DCTPtr->Timings.Tfaw = Tab2KTfawTK[(DCTPtr->Timings.Speed / 66) - 3];
759   }
760   if (Is1066) {
761     DCTPtr->Timings.Tfaw >>= 1;
762   }
763
764   //======================================================================
765   // Program DRAM Timing values
766   //======================================================================
767   //
768   NBPtr->ProgramCycTimings (NBPtr);
769
770   MemFInitTableDrive (NBPtr, MTAfterAutoCycTiming);
771
772   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
773 }
774
775 /* -----------------------------------------------------------------------------*/
776 /**
777  *
778  *   This function sets the bank addressing, program Mask values and build a chip-select population map.
779  *   This routine programs PCI 0:24N:2x80 config register.
780  *   This routine programs PCI 0:24N:2x60,64,68,6C config registers (CS Mask 0-3)
781  *
782  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
783  *
784  *     @return  TRUE - indicates that a FATAL error has not occurred
785  *     @return  FALSE - indicates that a FATAL error has occurred
786  */
787
788 BOOLEAN
789 MemTSPDSetBanks2 (
790   IN OUT   MEM_TECH_BLOCK *TechPtr
791   )
792 {
793   UINT8 *SpdBufferPtr;
794   UINT8 i;
795   UINT8 ChipSel;
796   UINT8 DimmID;
797   UINT8 Value8;
798   UINT8 Rows;
799   UINT8 Cols;
800   UINT8 Ranks;
801   UINT8 Banks;
802   UINT32 BankAddrReg;
803   UINT32 CsMask;
804   UINT16 CSSpdCSE;
805   UINT16 CSExclude;
806   UINT16 DimmQRDR;
807   DIE_STRUCT *MCTPtr;
808   DCT_STRUCT *DCTPtr;
809   MEM_NB_BLOCK *NBPtr;
810
811   NBPtr = TechPtr->NBPtr;
812   MCTPtr = NBPtr->MCTPtr;
813   DCTPtr = NBPtr->DCTPtr;
814
815   BankAddrReg = 0;
816   CSSpdCSE = 0;
817   CSExclude = 0;
818   for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
819     DimmID = ChipSel >> 1;
820
821     DimmQRDR = (DCTPtr->Timings.DimmQrPresent) | (DCTPtr->Timings.DimmDrPresent);
822     if (DCTPtr->Timings.DimmSpdCse & (UINT16) 1 << DimmID) {
823       CSSpdCSE |= (UINT16) ((DimmQRDR & (UINT16) 1 << DimmID) ? 3 : 1) << ChipSel;
824     }
825     if ((DCTPtr->Timings.DimmExclude & ((UINT16) 1 << DimmID)) != 0) {
826       CSExclude |= (UINT16) ((DimmQRDR & (UINT16) 1 << DimmID) ? 3: 1) << ChipSel;
827     }
828
829     if (DCTPtr->Timings.DctDimmValid & ((UINT16)1 << DimmID)) {
830       MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, DimmID);
831
832       //  Get the basic data
833       Rows = SpdBufferPtr[SPD_ROW_SZ] & 0x1F;
834       Cols = SpdBufferPtr[SPD_COL_SZ] & 0x1F;
835       Banks = SpdBufferPtr[SPD_L_BANKS];
836       Ranks = (SpdBufferPtr[SPD_DM_BANKS] & 0x07) + 1;
837
838       //  Configure the bank encoding
839       Value8 = (Cols - 9) << 3;
840       Value8 |= (Banks == 8) ? 4 : 0;
841       Value8 |= (Rows - 13);
842
843       for (i = 0; i < 12; i++) {
844         if (Value8 == MemTGetBankAddr2 (i)) {
845           break;
846         }
847       }
848
849       if (i < 12) {
850         BankAddrReg |= ((UINT32)i << (ChipSel << 1));
851
852         // Mask value=(2pow(rows+cols+banks+3)-1)>>8,
853         // or 2pow(rows+cols+banks-5)-1
854         //
855         Value8 = Rows + Cols;
856         Value8 -= (Banks == 8) ? 2:3;
857         if (MCTPtr->Status[Sb128bitmode]) {
858           Value8++;
859         }
860         CsMask = ((UINT32)1 << Value8) - 1;
861         DCTPtr->Timings.CsPresent |= (UINT16)1 << ChipSel;
862
863         if (Ranks >= 2) {
864           DCTPtr->Timings.CsPresent |= (UINT16)1 << (ChipSel + 1);
865         }
866
867         //  Update the DRAM CS Mask for this chipselect
868         NBPtr->SetBitField (NBPtr, BFCSMask0Reg + (ChipSel >> 1), (CsMask & NBPtr->CsRegMsk));
869       }
870     }
871   }
872   // For ranks that need to be excluded, the loading of this rank should be considered
873   // in timing, so need to set CsPresent before setting CsTestFail
874   if ((CSSpdCSE != 0) || (CSExclude != 0)) {
875     if (!NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, (CSSpdCSE | CSExclude), &NBPtr->MemPtr->StdHeader)) {
876       ASSERT (FALSE);
877     }
878   }
879
880   //  If there are no chip selects, we have an error situation.
881   if (DCTPtr->Timings.CsPresent == 0) {
882     PutEventLog (AGESA_ERROR, MEM_ERROR_NO_CHIPSELECT, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
883     SetMemError (AGESA_ERROR, MCTPtr);
884   }
885
886   NBPtr->SetBitField (NBPtr, BFDramBankAddrReg, BankAddrReg);
887
888   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
889 }
890
891 /* -----------------------------------------------------------------------------*/
892 /**
893  *
894  *      This function returns the low bit that will be swapped to enable CS interleaving
895  *
896  *     @param[in]   BankEnc - AddrMap Bank encoding from F2x80
897  *     @param[in]   *LowBit - pointer to low bit
898  *     @param[in]   *HiBit  - pointer hight bit
899  *
900  */
901
902 VOID
903 MemTGetCSIntLvAddr2 (
904   IN       UINT8 BankEnc,
905      OUT   UINT8 *LowBit,
906      OUT   UINT8 *HiBit
907   )
908 {
909   CONST UINT8 ArrCodesLo[] = {6, 7, 7, 8, 8, 8, 8, 8, 9, 9, 8, 9};
910   CONST UINT8 ArrCodesHi[] = {19, 20, 21, 21, 21, 22, 22, 23, 23, 24, 24, 25};
911   ASSERT (BankEnc < GET_SIZE_OF (ArrCodesLo));
912   ASSERT (BankEnc < GET_SIZE_OF (ArrCodesHi));
913   //  return ArrCodes[BankEnc];
914   *LowBit = ArrCodesLo[BankEnc];
915   *HiBit = ArrCodesHi[BankEnc];
916 }
917
918 /*----------------------------------------------------------------------------
919  *                              LOCAL FUNCTIONS
920  *
921  *----------------------------------------------------------------------------
922  */
923 /* -----------------------------------------------------------------------------*/
924 /**
925  *
926  *   This function returns the CAS latency of the current frequency.
927  *
928  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
929  *
930  *     @return  CAS Latency
931  */
932 UINT8
933 STATIC
934 MemTSPDGetTCL2 (
935   IN OUT   MEM_TECH_BLOCK *TechPtr
936   )
937 {
938   return TechPtr->NBPtr->DCTPtr->Timings.CasL;
939 }
940
941 /* -----------------------------------------------------------------------------*/
942 /**
943  *
944  *               Get max frequency from OEM platform definition, from
945  *               any user override (limiting) of max frequency, and
946  *               from any Si Revision Specific information.  Return
947  *               the least of these three in DIE_STRUCT.PresetmaxFreq.
948  *
949  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
950  *     @param[in]   k -  Frequency index
951  *     @param[in]   j - CAS Latency index
952  *
953  *     @return  TRUE  - (k << 8) | j
954  *     @return  FALSE - 0
955  */
956
957 BOOLEAN
958 STATIC
959 MemTSysCapability2 (
960   IN OUT   MEM_TECH_BLOCK *TechPtr,
961   IN       UINT8 k,
962   IN       UINT16 j
963   )
964 {
965   if ((k > TechPtr->NBPtr->DCTPtr->Timings.TargetSpeed) || (j > J_MAX)) {
966     return FALSE;
967   }
968
969   return TRUE;    //(k << 8) | j;
970 }
971
972
973 /* -----------------------------------------------------------------------------*/
974 /**
975  *
976  *      Determine whether dimm(b,i) supports CL(j) and F(k)
977  *
978  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
979  *     @param[in]   k -  Frequency index
980  *     @param[in]   j - CAS Latency index
981  *     @param[in]   i - DIMM number
982  *
983  *     @return  TRUE  - DIMM supports
984  *     @return  FALSE - DIMM does not support
985  */
986
987 BOOLEAN
988 STATIC
989 MemTDimmSupports2 (
990   IN OUT   MEM_TECH_BLOCK *TechPtr,
991   IN       UINT8 k,
992   IN       UINT8 j,
993   IN       UINT8 i
994   )
995 {
996   CONST UINT8 SpdBytesForCL[3] = { 9, 23, 25};   // SPD bytes for CL X, CL X-.5, and CL X-1
997   UINT8 CLj;
998   UINT8 CLi;
999   UINT8 T1;
1000   UINT8 T2;
1001   UINT8 Tk;
1002   UINT8 *SpdBufferPtr;
1003   MEM_NB_BLOCK *NBPtr;
1004
1005   NBPtr = TechPtr->NBPtr;
1006
1007   MemTGetDimmSpdBuffer2 (TechPtr, &SpdBufferPtr, i);
1008   CLj = (UINT8) 1 << (j + 2);
1009   CLi = SpdBufferPtr[SPD_CAS_LAT];
1010
1011   if (CLj & CLi) {
1012     //  If this dimm supports the desired CAS latency...
1013     //  Determine the SPD location of the dimm speed UINT8 appropriate
1014     //  to the CAS latency indicated by Table_CL2_j.
1015     //
1016     T1 = LibAmdBitScanReverse ((UINT32)CLj);
1017     T2 = LibAmdBitScanReverse ((UINT32)CLi);
1018     ASSERT ((T2 - T1) < 3);
1019     CLi = SpdBufferPtr[SpdBytesForCL[(T2 - T1)]];
1020     Tk = MemTGetTk2 (k);
1021     if (CLi == 0) {
1022       PutEventLog (AGESA_FATAL, MEM_ERROR_NO_CYC_TIME, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
1023       SetMemError (AGESA_WARNING, NBPtr->MCTPtr);
1024     } else if (Tk >= CLi) {
1025       return TRUE;
1026     }
1027   }
1028   return FALSE;
1029 }
1030
1031 /* -----------------------------------------------------------------------------*/
1032 /**
1033  *
1034  *      This function returns the cycle time
1035  *
1036  *     @param[in]   k - CAS Latency index
1037  *
1038  *     @return      Tk as specified by JEDEC SPD byte 9.
1039  */
1040
1041 UINT8
1042 STATIC
1043 MemTGetTk2 (
1044   IN       UINT8 k
1045   )
1046 {
1047   CONST UINT8 TableTK[] = {0x00, 0x50, 0x3D, 0x30, 0x25, 0x18};
1048   ASSERT (k < GET_SIZE_OF (TableTK));
1049   return TableTK[k];
1050 }
1051
1052 /* -----------------------------------------------------------------------------*/
1053 /**
1054  *
1055  *       This function returns the encoded value of bank address.
1056  *
1057  *     @param[in]  k  value
1058  *
1059  *     @return      RRRBCC, where CC is the number of Columns minus 9,
1060  *                  RRR is the number of Rows minus 12, and B is the number of banks
1061  *                  minus 3.
1062  */
1063
1064 UINT8
1065 STATIC
1066 MemTGetBankAddr2 (
1067   IN       UINT8 k
1068   )
1069 {
1070   CONST UINT8 TabBankAddr[] = {
1071     0x00, 0x08, 0x09, 0x10, 0x0C, 0x0D,
1072     0x11, 0x0E, 0x15, 0x16, 0x0F, 0x17
1073   };
1074   ASSERT (k < GET_SIZE_OF (TabBankAddr));
1075   return TabBankAddr[k];
1076 }
1077
1078 /* -----------------------------------------------------------------------------*/
1079 /**
1080  *
1081  *       This function returns a pointer to the SPD Buffer of a specific dimm on
1082  *    the current channel.
1083  *
1084  *     @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1085  *     @param[in,out] **SpdBuffer - Pointer to a pointer to a UINT8 Buffer
1086  *     @param[in] Dimm - Dimm number
1087  *
1088  *
1089  *     @return BOOLEAN - Value of DimmPresent
1090  *                       TRUE = Dimm is present, pointer is valid
1091  *                       FALSE = Dimm is not present, pointer has not been modified.
1092  */
1093
1094 BOOLEAN
1095 MemTGetDimmSpdBuffer2 (
1096   IN OUT   MEM_TECH_BLOCK *TechPtr,
1097   IN OUT   UINT8 **SpdBuffer,
1098   IN       UINT8 Dimm
1099   )
1100 {
1101   CH_DEF_STRUCT *ChannelPtr;
1102   SPD_DEF_STRUCT *SPDPtr;
1103   BOOLEAN DimmPresent;
1104
1105   DimmPresent = FALSE;
1106   ChannelPtr = TechPtr->NBPtr->ChannelPtr;
1107   ASSERT (Dimm < (sizeof (ChannelPtr->DimmSpdPtr) / sizeof (ChannelPtr->DimmSpdPtr[0])))
1108   SPDPtr = ChannelPtr->DimmSpdPtr[Dimm];
1109
1110
1111   if (SPDPtr != NULL) {
1112     DimmPresent = SPDPtr->DimmPresent;
1113     if (DimmPresent) {
1114       *SpdBuffer = SPDPtr->Data;
1115     }
1116   }
1117   return DimmPresent;
1118 }