Fix some settings fo AMD MCT. It is based on BIOS test suite.
[coreboot.git] / src / northbridge / amd / amdmct / mct_ddr3 / mcthwl.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 SetTargetFreq(struct MCTStatStruc *pMCTstat,
21                                         struct DCTStatStruc *pDCTstat);
22 static void AgesaHwWlPhase1(sMCTStruct *pMCTData,
23                                         sDCTStruct *pDCTData, u8 dimm, u8 pass);
24 static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
25 static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
26 static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
27 static void PrepareC_DCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
28 static void MultiplyDelay(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
29 static void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
30 static void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
31
32 static void SetEccWrDQS_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
33 {
34         u8 ByteLane, DimmNum, OddByte, Addl_Index, Channel;
35         u8 EccRef1, EccRef2, EccDQSScale;
36         u32 val;
37         u16 word;
38
39         for (Channel = 0; Channel < 2; Channel ++) {
40                 for (DimmNum = 0; DimmNum < C_MAX_DIMMS; DimmNum ++) { /* we use DimmNum instead of DimmNumx3 */
41                         for (ByteLane = 0; ByteLane < 9; ByteLane ++) {
42                                 /* Get RxEn initial value from WrDqs */
43                                 if (ByteLane & 1)
44                                         OddByte = 1;
45                                 else
46                                         OddByte = 0;
47                                 if (ByteLane < 2)
48                                         Addl_Index = 0x30;
49                                 else if (ByteLane < 4)
50                                         Addl_Index = 0x31;
51                                 else if (ByteLane < 6)
52                                         Addl_Index = 0x40;
53                                 else if (ByteLane < 8)
54                                         Addl_Index = 0x41;
55                                 else
56                                         Addl_Index = 0x32;
57                                 Addl_Index += DimmNum * 3;
58
59                                 val = Get_NB32_index_wait(pDCTstat->dev_dct, Channel * 0x100 + 0x98, Addl_Index);
60                                 if (OddByte)
61                                         val >>= 16;
62                                 /* Save WrDqs to stack for later usage */
63                                 pDCTstat->CH_D_B_TxDqs[Channel][DimmNum][ByteLane] = val & 0xFF;
64                                 EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
65                                 word = pDCTstat->CH_EccDQSLike[Channel];
66                                 if ((word & 0xFF) == ByteLane) EccRef1 = val & 0xFF;
67                                 if (((word >> 8) & 0xFF) == ByteLane) EccRef2 = val & 0xFF;
68                         }
69                 }
70         }
71 }
72
73 static void EnableAutoRefresh_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
74 {
75         u32 val;
76
77         val = Get_NB32(pDCTstat->dev_dct, 0x8C);
78         val &= ~(1 << DisAutoRefresh);
79         Set_NB32(pDCTstat->dev_dct, 0x8C, val);
80
81         val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
82         val &= ~(1 << DisAutoRefresh);
83         Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
84 }
85
86 static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
87                                         struct DCTStatStruc *pDCTstat)
88 {
89         u32 val;
90
91         val = Get_NB32(pDCTstat->dev_dct, 0x8C);
92         val |= 1 << DisAutoRefresh;
93         Set_NB32(pDCTstat->dev_dct, 0x8C, val);
94
95         val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
96         val |= 1 << DisAutoRefresh;
97         Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
98 }
99
100
101 static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
102                                         struct DCTStatStruc *pDCTstat, u8 dct)
103 {
104         u8 dimm;
105         u16 DIMMValid;
106         void *DCTPtr;
107
108         dct &= 1;
109
110         DCTPtr = (void *)(pDCTstat->C_DCTPtr[dct]);
111         pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
112         pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
113
114         if (pDCTstat->GangedMode & 1)
115                 pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
116
117         if (pDCTstat->DIMMValid) {
118                 DIMMValid = pDCTstat->DIMMValid;
119                 PrepareC_DCT(pMCTstat, pDCTstat, dct);
120                 for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
121                         if (DIMMValid & (1 << (dimm << 1)))
122                                 AgesaHwWlPhase1(pDCTstat->C_MCTPtr, DCTPtr, dimm, FirstPass);
123                 }
124         }
125 }
126
127 static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
128                                         struct DCTStatStruc *pDCTstat, u8 dct)
129 {
130         u8 dimm;
131         u16 DIMMValid;
132         void *DCTPtr;
133
134         dct &= 1;
135
136         DCTPtr = (void *)&(pDCTstat->C_DCTPtr[dct]); /* todo: */
137         pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
138         pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
139
140         if (pDCTstat->GangedMode & 1)
141                 pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
142
143         if (pDCTstat->DIMMValid) {
144                 DIMMValid = pDCTstat->DIMMValid;
145                 PrepareC_DCT(pMCTstat, pDCTstat, dct);
146                 pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
147                 pDCTstat->CASL = pDCTstat->DIMMCASL = pDCTstat->TargetCASL;
148                 SPD2ndTiming(pMCTstat, pDCTstat, dct);
149                 ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
150                 PlatformSpec_D(pMCTstat, pDCTstat, dct);
151                 fenceDynTraining_D(pMCTstat, pDCTstat, dct);
152                 Restore_OnDimmMirror(pMCTstat, pDCTstat);
153                 StartupDCT_D(pMCTstat, pDCTstat, dct);
154                 Clear_OnDimmMirror(pMCTstat, pDCTstat);
155                 SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
156                 DisableAutoRefresh_D(pMCTstat, pDCTstat);
157                 MultiplyDelay(pMCTstat, pDCTstat, dct);
158                 for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
159                         if (DIMMValid & (1 << (dimm << 1)))
160                                 AgesaHwWlPhase1(pDCTstat->C_MCTPtr, pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
161                 }
162         }
163 }
164
165 static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
166                                         struct DCTStatStruc *pDCTstat)
167 {
168         pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
169         pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
170         pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
171
172         /* Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1 */
173         DisableAutoRefresh_D(pMCTstat, pDCTstat);
174
175         /* Disable ZQ calibration short command by F2x[1,0]94[ZqcsInterval]=00b */
176         DisableZQcalibration(pMCTstat, pDCTstat);
177         PrepareC_MCT(pMCTstat, pDCTstat);
178
179         if (pDCTstat->GangedMode & (1 << 0)) {
180                 pDCTstat->DIMMValidDCT[1] = pDCTstat->DIMMValidDCT[0];
181         }
182
183         PhyWLPass1(pMCTstat, pDCTstat, 0);
184         PhyWLPass1(pMCTstat, pDCTstat, 1);
185
186         if (pDCTstat->TargetFreq > 4) {
187                 /* 8.Prepare the memory subsystem for the target MEMCLK frequency.
188                  * Note: BIOS must program both DCTs to the same frequency.
189                  */
190                 SetTargetFreq(pMCTstat, pDCTstat);
191                 PhyWLPass2(pMCTstat, pDCTstat, 0);
192                 PhyWLPass2(pMCTstat, pDCTstat, 1);
193         }
194
195         SetEccWrDQS_D(pMCTstat, pDCTstat);
196         EnableAutoRefresh_D(pMCTstat, pDCTstat);
197         EnableZQcalibration(pMCTstat, pDCTstat);
198 }
199
200 void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
201                                         struct DCTStatStruc *pDCTstatA)
202 {
203         u8 Node;
204
205         for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
206                 struct DCTStatStruc *pDCTstat;
207                 pDCTstat = pDCTstatA + Node;
208
209                 if (pDCTstat->NodePresent) {
210                         mctSMBhub_Init(Node);
211                         Clear_OnDimmMirror(pMCTstat, pDCTstat);
212                         WriteLevelization_HW(pMCTstat, pDCTstat);
213                         Restore_OnDimmMirror(pMCTstat, pDCTstat);
214                 }
215         }
216 }