AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Main / muc.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * muc.c
6  *
7  * Utility functions
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/Main)
12  * @e \$Revision: 56322 $ @e \$Date: 2011-07-11 16:51:42 -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 "cpuServices.h"
57 #include "amdlib.h"
58 #include "OptionMemory.h"
59 #include "PlatformMemoryConfiguration.h"
60 #include "Ids.h"
61 #include "mport.h"
62 #include "mu.h"
63 #include "cpuFamilyTranslation.h"
64 #include "cpuCacheInit.h"
65 #include "Filecode.h"
66 CODE_GROUP (G1_PEICC)
67 RDATA_GROUP (G2_PEI)
68
69 #define FILECODE PROC_MEM_MAIN_MUC_FILECODE
70 /*----------------------------------------------------------------------------
71  *                          DEFINITIONS AND MACROS
72  *
73  *----------------------------------------------------------------------------
74  */
75 CONST UINT32 Pattern2[16] = {
76   0x12345678, 0x87654321, 0x23456789, 0x98765432,
77   0x59385824, 0x30496724, 0x24490795, 0x99938733,
78   0x40385642, 0x38465245, 0x29432163, 0x05067894,
79   0x12349045, 0x98723467, 0x12387634, 0x34587623
80 };
81
82 CONST UINT32 MaxLatPat[48] = {
83   0x6E0E3FAC, 0x0C3CFF52,
84   0x4A688181, 0x49C5B613,
85   0x7C780BA6, 0x5C1650E3,
86   0x0C4F9D76, 0x0C6753E6,
87   0x205535A5, 0xBABFB6CA,
88   0x610E6E5F, 0x0C5F1C87,
89   0x488493CE, 0x14C9C383,
90   0xF5B9A5CD, 0x9CE8F615,
91
92   0xAAD714B5, 0xC38F1B4C,
93   0x72ED647C, 0x669F7562,
94   0x5233F802, 0x4A898B30,
95   0x10A40617, 0x3326B465,
96   0x55386E04, 0xC807E3D3,
97   0xAB49E193, 0x14B4E63A,
98   0x67DF2495, 0xEA517C45,
99   0x7624CE51, 0xF8140C51,
100
101   0x4824BD23, 0xB61DD0C9,
102   0x072BCFBE, 0xE8F3807D,
103   0x919EA373, 0x25E30C47,
104   0xFEB12958, 0x4DA80A5A,
105   0xE9A0DDF8, 0x792B0076,
106   0xE81C73DC, 0xF025B496,
107   0x1DB7E627, 0x808594FE,
108   0x82668268, 0x655C7783
109 };
110
111 CONST UINT8 PatternJD[9] = {0x44, 0xA6, 0x38, 0x4F, 0x4B, 0x2E, 0xEF, 0xD5, 0x54};
112
113 CONST UINT8 PatternJD_256[256] = {
114   0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
115   0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
116   0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
117   0xFF, 0xFF, 0x00, 0xF7, 0x08, 0xF7, 0x00, 0xFF,
118   0x00, 0xF7, 0x00, 0xFF, 0x00, 0xF7, 0x00, 0xF7,
119   0x08, 0xF7, 0x08, 0xFF, 0x00, 0xFF, 0x08, 0xFF,
120   0x00, 0xFF, 0x08, 0xFF, 0x08, 0xF7, 0xFB, 0x04,
121   0xFB, 0xFB, 0x04, 0xFB, 0xFB, 0xFB, 0x04, 0xFB,
122   0xFB, 0xFB, 0xFB, 0x04, 0xFB, 0x04, 0x04, 0xFB,
123   0x04, 0x04, 0x04, 0xFB, 0x04, 0x04, 0x04, 0x04,
124   0xFB, 0x7F, 0x80, 0x7F, 0x00, 0xFF, 0x00, 0x7F,
125   0x00, 0xFF, 0x00, 0x7F, 0x00, 0x7F, 0x80, 0x7F,
126   0x80, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x00, 0xFF,
127   0x80, 0xFF, 0x80, 0x7F, 0xBF, 0x40, 0xBF, 0xBF,
128   0x40, 0xBF, 0xBF, 0xBF, 0x40, 0xBF, 0xBF, 0xBF,
129   0xBF, 0x40, 0xBF, 0x40, 0x40, 0xBF, 0x40, 0x40,
130   0x40, 0xBF, 0x40, 0x40, 0x40, 0x40, 0xBF, 0xFD,
131   0x02, 0xFD, 0x00, 0xFF, 0x00, 0xFD, 0x00, 0xFF,
132   0x00, 0xFD, 0x00, 0xFD, 0x02, 0xFD, 0x02, 0xFF,
133   0x00, 0xFF, 0x02, 0xFF, 0x00, 0xFF, 0x02, 0xFF,
134   0x02, 0xFD, 0xFE, 0x01, 0xFE, 0xFE, 0x01, 0xFE,
135   0xFE, 0xFE, 0x01, 0xFE, 0xFE, 0xFE, 0xFE, 0x01,
136   0xFE, 0x01, 0x01, 0xFE, 0x01, 0x01, 0x01, 0xFE,
137   0x01, 0x01, 0x01, 0x01, 0xFE, 0xDF, 0x20, 0xDF,
138   0x00, 0xFF, 0x00, 0xDF, 0x00, 0xFF, 0x00, 0xDF,
139   0x00, 0xDF, 0x20, 0xDF, 0x20, 0xFF, 0x00, 0xFF,
140   0x20, 0xFF, 0x00, 0xFF, 0x20, 0xFF, 0x20, 0xDF,
141   0xEF, 0x10, 0xEF, 0xEF, 0x10, 0xEF, 0xEF, 0xEF,
142   0x10, 0xEF, 0xEF, 0xEF, 0xEF, 0x10, 0xEF, 0x10,
143   0x10, 0xEF, 0x10, 0x10, 0x10, 0xEF, 0x10, 0x10,
144   0x10, 0x10, 0xEF, 0xF7, 0x00, 0xFF, 0x04, 0x7F,
145   0x00, 0xFF, 0x40, 0xFD, 0x00, 0xFF, 0x01, 0xDF
146 };
147
148 /*----------------------------------------------------------------------------
149  *                           TYPEDEFS AND STRUCTURES
150  *
151  *----------------------------------------------------------------------------
152  */
153
154 /*----------------------------------------------------------------------------
155  *                        PROTOTYPES OF LOCAL FUNCTIONS
156  *
157  *----------------------------------------------------------------------------
158  */
159
160
161 /*----------------------------------------------------------------------------
162  *                            EXPORTED FUNCTIONS
163  *
164  *----------------------------------------------------------------------------
165  */
166 /* -----------------------------------------------------------------------------*/
167 /**
168  *
169  *      This function returns the (index)th UINT8
170  *   from an indicated test pattern.
171  *
172  *     @param[in] Pattern - encoding of test pattern type
173  *     @param[in] Buffer[] - buffer to be filled
174  *     @param[in] Size - Size of the buffer
175  *
176  * ----------------------------------------------------------------------------
177  */
178
179 VOID
180 MemUFillTrainPattern (
181   IN       TRAIN_PATTERN Pattern,
182   IN       UINT8 Buffer[],
183   IN       UINT16 Size
184   )
185 {
186   UINT8 Result;
187   UINT8 i;
188   UINT8 Mask;
189   UINT16 Index;
190   UINT16 k;
191
192   for (Index = 0; Index < Size; Index++) {
193     k = Index;
194     // get one byte from Pattern
195     switch (Pattern) {
196     case TestPattern0:
197       Result = 0xAA;
198       break;
199     case TestPattern1:
200       Result = 0x55;
201       break;
202     case TestPattern2:
203       ASSERT (Index < sizeof (Pattern2));
204       Result = ((UINT8 *)Pattern2)[Index];
205       break;
206     case TestPatternML:
207       if (Size != 6 * 64) {
208         Result = ((UINT8 *)MaxLatPat)[Index];
209       } else {
210         Result = ((UINT8 *)MaxLatPat)[Index & 0xF7];
211       }
212       break;
213     case TestPatternJD256B:
214       k >>= 1;
215       // break is not being used here because TestPatternJD256B also need
216       // to run TestPatternJD256A sequence.
217     case TestPatternJD256A:
218       k >>= 3;
219       ASSERT (k < sizeof (PatternJD_256));
220       Result = PatternJD_256[k];
221       break;
222     case TestPatternJD1B:
223       k >>= 1;
224       // break is not being used here because TestPatternJD1B also need
225       // to run TestPatternJD1A sequence.
226     case TestPatternJD1A:
227       k >>= 3;
228       i = (UINT8) (k >> 3);
229       Mask = (UINT8) (0x80 >> (k & 7));
230
231       if (i == 0) {
232         Result = 0;
233       } else {
234         Result = (UINT16)1 << (i - 1);
235       }
236
237       ASSERT (i < sizeof (PatternJD));
238       if (PatternJD[i] & Mask) {
239         Result = ~Result;
240       }
241       break;
242     case TestPattern3:
243       Result = 0x36;
244       break;
245     case TestPattern4:
246       Result = 0xC9;
247       break;
248     default:
249       Result = 0;
250       IDS_ERROR_TRAP;
251     }
252
253     // fill in the Pattern buffer
254     Buffer[Index] = Result;
255   }
256 }
257
258 /* -----------------------------------------------------------------------------*/
259 /**
260  *
261  *      This function flushes cache lines
262  *
263  *     @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
264  *     @param[in] ClCount - Number of cache lines
265  *     @param[in] Address - System Address [47:16]
266  *
267  * ----------------------------------------------------------------------------
268  */
269
270 VOID
271 MemUProcIOClFlush (
272   IN       UINT32 Address,
273   IN       UINT16 ClCount,
274   IN OUT   MEM_DATA_STRUCT *MemPtr
275   )
276 {
277   MemUSetTargetWTIO (Address, MemPtr);
278   MemUFlushPattern (MemUSetUpperFSbase (Address, MemPtr), ClCount);
279   MemUResetTargetWTIO (MemPtr);
280 }
281
282 /*----------------------------------------------------------------------------
283  *                              LOCAL FUNCTIONS
284  *
285  *----------------------------------------------------------------------------
286  */
287
288 /* -----------------------------------------------------------------------------*/
289 /**
290  *
291  *      This function sets the upper 32-bits of the Base address, 4GB aligned) for the FS selector.
292  *      @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
293  *      @param[in] Address - System Address [47:16]
294  *
295  *     @return  Address - Lowest 32-bit of physical address
296  * ----------------------------------------------------------------------------
297  */
298
299 UINT32
300 MemUSetUpperFSbase (
301   IN       UINT32 Address,
302   IN OUT   MEM_DATA_STRUCT *MemPtr
303   )
304 {
305   S_UINT64 SMsr;
306
307   SMsr.lo = 0;
308   SMsr.hi = Address >> 16;
309   LibAmdMsrWrite (FS_BASE, (UINT64 *)&SMsr, &MemPtr->StdHeader);
310   return Address << 16;
311 }
312
313
314 /* -----------------------------------------------------------------------------*/
315 /**
316  *
317  *      This function resets the target address space to Write Through IO by disabling IORRs
318  *
319  *      @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
320  *
321  * ----------------------------------------------------------------------------
322  */
323
324 VOID
325 MemUResetTargetWTIO (
326   IN OUT   MEM_DATA_STRUCT *MemPtr
327   )
328 {
329   S_UINT64 SMsr;
330   SMsr.hi = 0;
331   SMsr.lo = 0;
332   LibAmdMsrWrite (IORR0_MASK, (UINT64 *)&SMsr, &MemPtr->StdHeader);
333 }
334
335 /* -----------------------------------------------------------------------------*/
336 /**
337  *
338  *       This function sets the target range to WT IO (using an IORR overlapping
339  *       the already existing
340  *
341  *      @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
342  *      @param[in] Address - System Address [47:16]
343  *
344  * ----------------------------------------------------------------------------
345  */
346
347 VOID
348 MemUSetTargetWTIO (
349   IN       UINT32 Address,
350   IN OUT   MEM_DATA_STRUCT *MemPtr
351   )
352 {
353   S_UINT64 SMsr;
354
355   SMsr.lo = Address << 16;
356   SMsr.hi = Address >> 16;
357   LibAmdMsrWrite (IORR0_BASE,(UINT64 *)&SMsr, &MemPtr->StdHeader);           // IORR0 Base
358   SMsr.hi = 0xFFFF;
359   SMsr.lo = 0xFC000800;
360   LibAmdMsrWrite (IORR0_MASK, (UINT64 *)&SMsr, &MemPtr->StdHeader);          // 64MB Mask
361 }
362
363 /* -----------------------------------------------------------------------------*/
364 /**
365  *
366  *  Waits specified number of 10ns cycles
367  *      @param[in,out] MemPtr - pointer to MEM_DATA_STRUCTURE
368  *      @param[in] Count - Number of 10ns cycles to wait; Note that Count must not exceed 1000000
369  *
370  * ----------------------------------------------------------------------------
371  */
372
373 VOID
374 MemUWait10ns (
375   IN       UINT32 Count,
376   IN OUT   MEM_DATA_STRUCT *MemPtr
377   )
378 {
379   UINT64 TargetTsc;
380   UINT64 CurrentTsc;
381
382   ASSERT (Count <= 1000000);
383
384   MemUMFenceInstr ();
385
386   LibAmdMsrRead (TSC, &CurrentTsc, &MemPtr->StdHeader);
387   TargetTsc = CurrentTsc + ((Count * MemPtr->TscRate + 99) / 100);
388   do {
389     LibAmdMsrRead (TSC, &CurrentTsc, &MemPtr->StdHeader);
390   } while (CurrentTsc < TargetTsc);
391 }
392
393 /* -----------------------------------------------------------------------------*/
394 /**
395  *
396  *      Find the entry of platform specific overriding table.
397  *
398  *      @param[in] PlatformMemoryConfiguration - Platform config table
399  *      @param[in] EntryType - Entry type
400  *      @param[in] SocketID - Physical socket ID
401  *      @param[in] ChannelID - Physical channel ID
402  *      @param[in] DimmID - Physical Dimm ID
403  *      @param[in] *LogicalIdPtr - Pointer to the CPU_LOGICAL_ID
404  *      @param[in,out]  *StdHeader - Pointer of AMD_CONFIG_PARAMS
405  *                 - If both *LogicalIdPtr and *StdHeader are "NULL" input,
406  *                   that means, the "EntryType" are not CPU family dependent,
407  *                   ex. PSO_MAX_DIMMS for NUMBER_OF_DIMMS_SUPPORTED macro.
408  *
409  *
410  *      @return  NULL - entry could not be found.
411  *      @return  Pointer - points to the entry's data.
412  *
413  * ----------------------------------------------------------------------------
414  */
415
416 VOID *
417 FindPSOverrideEntry (
418   IN       PSO_TABLE *PlatformMemoryConfiguration,
419   IN       PSO_ENTRY EntryType,
420   IN       UINT8 SocketID,
421   IN       UINT8 ChannelID,
422   IN       UINT8 DimmID,
423   IN       CPU_LOGICAL_ID *LogicalIdPtr,
424   IN       AMD_CONFIG_PARAMS *StdHeader
425   )
426 {
427   UINT8 *Buffer;
428   CPU_LOGICAL_ID LogicalCpuId;
429   UINT32 RawCpuId;
430
431   LogicalCpuId.Family = AMD_FAMILY_UNKNOWN;
432   LogicalCpuId.Revision = 0;
433   RawCpuId = 0;
434
435   Buffer = PlatformMemoryConfiguration;
436   //
437   // Do not need to look for CPU family specific PSO if LogicalIdPtr and StdHeader are NULL.
438   //
439   if ((LogicalIdPtr != NULL) && (StdHeader != NULL)) {
440     //
441     // Looking for the CPU family signature followed by CPUID value.
442     // And check to see if the CPUID value is matched with current CPU's :
443     //    - If matched, Buffer points to following PSO macros' start address.
444     //    - If not matched, Buffer points to PlatformMemoryConfiguration for global PSO parsing.
445     //
446     while (Buffer[0] != PSO_END) {
447       if (Buffer[0] == PSO_CPU_FAMILY_TO_OVERRIDE) {
448         RawCpuId = *(UINT32 *)&Buffer[2];
449         GetLogicalIdFromCpuid (RawCpuId, &LogicalCpuId, StdHeader);
450         if ((LogicalCpuId.Family & LogicalIdPtr->Family) != 0) {
451           if ((LogicalCpuId.Revision & LogicalIdPtr->Revision) != 0) {
452             Buffer += Buffer[1] + 2;
453             break;
454           }
455         }
456       }
457       Buffer += Buffer[1] + 2;
458     }
459     //
460     // If no CPU family specific PSO macros exist, Buffer points to PlatformMemoryConfiguration again
461     //
462     if (Buffer[0] == PSO_END) {
463       Buffer = PlatformMemoryConfiguration;
464     }
465   }
466
467   while ((Buffer[0] != PSO_END) && (Buffer[0] != PSO_CPU_FAMILY_TO_OVERRIDE)) {
468     if (Buffer[0] == EntryType) {
469       if ((Buffer[2] & ((UINT8) 1 << SocketID)) != 0 ) {
470         if ((Buffer[3] & ((UINT8) 1 << ChannelID)) != 0 ) {
471           if ((Buffer[4] & ((UINT8) 1 << DimmID)) != 0 ) {
472             return &Buffer[5];
473           }
474         }
475       }
476     }
477     Buffer += Buffer[1] + 2;
478   }
479
480   return NULL;
481 }
482
483 /* -----------------------------------------------------------------------------*/
484 /**
485  *
486  *
487  *      This function returns the max dimms for a given memory channel on a given
488  *  processor.  It first searches the platform override table for the max dimms
489  *  value.  If it is not provided, the AGESA default value is returned. The target
490  *  socket must be a valid present socket.
491  *
492  *     @param[in] PlatformMemoryConfiguration - Platform config table
493  *     @param[in] SocketID  - ID of the processor that owns the channel
494  *     @param[in] ChannelID - Channel to get max dimms for
495  *
496  *
497  *     @return UINT8 - Max Number of Dimms for that channel
498  */
499 UINT8
500 GetMaxDimmsPerChannel (
501   IN       PSO_TABLE *PlatformMemoryConfiguration,
502   IN       UINT8 SocketID,
503   IN       UINT8 ChannelID
504   )
505 {
506   UINT8  *DimmsPerChPtr;
507   UINT8  MaxDimmPerCH;
508
509   DimmsPerChPtr = FindPSOverrideEntry (PlatformMemoryConfiguration, PSO_MAX_DIMMS, SocketID, ChannelID, 0, NULL, NULL);
510   if (DimmsPerChPtr != NULL) {
511     MaxDimmPerCH = *DimmsPerChPtr;
512   } else {
513     MaxDimmPerCH = MAX_DIMMS_PER_CHANNEL;
514   }
515   // Maximum number of dimms per channel cannot be larger than its default value.
516   ASSERT (MaxDimmPerCH <= MAX_DIMMS_PER_CHANNEL);
517
518   return MaxDimmPerCH;
519 }
520
521 /* -----------------------------------------------------------------------------*/
522 /**
523  *
524  *
525  *      This function returns the max memory channels on a given processor.
526  *  It first searches the platform override table for the max channels value.
527  *  If it is not provided, the AGESA default value is returned.
528  *
529  *     @param[in] PlatformMemoryConfiguration - Platform config table
530  *     @param[in] SocketID - ID of the processor
531  *     @param[in] StdHeader - Header for library and services
532  *
533  *
534  *     @return UINT8 - Max Number of Channels on that Processor
535  */
536 UINT8
537 GetMaxChannelsPerSocket (
538   IN       PSO_TABLE *PlatformMemoryConfiguration,
539   IN       UINT8 SocketID,
540   IN       AMD_CONFIG_PARAMS *StdHeader
541   )
542 {
543   UINT8  *ChannelsPerSocketPtr;
544   UINT8  MaxChannelsPerSocket;
545
546   if (IsProcessorPresent (SocketID, StdHeader)) {
547     ChannelsPerSocketPtr = FindPSOverrideEntry (PlatformMemoryConfiguration, PSO_MAX_CHNLS, SocketID, 0, 0, NULL, NULL);
548     if (ChannelsPerSocketPtr != NULL) {
549       MaxChannelsPerSocket = *ChannelsPerSocketPtr;
550     } else {
551       MaxChannelsPerSocket = MAX_CHANNELS_PER_SOCKET;
552     }
553     // Maximum number of channels per socket cannot be larger than its default value.
554     ASSERT (MaxChannelsPerSocket <= MAX_CHANNELS_PER_SOCKET);
555   } else {
556     MaxChannelsPerSocket = 0;
557   }
558
559   return MaxChannelsPerSocket;
560 }
561
562 /* -----------------------------------------------------------------------------*/
563 /**
564  *
565  *
566  *      This function returns the max number of chip select on a given channel of
567  *  a given processor. It first searches the platform override table for the max
568  *  chip select value. If it is not provided, the AGESA default value is returned.
569  *  The target socket must be a valid present socket.
570  *
571  *     @param[in] PlatformMemoryConfiguration - Platform config table
572  *     @param[in] SocketID - ID of the processor
573  *     @param[in] ChannelID - ID of a channel
574  *
575  *
576  *     @return UINT8 - Max Number of chip selects on the channel of the Processor
577  */
578 UINT8
579 GetMaxCSPerChannel (
580   IN      PSO_TABLE *PlatformMemoryConfiguration,
581   IN      UINT8 SocketID,
582   IN      UINT8 ChannelID
583   )
584 {
585   UINT8  *CSPerSocketPtr;
586   UINT8  MaxCSPerChannel;
587
588   CSPerSocketPtr = FindPSOverrideEntry (PlatformMemoryConfiguration, PSO_MAX_CHIPSELS, SocketID, ChannelID, 0, NULL, NULL);
589   if (CSPerSocketPtr != NULL) {
590     MaxCSPerChannel = *CSPerSocketPtr;
591   } else {
592     MaxCSPerChannel = MAX_CS_PER_CHANNEL;
593   }
594   // Max chip select per channel cannot be larger than its default value
595   ASSERT (MaxCSPerChannel <= MAX_CS_PER_CHANNEL);
596
597   return MaxCSPerChannel;
598 }
599
600 /* -----------------------------------------------------------------------------*/
601 /**
602  *
603  *
604  *      This function returns the index of the first Dimm SPD structure for a
605  *  given processor socket. It checks the Max Dimms per channel for every memory
606  *  channel on every processor up to the current one, and adds them together.
607  *
608  *      This function may also be used to calculate the maximum dimms per system
609  *  by passing the total number of dimm sockets
610  *
611  *     @param[in] PlatformMemoryConfiguration - Platform config table
612  *     @param[in] SocketID - ID of the processor
613  *     @param[in] StdHeader - Header for library and services
614  *
615  *     @return UINT8 - SPD Index
616  */
617 UINT8
618 GetSpdSocketIndex (
619   IN       PSO_TABLE *PlatformMemoryConfiguration,
620   IN       UINT8 SocketID,
621   IN       AMD_CONFIG_PARAMS *StdHeader
622   )
623 {
624   UINT8 SpdSocketIndex;
625   UINT8 Socket;
626   UINT8 Channel;
627   UINT8  MaxChannelsPerSocket;
628
629   SpdSocketIndex = 0;
630   for (Socket = 0; Socket < SocketID; Socket++) {
631     MaxChannelsPerSocket = GetMaxChannelsPerSocket (PlatformMemoryConfiguration, Socket, StdHeader);
632     for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
633       SpdSocketIndex = SpdSocketIndex + GetMaxDimmsPerChannel (PlatformMemoryConfiguration, Socket, Channel);
634     }
635   }
636   return SpdSocketIndex;
637 }
638
639 /* -----------------------------------------------------------------------------*/
640 /**
641  *
642  *
643  *      This function returns the index of the first Dimm SPD structure for a
644  *  given channel relative to the processor socket. It checks the Max Dimms per
645  *  channel for every memory channel on that processor up to the current one,
646  *  and adds them together.
647  *
648  *      This function may also be used to calculate the maximum dimms per system
649  *  by passing the total number of DIMM sockets
650  *
651  *     @param[in] PlatformMemoryConfiguration - Platform config table
652  *     @param[in] SocketID - ID of the processor
653  *     @param[in] ChannelID - ID of the Channel
654  *     @param[in] StdHeader - Header for library and services
655  *
656  *     @return UINT8 - SPD Index
657  */
658 UINT8
659 GetSpdChannelIndex (
660   IN       PSO_TABLE *PlatformMemoryConfiguration,
661   IN       UINT8 SocketID,
662   IN       UINT8 ChannelID,
663   IN       AMD_CONFIG_PARAMS *StdHeader
664   )
665 {
666   UINT8 SpdChannelIndex;
667   UINT8 Channel;
668
669   SpdChannelIndex = 0;
670   ASSERT (ChannelID < GetMaxChannelsPerSocket (PlatformMemoryConfiguration, SocketID, StdHeader))
671   for (Channel = 0; Channel < ChannelID; Channel++) {
672     SpdChannelIndex = SpdChannelIndex + GetMaxDimmsPerChannel (PlatformMemoryConfiguration, SocketID, Channel);
673   }
674   return SpdChannelIndex;
675 }
676
677 /*-----------------------------------------------------------------------------*/
678 /**
679  *
680  *     This function returns the upper 32 bits mask for variable MTRR based on
681  *     the CPU_LOGICAL_ID.
682  *     @param[in]       *LogicalIdPtr - Pointer to the CPU_LOGICAL_ID
683  *     @param[in]       StdHeader - Header for library and services
684  *
685  *     @return          UINT32 - MTRR mask for upper 32 bits
686  *
687  */
688 UINT32
689 GetVarMtrrHiMsk (
690   IN       CPU_LOGICAL_ID *LogicalIdPtr,
691   IN       AMD_CONFIG_PARAMS *StdHeader
692   )
693 {
694   UINT8 TempNotCare;
695   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
696   CONST CACHE_INFO *CacheInfoPtr;
697
698   GetCpuServicesFromLogicalId (LogicalIdPtr, (CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
699   FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **) &CacheInfoPtr, &TempNotCare, StdHeader);
700   return (UINT32) (CacheInfoPtr->VariableMtrrMask >> 32);
701 }
702
703
704 /*-----------------------------------------------------------------------------*/
705 /**
706  *
707  *     This function returns number of memclk converted from ns
708  *     @param[in]       Speed - memclk frequency
709  *     @param[in]       NumberOfns - number of ns to be converted
710  *
711  *     @return          UINT32 - number of memclk
712  *
713  */
714 UINT32
715 MemUnsToMemClk (
716   IN       MEMORY_BUS_SPEED Speed,
717   IN       UINT32 NumberOfns
718   )
719 {
720   return (UINT32) ((NumberOfns * Speed + 999) / 1000);
721 }