blob: f39655d7012abf457b4d253873ed8e05a04d9f97 [file] [log] [blame]
/**
* @file
*
* mrtspd3.c
*
* Technology SPD supporting functions for DDR3 Recovery
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: (Proc/Recovery/Mem)
* @e \$Revision: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
*
**/
/*****************************************************************************
*
* 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 "amdlib.h"
#include "Ids.h"
#include "mm.h"
#include "mn.h"
#include "mt.h"
#include "mrtspd3.h"
#include "Filecode.h"
#define FILECODE PROC_RECOVERY_MEM_TECH_DDR3_MRTSPD3_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
#define _UNDEF_ 0xFF
#define MAX_DIES_PER_SOCKET 2 ///< Set to largest of any CPU
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* EXPORTED FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/* -----------------------------------------------------------------------------*/
/**
*
* 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 DDR2
*/
BOOLEAN
MemRecTSetDramMode3 (
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 FALL - indicates that a FATAL error has not occurred
*/
BOOLEAN
MemRecTDIMMPresence3 (
IN OUT MEM_TECH_BLOCK *TechPtr
)
{
UINT8 Node;
UINT8 Dct;
UINT8 Channel;
UINT8 i;
SPD_DEF_STRUCT *SPDPtr;
UINT8 *SpdBufferPtr;
DIE_STRUCT *MCTPtr;
DCT_STRUCT *DCTPtr;
CH_DEF_STRUCT *ChannelPtr;
MEM_NB_BLOCK *NBPtr;
UINT16 MaxDimms;
UINT16 Value16;
UINT8 Devwidth;
UINT8 Value8;
UINT16 DimmMask;
NBPtr = TechPtr->NBPtr;
MCTPtr = NBPtr->MCTPtr;
NBPtr->DimmToBeUsed = _UNDEF_;
for (Node = 0; Node < MAX_DIES_PER_SOCKET; Node++) {
NBPtr->SwitchNodeRec (NBPtr, Node);
for (Dct = 0; Dct < NBPtr->MCTPtr->DctCount; Dct++) {
NBPtr->SwitchDCT (NBPtr, Dct);
DCTPtr = NBPtr->DCTPtr;
for (Channel = 0; Channel < DCTPtr->ChannelCount; Channel++) {
NBPtr->SwitchChannel (NBPtr, Channel);
ChannelPtr = NBPtr->ChannelPtr;
SPDPtr = NBPtr->SPDPtr;
// 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 (SPDPtr[i].DimmPresent) {
SpdBufferPtr = (UINT8 *)&(SPDPtr[i].Data);
MCTPtr->DimmPresent |= DimmMask;
if (SpdBufferPtr[SPD_TYPE] == JED_DDR3SDRAM) {
ChannelPtr->ChDimmValid |= DimmMask;
if (NBPtr->DimmToBeUsed == _UNDEF_) {
NBPtr->DimmToBeUsed = i;
}
}
// Check module type information.
if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_RDIMM || SpdBufferPtr[SPD_DIMM_TYPE] == JED_MINIRDIMM) {
ChannelPtr->RegDimmPresent |= DimmMask;
}
if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_SODIMM) {
ChannelPtr->SODimmPresent |= DimmMask;
}
// 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;
}
// Determine the page size.
// page_size = 2^COLBITS * Devwidth/8
//
Value16 = (((UINT16) 1 << (SpdBufferPtr[SPD_COL_SZ]&7)) * Devwidth) / 8;
if ((Value16 >> 11) == 0) {
DCTPtr->Timings.DIMM1KPage |= DimmMask;
}
// Calculate bus loading per Channel
if (Devwidth == 16) {
Devwidth = 4;
} else if (Devwidth == 4) {
Devwidth = 16;
}
// specify the number of ranks
Value8 = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
if (Value8 > 2) {
ChannelPtr->DimmQrPresent |= DimmMask;
Devwidth = Devwidth << 2;
} else if (Value8 == 2) {
ChannelPtr->DimmDrPresent |= DimmMask; // Dual rank dimms
Devwidth = Devwidth << 1;
}
ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
ChannelPtr->Dimms++;
// Check address mirror support for Unbuffered Dimms only
if ((ChannelPtr->RegDimmPresent & DimmMask) == 0) {
if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) {
ChannelPtr->DimmMirrorPresent |= DimmMask;
}
}
// 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;
} // if DIMM present
} // Dimm loop
if (ChannelPtr->ChDimmValid != 0) {
// exit loops
Channel = DCTPtr->ChannelCount;
Dct = NBPtr->MCTPtr->DctCount;
Node = MAX_DIES_PER_SOCKET;
}
} // Channel loop
} // DCT loop
}
// If we have DIMMs, some further general characteristics checking
if (NBPtr->DimmToBeUsed == _UNDEF_) {
// Leave with an error - no dimms on this DCT
// LibAmdEventLog (AGESA_FATAL, MEM_ERROR_NO_DIMM_FOUND, 0, NBPtr->Dct, NBPtr->Channel, 0); //@attention commented out since it is not defined in recovery code
SetMemRecError (AGESA_FATAL, MCTPtr);
}
return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
}
/*----------------------------------------------------------------------------
* LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/