AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Recovery / Mem / Tech / mrtthrc.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mrtthrc.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: (Proc/Recovery/Mem)
12  * @e \$Revision: 50454 $ @e \$Date: 2011-04-10 21:20:37 -0600 (Sun, 10 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  *                                MODULES USED
49  *
50  *----------------------------------------------------------------------------
51  */
52
53
54
55 #include "AGESA.h"
56 #include "OptionMemory.h"
57 #include "amdlib.h"
58 #include "Ids.h"
59 #include "mm.h"
60 #include "mn.h"
61 #include "mru.h"
62 #include "mt.h"
63 #include "PlatformMemoryConfiguration.h"
64 #include "Filecode.h"
65 CODE_GROUP (G2_PEI)
66 RDATA_GROUP (G2_PEI)
67
68 #define FILECODE PROC_RECOVERY_MEM_TECH_MRTTHRC_FILECODE
69 /*----------------------------------------------------------------------------
70  *                          DEFINITIONS AND MACROS
71  *
72  *----------------------------------------------------------------------------
73  */
74 #define MAX_BYTELANES 8             /* Max Bytelanes per channel */
75
76 /*----------------------------------------------------------------------------
77  *                           TYPEDEFS AND STRUCTURES
78  *
79  *----------------------------------------------------------------------------
80  */
81
82 /*----------------------------------------------------------------------------
83  *                        PROTOTYPES OF LOCAL FUNCTIONS
84  *
85  *----------------------------------------------------------------------------
86  */
87
88 VOID
89 STATIC
90 MemRecTPrepareRcvrEnDlySeed (
91   IN OUT   MEM_TECH_BLOCK *TechPtr,
92   IN       UINT8 ChipSel
93   );
94
95 UINT16
96 STATIC
97 MemRecTProgramRcvrEnDly (
98   IN OUT   MEM_TECH_BLOCK *TechPtr,
99   IN       UINT8 ChipSel
100   );
101
102 /*----------------------------------------------------------------------------
103  *                            EXPORTED FUNCTIONS
104  *
105  *----------------------------------------------------------------------------
106  */
107
108 /* -----------------------------------------------------------------------------*/
109 /**
110  *
111  *      This function executes Phy assisted receiver enable training for current node.
112  *
113  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
114  *
115  *     @pre   Auto refresh and ZQCL must be disabled
116  *
117  */
118 VOID
119 MemRecTTrainRcvrEnHw (
120   IN OUT   MEM_TECH_BLOCK *TechPtr
121   )
122 {
123   UINT8  TempBuffer[64];
124   UINT8  Count;
125   UINT32 TestAddr;
126   UINT8  ChipSel;
127   UINT16 MaxRcvrDly;
128   MEM_NB_BLOCK  *NBPtr;
129
130   NBPtr = TechPtr->NBPtr;
131
132   AGESA_TESTPOINT (TpProcMemReceiverEnableTraining , &(NBPtr->MemPtr->StdHeader));
133   IDS_HDT_CONSOLE (MEM_STATUS, "\nStart HW RxEn training\n");
134
135   // Set environment settings before training
136   MemRecTBeginTraining (TechPtr);
137
138   ChipSel = NBPtr->DimmToBeUsed << 1;
139   TestAddr = 1 << 21;
140
141   IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", TechPtr->NBPtr->Dct);
142   IDS_HDT_CONSOLE (MEM_STATUS, "\t\tCS %d\n", ChipSel);
143   IDS_HDT_CONSOLE (MEM_FLOW, "\t\tTestAddr %x\n", TestAddr);
144   IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t     Byte:  00  01  02  03  04  05  06  07  ECC\n");
145
146   // 1.Prepare the DIMMs for training
147   NBPtr->SetBitField (NBPtr, BFTrDimmSel, ChipSel >> 1);
148
149   // 2.Prepare the phy for DQS receiver enable training.
150   MemRecTPrepareRcvrEnDlySeed (TechPtr, ChipSel);
151
152   // 3.BIOS initiates the phy assisted receiver enable training
153   NBPtr->SetBitField (NBPtr, BFDqsRcvTrEn, 1);
154
155   // 4.BIOS begins sending out of back-to-back reads to create
156   //   a continuous stream of DQS edges on the DDR interface.
157   for (Count = 0; Count < 3; Count++) {
158     NBPtr->ReadPattern (NBPtr, TempBuffer, TestAddr, 64);
159   }
160
161   // 6.Wait 200 MEMCLKs.
162   MemRecUWait10ns (200, NBPtr->MemPtr);
163
164   // 7.Program [DqsRcvTrEn]=0 to stop the DQS receive enable training.
165   NBPtr->SetBitField (NBPtr, BFDqsRcvTrEn, 0);
166
167   // 8.Get the gross and fine delay values.
168   // 9.Calculate the corresponding final delay values
169   MaxRcvrDly = MemRecTProgramRcvrEnDly (TechPtr, ChipSel);
170
171   // Set Max Latency for both channels
172   NBPtr->SetMaxLatency (NBPtr, MaxRcvrDly);
173
174   // Restore environment settings after training
175   MemRecTEndTraining (TechPtr);
176   IDS_HDT_CONSOLE (MEM_FLOW, "End HW RxEn training\n\n");
177 }
178
179
180 /* -----------------------------------------------------------------------------*/
181 /**
182  *
183  *      This function calculates RcvEn seed value for each rank
184  *
185  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
186  *     @param[in]  ChipSel - rank to be trained
187  *
188  */
189 VOID
190 STATIC
191 MemRecTPrepareRcvrEnDlySeed (
192   IN OUT   MEM_TECH_BLOCK *TechPtr,
193   IN       UINT8 ChipSel
194   )
195 {
196   MEM_NB_BLOCK  *NBPtr;
197   CH_DEF_STRUCT *ChannelPtr;
198   UINT16 SeedTotal;
199   UINT16 SeedFine;
200   UINT16 SeedGross;
201   UINT16 SeedPreGross;
202   UINT16 DiffSeedGrossSeedPreGross;
203   UINT8  ByteLane;
204   UINT16 PlatEst;
205   UINT16 *PlatEstSeed;
206   UINT16 SeedValue[8];
207   UINT16 SeedTtl[8];
208   UINT16 SeedPre[8];
209
210   NBPtr = TechPtr->NBPtr;
211   ChannelPtr = TechPtr->NBPtr->ChannelPtr;
212
213   // Get platform override seed
214   PlatEstSeed = (UINT16 *) MemRecFindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_RXEN_SEED, NBPtr->MCTPtr->SocketId, ChannelPtr->ChannelID, ChipSel >> 1);
215
216   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
217     // For Pass1, BIOS starts with the delay value obtained from the first pass of write
218     // levelization training that was done in DDR3 Training and add a delay value of 3Bh.
219     PlatEst = 0x3B;
220     NBPtr->FamilySpecificHook[OverrideRcvEnSeed] (NBPtr, &PlatEst);
221     PlatEst = ((PlatEstSeed != NULL) ? PlatEstSeed[ByteLane] : PlatEst);
222     SeedTotal = ChannelPtr->WrDqsDlys[((ChipSel >> 1) * MAX_BYTELANES) + ByteLane] + PlatEst;
223     SeedValue[ByteLane] = PlatEst;
224     SeedTtl[ByteLane] = SeedTotal;
225     // SeedGross = SeedTotal DIV 32.
226     SeedGross = SeedTotal >> 5;
227     // SeedFine = SeedTotal MOD 32.
228     SeedFine = SeedTotal & 0x1F;
229
230     // Next, determine the gross component of SeedTotal. SeedGrossPass1=SeedTotal DIV 32.
231     // Then, determine the fine delay component of SeedTotal. SeedFinePass1=SeedTotal MOD 32.
232     // Use SeedGrossPass1 to determine SeedPreGrossPass1:
233
234     if ((SeedGross & 0x1) != 0) {
235       //if SeedGross is odd
236       SeedPreGross = 1;
237     } else {
238       //if SeedGross is even
239       SeedPreGross = 2;
240     }
241
242     // (SeedGross - SeedPreGross)
243     DiffSeedGrossSeedPreGross = SeedGross - SeedPreGross;
244
245     ChannelPtr->RcvEnDlys[(ChipSel * MAX_BYTELANES) + ByteLane] =  DiffSeedGrossSeedPreGross << 5;
246
247     //BIOS programs registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52) with SeedPreGrossPass1
248     //and SeedFinePass1 from the preceding steps.
249     NBPtr->SetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (ChipSel >> 1, ByteLane), (SeedPreGross << 5) | SeedFine);
250     SeedPre[ByteLane] = (SeedPreGross << 5) | SeedFine;
251
252     // 202688: Program seed value to RcvEnDly also.
253     NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (ChipSel >> 1, ByteLane), SeedGross << 5);
254   }
255   IDS_HDT_CONSOLE_DEBUG_CODE (
256    IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSeedValue: ");
257   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
258     IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", SeedValue[ByteLane]);
259   }
260   IDS_HDT_CONSOLE (MEM_FLOW, "\n");
261
262   IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tSeedTotal: ");
263   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
264     IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", SeedTtl[ByteLane]);
265   }
266   IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t  SeedPRE: ");
267   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
268     IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", SeedPre[ByteLane]);
269   }
270   IDS_HDT_CONSOLE (MEM_FLOW, "\n");
271   );
272 }
273
274 /* -----------------------------------------------------------------------------*/
275 /**
276  *
277  *      This function calculates final RcvrEnDly for each rank
278  *
279  *     @param[in,out]   *TechPtr   - Pointer to the MEM_TECH_BLOCK
280  *     @param[in]  ChipSel - Rank to be trained
281  *
282  *     @return   MaxDly - The largest delay value
283  *
284  */
285 UINT16
286 STATIC
287 MemRecTProgramRcvrEnDly (
288   IN OUT   MEM_TECH_BLOCK *TechPtr,
289   IN       UINT8 ChipSel
290   )
291 {
292   MEM_NB_BLOCK  *NBPtr;
293   CH_DEF_STRUCT *ChannelPtr;
294   UINT16 DiffSeedGrossSeedPreGross;
295   UINT8  ByteLane;
296   UINT16 RcvEnDly;
297   UINT16 MaxDly;
298   UINT16 RankRcvEnDly[8];
299   NBPtr = TechPtr->NBPtr;
300   ChannelPtr = TechPtr->NBPtr->ChannelPtr;
301   IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\t      PRE: ");
302   MaxDly = 0;
303   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
304     DiffSeedGrossSeedPreGross = (ChannelPtr->RcvEnDlys[(ChipSel * MAX_BYTELANES) + ByteLane]) & 0x1E0;
305     RcvEnDly = (UINT8) NBPtr->GetTrainDly (NBPtr, AccessPhRecDly, DIMM_BYTE_ACCESS (ChipSel >> 1, ByteLane));
306     IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RcvEnDly);
307
308     RcvEnDly = RcvEnDly + DiffSeedGrossSeedPreGross;
309
310     // Add 1 UI to get to the midpoint of preamble
311     RcvEnDly += 0x20;
312     RankRcvEnDly[ByteLane] = RcvEnDly;
313
314     if (RcvEnDly > MaxDly) {
315       MaxDly = RcvEnDly;
316     }
317
318     NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS ((ChipSel >> 1), ByteLane), RcvEnDly);
319   }
320   IDS_HDT_CONSOLE_DEBUG_CODE (
321    IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\t\t     RxEn: ");
322   for (ByteLane = 0; ByteLane < 8; ByteLane++) {
323     IDS_HDT_CONSOLE (MEM_FLOW, "%03x ", RankRcvEnDly[ByteLane]);
324   }
325     IDS_HDT_CONSOLE (MEM_FLOW, "\n\n");
326   );
327   return MaxDly;
328 }
329