Fix some settings fo AMD MCT. It is based on BIOS test suite.
[coreboot.git] / src / northbridge / amd / amdmct / mct_ddr3 / mctwl.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2010 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 static void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
21                         struct DCTStatStruc *pDCTstat);
22
23
24 static void AgesaDelay(u32 msec)
25 {
26         mct_Wait(msec*10);
27 }
28
29 void PrepareC_MCT(struct MCTStatStruc *pMCTstat,
30                                         struct DCTStatStruc *pDCTstat)
31 {
32         pDCTstat->C_MCTPtr->AgesaDelay = AgesaDelay;
33         pDCTstat->C_MCTPtr->PlatMaxTotalDimms = mctGet_NVbits(NV_MAX_DIMMS);
34         pDCTstat->C_MCTPtr->PlatMaxDimmsDct = pDCTstat->C_MCTPtr->PlatMaxTotalDimms >> 1;
35 }
36
37 void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
38                                         struct DCTStatStruc *pDCTstat, u8 dct)
39 {
40         u8 dimm;
41         u16 DimmValid;
42         u16 Dimmx8Present;
43
44         dct &= 1;
45
46         pDCTstat->C_DCTPtr[dct]->DctTrain = dct;
47
48         if (dct == 1) {
49                 Dimmx8Present = pDCTstat->Dimmx8Present >> 1;
50         } else
51                 Dimmx8Present = pDCTstat->Dimmx8Present;
52         Dimmx8Present &= 0x55;
53
54         pDCTstat->C_DCTPtr[dct]->MaxDimmsInstalled = pDCTstat->MAdimms[dct];
55         DimmValid = pDCTstat->DIMMValidDCT[dct];
56
57         pDCTstat->C_DCTPtr[dct]->NodeId = pDCTstat->Node_ID;
58         pDCTstat->C_DCTPtr[dct]->LogicalCPUID = pDCTstat->LogicalCPUID;
59
60         for (dimm = 0; dimm < MAX_DIMMS; dimm++) {
61                 if (DimmValid & (1 << dimm))
62                         pDCTstat->C_DCTPtr[dct]->DimmPresent[dimm] = 1;
63                 if (Dimmx8Present & (1 << dimm))
64                         pDCTstat->C_DCTPtr[dct]->DimmX8Present[dimm] = 1;
65         }
66
67         if (pDCTstat->GangedMode & (1 << 0))
68                 pDCTstat->C_DCTPtr[dct]->CurrDct = 0;
69         else
70                 pDCTstat->C_DCTPtr[dct]->CurrDct = dct;
71
72         pDCTstat->C_DCTPtr[dct]->DctCSPresent = pDCTstat->CSPresent_DCT[dct];
73         if (!(pDCTstat->GangedMode & (1 << 0)) && (dct == 1))
74                 pDCTstat->C_DCTPtr[dct]->DctCSPresent = pDCTstat->CSPresent_DCT[0];
75
76         if (pDCTstat->Status & (1 << SB_Registered)) {
77                 pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 1;
78                 pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_OnDimmMirror] = 0;
79         } else {
80                 if (pDCTstat->MirrPresU_NumRegR > 0)
81                         pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_OnDimmMirror] = 1;
82                 pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 0;
83         }
84
85         pDCTstat->C_DCTPtr[dct]->RegMan1Present = pDCTstat->RegMan1Present;
86
87         for (dimm = 0; dimm < MAX_TOTAL_DIMMS; dimm++) {
88                 u8  DimmRanks;
89                 if (DimmValid & (1 << (dimm << 1))) {
90                         DimmRanks = 1;
91                         if (pDCTstat->DimmDRPresent & (1 << (dimm+dct)))
92                                 DimmRanks = 2;
93                         else if (pDCTstat->DimmQRPresent & (1 << (dimm+dct)))
94                                 DimmRanks = 4;
95                 } else
96                         DimmRanks = 0;
97                 pDCTstat->C_DCTPtr[dct]->DimmRanks[dimm] = DimmRanks;
98         }
99 }
100
101 void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
102 {
103         u32 val;
104
105         val = Get_NB32(pDCTstat->dev_dct, 0x94);
106         val |= 1 << 11;
107         Set_NB32(pDCTstat->dev_dct, 0x94, val);
108
109         val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
110         val |= 1 << 11;
111         Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
112 }
113
114 void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
115                                         struct DCTStatStruc *pDCTstat)
116 {
117         u32 val;
118
119         val = Get_NB32(pDCTstat->dev_dct, 0x94);
120         val &= ~(1 << 11);
121         val &= ~(1 << 10);
122         Set_NB32(pDCTstat->dev_dct, 0x94, val);
123
124         val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
125         val &= ~(1 << 11);
126         val &= ~(1 << 10);
127         Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
128 }
129
130 static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
131                                         struct DCTStatStruc *pDCTstat)
132 {
133         u8 DCT0Present, DCT1Present;
134         u32 val;
135
136         DCT0Present = pDCTstat->DIMMValidDCT[0];
137         if (pDCTstat->GangedMode)
138                 DCT1Present = 0;
139         else
140                 DCT1Present = pDCTstat->DIMMValidDCT[1];
141
142         /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
143         if (DCT0Present) {
144                 val = Get_NB32(pDCTstat->dev_dct, 0x90);
145                 val |= 1 << EnterSelfRef;
146                 Set_NB32(pDCTstat->dev_dct, 0x90, val);
147         }
148         if (DCT1Present) {
149                 val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
150                 val |= 1 << EnterSelfRef;
151                 Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
152         }
153         /* Wait until the hardware resets F2x[1, 0]90[EnterSelfRefresh]=0. */
154         if (DCT0Present)
155                 do {
156                         val = Get_NB32(pDCTstat->dev_dct, 0x90);
157                 } while (val & (1 <<EnterSelfRef));
158         if (DCT1Present)
159                 do {
160                         val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
161                 } while (val & (1 <<EnterSelfRef));
162 }
163
164 /*
165  * Change memclk for write levelization pass 2
166  */
167 static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
168                                         struct DCTStatStruc *pDCTstat)
169 {
170         u8 DCT0Present, DCT1Present;
171         u32 val;
172
173         DCT0Present = pDCTstat->DIMMValidDCT[0];
174         if (pDCTstat->GangedMode)
175                 DCT1Present = 0;
176         else
177                 DCT1Present = pDCTstat->DIMMValidDCT[1];
178
179         /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
180         if (DCT0Present) {
181                 val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
182                 val |= 1 << DisAutoComp;
183                 Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
184         }
185         if (DCT1Present) {
186                 val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
187                 val |= 1 << DisAutoComp;
188                 Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
189         }
190
191         /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
192         if (DCT0Present) {
193                 val = Get_NB32(pDCTstat->dev_dct, 0x94);
194                 val &= ~(1 << MemClkFreqVal);
195                 Set_NB32(pDCTstat->dev_dct, 0x94, val);
196         }
197         if (DCT1Present) {
198                 val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
199                 val &= ~(1 << MemClkFreqVal);
200                 Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
201         }
202
203         /* Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency. */
204         if (DCT0Present) {
205                 val = Get_NB32(pDCTstat->dev_dct, 0x94);
206                 val &= 0xFFFFFFF8;
207                 val |= pDCTstat->TargetFreq - 1;
208                 Set_NB32(pDCTstat->dev_dct, 0x94, val);
209         }
210         if (DCT1Present) {
211                 val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
212                 val &= 0xFFFFFFF8;
213                 val |= pDCTstat->TargetFreq - 1;
214                 Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
215         }
216
217         /* Program F2x[1, 0]94[MemClkFreqVal] = 1. */
218         if (DCT0Present) {
219                 val = Get_NB32(pDCTstat->dev_dct, 0x94);
220                 val |= 1 << MemClkFreqVal;
221                 Set_NB32(pDCTstat->dev_dct, 0x94, val);
222         }
223         if (DCT1Present) {
224                 val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
225                 val |= 1 << MemClkFreqVal;
226                 Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
227         }
228
229         /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
230         if (DCT0Present)
231                 do {
232                         val = Get_NB32(pDCTstat->dev_dct, 0x94);
233                 } while (val & (1 << FreqChgInProg));
234         if (DCT1Present)
235                 do {
236                         val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
237                 } while (val & (1 << FreqChgInProg));
238
239         /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
240         if (DCT0Present) {
241                 val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
242                 val &= ~(1 << DisAutoComp);
243                 Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
244         }
245         if (DCT1Present) {
246                 val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
247                 val &= ~(1 << DisAutoComp);
248                 Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
249         }
250 }
251
252 /* Multiply the previously saved delay values in Pass 1, step #5 by
253    (target frequency)/400 to find the gross and fine delay initialization
254    values at the target frequency.
255  */
256 void MultiplyDelay(struct MCTStatStruc *pMCTstat,
257                                         struct DCTStatStruc *pDCTstat, u8 dct)
258 {
259         u16 index;
260         u8 Multiplier;
261         u8 gross, fine;
262         u16 total;
263
264         Multiplier = pDCTstat->TargetFreq;
265
266         for (index=0; index < MAX_BYTE_LANES*MAX_LDIMMS; index ++) {
267                 gross = pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index];
268                 fine = pDCTstat->C_DCTPtr[dct]->WLFineDelay[index];
269
270                 total = gross << 5 | fine;
271                 total *= Multiplier;
272                 if (total % 3)
273                         total = total / 3 + 1;
274                 else
275                         total = total / 3;
276                 pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index] = (total & 0xFF) >> 5;
277                 pDCTstat->C_DCTPtr[dct]->WLFineDelay[index] = total & 0x1F;
278         }
279 }
280
281 /*
282  * the DRAM controller to bring the DRAMs out of self refresh mode.
283  */
284 static void ExitSelfRefresh(struct MCTStatStruc *pMCTstat,
285                                         struct DCTStatStruc *pDCTstat)
286 {
287         u8 DCT0Present, DCT1Present;
288         u32 val;
289
290         DCT0Present = pDCTstat->DIMMValidDCT[0];
291         if (pDCTstat->GangedMode)
292                 DCT1Present = 0;
293         else
294                 DCT1Present = pDCTstat->DIMMValidDCT[1];
295
296         /* Program F2x[1, 0]90[ExitSelfRef]=1 for both DCTs. */
297         if (DCT0Present) {
298                 val = Get_NB32(pDCTstat->dev_dct, 0x90);
299                 val |= 1 << ExitSelfRef;
300                 Set_NB32(pDCTstat->dev_dct, 0x90, val);
301         }
302         if (DCT1Present) {
303                 val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
304                 val |= 1 << ExitSelfRef;
305                 Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
306         }
307         /* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0. */
308         if (DCT0Present)
309                 do {
310                         val = Get_NB32(pDCTstat->dev_dct, 0x90);
311                 } while (val & (1 << ExitSelfRef));
312         if (DCT1Present)
313                 do {
314                         val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
315                 } while (val & (1 << ExitSelfRef));
316 }
317
318 void SetTargetFreq(struct MCTStatStruc *pMCTstat,
319                                         struct DCTStatStruc *pDCTstat)
320 {
321         /* Program F2x[1,0]90[EnterSelfRefresh]=1.
322          * Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
323          */
324         EnterSelfRefresh(pMCTstat, pDCTstat);
325
326         /*
327          * Program F2x[1,0]9C_x08[DisAutoComp]=1
328          * Program F2x[1,0]94[MemClkFreqVal] = 0.
329          * Program F2x[1,0]94[MemClkFreq] to specify the target MEMCLK frequency.
330          * Program F2x[1,0]94[MemClkFreqVal] = 1.
331          * Wait until F2x[1,0]94[FreqChgInProg]=0.
332          * Program F2x[1,0]9C_x08[DisAutoComp]=0
333          */
334         ChangeMemClk(pMCTstat, pDCTstat);
335
336         /* Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
337          * Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
338          */
339         ExitSelfRefresh(pMCTstat, pDCTstat);
340
341         /* wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns */
342         mct_Wait(250);
343
344         if (pDCTstat->Status & (1 << SB_Registered)) {
345                 /* TODO: Assuming the dct==0. The agesa here is confusing. */
346                 FreqChgCtrlWrd(pMCTstat, pDCTstat);
347         }
348 }
349
350 static void Modify_OnDimmMirror(struct DCTStatStruc *pDCTstat, u8 dct, u8 set)
351 {
352         u32 val;
353         u32 reg_off = dct * 0x100 + 0x44;
354         while (reg_off < (dct * 0x100 + 0x60)) {
355                 val = Get_NB32(pDCTstat->dev_dct, reg_off);
356                 if (val & (1 << CSEnable))
357                         set ? (val |= 1 << onDimmMirror) : (val &= ~(1<<onDimmMirror));
358                 Set_NB32(pDCTstat->dev_dct, reg_off, val);
359                 reg_off += 8;
360         }
361 }
362
363 void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat,
364                                 struct DCTStatStruc *pDCTstat)
365 {
366         if (pDCTstat->LogicalCPUID & (AMD_DR_Bx /* | AMD_RB_C0 */)) { /* We dont support RB-C0 now */
367                 if (pDCTstat->MirrPresU_NumRegR & 0x55)
368                         Modify_OnDimmMirror(pDCTstat, 0, 1); /* dct=0, set */
369                 if (pDCTstat->MirrPresU_NumRegR & 0xAA)
370                         Modify_OnDimmMirror(pDCTstat, 1, 1); /* dct=1, set */
371         }
372 }
373 void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat,
374                                 struct DCTStatStruc *pDCTstat)
375 {
376         if (pDCTstat->LogicalCPUID & (AMD_DR_Bx /* | AMD_RB_C0 */)) { /* We dont support RB-C0 now */
377                 if (pDCTstat->MirrPresU_NumRegR & 0x55)
378                         Modify_OnDimmMirror(pDCTstat, 0, 0); /* dct=0, clear */
379                 if (pDCTstat->MirrPresU_NumRegR & 0xAA)
380                         Modify_OnDimmMirror(pDCTstat, 1, 0); /* dct=1, clear */
381         }
382 }