blob: 5107fee63d605a36c6a926353806eb6da39cf798 [file] [log] [blame]
Zheng Baoeb75f652010-04-23 17:32:48 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2010 Advanced Micro Devices, Inc.
Timothy Pearsonb8a355d2015-09-05 17:55:58 -05005 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
Zheng Baoeb75f652010-04-23 17:32:48 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Zheng Baoeb75f652010-04-23 17:32:48 +000015 */
16
Timothy Pearson730a0432015-10-16 13:51:51 -050017static void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
18 struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, u8 pass);
19static void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
20 struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, u8 pass);
21static void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
22 struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, u8 pass);
Zheng Baoeb75f652010-04-23 17:32:48 +000023static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
24static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
25static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
26static void PrepareC_DCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
Zheng Baoeb75f652010-04-23 17:32:48 +000027static void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
28static void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
29
30static void SetEccWrDQS_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
31{
32 u8 ByteLane, DimmNum, OddByte, Addl_Index, Channel;
33 u8 EccRef1, EccRef2, EccDQSScale;
34 u32 val;
35 u16 word;
36
37 for (Channel = 0; Channel < 2; Channel ++) {
38 for (DimmNum = 0; DimmNum < C_MAX_DIMMS; DimmNum ++) { /* we use DimmNum instead of DimmNumx3 */
39 for (ByteLane = 0; ByteLane < 9; ByteLane ++) {
40 /* Get RxEn initial value from WrDqs */
41 if (ByteLane & 1)
42 OddByte = 1;
43 else
44 OddByte = 0;
45 if (ByteLane < 2)
46 Addl_Index = 0x30;
47 else if (ByteLane < 4)
48 Addl_Index = 0x31;
49 else if (ByteLane < 6)
50 Addl_Index = 0x40;
51 else if (ByteLane < 8)
52 Addl_Index = 0x41;
53 else
54 Addl_Index = 0x32;
55 Addl_Index += DimmNum * 3;
56
Timothy Pearson730a0432015-10-16 13:51:51 -050057 val = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, Channel, 0x98, Addl_Index);
Zheng Baoeb75f652010-04-23 17:32:48 +000058 if (OddByte)
59 val >>= 16;
60 /* Save WrDqs to stack for later usage */
61 pDCTstat->CH_D_B_TxDqs[Channel][DimmNum][ByteLane] = val & 0xFF;
62 EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
63 word = pDCTstat->CH_EccDQSLike[Channel];
64 if ((word & 0xFF) == ByteLane) EccRef1 = val & 0xFF;
65 if (((word >> 8) & 0xFF) == ByteLane) EccRef2 = val & 0xFF;
66 }
67 }
68 }
69}
70
71static void EnableAutoRefresh_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
72{
73 u32 val;
74
Timothy Pearson730a0432015-10-16 13:51:51 -050075 val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
Zheng Baoeb75f652010-04-23 17:32:48 +000076 val &= ~(1 << DisAutoRefresh);
Timothy Pearson730a0432015-10-16 13:51:51 -050077 Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
Zheng Baoeb75f652010-04-23 17:32:48 +000078
Timothy Pearson730a0432015-10-16 13:51:51 -050079 val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
Zheng Baoeb75f652010-04-23 17:32:48 +000080 val &= ~(1 << DisAutoRefresh);
Timothy Pearson730a0432015-10-16 13:51:51 -050081 Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
Zheng Baoeb75f652010-04-23 17:32:48 +000082}
83
84static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
85 struct DCTStatStruc *pDCTstat)
86{
87 u32 val;
88
Timothy Pearson730a0432015-10-16 13:51:51 -050089 val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
Zheng Baoeb75f652010-04-23 17:32:48 +000090 val |= 1 << DisAutoRefresh;
Timothy Pearson730a0432015-10-16 13:51:51 -050091 Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
Zheng Baoeb75f652010-04-23 17:32:48 +000092
Timothy Pearson730a0432015-10-16 13:51:51 -050093 val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
Zheng Baoeb75f652010-04-23 17:32:48 +000094 val |= 1 << DisAutoRefresh;
Timothy Pearson730a0432015-10-16 13:51:51 -050095 Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
Zheng Baoeb75f652010-04-23 17:32:48 +000096}
97
98
99static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
100 struct DCTStatStruc *pDCTstat, u8 dct)
101{
102 u8 dimm;
103 u16 DIMMValid;
104 void *DCTPtr;
105
106 dct &= 1;
107
108 DCTPtr = (void *)(pDCTstat->C_DCTPtr[dct]);
109 pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
110 pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
111
112 if (pDCTstat->GangedMode & 1)
113 pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
114
115 if (pDCTstat->DIMMValid) {
116 DIMMValid = pDCTstat->DIMMValid;
117 PrepareC_DCT(pMCTstat, pDCTstat, dct);
118 for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
Timothy Pearson730a0432015-10-16 13:51:51 -0500119 if (DIMMValid & (1 << (dimm << 1))) {
120 AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, FirstPass);
121 AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, FirstPass);
122 AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, FirstPass);
123 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000124 }
125 }
126}
127
128static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
129 struct DCTStatStruc *pDCTstat, u8 dct)
130{
131 u8 dimm;
132 u16 DIMMValid;
133 void *DCTPtr;
134
135 dct &= 1;
136
137 DCTPtr = (void *)&(pDCTstat->C_DCTPtr[dct]); /* todo: */
138 pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
139 pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
140
141 if (pDCTstat->GangedMode & 1)
142 pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
143
144 if (pDCTstat->DIMMValid) {
145 DIMMValid = pDCTstat->DIMMValid;
146 PrepareC_DCT(pMCTstat, pDCTstat, dct);
147 pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
148 pDCTstat->CASL = pDCTstat->DIMMCASL = pDCTstat->TargetCASL;
149 SPD2ndTiming(pMCTstat, pDCTstat, dct);
Timothy Pearson730a0432015-10-16 13:51:51 -0500150 if (!is_fam15h()) {
151 ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
152 PlatformSpec_D(pMCTstat, pDCTstat, dct);
153 fenceDynTraining_D(pMCTstat, pDCTstat, dct);
154 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000155 Restore_OnDimmMirror(pMCTstat, pDCTstat);
156 StartupDCT_D(pMCTstat, pDCTstat, dct);
157 Clear_OnDimmMirror(pMCTstat, pDCTstat);
158 SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
159 DisableAutoRefresh_D(pMCTstat, pDCTstat);
Zheng Baoeb75f652010-04-23 17:32:48 +0000160 for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
Timothy Pearson730a0432015-10-16 13:51:51 -0500161 if (DIMMValid & (1 << (dimm << 1))) {
162 AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, SecondPass);
163 AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, SecondPass);
164 AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, SecondPass);
165 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000166 }
167 }
168}
169
Timothy Pearson730a0432015-10-16 13:51:51 -0500170static uint16_t fam15h_next_highest_memclk_freq(uint16_t memclk_freq)
171{
172 uint16_t fam15h_next_highest_freq_tab[] = {0, 0, 0, 0, 0x6, 0, 0xa, 0, 0, 0, 0xe, 0, 0, 0, 0x12, 0, 0, 0, 0x16, 0, 0, 0, 0x16};
173 return fam15h_next_highest_freq_tab[memclk_freq];
174}
175
Timothy Pearsonb8a355d2015-09-05 17:55:58 -0500176/* Write Levelization Training
177 * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
178 */
Zheng Baoeb75f652010-04-23 17:32:48 +0000179static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
Timothy Pearson730a0432015-10-16 13:51:51 -0500180 struct DCTStatStruc *pDCTstat, uint8_t Pass)
Zheng Baoeb75f652010-04-23 17:32:48 +0000181{
Timothy Pearson730a0432015-10-16 13:51:51 -0500182 uint16_t final_target_freq;
183
Zheng Baoeb75f652010-04-23 17:32:48 +0000184 pDCTstat->C_MCTPtr = &(pDCTstat->s_C_MCTPtr);
185 pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
186 pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
187
188 /* Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1 */
189 DisableAutoRefresh_D(pMCTstat, pDCTstat);
190
191 /* Disable ZQ calibration short command by F2x[1,0]94[ZqcsInterval]=00b */
192 DisableZQcalibration(pMCTstat, pDCTstat);
193 PrepareC_MCT(pMCTstat, pDCTstat);
194
195 if (pDCTstat->GangedMode & (1 << 0)) {
196 pDCTstat->DIMMValidDCT[1] = pDCTstat->DIMMValidDCT[0];
197 }
198
Timothy Pearson730a0432015-10-16 13:51:51 -0500199 if (Pass == FirstPass) {
200 PhyWLPass1(pMCTstat, pDCTstat, 0);
201 PhyWLPass1(pMCTstat, pDCTstat, 1);
202 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000203
Timothy Pearson730a0432015-10-16 13:51:51 -0500204 if (Pass == SecondPass) {
205 if (pDCTstat->TargetFreq > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
206 /* 8.Prepare the memory subsystem for the target MEMCLK frequency.
207 * NOTE: BIOS must program both DCTs to the same frequency.
208 * NOTE: Fam15h steps the frequency, Fam10h slams the frequency.
209 */
210 final_target_freq = pDCTstat->TargetFreq;
211
212 while (pDCTstat->Speed != final_target_freq) {
213 if (is_fam15h())
214 pDCTstat->TargetFreq = fam15h_next_highest_memclk_freq(pDCTstat->Speed);
215 else
216 pDCTstat->TargetFreq = final_target_freq;
217 SetTargetFreq(pMCTstat, pDCTstat);
218 PhyWLPass2(pMCTstat, pDCTstat, 0);
219 PhyWLPass2(pMCTstat, pDCTstat, 1);
220 }
221
222 pDCTstat->TargetFreq = final_target_freq;
223
224 uint8_t dct;
225 for (dct = 0; dct < 2; dct++) {
226 sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
227 memcpy(pDCTData->WLGrossDelayFinalPass, pDCTData->WLGrossDelayPrevPass, sizeof(pDCTData->WLGrossDelayPrevPass));
228 memcpy(pDCTData->WLFineDelayFinalPass, pDCTData->WLFineDelayPrevPass, sizeof(pDCTData->WLFineDelayPrevPass));
229 pDCTData->WLCriticalGrossDelayFinalPass = pDCTData->WLCriticalGrossDelayPrevPass;
230 }
231 }
Zheng Baoeb75f652010-04-23 17:32:48 +0000232 }
233
234 SetEccWrDQS_D(pMCTstat, pDCTstat);
235 EnableAutoRefresh_D(pMCTstat, pDCTstat);
236 EnableZQcalibration(pMCTstat, pDCTstat);
237}
238
239void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
Timothy Pearson730a0432015-10-16 13:51:51 -0500240 struct DCTStatStruc *pDCTstatA, uint8_t Pass)
Zheng Baoeb75f652010-04-23 17:32:48 +0000241{
242 u8 Node;
243
244 for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
245 struct DCTStatStruc *pDCTstat;
246 pDCTstat = pDCTstatA + Node;
247
248 if (pDCTstat->NodePresent) {
249 mctSMBhub_Init(Node);
250 Clear_OnDimmMirror(pMCTstat, pDCTstat);
Timothy Pearson730a0432015-10-16 13:51:51 -0500251 WriteLevelization_HW(pMCTstat, pDCTstat, Pass);
Zheng Baoeb75f652010-04-23 17:32:48 +0000252 Restore_OnDimmMirror(pMCTstat, pDCTstat);
253 }
254 }
255}