AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / Tech / mtthrc.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mtthrc.c
6  *
7  * Phy assisted DQS receiver enable training
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/Tech)
12  * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 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  *                                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 "Filecode.h"
62 CODE_GROUP (G1_PEICC)
63 RDATA_GROUP (G2_PEI)
64
65 #define FILECODE PROC_MEM_TECH_MTTHRC_FILECODE
66 /*----------------------------------------------------------------------------
67  *                          DEFINITIONS AND MACROS
68  *
69  *----------------------------------------------------------------------------
70  */
71 #define TpProcMemRcvrSetSeed TpProcMemRcvrSetDelay
72 #define TpProcMemRcvrInitPRE TpProcMemRcvrStartSweep
73 #define TpProcMemRcvrBackToBackRead TpProcMemRcvrTestPattern
74
75 /*----------------------------------------------------------------------------
76  *                           TYPEDEFS AND STRUCTURES
77  *
78  *----------------------------------------------------------------------------
79  */
80
81 /*----------------------------------------------------------------------------
82  *                        PROTOTYPES OF LOCAL FUNCTIONS
83  *
84  *----------------------------------------------------------------------------
85  */
86
87 VOID
88 STATIC
89 MemTProgramRcvrEnDly (
90   IN OUT   MEM_TECH_BLOCK *TechPtr,
91   IN       UINT8 ChipSel,
92   IN       UINT8 Pass
93   );
94
95 BOOLEAN
96 STATIC
97 MemTDqsTrainRcvrEnHw (
98   IN OUT   MEM_TECH_BLOCK *TechPtr,
99   IN       UINT8 Pass
100   );
101
102 /*----------------------------------------------------------------------------
103  *                            EXPORTED FUNCTIONS
104  *
105  *----------------------------------------------------------------------------
106  */
107 extern UINT16 T1minToFreq[];
108
109 /* -----------------------------------------------------------------------------*/
110 /**
111  *
112  *      This function executes first pass of Phy assisted receiver enable training
113  *      for current node at DDR800 and below.
114  *
115  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
116  *
117  *     @pre   Auto refresh and ZQCL must be disabled
118  *
119  *     @return          TRUE -  No fatal error occurs.
120  *     @return          FALSE - Fatal error occurs.
121  */
122 BOOLEAN
123 MemTDqsTrainRcvrEnHwPass1 (
124   IN OUT   MEM_TECH_BLOCK *TechPtr
125   )
126 {
127   return MemTDqsTrainRcvrEnHw (TechPtr, 1);
128 }
129
130 /* -----------------------------------------------------------------------------*/
131 /**
132  *
133  *      This function executes second pass of Phy assisted receiver enable training
134  *      for current node at DDR1066 and above.
135  *
136  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
137  *
138  *     @pre   Auto refresh and ZQCL must be disabled
139  *
140  *     @return          TRUE -  No fatal error occurs.
141  *     @return          FALSE - Fatal error occurs.
142  */
143 BOOLEAN
144 MemTDqsTrainRcvrEnHwPass2 (
145   IN OUT   MEM_TECH_BLOCK *TechPtr
146   )
147 {
148   // If current speed is higher than start-up speed, do second pass of WL
149   if (TechPtr->NBPtr->DCTPtr->Timings.Speed > TechPtr->NBPtr->StartupSpeed) {
150     return MemTDqsTrainRcvrEnHw (TechPtr, 2);
151   }
152   return TRUE;
153 }
154
155 /*----------------------------------------------------------------------------
156  *                              LOCAL FUNCTIONS
157  *
158  *----------------------------------------------------------------------------
159  */
160
161 /* -----------------------------------------------------------------------------*/
162 /**
163  *
164  *      This function executes Phy assisted receiver enable training for current node.
165  *
166  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
167  *     @param[in]  Pass - Pass of the receiver training
168  *
169  *     @pre   Auto refresh and ZQCL must be disabled
170  *
171  */
172 BOOLEAN
173 STATIC
174 MemTDqsTrainRcvrEnHw (
175   IN OUT   MEM_TECH_BLOCK *TechPtr,
176   IN       UINT8 Pass
177   )
178 {
179   MEM_NB_BLOCK  *NBPtr;
180   UINT32 TestAddrRJ16;
181   UINT8  Dct;
182   UINT8  ChipSel;
183   NBPtr = TechPtr->NBPtr;
184
185   TechPtr->TrainingType = TRN_RCVR_ENABLE;
186
187   AGESA_TESTPOINT (TpProcMemReceiverEnableTraining , &(NBPtr->MemPtr->StdHeader));
188   IDS_HDT_CONSOLE (MEM_STATUS, "\nStart HW RxEn training\n");
189
190   // Set environment settings before training
191   MemTBeginTraining (TechPtr);
192   //
193   // Setup hardware training engine (if applicable)
194   //
195   NBPtr->FamilySpecificHook[SetupHwTrainingEngine] (NBPtr, &TechPtr->TrainingType);
196
197   for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
198     IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
199     NBPtr->SwitchDCT (NBPtr, Dct);
200     //training for each rank
201     for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL; (NBPtr->MCTPtr->Status[SbLrdimms])? ChipSel += 2: ChipSel++) {
202       if (NBPtr->GetSysAddr (NBPtr, ChipSel, &TestAddrRJ16)) {
203         if (!(NBPtr->MCTPtr->Status[SbLrdimms]) || ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << (ChipSel >> 1))) != 0)) {
204           // 1.Prepare the DIMMs for training
205           NBPtr->SetBitField (NBPtr, BFTrDimmSel, ChipSel >> 1);
206
207           TechPtr->ChipSel = ChipSel;
208           TechPtr->Pass = Pass;
209           NBPtr->FamilySpecificHook[InitPerNibbleTrn] (NBPtr, NULL);
210           for (TechPtr->TrnNibble = NIBBLE_0; TechPtr->TrnNibble <= (NBPtr->FamilySpecificHook[TrainRxEnPerNibble] (NBPtr, &ChipSel)? NIBBLE_0 : NIBBLE_1); TechPtr->TrnNibble++) {
211             // 2.Prepare the phy for DQS receiver enable training.
212             IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel);
213             IDS_HDT_CONSOLE (MEM_FLOW, "\t\tTestAddr %x0000\n", TestAddrRJ16);
214             IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t     Byte:  00  01  02  03  04  05  06  07  ECC\n");
215
216             AGESA_TESTPOINT (TpProcMemRcvrSetSeed, &(NBPtr->MemPtr->StdHeader));
217             NBPtr->MemNPrepareRcvrEnDlySeed (NBPtr);
218
219             AGESA_TESTPOINT (TpProcMemRcvrInitPRE, &(NBPtr->MemPtr->StdHeader));
220             // 3.BIOS initiates the phy assisted receiver enable training
221             NBPtr->SetBitField (NBPtr, BFDqsRcvTrEn, 1);
222
223             // 4.BIOS begins sending out of back-to-back reads to create
224             //   a continuous stream of DQS edges on the DDR interface
225             AGESA_TESTPOINT (TpProcMemRcvrBackToBackRead, &(NBPtr->MemPtr->StdHeader));
226             NBPtr->GenHwRcvEnReads (NBPtr, TestAddrRJ16);
227
228             // 7.Program [DqsRcvTrEn]=0 to stop the DQS receive enable training.
229             NBPtr->SetBitField (NBPtr, BFDqsRcvTrEn, 0);
230
231             // 8.Get the gross and fine delay values.
232             // 9.Calculate the corresponding final delay values
233             MemTProgramRcvrEnDly (TechPtr, ChipSel, Pass);
234           }
235         }
236       }
237     }
238   }
239   // Restore environment settings after training
240   MemTEndTraining (TechPtr);
241   IDS_HDT_CONSOLE (MEM_FLOW, "End HW RxEn training\n\n");
242
243   return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL);
244 }
245
246 /* -----------------------------------------------------------------------------*/
247 /**
248  *
249  *      This function calculates final RcvrEnDly for each rank
250  *
251  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
252  *     @param[in]  ChipSel - Rank to be trained
253  *     @param[in]  Pass - Pass of the receiver training
254  *
255  */
256 VOID
257 STATIC
258 MemTProgramRcvrEnDly (
259   IN OUT   MEM_TECH_BLOCK *TechPtr,
260   IN       UINT8 ChipSel,
261   IN       UINT8 Pass
262   )
263 {
264   MEM_NB_BLOCK  *NBPtr;
265   CH_DEF_STRUCT *ChannelPtr;
266   UINT8  ByteLane;
267   UINT16 RcvEnDly;
268   UINT16 CsPairRcvEnDly;
269   UINT16 RankRcvEnDly[9];
270   NBPtr = TechPtr->NBPtr;
271   ChannelPtr = TechPtr->NBPtr->ChannelPtr;
272   IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t      PRE: ");
273   for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8) ; ByteLane++) {
274     RcvEnDly = (UINT8) NBPtr->GetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (ChipSel >> 1, ByteLane));
275     IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RcvEnDly);
276
277     RcvEnDly = RcvEnDly + TechPtr->DiffSeedGrossSeedPreGross[ByteLane];
278
279     // Add 1 UI to get to the midpoint of preamble
280     RcvEnDly += 0x20;
281     TechPtr->Bytelane = ByteLane;
282     RankRcvEnDly[ByteLane] = RcvEnDly;
283     if (NBPtr->FamilySpecificHook[TrainRxEnAdjustDlyPerNibble] (NBPtr, &RcvEnDly)) {
284       if ((ChipSel & 1) == 1) {
285         // For each rank pair on a dual-rank DIMM, compute the average value of the total delays saved during the
286         //  training of each rank and program the result in D18F2x[1,0]9C_x0000_00[24:10][DqsRcvEnGrossDelay,
287         //  DqsRcvEnFineDelay].
288         CsPairRcvEnDly = ChannelPtr->RcvEnDlys[(ChipSel >> 1) * TechPtr->DlyTableWidth () + ByteLane];
289         RcvEnDly = (CsPairRcvEnDly + RcvEnDly + 1) / 2;
290       }
291     }
292     ChannelPtr->RcvEnDlys[(ChipSel >> 1) * TechPtr->DlyTableWidth () + ByteLane] = RcvEnDly;
293     NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS ((ChipSel >> 1), ByteLane), RcvEnDly);
294   }
295
296   IDS_HDT_CONSOLE_DEBUG_CODE (
297     IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t     RxEn: ");
298     for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
299       IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RankRcvEnDly[ByteLane]);
300     }
301     if (NBPtr->FamilySpecificHook[TrainRxEnGetAvgDlyPerNibble] (NBPtr, NULL)) {
302       if ((ChipSel & 1) == 1) {
303         IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t      Avg: ");
304         for (ByteLane = 0; ByteLane < (NBPtr->MCTPtr->Status[SbEccDimms] ? 9 : 8); ByteLane++) {
305           IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", ChannelPtr->RcvEnDlys[(ChipSel >> 1) * TechPtr->DlyTableWidth () + ByteLane]);
306         }
307       }
308     }
309     IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
310   );
311 }