7 * Memory DMI table support.
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/Main)
12 * @e \$Revision: 60218 $ @e \$Date: 2011-10-10 23:12:47 -0600 (Mon, 10 Oct 2011) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ***************************************************************************
47 *----------------------------------------------------------------------------
50 *----------------------------------------------------------------------------
55 #include "heapManager.h"
56 #include "cpuServices.h"
60 #include "GeneralServices.h"
65 #define FILECODE PROC_MEM_FEAT_DMI_MFDMI_FILECODE
66 /*----------------------------------------------------------------------------
67 * DEFINITIONS AND MACROS
69 *----------------------------------------------------------------------------
72 #define MAX_DCTS_PER_DIE 2
74 /*----------------------------------------------------------------------------
75 * TYPEDEFS AND STRUCTURES
77 *----------------------------------------------------------------------------
80 /*----------------------------------------------------------------------------
81 * PROTOTYPES OF LOCAL FUNCTIONS
83 *----------------------------------------------------------------------------
87 IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
92 IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
95 /*----------------------------------------------------------------------------
98 *----------------------------------------------------------------------------
101 /* -----------------------------------------------------------------------------*/
105 * This function gets DDR3 DMI information from SPD buffer and stores the info into heap
107 * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK
112 IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
124 UINT8 MaxChannelsPerSocket;
125 UINT8 MaxDimmsPerChannel;
132 UINT64 ManufacturerIdCode;
143 MEM_DATA_STRUCT *MemPtr;
144 ALLOCATE_HEAP_PARAMS AllocHeapParams;
145 MEM_DMI_INFO *DmiTable;
146 MEM_PARAMETER_STRUCT *RefPtr;
149 CH_DEF_STRUCT *ChannelPtr;
150 SPD_DEF_STRUCT *SpdDataStructure;
152 NBPtr = MemMainPtr->NBPtr;
153 MemPtr = MemMainPtr->MemPtr;
154 SpdDataStructure = MemPtr->SpdDataStructure;
155 MCTPtr = NBPtr->MCTPtr;
156 RefPtr = MemPtr->ParameterListPtr;
158 // Initialize local variables
162 AGESA_TESTPOINT (TpProcMemDmi, &MemPtr->StdHeader);
164 ASSERT (NBPtr != NULL);
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;
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);
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
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
191 // Gather memory DMI info
194 for (Socket = 0; Socket < MaxSockets; Socket++) {
195 MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
196 for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
198 // Get Node number and Dct number for this channel
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;
223 for (i = 0; i < 4; i++) {
224 DmiTable[DimmIndex].SerialNumber[i] = 0xFF;
227 for (i = 0; i < 18; i++) {
228 DmiTable[DimmIndex].PartNumber[i] = 0x0;
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) {
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
245 DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth ;
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
257 DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth - 8;
260 // Memory Size (offset 0Ch)
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
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
293 temp = (UINT8) SpdDataStructure[DimmIndex].Data[7];
294 if ((temp & 0x07) == 0) {
296 } else if ((temp & 0x07) == 1) {
298 } else if ((temp & 0x07) == 2) {
299 Width = 16; // 16 bits
300 } else if ((temp & 0x07) == 3) {
301 Width = 32; // 32 bits
304 temp = (UINT8) SpdDataStructure[DimmIndex].Data[7];
305 if (((temp >> 3) & 0x07) == 0) {
307 DmiTable[DimmIndex].Attributes = 1; // Single Rank Dimm
308 } else if (((temp >> 3) & 0x07) == 1) {
310 DmiTable[DimmIndex].Attributes = 2; // Dual Rank Dimm
311 } else if (((temp >> 3) & 0x07) == 2) {
313 } else if (((temp >> 3) & 0x07) == 3) {
315 DmiTable[DimmIndex].Attributes = 4; // Quad Rank Dimm
318 DimmSize = (UINT32) (Capacity / 8 * BusWidth / Width * Rank);
319 if (DimmSize < 0x7FFF) {
320 DmiTable[DimmIndex].MemorySize = (UINT16) DimmSize;
322 DmiTable[DimmIndex].MemorySize = 0x7FFF;
323 DmiTable[DimmIndex].ExtSize = DimmSize;
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
335 DmiTable[DimmIndex].DimmPresent = 1;
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
355 // Manufacturer (offset 17h)
356 ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[118];
357 DmiTable[DimmIndex].ManufacturerIdCode = (ManufacturerIdCode << 8) | ((UINT64) SpdDataStructure[DimmIndex].Data[117]);
359 // Serial Number (offset 18h)
360 for (i = 0; i < 4; i++) {
361 DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 122];
363 // Part Number (offset 1Ah)
364 for (i = 0; i < 18; i++) {
365 DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 128];
368 // Configured Memory Clock Speed (offset 20h)
369 DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed;
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;
386 DmiTable[DimmIndex].EndingAddr = (UINT32) AddrValue;
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;
396 DmiTable[DimmIndex].EndingAddr = (UINT32) AddrValue;
401 TotalSize += (UINT32) DmiTable[DimmIndex].MemorySize;
406 *((UINT32 *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2)) = TotalSize; // Max Capacity
411 /* -----------------------------------------------------------------------------*/
415 * This function gets DDR2 DMI information from SPD buffer and stores the info into heap
417 * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK
422 IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
434 UINT8 MaxChannelsPerSocket;
435 UINT8 MaxDimmsPerChannel;
445 MEM_DATA_STRUCT *MemPtr;
446 ALLOCATE_HEAP_PARAMS AllocHeapParams;
447 MEM_DMI_INFO *DmiTable;
449 CH_DEF_STRUCT *ChannelPtr;
450 SPD_DEF_STRUCT *SpdDataStructure;
451 MEM_PARAMETER_STRUCT *RefPtr;
453 NBPtr = MemMainPtr->NBPtr;
454 MemPtr = MemMainPtr->MemPtr;
455 SpdDataStructure = MemPtr->SpdDataStructure;
456 MCTPtr = NBPtr->MCTPtr;
457 RefPtr = MemPtr->ParameterListPtr;
459 // Initialize local variables
462 ASSERT (NBPtr != NULL);
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;
472 // Allocate heap for memory DMI table 16, 17, 19, 20
473 AllocHeapParams.RequestedBufferSize = MaxDimms * sizeof (MEM_DMI_INFO) + 3;
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
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
492 for (Socket = 0; Socket < MaxSockets; Socket++) {
493 MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
494 for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
496 // Get Node number and Dct number for this channel
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;
516 for (i = 0; i < 4; i++) {
517 DmiTable[DimmIndex].SerialNumber[i] = 0xFF;
520 for (i = 0; i < 18; i++) {
521 DmiTable[DimmIndex].PartNumber[i] = 0x0;
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
536 DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth;
538 // Memory Size (offset 0Ch), Attributes (offset 1Bh)
539 Rank = (UINT8) SpdDataStructure[DimmIndex].Data[5] & 0x07;
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
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);
556 // Form Factor (offset 0Eh)
557 FormFactor = (UINT8) SpdDataStructure[DimmIndex].Data[20];
558 if ((FormFactor & 0x04) == 4) {
559 DmiTable[DimmIndex].FormFactor = 0x0D; // SO-DIMM
561 DmiTable[DimmIndex].FormFactor = 0x09; // RDIMM or UDIMM
565 DmiTable[DimmIndex].DimmPresent = 1;
568 DmiTable[DimmIndex].Socket = Socket;
569 DmiTable[DimmIndex].Channel = Channel;
570 DmiTable[DimmIndex].Dimm = Dimm;
572 // Speed (offset 15h)
573 Speed = NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFDramConfigHiReg);
574 Speed = Speed & 0x00000007;
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
585 // Manufacturer (offset 17h)
586 DmiTable[DimmIndex].ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[64];
588 // Serial Number (offset 18h)
589 for (i = 0; i < 4; i++) {
590 DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 95];
593 // Part Number (offset 1Ah)
594 for (i = 0; i < 18; i++) {
595 DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 73];
598 // Configured Memory Clock Speed (offset 20h)
599 DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed;
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);
619 /*---------------------------------------------------------------------------------------
620 * L O C A L F U N C T I O N S
621 *---------------------------------------------------------------------------------------