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