AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Recovery / Mem / Tech / DDR3 / mrtspd3.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mrtspd3.c
6  *
7  * Technology SPD supporting functions for DDR3 Recovery
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Proc/Recovery/Mem)
12  * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 02:16:51 -0700 (Wed, 22 Dec 2010) $
13  *
14  **/
15 /*****************************************************************************
16 *
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
19 *
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.
30 *
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.
41 *
42 * ***************************************************************************
43 *
44 */
45
46 /*
47  *----------------------------------------------------------------------------
48  *                                MODULES USED
49  *
50  *----------------------------------------------------------------------------
51  */
52
53
54
55 #include "AGESA.h"
56 #include "amdlib.h"
57 #include "Ids.h"
58 #include "mm.h"
59 #include "mn.h"
60 #include "mt.h"
61 #include "mrtspd3.h"
62 #include "Filecode.h"
63 CODE_GROUP (G2_PEI)
64 RDATA_GROUP (G2_PEI)
65
66 #define FILECODE PROC_RECOVERY_MEM_TECH_DDR3_MRTSPD3_FILECODE
67
68 /*----------------------------------------------------------------------------
69  *                          DEFINITIONS AND MACROS
70  *
71  *----------------------------------------------------------------------------
72  */
73 #define _UNDEF_ 0xFF
74 #define MAX_DIES_PER_SOCKET     2   ///< Set to largest of any CPU
75
76 /*----------------------------------------------------------------------------
77  *                           TYPEDEFS AND STRUCTURES
78  *
79  *----------------------------------------------------------------------------
80  */
81
82 /*----------------------------------------------------------------------------
83  *                        PROTOTYPES OF LOCAL FUNCTIONS
84  *
85  *----------------------------------------------------------------------------
86  */
87
88 /*----------------------------------------------------------------------------
89  *                            EXPORTED FUNCTIONS
90  *
91  *----------------------------------------------------------------------------
92  */
93
94
95 /* -----------------------------------------------------------------------------*/
96 /**
97  *
98  *   This function sets the DRAM mode
99  *
100  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
101  *
102  *     @return  TRUE - indicates that the DRAM mode is set to DDR2
103  */
104
105 BOOLEAN
106 MemRecTSetDramMode3 (
107   IN OUT   MEM_TECH_BLOCK *TechPtr
108   )
109 {
110   TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFLegacyBiosMode, 0);
111   TechPtr->NBPtr->SetBitField (TechPtr->NBPtr, BFDdr3Mode, 1);
112   return TRUE;
113 }
114
115 /* -----------------------------------------------------------------------------*/
116 /**
117  *
118  *   This function determines if DIMMs are present. It checks checksum and interrogates the SPDs
119  *
120  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
121  *
122  *     @return  TRUE - indicates that a FATAL error has not occurred
123  *     @return  FALL - indicates that a FATAL error has not occurred
124  */
125
126 BOOLEAN
127 MemRecTDIMMPresence3 (
128   IN OUT   MEM_TECH_BLOCK *TechPtr
129   )
130 {
131   UINT8 Node;
132   UINT8 Dct;
133   UINT8 Channel;
134   UINT8 i;
135   SPD_DEF_STRUCT *SPDPtr;
136   UINT8 *SpdBufferPtr;
137   DIE_STRUCT *MCTPtr;
138   DCT_STRUCT *DCTPtr;
139   CH_DEF_STRUCT *ChannelPtr;
140   MEM_NB_BLOCK *NBPtr;
141   UINT16 MaxDimms;
142   UINT16 Value16;
143   UINT8 Devwidth;
144   UINT8 Value8;
145   UINT16 DimmMask;
146   UINT8 VoltageMap;
147   UINT8 VDDByte;
148   UINT32 V1_2XDimmMap;
149   UINT32 V1_35DimmMap;
150   UINT32 V1_5DimmMap;
151
152   NBPtr = TechPtr->NBPtr;
153   MCTPtr = NBPtr->MCTPtr;
154   VoltageMap = 0xFF;
155   V1_2XDimmMap = 0;
156   V1_35DimmMap = 0;
157   V1_5DimmMap = 0;
158
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;
169
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;
175
176           if (SPDPtr[i].DimmPresent) {
177             SpdBufferPtr = (UINT8 *)&(SPDPtr[i].Data);
178
179             MCTPtr->DimmPresent |= DimmMask;
180             if (SpdBufferPtr[SPD_TYPE] == JED_DDR3SDRAM) {
181               ChannelPtr->ChDimmValid |= DimmMask;
182             }
183
184             //  Check module type information.
185             if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_RDIMM || SpdBufferPtr[SPD_DIMM_TYPE] == JED_MINIRDIMM) {
186               ChannelPtr->RegDimmPresent |= DimmMask;
187             }
188
189             if (SpdBufferPtr[SPD_DIMM_TYPE] == JED_SODIMM) {
190               ChannelPtr->SODimmPresent |= DimmMask;
191             }
192
193             //  Get the Dimm width data
194             Devwidth = SpdBufferPtr[SPD_DEV_WIDTH] & 0x7;
195             switch (Devwidth) {
196             case 0:
197               ChannelPtr->Dimmx4Present |= DimmMask;
198               Devwidth = 4;
199               break;
200             case 1:
201               ChannelPtr->Dimmx8Present |= DimmMask;
202               Devwidth = 8;
203               break;
204             case 2:
205               ChannelPtr->Dimmx16Present |= DimmMask;
206               Devwidth = 16;
207               break;
208             default:
209               IDS_ERROR_TRAP;
210             }
211
212             //  Determine the page size.
213             //       page_size = 2^COLBITS * Devwidth/8
214             //
215             Value16 = (((UINT16) 1 << (SpdBufferPtr[SPD_COL_SZ]&7)) * Devwidth) / 8;
216             if ((Value16 >> 11) == 0) {
217               DCTPtr->Timings.DIMM1KPage |= DimmMask;
218             }
219
220             //  Calculate bus loading per Channel
221             if (Devwidth == 16) {
222               Devwidth = 4;
223             } else if (Devwidth == 4) {
224               Devwidth = 16;
225             }
226
227             //  specify the number of ranks
228             Value8 = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
229             if (Value8 > 2) {
230               ChannelPtr->DimmQrPresent |= DimmMask;
231               Devwidth = Devwidth << 2;
232             } else if (Value8 == 2) {
233               ChannelPtr->DimmDrPresent |= DimmMask;   //  Dual rank dimms
234               Devwidth = Devwidth << 1;
235             } else {
236               ChannelPtr->DimmSRPresent |= DimmMask;
237             }
238
239             ChannelPtr->Ranks = ChannelPtr->Ranks + Value8;
240             ChannelPtr->Loads = ChannelPtr->Loads + Devwidth;
241             ChannelPtr->Dimms++;
242
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;
247               }
248             }
249
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;
254             //
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
257             //
258             ChannelPtr->CtrlWrd02[i] = SpdBufferPtr[SPD_ADDRMAP] & 0x03;
259
260             // Get the common voltage if possible and create the individual Dimm maps per voltage
261             VDDByte = SpdBufferPtr[SPD_MNVVDD];
262             VDDByte ^= 1;
263             VoltageMap &= VDDByte;
264             //
265             // Create the Dimms map
266             //
267             // Node:            1         0
268             // Dct:          1    0    1    0
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);
277             } else {
278               V1_5DimmMap |= (UINT32) DimmMask << ((Node * NBPtr->MCTPtr->DctCount + Dct) * MAX_DIMMS_PER_CHANNEL);
279             }
280           } // if DIMM present
281         } // Dimm loop
282       } // Channel loop
283     } // DCT loop
284   }
285
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);
291       } else {
292         i = (UINT8) LibAmdBitScanForward (V1_2XDimmMap);
293       }
294     } else {
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);
301       }
302     }
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);
309   }
310
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);
316   }
317
318   return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL);
319 }
320
321 /*----------------------------------------------------------------------------
322  *                              LOCAL FUNCTIONS
323  *
324  *----------------------------------------------------------------------------
325  */