aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f12/Proc/Mem/Tech/DDR3/mtspd3.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode/amd/agesa/f12/Proc/Mem/Tech/DDR3/mtspd3.c')
-rw-r--r--src/vendorcode/amd/agesa/f12/Proc/Mem/Tech/DDR3/mtspd3.c1156
1 files changed, 0 insertions, 1156 deletions
diff --git a/src/vendorcode/amd/agesa/f12/Proc/Mem/Tech/DDR3/mtspd3.c b/src/vendorcode/amd/agesa/f12/Proc/Mem/Tech/DDR3/mtspd3.c
deleted file mode 100644
index e0a1850ddc..0000000000
--- a/src/vendorcode/amd/agesa/f12/Proc/Mem/Tech/DDR3/mtspd3.c
+++ /dev/null
@@ -1,1156 +0,0 @@
-/* $NoKeywords:$ */
-/**
- * @file
- *
- * mtspd3.c
- *
- * Technology SPD supporting functions for DDR3
- *
- * @xrefitem bom "File Content Label" "Release Content"
- * @e project: AGESA
- * @e sub-project: (Mem/Tech/DDR3)
- * @e \$Revision: 49133 $ @e \$Date: 2011-03-17 16:54:42 +0800 (Thu, 17 Mar 2011) $
- *
- **/
-/*****************************************************************************
-*
-* Copyright (c) 2011, Advanced Micro Devices, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Advanced Micro Devices, Inc. nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-* ***************************************************************************
-*
-*/
-
-/*
- *----------------------------------------------------------------------------
- * MODULES USED
- *
- *----------------------------------------------------------------------------
- */
-
-
-
-#include "AGESA.h"
-#include "AdvancedApi.h"
-#include "Ids.h"
-#include "mport.h"
-#include "mm.h"
-#include "mn.h"
-#include "mt.h"
-#include "mt3.h"
-#include "mu.h"
-#include "mtspd3.h"
-#include "mftds.h"
-#include "GeneralServices.h"
-#include "Filecode.h"
-CODE_GROUP (G1_PEICC)
-RDATA_GROUP (G1_PEICC)
-
-#define FILECODE PROC_MEM_TECH_DDR3_MTSPD3_FILECODE
-
-/*----------------------------------------------------------------------------
- * DEFINITIONS AND MACROS
- *
- *----------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------
- * TYPEDEFS AND STRUCTURES
- *
- *----------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------
- * PROTOTYPES OF LOCAL FUNCTIONS
- *
- *----------------------------------------------------------------------------
- */
-BOOLEAN
-STATIC
-MemTCRCCheck3 (
- IN OUT UINT8 *SPDPtr
- );
-
-UINT8
-STATIC
-MemTSPDGetTCL3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- );
-
-BOOLEAN
-STATIC
-MemTCheckBankAddr3 (
- IN UINT8 Encode,
- OUT UINT8 *Index
- );
-
-/*----------------------------------------------------------------------------
- * EXPORTED FUNCTIONS
- *
- *----------------------------------------------------------------------------
- */
-
-extern BUILD_OPT_CFG UserOptions;
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function sets the DRAM mode
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- *
- * @return TRUE - indicates that the DRAM mode is set to DDR3
- */
-
-BOOLEAN
-MemTSetDramMode3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- )
-{
- TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFLegacyBiosMode, 0);
- TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFDdr3Mode, 1);
- return TRUE;
-}
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function determines if DIMMs are present. It checks checksum and interrogates the SPDs
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- *
- * @return TRUE - indicates that a FATAL error has not occurred
- * @return FALSE - indicates that a FATAL error has occurred
- */
-
-BOOLEAN
-MemTDIMMPresence3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- )
-{
- UINT8 Dct;
- UINT8 Channel;
- UINT8 i;
- MEM_PARAMETER_STRUCT *RefPtr;
- UINT8 *SpdBufferPtr = NULL;
- DIE_STRUCT *MCTPtr;
- DCT_STRUCT *DCTPtr;
- CH_DEF_STRUCT *ChannelPtr;
- MEM_NB_BLOCK *NBPtr;
- BOOLEAN SPDCtrl;
- UINT8 Devwidth;
- UINT8 MaxDimms;
- UINT8 Value8;
- UINT16 DimmMask;
-
- NBPtr = TechPtr->NBPtr;
- RefPtr = NBPtr->RefPtr;
- MCTPtr = NBPtr->MCTPtr;
-
- SPDCtrl = UserOptions.CfgIgnoreSpdChecksum;
- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
- NBPtr->SwitchDCT (NBPtr, Dct);
- DCTPtr = NBPtr->DCTPtr;
- for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
- NBPtr->SwitchChannel (NBPtr, Channel);
- ChannelPtr = NBPtr->ChannelPtr;
- ChannelPtr->DimmQrPresent = 0;
- //
- // Get the maximum number of DIMMs
- //
- MaxDimms = MAX_DIMMS_PER_CHANNEL;
- for (i = 0; i < MaxDimms; i++) {
- // Bitmask representing dimm #i.
- DimmMask = (UINT16)1 << i;
- //
- if (MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, i)) {
- MCTPtr->DimmPresent |= DimmMask;
- //
- // Check for valid checksum value
- //
- AGESA_TESTPOINT (TpProcMemSPDChecking, &(NBPtr->MemPtr->StdHeader));
- if (SpdBufferPtr[SPD_TYPE] == JED_DDR3SDRAM) {
- ChannelPtr->ChDimmValid |= DimmMask;
- MCTPtr->DimmValid |= DimmMask;
- } else {
- // Current socket is set up to only support DDR3 dimms.
- IDS_ERROR_TRAP;
- }
- if (!MemTCRCCheck3 (SpdBufferPtr) && !SPDCtrl) {
- //
- // NV_SPDCHK_RESTRT is set to 0,
- // cannot ignore faulty SPD checksum
- //
- // Indicate checksum error
- ChannelPtr->DimmSpdCse |= DimmMask;
- PutEventLog (AGESA_ERROR, MEM_ERROR_CHECKSUM_NV_SPDCHK_RESTRT_ERROR, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- SetMemError (AGESA_ERROR, MCTPtr);
- }
- //
- // Check module type information.
- //
- if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_LRDIMM) {
- //
- // LRDIMMS
- //
- ChannelPtr->LrDimmPresent |= DimmMask;
- MCTPtr->LrDimmPresent |= DimmMask;
- if (!UserOptions.CfgMemoryLRDimmCapable) {
- PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_LRDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- IDS_ERROR_TRAP;
- }
- }
- if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_RDIMM || SpdBufferPtr[SPD_DIMM_TYPE] == JED_MINIRDIMM) {
- //
- // RDIMMS
- //
- ChannelPtr->RegDimmPresent |= DimmMask;
- MCTPtr->RegDimmPresent |= DimmMask;
- if (!UserOptions.CfgMemoryRDimmCapable) {
- PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_RDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- IDS_ERROR_TRAP;
- }
- }
- if ((SpdBufferPtr[SPD_DIMM_TYPE] == JED_UDIMM) && !UserOptions.CfgMemoryUDimmCapable) {
- PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_UDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- IDS_ERROR_TRAP;
- }
- if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_SODIMM) {
- ChannelPtr->SODimmPresent |= DimmMask;
- if (!UserOptions.CfgMemorySODimmCapable) {
- PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_SODIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- IDS_ERROR_TRAP;
- }
- }
- //
- // Check error correction type
- //
- if ((SpdBufferPtr[SPD_ECCBITS] & JED_ECC) != 0) {
- MCTPtr->DimmEccPresent |= DimmMask; // Dimm has ECC
- }
- //
- // Get the Dimm width data
- //
- Devwidth = SpdBufferPtr[SPD_DEV_WIDTH] & 0x7;
- switch (Devwidth) {
- case 0:
- ChannelPtr->Dimmx4Present |= DimmMask;
- Devwidth = 4;
- break;
- case 1:
- ChannelPtr->Dimmx8Present |= DimmMask;
- Devwidth = 8;
- break;
- case 2:
- ChannelPtr->Dimmx16Present |= DimmMask;
- Devwidth = 16;
- break;
- default:
- IDS_ERROR_TRAP;
- }
- //
- // Check for 'analysis probe installed'
- // if (SpdBufferPtr[SPD_ATTRIB] & JED_PROBE_MSK)
- //
- // Determine the geometry of the DIMM module
- // if (SpdBufferPtr[SPD_DM_BANKS] & SP_DPL_BIT)
- //
- // specify the number of ranks
- //
- Value8 = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
- if (Value8 == 5) {
- // Octal Rank
- Value8 = 8;
- }
- //
- // For LRDIMMS we will assume that if there are at least 4 Physical ranks, then it Could be used
- // as a QR RDIMM with a rank Mux of x1 and therefore all four CS will be used. So an 8R LRDIMM will
- // be marked as a QR even if Rank multiplication allows it to use only 2 logical ranks.
- //
- if ((ChannelPtr->LrDimmPresent & DimmMask) != 0) {
- //
- // LRDIMM Physical Ranks
- //
- ChannelPtr->LrdimmPhysicalRanks[i] = Value8;
- }
- if (Value8 > 2) {
- if (!UserOptions.CfgMemoryQuadRankCapable) {
- PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_QRDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- }
- //
- // Mark this Dimm as Quad Rank
- //
- ChannelPtr->DimmQrPresent |= DimmMask;
- Value8 = 2;
- } else if (Value8 == 2) {
- ChannelPtr->DimmDrPresent |= DimmMask; // Dual rank dimms
- } else {
- ChannelPtr->DimmSRPresent |= DimmMask; // Single rank dimms
- }
- //
- // Calculate bus loading per Channel
- if (Devwidth == 16) {
- Devwidth = 4;
- } else if (Devwidth == 4) {
- Devwidth = 16;
- }
- //
- // Double Addr bus load value for dual rank DIMMs (Unless LRDIMM)
- //
- if (((ChannelPtr->LrDimmPresent & DimmMask) == 0) && (Value8 == 2) ) {
- Devwidth = Devwidth << 1;
- }
- //
- ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
- ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
- if ((i < 2) || ((ChannelPtr->DimmQrPresent & DimmMask) == 0)) {
- ChannelPtr->Dimms++;
- }
- //
- // Check address mirror support for Unbuffered Dimms or LRDimms
- //
- if ((ChannelPtr->RegDimmPresent & DimmMask) == 0) {
- if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) {
- ChannelPtr->DimmMirrorPresent |= DimmMask;
- }
- }
- //
- // Get byte62: Reference Raw Card information
- //
- ChannelPtr->RefRawCard[i] = SpdBufferPtr[SPD_RAWCARD] & 0x1F;
- //
- // Get control word values for RC3, RC4 and RC5
- //
- ChannelPtr->CtrlWrd03[i] = SpdBufferPtr[SPD_CTLWRD03] >> 4;
- ChannelPtr->CtrlWrd04[i] = SpdBufferPtr[SPD_CTLWRD04] & 0x0F;
- ChannelPtr->CtrlWrd05[i] = SpdBufferPtr[SPD_CTLWRD05] >> 4;
- //
- // Temporarily store info. of SPD byte 63 into CtrlWrd02(s),
- // and they will be used late to calculate real RC2 and RC8 value
- //
- ChannelPtr->CtrlWrd02[i] = SpdBufferPtr[SPD_ADDRMAP] & 0x03;
- //
- // Copy the number of registers to the Ps Block to persist across frequency changes
- //
- NBPtr->PsPtr->NumOfReg[i] = SpdBufferPtr[SPD_ADDRMAP] & 0x03;
- //
- // Workaround for early revisions of DIMMs which SPD byte 63 is 0
- //
- if (NBPtr->PsPtr->NumOfReg[i] == JED_UNDEFINED) {
- NBPtr->PsPtr->NumOfReg[i] = 1;
- }
- } // if DIMM present
- } // Dimm loop
-
- if (Channel == 0) {
- DCTPtr->Timings.DctDimmValid = ChannelPtr->ChDimmValid;
- DCTPtr->Timings.DimmMirrorPresent = ChannelPtr->DimmMirrorPresent;
- DCTPtr->Timings.DimmSpdCse = ChannelPtr->DimmSpdCse;
- DCTPtr->Timings.DimmQrPresent = ChannelPtr->DimmQrPresent;
- DCTPtr->Timings.DimmDrPresent = ChannelPtr->DimmDrPresent;
- DCTPtr->Timings.DimmSRPresent = ChannelPtr->DimmSRPresent;
- DCTPtr->Timings.Dimmx4Present = ChannelPtr->Dimmx4Present;
- DCTPtr->Timings.Dimmx8Present = ChannelPtr->Dimmx8Present;
- DCTPtr->Timings.Dimmx16Present = ChannelPtr->Dimmx16Present;
- }
- if ((Channel != 1) || (Dct != 1)) {
- MCTPtr->DimmPresent <<= 8;
- MCTPtr->DimmValid <<= 8;
- MCTPtr->RegDimmPresent <<= 8;
- MCTPtr->LrDimmPresent <<= 8;
- MCTPtr->DimmEccPresent <<= 8;
- MCTPtr->DimmParPresent <<= 8;
- }
- } // Channel loop
- } // DCT loop
-
- // If we have DIMMs, some further general characteristics checking
- if (MCTPtr->DimmValid != 0) {
- // If there are registered dimms, all the dimms must be registered
- if (MCTPtr->RegDimmPresent == MCTPtr->DimmValid) {
- // All dimms registered
- MCTPtr->Status[SbRegistered] = TRUE;
- MCTPtr->Status[SbParDimms] = TRUE; // All DDR3 RDIMMs are parity capable
- TechPtr->SetDqsEccTmgs = MemTSetDQSEccTmgsRDdr3; // Change the function pointer for DQS ECC timing
- } else if (MCTPtr->RegDimmPresent != 0) {
- // We have an illegal DIMM mismatch
- PutEventLog (AGESA_FATAL, MEM_ERROR_MODULE_TYPE_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- SetMemError (AGESA_FATAL, MCTPtr);
- }
- // If there are LrDimms, all the dimms must be LrDimms
- if (MCTPtr->LrDimmPresent == MCTPtr->DimmValid) {
- // All dimms LRDIMMs
- MCTPtr->Status[SbLrdimms] = TRUE;
- } else if (MCTPtr->LrDimmPresent != 0) {
- // We have an illegal DIMM mismatch
- PutEventLog (AGESA_FATAL, MEM_ERROR_MODULE_TYPE_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- SetMemError (AGESA_FATAL, MCTPtr);
- }
-
- // check the ECC capability of the DIMMs
- if (MCTPtr->DimmEccPresent == MCTPtr->DimmValid) {
- MCTPtr->Status[SbEccDimms] = TRUE; // All dimms ECC capable
- }
- } else {
- }
-
- NBPtr->SwitchDCT (NBPtr, 0);
- NBPtr->SwitchChannel (NBPtr, 0);
- return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
-}
-
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function finds the maximum frequency that each channel is capable to run at.
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- *
- * @return TRUE - indicates that a FATAL error has not occurred
- * @return FALSE - indicates that a FATAL error has occurred
- */
-
-BOOLEAN
-MemTSPDGetTargetSpeed3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- )
-{
- UINT8 *SpdBufferPtr = NULL;
- UINT8 Dimm;
- UINT8 Dct;
- UINT8 Channel;
- INT32 MTB_ps;
- INT32 FTB_ps;
- INT32 TCKmin_ps;
- INT32 Value32;
- MEM_NB_BLOCK *NBPtr;
- DCT_STRUCT *DCTPtr;
- CH_DEF_STRUCT *ChannelPtr;
-
- NBPtr = TechPtr->NBPtr;
- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
- NBPtr->SwitchDCT (NBPtr, Dct);
- DCTPtr = NBPtr->DCTPtr;
- TCKmin_ps = 0;
- for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
- NBPtr->SwitchChannel (NBPtr, Channel);
- ChannelPtr = NBPtr->ChannelPtr;
- for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
- if ((ChannelPtr->ChDimmValid & ((UINT8)1 << Dimm)) != 0) {
- MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
-
- // Determine tCKmin(all) which is the largest tCKmin
- // value for all modules on the memory Channel (SPD byte 12).
- //
- MTB_ps = ((INT32) SpdBufferPtr[SPD_DIVIDENT] * 1000) / SpdBufferPtr[SPD_DIVISOR];
- FTB_ps = (SpdBufferPtr[SPD_FTB] >> 4) / (SpdBufferPtr[SPD_FTB] & 0xF);
- Value32 = (MTB_ps * SpdBufferPtr[SPD_TCK]) + (FTB_ps * (INT8) SpdBufferPtr[SPD_TCK_FTB]) ;
- if (TCKmin_ps < Value32) {
- TCKmin_ps = Value32;
- }
- }
- }
- }
- if (TCKmin_ps <= 1071) {
- DCTPtr->Timings.TargetSpeed = DDR1866_FREQUENCY;
- } else if (TCKmin_ps <= 1250) {
- DCTPtr->Timings.TargetSpeed = DDR1600_FREQUENCY;
- } else if (TCKmin_ps <= 1500) {
- DCTPtr->Timings.TargetSpeed = DDR1333_FREQUENCY;
- } else if (TCKmin_ps <= 1875) {
- DCTPtr->Timings.TargetSpeed = DDR1066_FREQUENCY;
- } else if (TCKmin_ps <= 2500) {
- DCTPtr->Timings.TargetSpeed = DDR800_FREQUENCY;
- } else {
- DCTPtr->Timings.TargetSpeed = DDR667_FREQUENCY;
- }
- }
-
- // Ensure the target speed can be applied to all channels of the current node
- NBPtr->SyncTargetSpeed (NBPtr);
-
- // Set the start-up frequency
- for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
- NBPtr->SwitchDCT (NBPtr, Dct);
- NBPtr->DCTPtr->Timings.Speed = TechPtr->NBPtr->StartupSpeed;
- }
- return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
-}
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function check the symmetry of DIMM pairs (DIMM on Channel A matching with
- * DIMM on Channel B), the overall DIMM population, and determine the width mode:
- * 64-bit, 64-bit muxed, 128-bit.
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- *
- * @return TRUE - indicates that a FATAL error has not occurred
- * @return FALSE - indicates that a FATAL error has occurred
- */
-
-BOOLEAN
-MemTSPDCalcWidth3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- )
-{
- UINT8 *SpdBufferAPtr = NULL;
- UINT8 *SpdBufferBPtr = NULL;
- MEM_NB_BLOCK *NBPtr;
- DIE_STRUCT *MCTPtr;
- DCT_STRUCT *DCTPtr;
- UINT8 i;
- UINT16 DimmMask;
- UINT8 UngangMode;
-
- NBPtr = TechPtr->NBPtr;
- MCTPtr = NBPtr->MCTPtr;
- DCTPtr = NBPtr->DCTPtr;
- UngangMode = UserOptions.CfgMemoryModeUnganged;
- // Does not support ganged mode for DDR3 dimms
- ASSERT (UngangMode);
- IDS_OPTION_HOOK (IDS_GANGING_MODE, &UngangMode, &(NBPtr->MemPtr->StdHeader));
-
- // Check symmetry of channel A and channel B dimms for 128-bit mode
- // capability.
- //
- AGESA_TESTPOINT (TpProcMemModeChecking, &(NBPtr->MemPtr->StdHeader));
- i = 0;
- if (!UngangMode) {
- if (MCTPtr->DctData[0].Timings.DctDimmValid == MCTPtr->DctData[1].Timings.DctDimmValid) {
- for (; i < MAX_DIMMS_PER_CHANNEL; i++) {
- DimmMask = (UINT16)1 << i;
- if ((DCTPtr->Timings.DctDimmValid & DimmMask) != 0) {
- NBPtr->SwitchDCT (NBPtr, 0);
- MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferAPtr, i);
- NBPtr->SwitchDCT (NBPtr, 1);
- MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferBPtr, i);
- // compare rows and columns
- if ((SpdBufferAPtr[SPD_ROW_SZ]&0x3F) != (SpdBufferBPtr[SPD_ROW_SZ]&0x3F)) {
- break;
- }
- if ((SpdBufferAPtr[SPD_DENSITY]&0x0F) != (SpdBufferBPtr[SPD_DENSITY]&0x0F)) {
- break;
- }
- // compare ranks and devwidth
- if ((SpdBufferAPtr[SPD_DEV_WIDTH]&0x7F) != (SpdBufferBPtr[SPD_DEV_WIDTH]&0x7F)) {
- break;
- }
- }
- }
- }
- if (i < MAX_DIMMS_PER_CHANNEL) {
- PutEventLog (AGESA_ALERT, MEM_ALERT_ORG_MISMATCH_DIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- SetMemError (AGESA_ALERT, MCTPtr);
- } else {
- NBPtr->Ganged = TRUE;
- MCTPtr->GangedMode = TRUE;
- MCTPtr->Status[Sb128bitmode] = TRUE;
- NBPtr->SetBitField (NBPtr, BFDctGangEn, 1);
- }
- }
-
- return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
-}
-
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * Initialize DCT Timing registers as per DIMM SPD.
- * For primary timing (T, CL) use best case T value.
- * For secondary timing params., use most aggressive settings
- * of slowest DIMM.
- *
- * Note:
- * There are three components to determining "maximum frequency": SPD component,
- * Bus load component, and "Preset" max frequency component.
- * The SPD component is a function of the min cycle time specified by each DIMM,
- * and the interaction of cycle times from all DIMMs in conjunction with CAS
- * latency. The SPD component only applies when user timing mode is 'Auto'.
- *
- * The Bus load component is a limiting factor determined by electrical
- * characteristics on the bus as a result of varying number of device loads. The
- * Bus load component is specific to each platform but may also be a function of
- * other factors. The bus load component only applies when user timing mode is
- * ' Auto'.
- *
- * The Preset component is subdivided into three items and is the minimum of
- * the set: Silicon revision, user limit setting when user timing mode is 'Auto' and
- * memclock mode is 'Limit', OEM build specification of the maximum frequency.
- * The Preset component only applies when user timing mode is 'Auto'.
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- *
- * @return TRUE - indicates that a FATAL error has not occurred
- * @return FALSE - indicates that a FATAL error has occurred
- */
-
-BOOLEAN
-MemTAutoCycTiming3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- )
-{
- CONST UINT8 SpdIndexes[] = {
- SPD_TRCD,
- SPD_TRP,
- SPD_TRTP,
- SPD_TRAS,
- SPD_TRC,
- SPD_TWR,
- SPD_TRRD,
- SPD_TWTR,
- SPD_TFAW
- };
-
- CONST UINT8 SpdFTBIndexes[] = {
- SPD_TRCD_FTB,
- SPD_TRP_FTB,
- 0,
- 0,
- SPD_TRC_FTB,
- 0,
- 0,
- 0,
- 0
- };
-
- UINT8 *SpdBufferPtr = NULL;
- INT32 MiniMaxTmg[GET_SIZE_OF (SpdIndexes)];
- UINT8 MiniMaxTrfc[4];
-
- DIE_STRUCT *MCTPtr;
- DCT_STRUCT *DCTPtr;
- MEM_NB_BLOCK *NBPtr;
- UINT16 DimmMask;
- INT32 Value32;
- INT32 MTB_ps;
- INT32 FTB_ps;
- INT32 TCK_ps;
- UINT8 i;
- UINT8 j;
- UINT8 Value8;
- UINT8 *StatTmgPtr;
- UINT16 *StatDimmTmgPtr;
-
- NBPtr = TechPtr->NBPtr;
- MCTPtr = NBPtr->MCTPtr;
- DCTPtr = NBPtr->DCTPtr;
- // initialize mini-max arrays
- for (j = 0; j < GET_SIZE_OF (MiniMaxTmg); j++) {
- MiniMaxTmg[j] = 0;
- }
- for (j = 0; j < GET_SIZE_OF (MiniMaxTrfc); j++) {
- MiniMaxTrfc[j] = 0;
- }
-
- // ======================================================================
- // Get primary timing (CAS Latency and Cycle Time)
- // ======================================================================
- // Get OEM specific load variant max
- //
-
- //======================================================================
- // Gather all DIMM mini-max values for cycle timing data
- //======================================================================
- //
- DimmMask = 1;
- for (i = 0; i < (MAX_CS_PER_CHANNEL / 2); i++) {
- if ((DCTPtr->Timings.DctDimmValid & DimmMask) != 0) {
- MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, i);
- MTB_ps = ((INT32) SpdBufferPtr[SPD_DIVIDENT] * 1000) / SpdBufferPtr[SPD_DIVISOR];
- FTB_ps = (SpdBufferPtr[SPD_FTB] >> 4) / (SpdBufferPtr[SPD_FTB] & 0xF);
-
- for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
- Value32 = (UINT16)SpdBufferPtr[SpdIndexes[j]];
- if (SpdIndexes[j] == SPD_TRC) {
- Value32 |= ((UINT16)SpdBufferPtr[SPD_UPPER_TRC] & 0xF0) << 4;
- } else if (SpdIndexes[j] == SPD_TRAS) {
- Value32 |= ((UINT16)SpdBufferPtr[SPD_UPPER_TRAS] & 0x0F) << 8;
- } else if (SpdIndexes[j] == SPD_TFAW) {
- Value32 |= ((UINT16)SpdBufferPtr[SPD_UPPER_TFAW] & 0x0F) << 8;
- }
-
- Value32 *= MTB_ps;
- if (SpdFTBIndexes[j] != 0) {
- Value32 += (FTB_ps * (INT8) SpdBufferPtr[SpdFTBIndexes[j]]) ;
- }
- if (MiniMaxTmg[j] < Value32) {
- MiniMaxTmg[j] = Value32;
- }
- }
-
- // get Trfc0 - Trfc3 values
- Value8 = SpdBufferPtr[SPD_DENSITY] & 0x0F;
- if (MiniMaxTrfc[i] < Value8) {
- MiniMaxTrfc[i] = Value8;
- }
- }
- DimmMask <<= 1;
- }
-
- // ======================================================================
- // Convert DRAM CycleTiming values and store into DCT structure
- // ======================================================================
- //
- TCK_ps = 1000500 / DCTPtr->Timings.Speed;
-
- StatDimmTmgPtr = &DCTPtr->Timings.DIMMTrcd;
- StatTmgPtr = &DCTPtr->Timings.Trcd;
- for (j = 0; j < GET_SIZE_OF (SpdIndexes); j++) {
- Value32 = MiniMaxTmg[j];
-
- MiniMaxTmg[j] = (MiniMaxTmg[j] + TCK_ps - 1) / TCK_ps;
-
- StatDimmTmgPtr[j] = (UINT16) (Value32 / (1000 / 40));
- StatTmgPtr[j] = (UINT8) MiniMaxTmg[j];
- }
- DCTPtr->Timings.Trfc0 = MiniMaxTrfc[0];
- DCTPtr->Timings.Trfc1 = MiniMaxTrfc[1];
- DCTPtr->Timings.Trfc2 = MiniMaxTrfc[2];
- DCTPtr->Timings.Trfc3 = MiniMaxTrfc[3];
-
- DCTPtr->Timings.CasL = MemTSPDGetTCL3 (TechPtr);
-
- //======================================================================
- // Program DRAM Timing values
- //======================================================================
- //
- NBPtr->ProgramCycTimings (NBPtr);
-
- MemFInitTableDrive (NBPtr, MTAfterAutoCycTiming);
-
- return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
-}
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function sets the bank addressing, program Mask values and build a chip-select population map.
- * This routine programs PCI 0:24N:2x80 config register.
- * This routine programs PCI 0:24N:2x60,64,68,6C config registers (CS Mask 0-3)
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- *
- * @return TRUE - indicates that a FATAL error has not occurred
- * @return FALSE - indicates that a FATAL error has occurred
- */
-
-BOOLEAN
-MemTSPDSetBanks3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- )
-{
- UINT8 *SpdBufferPtr = NULL;
- UINT8 i;
- UINT8 ChipSel;
- UINT8 DimmID;
- UINT8 Value8;
- UINT8 Rows;
- UINT8 Cols;
- UINT8 Ranks;
- UINT8 Banks;
- UINT32 BankAddrReg;
- UINT32 CsMask;
- UINT16 CSSpdCSE;
- UINT16 CSExclude;
- UINT16 DimmQRDR;
- DIE_STRUCT *MCTPtr;
- DCT_STRUCT *DCTPtr;
- MEM_NB_BLOCK *NBPtr;
-
- NBPtr = TechPtr->NBPtr;
- MCTPtr = NBPtr->MCTPtr;
- DCTPtr = NBPtr->DCTPtr;
- BankAddrReg = 0;
- CSSpdCSE = 0;
- CSExclude = 0;
-
- for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
- DimmID = ChipSel >> 1;
-
- DimmQRDR = (DCTPtr->Timings.DimmQrPresent) | (DCTPtr->Timings.DimmDrPresent);
- if ((DCTPtr->Timings.DimmSpdCse & ((UINT16) 1 << DimmID)) != 0) {
- CSSpdCSE |= (UINT16) ((DimmQRDR & (UINT16) 1 << DimmID) ? 3 : 1) << ChipSel;
- }
- if ((DCTPtr->Timings.DimmExclude & ((UINT16) 1 << DimmID)) != 0) {
- CSExclude |= (UINT16) ((DimmQRDR & (UINT16) 1 << DimmID) ? 3: 1) << ChipSel;
- }
-
- if ((DCTPtr->Timings.DctDimmValid & ((UINT16)1 << DimmID)) != 0) {
- MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, DimmID);
-
- // Get the basic data
- Rows = (SpdBufferPtr[SPD_ROW_SZ] >> 3) & 0x7;
- Cols = SpdBufferPtr[SPD_COL_SZ] & 0x7;
- Banks = (SpdBufferPtr[SPD_L_BANKS] >> 4) & 0x7;
- Ranks = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
- if (Ranks == 5) {
- Ranks = 8;
- }
-
- //
- // Configure the bank encoding
- // Use a 6-bit key into a lookup table.
- // Key (index) = RRRBCC, where CC is the number of Columns minus 9,
- // RRR is the number of Rows minus 12, and B is the number of banks
- // minus 3.
- //
- Value8 = Cols;
- Value8 |= (Banks == 1) ? 4 : 0;
- Value8 |= Rows << 3;
-
- if (MemTCheckBankAddr3 (Value8, &i)) {
- BankAddrReg |= ((UINT32)i << (ChipSel << 1));
-
- // Mask value=(2pow(rows+cols+banks+3)-1)>>8,
- // or 2pow(rows+cols+banks-5)-1
- //
- Value8 = (Rows + 12) + (Cols + 9) + (Banks + 3) + 3 - 8;
- if (MCTPtr->Status[Sb128bitmode]) {
- Value8++;
- }
-
- DCTPtr->Timings.CsPresent |= (UINT16)1 << ChipSel;
-
- if (Ranks >= 2) {
- DCTPtr->Timings.CsPresent |= (UINT16)1 << (ChipSel + 1);
- }
- //
- // Determine LRDIMM Rank Multiplication
- //
- if (TechPtr->TechnologySpecificHook[LrdimmRankMultiplication] (TechPtr, &DimmID)) {
- //
- // Increase the CS Size by the rank multiplication factor
- //
- Value8 += ((NBPtr->ChannelPtr->LrDimmRankMult[DimmID]) >> 1);
- }
-
- CsMask = ((UINT32)1 << Value8) - 1;
- // Update the DRAM CS Mask for this chipselect
- NBPtr->SetBitField (NBPtr, BFCSMask0Reg + (ChipSel >> 1), (CsMask & NBPtr->CsRegMsk));
- } else {
- // Dimm is not supported, as no address mapping is found.
- DCTPtr->Timings.CsPresent |= (UINT16)1 << ChipSel;
- DCTPtr->Timings.CsTestFail |= (UINT16)1 << ChipSel;
- if (Ranks >= 2) {
- DCTPtr->Timings.CsPresent |= (UINT16)1 << (ChipSel + 1);
- DCTPtr->Timings.CsTestFail |= (UINT16)1 << (ChipSel + 1);
- }
- PutEventLog (AGESA_ERROR, MEM_ERROR_NO_ADDRESS_MAPPING, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, DimmID, &NBPtr->MemPtr->StdHeader);
- SetMemError (AGESA_ERROR, MCTPtr);
- }
- }
- }
- // For ranks that need to be excluded, the loading of this rank should be considered
- // in timing, so need to set CsPresent before setting CsTestFail
- if ((CSSpdCSE != 0) || (CSExclude != 0)) {
- NBPtr->MemPtr->ErrorHandling (MCTPtr, NBPtr->Dct, (CSSpdCSE | CSExclude), &NBPtr->MemPtr->StdHeader);
- }
-
- // If there are no chip selects, we have an error situation.
- if (DCTPtr->Timings.CsPresent == 0) {
- PutEventLog (AGESA_ERROR, MEM_ERROR_NO_CHIPSELECT, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
- SetMemError (AGESA_ERROR, MCTPtr);
- }
-
- NBPtr->SetBitField (NBPtr, BFDramBankAddrReg, BankAddrReg);
-
- return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
-}
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function returns the low bit that will be swapped to enable CS interleaving
- *
- * @param[in] BankEnc - AddrMap Bank encoding from F2x80
- * @param[in] *LowBit - pointer to low bit
- * @param[in] *HiBit - pointer hight bit
- *
- */
-
-VOID
-MemTGetCSIntLvAddr3 (
- IN UINT8 BankEnc,
- OUT UINT8 *LowBit,
- OUT UINT8 *HiBit
- )
-{
- CONST UINT8 ArrCodesLo[] = {0, 8, 8, 0, 0, 8, 9, 8, 9, 9, 8, 9};
- CONST UINT8 ArrCodesHi[] = {0, 20, 21, 0, 0, 22, 22, 23, 23, 24, 24, 25};
- ASSERT (BankEnc < GET_SIZE_OF (ArrCodesLo));
- ASSERT (BankEnc < GET_SIZE_OF (ArrCodesHi));
- // return ArrCodes[BankEnc];
- *LowBit = ArrCodesLo[BankEnc];
- *HiBit = ArrCodesHi[BankEnc];
-}
-
-/*----------------------------------------------------------------------------
- * LOCAL FUNCTIONS
- *
- *----------------------------------------------------------------------------
- */
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function determines if the checksum is correct
- *
- * @param[in] *SPDPtr - Pointer to SPD data
- *
- * @return TRUE - CRC check passes
- * @return FALSE - CRC check fails
- */
-
-BOOLEAN
-STATIC
-MemTCRCCheck3 (
- IN OUT UINT8 *SPDPtr
- )
-{
- UINT16 Crc;
- INT16 i;
- INT16 j;
- INT16 Count;
-
- if (SPDPtr[SPD_TYPE] == JED_DDR3SDRAM) {
- Count = (SPDPtr[SPD_BYTE_USED] & 0x80) ? 117 : 126;
- Crc = 0;
- for (j = 0; j < Count; j++) {
- Crc = Crc ^ ((UINT16)SPDPtr[j] << 8);
- for (i = 0; i < 8; i++) {
- if (Crc & 0x8000) {
- Crc = (Crc << 1) ^ 0x1021;
- } else {
- Crc = (Crc << 1);
- }
- }
- }
- if (*(UINT16 *) (SPDPtr + 126) == Crc) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function returns the CAS latency of the current frequency (DCTPtr->Timings.Speed).
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- *
- * @return CAS Latency
- */
-
-UINT8
-STATIC
-MemTSPDGetTCL3 (
- IN OUT MEM_TECH_BLOCK *TechPtr
- )
-{
- UINT8 *SpdBufferPtr = NULL;
- UINT8 CLdesired;
- UINT8 CLactual;
- UINT8 Dimm;
- UINT8 Channel;
- UINT16 CASLat;
- UINT16 Mask16;
- INT32 MTB_ps;
- INT32 FTB_ps;
- INT32 TAAmin_ps;
- INT32 TCKproposed_ps;
- INT32 Value32;
- BOOLEAN CltFail;
- MEM_NB_BLOCK *NBPtr;
- DCT_STRUCT *DCTPtr;
- CH_DEF_STRUCT *ChannelPtr;
-
- NBPtr = TechPtr->NBPtr;
- DCTPtr = NBPtr->DCTPtr;
-
- CASLat = 0xFFFF;
- TAAmin_ps = 0;
- CltFail = FALSE;
-
- for (Channel = 0; Channel < NBPtr->ChannelCount; Channel++) {
- NBPtr->SwitchChannel (NBPtr, Channel);
- ChannelPtr = NBPtr->ChannelPtr;
- for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
- if ((ChannelPtr->ChDimmValid & ((UINT8)1 << Dimm)) != 0) {
- MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
-
- // Step 1: Determine the common set of supported CAS Latency
- // values for all modules on the memory Channel using the CAS
- // Latencies Supported in SPD bytes 14 and 15.
- //
- CASLat &= ((UINT16)SpdBufferPtr[SPD_CASHI] << 8) | SpdBufferPtr[SPD_CASLO];
-
- // Step 2: Determine tAAmin(all) which is the largest tAAmin
- // value for all modules on the memory Channel (SPD byte 16).
- //
- MTB_ps = ((INT32) SpdBufferPtr[SPD_DIVIDENT] * 1000) / SpdBufferPtr[SPD_DIVISOR];
- FTB_ps = (SpdBufferPtr[SPD_FTB] >> 4) / (SpdBufferPtr[SPD_FTB] & 0xF);
- Value32 = (MTB_ps * SpdBufferPtr[SPD_TAA]) + (FTB_ps * (INT8) SpdBufferPtr[SPD_TAA_FTB]) ;
- if (TAAmin_ps < Value32) {
- TAAmin_ps = Value32;
- }
-
- // Step 3: Determine tCKmin(all) which is the largest tCKmin
- // value for all modules on the memory Channel (SPD byte 12).
- // * This step has been done in SPDGetTargetSpeed
- }
- }
- }
-
- TCKproposed_ps = 1000500 / DCTPtr->Timings.Speed;
-
- // Step 4: For a proposed tCK value (tCKproposed) between tCKmin(all) and tCKmax,
- // determine the desired CAS Latency. If tCKproposed is not a standard JEDEC
- // value (2.5, 1.875, 1.5, or 1.25 ns) then tCKproposed must be adjusted to the
- // next lower standard tCK value for calculating CLdesired.
- // CLdesired = ceiling ( tAAmin(all) / tCKproposed )
- // where tAAmin is defined in Byte 16. The ceiling function requires that the
- // quotient be rounded up always.
- //
- CLdesired = (UINT8) ((TAAmin_ps + TCKproposed_ps - 1) / TCKproposed_ps);
-
- // Step 5: Choose an actual CAS Latency (CLactual) that is greater than or equal
- // to CLdesired and is supported by all modules on the memory Channel as
- // determined in step 1. If no such value exists, choose a higher tCKproposed
- // value and repeat steps 4 and 5 until a solution is found.
- //
- CLactual = 4;
- for (Mask16 = 1; Mask16 < 0x8000; Mask16 <<= 1) {
- if (CASLat & Mask16) {
- if (CLdesired <= CLactual) {
- break;
- }
- }
- CLactual++;
- }
- if (Mask16 == 0x8000) {
- CltFail = TRUE;
- }
-
- // Step 6: Once the calculation of CLactual is completed, the BIOS must also
- // verify that this CAS Latency value does not exceed tAAmax, which is 20 ns
- // for all DDR3 speed grades, by multiplying CLactual times tCKproposed. If
- // not, choose a lower CL value and repeat steps 5 and 6 until a solution is found.
- //
- if ((TCKproposed_ps * CLactual) > 20000) {
- CltFail = TRUE;
- }
-
- if (!CltFail) {
- DCTPtr->Timings.CasL = CLactual;
- } else {
- // Fail to find supported Tcl, use 6 clocks since it is required for all DDR3 speed bin.
- DCTPtr->Timings.CasL = 6;
- }
-
- return DCTPtr->Timings.CasL;
-}
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function returns the encoded value of bank address.
- *
- * @param[in] Encode - RRRBCC, where CC is the number of Columns minus 9,
- * RRR is the number of Rows minus 12, and B is the number of banks
- * minus 3.
- * @param[out] *Index - index in bank address table
- * @return TRUE - encoded value is found.
- * FALSE - encoded value is not found.
- */
-
-BOOLEAN
-STATIC
-MemTCheckBankAddr3 (
- IN UINT8 Encode,
- OUT UINT8 *Index
- )
-{
- UINT8 i;
- CONST UINT8 TabBankAddr[] = {
- 0x3F, 0x01, 0x09, 0x3F, 0x3F, 0x11,
- 0x0A, 0x19, 0x12, 0x1A, 0x21, 0x22
- };
-
- for (i = 0; i < GET_SIZE_OF (TabBankAddr); i++) {
- if (Encode == TabBankAddr[i]) {
- *Index = i;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/* -----------------------------------------------------------------------------*/
-/**
- *
- * This function returns a pointer to the SPD Buffer of a specific dimm on
- * the current channel.
- *
- * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
- * @param[in,out] **SpdBuffer - Pointer to a pointer to a UINT8 Buffer
- * @param[in] Dimm - Dimm number
- *
- *
- * @return BOOLEAN - Value of DimmPresent
- * TRUE = Dimm is present, pointer is valid
- * FALSE = Dimm is not present, pointer has not been modified.
- */
-
-BOOLEAN
-MemTGetDimmSpdBuffer3 (
- IN OUT MEM_TECH_BLOCK *TechPtr,
- IN OUT UINT8 **SpdBuffer,
- IN UINT8 Dimm
- )
-{
- CH_DEF_STRUCT *ChannelPtr;
- SPD_DEF_STRUCT *SPDPtr;
- BOOLEAN DimmPresent;
-
- DimmPresent = FALSE;
- ChannelPtr = TechPtr->NBPtr->ChannelPtr;
- ASSERT (Dimm < (sizeof (ChannelPtr->DimmSpdPtr) / sizeof (ChannelPtr->DimmSpdPtr[0])))
- SPDPtr = ChannelPtr->DimmSpdPtr[Dimm];
-
-
- if (SPDPtr != NULL) {
- DimmPresent = SPDPtr->DimmPresent;
- if (DimmPresent) {
- *SpdBuffer = SPDPtr->Data;
- }
- }
- return DimmPresent;
-}
-