AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Feat / TABLE / mftds.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mftds.c
6  *
7  * Northbridge table drive support file for DR
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/Feat/TABLE)
12  * @e \$Revision: 51024 $ @e \$Date: 2011-04-18 06:02:44 -0600 (Mon, 18 Apr 2011) $
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 #include "AGESA.h"
49 #include "amdlib.h"
50 #include "mm.h"
51 #include "mn.h"
52 #include "mt.h"
53 #include "mftds.h"
54 #include "Ids.h"
55 #include "OptionMemory.h"
56 #include "Filecode.h"
57 CODE_GROUP (G2_PEI)
58 RDATA_GROUP (G2_PEI)
59
60 #define FILECODE PROC_MEM_FEAT_TABLE_MFTDS_FILECODE
61 /*----------------------------------------------------------------------------
62  *   Mixed (DEFINITIONS AND MACROS / TYPEDEFS, STRUCTURES, ENUMS)
63  *
64  *----------------------------------------------------------------------------
65  */
66
67 /*-----------------------------------------------------------------------------
68  *                         DEFINITIONS AND MACROS
69  *
70  *-----------------------------------------------------------------------------
71  */
72 #define MAX_BYTELANES_PER_CHANNEL   (8 + 1)  ///< Max Bytelanes per channel
73
74 /*----------------------------------------------------------------------------
75  *                         TYPEDEFS, STRUCTURES, ENUMS
76  *
77  *----------------------------------------------------------------------------
78  */
79
80 /*----------------------------------------------------------------------------
81  *                           FUNCTIONS PROTOTYPE
82  *
83  *----------------------------------------------------------------------------
84  */
85
86 VOID
87 SetTableValues (
88   IN OUT   MEM_NB_BLOCK *NBPtr,
89   IN       MEM_TABLE_ALIAS MTPtr
90   );
91
92 VOID
93 SetTableValuesLoop (
94   IN OUT   MEM_NB_BLOCK *NBPtr,
95   IN       MEM_TABLE_ALIAS *MTPtr,
96   IN       UINT8     time
97   );
98
99 /*-----------------------------------------------------------------------------
100  *
101  *   This function initializes bit field translation table
102  *
103  *     @param[in,out]   *NBPtr   - Pointer to the MEM_TABLE_ALIAS structure
104  *     @param[in]       time     - Indicate the timing for the register which is written.
105  *
106  *     @return          None
107  * ----------------------------------------------------------------------------
108  */
109 VOID
110 MemFInitTableDrive (
111   IN OUT   MEM_NB_BLOCK *NBPtr,
112   IN       UINT8     time
113   )
114 {
115   MEM_TABLE_ALIAS *MTPtr;
116   MEM_TABLE_ALIAS *IdsMTPtr;
117
118   ASSERT (NBPtr != NULL);
119   IdsMTPtr = NULL;
120   IDS_HDT_CONSOLE (MEM_FLOW, "MemFInitTableDrive [%X] Start\n", time);
121   MTPtr = (MEM_TABLE_ALIAS *) NBPtr->RefPtr->TableBasedAlterations;
122
123   IDS_SKIP_HOOK (IDS_GET_DRAM_TABLE, &IdsMTPtr, &(NBPtr->MemPtr->StdHeader)) {
124     IDS_OPTION_HOOK (IDS_INIT_DRAM_TABLE, NBPtr, &(NBPtr->MemPtr->StdHeader));
125     IDS_OPTION_HOOK (IDS_GET_DRAM_TABLE, &IdsMTPtr, &(NBPtr->MemPtr->StdHeader));
126   }
127
128   SetTableValuesLoop (NBPtr, MTPtr, time);
129   SetTableValuesLoop (NBPtr, IdsMTPtr, time);
130
131   IDS_OPTION_HOOK (IDS_MT_BASE + time, NBPtr, &(NBPtr->MemPtr->StdHeader));
132   IDS_HDT_CONSOLE (MEM_FLOW, "MemFInitTableDrive End\n");
133 }
134
135 /*-----------------------------------------------------------------------------
136  *
137  *   This function initializes bit field translation table
138  *
139  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
140  *     @param[in,out]   *MTPtr   - Pointer to the MEM_TABLE_ALIAS structure
141  *     @param[in]       time     - Indicate the timing for the register which is written.
142  *
143  *     @return          None
144  * ----------------------------------------------------------------------------
145  */
146 VOID
147 SetTableValuesLoop (
148   IN OUT   MEM_NB_BLOCK *NBPtr,
149   IN       MEM_TABLE_ALIAS *MTPtr,
150   IN       UINT8     time
151   )
152 {
153   UINT8 i;
154   UINT8 CurDct;
155
156   if (MTPtr != NULL) {
157     CurDct = NBPtr->Dct;
158     for (i = 0; MTPtr[i].time != MTEnd; i++) {
159       if ((MTPtr[i].attr != MTAuto) && (MTPtr[i].time == time)) {
160         SetTableValues (NBPtr, MTPtr[i]);
161       }
162     }
163     NBPtr->SwitchDCT (NBPtr, CurDct);
164   }
165 }
166
167 /*-----------------------------------------------------------------------------
168  *
169  *   Engine for setting Table Value.
170  *
171  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
172  *     @param[in]       MTPtr    - Pointer to the MEM_TABLE_ALIAS structure
173  *
174  *     @return      None
175  * ----------------------------------------------------------------------------
176  */
177 VOID
178 SetTableValues (
179   IN OUT   MEM_NB_BLOCK *NBPtr,
180   IN       MEM_TABLE_ALIAS MTPtr
181   )
182 {
183   UINT8 AccessType;
184   UINT16 ByteLane;
185   UINT8 Dct;
186   UINT8 i;
187   UINT8 j;
188   UINT32 TempVal[36];
189   UINT32 Temp2Val[72];
190   UINT8 *DqsSavePtr;
191   UINT8  DqsOffset;
192   BOOLEAN SaveDqs;
193
194   AccessType = 0;
195   DqsSavePtr = NULL;
196   SaveDqs = TRUE;
197
198   ASSERT (MTPtr.time <= MTValidTimePointLimit);
199   ASSERT (MTPtr.attr <= MTOr);
200   ASSERT (MTPtr.node <= MTNodes);
201   ASSERT (MTPtr.dct <= MTDcts);
202   ASSERT (MTPtr.dimm <= MTDIMMs);
203   ASSERT (MTPtr.data.s.bytelane <= MTBLs);
204
205   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
206     if ((MTPtr.dct == MTDcts) || (MTPtr.dct == Dct)) {
207       NBPtr->SwitchDCT (NBPtr, Dct);
208       switch (MTPtr.bfindex) {
209       case BFRcvEnDly:
210         AccessType = AccessRcvEnDly;
211         DqsSavePtr = NULL;
212         break;
213       case BFWrDatDly:
214         AccessType = AccessWrDatDly;
215         DqsSavePtr = NBPtr->ChannelPtr->WrDatDlys;
216         break;
217       case BFRdDqsDly:
218         AccessType = AccessRdDqsDly;
219         DqsSavePtr = NBPtr->ChannelPtr->RdDqsDlys;
220         break;
221       case BFWrDqsDly:
222         AccessType = AccessWrDqsDly;
223         DqsSavePtr = NBPtr->ChannelPtr->WrDqsDlys;
224         break;
225       case BFRdDqs__Dly:
226         AccessType = AccessRdDqs__Dly;
227         DqsSavePtr = NBPtr->ChannelPtr->RdDqs__Dlys;
228         break;
229       case BFPhRecDly:
230         AccessType = AccessPhRecDly;
231         SaveDqs = FALSE;
232         break;
233       default:
234         AccessType = 0xFF;
235         break;
236       }
237       if (AccessType == 0xFF) {
238         if (MTPtr.attr == MTOverride) {
239           NBPtr->SetBitField (NBPtr, MTPtr.bfindex, MTPtr.data.s.value);
240         }
241         if (MTPtr.attr == MTSubtract) {
242           NBPtr->SetBitField (NBPtr, MTPtr.bfindex, NBPtr->GetBitField (NBPtr, MTPtr.bfindex) - MTPtr.data.s.value);
243         }
244         if (MTPtr.attr == MTAdd) {
245           NBPtr->SetBitField (NBPtr, MTPtr.bfindex, NBPtr->GetBitField (NBPtr, MTPtr.bfindex) + MTPtr.data.s.value);
246         }
247         if (MTPtr.attr == MTAnd) {
248           NBPtr->SetBitField (NBPtr, MTPtr.bfindex, (NBPtr->GetBitField (NBPtr, MTPtr.bfindex) & MTPtr.data.s.value));
249         }
250         if (MTPtr.attr == MTOr) {
251           NBPtr->SetBitField (NBPtr, MTPtr.bfindex, (NBPtr->GetBitField (NBPtr, MTPtr.bfindex) | MTPtr.data.s.value));
252         }
253       } else {
254         // Store the DQS data first
255         for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
256           if (AccessType == AccessRdDqs__Dly) {
257             for (j = 0; j < MAX_NUMBER_LANES; j++) {
258               Temp2Val[i * MAX_NUMBER_LANES + j] = NBPtr->GetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j));
259             }
260           } else {
261             for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
262               TempVal[i * MAX_BYTELANES_PER_CHANNEL + j] = NBPtr->GetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i, j));
263             }
264           }
265         }
266         //
267         // Single Value with Bytleane mask option
268         //   Indicated by the vtype flag
269         //
270         if (MTPtr.vtype == VT_MSK_VALUE) {
271           // set the value which defined in Memory table.
272           for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
273             ByteLane = MTPtr.data.s.bytelane;
274             if ((MTPtr.dimm == MTDIMMs) || (MTPtr.dimm == i)) {
275               if (AccessType == AccessRdDqs__Dly) {
276                 for (j = 0; j < MAX_NUMBER_LANES; j++) {
277                   DqsOffset = (i * MAX_NUMBER_LANES + j);
278                   if ((ByteLane & (UINT16)1) != 0) {
279                     if (MTPtr.attr == MTOverride) {
280                       Temp2Val[DqsOffset] = (UINT16)MTPtr.data.s.value;
281                     }
282                     if (MTPtr.attr == MTSubtract) {
283                       Temp2Val[DqsOffset] -= (UINT16)MTPtr.data.s.value;
284                     }
285                     if (MTPtr.attr == MTAdd) {
286                       Temp2Val[DqsOffset] += (UINT16)MTPtr.data.s.value;
287                     }
288                     NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j), (UINT16)Temp2Val[DqsOffset]);
289                     if (SaveDqs) {
290                       if (DqsSavePtr == NULL) {
291                         NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)TempVal[DqsOffset];
292                       } else {
293                         DqsSavePtr[DqsOffset] = (UINT8)Temp2Val[DqsOffset];
294                       }
295                     }
296                   }
297                   ByteLane = ByteLane >> (UINT16)1;
298                 }
299               } else {
300                 for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
301                   DqsOffset = (i * MAX_BYTELANES_PER_CHANNEL + j);
302                   if ((ByteLane & (UINT16)1) != 0) {
303                     if (MTPtr.attr == MTOverride) {
304                       TempVal[DqsOffset] = (UINT16)MTPtr.data.s.value;
305                     }
306                     if (MTPtr.attr == MTSubtract) {
307                       TempVal[DqsOffset] -= (UINT16)MTPtr.data.s.value;
308                     }
309                     if (MTPtr.attr == MTAdd) {
310                       TempVal[DqsOffset] += (UINT16)MTPtr.data.s.value;
311                     }
312                     NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i, j), (UINT16)TempVal[DqsOffset]);
313                     if (SaveDqs) {
314                       if (DqsSavePtr == NULL) {
315                         NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)TempVal[DqsOffset];
316                       } else {
317                         DqsSavePtr[DqsOffset] = (UINT8)TempVal[DqsOffset];
318                       }
319                     }
320                   }
321                   ByteLane = ByteLane >> (UINT16)1;
322                 }
323               }
324             }
325           }
326         } else {
327           // Multiple values specified in a byte array
328           for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
329             if ((MTPtr.dimm == MTDIMMs) || (MTPtr.dimm == i)) {
330               if (AccessType == AccessRdDqs__Dly) {
331                 for (j = 0; j < MAX_NUMBER_LANES; j++) {
332                   DqsOffset = (i * MAX_NUMBER_LANES + j);
333                   if (MTPtr.attr == MTOverride) {
334                     Temp2Val[DqsOffset] = MTPtr.data.bytelanevalue[j];
335                   }
336                   if (MTPtr.attr == MTSubtract) {
337                     Temp2Val[DqsOffset] -= MTPtr.data.bytelanevalue[j];
338                   }
339                   if (MTPtr.attr == MTAdd) {
340                     Temp2Val[DqsOffset] += MTPtr.data.bytelanevalue[j];
341                   }
342                   NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j), (UINT16)Temp2Val[DqsOffset]);
343                   if (SaveDqs) {
344                     if (DqsSavePtr == NULL) {
345                       NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)Temp2Val[DqsOffset];
346                     } else {
347                       DqsSavePtr[DqsOffset] = (UINT8)Temp2Val[DqsOffset];
348                     }
349                   }
350                 }
351               } else {
352                 for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
353                   DqsOffset = (i * MAX_BYTELANES_PER_CHANNEL + j);
354                   if (MTPtr.attr == MTOverride) {
355                     TempVal[DqsOffset] = MTPtr.data.bytelanevalue[j];
356                   }
357                   if (MTPtr.attr == MTSubtract) {
358                     TempVal[DqsOffset] -= MTPtr.data.bytelanevalue[j];
359                   }
360                   if (MTPtr.attr == MTAdd) {
361                     TempVal[DqsOffset] += MTPtr.data.bytelanevalue[j];
362                   }
363                   NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i, j), (UINT16)TempVal[DqsOffset]);
364                   if (SaveDqs) {
365                     if (DqsSavePtr == NULL) {
366                       NBPtr->ChannelPtr->RcvEnDlys[DqsOffset] = (UINT16)TempVal[DqsOffset];
367                     } else {
368                       DqsSavePtr[DqsOffset] = (UINT8)TempVal[DqsOffset];
369                     }
370                   }
371                 }
372               }
373             }
374           }
375         }
376         // set the DQS value to left DIMMs.
377         i = MTPtr.dimm;
378         while ((i != MTDIMMs) && ((++i) < MAX_DIMMS_PER_CHANNEL)) {
379           if (AccessType == AccessRdDqs__Dly) {
380             for (j = 0; j < MAX_NUMBER_LANES; j++) {
381               NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_NBBL_ACCESS (i, j), (UINT16)Temp2Val[i * MAX_BYTELANES_PER_CHANNEL + j]);
382             }
383           } else {
384             for (j = 0; j < MAX_BYTELANES_PER_CHANNEL; j++) {
385               NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (i, j), (UINT16)TempVal[i * MAX_BYTELANES_PER_CHANNEL + j]);
386             }
387           }
388         }
389       }
390     }
391   }
392 }
393
394
395
396
397
398