Bring Fam10 memory controller init up to date with the latest AMD BKDG
[coreboot.git] / src / northbridge / amd / amdmct / mct / mcttmrl.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20
21 /*
22  * Description: Max Read Latency Training feature for DDR 2 MCT
23  */
24
25 static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr);
26 static u32 GetMaxRdLatTestAddr_D(struct MCTStatStruc *pMCTstat,
27                                 struct DCTStatStruc *pDCTstat, u8 Channel,
28                                 u8 *MaxRcvrEnDly, u8 *valid);
29 u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
30                                 struct DCTStatStruc *pDCTstat, u8 Channel,
31                                 u8 DQSRcvEnDly, u32 *Margin);
32 static void maxRdLatencyTrain_D(struct MCTStatStruc *pMCTstat,
33                                 struct DCTStatStruc *pDCTstat);
34 static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat, u8 Channel,
35                                         u16 MaxRdLatVal);
36
37 /*Warning:  These must be located so they do not cross a logical 16-bit
38    segment boundary!*/
39 static const u32 TestMaxRdLAtPattern_D[] = {
40         0x6E0E3FAC, 0x0C3CFF52,
41         0x4A688181, 0x49C5B613,
42         0x7C780BA6, 0x5C1650E3,
43         0x0C4F9D76, 0x0C6753E6,
44         0x205535A5, 0xBABFB6CA,
45         0x610E6E5F, 0x0C5F1C87,
46         0x488493CE, 0x14C9C383,
47         0xF5B9A5CD, 0x9CE8F615,
48
49         0xAAD714B5, 0xC38F1B4C,
50         0x72ED647C, 0x669F7562,
51         0x5233F802, 0x4A898B30,
52         0x10A40617, 0x3326B465,
53         0x55386E04, 0xC807E3D3,
54         0xAB49E193, 0x14B4E63A,
55         0x67DF2495, 0xEA517C45,
56         0x7624CE51, 0xF8140C51,
57
58         0x4824BD23, 0xB61DD0C9,
59         0x072BCFBE, 0xE8F3807D,
60         0x919EA373, 0x25E30C47,
61         0xFEB12958, 0x4DA80A5A,
62         0xE9A0DDF8, 0x792B0076,
63         0xE81C73DC, 0xF025B496,
64         0x1DB7E627, 0x808594FE,
65         0x82668268, 0x655C7783,
66 };
67
68
69 static u32 SetupMaxRdPattern(struct MCTStatStruc *pMCTstat,
70                                         struct DCTStatStruc *pDCTstat,
71                                         u32 *buffer)
72 {
73         /* 1. Copy the alpha and Beta patterns from ROM to Cache,
74          *    aligning on 16 byte boundary
75          * 2. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufA
76          *    for Alpha
77          * 3. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufB
78          *    for Beta
79          */
80
81         u32 *buf;
82         u8 i;
83
84         buf = (u32 *)(((u32)buffer + 0x10) & (0xfffffff0));
85
86         for(i = 0; i < (16 * 3); i++) {
87                 buf[i] = TestMaxRdLAtPattern_D[i];
88         }
89
90         return (u32)buf;
91
92 }
93
94
95 void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat,
96                                 struct DCTStatStruc *pDCTstatA)
97 {
98         u8 Node;
99
100         for(Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
101                 struct DCTStatStruc *pDCTstat;
102                 pDCTstat = pDCTstatA + Node;
103
104                 if(!pDCTstat->NodePresent)
105                         break;
106
107                 if(pDCTstat->DCTSysLimit)
108                         maxRdLatencyTrain_D(pMCTstat, pDCTstat);
109         }
110 }
111
112
113 static void maxRdLatencyTrain_D(struct MCTStatStruc *pMCTstat,
114                                         struct DCTStatStruc *pDCTstat)
115 {
116         u8 Channel;
117         u32 TestAddr0;
118         u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
119         u16 MaxRdLatDly;
120         u8 RcvrEnDly = 0;
121         u32 PatternBuffer[60];  // FIXME: why not 48 + 4
122         u32 Margin;
123         u32 addr;
124         u32 cr4;
125         u32 lo, hi;
126
127         u8 valid;
128         u32 pattern_buf;
129
130         cr4 = read_cr4();
131         if(cr4 & (1<<9)) {              /* save the old value */
132                 _SSE2 = 1;
133         }
134         cr4 |= (1<<9);                  /* OSFXSR enable SSE2 */
135         write_cr4(cr4);
136
137         addr = HWCR;
138         _RDMSR(addr, &lo, &hi);
139         if(lo & (1<<17)) {              /* save the old value */
140                 _Wrap32Dis = 1;
141         }
142         lo |= (1<<17);                  /* HWCR.wrap32dis */
143         lo &= ~(1<<15);                 /* SSEDIS */
144         /* Setting wrap32dis allows 64-bit memory references in
145            real mode */
146         _WRMSR(addr, lo, hi);
147
148         _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
149
150         pattern_buf = SetupMaxRdPattern(pMCTstat, pDCTstat, PatternBuffer);
151
152         for (Channel = 0; Channel < 2; Channel++) {
153                 print_debug_dqs("\tMaxRdLatencyTrain51: Channel ",Channel, 1);
154                 pDCTstat->Channel = Channel;
155
156                 if( (pDCTstat->Status & (1 << SB_128bitmode)) && Channel)
157                         break;          /*if ganged mode, skip DCT 1 */
158
159                 TestAddr0 = GetMaxRdLatTestAddr_D(pMCTstat, pDCTstat, Channel, &RcvrEnDly,       &valid);
160                 if(!valid)      /* Address not supported on current CS */
161                         continue;
162                 /* rank 1 of DIMM, testpattern 0 */
163                 WriteMaxRdLat1CLTestPattern_D(pattern_buf, TestAddr0);
164
165                 MaxRdLatDly = mct_GetStartMaxRdLat_D(pMCTstat, pDCTstat, Channel, RcvrEnDly, &Margin);
166                 print_debug_dqs("\tMaxRdLatencyTrain52:  MaxRdLatDly start ", MaxRdLatDly, 2);
167                 print_debug_dqs("\tMaxRdLatencyTrain52:  MaxRdLatDly Margin ", Margin, 2);
168                 while(MaxRdLatDly < MAX_RD_LAT) {       /* sweep Delay value here */
169                         mct_setMaxRdLatTrnVal_D(pDCTstat, Channel, MaxRdLatDly);
170                         ReadMaxRdLat1CLTestPattern_D(TestAddr0);
171                         if( CompareMaxRdLatTestPattern_D(pattern_buf, TestAddr0) == DQS_PASS)
172                                 break;
173                         SetTargetWTIO_D(TestAddr0);
174                         FlushMaxRdLatTestPattern_D(TestAddr0);
175                         ResetTargetWTIO_D();
176                         MaxRdLatDly++;
177                 }
178                 print_debug_dqs("\tMaxRdLatencyTrain53:  MaxRdLatDly end ", MaxRdLatDly, 2);
179                 mct_setMaxRdLatTrnVal_D(pDCTstat, Channel, MaxRdLatDly + Margin);
180         }
181
182         if(_DisableDramECC) {
183                 mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
184         }
185
186         if(!_Wrap32Dis) {
187                 addr = HWCR;
188                 _RDMSR(addr, &lo, &hi);
189                 lo &= ~(1<<17); /* restore HWCR.wrap32dis */
190                 _WRMSR(addr, lo, hi);
191         }
192         if(!_SSE2){
193                 cr4 = read_cr4();
194                 cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
195                 write_cr4(cr4);
196         }
197
198 #if DQS_TRAIN_DEBUG > 0
199         {
200                 u8 Channel;
201                 print_debug("maxRdLatencyTrain: CH_MaxRdLat:\n");
202                 for(Channel = 0; Channel<2; Channel++) {
203                         print_debug("Channel:"); print_debug_hex8(Channel);
204                         print_debug(": ");
205                         print_debug_hex8( pDCTstat->CH_MaxRdLat[Channel] );
206                         print_debug("\n");
207                 }
208         }
209 #endif
210
211 }
212
213 static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat,
214                                         u8 Channel, u16 MaxRdLatVal)
215 {
216         u8 i;
217         u32 reg;
218         u32 dev;
219         u32 val;
220
221         if (pDCTstat->GangedMode) {
222                 Channel = 0; // for safe
223         for (i=0; i<2; i++)
224                 pDCTstat->CH_MaxRdLat[i] = MaxRdLatVal;
225         } else {
226                 pDCTstat->CH_MaxRdLat[Channel] = MaxRdLatVal;
227         }
228
229         dev = pDCTstat->dev_dct;
230         reg = 0x78 + Channel * 0x100;
231         val = Get_NB32(dev, reg);
232         val &= ~(0x3ff<<22);
233         val |= MaxRdLatVal<<22;
234         /* program MaxRdLatency to correspond with current delay */
235         Set_NB32(dev, reg, val);
236
237 }
238
239
240 static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr)
241 {
242         /* Compare only the first beat of data.  Since target addrs are cache
243          * line aligned, the Channel parameter is used to determine which cache
244          * QW to compare.
245          */
246
247         u32 *test_buf = (u32 *)pattern_buf;
248         u32 addr_lo;
249         u32 val, val_test;
250         int i;
251         u8 ret = DQS_PASS;
252
253         SetUpperFSbase(addr);
254         addr_lo = addr<<8;
255
256         _EXECFENCE;
257         for (i=0; i<(16*3); i++) {
258                 val = read32_fs(addr_lo);
259                 val_test = test_buf[i];
260
261                 print_debug_dqs_pair("\t\t\t\t\t\ttest_buf = ", (u32)test_buf, " value = ", val_test, 5);
262                 print_debug_dqs_pair("\t\t\t\t\t\ttaddr_lo = ", addr_lo, " value = ", val, 5);
263                 if(val != val_test) {
264                         ret = DQS_FAIL;
265                         break;
266                 }
267                 addr_lo += 4;
268         }
269
270         return ret;
271 }
272
273 static u32 GetMaxRdLatTestAddr_D(struct MCTStatStruc *pMCTstat,
274                                         struct DCTStatStruc *pDCTstat,
275                                         u8 Channel, u8 *MaxRcvrEnDly,
276                                         u8 *valid)
277 {
278         u8 Max = 0;
279
280         u8 Channel_Max = 0;
281         u8 d;
282         u8 d_Max = 0;
283
284         u8 Byte;
285         u32 TestAddr0 = 0;
286         u8 ch, ch_start, ch_end;
287         u8 bn;
288
289         bn = 8;
290
291         if(pDCTstat->Status & (1 << SB_128bitmode)) {
292                 ch_start = 0;
293                 ch_end = 2;
294         } else {
295                 ch_start = Channel;
296                 ch_end = Channel + 1;
297         }
298
299         *valid = 0;
300
301         for(ch = ch_start; ch < ch_end; ch++) {
302                 for(d=0; d<4; d++) {
303                         for(Byte = 0; Byte<bn; Byte++) {
304                                 u8 tmp;
305                                 tmp = pDCTstat->CH_D_B_RCVRDLY[ch][d][Byte];
306                                 if(tmp>Max) {
307                                         Max = tmp;
308                                         Channel_Max = Channel;
309                                         d_Max = d;
310                                 }
311                         }
312                 }
313         }
314
315         if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel_Max, d_Max << 1))  {
316                 TestAddr0 = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, Channel_Max, d_Max << 1, valid);
317         }
318
319         if(*valid)
320                 *MaxRcvrEnDly = Max;
321
322         return TestAddr0;
323
324 }
325
326 u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
327                                 struct DCTStatStruc *pDCTstat,
328                                 u8 Channel, u8 DQSRcvEnDly, u32 *Margin)
329 {
330         u32 SubTotal;
331         u32 val;
332         u32 valx;
333         u32 valxx;
334         u32 index_reg;
335         u32 reg_off;
336         u32 dev;
337
338         if(pDCTstat->GangedMode)
339                 Channel =  0;
340
341         index_reg = 0x98 + 0x100 * Channel;
342
343         reg_off = 0x100 * Channel;
344         dev = pDCTstat->dev_dct;
345
346         /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
347         val = Get_NB32(dev, 0x88 + reg_off);
348         SubTotal = ((val & 0x0f) + 1) << 1;     /* SubTotal is 1/2 Memclk unit */
349
350         /* If registered DIMMs are being used then add 1 MEMCLK to the sub-total*/
351         val = Get_NB32(dev, 0x90 + reg_off);
352         if(!(val & (1 << UnBuffDimm)))
353                 SubTotal += 2;
354
355         /*If the address prelaunch is setup for 1/2 MEMCLKs then add 1,
356          *  else add 2 to the sub-total. if (AddrCmdSetup || CsOdtSetup
357          *  || CkeSetup) then K := K + 2; */
358         val = Get_NB32_index_wait(dev, index_reg, 0x04);
359         if(!(val & 0x00202020))
360                 SubTotal += 1;
361         else
362                 SubTotal += 2;
363
364         /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
365          *  then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
366         val = Get_NB32(dev, 0x78 + reg_off);
367         SubTotal += 8 - (val & 0x0f);
368
369         /* Convert bits 7-5 (also referred to as the course delay) of the current
370          * (or worst case) DQS receiver enable delay to 1/2 MEMCLKs units,
371          * rounding up, and add this to the sub-total. */
372         SubTotal += DQSRcvEnDly >> 5;   /*BOZO-no rounding up */
373
374         SubTotal <<= 1;                 /*scale 1/2 MemClk to 1/4 MemClk */
375
376         /* Convert the sub-total (in 1/2 MEMCLKs) to northbridge clocks (NCLKs)
377          * as follows (assuming DDR400 and assuming that no P-state or link speed
378          * changes have occurred). */
379
380         /*New formula:
381         SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
382         val = Get_NB32(dev, 0x94 + reg_off);
383         /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
384         val &= 7;
385         if (val == 4) {
386                 val++;          /* adjust for DDR2-1066 */
387         }
388         valx = (val + 3) << 2;  /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
389
390
391         val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4);
392         val = ((val & 0x1f) + 4 ) * 3;
393
394         /* Calculate 1 MemClk + 1 NCLK delay in NCLKs for margin */
395         valxx = val << 2;
396         valxx /= valx;
397         if (valxx % valx)
398                 valxx++;        /* round up */
399         valxx++;                /* add 1NCLK */
400         *Margin = valxx;        /* one MemClk delay in NCLKs and one additional NCLK */
401
402         val *= SubTotal;
403
404         val /= valx;
405         if (val % valx)
406                 val++;          /* round up */
407
408
409
410         return val;
411 }
412
413