diff options
author | efdesign98 <efdesign98@gmail.com> | 2011-06-20 18:12:43 -0700 |
---|---|---|
committer | Marc Jones <marcj303@gmail.com> | 2011-06-22 01:35:45 +0200 |
commit | 621ca384a7a5efb2cc7597504dc17b741cd2df10 (patch) | |
tree | 01871adc6d39f48916b5625b3aa1a4b6d5ab9c92 /src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3 | |
parent | 05a89ab922473f375820a3bd68691bb085c62448 (diff) |
Move existing AMD Ffamily14 code to f14 folder
This change moves the AMD Family14 cpu Agesa code to
the vendorcode/amd/agesa/f14 folder to complete the
transition to the family oriented folder structure.
Change-Id: I211e80ee04574cc713f38b4cc1b767dbb2bfaa59
Signed-off-by: Frank Vibrans <frank.vibrans@amd.com>
Signed-off-by: efdesign98 <efdesign98@gmail.com>
Reviewed-on: http://review.coreboot.org/52
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marcj303@gmail.com>
Diffstat (limited to 'src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3')
14 files changed, 5023 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.c new file mode 100644 index 0000000000..b1ab754103 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.c @@ -0,0 +1,237 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mt3.c + * + * Common Technology functions for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 36765 $ @e \$Date: 2010-08-25 23:06:36 +0800 (Wed, 25 Aug 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 "Ids.h" +#include "mm.h" +#include "mn.h" +#include "mu.h" +#include "mt.h" +#include "mt3.h" +#include "mtspd3.h" +#include "mtot3.h" +#include "OptionMemory.h" +#include "PlatformMemoryConfiguration.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) + +/* features */ +#define FILECODE PROC_MEM_TECH_DDR3_MT3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ +/* -----------------------------------------------------------------------------*/ +/** + * + * This function Constructs the technology block + * + * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +BOOLEAN +MemConstructTechBlock3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT MEM_NB_BLOCK *NBPtr + ) +{ + TECHNOLOGY_TYPE *TechTypePtr; + UINT8 Dct; + UINT8 Channel; + UINT8 i; + DIE_STRUCT *MCTPtr; + DCT_STRUCT *DCTPtr; + CH_DEF_STRUCT *ChannelPtr; + UINT8 DimmSlots; + + + TechTypePtr = (TECHNOLOGY_TYPE *) FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_MEM_TECH, NBPtr->MCTPtr->SocketId, 0); + if (TechTypePtr != NULL) { + // Ensure the platform override value is valid + ASSERT ((*TechTypePtr == DDR3_TECHNOLOGY) || (*TechTypePtr == DDR2_TECHNOLOGY)); + if (*TechTypePtr != DDR3_TECHNOLOGY) { + return FALSE; + } + } + + TechPtr->NBPtr = NBPtr; + TechPtr->RefPtr = NBPtr->RefPtr; + MCTPtr = NBPtr->MCTPtr; + + TechPtr->SendAllMRCmds = MemTSendAllMRCmds3; + TechPtr->FreqChgCtrlWrd = FreqChgCtrlWrd3; + TechPtr->SetDramMode = MemTSetDramMode3; + TechPtr->DimmPresence = MemTDIMMPresence3; + TechPtr->SpdCalcWidth = MemTSPDCalcWidth3; + TechPtr->SpdGetTargetSpeed = MemTSPDGetTargetSpeed3; + TechPtr->AutoCycTiming = MemTAutoCycTiming3; + TechPtr->SpdSetBanks = MemTSPDSetBanks3; + TechPtr->SetDqsEccTmgs = MemTSetDQSEccTmgs; + TechPtr->GetCSIntLvAddr = MemTGetCSIntLvAddr3; + TechPtr->AdjustTwrwr = MemTAdjustTwrwr3; + TechPtr->AdjustTwrrd = MemTAdjustTwrrd3; + TechPtr->GetDimmSpdBuffer = MemTGetDimmSpdBuffer3; + TechPtr->GetLD = MemTGetLD3; + TechPtr->MaxFilterDly = 0; + + // + // Map the Logical Dimms on this channel to the SPD that should be used for that logical DIMM. + // The pointers to the DIMM SPD information is as follows (2 Dimm/Ch and 3 Dimm/Ch examples). + // + // DIMM Spd Buffer Current Channel DimmSpdPtr[MAX_DIMMS_PER_CHANNEL] array + // (Number of dimms varies by platform) (Array size is determined in AGESA.H) Dimm operations loop + // on this array only) + // 2 DIMMS PER CHANNEL + // + // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0] + // Dimm 1 SR/DR DIMM <--------------DimmSpdPtr[1] + // DimmSpdPtr[2]------->NULL + // DimmSpdPtr[3]------->NULL + // + // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0] + // Dimm 1 QR DIMM <---------+----DimmSpdPtr[1] + // | DimmSpdPtr[2]------->NULL + // +----DimmSpdPtr[3] + // + // Socket N Channel N Dimm 0 QR DIMM <-----+--------DimmSpdPtr[0] + // Dimm 1 QR DIMM <-----|---+----DimmSpdPtr[1] + // +-- | ---DimmSpdPtr[2] + // +----DimmSpdPtr[3] + // + // 3 DIMMS PER CHANNEL + // + // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0] + // Dimm 1 SR/DR DIMM <--------------DimmSpdPtr[1] + // Dimm 3 SR/DR DIMM <--------------DimmSpdPtr[2] + // DimmSpdPtr[3]------->NULL + // + // Socket N Channel N Dimm 0 SR/DR DIMM <--------------DimmSpdPtr[0] + // Dimm 1 QR DIMM <---------+----DimmSpdPtr[1] + // Dimm 3 SR/DR DIMM <-------- | ---DimmSpdPtr[2] + // +----DimmSpdPtr[3] + // + // + // FOR LRDIMMS + // + // This code will assign SPD pointers on the basis of Physical ranks, even though + // an LRDIMM may only use one or two logical ranks, that determination will have to + // be made from downstream code. An LRDIMM with greater than 2 Physical ranks will have + // its DimmSpdPtr[] mapped as if it were a QR in the above diagrams. + + 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->TechType = DDR3_TECHNOLOGY; + ChannelPtr->MCTPtr = MCTPtr; + ChannelPtr->DCTPtr = DCTPtr; + + DimmSlots = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, + MCTPtr->SocketId, + NBPtr->GetSocketRelativeChannel (NBPtr, Dct, Channel) + ); + // + // Initialize the SPD pointers for each Dimm + // + for (i = 0 ; i < (sizeof (ChannelPtr->DimmSpdPtr) / sizeof (ChannelPtr->DimmSpdPtr[0])) ; i++) { + ChannelPtr->DimmSpdPtr[i] = NULL; + } + for (i = 0 ; i < DimmSlots; i++) { + ChannelPtr->DimmSpdPtr[i] = &(ChannelPtr->SpdPtr[i]); + if ( (i + 2) < (sizeof (ChannelPtr->DimmSpdPtr) / sizeof (ChannelPtr->DimmSpdPtr[0]))) { + if (ChannelPtr->DimmSpdPtr[i]->DimmPresent) { + if ((((ChannelPtr->DimmSpdPtr[i]->Data[SPD_RANKS] >> 3) & 0x07) + 1) > 2) { + ChannelPtr->DimmSpdPtr[i + 2] = &(ChannelPtr->SpdPtr[i]); + } + } + } + } + } + } + // Initialize Common technology functions + MemTCommonTechInit (TechPtr); + + return TRUE; +} + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.h new file mode 100644 index 0000000000..6769da03ab --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mt3.h @@ -0,0 +1,136 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mt3.h + * + * Common Technology + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 34897 $ @e \$Date: 2010-07-14 10:07:10 +0800 (Wed, 14 Jul 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. + * + * *************************************************************************** + * + */ + +#ifndef _MT3_H_ +#define _MT3_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +BOOLEAN +MemConstructTechBlock3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT MEM_NB_BLOCK *NBPtr + ); +BOOLEAN +MemTSetDramMode3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +BOOLEAN +MemTDIMMPresence3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +BOOLEAN +MemTSPDCalcWidth3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +BOOLEAN +MemTSPDGetTargetSpeed3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +BOOLEAN +MemTAutoCycTiming3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +BOOLEAN +MemTSPDSetBanks3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +VOID +MemTGetCSIntLvAddr3 ( + IN UINT8 BankEnc, + OUT UINT8 *LowBit, + OUT UINT8 *HiBit + ); + +VOID +MemTSendAllMRCmds3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 ChipSel + ); + +VOID +FreqChgCtrlWrd3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + + +BOOLEAN +MemTGetDimmSpdBuffer3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT UINT8 **SpdBuffer, + IN UINT8 Dimm + ); +#endif /* _MT3_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.c new file mode 100644 index 0000000000..4775def8a2 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.c @@ -0,0 +1,1102 @@ +/** + * @file + * + * mtlrdimm3.c + * + * Technology initialization and control workd support for DDR3 LRDIMMS + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 23714 $ @e \$Date: 2009-12-09 17:28:37 -0600 (Wed, 09 Dec 2009) $ + * + **/ +/* + ***************************************************************************** + * + * 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 "mu.h" +#include "mt.h" +#include "mt3.h" +#include "mtspd3.h" +#include "mtrci3.h" +#include "mtsdi3.h" +#include "mtlrdimm3.h" +#include "merrhdl.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) +#define FILECODE PROC_MEM_TECH_DDR3_MTLRDIMM3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +VOID +STATIC +MemTSendMBCtlWord3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Fn, + IN UINT8 Rcw, + IN UINT8 Value + ); + +UINT8 +STATIC +MemTGetSpecialMBCtlWord3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm, + IN UINT8 Fn, + IN UINT8 Rc + ); + +BOOLEAN +STATIC +MemTLrDimmControlRegInit3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ); + +BOOLEAN +STATIC +MemTLrDimmFreqChgCtrlWrd3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ); + +BOOLEAN +STATIC +MemTWLPrepareLrdimm3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *Wl + ); + +BOOLEAN +STATIC +MemTSendAllMRCmdsLR3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *CsPtr + ); + +VOID +STATIC +MemTEMRS1Lr3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 ChipSel, + IN UINT8 PhyRank + ); + +VOID +STATIC +MemTEMRS2Lr3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 ChipSel + ); + + +BOOLEAN +STATIC +MemTLrdimmRankMultiplication ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *DimmID + ); + +BOOLEAN +STATIC +MemTLrdimmBuf2DramTrain3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ); + +BOOLEAN +STATIC +MemTLrdimmSyncTrainedDlys ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ); + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function initializes LRDIMM functions. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +BOOLEAN +MemTLrdimmConstructor3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] = MemTSendAllMRCmdsLR3; + TechPtr->TechnologySpecificHook[LrdimmControlRegInit] = MemTLrDimmControlRegInit3; + TechPtr->TechnologySpecificHook[LrdimmFreqChgCtrlWrd] = MemTLrDimmFreqChgCtrlWrd3; + TechPtr->TechnologySpecificHook[WlTrainingPrepareLrdimm] = MemTWLPrepareLrdimm3; + TechPtr->TechnologySpecificHook[LrdimmRankMultiplication] = MemTLrdimmRankMultiplication; + TechPtr->TechnologySpecificHook[LrdimmBuf2DramTrain] = MemTLrdimmBuf2DramTrain3; + TechPtr->TechnologySpecificHook[LrdimmSyncTrainedDlys] = MemTLrdimmSyncTrainedDlys; + return TRUE; +} + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function sends a Control word command to an LRDIMM Memory Buffer + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Fn - control word function + * @param[in] Rcw - control word number + * @param[in] Value - value to send + * + */ + +VOID +STATIC +MemTSendMBCtlWord3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Fn, + IN UINT8 Rcw, + IN UINT8 Value + ) +{ + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + ASSERT (Rcw != RCW_FN_SELECT); // RC7 can only be used for function select + IDS_HDT_CONSOLE (MEM_FLOW, "\t\tF%dRC%d = %x\n", Fn, Rcw, Value); + // + // Select the MB Function by sending the Fn number + // to the Function Select Control Word + // + MemUWait10ns (800, NBPtr->MemPtr); + MemTSendCtlWord3 (TechPtr, RCW_FN_SELECT, Fn); + // + // Send the value to the control word + // + MemUWait10ns (800, NBPtr->MemPtr); + MemTSendCtlWord3 (TechPtr, Rcw, Value); + + +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function gets the value of special RCW + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Dimm - Physical LR DIMM number + * @param[in] Fn - control word function + * @param[in] Rc - control word number + * + * @return Special RCW value + * + */ + +UINT8 +STATIC +MemTGetSpecialMBCtlWord3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm, + IN UINT8 Fn, + IN UINT8 Rc + ) +{ + CONST UINT8 F0RC13PhyRankTab[] = {3, 2, 0, 1, 0}; + UINT8 PhyRanks; + UINT8 LogRanks; + UINT8 DramCap; + UINT8 Value8; + UINT8 *SpdBufferPtr; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm); + + Value8 = 0; + switch (Fn) { + case 0: + switch (Rc) { + case 8: + // F0RC8 + Value8 = NBPtr->PsPtr->F0RC8; + break; + case 10: + // F0RC10 + // 2:0 OperatingSpeed: operating speed. BIOS: Table 88. + if (NBPtr->DCTPtr->Timings.Speed == DDR667_FREQUENCY) { + Value8 = 0; + } else { + Value8 = (UINT8) (NBPtr->DCTPtr->Timings.Speed / 133) - 3; + } + break; + case 11: + // F0RC11 + // 3:2 ParityCalculation: partiy calculation. BIOS: Table. + // 1:0 OperatingVoltage: operating voltage. BIOS: IF(VDDIO == 1.5) THEN 00b ELSEIF (VDDIO == + // 1.35) THEN 01b ELSE 10b ENDIF. + DramCap = SpdBufferPtr[SPD_DENSITY] & 0xF; + if ((NBPtr->ChannelPtr->LrDimmRankMult[Dimm] + DramCap * 2) > 8) { + Value8 = 8; + } else { + Value8 = 4; + } + Value8 |= NBPtr->RefPtr->DDR3Voltage; + break; + case 13: + // F0RC13 + // 3:2 NumLogicalRanks: partiy calculation. BIOS: Table 90. + // 1:0 NumPhysicalRanks: operating voltage. BIOS: Table 89. + LogRanks = NBPtr->ChannelPtr->LrDimmLogicalRanks[Dimm] >> 1; + PhyRanks = F0RC13PhyRankTab[(SpdBufferPtr[SPD_RANKS] >> 3) & 7]; + Value8 = (LogRanks << 2) | PhyRanks; + break; + case 14: + // F0RC14 + // 3 DramBusWidth: DRAM bus width. BIOS: IF (DeviceWidth==0) THEN 0 ELSE 1 ENDIF. + // 2 MRSCommandControl: MRS command control. BIOS: IF (F0RC15[RankMultiplicationControl] + // > 0) THEN 1 ELSE 0 ENDIF. + // 1 RefreshPrechargeCommandControl: refresh and precharge command control. BIOS: IF + // (F0RC15[RankMultiplicationControl] > 0) THEN D18F2xA8_dct[1:0][LrDimmEnhRefEn] ELSE 0 ENDIF. + // 0 AddressMirror: address mirror. BIOS: RankMap. See D18F2x[5C:40]_dct[1:0][OnDimmMirror]. + if ((SpdBufferPtr[SPD_DEV_WIDTH] & 7) != 0) { + Value8 |= 8; + } + if (NBPtr->ChannelPtr->LrDimmRankMult[Dimm] > 1) { + Value8 |= 4; + if (NBPtr->GetBitField (NBPtr, BFLrDimmEnhRefEn) == 1) { + Value8 |= 2; + } + } + if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) { + Value8 |= 1; + } + break; + case 15: + // F0RC15 + // 3:0 RankMultiplicationControl: rank multiplication control. BIOS: Table 91. + DramCap = SpdBufferPtr[SPD_DENSITY] & 0xF; + ASSERT ((DramCap >= 2) && (DramCap <= 4)); // BKDG only lists 1Gb, 2Gb, and 4Gb + switch (NBPtr->ChannelPtr->LrDimmRankMult[Dimm]) { + case 1: + Value8 = 0; + break; + case 2: + Value8 = DramCap - 1; + break; + case 4: + Value8 = DramCap + 3; + break; + default: + ASSERT (FALSE); + } + break; + default: + ASSERT (FALSE); + } + break; + case 1: + switch (Rc) { + case 0: + // F1RC0 + Value8 = NBPtr->PsPtr->F1RC0; + Value8 |= (UINT8) NBPtr->GetBitField (NBPtr, BFCSTimingMux67) << 3; + break; + case 1: + // F1RC1 + Value8 = NBPtr->PsPtr->F1RC1; + break; + case 2: + // F1RC2 + Value8 = NBPtr->PsPtr->F1RC2; + break; + case 9: + // F1RC9 + if (NBPtr->GetBitField (NBPtr, BFLrDimmEnhRefEn) == 0) { + Value8 = 1; + } + break; + default: + ASSERT (FALSE); + } + break; + case 3: + switch (Rc) { + case 0: + // F3RC0 + // 3 TDQSControl: TDQS control. BIOS: 0. + // 2:0 RttNom: RttNom. BIOS: Table 57, Table 60 + Value8 = NBPtr->PsPtr->RttNom[Dimm << 1]; + break; + case 1: + // F3RC1 + // 3 Vref: Vref. BIOS: 0. + // 2:0 RttWr: RttWr. BIOS: Table 57, Table 60. + Value8 = NBPtr->PsPtr->RttWr[Dimm << 1]; + break; + default: + ASSERT (FALSE); + } + break; + default: + ASSERT (FALSE); + } + + return Value8; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function sends LRDIMM Control Words to all LRDIMMS + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return TRUE + */ + +BOOLEAN +STATIC +MemTLrDimmControlRegInit3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ) +{ + CONST UINT8 RCWInitTable[] = { + // RCW, Mask, SPD + F0, RC0, 0x00, SPD_NONE, + F0, RC1, 0x00, SPD_NONE, + F0, RC2, 0x03, SPD_67, + F0, RC10, 0x00, SPECIAL_CASE, + F0, RC11, 0x00, SPECIAL_CASE, + + F1, RC8, 0x0F, SPD_69, + F1, RC11, 0xF0, SPD_69, + F1, RC12, 0x0F, SPD_70, + F1, RC13, 0xF0, SPD_70, + F1, RC14, 0x0F, SPD_71, + F1, RC15, 0xF0, SPD_71, + + WAIT_6US, 0, 0, 0, + + F0, RC3, 0xF0, SPD_67, + F0, RC4, 0x0F, SPD_68, + F0, RC5, 0xF0, SPD_68, + + F0, RC6, 0x00, SPD_NONE, + F0, RC8, 0x00, SPECIAL_CASE, + F0, RC9, 0x0C, SPD_NONE, + F0, RC13, 0x00, SPECIAL_CASE, + F0, RC14, 0x00, SPECIAL_CASE, + F0, RC15, 0x00, SPECIAL_CASE, + + F1, RC0, 0x00, SPECIAL_CASE, + F1, RC1, 0x00, SPECIAL_CASE, + F1, RC2, 0x00, SPECIAL_CASE, + F1, RC3, 0x00, SPD_NONE, + F1, RC9, 0x00, SPECIAL_CASE, + F1, RC10, 0x00, SPD_NONE, + + F2, RC0, 0x00, SPD_NONE, + F2, RC1, 0x00, SPD_NONE, + F2, RC2, 0x0F, SPD_NONE, + F2, RC3, 0x00, SPD_NONE, + + F3, RC0, 0x00, SPECIAL_CASE, + F3, RC1, 0x00, SPECIAL_CASE, + F3, RC2, 0x01, SPD_NONE, + F3, RC6, 0x08, SPD_NONE + + // F3 RC[8,9] are programmed in MDQ RC loop + + // F[10:3] RC[11,10] are programmed in QxODT RC loop + + // F[15,14] RC[15:0] are programmed in personality RC loop + }; + + UINT8 Dimm; + UINT16 i; + UINT16 DimmMask; + UINT8 Fn; + UINT8 Rc; + UINT8 Mask; + UINT8 Spd; + UINT8 *SpdBufferPtr; + UINT8 FreqDiffOffset; + UINT8 Value8; + MEM_DATA_STRUCT *MemPtr; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + MemPtr = NBPtr->MemPtr; + + if (NBPtr->MCTPtr->Status[SbLrdimms]) { + for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) { + DimmMask = (UINT16)1 << Dimm; + if ((NBPtr->ChannelPtr->LrDimmPresent & DimmMask) != 0) { + IDS_HDT_CONSOLE (MEM_FLOW, "\t\tSending LRDIMM Control Words: Dimm %02x\n", Dimm); + // + // Select the Target Chipselects + // + NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1)); + NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1)); + + MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm); + for (i = 0; i < sizeof (RCWInitTable) ; i += 4) { + Fn = RCWInitTable[i]; + Rc = RCWInitTable[i + 1]; + Mask = RCWInitTable[i + 2]; + Spd = RCWInitTable[i + 3]; + + if (Fn == WAIT_6US) { + MemUWait10ns (600, MemPtr); // wait 6us for TSTAB + } else { + if (Spd == SPD_NONE) { + Value8 = Mask; + } else if (Spd == SPECIAL_CASE) { + Value8 = MemTGetSpecialMBCtlWord3 (TechPtr, Dimm, Fn, Rc); + } else { + Value8 = (Mask > 0x0F) ? ((SpdBufferPtr[Spd] & Mask) >> 4) : (SpdBufferPtr[Spd] & Mask); + } + MemTSendMBCtlWord3 (TechPtr, Fn, Rc, Value8); + } + } + + FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2)); + // + // Send RCW to program MDQ termination and drive strength + // + for (Rc = 8; Rc <= 9; Rc++) { + Value8 = SpdBufferPtr[SPD_MDQ_800_1066 + FreqDiffOffset]; + Value8 = (Rc == 9) ? (Value8 >> 4) : Value8; + MemTSendMBCtlWord3 (TechPtr, 3, Rc, Value8 & 0x07); + } + + // + // Send RCW to program QxODT + // + for (Fn = 3; Fn <= 10; Fn ++) { + for (Rc = 10; Rc <= 11; Rc++) { + Value8 = SpdBufferPtr[SPD_QXODT_800_1066 + FreqDiffOffset + ((Fn - 3) >> 1)]; + Value8 = (Rc == 11) ? (Value8 >> 4) : (Value8 & 0x0F); + Value8 = ((Fn & 1) == 0) ? (Value8 >> 2) : (Value8 & 0x03); + MemTSendMBCtlWord3 (TechPtr, Fn, Rc, Value8); + } + } + + // + // Send Personality bytes from SPD + // + for (Fn = 14; Fn < 16; Fn ++) { + for (Rc = 0; Rc < 16 ; Rc++) { + Value8 = SpdBufferPtr[SPD_PERSONALITY_BYTE + ((Fn - 14) << 3) + (Rc >> 1)]; + if ((Fn == 14) && (Rc == 0)) { + Value8 |= 0x01; // Write global enable + } + if (Rc != 0x07) { + MemTSendMBCtlWord3 (TechPtr, Fn, Rc, ((Rc & 1) != 0) ? (Value8 >> 4) : (Value8 & 0x0F)); + } + } + } + } + } + } + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function sends LRDIMM Control Words to all LRDIMMS + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return FALSE - The current channel does not have LRDIMM populated + * TRUE - The current channel has LRDIMM populated + */ + +BOOLEAN +STATIC +MemTLrDimmFreqChgCtrlWrd3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ) +{ + UINT8 Dct; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + if (NBPtr->MCTPtr->Status[SbLrdimms]) { + for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { + MemNSwitchDCTNb (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + MemTLrDimmControlRegInit3 (TechPtr, NULL); + } + } + return TRUE; + } + return FALSE; +} + +/*----------------------------------------------------------------------------- + * + * + * This function prepares LRDIMMs for WL training. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in,out] *Wl - Indicates if WL mode should be enabled + * + * @return TRUE - LRDIMMs present + * ---------------------------------------------------------------------------- + */ +BOOLEAN +STATIC +MemTWLPrepareLrdimm3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *Wl + ) +{ + UINT8 Dimm; + UINT8 Value8; + UINT16 MrsAddress; + MEM_NB_BLOCK *NBPtr; + NBPtr = TechPtr->NBPtr; + MrsAddress = 0; + if (NBPtr->MCTPtr->Status[SbLrdimms]) { + for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) { + if (*(BOOLEAN *) Wl == TRUE) { + // Program WrLvOdt + NBPtr->SetBitField (NBPtr, BFWrLvOdt, NBPtr->ChannelPtr->PhyWLODT[Dimm]); + } + if ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << Dimm)) != 0) { + if (Dimm == TechPtr->TargetDIMM) { + if (*(BOOLEAN *) Wl == TRUE) { + // + // Select the Target Chipselects + // + NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1)); + NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1)); + + // Program F0RC12 to 1h + MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0x01); + if (NBPtr->ChannelPtr->Dimms >= 2) { + // For two or more LRDIMMs per channel program the buffer RttNom to the + // corresponding specifed RttWr termination + Value8 = NBPtr->MemNGetDynDramTerm (NBPtr, Dimm << 2); + } else { + // Program RttNom as normal + Value8 = NBPtr->MemNGetDramTerm (NBPtr, Dimm << 2); + } + if ((Value8 & ((UINT8) 1 << 2)) != 0) { + MrsAddress |= ((UINT16) 1 << 9); + } + if ((Value8 & ((UINT8) 1 << 1)) != 0) { + MrsAddress |= ((UINT16) 1 << 6); + } + if ((Value8 & ((UINT8) 1 << 0)) != 0) { + MrsAddress |= ((UINT16) 1 << 2); + } + NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress); + } else { + // Program F0RC12 to 0h + MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0x00); + } + } + } + } + return TRUE; + } else { + return FALSE; + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This send all MR commands to all physical ranks of an LRDIMM + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] *CsPtr - Target Chip Select + * + * @return FALSE - The current channel does not have LRDIMM populated + * TRUE - The current channel has LRDIMM populated + */ + +BOOLEAN +STATIC +MemTSendAllMRCmdsLR3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *CsPtr + ) +{ + UINT8 *SpdBufferPtr; + BOOLEAN Skip; + UINT8 Rank; + UINT8 PhyRank; + UINT8 ChipSel; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + ChipSel = *((UINT8 *) CsPtr); + + if (NBPtr->MCTPtr->Status[SbLrdimms]) { + // + // LRDIMM: MR0, MR2, and MR3 can be broadcasted. + // MR1[Rtt_Nom] needs to be programmed differently per physical ranks. + // + // CS 0 1 2 3 4 5 6 7 + // MR[0,2,3] x x ? + // MR1 x x x x x x x x + // + // ? If 3 DIMMs/ch, need to send to CS4 since it is on the 3rd physical DIMM. + // + Skip = TRUE; + switch (ChipSel) { + case 0: + case 2: + Skip = FALSE; + break; + case 4: + if (GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, + NBPtr->MCTPtr->SocketId, + NBPtr->ChannelPtr->ChannelID) == 3) { + Skip = FALSE; + } + break; + } + + // Select target chip select + NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel); + + if (!Skip) { + // 13.Send EMRS(2) + MemTEMRS2Lr3 (TechPtr, ChipSel); + NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast + NBPtr->SendMrsCmd (NBPtr); + + // 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b + MemTEMRS33 (TechPtr); + NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast + NBPtr->SendMrsCmd (NBPtr); + } + + // 15.Send EMRS(1). Send to each physical rank. + MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1); + for (Rank = 0; Rank < NBPtr->ChannelPtr->LrDimmRankMult[ChipSel >> 1]; Rank++) { + PhyRank = (((ChipSel >> 1) & 2) | (ChipSel & 1)) + (Rank * NBPtr->ChannelPtr->LrDimmLogicalRanks[ChipSel >> 1]); + MemTEMRS1Lr3 (TechPtr, ChipSel, PhyRank); + // Set Address bit 14, 15, 16, or 17 to select physical rank according to the device size + NBPtr->SetBitField (NBPtr, BFMrsAddressHi, Rank << (SpdBufferPtr[SPD_DENSITY] & 0xF)); + NBPtr->SendMrsCmd (NBPtr); + } + + if (!Skip) { + // 16.Send MRS with MrsAddress[8]=1(reset the DLL) + MemTMRS3 (TechPtr); + NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast + NBPtr->SendMrsCmd (NBPtr); + } + + // If LRDIMM, return TRUE to skip sending regular MR commands. + return TRUE; + } + // If not LRDIMM, send regular MR commands. + return FALSE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function calculates the EMRS1 value for an LRDIMM + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] ChipSel - Chip select number + * @param[in] PhyRank - Physical rank number + */ + +VOID +STATIC +MemTEMRS1Lr3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 ChipSel, + IN UINT8 PhyRank + ) +{ + UINT16 MrsAddress; + UINT8 Value8; + UINT8 *SpdBufferPtr; + UINT8 FreqDiffOffset; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1); + FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2)); + + // BA2=0,BA1=0,BA0=1 + NBPtr->SetBitField (NBPtr, BFMrsBank, 1); + + MrsAddress = 0; + + // program MrsAddress[5,1]=output driver impedance control (DIC): 01b + MrsAddress |= ((UINT16) 1 << 1); + + // program MrsAddress[5,1]=output driver impedance control (DIC): + // DIC is read from SPD byte 77, 83, or 89 depending on DDR speed + Value8 = SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] & 3; + if ((Value8 & ((UINT8) 1 << 1)) != 0) { + MrsAddress |= ((UINT16) 1 << 5); + } + if ((Value8 & ((UINT8) 1 << 0)) != 0) { + MrsAddress |= ((UINT16) 1 << 1); + } + + // program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT): + // RttNom is read from SPD byte 77, 83, or 89 depending on DDR speed + if (PhyRank <= 1) { + Value8 = (SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] >> 2) & 7; + if ((Value8 & ((UINT8) 1 << 2)) != 0) { + MrsAddress |= ((UINT16) 1 << 9); + } + if ((Value8 & ((UINT8) 1 << 1)) != 0) { + MrsAddress |= ((UINT16) 1 << 6); + } + if ((Value8 & ((UINT8) 1 << 0)) != 0) { + MrsAddress |= ((UINT16) 1 << 2); + } + } + + NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function calculates the EMRS2 value for an LRDIMM + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] ChipSel - Chip select number + */ + +VOID +STATIC +MemTEMRS2Lr3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 ChipSel + ) +{ + UINT8 RttWr; + UINT8 *SpdBufferPtr; + UINT8 FreqDiffOffset; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + // Save default RttWr + RttWr = NBPtr->PsPtr->RttWr[ChipSel]; + + // Override RttWr with the value read from SPD byte 77, 83, or 89 depending on DDR speed + MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1); + FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2)); + NBPtr->PsPtr->RttWr[ChipSel] = SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] >> 6; + + // Call EMRS2 calculation + MemTEMRS23 (TechPtr); + + // Restore RttWr + NBPtr->PsPtr->RttWr[ChipSel] = RttWr; +} + +/*----------------------------------------------------------------------------- + * + * + * This function to determine the Rank Multiplication to use for an LRDIMM + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in,out] *DimmID - Dimm ID + * + * @return TRUE - LRDIMM Support is installed and LRDIMMs are present + * ---------------------------------------------------------------------------- + */ +BOOLEAN +STATIC +MemTLrdimmRankMultiplication ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *DimmID + ) +{ + BOOLEAN RetVal; + UINT8 *SpdBufferPtr; + UINT8 Dimm; + UINT8 NumDimmslots; + UINT8 DramCapacity; + UINT8 Ranks; + UINT8 Rows; + UINT8 RankMult; + MEM_NB_BLOCK *NBPtr; + CH_DEF_STRUCT *ChannelPtr; + + ASSERT (TechPtr != NULL); + ASSERT (DimmID != NULL); + + Dimm = *(UINT8*)DimmID; + ASSERT (Dimm < MAX_DIMMS_PER_CHANNEL); + + NBPtr = TechPtr->NBPtr; + ChannelPtr = NBPtr->ChannelPtr; + RetVal = FALSE; + RankMult = 0; + + if (!MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm)) { + ASSERT (FALSE); + } + + NumDimmslots = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, + NBPtr->MCTPtr->SocketId, + ChannelPtr->ChannelID); + + if (NBPtr->MCTPtr->Status[SbLrdimms]) { + RetVal = TRUE; + // + // Determine LRDIMM Rank Multiplication + // + Ranks = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1; + if (Ranks == 5) { + Ranks = 8; + } + DramCapacity = (SpdBufferPtr[SPD_DENSITY] & 0x0F); + Rows = 12 + (SpdBufferPtr[SPD_ROW_SZ] >> 3) & 0x7; + + if (Ranks < 4) { + RankMult = 1; + } else if (Ranks == 4) { + RankMult = (NumDimmslots < 3) ? 1 : 2; + } else if (Ranks == 8) { + RankMult = ((NumDimmslots < 3) && (DramCapacity < 4)) ? 2 : 4; + } + // + // Save Rank Information + // + ChannelPtr->LrDimmRankMult[Dimm] = RankMult; + ChannelPtr->LrDimmLogicalRanks[Dimm] = Ranks / RankMult; + NBPtr->PsPtr->LrdimmRowAddrBits[Dimm] = Rows + (RankMult >> 1); + // + // Program RankDef + // + NBPtr->SetBitField (NBPtr, BFRankDef0 + Dimm, (RankMult == 4) ? 3 : RankMult); + // + // If LrdimmRowAddressBits > 16, then we must be useing some CS signals for rank + // multiplication. If this is the case, then we want to clear the CSPresent bits + // that correspond to those chipselects. + // If there are 3 DIMMs per channel, then it will always be CS67, if there are + // 2DPCH, then DIMM0 will use CS45, adn DIMM1 will use CS67. + // + if (NBPtr->PsPtr->LrdimmRowAddrBits[Dimm] > 16) { + NBPtr->DCTPtr->Timings.CsPresent &= ~(0x30 << ((NumDimmslots > 2) ? 1 : Dimm) ); + } + } + + return RetVal; + +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function performs buffer to DRAM training for LRDIMMs + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return TRUE + */ + +BOOLEAN +STATIC +MemTLrdimmBuf2DramTrain3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ) +{ + UINT8 Dct; + UINT8 Dimm; + UINT8 ChipSel; + UINT16 DimmMask; + UINT8 i; + MEM_DATA_STRUCT *MemPtr; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + MemPtr = NBPtr->MemPtr; + + if (NBPtr->MCTPtr->Status[SbLrdimms]) { + IDS_HDT_CONSOLE (MEM_FLOW, "\nStart Buffer to DRAM training\n"); + + for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { + IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); + NBPtr->SwitchDCT (NBPtr, Dct); + + // + // ODM needs to be set after Dram Init + // + if (NBPtr->StartupSpeed == NBPtr->DCTPtr->Timings.Speed) { + for (ChipSel = 1; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) { + if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) { + if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) { + NBPtr->SetBitField (NBPtr, BFCSBaseAddr0Reg + ChipSel, ((NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + ChipSel)) | ((UINT32)1 << BFOnDimmMirror ))); + } + } + } + } + + // + // Buffer to DRAM training + // + for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) { + DimmMask = (UINT16)1 << Dimm; + if ((NBPtr->ChannelPtr->LrDimmPresent & DimmMask) != 0) { + IDS_HDT_CONSOLE (MEM_STATUS, "\t\nDimm %d\n", Dimm); + // Select the Target Chipselects + NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1)); + NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1)); + + // Send F0RC12 with data = 0010b. + MemTSendMBCtlWord3 (TechPtr, F0, RC12, 2); + + // Wait until D18F2xA0_dct[1:0][RcvParErr]=0 or tCAL * the number of physical ranks expires. + IDS_HDT_CONSOLE (MEM_FLOW, "\t\tWaiting %d ms...\n", 10 * NBPtr->ChannelPtr->LrDimmRankMult[Dimm]); + for (i = 0; i < (NBPtr->ChannelPtr->LrdimmPhysicalRanks[Dimm] * 10); i++) { + MemUWait10ns (1000000, MemPtr); + } + + // Configure for normal operation: Send F0RC12 with data = 0000b. + MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0); + } + } + } + IDS_HDT_CONSOLE (MEM_FLOW, "\nEnd Buffer to DRAM training\n"); + } + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function copies trained delays of the first rank of a QR LRDIMM to the third rank + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in,out] OptParam - Optional parameter + * + * @return TRUE + */ + +BOOLEAN +STATIC +MemTLrdimmSyncTrainedDlys ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN OUT VOID *OptParam + ) +{ + UINT8 i; + UINT8 Dimm; + MEM_NB_BLOCK *NBPtr; + CH_DEF_STRUCT *ChannelPtr; + + NBPtr = TechPtr->NBPtr; + ChannelPtr = NBPtr->ChannelPtr; + + if (NBPtr->MCTPtr->Status[SbLrdimms]) { + for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) { + for (i = 0; i < TechPtr->DlyTableWidth (); i++) { + if (ChannelPtr->LrDimmLogicalRanks[Dimm] > 2) { + // If logical QR LRDIMM, copy trained delays from first rank to third rank + NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i), + ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + i]); + NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Dimm + 2, i), + ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + i]); + NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i), + ChannelPtr->RdDqsDlys[Dimm * TechPtr->DlyTableWidth () + i]); + NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i), + ChannelPtr->WrDatDlys[Dimm * TechPtr->DlyTableWidth () + i]); + } + } + } + return TRUE; + } else { + return FALSE; + } +} + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.h new file mode 100644 index 0000000000..ebbec4782a --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtlrdimm3.h @@ -0,0 +1,127 @@ +/** + * @file + * + * mtlrdimm3.h + * + * Definitions and declarations for DDR3 LRDIMM support + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem) + * @e \$Revision: 27045 $ @e \$Date: 2010-02-22 17:21:31 -0600 (Mon, 22 Feb 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. + * + * *************************************************************************** + * + */ + +#ifndef _MTLRDIMM3_H_ +#define _MTLRDIMM3_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ +#define RCW_FN_SELECT 7 + +#define F0 0 +#define F1 1 +#define F2 2 +#define F3 3 +#define F4 4 +#define F5 5 +#define F6 6 +#define F7 7 +#define F8 8 +#define F9 9 +#define F10 10 +#define F11 11 +#define F12 12 +#define F13 13 +#define F14 14 +#define F15 15 + +#define RC0 0 +#define RC1 1 +#define RC2 2 +#define RC3 3 +#define RC4 4 +#define RC5 5 +#define RC6 6 +#define RC7 7 +#define RC8 8 +#define RC9 9 +#define RC10 10 +#define RC11 11 +#define RC12 12 +#define RC13 13 +#define RC14 14 +#define RC15 15 + +#define SPD_NONE 0 +#define SPD_67 67 +#define SPD_68 68 +#define SPD_69 69 +#define SPD_70 70 +#define SPD_71 71 + +#define SPD_MDQ_800_1066 72 +#define SPD_QXODT_800_1066 73 +#define SPD_MR1_MR2_800_1066 77 +#define SPD_PERSONALITY_BYTE 150 + +#define SPD_FREQ_DIFF_OFFSET 6 + +#define SPECIAL_CASE 0xFF + +#define WAIT_6US 0xF6 + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +#endif /* _MTLRDIMM3_H_ */ diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.c new file mode 100644 index 0000000000..2163ccf919 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.c @@ -0,0 +1,170 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mtot3.c + * + * Technology Non-SPD Timings for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 38442 $ @e \$Date: 2010-09-24 06:39:57 +0800 (Fri, 24 Sep 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 "Ids.h" +#include "mm.h" +#include "mn.h" +#include "mu.h" +#include "mt.h" +#include "mtot3.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) + +#define FILECODE PROC_MEM_TECH_DDR3_MTOT3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function adjusts the Twrwr value for DDR3. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +MemTAdjustTwrwr3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + DCT_STRUCT *DCTPtr; + + DCTPtr = TechPtr->NBPtr->DCTPtr; + + // For DDR3, value 0000b-0001b and >= 1011b of Twrwr is reserved. + if (DCTPtr->Timings.Twrwr < 2) { + DCTPtr->Timings.Twrwr = 2; + } else if (DCTPtr->Timings.Twrwr > 10) { + DCTPtr->Timings.Twrwr = 10; + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function adjusts the Twrrd value for DDR3. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +MemTAdjustTwrrd3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + DCT_STRUCT *DCTPtr; + + DCTPtr = TechPtr->NBPtr->DCTPtr; + + // For DDR3, value 0000b, 0001b, and > 1010b of Twrrd is reserved. + if (DCTPtr->Timings.Twrrd < 2) { + DCTPtr->Timings.Twrrd = 2; + } else if (DCTPtr->Timings.Twrrd > 10) { + DCTPtr->Timings.Twrrd = 10; + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function gets the LD value for DDR3. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + * @return Value of LD + */ + +INT8 +MemTGetLD3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + INT8 LD; + MEM_NB_BLOCK *NBPtr; + NBPtr = TechPtr->NBPtr; + // + // For DDR3, BIOS calculates the latency difference (Ld) as equal to read CAS latency minus write CAS + // latency, in MEMCLKs (see F2x[1, 0]88[Tcl] and F2x[1, 0]84[Tcwl]) which can be a negative or positive + // value. + // + LD = ((INT8) NBPtr->GetBitField (NBPtr, BFTcl) + 4) - ((INT8) NBPtr->GetBitField (NBPtr, BFTcwl) + 5); + + return LD; +} diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.h new file mode 100644 index 0000000000..8cdb9be480 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtot3.h @@ -0,0 +1,92 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mtot3.h + * + * Technology Non-SPD timings for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 34897 $ @e \$Date: 2010-07-14 10:07:10 +0800 (Wed, 14 Jul 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. + * + * *************************************************************************** + * + */ + +#ifndef _MTOT3_H_ +#define _MTOT3_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + + +VOID +MemTAdjustTwrwr3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +VOID +MemTAdjustTwrrd3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +INT8 +MemTGetLD3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +#endif /* _MTOT3_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.c new file mode 100644 index 0000000000..106f501948 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.c @@ -0,0 +1,297 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mtrci3.c + * + * Technology Control word initialization for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 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 "Ids.h" +#include "mm.h" +#include "mn.h" +#include "mu.h" +#include "mt.h" +#include "mtrci3.h" +#include "merrhdl.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) + +#define FILECODE PROC_MEM_TECH_DDR3_MTRCI3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function sends control words + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +MemTDramControlRegInit3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + UINT8 ChipSel; + UINT8 i; + UINT8 RawCard; + UINT8 Data; + UINT16 CsPresent; + + MEM_DATA_STRUCT *MemPtr; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + MemPtr = NBPtr->MemPtr; + CsPresent = NBPtr->DCTPtr->Timings.CsPresent; + + MemUWait10ns (800, MemPtr); // wait 8us TACT must be changed to optimize to 8 MEM CLKs + + // Set EnDramInit to start DRAM initialization + + MemUWait10ns (600, MemPtr); // wait 6us for PLL LOCK + + for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) { + // + // If chip select present + // + if ((CsPresent & ((UINT16)3 << ChipSel)) != 0) { + NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel); + + // 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects. + NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (ChipSel & 0xFE)); + + RawCard = NBPtr->ChannelPtr->RefRawCard[ChipSel >> 1]; + + for (i = 0; i <= 15; i++) { + // wait 8us for TMRD, must be changed to optimize to 8 MEM CLKs + MemUWait10ns (800, MemPtr); + if ((i != 6) && (i != 7)) { + Data = MemTGetCtlWord3 (TechPtr, i, RawCard, ChipSel); + MemTSendCtlWord3 (TechPtr, i, Data); + } + } + } + } + MemUWait10ns (600, MemPtr); // wait 6us for TSTAB +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function calculates the ControlRC value + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] CtrlWordNum - control Word number. + * @param[in] RawCard - Raw Card + * @param[in] ChipSel - Target Chip Select + * @return Control Word value + */ + +UINT8 +MemTGetCtlWord3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 CtrlWordNum, + IN UINT8 RawCard, + IN UINT8 ChipSel + ) +{ + UINT8 Data; + DCT_STRUCT *DCTPtr; + CH_DEF_STRUCT *ChannelPtr; + + DCTPtr = TechPtr->NBPtr->DCTPtr; + ChannelPtr = TechPtr->NBPtr->ChannelPtr; + + Data = 0; //Default value for all control words is 0 + switch (CtrlWordNum) { + case 0: + Data = 0x02; // DA4=1 + break; + case 1: + if (DCTPtr->Timings.DimmSRPresent & ((UINT16) 1 << (ChipSel >> 1))) { + Data = 0x0C; // if single rank, set DBA1 and DBA0 + } + break; + case 2: + Data = ChannelPtr->CtrlWrd02[ChipSel >> 1]; + break; + case 3: + Data = ChannelPtr->CtrlWrd03[ChipSel >> 1]; + break; + case 4: + Data = ChannelPtr->CtrlWrd04[ChipSel >> 1]; + break; + case 5: + Data = ChannelPtr->CtrlWrd05[ChipSel >> 1]; + break; + case 8: + Data = ChannelPtr->CtrlWrd08[ChipSel >> 1]; + break; + case 9: + Data = 0x0D; + break; + default:; + } + + return (Data & 0x0F); +} +/* -----------------------------------------------------------------------------*/ +/** + * + * This function sends control word command + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] CmdNum - control number. + * @param[in] Value - value to send + * + */ + +VOID +MemTSendCtlWord3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 CmdNum, + IN UINT8 Value + ) +{ + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + // 1. Program MrsBank and MrsAddress. + // n = [BA2, A2, A1, A0]. + // data = [BA1, BA0, A4, A3]. + // Set all other bits in MrsAddress to zero. + // + NBPtr->SetBitField (NBPtr, BFMrsBank, ((CmdNum & 8) >> 1) | (Value >> 2)); + NBPtr->SetBitField (NBPtr, BFMrsAddress, ((Value & 3) << 3) | (CmdNum & 7)); + IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d RC%02d %04x\n", (MemNGetBitFieldNb (NBPtr, BFMrsChipSel) & 7), CmdNum, Value); + + // 2.Set SendCtrlWord=1 + NBPtr->SetBitField (NBPtr, BFSendCtrlWord, 1); + // 3.Wait for BFSendCtrlWord=0 + NBPtr->PollBitField (NBPtr, BFSendCtrlWord, 0, PCI_ACCESS_TIMEOUT, FALSE); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function sends specific control words commands before frequency change for certain DRAM buffers. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +FreqChgCtrlWrd3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + UINT8 ChipSel; + UINT16 Speed; + UINT16 CsPresent; + + MEM_DATA_STRUCT *MemPtr; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + MemPtr = NBPtr->MemPtr; + Speed = NBPtr->DCTPtr->Timings.Speed; + CsPresent = NBPtr->DCTPtr->Timings.CsPresent; + + + for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) { + // + // If chip select present. + // + if ((CsPresent & ((UINT16)3 << ChipSel)) != 0) { + + NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel); + // program F2x[1, 0]A8[CtrlWordCS]=bit mask for target chip selects. + NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (ChipSel & 0xFE)); + + //wait 8us for TMRD, must be changed to optimize to 8 MEM CLKs + MemUWait10ns (800, MemPtr); + if (Speed == DDR1066_FREQUENCY) { + MemTSendCtlWord3 (TechPtr, 0x0A, 1); + } else if (Speed == DDR1333_FREQUENCY) { + MemTSendCtlWord3 (TechPtr, 0x0A, 2); + } else if (Speed == DDR1600_FREQUENCY) { + MemTSendCtlWord3 (TechPtr, 0x0A, 3); + } + } + } +} + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.h new file mode 100644 index 0000000000..d5fdfeec7f --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtrci3.h @@ -0,0 +1,89 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mtrci3.h + * + * Technology control word init for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 34897 $ @e \$Date: 2010-07-14 10:07:10 +0800 (Wed, 14 Jul 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. + * + * *************************************************************************** + * + */ + +#ifndef _MTRCI3_H_ +#define _MTRCI3_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +UINT8 +MemTGetCtlWord3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 CtrlWordNum, + IN UINT8 RawCard, + IN UINT8 ChipSel + ); + +VOID +MemTDramControlRegInit3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +#endif /* _MTRCI3_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.c new file mode 100644 index 0000000000..48dc007b10 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.c @@ -0,0 +1,493 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mtsdi3.c + * + * Technology Software DRAM Init for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 37303 $ @e \$Date: 2010-09-02 03:43:36 +0800 (Thu, 02 Sep 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 "Ids.h" +#include "mm.h" +#include "mn.h" +#include "mu.h" +#include "mt.h" +#include "mt3.h" +#include "mtsdi3.h" +#include "mtrci3.h" +#include "merrhdl.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) +#define FILECODE PROC_MEM_TECH_DDR3_MTSDI3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + + + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function initiates software DRAM init for both DCTs + * at the same time. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +BOOLEAN +MemTDramInitSw3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + UINT8 Dct; + UINT8 ChipSel; + UINT32 Dummy; + + MEM_DATA_STRUCT *MemPtr; + DIE_STRUCT *MCTPtr; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + MemPtr = NBPtr->MemPtr; + MCTPtr = NBPtr->MCTPtr; + + IDS_HDT_CONSOLE (MEM_STATUS, "\nStart Dram Init\n"); + // 3.Program F2x[1,0]7C[EnDramInit]=1 + IDS_HDT_CONSOLE (MEM_FLOW, "\tEnDramInit = 1 for both DCTs\n"); + NBPtr->BrdcstSet (NBPtr, BFEnDramInit, 1); + NBPtr->PollBitField (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, TRUE); + + // 4.wait 200us + MemUWait10ns (20000, MemPtr); + + // 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1. + NBPtr->BrdcstSet (NBPtr, BFDeassertMemRstX, 1); + + // 6.wait 500us + MemUWait10ns (50000, MemPtr); + + // Do Phy Fence training before sending MRS commands + if (!NBPtr->IsSupported[FenceTrnBeforeDramInit]) { + AGESA_TESTPOINT (TpProcMemPhyFenceTraining, &(NBPtr->MemPtr->StdHeader)); + for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { + NBPtr->SwitchDCT (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); + NBPtr->PhyFenceTraining (NBPtr); + } + } + } + + // 7.NOP or deselect & take CKE high + NBPtr->BrdcstSet (NBPtr, BFAssertCke, 1); + + // 8.wait 360ns + MemUWait10ns (36, MemPtr); + + // The following steps are performed once for each channel with unbuffered DIMMs + // and once for each chip select on registered DIMMs: + for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { + NBPtr->SwitchDCT (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); + + // Enable Dram Parity if appropriate. + NBPtr->FamilySpecificHook[EnableParityAfterMemRst] (NBPtr, NULL); + + // The following steps are performed with registered DIMMs only and + // must be done for each chip select pair: + if (MCTPtr->Status[SbRegistered]) { + MemTDramControlRegInit3 (TechPtr); + } + + // Initialize LRDIMM's register + TechPtr->TechnologySpecificHook[LrdimmControlRegInit] (TechPtr, NULL); + + for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) { + if (NBPtr->GetSysAddr (NBPtr, ChipSel, &Dummy)) { + IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel); + // if chip select present + if (!(TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] (TechPtr, &ChipSel))) { + MemTSendAllMRCmds3 (TechPtr, ChipSel); + } + // NOTE: wait 512 clocks for DLL-relock + MemUWait10ns (50000, NBPtr->MemPtr); // wait 500us + if (!(MCTPtr->Status[SbRegistered] || MCTPtr->Status[SbLrdimms])) { + break; + } + } + } + + // 17.Send two ZQCL commands (to even then odd chip select) + NBPtr->sendZQCmd (NBPtr); + NBPtr->sendZQCmd (NBPtr); + } + } + + // 18.Program F2x[1,0]7C[EnDramInit]=0 + NBPtr->BrdcstSet (NBPtr, BFEnDramInit, 0); + NBPtr->PollBitField (NBPtr, BFDctAccessDone, 1, PCI_ACCESS_TIMEOUT, TRUE); + // + // For Unbuffered Dimms, Issue MRS for remaining CS without EnDramInit + // + NBPtr->FamilySpecificHook[SendMrsCmdsPerCs] (NBPtr, NBPtr); + + IDS_HDT_CONSOLE (MEM_FLOW, "End Dram Init\n\n"); + return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function calculates the EMRS1 value + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Wl - Indicates if WL mode should be enabled + * @param[in] TargetDIMM - DIMM target for WL + */ + +VOID +MemTEMRS13 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN BOOLEAN Wl, + IN UINT8 TargetDIMM + ) +{ + UINT16 MrsAddress; + UINT8 MaxDimmPerCH; + UINT8 ChipSel; + UINT8 Value8; + + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + MaxDimmPerCH = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, + NBPtr->MCTPtr->SocketId, + NBPtr->ChannelPtr->ChannelID); + ChipSel = (UINT8) (0x0FF & NBPtr->GetBitField (NBPtr, BFMrsChipSel)); + + // BA2=0,BA1=0,BA0=1 + NBPtr->SetBitField (NBPtr, BFMrsBank, 1); + + MrsAddress = 0; + + // program MrsAddress[5,1]=output driver impedance control (DIC): + // based on F2x[1,0]84[DrvImpCtrl] + if (!(NBPtr->IsSupported[CheckDrvImpCtrl])) { + Value8 = (UINT8)NBPtr->GetBitField (NBPtr, BFDrvImpCtrl); + if ((Value8 & ((UINT8) 1 << 1)) != 0) { + MrsAddress |= ((UINT16) 1 << 5); + } + if ((Value8 & ((UINT8) 1 << 0)) != 0) { + MrsAddress |= ((UINT16) 1 << 1); + } + } else { + MrsAddress |= ((UINT16) 1 << 1); + } + // program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT): + // Different CS may have different RTT. + // + Value8 = NBPtr->MemNGetDramTerm (NBPtr, ChipSel); + + // + // If Write Leveling this DIMM + // + if (Wl) { + if ((ChipSel >> 1) == TargetDIMM) { + // Program MrsAddress[7] = 1 for Write leveling enable + MrsAddress |= ((UINT16) 1 << 7); + if (ChipSel & 1) { + // Output buffer disabled, MrsAddress[7] (Qoff = 1) + MrsAddress |= ((UINT16) 1 << 12); + } + // Set Rtt_Nom = Rtt_Wr if there are 2 or more dimms + if ((NBPtr->ChannelPtr->DimmQrPresent != 0) || (NBPtr->ChannelPtr->Dimms >= 2)) { + Value8 = NBPtr->MemNGetDynDramTerm (NBPtr, ChipSel); + } + } + } + // + // Turn off Rtt_Nom (DramTerm=0) for certain CS in certain configs. + // + // All odd CS for 4 Dimm Systems + if (MaxDimmPerCH == 4) { + if (ChipSel & 0x01) { + Value8 = 0; + } + // CS 1 and 5 for 3 Dimm configs + } else if (MaxDimmPerCH == 3) { + if ((ChipSel == 1) || (ChipSel == 5)) { + Value8 = 0; + } + } + // All odd CS of any QR Dimms + if ((NBPtr->ChannelPtr->DimmQrPresent & ((UINT8) (1 << (ChipSel >> 1)))) != 0) { + if (ChipSel & 0x01) { + Value8 = 0; + } + } + if ((Value8 & ((UINT8) 1 << 2)) != 0) { + MrsAddress |= ((UINT16) 1 << 9); + } + if ((Value8 & ((UINT8) 1 << 1)) != 0) { + MrsAddress |= ((UINT16) 1 << 6); + } + if ((Value8 & ((UINT8) 1 << 0)) != 0) { + MrsAddress |= ((UINT16) 1 << 2); + } + + // program MrsAddress[12]=output disable (QOFF): + // based on F2x[1,0]84[Qoff] + + if (!NBPtr->IsSupported[CheckQoff]) { + if (NBPtr->GetBitField (NBPtr, BFQoff) != 0) { + MrsAddress |= ((UINT16) 1 << 12); + } + } + + // program MrsAddress[11]=TDQS: + // based on F2x[1,0]94[RDqsEn] + + if ((NBPtr->DCTPtr->Timings.Dimmx4Present != 0) && (NBPtr->DCTPtr->Timings.Dimmx8Present != 0)) { + MrsAddress |= ((UINT16) 1 << 11); + } + + NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function calculates the EMRS2 value + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +MemTEMRS23 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + UINT32 MrsAddress; + UINT8 DramTermDyn; + UINT8 MaxDimmPerCH; + UINT8 ChipSel; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + MaxDimmPerCH = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID ); + ChipSel = (UINT8) (0x0FF & NBPtr->GetBitField (NBPtr, BFMrsChipSel)); + + // BA2=0,BA1=1,BA0=0 + NBPtr->SetBitField (NBPtr, BFMrsBank, 2); + + // program MrsAddress[5:3]=CAS write latency (CWL): + MrsAddress = NBPtr->MemNGetMR2CWL (NBPtr); + + // program MrsAddress[6]=auto self refresh method (ASR): + // program MrsAddress[7]=self refresh temperature range (SRT): + MrsAddress |= 1 << 6; + MrsAddress &= ( ~ (1 << 7)); + + // program MrsAddress[10:9]=dynamic termination during writes (RTT_WR): + DramTermDyn = NBPtr->MemNGetDynDramTerm (NBPtr, ChipSel); + // Special Case for 1 DR Unbuffered Dimm in 3 Dimm/Ch + if (!(NBPtr->MCTPtr->Status[SbRegistered])) { + if (MaxDimmPerCH == 3) { + if (NBPtr->ChannelPtr->Dimms == 1) { + if ((NBPtr->ChannelPtr->DimmDrPresent & ((UINT8) (1 << (ChipSel >> 1)))) != 0) { + DramTermDyn = 1; + } + } + } + } + MrsAddress |= (UINT16) DramTermDyn << 9; + + NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function calculates the EMRS3 value + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +MemTEMRS33 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + // BA2=0,BA1=1,BA0=1 + NBPtr->SetBitField (NBPtr, BFMrsBank, 3); + + // program MrsAddress[1:0]=multi purpose register address location + // (MPR Location):based on F2x[1,0]84[MprLoc] + // program MrsAddress[2]=multi purpose register + // (MPR):based on F2x[1,0]84[MprEn] + NBPtr->SetBitField (NBPtr, BFMrsAddress, (NBPtr->GetBitField (NBPtr, BFDramMRSReg) >> 24) & 0x0007); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This sets MRS value + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + */ + +VOID +MemTMRS3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + UINT32 MrsAddress; + MEM_NB_BLOCK *NBPtr; + UINT32 Ppd; + + NBPtr = TechPtr->NBPtr; + + // BA2=0,BA1=0,BA0=0 + NBPtr->SetBitField (NBPtr, BFMrsBank, 0); + + // program MrsAddress[1:0]=burst length and control method + // (BL):based on F2x[1,0]84[BurstCtrl] + MrsAddress = NBPtr->GetBitField (NBPtr, BFBurstCtrl); + + // program MrsAddress[3]=1 (BT):interleaved + MrsAddress |= (UINT16) 1 << 3; + + // program MrsAddress[6:4,2]=read CAS latency + MrsAddress |= NBPtr->MemNGetMR0CL (NBPtr); + + // program MrsAddress[11:9]=write recovery for auto-precharge + MrsAddress |= NBPtr->MemNGetMR0WR (NBPtr); + + // program MrsAddress[12] (PPD):based on F2x[1,0]84[PChgPDModeSel] + Ppd = NBPtr->GetBitField (NBPtr, BFPchgPDModeSel); + NBPtr->FamilySpecificHook[MR0_PPD] (NBPtr, &Ppd); + IDS_OPTION_HOOK (IDS_MEM_MR0, &Ppd, &TechPtr->NBPtr->MemPtr->StdHeader); + MrsAddress |= Ppd << 12; + + // program MrsAddress[8]=1 (DLL):DLL reset + MrsAddress |= (UINT32) 1 << 8; + + NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This send all MR commands to a rank in sequence 2-3-1-0 + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] ChipSel - Target Chip Select + */ + +VOID +MemTSendAllMRCmds3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 ChipSel + ) +{ + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + + NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel); + + // 13.Send EMRS(2) + MemTEMRS23 (TechPtr); + NBPtr->SendMrsCmd (NBPtr); + + // 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b + MemTEMRS33 (TechPtr); + NBPtr->SendMrsCmd (NBPtr); + + // 15.Send EMRS(1). + MemTEMRS13 (TechPtr, FALSE, (ChipSel >> 1)); + NBPtr->SendMrsCmd (NBPtr); + + // 16.Send MRS with MrsAddress[8]=1(reset the DLL) + MemTMRS3 (TechPtr); + NBPtr->SendMrsCmd (NBPtr); +} diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.h new file mode 100644 index 0000000000..5715a22d27 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtsdi3.h @@ -0,0 +1,98 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mtsdi3.h + * + * Technology software DRAM init for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 34985 $ @e \$Date: 2010-07-15 04:48:28 +0800 (Thu, 15 Jul 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. + * + * *************************************************************************** + * + */ + +#ifndef _MTSDI3_H_ +#define _MTSDI3_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + +VOID +MemTEMRS33 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +VOID +MemTMRS3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +VOID +MemTEMRS13 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN BOOLEAN Wl, + IN UINT8 TargetDIMM + ); + +VOID +MemTEMRS23 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ); + +#endif /* _MTSDI3_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.c new file mode 100644 index 0000000000..c2f93724f8 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.c @@ -0,0 +1,1153 @@ +/* $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: 36054 $ @e \$Date: 2010-08-10 05:26:12 +0800 (Tue, 10 Aug 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 "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; + 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) { + // + // 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; + // + } // 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; + 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; + UINT8 *SpdBufferBPtr; + 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; + 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; + 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 & 0x1FF83FE0)); + } 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; + 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; +} + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.h b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.h new file mode 100644 index 0000000000..97f768335c --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mtspd3.h @@ -0,0 +1,177 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mtspd3.h + * + * Technology SPD support for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 35415 $ @e \$Date: 2010-07-22 06:10:32 +0800 (Thu, 22 Jul 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. + * + * *************************************************************************** + * + */ + +#ifndef _MTSPD3_H_ +#define _MTSPD3_H_ + +/*---------------------------------------------------------------------------- + * Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS) + * + *---------------------------------------------------------------------------- + */ + +/*----------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *----------------------------------------------------------------------------- + */ + +/*=============================================================================== + * Jedec DDR III + *=============================================================================== + */ +#define SPD_BYTE_USED 0 +#define SPD_TYPE 2 /* SPD byte read location */ +#define JED_DDR_SDRAM 7 /* Jedec defined bit field */ +#define JED_DDR2_SDRAM 8 /* Jedec defined bit field */ +#define JED_DDR3SDRAM 0xB /* Jedec defined bit field */ + +#define SPD_DIMM_TYPE 3 +#define SPD_ATTRIB 21 +#define JED_DIF_CK_MSK 0x20 /* Differential Clock Input */ +#define JED_RDIMM 1 +#define JED_MINIRDIMM 5 +#define JED_UDIMM 2 +#define JED_SODIMM 3 +#define JED_LRDIMM 0xB + +#define SPD_L_BANKS 4 /* [7:4] number of [logical] banks on each device */ +#define SPD_DENSITY 4 /* bit 3:0 */ +#define SPD_ROW_SZ 5 /* bit 5:3 */ +#define SPD_COL_SZ 5 /* bit 2:0 */ +#define SPD_RANKS 7 /* bit 5:3 */ +#define SPD_DEV_WIDTH 7 /* bit 2:0 */ +#define SPD_ECCBITS 8 /* bit 4:3 */ +#define JED_ECC 8 +#define SPD_RAWCARD 62 /* bit 2:0 */ +#define SPD_ADDRMAP 63 /* bit 0 */ + +#define SPD_CTLWRD03 70 /* bit 7:4 */ +#define SPD_CTLWRD04 71 /* bit 3:0 */ +#define SPD_CTLWRD05 71 /* bit 7:4 */ + +#define SPD_FTB 9 + +#define SPD_DIVIDENT 10 +#define SPD_DIVISOR 11 + +#define SPD_TCK 12 +#define SPD_CASLO 14 +#define SPD_CASHI 15 +#define SPD_TAA 16 + +#define SPD_TRP 20 +#define SPD_TRRD 19 +#define SPD_TRCD 18 +#define SPD_TRAS 22 +#define SPD_TWR 17 +#define SPD_TWTR 26 +#define SPD_TRTP 27 +#define SPD_TRC 23 +#define SPD_UPPER_TRC 21 /* bit 7:4 */ +#define SPD_UPPER_TRAS 21 /* bit 3:0 */ +#define SPD_TFAW 29 +#define SPD_UPPER_TFAW 28 /* bit 3:0 */ + +#define SPD_TCK_FTB 34 +#define SPD_TAA_FTB 35 +#define SPD_TRCD_FTB 36 +#define SPD_TRP_FTB 37 +#define SPD_TRC_FTB 38 + +/*----------------------------- + * Jedec DDR II related equates + *----------------------------- + */ + +#define CL_DEF 4 /* Default value for failsafe operation. 4=CL 6.0 T */ +#define T_DEF 4 /* Default value for failsafe operation. 4=2.5ns (cycle time) */ + +#define BIAS_TRTP_T 4 +#define BIAS_TRCD_T 5 +#define BIAS_TRAS_T 15 +#define BIAS_TRC_T 11 +#define BIAS_TRRD_T 4 +#define BIAS_TWR_T 4 +#define BIAS_TRP_T 5 +#define BIAS_TWTR_T 4 +#define BIAS_TFAW_T 14 + +#define MIN_TRTP_T 4 +#define MAX_TRTP_T 7 +#define MIN_TRCD_T 5 +#define MAX_TRCD_T 12 +#define MIN_TRAS_T 15 +#define MAX_TRAS_T 30 +#define MIN_TRC_T 11 +#define MAX_TRC_T 42 +#define MIN_TRRD_T 4 +#define MAX_TRRD_T 7 +#define MIN_TWR_T 5 +#define MAX_TWR_T 12 +#define MIN_TRP_T 5 +#define MAX_TRP_T 12 +#define MIN_TWTR_T 4 +#define MAX_TWTR_T 7 +#define MIN_TFAW_T 16 +#define MAX_TFAW_T 32 + +/*---------------------------------------------------------------------------- + * TYPEDEFS, STRUCTURES, ENUMS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * FUNCTIONS PROTOTYPE + * + *---------------------------------------------------------------------------- + */ + + +#endif /* _MTSPD3_H_ */ + + diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttecc3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttecc3.c new file mode 100644 index 0000000000..5f948733a7 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttecc3.c @@ -0,0 +1,166 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mttecc3.c + * + * Technology ECC byte support for registered DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 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 "mm.h" +#include "mn.h" +#include "mu.h" +#include "mt.h" +#include "Filecode.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) + +#define FILECODE PROC_MEM_TECH_DDR3_MTTECC3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function sets the DQS ECC timings for registered DDR3 + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + * @return TRUE - No fatal error occurs. + * @return FALSE - Fatal error occurs. + */ + +BOOLEAN +MemTSetDQSEccTmgsRDdr3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + UINT8 Dct; + UINT8 Dimm; + UINT8 i; + UINT8 *WrDqsDly; + UINT16 *RcvEnDly; + UINT8 *RdDqsDly; + UINT8 *WrDatDly; + UINT8 EccByte; + INT16 TempValue; + + MEM_NB_BLOCK *NBPtr; + CH_DEF_STRUCT *ChannelPtr; + + EccByte = TechPtr->MaxByteLanes (); + NBPtr = TechPtr->NBPtr; + + if (NBPtr->MCTPtr->NodeMemSize) { + for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { + NBPtr->SwitchDCT (NBPtr, Dct); + if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { + ChannelPtr = NBPtr->ChannelPtr; + for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) { + if (NBPtr->DCTPtr->Timings.CsEnabled & ((UINT16)3 << (Dimm * 2))) { + i = Dimm * TechPtr->DlyTableWidth (); + WrDqsDly = &ChannelPtr->WrDqsDlys[i]; + RcvEnDly = &ChannelPtr->RcvEnDlys[i]; + RdDqsDly = &ChannelPtr->RdDqsDlys[i]; + WrDatDly = &ChannelPtr->WrDatDlys[i]; + // Receiver DQS Enable: + // Receiver DQS enable for ECC bytelane = Receiver DQS enable for bytelane 3 - + // [write DQS for bytelane 3 - write DQS for ECC] + + TempValue = (INT16) RcvEnDly[3] - (INT16) (WrDqsDly[3] - WrDqsDly[EccByte]); + if (TempValue < 0) { + TempValue = 0; + } + RcvEnDly[EccByte] = (UINT16) TempValue; + + // Read DQS: + // Read DQS for ECC bytelane = read DQS of byte lane 3 + // + RdDqsDly[EccByte] = RdDqsDly[3]; + + // Write Data: + // Write Data for ECC bytelane = Write DQS for ECC + + // [write data for bytelane 3 - Write DQS for bytelane 3] + TempValue = (INT16) (WrDqsDly[EccByte] + (INT8) (WrDatDly[3] - WrDqsDly[3])); + if (TempValue < 0) { + TempValue = 0; + } + WrDatDly[EccByte] = (UINT8) TempValue; + + NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Dimm, EccByte), RcvEnDly[EccByte]); + NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm, EccByte), RdDqsDly[EccByte]); + NBPtr->SetTrainDly (NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS (Dimm, EccByte), WrDatDly[EccByte]); + } + } + } + } + } + return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); +}
\ No newline at end of file diff --git a/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttwl3.c b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttwl3.c new file mode 100644 index 0000000000..34e0927640 --- /dev/null +++ b/src/vendorcode/amd/agesa/f14/Proc/Mem/Tech/DDR3/mttwl3.c @@ -0,0 +1,686 @@ +/* $NoKeywords:$ */ +/** + * @file + * + * mttwl3.c + * + * Technology Phy assisted write levelization for DDR3 + * + * @xrefitem bom "File Content Label" "Release Content" + * @e project: AGESA + * @e sub-project: (Mem/Tech/DDR3) + * @e \$Revision: 38442 $ @e \$Date: 2010-09-24 06:39:57 +0800 (Fri, 24 Sep 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 "Ids.h" +#include "mm.h" +#include "mn.h" +#include "mu.h" +#include "mt.h" +#include "mtsdi3.h" +#include "merrhdl.h" +#include "OptionMemory.h" +#include "PlatformMemoryConfiguration.h" +#include "GeneralServices.h" +#include "Filecode.h" +#include "mtlrdimm3.h" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G1_PEICC) + +#define FILECODE PROC_MEM_TECH_DDR3_MTTWL3_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * TYPEDEFS AND STRUCTURES + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * PROTOTYPES OF LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +BOOLEAN +STATIC +MemTWriteLevelizationHw3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Pass + ); + +VOID +STATIC +MemTWLPerDimmHw3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm, + IN UINT8 Pass + ); + +VOID +STATIC +MemTPrepareDIMMs3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 TargetDIMM, + IN BOOLEAN Wl + ); + +VOID +STATIC +MemTProcConfig3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm, + IN UINT8 Pass + ); + +VOID +STATIC +MemTBeginWLTrain3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm + ); + +/*---------------------------------------------------------------------------- + * EXPORTED FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function executes first pass of Phy assisted write levelization + * for a specific node (DDR800). + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + * @return TRUE - No fatal error occurs. + * @return FALSE - Fatal error occurs. + */ + +BOOLEAN +MemTWriteLevelizationHw3Pass1 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + return MemTWriteLevelizationHw3 (TechPtr, 1); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function executes second pass of Phy assisted write levelization + * for a specific node (DDR1066 and above). + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + * @return TRUE - No fatal error occurs. + * @return FALSE - Fatal error occurs. + */ + +BOOLEAN +MemTWriteLevelizationHw3Pass2 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + // If current speed is higher than start-up speed, do second pass of WL + if (TechPtr->NBPtr->DCTPtr->Timings.Speed > TechPtr->NBPtr->StartupSpeed) { + return MemTWriteLevelizationHw3 (TechPtr, 2); + } + return TRUE; +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function prepares for Phy assisted training. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + * @return TRUE - No fatal error occurs. + * @return FALSE - Fatal error occurs. + */ + +BOOLEAN +MemTPreparePhyAssistedTraining ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + // Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1. + TechPtr->NBPtr->BrdcstSet (TechPtr->NBPtr, BFDisAutoRefresh, 1); + // Disable ZQ calibration short command by configuring F2x[1, 0]94[ZqcsInterval] = 00b. + TechPtr->NBPtr->BrdcstSet (TechPtr->NBPtr, BFZqcsInterval, 0); + return (BOOLEAN) (TechPtr->NBPtr->MCTPtr->ErrCode < AGESA_FATAL); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function revert to normal settings when exiting from Phy assisted training. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + * @return TRUE - No fatal error occurs. + * @return FALSE - Fatal error occurs. + */ + +BOOLEAN +MemTExitPhyAssistedTraining ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + MEM_NB_BLOCK *NBPtr; + NBPtr = TechPtr->NBPtr; + + // 13.Program F2x[1, 0]8C[DisAutoRefresh] = 0. + NBPtr->BrdcstSet (NBPtr, BFDisAutoRefresh, 0); + // 14.Program F2x[1, 0]94[ZqcsInterval] to the proper interval for the current memory configuration. + NBPtr->BrdcstSet (NBPtr, BFZqcsInterval, 2); + NBPtr->FamilySpecificHook[ExitPhyAssistedTraining] (NBPtr, NBPtr); + + return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); +} + +/*---------------------------------------------------------------------------- + * LOCAL FUNCTIONS + * + *---------------------------------------------------------------------------- + */ + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function executed hardware based write levelization for a specific die + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Pass - Pass number (1 (400Mhz) or 2 (>400Mhz)) + * + * @pre Auto refresh and ZQCL must be disabled + * + * @return TRUE - No fatal error occurs. + * @return FALSE - Fatal error occurs. + */ + +BOOLEAN +STATIC +MemTWriteLevelizationHw3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Pass + ) +{ + MEM_NB_BLOCK *NBPtr; + DCT_STRUCT *DCTPtr; + UINT8 Dct; + UINT8 Dimm; + + NBPtr = TechPtr->NBPtr; + + IDS_HDT_CONSOLE (MEM_STATUS, "\nStart write leveling\n"); + AGESA_TESTPOINT (TpProcMemWriteLevelizationTraining, &(NBPtr->MemPtr->StdHeader)); + // Begin DQS Write timing training + for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { + NBPtr->SwitchDCT (NBPtr, Dct); + IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); + DCTPtr = NBPtr->DCTPtr; + + TechPtr->WLCriticalDelay = 0x00; + + //training for each Dimm + for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) { + if ((DCTPtr->Timings.CsEnabled & ((UINT16)3 << (Dimm << 1))) != 0) { + if (!(NBPtr->MCTPtr->Status[SbLrdimms]) || ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << Dimm)) != 0)) { + IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", Dimm << 1); + MemTWLPerDimmHw3 (TechPtr, Dimm, Pass); + } + } + } + + NBPtr->FamilySpecificHook[CalcWrDqDqsEarly] (NBPtr, NULL); + } + IDS_HDT_CONSOLE (MEM_FLOW, "End write leveling\n\n"); + return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function initializes per DIMM write levelization + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Dimm - DIMM to be trained + * @param[in] Pass - Pass number (1 (400Mhz) or 2 (>400Mhz)) + * + */ + +VOID +STATIC +MemTWLPerDimmHw3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm, + IN UINT8 Pass + ) +{ + MEM_DATA_STRUCT *MemPtr; + MEM_NB_BLOCK *NBPtr; + + NBPtr = TechPtr->NBPtr; + MemPtr = NBPtr->MemPtr; + + ASSERT (Dimm < MAX_DIMMS_PER_CHANNEL); + + // 1. A. Specify the target Dimm that is to be trained by programming + // F2x[1, 0]9C_x08[TrDimmSel]. + NBPtr->SetBitField (NBPtr, BFTrDimmSel, Dimm); + + TechPtr->TargetDIMM = Dimm; + NBPtr->FamilySpecificHook[InitPerNibbleTrn] (NBPtr, NULL); + for (TechPtr->TrnNibble = NIBBLE_0; TechPtr->TrnNibble <= (NBPtr->FamilySpecificHook[TrainWlPerNibble] (NBPtr, &Dimm)? NIBBLE_0 : NIBBLE_1); TechPtr->TrnNibble++) { + // 2. Prepare the DIMMs for write levelization using DDR3-defined + // MR commands. + MemTPrepareDIMMs3 (TechPtr, Dimm, TRUE); + + // 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to + // satisfy DDR3-defined internal DRAM timing. + NBPtr->WaitXMemClks (NBPtr, 40); + + // 4. Configure the processor's DDR phy for write levelization training: + MemTProcConfig3 (TechPtr, Dimm, Pass); + + // 5. Begin write levelization training + MemTBeginWLTrain3 (TechPtr, Dimm); + } + // 7. Program the target Dimm back to normal operation + MemTPrepareDIMMs3 (TechPtr, Dimm, FALSE); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function prepares the DIMMS for Write Levelization + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] TargetDIMM - DIMM to be trained + * @param[in] Wl - Indicates if WL mode should be enabled + * + */ + +VOID +STATIC +MemTPrepareDIMMs3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 TargetDIMM, + IN BOOLEAN Wl + ) +{ + MEM_NB_BLOCK *NBPtr; + UINT8 ChipSel; + + NBPtr = TechPtr->NBPtr; + + AGESA_TESTPOINT (TpProcMemWlPrepDimms, &(NBPtr->MemPtr->StdHeader)); + ASSERT (TargetDIMM < MAX_DIMMS_PER_CHANNEL); + TechPtr->TargetDIMM = TargetDIMM; + if (!(TechPtr->TechnologySpecificHook[WlTrainingPrepareLrdimm] (TechPtr, &Wl))) { + for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; ChipSel++) { + if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) { + if (Wl) { + // Program WrLvOdt + NBPtr->SetBitField (NBPtr, BFWrLvOdt, NBPtr->ChannelPtr->PhyWLODT[ChipSel >> 1]); + } + NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel); + // Set MR1 to F2x7C[MrsAddress], F2x7C[MrsBank]=1 + MemTEMRS13 (TechPtr, Wl, TargetDIMM); + NBPtr->SendMrsCmd (NBPtr); + // Set MR2 to F2x7C[MrsAddress], F2x7C[MrsBank]=1 + MemTEMRS23 (TechPtr); + // Send command + NBPtr->SendMrsCmd (NBPtr); + } + } + } +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function programs seed values for Write Levelization + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Dimm - DIMM to be trained + * @param[in] Pass - Pass for WL training (1 - 400Mhz or 2 - >400Mhz) + * + */ + +VOID +STATIC +MemTProcConfig3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm, + IN UINT8 Pass + ) +{ + DIE_STRUCT *MCTPtr; + CH_DEF_STRUCT *ChannelPtr; + MEM_NB_BLOCK *NBPtr; + UINT16 WrDqsDly; + // Memclk Delay incurred by register. + UINT8 MemClkRegDly; + UINT8 ByteLane; + UINT8 DefaultSeed; + UINT8 CurrentSeed; + UINT8 *Seed; + UINT8 RCW2; + UINT16 Speed; + + NBPtr = TechPtr->NBPtr; + MCTPtr = NBPtr->MCTPtr; + ChannelPtr = TechPtr->NBPtr->ChannelPtr; + + AGESA_TESTPOINT (TpProcMemWlConfigDimms, &(NBPtr->MemPtr->StdHeader)); + RCW2 = ChannelPtr->CtrlWrd02[Dimm]; + Speed = TechPtr->NBPtr->DCTPtr->Timings.Speed; + + IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t Byte: 00 01 02 03 04 05 06 07 ECC\n"); + IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSeeds: "); + // Program an initialization Value to registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to set + // the gross and fine delay for all the byte lane fields. If the target frequency is different than 400MHz, + // BIOS must execute two training passes for each Dimm. For pass 1 at a 400MHz MEMCLK frequency, + // use an initial total delay value. + if (Pass == 1) { + // + // Get the default value of seed + // + if (MCTPtr->Status[SbRegistered]) { + // + // RDIMM + // + if (Speed == DDR667_FREQUENCY) { + DefaultSeed = ((RCW2 & BIT0) == 0) ? 0x3B : 0x4B; + } else { + DefaultSeed = ((RCW2 & BIT0) == 0) ? 0x41 : 0x51; + } + } else if (ChannelPtr->SODimmPresent != 0) { + // + // SODIMMM + // + DefaultSeed = 0x12; + } else if (MCTPtr->Status[SbLrdimms]) { + // + // LRDIMM + // + DefaultSeed = 0x0; + } else { + // + // UDIMMM + // + DefaultSeed = 0x1A; + } + + ASSERT (Speed >= DDR667_FREQUENCY); + + // Get platform override seed + Seed = (UINT8 *) FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_WL_SEED, MCTPtr->SocketId, ChannelPtr->ChannelID); + + for (ByteLane = 0; ByteLane < TechPtr->DlyTableWidth (); ByteLane++) { + // This includes ECC as byte 8 + CurrentSeed = ((Seed != NULL) ? Seed[ByteLane] : DefaultSeed); + ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + ByteLane] = CurrentSeed; + + if (NBPtr->IsSupported[WLSeedAdjust]) { + if ((CurrentSeed & 0x20) != 0) { + // If (SeedGross is odd) then SeedPreGross = 1 + CurrentSeed = (CurrentSeed & 0x1F) | 0x20; + } else { + // If (SeedGross is even) then SeedPreGross = 2 + CurrentSeed = (CurrentSeed & 0x1F) | 0x40; + } + } + + NBPtr->SetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), CurrentSeed); + IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", CurrentSeed); + } + } else { + //10.Multiply the previously saved delay values in Pass 1, step #5 by (target frequency)/400 to find + //the gross and fine delay initialization values at the target frequency. Use these values as the initial + //seed values when executing Pass 2, step #4. + for (ByteLane = 0; ByteLane < TechPtr->DlyTableWidth (); ByteLane++) { + // This includes ECC as byte 8 + WrDqsDly = ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + ByteLane]; + TechPtr->Bytelane = ByteLane; + NBPtr->FamilySpecificHook[TrainWlPerNibbleSeed] (NBPtr, &WrDqsDly); + // + // For Registered Dimms + // + if (MCTPtr->Status[SbRegistered]) { + MemClkRegDly = ((RCW2 & BIT0) == 0) ? 0x20 : 0x30; + WrDqsDly = (UINT16) (MemClkRegDly + ((((UINT32) WrDqsDly - MemClkRegDly) * Speed) / TechPtr->PrevSpeed)); + } else { + // + // Unbuffered Dimms and LRDIMMs + // + WrDqsDly = (UINT16) (((UINT32) WrDqsDly * Speed) / TechPtr->PrevSpeed); + } + + ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + ByteLane] = (UINT8) WrDqsDly; + + if (NBPtr->IsSupported[WLSeedAdjust]) { + if ((WrDqsDly & 0x20) != 0) { + // If (SeedGross is odd) then SeedPreGross = 1 + WrDqsDly = (WrDqsDly & 0x1F) | 0x20; + } else { + // If (SeedGross is even) then SeedPreGross = 2 + WrDqsDly = (WrDqsDly & 0x1F) | 0x40; + } + } + NBPtr->SetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), WrDqsDly); + IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", WrDqsDly); + } + } + IDS_HDT_CONSOLE (MEM_FLOW, "\n"); +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function begins WL training for a specific DIMM + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * @param[in] Dimm - DIMM to be trained + * + */ + +VOID +STATIC +MemTBeginWLTrain3 ( + IN OUT MEM_TECH_BLOCK *TechPtr, + IN UINT8 Dimm + ) +{ + MEM_DATA_STRUCT *MemPtr; + DIE_STRUCT *MCTPtr; + MEM_NB_BLOCK *NBPtr; + UINT8 ByteLane; + UINT8 Seed; + UINT8 Delay; + + NBPtr = TechPtr->NBPtr; + MemPtr = NBPtr->MemPtr; + MCTPtr = NBPtr->MCTPtr; + // Assert ODT pins for write leveling + NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 1); + + // Wait 10 MEMCLKs to allow for ODT signal settling. + NBPtr->WaitXMemClks (NBPtr, 10); + + IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tWrtLvTrEn = 1\n"); + // Program F2x[1, 0]9C_x08[WrtLlTrEn]=1. + NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 1); + + // Wait 200 MEMCLKs. + NBPtr->WaitXMemClks (NBPtr, 200); + + // Program F2x[1, 0]9C_x08[WrtLlTrEn]=0. + NBPtr->SetBitField (NBPtr, BFWrtLvTrEn, 0); + + // Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 to get the gross and fine Delay settings + // for the target Dimm and save these values. + IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t PRE: "); + for (ByteLane = 0; ByteLane < (MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) { + // This includes ECC as byte 8 + Seed = NBPtr->ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ()) + ByteLane]; + Delay = (UINT8)NBPtr->GetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (Dimm, ByteLane)); + IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", Delay); + + if (NBPtr->IsSupported[WLSeedAdjust]) { + // Recover WrDqsGrossDly: + // WrDqsGrossDly = SeedGross + PhRecGrossDlyByte - SeedPreGross + if ((Seed & 0x20) != 0) { + // If (SeedGross is odd) then SeedPreGross = 1 + Delay += (Seed & 0xE0) - 0x20; + } else { + // If (SeedGross is even) then SeedPreGross = 2 + if (((Seed & 0xE0) == 0) && (Delay < 0x40)) { + // If SeedGross is 0 and PhRecGrossDlyByte is less than SeedPreGross, + // we have a negative result and need to program the delay to 0 + if (NBPtr->IsSupported[WLNegativeDelay]) { + // + // Save the lowest negative delay value across all Dimms and Bytelanes + // + TechPtr->WLCriticalDelay = MIN (TechPtr->WLCriticalDelay, (INT16)Delay - 0x40); + Delay -= 0x40; + } else { + Delay = 0; + } + } else { + Delay += (Seed & 0xE0) - 0x40; + } + } + } else if (((Seed >> 5) == 0) && ((Delay >> 5) == 3)) { + IDS_OPTION_HOOK (IDS_CHECK_NEGATIVE_WL, &Delay, &(TechPtr->NBPtr->MemPtr->StdHeader)); + // If seed has gross delay of 0 and PRE has gross delay of 3, + // then round the total delay of TxDqs to 0. + Delay = 0; + } + + if ((Delay > (Seed + 0x20)) || (Seed > (Delay + 0x20))) { + // + // If PRE comes back with more than Seed +/- 0x20, then this is an + // unexpected condition. Log the condition. + // + PutEventLog (AGESA_ERROR, MEM_ERROR_WL_PRE_OUT_OF_RANGE, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, ((Seed << 8) + Delay), &NBPtr->MemPtr->StdHeader); + } + + TechPtr->Bytelane = ByteLane; + TechPtr->TargetDIMM = Dimm; + NBPtr->FamilySpecificHook[TrainWlPerNibbleAdjustWLDly] (NBPtr, &Delay); + NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm, ByteLane), Delay); + NBPtr->ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ()) + ByteLane] = Delay; + } + + IDS_HDT_CONSOLE_DEBUG_CODE ( + IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\tWrDqs: "); + for (ByteLane = 0; ByteLane < (MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) { + IDS_HDT_CONSOLE (MEM_FLOW, "%02x ", NBPtr->ChannelPtr->WrDqsDlys[(Dimm * TechPtr->DlyTableWidth ()) + ByteLane]); + } + IDS_HDT_CONSOLE (MEM_FLOW, "\n\n"); + ); + + // Disable write leveling ODT pins + NBPtr->SetBitField (NBPtr, BFWrLvOdtEn, 0); + + // Wait 10 MEMCLKs to allow for ODT signal settling. + NBPtr->WaitXMemClks (NBPtr, 10); + +} + +/* -----------------------------------------------------------------------------*/ +/** + * + * This function programs register after Phy assisted training is finish. + * + * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK + * + * @return TRUE - No fatal error occurs. + * @return FALSE - Fatal error occurs. + */ + +BOOLEAN +MemTExitPhyAssistedTrainingClient3 ( + IN OUT MEM_TECH_BLOCK *TechPtr + ) +{ + MEM_NB_BLOCK *NBPtr; + UINT8 Dct; + UINT8 ChipSel; + NBPtr = TechPtr->NBPtr; + + NBPtr->FamilySpecificHook[ReEnablePhyComp] (NBPtr, NBPtr); + NBPtr->BrdcstSet (NBPtr, BFRxPtrInitReq, 1); + NBPtr->PollBitField (NBPtr, BFRxPtrInitReq, 0, PCI_ACCESS_TIMEOUT, TRUE); + NBPtr->BrdcstSet (NBPtr, BFDisDllShutdownSR, 1); + NBPtr->BrdcstSet (NBPtr, BFEnterSelfRef, 1); + NBPtr->PollBitField (NBPtr, BFEnterSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE); + IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClkAlign = 2\n"); + NBPtr->BrdcstSet (NBPtr, BFDbeGskMemClkAlignMode, 2); + NBPtr->BrdcstSet (NBPtr, BFExitSelfRef, 1); + NBPtr->PollBitField (NBPtr, BFExitSelfRef, 0, PCI_ACCESS_TIMEOUT, TRUE); + NBPtr->BrdcstSet (NBPtr, BFDisDllShutdownSR, 0); + + // Calculate Max Latency for both channels to prepare for position training + for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { + IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); + NBPtr->SwitchDCT (NBPtr, Dct); + if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) { + NBPtr->SetMaxLatency (NBPtr, TechPtr->MaxDlyForMaxRdLat); + } + } + return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); +} + |