AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Feat / DMI / mfDMI.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mfDMI.c
6  *
7  * Memory DMI table support.
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/Main)
12  * @e \$Revision: 60218 $ @e \$Date: 2011-10-10 23:12:47 -0600 (Mon, 10 Oct 2011) $
13  *
14  **/
15 /*****************************************************************************
16   *
17  * Copyright (C) 2012 Advanced Micro Devices, Inc.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions are met:
22  *     * Redistributions of source code must retain the above copyright
23  *       notice, this list of conditions and the following disclaimer.
24  *     * Redistributions in binary form must reproduce the above copyright
25  *       notice, this list of conditions and the following disclaimer in the
26  *       documentation and/or other materials provided with the distribution.
27  *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
28  *       its contributors may be used to endorse or promote products derived
29  *       from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34  * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41   *
42   * ***************************************************************************
43   *
44  */
45
46 /*
47  *----------------------------------------------------------------------------
48  *                                MODULES USED
49  *
50  *----------------------------------------------------------------------------
51  */
52
53 #include "AGESA.h"
54 #include "Ids.h"
55 #include "heapManager.h"
56 #include "cpuServices.h"
57 #include "mm.h"
58 #include "mn.h"
59 #include "mu.h"
60 #include "GeneralServices.h"
61 #include "Filecode.h"
62 CODE_GROUP (G2_PEI)
63 RDATA_GROUP (G2_PEI)
64
65 #define FILECODE PROC_MEM_FEAT_DMI_MFDMI_FILECODE
66 /*----------------------------------------------------------------------------
67  *                          DEFINITIONS AND MACROS
68  *
69  *----------------------------------------------------------------------------
70  */
71
72 #define MAX_DCTS_PER_DIE 2
73
74 /*----------------------------------------------------------------------------
75  *                           TYPEDEFS AND STRUCTURES
76  *
77  *----------------------------------------------------------------------------
78  */
79
80 /*----------------------------------------------------------------------------
81  *                        PROTOTYPES OF LOCAL FUNCTIONS
82  *
83  *----------------------------------------------------------------------------
84  */
85 BOOLEAN
86 MemFDMISupport3 (
87   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
88   );
89
90 BOOLEAN
91 MemFDMISupport2 (
92   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
93   );
94
95 /*----------------------------------------------------------------------------
96  *                            EXPORTED FUNCTIONS
97  *
98  *----------------------------------------------------------------------------
99  */
100
101 /* -----------------------------------------------------------------------------*/
102 /**
103  *
104  *
105  *  This function gets DDR3 DMI information from SPD buffer and stores the info into heap
106  *
107  *     @param[in,out]   *MemMainPtr   - Pointer to the MEM_MAIN_DATA_BLOCK
108  *
109  */
110 BOOLEAN
111 MemFDMISupport3 (
112   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
113   )
114 {
115   UINT8  i;
116   UINT8  Dimm;
117   UINT8  Socket;
118   UINT8  NodeId;
119   UINT8  Dct;
120   UINT8  Channel;
121   UINT8  temp;
122   UINT8  MaxDimms;
123   UINT8  DimmIndex;
124   UINT8  MaxChannelsPerSocket;
125   UINT8  MaxDimmsPerChannel;
126   UINT8  FormFactor;
127   UINT16 TotalWidth;
128   UINT16 Capacity;
129   UINT16 Width;
130   UINT16 Rank;
131   UINT16 BusWidth;
132   UINT64 ManufacturerIdCode;
133   UINT32 MaxSockets;
134   UINT32 Address;
135   UINT32 TotalSize;
136   UINT32 DimmSize;
137   UINT64 AddrValue;
138   INT32  MTB_ps;
139   INT32  FTB_ps;
140   INT32  Value32;
141
142   MEM_NB_BLOCK  *NBPtr;
143   MEM_DATA_STRUCT *MemPtr;
144   ALLOCATE_HEAP_PARAMS AllocHeapParams;
145   MEM_DMI_INFO *DmiTable;
146   MEM_PARAMETER_STRUCT *RefPtr;
147
148   DIE_STRUCT *MCTPtr;
149   CH_DEF_STRUCT *ChannelPtr;
150   SPD_DEF_STRUCT *SpdDataStructure;
151
152   NBPtr = MemMainPtr->NBPtr;
153   MemPtr = MemMainPtr->MemPtr;
154   SpdDataStructure = MemPtr->SpdDataStructure;
155   MCTPtr = NBPtr->MCTPtr;
156   RefPtr = MemPtr->ParameterListPtr;
157
158   // Initialize local variables
159   MaxDimms = 0;
160   TotalSize = 0;
161
162   AGESA_TESTPOINT (TpProcMemDmi, &MemPtr->StdHeader);
163
164   ASSERT (NBPtr != NULL);
165
166   MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
167   for (Socket = 0; Socket < MaxSockets; Socket++) {
168     for (Channel = 0; Channel < GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); Channel++) {
169       temp = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
170       MaxDimms = MaxDimms + temp;
171     }
172   }
173
174   // Allocate heap for memory DMI table 16, 17, 19, 20
175   AllocHeapParams.RequestedBufferSize = MaxDimms * sizeof (MEM_DMI_INFO) + 6 + sizeof (DMI_T17_MEMORY_TYPE);
176
177   AllocHeapParams.BufferHandle = AMD_DMI_MEM_DEV_INFO_HANDLE;
178   AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
179   if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
180     PutEventLog (AGESA_CRITICAL, MEM_ERROR_HEAP_ALLOCATE_FOR_DMI_TABLE_DDR3, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader);
181     SetMemError (AGESA_CRITICAL, MCTPtr);
182     ASSERT(FALSE); // Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR3
183     return FALSE;
184   }
185
186   DmiTable = (MEM_DMI_INFO *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 6 + sizeof (DMI_T17_MEMORY_TYPE));
187   *((UINT16 *) (AllocHeapParams.BufferPtr)) = MaxDimms;          // Number of memory devices
188   *((DMI_T17_MEMORY_TYPE *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 6)) = Ddr3MemType;  // Memory type
189
190   //
191   // Gather memory DMI info
192   //
193   DimmIndex = 0;
194   for (Socket = 0; Socket < MaxSockets; Socket++) {
195     MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
196     for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
197       //
198       // Get Node number and Dct number for this channel
199       //
200       ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
201       NodeId = ChannelPtr->MCTPtr->NodeId;
202       Dct = ChannelPtr->Dct;
203       NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct);
204       MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
205       for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++, DimmIndex++) {
206         DmiTable[DimmIndex].TotalWidth = 0xFFFF;
207         DmiTable[DimmIndex].DataWidth = 0xFFFF;
208         DmiTable[DimmIndex].MemorySize = 0;
209         DmiTable[DimmIndex].Speed = 0;
210         DmiTable[DimmIndex].ManufacturerIdCode = 0;
211         DmiTable[DimmIndex].Attributes = 0;
212         DmiTable[DimmIndex].StartingAddr = 0;
213         DmiTable[DimmIndex].EndingAddr = 0;
214         DmiTable[DimmIndex].DimmPresent = 0;
215         DmiTable[DimmIndex].Socket = Socket;
216         DmiTable[DimmIndex].Channel = Channel;
217         DmiTable[DimmIndex].Dimm = Dimm;
218         DmiTable[DimmIndex].ConfigSpeed = 0;
219         DmiTable[DimmIndex].ExtSize = 0;
220         DmiTable[DimmIndex].ExtStartingAddr = 0;
221         DmiTable[DimmIndex].ExtEndingAddr = 0;
222
223         for (i = 0; i < 4; i++) {
224           DmiTable[DimmIndex].SerialNumber[i] = 0xFF;
225         }
226
227         for (i = 0; i < 18; i++) {
228           DmiTable[DimmIndex].PartNumber[i] = 0x0;
229         }
230
231         if (SpdDataStructure[DimmIndex].DimmPresent) {
232           // Total Width (offset 08h) & Data Width (offset 0Ah)
233           TotalWidth = (UINT16) SpdDataStructure[DimmIndex].Data[8];
234           if ((TotalWidth & 0x18) == 0) {
235             // non ECC
236             if ((TotalWidth & 0x07) == 0) {
237               DmiTable[DimmIndex].TotalWidth = 8;           // 8 bits
238             } else if ((TotalWidth & 0x07) == 1) {
239               DmiTable[DimmIndex].TotalWidth  = 16;         // 16 bits
240             } else if ((TotalWidth & 0x07) == 2) {
241               DmiTable[DimmIndex].TotalWidth  = 32;         // 32 bits
242             } else if ((TotalWidth & 0x07) == 3) {
243               DmiTable[DimmIndex].TotalWidth  = 64;         // 64 bits
244             }
245             DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth ;
246           } else {
247             // ECC
248             if ((TotalWidth & 0x07) == 0) {
249               DmiTable[DimmIndex].TotalWidth  = 8 + 8;      // 8 bits
250             } else if ((TotalWidth & 0x07) == 1) {
251               DmiTable[DimmIndex].TotalWidth = 16 + 8;      // 16 bits
252             } else if ((TotalWidth & 0x07) == 2) {
253               DmiTable[DimmIndex].TotalWidth  = 32 + 8;     // 32 bits
254             } else if ((TotalWidth & 0x07) == 3) {
255               DmiTable[DimmIndex].TotalWidth  = 64 + 8;     // 64 bits
256             }
257             DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth - 8;
258           }
259
260           // Memory Size (offset 0Ch)
261           Capacity = 0;
262           BusWidth = 0;
263           Width = 0;
264           Rank = 0;
265           temp = (UINT8) SpdDataStructure[DimmIndex].Data[4];
266           if ((temp & 0x0F) == 0) {
267             Capacity = 0x0100;                              // 256M
268           } else if ((temp & 0x0F) == 1) {
269             Capacity = 0x0200;                              // 512M
270           } else if ((temp & 0x0F) == 2) {
271             Capacity = 0x0400;                              // 1G
272           } else if ((temp & 0x0F) == 3) {
273             Capacity = 0x0800;                              // 2G
274           } else if ((temp & 0x0F) == 4) {
275             Capacity = 0x1000;                              // 4G
276           } else if ((temp & 0x0F) == 5) {
277             Capacity = 0x2000;                              // 8G
278           } else if ((temp & 0x0F) == 6) {
279             Capacity = 0x4000;                              // 16G
280           }
281
282           temp = (UINT8) SpdDataStructure[DimmIndex].Data[8];
283           if ((temp & 0x07) == 0) {
284             BusWidth = 8;                                   // 8 bits
285           } else if ((temp & 0x07) == 1) {
286             BusWidth = 16;                                  // 16 bits
287           } else if ((temp & 0x07) == 2) {
288             BusWidth = 32;                                  // 32 bits
289           } else if ((temp & 0x07) == 3) {
290             BusWidth = 64;                                  // 64 bits
291           }
292
293           temp = (UINT8) SpdDataStructure[DimmIndex].Data[7];
294           if ((temp & 0x07) == 0) {
295             Width = 4;                                      // 4 bits
296           } else if ((temp & 0x07) == 1) {
297             Width = 8;                                      // 8 bits
298           } else if ((temp & 0x07) == 2) {
299             Width = 16;                                     // 16 bits
300           } else if ((temp & 0x07) == 3) {
301             Width = 32;                                     // 32 bits
302           }
303
304           temp = (UINT8) SpdDataStructure[DimmIndex].Data[7];
305           if (((temp >> 3) & 0x07) == 0) {
306             Rank = 1;                                       // 4 bits
307             DmiTable[DimmIndex].Attributes = 1;             // Single Rank Dimm
308           } else if (((temp >> 3) & 0x07) == 1) {
309             Rank = 2;                                       // 8 bits
310             DmiTable[DimmIndex].Attributes = 2;             // Dual Rank Dimm
311           } else if (((temp >> 3) & 0x07) == 2) {
312             Rank = 3;                                       // 16 bits
313           } else if (((temp >> 3) & 0x07) == 3) {
314             Rank = 4;                                       // 32 bits
315             DmiTable[DimmIndex].Attributes = 4;             // Quad Rank Dimm
316           }
317
318           DimmSize = (UINT32) (Capacity / 8 * BusWidth / Width * Rank);
319           if (DimmSize < 0x7FFF) {
320             DmiTable[DimmIndex].MemorySize = (UINT16) DimmSize;
321           } else {
322             DmiTable[DimmIndex].MemorySize = 0x7FFF;
323             DmiTable[DimmIndex].ExtSize = DimmSize;
324           }
325
326           // Form Factor (offset 0Eh)
327           FormFactor = (UINT8) SpdDataStructure[DimmIndex].Data[3];
328           if ((FormFactor & 0x0F) == 0x01 || (FormFactor & 0x0F) == 0x02) {
329             DmiTable[DimmIndex].FormFactor = 0x09;         // RDIMM or UDIMM
330           } else if ((FormFactor & 0x0F) == 0x03) {
331             DmiTable[DimmIndex].FormFactor = 0x0D;         // SO-DIMM
332           }
333
334           // DIMM Present
335           DmiTable[DimmIndex].DimmPresent = 1;
336
337           // Speed (offset 15h)
338           MTB_ps = ((INT32) SpdDataStructure[DimmIndex].Data[10] * 1000) / SpdDataStructure[DimmIndex].Data[11];
339           FTB_ps = (SpdDataStructure[DimmIndex].Data[9] >> 4) / (SpdDataStructure[DimmIndex].Data[9] & 0xF);
340           Value32 = (MTB_ps * SpdDataStructure[DimmIndex].Data[12]) + (FTB_ps * (INT8) SpdDataStructure[DimmIndex].Data[34]) ;
341           if (Value32 <= 938) {
342             DmiTable[DimmIndex].Speed = 1067;              // DDR3-2133
343           } else if (Value32 <= 1071) {
344             DmiTable[DimmIndex].Speed = 933;               // DDR3-1866
345           } else if (Value32 <= 1250) {
346             DmiTable[DimmIndex].Speed = 800;               // DDR3-1600
347           } else if (Value32 <= 1500) {
348             DmiTable[DimmIndex].Speed = 667;               // DDR3-1333
349           } else if (Value32 <= 1875) {
350             DmiTable[DimmIndex].Speed = 533;               // DDR3-1066
351           } else if (Value32 <= 2500) {
352             DmiTable[DimmIndex].Speed = 400;               // DDR3-800
353           }
354
355           // Manufacturer (offset 17h)
356           ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[118];
357           DmiTable[DimmIndex].ManufacturerIdCode = (ManufacturerIdCode << 8) | ((UINT64) SpdDataStructure[DimmIndex].Data[117]);
358
359           // Serial Number (offset 18h)
360           for (i = 0; i < 4; i++) {
361             DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 122];
362           }
363           // Part Number (offset 1Ah)
364           for (i = 0; i < 18; i++) {
365             DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 128];
366           }
367
368           // Configured Memory Clock Speed (offset 20h)
369           DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed;
370
371           // Starting/Ending Address for each DIMM
372           // If Ending Address >= 0xFFFFFFFF, update Starting Address & Ending Address to 0xFFFFFFFF,
373           // and use the Extended Starting Address & Extended Ending Address instead.
374           if ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm) & 1) != 0) {
375             Address = (NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm)) & NBPtr->CsRegMsk;
376             Address = (Address & 0xFFFF0000) >> 2;
377             DmiTable[DimmIndex].StartingAddr = Address;
378             if (RefPtr->EnableBankIntlv && !NBPtr[NodeId].MCTPtr->DctData[Dct].BkIntDis) {
379               AddrValue = (UINT64) Address + ((UINT64) ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSMask0Reg + Dimm) & 0xFFFF0000) + 0x00080000) >> 2) - 1;
380               if (AddrValue >= (UINT64) 0xFFFFFFFF) {
381                 DmiTable[DimmIndex].StartingAddr = 0xFFFFFFFF;
382                 DmiTable[DimmIndex].EndingAddr = 0xFFFFFFFF;
383                 DmiTable[DimmIndex].ExtStartingAddr = (UINT64) Address;
384                 DmiTable[DimmIndex].ExtEndingAddr = AddrValue;
385               } else {
386                 DmiTable[DimmIndex].EndingAddr = (UINT32) AddrValue;
387               }
388             } else {
389               AddrValue = (UINT64) Address + (UINT64) (DmiTable[DimmIndex].MemorySize * 0x0400) - 1;
390               if (AddrValue >= (UINT64) 0xFFFFFFFF) {
391                 DmiTable[DimmIndex].StartingAddr = 0xFFFFFFFF;
392                 DmiTable[DimmIndex].EndingAddr = 0xFFFFFFFF;
393                 DmiTable[DimmIndex].ExtStartingAddr = (UINT64) Address;
394                 DmiTable[DimmIndex].ExtEndingAddr = AddrValue;
395               } else {
396                 DmiTable[DimmIndex].EndingAddr = (UINT32) AddrValue;
397               }
398             }
399           }
400         }  // Dimm present
401         TotalSize += (UINT32) DmiTable[DimmIndex].MemorySize;
402       }    // Dimm loop
403     }      // Channel loop
404   }          // Socket loop
405
406   *((UINT32 *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2)) = TotalSize;      // Max Capacity
407
408   return TRUE;
409 }
410
411 /* -----------------------------------------------------------------------------*/
412 /**
413  *
414  *
415  *  This function gets DDR2 DMI information from SPD buffer and stores the info into heap
416  *
417  *     @param[in,out]   *MemMainPtr   - Pointer to the MEM_MAIN_DATA_BLOCK
418  *
419  */
420 BOOLEAN
421 MemFDMISupport2 (
422   IN OUT   MEM_MAIN_DATA_BLOCK *MemMainPtr
423   )
424 {
425   UINT8  i;
426   UINT8  Dimm;
427   UINT8  Socket;
428   UINT8  NodeId;
429   UINT8  Dct;
430   UINT8  Channel;
431   UINT8  temp;
432   UINT8  MaxDimms;
433   UINT8  DimmIndex;
434   UINT8  MaxChannelsPerSocket;
435   UINT8  MaxDimmsPerChannel;
436   UINT8  FormFactor;
437   UINT8  Temp;
438   UINT8  Rank;
439   UINT16 TotalWidth;
440   UINT32 Speed;
441   UINT32 MaxSockets;
442   UINT32 Address;
443
444   MEM_NB_BLOCK  *NBPtr;
445   MEM_DATA_STRUCT *MemPtr;
446   ALLOCATE_HEAP_PARAMS AllocHeapParams;
447   MEM_DMI_INFO *DmiTable;
448   DIE_STRUCT *MCTPtr;
449   CH_DEF_STRUCT *ChannelPtr;
450   SPD_DEF_STRUCT *SpdDataStructure;
451   MEM_PARAMETER_STRUCT *RefPtr;
452
453   NBPtr = MemMainPtr->NBPtr;
454   MemPtr = MemMainPtr->MemPtr;
455   SpdDataStructure = MemPtr->SpdDataStructure;
456   MCTPtr = NBPtr->MCTPtr;
457   RefPtr = MemPtr->ParameterListPtr;
458
459   // Initialize local variables
460   MaxDimms = 0;
461
462   ASSERT (NBPtr != NULL);
463
464   MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
465   for (Socket = 0; Socket < MaxSockets; Socket++) {
466     for (Channel = 0; Channel < GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); Channel++) {
467       temp = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
468       MaxDimms = MaxDimms + temp;
469     }
470   }
471
472   // Allocate heap for memory DMI table 16, 17, 19, 20
473   AllocHeapParams.RequestedBufferSize = MaxDimms * sizeof (MEM_DMI_INFO) + 3;
474
475   AllocHeapParams.BufferHandle = AMD_DMI_MEM_DEV_INFO_HANDLE;
476   AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
477   if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
478     PutEventLog (AGESA_CRITICAL, MEM_ERROR_HEAP_ALLOCATE_FOR_DMI_TABLE_DDR2, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader);
479     SetMemError (AGESA_CRITICAL, MCTPtr);
480     ASSERT(FALSE); // Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR2
481     return FALSE;
482   }
483
484   DmiTable = (MEM_DMI_INFO *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2 + sizeof (DMI_T17_MEMORY_TYPE));
485   *((UINT16 *) (AllocHeapParams.BufferPtr)) = MaxDimms;          // Number of memory devices
486   *((DMI_T17_MEMORY_TYPE *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2)) = Ddr2MemType;  // Memory type
487
488   //
489   // DMI TYPE 17
490   //
491   DimmIndex = 0;
492   for (Socket = 0; Socket < MaxSockets; Socket++) {
493     MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
494     for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
495       //
496       // Get Node number and Dct number for this channel
497       //
498       ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
499       NodeId = ChannelPtr->MCTPtr->NodeId;
500       Dct = ChannelPtr->Dct;
501       NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct);
502       NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct);
503       MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
504       for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++, DimmIndex++) {
505         DmiTable[DimmIndex].TotalWidth = 0xFFFF;
506         DmiTable[DimmIndex].DataWidth = 0xFFFF;
507         DmiTable[DimmIndex].MemorySize = 0xFFFF;
508         DmiTable[DimmIndex].Speed = 0;
509         DmiTable[DimmIndex].ManufacturerIdCode = 0;
510         DmiTable[DimmIndex].Attributes = 0;
511         DmiTable[DimmIndex].StartingAddr = 0xFFFFFFFF;
512         DmiTable[DimmIndex].EndingAddr = 0xFFFFFFFF;
513         DmiTable[DimmIndex].DimmPresent = 0;
514         DmiTable[DimmIndex].ConfigSpeed = 0;
515
516         for (i = 0; i < 4; i++) {
517           DmiTable[DimmIndex].SerialNumber[i] = 0xFF;
518         }
519
520         for (i = 0; i < 18; i++) {
521           DmiTable[DimmIndex].PartNumber[i] = 0x0;
522         }
523
524         if (SpdDataStructure[DimmIndex].DimmPresent) {
525           // Total Width (offset 08h) & Data Width (offset 0Ah)
526           TotalWidth = (UINT16) SpdDataStructure[DimmIndex].Data[13];
527           if ((TotalWidth & 0x04) != 0) {
528             DmiTable[DimmIndex].TotalWidth = 4;          // 4 bits
529           } else if ((TotalWidth & 0x08) != 0) {
530             DmiTable[DimmIndex].TotalWidth = 8;          // 8 bits
531           } else if ((TotalWidth & 0x10) != 0) {
532             DmiTable[DimmIndex].TotalWidth = 16;         // 16 bits
533           } else if ((TotalWidth & 0x20) != 0) {
534             DmiTable[DimmIndex].TotalWidth = 32;         // 32 bits
535           }
536           DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth;
537
538           // Memory Size (offset 0Ch), Attributes (offset 1Bh)
539           Rank = (UINT8) SpdDataStructure[DimmIndex].Data[5] & 0x07;
540           if (Rank == 0) {
541             DmiTable[DimmIndex].Attributes = 1;          // Single Rank Dimm
542           } else if (Rank == 1) {
543             DmiTable[DimmIndex].Attributes = 2;          // Dual Rank Dimm
544           } else if (Rank == 3) {
545             DmiTable[DimmIndex].Attributes = 4;          // Quad Rank Dimm
546           }
547
548           Temp = (UINT8) SpdDataStructure[DimmIndex].Data[31];
549           for (i = 0; i < 8; i++) {
550             if ((Temp & 0x01) == 1) {
551               DmiTable[DimmIndex].MemorySize = 0x80 * (i + 1) * (Rank + 1);
552             }
553             Temp = Temp >> 1;
554           }
555
556           // Form Factor (offset 0Eh)
557           FormFactor = (UINT8) SpdDataStructure[DimmIndex].Data[20];
558           if ((FormFactor & 0x04) == 4) {
559             DmiTable[DimmIndex].FormFactor = 0x0D;       // SO-DIMM
560           } else {
561             DmiTable[DimmIndex].FormFactor = 0x09;       // RDIMM or UDIMM
562           }
563
564           // DIMM Present
565           DmiTable[DimmIndex].DimmPresent = 1;
566
567           // DIMM Index
568           DmiTable[DimmIndex].Socket = Socket;
569           DmiTable[DimmIndex].Channel = Channel;
570           DmiTable[DimmIndex].Dimm = Dimm;
571
572           // Speed (offset 15h)
573           Speed = NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFDramConfigHiReg);
574           Speed = Speed & 0x00000007;
575           if (Speed == 0) {
576             DmiTable[DimmIndex].Speed = 400;              // 400MHz
577           } else if (Speed == 1) {
578             DmiTable[DimmIndex].Speed = 533;              // 533MHz
579           } else if (Speed == 2) {
580             DmiTable[DimmIndex].Speed = 667;              // 667MHz
581           } else if (Speed == 3) {
582             DmiTable[DimmIndex].Speed = 800;              // 800MHz
583           }
584
585           // Manufacturer (offset 17h)
586           DmiTable[DimmIndex].ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[64];
587
588           // Serial Number (offset 18h)
589           for (i = 0; i < 4; i++) {
590             DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 95];
591           }
592
593           // Part Number (offset 1Ah)
594           for (i = 0; i < 18; i++) {
595             DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 73];
596           }
597
598           // Configured Memory Clock Speed (offset 20h)
599           DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed;
600
601           // AGESA does NOT support this feature when bank interleaving is enabled.
602           if (!RefPtr->EnableBankIntlv) {
603             if ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm) & 1) != 0) {
604               Address = (NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm)) & NBPtr->CsRegMsk;
605               Address = Address >> 2;
606               DmiTable[DimmIndex].StartingAddr = Address;
607               DmiTable[DimmIndex].EndingAddr = Address + (UINT32) (DmiTable[DimmIndex].MemorySize * 0x0400);
608             }
609           }
610
611         }        // DIMM Present
612       }          // DIMM loop
613     }
614   }
615
616   return TRUE;
617 }
618
619 /*---------------------------------------------------------------------------------------
620  *                          L O C A L    F U N C T I O N S
621  *---------------------------------------------------------------------------------------
622  */
623