7 * Technology SPD supporting functions for DDR3 Recovery
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Proc/Recovery/Mem)
12 * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ***************************************************************************
47 *----------------------------------------------------------------------------
50 *----------------------------------------------------------------------------
66 #define FILECODE PROC_RECOVERY_MEM_TECH_DDR3_MRTSPD3_FILECODE
68 /*----------------------------------------------------------------------------
69 * DEFINITIONS AND MACROS
71 *----------------------------------------------------------------------------
74 #define MAX_DIES_PER_SOCKET 2 ///< Set to largest of any CPU
76 /*----------------------------------------------------------------------------
77 * TYPEDEFS AND STRUCTURES
79 *----------------------------------------------------------------------------
82 /*----------------------------------------------------------------------------
83 * PROTOTYPES OF LOCAL FUNCTIONS
85 *----------------------------------------------------------------------------
88 /*----------------------------------------------------------------------------
91 *----------------------------------------------------------------------------
95 /* -----------------------------------------------------------------------------*/
98 * This function sets the DRAM mode
100 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
102 * @return TRUE - indicates that the DRAM mode is set to DDR2
106 MemRecTSetDramMode3 (
107 IN OUT MEM_TECH_BLOCK *TechPtr
110 TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFLegacyBiosMode, 0);
111 TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFDdr3Mode, 1);
115 /* -----------------------------------------------------------------------------*/
118 * This function determines if DIMMs are present. It checks checksum and interrogates the SPDs
120 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
122 * @return TRUE - indicates that a FATAL error has not occurred
123 * @return FALL - indicates that a FATAL error has not occurred
127 MemRecTDIMMPresence3 (
128 IN OUT MEM_TECH_BLOCK *TechPtr
135 SPD_DEF_STRUCT *SPDPtr;
139 CH_DEF_STRUCT *ChannelPtr;
152 NBPtr = TechPtr->NBPtr;
153 MCTPtr = NBPtr->MCTPtr;
159 NBPtr->DimmToBeUsed = _UNDEF_;
160 for (Node = 0; Node < NBPtr->MemPtr->DieCount; Node++) {
161 NBPtr->SwitchNodeRec (NBPtr, Node);
162 for (Dct = 0; Dct < NBPtr->MCTPtr->DctCount; Dct++) {
163 NBPtr->SwitchDCT (NBPtr, Dct);
164 DCTPtr = NBPtr->DCTPtr;
165 for (Channel = 0; Channel < DCTPtr->ChannelCount; Channel++) {
166 NBPtr->SwitchChannel (NBPtr, Channel);
167 ChannelPtr = NBPtr->ChannelPtr;
168 SPDPtr = NBPtr->SPDPtr;
170 // Get the maximum number of DIMMs
171 MaxDimms = MAX_DIMMS_PER_CHANNEL;
172 for (i = 0; i < MaxDimms; i++) {
173 // Bitmask representing dimm #i.
174 DimmMask = (UINT16) 1 << i;
176 if (SPDPtr[i].DimmPresent) {
177 SpdBufferPtr = (UINT8 *)&(SPDPtr[i].Data);
179 MCTPtr->DimmPresent |= DimmMask;
180 if (SpdBufferPtr[SPD_TYPE] == JED_DDR3SDRAM) {
181 ChannelPtr->ChDimmValid |= DimmMask;
184 // Check module type information.
185 if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_RDIMM || SpdBufferPtr[SPD_DIMM_TYPE] == JED_MINIRDIMM) {
186 ChannelPtr->RegDimmPresent |= DimmMask;
189 if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_SODIMM) {
190 ChannelPtr->SODimmPresent |= DimmMask;
193 // Get the Dimm width data
194 Devwidth = SpdBufferPtr[SPD_DEV_WIDTH] & 0x7;
197 ChannelPtr->Dimmx4Present |= DimmMask;
201 ChannelPtr->Dimmx8Present |= DimmMask;
205 ChannelPtr->Dimmx16Present |= DimmMask;
212 // Determine the page size.
213 // page_size = 2^COLBITS * Devwidth/8
215 Value16 = (((UINT16) 1 << (SpdBufferPtr[SPD_COL_SZ]&7)) * Devwidth) / 8;
216 if ((Value16 >> 11) == 0) {
217 DCTPtr->Timings.DIMM1KPage |= DimmMask;
220 // Calculate bus loading per Channel
221 if (Devwidth == 16) {
223 } else if (Devwidth == 4) {
227 // specify the number of ranks
228 Value8 = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
230 ChannelPtr->DimmQrPresent |= DimmMask;
231 Devwidth = Devwidth << 2;
232 } else if (Value8 == 2) {
233 ChannelPtr->DimmDrPresent |= DimmMask; // Dual rank dimms
234 Devwidth = Devwidth << 1;
236 ChannelPtr->DimmSRPresent |= DimmMask;
239 ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
240 ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
243 // Check address mirror support for Unbuffered Dimms only
244 if ((ChannelPtr->RegDimmPresent & DimmMask) == 0) {
245 if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) {
246 ChannelPtr->DimmMirrorPresent |= DimmMask;
250 // Get control word values for RC3, RC4 and RC5
251 ChannelPtr->CtrlWrd03[i] = SpdBufferPtr[SPD_CTLWRD03] >> 4;
252 ChannelPtr->CtrlWrd04[i] = SpdBufferPtr[SPD_CTLWRD04] & 0x0F;
253 ChannelPtr->CtrlWrd05[i] = SpdBufferPtr[SPD_CTLWRD05] >> 4;
255 // Temporarily store info. of SPD byte 63 into CtrlWrd02(s),
256 // and they will be used late to calculate real RC2 and RC8 value
258 ChannelPtr->CtrlWrd02[i] = SpdBufferPtr[SPD_ADDRMAP] & 0x03;
260 // Get the common voltage if possible and create the individual Dimm maps per voltage
261 VDDByte = SpdBufferPtr[SPD_MNVVDD];
263 VoltageMap &= VDDByte;
265 // Create the Dimms map
269 // Dimm: 3210 3210 3210 3210
270 // Dimmbitmap: xxxx xxxx xxxx xxxx
271 // Ex. 0000 0001 0010 0000 (V1_2XDimmMap)
272 // This indicates Node0/Dct1/Dimm1 and Node1/Dct0/Dimm0 are 1.2XV supported.
273 if ((VDDByte & (UINT8) (1 << VOLT1_25)) != 0) {
274 V1_2XDimmMap |= (UINT32) DimmMask << ((Node * NBPtr->MCTPtr->DctCount + Dct) * MAX_DIMMS_PER_CHANNEL);
275 } else if ((VDDByte & (UINT8) (1 << VOLT1_35)) != 0) {
276 V1_35DimmMap |= (UINT32) DimmMask << ((Node * NBPtr->MCTPtr->DctCount + Dct) * MAX_DIMMS_PER_CHANNEL);
278 V1_5DimmMap |= (UINT32) DimmMask << ((Node * NBPtr->MCTPtr->DctCount + Dct) * MAX_DIMMS_PER_CHANNEL);
286 if (VoltageMap != 0xFF) {
287 if (VoltageMap == 0) {
288 NBPtr->RefPtr->DDR3Voltage = VOLT1_35;
289 if (V1_35DimmMap != 0) {
290 i = (UINT8) LibAmdBitScanForward (V1_35DimmMap);
292 i = (UINT8) LibAmdBitScanForward (V1_2XDimmMap);
295 NBPtr->RefPtr->DDR3Voltage = CONVERT_ENCODED_TO_VDDIO (LibAmdBitScanReverse (VoltageMap));
296 i = (UINT8) LibAmdBitScanForward (V1_2XDimmMap | V1_35DimmMap | V1_5DimmMap);
297 // In case of 1.35V Dimms and 1.5V Dimms mixture, we initialize the 1.35V Dimm.
298 if ((V1_35DimmMap != 0) && (V1_5DimmMap != 0)) {
299 NBPtr->RefPtr->DDR3Voltage = VOLT1_35;
300 i = (UINT8) LibAmdBitScanForward (V1_35DimmMap);
303 // Find out which Dimm we are going to initialize and which Node/Dct it belongs to
304 NBPtr->DimmToBeUsed = i % MAX_DIMMS_PER_CHANNEL;
305 Node = i / (NBPtr->MCTPtr->DctCount * MAX_DIMMS_PER_CHANNEL);
306 Dct = (i / MAX_DIMMS_PER_CHANNEL) & (NBPtr->MCTPtr->DctCount - 1);
307 NBPtr->SwitchNodeRec (NBPtr, Node);
308 NBPtr->SwitchDCT (NBPtr, Dct);
311 // If we have DIMMs, some further general characteristics checking
312 if (NBPtr->DimmToBeUsed == _UNDEF_) {
313 // Leave with an error - no dimms on this DCT
314 // LibAmdEventLog (AGESA_FATAL, MEM_ERROR_NO_DIMM_FOUND, 0, NBPtr->Dct, NBPtr->Channel, 0); //@attention commented out since it is not defined in recovery code
315 SetMemRecError (AGESA_FATAL, MCTPtr);
318 return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
321 /*----------------------------------------------------------------------------
324 *----------------------------------------------------------------------------