blob: 3e1b13d01f6fbf20168569f53c4399b4c7420604 [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.
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
20static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
21 struct DCTStatStruc *pDCTstat, u16 like,
22 u8 scale, u8 ChipSel);
23static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
24 struct DCTStatStruc *pDCTstat, u8 ChipSel);
25static u8 MiddleDQS_D(u8 min, u8 max);
26static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
27 struct DCTStatStruc *pDCTstat,
28 u8 cs_start);
29static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
30 struct DCTStatStruc *pDCTstat,
31 u8 cs_start);
32static void WriteDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
33 struct DCTStatStruc *pDCTstat,
34 u32 TestAddr_lo);
35static void WriteL18TestPattern_D(struct DCTStatStruc *pDCTstat,
36 u32 TestAddr_lo);
37static void WriteL9TestPattern_D(struct DCTStatStruc *pDCTstat,
38 u32 TestAddr_lo);
39static u16 CompareDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
40 struct DCTStatStruc *pDCTstat,
41 u32 addr_lo);
42static void FlushDQSTestPattern_D(struct DCTStatStruc *pDCTstat,
43 u32 addr_lo);
44static void SetTargetWTIO_D(u32 TestAddr);
45static void ResetTargetWTIO_D(void);
46static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
47 struct DCTStatStruc *pDCTstat,
48 u32 TestAddr_lo);
49static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
50 struct DCTStatStruc *pDCTstat, u8 ChipSel,
51 u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
52void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index);
53u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
54 struct DCTStatStruc *pDCTstat);
55static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
56 struct DCTStatStruc *pDCTstat,
57 u8 ChipSel);
58static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
59 struct DCTStatStruc *pDCTstat,
60 u8 cs_start);
61u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
62 struct DCTStatStruc *pDCTstat, u8 Channel,
63 u8 receiver, u8 *valid);
64static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
65 struct DCTStatStruc *pDCTstat,
66 u32 *buffer);
67
68static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
69 struct DCTStatStruc *pDCTstat, u8 ChipSel,
70 u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
71
72static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 ChipSel);
73
74#define DQS_TRAIN_DEBUG 0
75
76static void print_debug_dqs(const char *str, u32 val, u8 level)
77{
78#if DQS_TRAIN_DEBUG > 0
79 if (DQS_TRAIN_DEBUG >= level) {
80 printk(BIOS_DEBUG, "%s%x\n", str, val);
81 }
82#endif
83}
84
85static void print_debug_dqs_pair(const char *str, u32 val, const char *str2, u32 val2, u8 level)
86{
87#if DQS_TRAIN_DEBUG > 0
88 if (DQS_TRAIN_DEBUG >= level) {
89 printk(BIOS_DEBUG, "%s%08x%s%08x\n", str, val, str2, val2);
90 }
91#endif
92}
93
94/*Warning: These must be located so they do not cross a logical 16-bit segment boundary!*/
95const static u32 TestPatternJD1a_D[] = {
96 0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF, /* QW0-1, ALL-EVEN */
97 0x00000000,0x00000000,0x00000000,0x00000000, /* QW2-3, ALL-EVEN */
98 0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF, /* QW4-5, ALL-EVEN */
99 0x00000000,0x00000000,0x00000000,0x00000000, /* QW6-7, ALL-EVEN */
100 0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, /* QW0-1, DQ0-ODD */
101 0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, /* QW2-3, DQ0-ODD */
102 0x01010101,0x01010101,0xFeFeFeFe,0xFeFeFeFe, /* QW4-5, DQ0-ODD */
103 0xFeFeFeFe,0xFeFeFeFe,0x01010101,0x01010101, /* QW6-7, DQ0-ODD */
104 0x02020202,0x02020202,0x02020202,0x02020202, /* QW0-1, DQ1-ODD */
105 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW2-3, DQ1-ODD */
106 0xFdFdFdFd,0xFdFdFdFd,0x02020202,0x02020202, /* QW4-5, DQ1-ODD */
107 0x02020202,0x02020202,0x02020202,0x02020202, /* QW6-7, DQ1-ODD */
108 0x04040404,0x04040404,0xfBfBfBfB,0xfBfBfBfB, /* QW0-1, DQ2-ODD */
109 0x04040404,0x04040404,0x04040404,0x04040404, /* QW2-3, DQ2-ODD */
110 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW4-5, DQ2-ODD */
111 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW6-7, DQ2-ODD */
112 0x08080808,0x08080808,0xF7F7F7F7,0xF7F7F7F7, /* QW0-1, DQ3-ODD */
113 0x08080808,0x08080808,0x08080808,0x08080808, /* QW2-3, DQ3-ODD */
114 0xF7F7F7F7,0xF7F7F7F7,0x08080808,0x08080808, /* QW4-5, DQ3-ODD */
115 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW6-7, DQ3-ODD */
116 0x10101010,0x10101010,0x10101010,0x10101010, /* QW0-1, DQ4-ODD */
117 0xeFeFeFeF,0xeFeFeFeF,0x10101010,0x10101010, /* QW2-3, DQ4-ODD */
118 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW4-5, DQ4-ODD */
119 0xeFeFeFeF,0xeFeFeFeF,0x10101010,0x10101010, /* QW6-7, DQ4-ODD */
120 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW0-1, DQ5-ODD */
121 0xdFdFdFdF,0xdFdFdFdF,0x20202020,0x20202020, /* QW2-3, DQ5-ODD */
122 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW4-5, DQ5-ODD */
123 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW6-7, DQ5-ODD */
124 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW0-1, DQ6-ODD */
125 0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, /* QW2-3, DQ6-ODD */
126 0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, /* QW4-5, DQ6-ODD */
127 0x40404040,0x40404040,0xBfBfBfBf,0xBfBfBfBf, /* QW6-7, DQ6-ODD */
128 0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, /* QW0-1, DQ7-ODD */
129 0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, /* QW2-3, DQ7-ODD */
130 0x80808080,0x80808080,0x7F7F7F7F,0x7F7F7F7F, /* QW4-5, DQ7-ODD */
131 0x80808080,0x80808080,0x80808080,0x80808080 /* QW6-7, DQ7-ODD */
132};
133const static u32 TestPatternJD1b_D[] = {
134 0x00000000,0x00000000,0x00000000,0x00000000, /* QW0,CHA-B, ALL-EVEN */
135 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, /* QW1,CHA-B, ALL-EVEN */
136 0x00000000,0x00000000,0x00000000,0x00000000, /* QW2,CHA-B, ALL-EVEN */
137 0x00000000,0x00000000,0x00000000,0x00000000, /* QW3,CHA-B, ALL-EVEN */
138 0x00000000,0x00000000,0x00000000,0x00000000, /* QW4,CHA-B, ALL-EVEN */
139 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, /* QW5,CHA-B, ALL-EVEN */
140 0x00000000,0x00000000,0x00000000,0x00000000, /* QW6,CHA-B, ALL-EVEN */
141 0x00000000,0x00000000,0x00000000,0x00000000, /* QW7,CHA-B, ALL-EVEN */
142 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW0,CHA-B, DQ0-ODD */
143 0x01010101,0x01010101,0x01010101,0x01010101, /* QW1,CHA-B, DQ0-ODD */
144 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW2,CHA-B, DQ0-ODD */
145 0x01010101,0x01010101,0x01010101,0x01010101, /* QW3,CHA-B, DQ0-ODD */
146 0x01010101,0x01010101,0x01010101,0x01010101, /* QW4,CHA-B, DQ0-ODD */
147 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW5,CHA-B, DQ0-ODD */
148 0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe,0xFeFeFeFe, /* QW6,CHA-B, DQ0-ODD */
149 0x01010101,0x01010101,0x01010101,0x01010101, /* QW7,CHA-B, DQ0-ODD */
150 0x02020202,0x02020202,0x02020202,0x02020202, /* QW0,CHA-B, DQ1-ODD */
151 0x02020202,0x02020202,0x02020202,0x02020202, /* QW1,CHA-B, DQ1-ODD */
152 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW2,CHA-B, DQ1-ODD */
153 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW3,CHA-B, DQ1-ODD */
154 0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd,0xFdFdFdFd, /* QW4,CHA-B, DQ1-ODD */
155 0x02020202,0x02020202,0x02020202,0x02020202, /* QW5,CHA-B, DQ1-ODD */
156 0x02020202,0x02020202,0x02020202,0x02020202, /* QW6,CHA-B, DQ1-ODD */
157 0x02020202,0x02020202,0x02020202,0x02020202, /* QW7,CHA-B, DQ1-ODD */
158 0x04040404,0x04040404,0x04040404,0x04040404, /* QW0,CHA-B, DQ2-ODD */
159 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW1,CHA-B, DQ2-ODD */
160 0x04040404,0x04040404,0x04040404,0x04040404, /* QW2,CHA-B, DQ2-ODD */
161 0x04040404,0x04040404,0x04040404,0x04040404, /* QW3,CHA-B, DQ2-ODD */
162 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW4,CHA-B, DQ2-ODD */
163 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW5,CHA-B, DQ2-ODD */
164 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW6,CHA-B, DQ2-ODD */
165 0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB,0xfBfBfBfB, /* QW7,CHA-B, DQ2-ODD */
166 0x08080808,0x08080808,0x08080808,0x08080808, /* QW0,CHA-B, DQ3-ODD */
167 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW1,CHA-B, DQ3-ODD */
168 0x08080808,0x08080808,0x08080808,0x08080808, /* QW2,CHA-B, DQ3-ODD */
169 0x08080808,0x08080808,0x08080808,0x08080808, /* QW3,CHA-B, DQ3-ODD */
170 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW4,CHA-B, DQ3-ODD */
171 0x08080808,0x08080808,0x08080808,0x08080808, /* QW5,CHA-B, DQ3-ODD */
172 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW6,CHA-B, DQ3-ODD */
173 0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7,0xF7F7F7F7, /* QW7,CHA-B, DQ3-ODD */
174 0x10101010,0x10101010,0x10101010,0x10101010, /* QW0,CHA-B, DQ4-ODD */
175 0x10101010,0x10101010,0x10101010,0x10101010, /* QW1,CHA-B, DQ4-ODD */
176 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW2,CHA-B, DQ4-ODD */
177 0x10101010,0x10101010,0x10101010,0x10101010, /* QW3,CHA-B, DQ4-ODD */
178 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW4,CHA-B, DQ4-ODD */
179 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW5,CHA-B, DQ4-ODD */
180 0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF,0xeFeFeFeF, /* QW6,CHA-B, DQ4-ODD */
181 0x10101010,0x10101010,0x10101010,0x10101010, /* QW7,CHA-B, DQ4-ODD */
182 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW0,CHA-B, DQ5-ODD */
183 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW1,CHA-B, DQ5-ODD */
184 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW2,CHA-B, DQ5-ODD */
185 0x20202020,0x20202020,0x20202020,0x20202020, /* QW3,CHA-B, DQ5-ODD */
186 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW4,CHA-B, DQ5-ODD */
187 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW5,CHA-B, DQ5-ODD */
188 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW6,CHA-B, DQ5-ODD */
189 0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF,0xdFdFdFdF, /* QW7,CHA-B, DQ5-ODD */
190 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW0,CHA-B, DQ6-ODD */
191 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW1,CHA-B, DQ6-ODD */
192 0x40404040,0x40404040,0x40404040,0x40404040, /* QW2,CHA-B, DQ6-ODD */
193 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW3,CHA-B, DQ6-ODD */
194 0x40404040,0x40404040,0x40404040,0x40404040, /* QW4,CHA-B, DQ6-ODD */
195 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW5,CHA-B, DQ6-ODD */
196 0x40404040,0x40404040,0x40404040,0x40404040, /* QW6,CHA-B, DQ6-ODD */
197 0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf,0xBfBfBfBf, /* QW7,CHA-B, DQ6-ODD */
198 0x80808080,0x80808080,0x80808080,0x80808080, /* QW0,CHA-B, DQ7-ODD */
199 0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, /* QW1,CHA-B, DQ7-ODD */
200 0x80808080,0x80808080,0x80808080,0x80808080, /* QW2,CHA-B, DQ7-ODD */
201 0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, /* QW3,CHA-B, DQ7-ODD */
202 0x80808080,0x80808080,0x80808080,0x80808080, /* QW4,CHA-B, DQ7-ODD */
203 0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F, /* QW5,CHA-B, DQ7-ODD */
204 0x80808080,0x80808080,0x80808080,0x80808080, /* QW6,CHA-B, DQ7-ODD */
205 0x80808080,0x80808080,0x80808080,0x80808080 /* QW7,CHA-B, DQ7-ODD */
206};
207
208void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
209 struct DCTStatStruc *pDCTstatA, u8 Pass)
210{
211 u8 Node;
212 struct DCTStatStruc *pDCTstat;
213 u32 val;
214
215 for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
216 pDCTstat = pDCTstatA + Node;
217
218 if (pDCTstat->DCTSysLimit) {
219 val = Get_NB32(pDCTstat->dev_dct, 0x78);
220 val |= 1 <<DqsRcvEnTrain;
221 Set_NB32(pDCTstat->dev_dct, 0x78, val);
222 val = Get_NB32(pDCTstat->dev_dct, 0x78 + 0x100);
223 val |= 1 <<DqsRcvEnTrain;
224 Set_NB32(pDCTstat->dev_dct, 0x78 + 0x100, val);
225 mct_TrainRcvrEn_D(pMCTstat, pDCTstat, Pass);
226 }
227 }
228}
229
230static void SetEccDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
231 struct DCTStatStruc *pDCTstat, u8 ChipSel)
232{
233 u8 channel;
234 u8 direction;
235
236 for (channel = 0; channel < 2; channel++){
237 for (direction = 0; direction < 2; direction++) {
238 pDCTstat->Channel = channel; /* Channel A or B */
239 pDCTstat->Direction = direction; /* Read or write */
240 CalcEccDQSPos_D(pMCTstat, pDCTstat, pDCTstat->CH_EccDQSLike[channel], pDCTstat->CH_EccDQSScale[channel], ChipSel);
241 print_debug_dqs_pair("\t\tSetEccDQSRdWrPos: channel ", channel, direction==DQS_READDIR? " R dqs_delay":" W dqs_delay", pDCTstat->DQSDelay, 2);
242 pDCTstat->ByteLane = 8;
243 StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
244 mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, ChipSel);
245 }
246 }
247}
248
249static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
250 struct DCTStatStruc *pDCTstat,
251 u16 like, u8 scale, u8 ChipSel)
252{
253 u8 DQSDelay0, DQSDelay1;
254 u16 DQSDelay;
255
256 if (pDCTstat->Status & (1 << SB_Registered)) {
257 return;
258 }
259
260 pDCTstat->ByteLane = like & 0xff;
261 GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
262 DQSDelay0 = pDCTstat->DQSDelay;
263
264 pDCTstat->ByteLane = (like >> 8) & 0xff;
265 GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
266 DQSDelay1 = pDCTstat->DQSDelay;
267
268 if (DQSDelay0>DQSDelay1) {
269 DQSDelay = DQSDelay0 - DQSDelay1;
270 } else {
271 DQSDelay = DQSDelay1 - DQSDelay0;
272 }
273
274 DQSDelay = DQSDelay * (~scale);
275
276 DQSDelay += 0x80; /* round it */
277
278 DQSDelay >>= 8; /* 256 */
279
280 if (DQSDelay0>DQSDelay1) {
281 DQSDelay = DQSDelay1 - DQSDelay;
282 } else {
283 DQSDelay += DQSDelay1;
284 }
285
286 pDCTstat->DQSDelay = (u8)DQSDelay;
287}
288
289static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
290 struct DCTStatStruc *pDCTstat,
291 u8 cs_start)
292{
293 u32 Errors;
294 u8 Channel, DQSWrDelay;
295 u8 _DisableDramECC = 0;
296 u32 PatternBuffer[292];
297 u8 _Wrap32Dis = 0, _SSE2 = 0;
298 u8 dqsWrDelay_end;
299
300 u32 addr;
301 u32 cr4;
302 u32 lo, hi;
303
304 print_debug_dqs("\nTrainDQSRdWrPos: Node_ID ", pDCTstat->Node_ID, 0);
305 cr4 = read_cr4();
306 if (cr4 & (1<<9)) {
307 _SSE2 = 1;
308 }
309 cr4 |= (1<<9); /* OSFXSR enable SSE2 */
310 write_cr4(cr4);
311
312 addr = HWCR;
313 _RDMSR(addr, &lo, &hi);
314 if (lo & (1<<17)) {
315 _Wrap32Dis = 1;
316 }
317 lo |= (1<<17); /* HWCR.wrap32dis */
318 _WRMSR(addr, lo, hi); /* allow 64-bit memory references in real mode */
319
320 /* Disable ECC correction of reads on the dram bus. */
321 _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
322
323 SetupDqsPattern_D(pMCTstat, pDCTstat, PatternBuffer);
324
325 /* mct_BeforeTrainDQSRdWrPos_D */
326 dqsWrDelay_end = 0x20;
327
328 Errors = 0;
329 for (Channel = 0; Channel < 2; Channel++) {
330 print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ",Channel, 1);
331 pDCTstat->Channel = Channel;
332
333 if (pDCTstat->DIMMValidDCT[Channel] == 0) /* mct_BeforeTrainDQSRdWrPos_D */
334 continue;
Zheng Baoeb75f652010-04-23 17:32:48 +0000335 pDCTstat->DqsRdWrPos_Saved = 0;
336 for ( DQSWrDelay = 0; DQSWrDelay < dqsWrDelay_end; DQSWrDelay++) {
337 pDCTstat->DQSDelay = DQSWrDelay;
338 pDCTstat->Direction = DQS_WRITEDIR;
339 mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
340
341 print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DQSWrDelay ", DQSWrDelay, 2);
342 TrainReadDQS_D(pMCTstat, pDCTstat, cs_start);
343 print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 2);
344 if (pDCTstat->DqsRdWrPos_Saved == 0xFF)
345 break;
346
347 print_debug_dqs("\t\tTrainDQSRdWrPos: 22 TrainErrors ",pDCTstat->TrainErrors, 2);
348 if (pDCTstat->TrainErrors == 0) {
349 break;
350 }
351 Errors |= pDCTstat->TrainErrors;
352 }
353
354 pDCTstat->DqsRdWrPos_Saved = 0;
355 if (DQSWrDelay < dqsWrDelay_end) {
356 Errors = 0;
357
358 print_debug_dqs("\tTrainDQSRdWrPos: 231 DQSWrDelay ", DQSWrDelay, 1);
359 TrainWriteDQS_D(pMCTstat, pDCTstat, cs_start);
360 }
361 print_debug_dqs("\tTrainDQSRdWrPos: 232 Errors ", Errors, 1);
362 pDCTstat->ErrStatus |= Errors;
363 }
364
365#if DQS_TRAIN_DEBUG > 0
366 {
367 u8 val;
368 u8 i;
369 u8 Channel, Receiver, Dir;
370 u8 *p;
371
372 for (Dir = 0; Dir < 2; Dir++) {
373 if (Dir == 1) {
374 print_debug("TrainDQSRdWrPos: CH_D_DIR_B_DQS WR:\n");
375 } else {
376 print_debug("TrainDQSRdWrPos: CH_D_DIR_B_DQS RD:\n");
377 }
378 for (Channel = 0; Channel < 2; Channel++) {
379 print_debug("Channel:"); print_debug_hex8(Channel); print_debug("\n");
380 for (Receiver = cs_start; Receiver < (cs_start + 2); Receiver += 2) {
381 print_debug("\t\tReceiver:"); print_debug_hex8(Receiver);
382 p = pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][Dir];
383 print_debug(": ");
384 for (i=0;i<8; i++) {
385 val = p[i];
386 print_debug_hex8(val);
387 print_debug(" ");
388 }
389 print_debug("\n");
390 }
391 }
392 }
393
394 }
395#endif
396 if (_DisableDramECC) {
397 mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
398 }
399 if (!_Wrap32Dis) {
400 addr = HWCR;
401 _RDMSR(addr, &lo, &hi);
402 lo &= ~(1<<17); /* restore HWCR.wrap32dis */
403 _WRMSR(addr, lo, hi);
404 }
405 if (!_SSE2){
406 cr4 = read_cr4();
407 cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
408 write_cr4(cr4);
409 }
410
411 printk(BIOS_DEBUG, "TrainDQSRdWrPos: Status %x\n", pDCTstat->Status);
412 printk(BIOS_DEBUG, "TrainDQSRdWrPos: TrainErrors %x\n", pDCTstat->TrainErrors);
413 printk(BIOS_DEBUG, "TrainDQSRdWrPos: ErrStatus %x\n", pDCTstat->ErrStatus);
414 printk(BIOS_DEBUG, "TrainDQSRdWrPos: ErrCode %x\n", pDCTstat->ErrCode);
415 printk(BIOS_DEBUG, "TrainDQSRdWrPos: Done\n\n");
416}
417
418static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
419 struct DCTStatStruc *pDCTstat, u32 *buffer)
420{
421 /* 1. Set the Pattern type (0 or 1) in DCTStatstruc.Pattern
422 * 2. Copy the pattern from ROM to Cache, aligning on 16 byte boundary
423 * 3. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufA
424 */
425
426 u32 *buf;
427 u16 i;
428
429 buf = (u32 *)(((u32)buffer + 0x10) & (0xfffffff0));
430 if (pDCTstat->Status & (1<<SB_128bitmode)) {
431 pDCTstat->Pattern = 1; /* 18 cache lines, alternating qwords */
432 for (i=0; i<16*18; i++)
433 buf[i] = TestPatternJD1b_D[i];
434 } else {
435 pDCTstat->Pattern = 0; /* 9 cache lines, sequential qwords */
436 for (i=0; i<16*9; i++)
437 buf[i] = TestPatternJD1a_D[i];
438 }
439 pDCTstat->PtrPatternBufA = (u32)buf;
440}
441
442static void TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
443 struct DCTStatStruc *pDCTstat,
444 u8 cs_start)
445{
446 u32 Errors;
447 u8 ChipSel, DQSDelay;
448 u8 RnkDlySeqPassMin=0, RnkDlySeqPassMax=0xFF, RnkDlyFilterMin=0, RnkDlyFilterMax=0xFF;
449 u8 RnkDlySeqPassMinTot=0, RnkDlySeqPassMaxTot=0xFF, RnkDlyFilterMinTot=0, RnkDlyFilterMaxTot=0xFF;
450 u8 LastTest ,LastTestTot;
451 u32 TestAddr;
452 u8 ByteLane;
453 u8 MutualCSPassW[128];
454 u8 BanksPresent;
455 u8 dqsDelay_end;
456 u8 tmp, valid, tmp1;
457 u16 word;
458
459 /* MutualCSPassW: each byte represents a bitmap of pass/fail per
460 * ByteLane. The indext within MutualCSPassW is the delay value
461 * given the results.
462 */
463 print_debug_dqs("\t\t\tTrainDQSPos begin ", 0, 3);
464
465 Errors = 0;
466 BanksPresent = 0;
467
468 dqsDelay_end = 32;
469 /* Bitmapped status per delay setting, 0xff=All positions
470 * passing (1= PASS). Set the entire array.
471 */
472 for (DQSDelay=0; DQSDelay<128; DQSDelay++) {
473 MutualCSPassW[DQSDelay] = 0xFF;
474 }
475
476 for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) { /* logical register chipselects 0..7 */
477 print_debug_dqs("\t\t\t\tTrainDQSPos: 11 ChipSel ", ChipSel, 4);
478
479 if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel)) {
480 print_debug_dqs("\t\t\t\tmct_RcvrRankEnabled_D CS not enabled ", ChipSel, 4);
481 continue;
482 }
483
Zheng Baoc3af12f2010-10-08 05:08:47 +0000484 BanksPresent = 1; /* flag for at least one bank is present */
Zheng Baoeb75f652010-04-23 17:32:48 +0000485 TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel, &valid);
486 if (!valid) {
487 print_debug_dqs("\t\t\t\tAddress not supported on current CS ", TestAddr, 4);
488 continue;
489 }
490
491 print_debug_dqs("\t\t\t\tTrainDQSPos: 12 TestAddr ", TestAddr, 4);
492 SetUpperFSbase(TestAddr); /* fs:eax=far ptr to target */
493
Zheng Bao89122852010-10-13 02:46:59 +0000494 if (pDCTstat->Direction == DQS_READDIR) {
Zheng Baoeb75f652010-04-23 17:32:48 +0000495 print_debug_dqs("\t\t\t\tTrainDQSPos: 13 for read ", 0, 4);
Zheng Bao89122852010-10-13 02:46:59 +0000496 WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8);
Zheng Baoeb75f652010-04-23 17:32:48 +0000497 }
498
499 for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) {
500 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 141 DQSDelay ", DQSDelay, 5);
501
502 tmp = 0xFF;
503 tmp1 = DQSDelay;
504 if (pDCTstat->Direction == DQS_READDIR) {
505 tmp &= MutualCSPassW[DQSDelay];
506 tmp1 += dqsDelay_end;
507 }
508 tmp &= MutualCSPassW[tmp1];
509
510 if (tmp == 0) {
511 continue;/* skip current delay value if other chipselects have failed all 8 bytelanes */
512 }
513
514 pDCTstat->DQSDelay = DQSDelay;
515 mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
516 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 142 MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
517
518 if (pDCTstat->Direction == DQS_WRITEDIR) {
519 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 143 for write", 0, 5);
Zheng Bao89122852010-10-13 02:46:59 +0000520 WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8);
Zheng Baoeb75f652010-04-23 17:32:48 +0000521 }
522
523 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 Pattern ", pDCTstat->Pattern, 5);
Zheng Bao89122852010-10-13 02:46:59 +0000524 ReadDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8);
525 /* print_debug_dqs("\t\t\t\t\tTrainDQSPos: 145 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); */
Zheng Baoeb75f652010-04-23 17:32:48 +0000526 word = CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); /* 0=fail, 1=pass */
527 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 1 ", word, 3);
528
529 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 3);
530 word &= ~(pDCTstat->DqsRdWrPos_Saved); /* mask out bytelanes that already passed */
531 word &= ~(pDCTstat->DqsRdWrPos_Saved << 8);
532 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 2 ", word, 3);
533
534 tmp = DQSDelay;
535 if (pDCTstat->Direction == DQS_READDIR) {
536 MutualCSPassW[tmp] &= word >> 8;
537 tmp += dqsDelay_end;
538 }
539 MutualCSPassW[tmp] &= word & 0xFF;
540
541 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 \tMutualCSPassW ", MutualCSPassW[DQSDelay], 5);
542
543 SetTargetWTIO_D(TestAddr);
Zheng Bao89122852010-10-13 02:46:59 +0000544 FlushDQSTestPattern_D(pDCTstat, TestAddr << 8);
Zheng Baoeb75f652010-04-23 17:32:48 +0000545 ResetTargetWTIO_D();
546 }
547
548 }
549
550 if (pDCTstat->Direction == DQS_READDIR) {
551 dqsDelay_end <<= 1;
552 }
553
554 if (BanksPresent) {
Zheng Bao69436e12011-01-06 02:18:12 +0000555 #if 0 /* show the bitmap */
556 for (ByteLane = 0; ByteLane < 8; ByteLane++) { /* just print ByteLane 0 */
557 for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) {
558 if (!(MutualCSPassW[DQSDelay] &(1 << ByteLane))) {
559 printk(BIOS_DEBUG, ".");
560 } else {
561 printk(BIOS_DEBUG, "*");
562 }
563 }
564 printk(BIOS_DEBUG, "\n");
565 }
566 #endif
Zheng Baoeb75f652010-04-23 17:32:48 +0000567 for (ByteLane = 0; ByteLane < 8; ByteLane++) {
568 print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane ",ByteLane, 4);
569 if (!(pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane))) {
570 pDCTstat->ByteLane = ByteLane;
571 LastTest = DQS_FAIL; /* Analyze the results */
572 LastTestTot = DQS_FAIL;
573 /* RnkDlySeqPassMin = 0; */
574 /* RnkDlySeqPassMax = 0; */
575 RnkDlyFilterMax = 0;
576 RnkDlyFilterMin = 0;
577 RnkDlyFilterMaxTot = 0;
578 RnkDlyFilterMinTot = 0;
579 for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) {
580 if (MutualCSPassW[DQSDelay] & (1 << ByteLane)) {
581 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 321 DQSDelay ", DQSDelay, 5);
582 print_debug_dqs("\t\t\t\t\tTrainDQSPos: 322 MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
583 if (pDCTstat->Direction == DQS_READDIR)
584 tmp = 0x20;
585 else
586 tmp = 0;
587 if (DQSDelay >= tmp) {
588 RnkDlySeqPassMax = DQSDelay;
589 if (LastTest == DQS_FAIL) {
590 RnkDlySeqPassMin = DQSDelay; /* start sequential run */
591 }
592 if ((RnkDlySeqPassMax - RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)){
593 RnkDlyFilterMin = RnkDlySeqPassMin;
594 RnkDlyFilterMax = RnkDlySeqPassMax;
595 }
596 LastTest = DQS_PASS;
597 }
598
599 if (pDCTstat->Direction == DQS_READDIR) {
600 RnkDlySeqPassMaxTot = DQSDelay;
601 if (LastTestTot == DQS_FAIL)
602 RnkDlySeqPassMinTot = DQSDelay;
603 if ((RnkDlySeqPassMaxTot - RnkDlySeqPassMinTot)>(RnkDlyFilterMaxTot-RnkDlyFilterMinTot)){
604 RnkDlyFilterMinTot = RnkDlySeqPassMinTot;
605 RnkDlyFilterMaxTot = RnkDlySeqPassMaxTot;
606 }
607 LastTestTot = DQS_PASS;
608 }
609 } else {
610 LastTest = DQS_FAIL;
611 LastTestTot = DQS_FAIL;
612 }
613 }
614 print_debug_dqs("\t\t\t\tTrainDQSPos: 33 RnkDlySeqPassMax ", RnkDlySeqPassMax, 4);
615 if (RnkDlySeqPassMax == 0) {
Zheng Bao89122852010-10-13 02:46:59 +0000616 Errors |= 1 << SB_NODQSPOS; /* no passing window */
Zheng Baoeb75f652010-04-23 17:32:48 +0000617 } else {
618 print_debug_dqs_pair("\t\t\t\tTrainDQSPos: 34 RnkDlyFilter: ", RnkDlyFilterMin, " ", RnkDlyFilterMax, 4);
619 if (((RnkDlyFilterMax - RnkDlyFilterMin) < MIN_DQS_WNDW)){
620 Errors |= 1 << SB_SMALLDQS;
621 } else {
622 u8 middle_dqs;
623 /* mctEngDQSwindow_Save_D Not required for arrays */
624 if (pDCTstat->Direction == DQS_READDIR)
625 middle_dqs = MiddleDQS_D(RnkDlyFilterMinTot, RnkDlyFilterMaxTot);
626 else
627 middle_dqs = MiddleDQS_D(RnkDlyFilterMin, RnkDlyFilterMax);
628 pDCTstat->DQSDelay = middle_dqs;
629 mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, cs_start); /* load the register with the value */
630 if (pDCTstat->Direction == DQS_READDIR)
631 StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMinTot, RnkDlyFilterMaxTot); /* store the value into the data structure */
632 else
633 StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMin, RnkDlyFilterMax); /* store the value into the data structure */
634 print_debug_dqs("\t\t\t\tTrainDQSPos: 42 middle_dqs : ",middle_dqs, 4);
635 pDCTstat->DqsRdWrPos_Saved |= 1 << ByteLane;
636 }
637 }
Zheng Bao89122852010-10-13 02:46:59 +0000638 }
639 } /* if (pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane)) */
Zheng Baoeb75f652010-04-23 17:32:48 +0000640 }
641/* skipLocMiddle: */
642 pDCTstat->TrainErrors = Errors;
643
644 print_debug_dqs("\t\t\tTrainDQSPos: Errors ", Errors, 3);
645}
646
647static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
648 struct DCTStatStruc *pDCTstat, u8 ChipSel,
649 u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
650{
651 pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
652 [pDCTstat->Direction]
653 [0]
654 [pDCTstat->ByteLane] = RnkDlyFilterMin;
655 pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
656 [pDCTstat->Direction]
657 [1]
658 [pDCTstat->ByteLane] = RnkDlyFilterMax;
659}
660
661static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
662 struct DCTStatStruc *pDCTstat, u8 ChipSel)
663{
664 /* Store the DQSDelay value, found during a training sweep, into the DCT
665 * status structure for this node
666 */
667
668 /* When 400, 533, 667, it will support dimm0/1/2/3,
669 * and set conf for dimm0, hw will copy to dimm1/2/3
670 * set for dimm1, hw will copy to dimm3
671 * Rev A/B only support DIMM0/1 when 800Mhz and above + 0x100 to next dimm
672 * Rev C support DIMM0/1/2/3 when 800Mhz and above + 0x100 to next dimm
673 */
674
675 /* FindDQSDatDimmVal_D is not required since we use an array */
676 u8 dn = 0;
677
678 dn = ChipSel>>1; /* if odd or even logical DIMM */
679
680 pDCTstat->CH_D_DIR_B_DQS[pDCTstat->Channel][dn][pDCTstat->Direction][pDCTstat->ByteLane] =
681 pDCTstat->DQSDelay;
682}
683
684static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
685 struct DCTStatStruc *pDCTstat, u8 ChipSel,
686 u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
687{
688 u8 dn;
689
690 if (pDCTstat->Direction == DQS_WRITEDIR) {
691 dn = ChipSel >> 1;
692 RnkDlyFilterMin += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
693 RnkDlyFilterMax += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
694 pDCTstat->DQSDelay += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
695 } else {
696 RnkDlyFilterMin <<= 1;
697 RnkDlyFilterMax <<= 1;
698 pDCTstat->DQSDelay <<= 1;
699 }
700 mctEngDQSwindow_Save_D(pMCTstat, pDCTstat, ChipSel, RnkDlyFilterMin, RnkDlyFilterMax);
701 StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
702}
703
704static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
705 struct DCTStatStruc *pDCTstat, u8 ChipSel)
706{
707 u8 dn = 0;
708
709 /* When 400, 533, 667, it will support dimm0/1/2/3,
710 * and set conf for dimm0, hw will copy to dimm1/2/3
711 * set for dimm1, hw will copy to dimm3
712 * Rev A/B only support DIMM0/1 when 800Mhz and above + 0x100 to next dimm
713 * Rev C support DIMM0/1/2/3 when 800Mhz and above + 0x100 to next dimm
714 */
715
716 /* FindDQSDatDimmVal_D is not required since we use an array */
717 dn = ChipSel >> 1; /*if odd or even logical DIMM */
718
719 pDCTstat->DQSDelay =
720 pDCTstat->CH_D_DIR_B_DQS[pDCTstat->Channel][dn][pDCTstat->Direction][pDCTstat->ByteLane];
721}
722
723/* FindDQSDatDimmVal_D is not required since we use an array */
724
725static u8 MiddleDQS_D(u8 min, u8 max)
726{
727 u8 size;
728 size = max-min;
729 if (size % 2)
730 size++; /* round up if the size isn't even. */
731 return ( min + (size >> 1));
732}
733
734static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
735 struct DCTStatStruc *pDCTstat,
736 u8 cs_start)
737{
738 print_debug_dqs("\t\tTrainReadPos ", 0, 2);
739 pDCTstat->Direction = DQS_READDIR;
740 TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
741}
742
743static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
744 struct DCTStatStruc *pDCTstat,
745 u8 cs_start)
746{
747 pDCTstat->Direction = DQS_WRITEDIR;
748 print_debug_dqs("\t\tTrainWritePos", 0, 2);
749 TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
750}
751
752static void proc_IOCLFLUSH_D(u32 addr_hi)
753{
754 SetTargetWTIO_D(addr_hi);
755 proc_CLFLUSH(addr_hi);
756 ResetTargetWTIO_D();
757}
758
759static u8 ChipSelPresent_D(struct MCTStatStruc *pMCTstat,
760 struct DCTStatStruc *pDCTstat,
761 u8 Channel, u8 ChipSel)
762{
763 u32 val;
764 u32 reg;
765 u32 dev = pDCTstat->dev_dct;
766 u32 reg_off;
767 u8 ret = 0;
768
769 if (!pDCTstat->GangedMode) {
770 reg_off = 0x100 * Channel;
771 } else {
772 reg_off = 0;
773 }
774
775 if (ChipSel < MAX_CS_SUPPORTED){
776 reg = 0x40 + (ChipSel << 2) + reg_off;
777 val = Get_NB32(dev, reg);
778 if (val & ( 1 << 0))
779 ret = 1;
780 }
781
782 return ret;
783}
784
785/* proc_CLFLUSH_D located in mct_gcc.h */
786
787static void WriteDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
788 struct DCTStatStruc *pDCTstat,
789 u32 TestAddr_lo)
790{
791 /* Write a pattern of 72 bit times (per DQ), to test dram functionality.
792 * The pattern is a stress pattern which exercises both ISI and
793 * crosstalk. The number of cache lines to fill is dependent on DCT
794 * width mode and burstlength.
795 * Mode BL Lines Pattern no.
796 * ----+---+-------------------
797 * 64 4 9 0
798 * 64 8 9 0
799 * 64M 4 9 0
800 * 64M 8 9 0
801 * 128 4 18 1
802 * 128 8 N/A -
803 */
804 if (pDCTstat->Pattern == 0)
805 WriteL9TestPattern_D(pDCTstat, TestAddr_lo);
806 else
807 WriteL18TestPattern_D(pDCTstat, TestAddr_lo);
808}
809
810static void WriteL18TestPattern_D(struct DCTStatStruc *pDCTstat,
811 u32 TestAddr_lo)
812{
813 u8 *buf;
814
815 buf = (u8 *)pDCTstat->PtrPatternBufA;
816 WriteLNTestPattern(TestAddr_lo, buf, 18);
817
818}
819
820static void WriteL9TestPattern_D(struct DCTStatStruc *pDCTstat,
821 u32 TestAddr_lo)
822{
823 u8 *buf;
824
825 buf = (u8 *)pDCTstat->PtrPatternBufA;
826 WriteLNTestPattern(TestAddr_lo, buf, 9);
827}
828
829static u16 CompareDQSTestPattern_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 addr_lo)
830{
831 /* Compare a pattern of 72 bit times (per DQ), to test dram functionality.
832 * The pattern is a stress pattern which exercises both ISI and
833 * crosstalk. The number of cache lines to fill is dependent on DCT
834 * width mode and burstlength.
835 * Mode BL Lines Pattern no.
836 * ----+---+-------------------
837 * 64 4 9 0
838 * 64 8 9 0
839 * 64M 4 9 0
840 * 64M 8 9 0
841 * 128 4 18 1
842 * 128 8 N/A -
843 */
844
845 u32 *test_buf;
846 u16 MEn1Results, bitmap;
847 u8 bytelane;
848 u8 i;
849 u32 value;
850 u8 j;
851 u32 value_test;
Stefan Reinauer328a6942011-10-13 17:04:02 -0700852 u32 value_r = 0, value_r_test = 0;
Zheng Baoeb75f652010-04-23 17:32:48 +0000853 u8 pattern, channel, BeatCnt;
854 struct DCTStatStruc *ptrAddr;
855
856 ptrAddr = pDCTstat;
857 pattern = pDCTstat->Pattern;
858 channel = pDCTstat->Channel;
859 test_buf = (u32 *)pDCTstat->PtrPatternBufA;
860
861 if (pattern && channel) {
862 addr_lo += 8; /* second channel */
Zheng Bao89122852010-10-13 02:46:59 +0000863 test_buf += 2;
Zheng Baoeb75f652010-04-23 17:32:48 +0000864 }
865
Zheng Bao89122852010-10-13 02:46:59 +0000866 bytelane = 0; /* bytelane counter */
867 bitmap = 0xFFFF; /* bytelane test bitmap, 1=pass */
Zheng Baoeb75f652010-04-23 17:32:48 +0000868 MEn1Results = 0xFFFF;
869 BeatCnt = 0;
Zheng Bao89122852010-10-13 02:46:59 +0000870 for (i = 0; i < (9 * 64 / 4); i++) { /* sizeof testpattern. /4 due to next loop */
Zheng Baoeb75f652010-04-23 17:32:48 +0000871 value = read32_fs(addr_lo);
872 value_test = *test_buf;
873
874 print_debug_dqs_pair("\t\t\t\t\t\ttest_buf = ", (u32)test_buf, " value = ", value_test, 7);
875 print_debug_dqs_pair("\t\t\t\t\t\ttaddr_lo = ", addr_lo, " value = ", value, 7);
876
877 if (pDCTstat->Direction == DQS_READDIR) {
878 if (BeatCnt != 0) {
879 value_r = *test_buf;
Zheng Bao89122852010-10-13 02:46:59 +0000880 if (pattern) /* if multi-channel */
Zheng Baoeb75f652010-04-23 17:32:48 +0000881 value_r_test = read32_fs(addr_lo - 16);
882 else
883 value_r_test = read32_fs(addr_lo - 8);
884 }
885 print_debug_dqs_pair("\t\t\t\t\t\t\ttest_buf = ", (u32)test_buf, " value_r_test = ", value_r, 7);
886 print_debug_dqs_pair("\t\t\t\t\t\t\ttaddr_lo = ", addr_lo, " value_r = ", value_r_test, 7);
887 }
888
Zheng Bao89122852010-10-13 02:46:59 +0000889 for (j = 0; j < (4 * 8); j += 8) { /* go through a 32bit data, on 1 byte step. */
Zheng Baoeb75f652010-04-23 17:32:48 +0000890 if (((value >> j) & 0xff) != ((value_test >> j) & 0xff)) {
891 bitmap &= ~(1 << bytelane);
892 }
893
894 if (pDCTstat->Direction == DQS_READDIR) {
895 if (BeatCnt != 0) {
896 if (((value_r >> j) & 0xff) != ((value_r_test >> j) & 0xff)) {
897 MEn1Results &= ~(1 << bytelane);
898 }
899 }
900 }
901 bytelane++;
902 bytelane &= 0x7;
903 }
904
905 print_debug_dqs("\t\t\t\t\t\tbitmap = ", bitmap, 7);
906 print_debug_dqs("\t\t\t\t\t\tMEn1Results = ", MEn1Results, 7);
907
908 if (!bitmap)
909 break;
910
911 if (bytelane == 0){
912 BeatCnt += 4;
Zheng Bao89122852010-10-13 02:46:59 +0000913 if (!(pDCTstat->Status & (1 << SB_128bitmode))) {
Zheng Baoeb75f652010-04-23 17:32:48 +0000914 if (BeatCnt == 8) BeatCnt = 0; /* 8 beat burst */
915 } else {
916 if (BeatCnt == 4) BeatCnt = 0; /* 4 beat burst */
917 }
918 if (pattern == 1) { /* dual channel */
919 addr_lo += 8; /* skip over other channel's data */
920 test_buf += 2;
921 }
922 }
923 addr_lo += 4;
924 test_buf += 1;
925 }
926
927 if (pDCTstat->Direction == DQS_READDIR) {
928 bitmap &= 0xFF;
929 bitmap |= MEn1Results << 8;
930 }
931
932 print_debug_dqs("\t\t\t\t\t\tbitmap = ", bitmap, 6);
933
934 return bitmap;
935}
936
937static void FlushDQSTestPattern_D(struct DCTStatStruc *pDCTstat,
938 u32 addr_lo)
939{
940 /* Flush functions in mct_gcc.h */
941 if (pDCTstat->Pattern == 0){
942 FlushDQSTestPattern_L9(addr_lo);
943 } else {
944 FlushDQSTestPattern_L18(addr_lo);
945 }
946}
947
948static void SetTargetWTIO_D(u32 TestAddr)
949{
950 u32 lo, hi;
951 hi = TestAddr >> 24;
952 lo = TestAddr << 8;
953 _WRMSR(0xC0010016, lo, hi); /* IORR0 Base */
954 hi = 0xFF;
955 lo = 0xFC000800; /* 64MB Mask */
956 _WRMSR(0xC0010017, lo, hi); /* IORR0 Mask */
957}
958
959static void ResetTargetWTIO_D(void)
960{
961 u32 lo, hi;
962
963 hi = 0;
964 lo = 0;
965 _WRMSR(0xc0010017, lo, hi); /* IORR0 Mask */
966}
967
968static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
969 struct DCTStatStruc *pDCTstat,
970 u32 TestAddr_lo)
971{
972 /* Read a pattern of 72 bit times (per DQ), to test dram functionality.
973 * The pattern is a stress pattern which exercises both ISI and
974 * crosstalk. The number of cache lines to fill is dependent on DCT
975 * width mode and burstlength.
976 * Mode BL Lines Pattern no.
977 * ----+---+-------------------
978 * 64 4 9 0
979 * 64 8 9 0
980 * 64M 4 9 0
981 * 64M 8 9 0
982 * 128 4 18 1
983 * 128 8 N/A -
984 */
985 if (pDCTstat->Pattern == 0)
986 ReadL9TestPattern(TestAddr_lo);
987 else
988 ReadL18TestPattern(TestAddr_lo);
989 _MFENCE;
990}
991
992u32 SetUpperFSbase(u32 addr_hi)
993{
994 /* Set the upper 32-bits of the Base address, 4GB aligned) for the
995 * FS selector.
996 */
997 u32 lo, hi;
998 u32 addr;
999 lo = 0;
1000 hi = addr_hi>>24;
1001 addr = FS_Base;
1002 _WRMSR(addr, lo, hi);
Zheng Bao89122852010-10-13 02:46:59 +00001003 return addr_hi << 8;
Zheng Baoeb75f652010-04-23 17:32:48 +00001004}
1005
1006void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index)
1007{
1008 u32 val;
1009
1010 val = Get_NB32_index_wait(dev, index_reg, index);
1011 Set_NB32_index_wait(dev, index_reg, index, val);
1012}
1013
1014/* mctEngDQSwindow_Save_D not required with arrays */
1015
1016void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
1017 struct DCTStatStruc *pDCTstatA)
1018{
1019 u8 Node;
1020 u8 ChipSel;
1021 struct DCTStatStruc *pDCTstat;
1022
1023 for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
1024 pDCTstat = pDCTstatA + Node;
1025 if (pDCTstat->DCTSysLimit) {
1026 for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
1027 TrainDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
1028 SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
1029 }
1030 }
1031 }
1032}
1033
1034/* mct_BeforeTrainDQSRdWrPos_D
1035 * Function is inline.
1036 */
1037u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
1038 struct DCTStatStruc *pDCTstat)
1039{
1040 u8 _DisableDramECC = 0;
1041 u32 val;
1042 u32 reg;
1043 u32 dev;
1044
1045 /*Disable ECC correction of reads on the dram bus. */
1046
1047 dev = pDCTstat->dev_dct;
1048 reg = 0x90;
1049 val = Get_NB32(dev, reg);
1050 if (val & (1<<DimmEcEn)) {
1051 _DisableDramECC |= 0x01;
1052 val &= ~(1<<DimmEcEn);
1053 Set_NB32(dev, reg, val);
1054 }
1055 if (!pDCTstat->GangedMode) {
1056 reg = 0x190;
1057 val = Get_NB32(dev, reg);
1058 if (val & (1<<DimmEcEn)) {
1059 _DisableDramECC |= 0x02;
1060 val &= ~(1<<DimmEcEn);
1061 Set_NB32(dev, reg, val);
1062 }
1063 }
1064 return _DisableDramECC;
1065}
1066
1067void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
1068 struct DCTStatStruc *pDCTstat, u8 _DisableDramECC)
1069{
1070 u32 val;
1071 u32 reg;
1072 u32 dev;
1073
1074 /* Enable ECC correction if it was previously disabled */
1075
1076 dev = pDCTstat->dev_dct;
1077
1078 if ((_DisableDramECC & 0x01) == 0x01) {
1079 reg = 0x90;
1080 val = Get_NB32(dev, reg);
1081 val |= (1<<DimmEcEn);
1082 Set_NB32(dev, reg, val);
1083 }
1084 if ((_DisableDramECC & 0x02) == 0x02) {
1085 reg = 0x190;
1086 val = Get_NB32(dev, reg);
1087 val |= (1<<DimmEcEn);
1088 Set_NB32(dev, reg, val);
1089 }
1090}
1091
Zheng Bao89122852010-10-13 02:46:59 +00001092/*
1093 * Set DQS delay value to related register
1094 */
Zheng Baoeb75f652010-04-23 17:32:48 +00001095static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
1096 struct DCTStatStruc *pDCTstat, u8 ChipSel)
1097{
1098 u8 ByteLane;
1099 u32 val;
1100 u32 index_reg = 0x98 + 0x100 * pDCTstat->Channel;
1101 u8 shift;
1102 u32 dqs_delay = (u32)pDCTstat->DQSDelay;
1103 u32 dev = pDCTstat->dev_dct;
1104 u32 index;
1105
1106 ByteLane = pDCTstat->ByteLane;
1107
1108 if (!(pDCTstat->DqsRdWrPos_Saved & (1 << ByteLane))) {
1109 /* Channel is offset */
1110 if (ByteLane < 4) {
1111 index = 1;
1112 } else if (ByteLane <8) {
1113 index = 2;
1114 } else {
1115 index = 3;
1116 }
1117
1118 if (pDCTstat->Direction == DQS_READDIR) {
1119 index += 4;
1120 }
1121
1122 /* get the proper register index */
Zheng Bao89122852010-10-13 02:46:59 +00001123 shift = ByteLane % 4;
Zheng Baoeb75f652010-04-23 17:32:48 +00001124 shift <<= 3; /* get bit position of bytelane, 8 bit */
1125
1126 index += (ChipSel>>1) << 8;
1127
1128 val = Get_NB32_index_wait(dev, index_reg, index);
1129 if (ByteLane < 8) {
1130 if (pDCTstat->Direction == DQS_WRITEDIR) {
1131 dqs_delay += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][ChipSel>>1][ByteLane];
1132 } else {
1133 dqs_delay <<= 1;
1134 }
1135 }
1136 val &= ~(0x7f << shift);
1137 val |= (dqs_delay << shift);
1138 Set_NB32_index_wait(dev, index_reg, index, val);
1139 }
1140}
1141
Zheng Bao89122852010-10-13 02:46:59 +00001142/*
1143 * mct_SetDQSDelayAllCSR_D:
1144 * Write the Delay value to all eight byte lanes.
1145 */
Zheng Baoeb75f652010-04-23 17:32:48 +00001146static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
1147 struct DCTStatStruc *pDCTstat,
1148 u8 cs_start)
1149{
1150 u8 ByteLane;
1151 u8 ChipSel = cs_start;
1152
1153 for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) {
1154 if ( mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel)) {
1155 for (ByteLane = 0; ByteLane < 8; ByteLane++) {
1156 pDCTstat->ByteLane = ByteLane;
1157 mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, ChipSel);
1158 }
1159 }
1160 }
1161}
1162
1163u8 mct_RcvrRankEnabled_D(struct MCTStatStruc *pMCTstat,
1164 struct DCTStatStruc *pDCTstat,
1165 u8 Channel, u8 ChipSel)
1166{
1167 u8 ret;
1168
1169 ret = ChipSelPresent_D(pMCTstat, pDCTstat, Channel, ChipSel);
1170 return ret;
1171}
1172
1173u32 mct_GetRcvrSysAddr_D(struct MCTStatStruc *pMCTstat,
1174 struct DCTStatStruc *pDCTstat,
1175 u8 channel, u8 receiver, u8 *valid)
1176{
1177 return mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, channel, receiver, valid);
1178}
1179
1180u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
1181 struct DCTStatStruc *pDCTstat,
1182 u8 Channel, u8 receiver, u8 *valid)
1183{
1184 u32 val;
1185 u32 reg_off = 0;
1186 u32 reg;
1187 u32 dword;
1188 u32 dev = pDCTstat->dev_dct;
1189
1190 *valid = 0;
1191
1192
Kerry She99cfa1e2010-08-30 07:31:31 +00001193 if (!pDCTstat->GangedMode) {
Zheng Baoeb75f652010-04-23 17:32:48 +00001194 reg_off = 0x100 * Channel;
1195 }
1196
1197 /* get the local base addr of the chipselect */
Kerry She99cfa1e2010-08-30 07:31:31 +00001198 reg = 0x40 + (receiver << 2) + reg_off;
Zheng Baoeb75f652010-04-23 17:32:48 +00001199 val = Get_NB32(dev, reg);
1200
1201 val &= ~0x0F;
1202
1203 /* unganged mode DCT0+DCT1, sys addr of DCT1=node
1204 * base+DctSelBaseAddr+local ca base*/
1205 if ((Channel) && (pDCTstat->GangedMode == 0) && ( pDCTstat->DIMMValidDCT[0] > 0)) {
1206 reg = 0x110;
1207 dword = Get_NB32(dev, reg);
1208 dword &= 0xfffff800;
1209 dword <<= 8; /* scale [47:27] of F2x110[31:11] to [39:8]*/
1210 val += dword;
1211
1212 /* if DCTSelBaseAddr < Hole, and eax > HoleBase, then add Hole size to test address */
1213 if ((val >= pDCTstat->DCTHoleBase) && (pDCTstat->DCTHoleBase > dword)) {
1214 dword = (~(pDCTstat->DCTHoleBase >> (24 - 8)) + 1) & 0xFF;
1215 dword <<= (24 - 8);
1216 val += dword;
1217 }
1218 } else {
1219 /* sys addr=node base+local cs base */
1220 val += pDCTstat->DCTSysBase;
1221
1222 /* New stuff */
1223 if (pDCTstat->DCTHoleBase && (val >= pDCTstat->DCTHoleBase)) {
1224 val -= pDCTstat->DCTSysBase;
1225 dword = Get_NB32(pDCTstat->dev_map, 0xF0); /* get Hole Offset */
1226 val += (dword & 0x0000ff00) << (24-8-8);
1227 }
1228 }
1229
1230 /* New stuff */
1231 val += ((1 << 21) >> 8); /* Add 2MB offset to avoid compat area */
1232 if (val >= MCT_TRNG_KEEPOUT_START) {
1233 while(val < MCT_TRNG_KEEPOUT_END)
1234 val += (1 << (15-8)); /* add 32K */
1235 }
1236
1237 /* Add a node seed */
1238 val += (((1 * pDCTstat->Node_ID) << 20) >> 8); /* Add 1MB per node to avoid aliases */
1239
1240 /* HW remap disabled? */
1241 if (!(pDCTstat->Status & (1 << SB_HWHole))) {
1242 if (!(pDCTstat->Status & (1 << SB_SWNodeHole))) {
1243 /* SW memhole disabled */
1244 u32 lo, hi;
1245 _RDMSR(TOP_MEM, &lo, &hi);
1246 lo >>= 8;
1247 if ((val >= lo) && (val < _4GB_RJ8)) {
1248 val = 0;
1249 *valid = 0;
1250 goto exitGetAddr;
1251 } else {
1252 *valid = 1;
1253 goto exitGetAddrWNoError;
1254 }
1255 } else {
1256 *valid = 1;
1257 goto exitGetAddrWNoError;
1258 }
1259 } else {
1260 *valid = 1;
1261 goto exitGetAddrWNoError;
1262 }
1263
1264exitGetAddrWNoError:
1265
1266 /* Skip if Address is in UMA region */
1267 dword = pMCTstat->Sub4GCacheTop;
1268 dword >>= 8;
1269 if (dword != 0) {
1270 if ((val >= dword) && (val < _4GB_RJ8)) {
1271 val = 0;
1272 *valid = 0;
1273 } else {
1274 *valid = 1;
1275 }
1276 }
1277 print_debug_dqs("mct_GetMCTSysAddr_D: receiver ", receiver, 2);
1278 print_debug_dqs("mct_GetMCTSysAddr_D: Channel ", Channel, 2);
1279 print_debug_dqs("mct_GetMCTSysAddr_D: base_addr ", val, 2);
1280 print_debug_dqs("mct_GetMCTSysAddr_D: valid ", *valid, 2);
1281 print_debug_dqs("mct_GetMCTSysAddr_D: status ", pDCTstat->Status, 2);
1282 print_debug_dqs("mct_GetMCTSysAddr_D: HoleBase ", pDCTstat->DCTHoleBase, 2);
1283 print_debug_dqs("mct_GetMCTSysAddr_D: Cachetop ", pMCTstat->Sub4GCacheTop, 2);
1284
1285exitGetAddr:
1286 return val;
1287}
1288
1289static void mct_Write1LTestPattern_D(struct MCTStatStruc *pMCTstat,
1290 struct DCTStatStruc *pDCTstat,
1291 u32 TestAddr, u8 pattern)
1292{
1293
1294 u8 *buf;
1295
1296 /* Issue the stream of writes. When F2x11C[MctWrLimit] is reached
1297 * (or when F2x11C[FlushWr] is set again), all the writes are written
1298 * to DRAM.
1299 */
1300
1301 SetUpperFSbase(TestAddr);
1302
1303 if (pattern)
1304 buf = (u8 *)pDCTstat->PtrPatternBufB;
1305 else
1306 buf = (u8 *)pDCTstat->PtrPatternBufA;
1307
1308 WriteLNTestPattern(TestAddr << 8, buf, 1);
1309}
1310
1311void mct_Read1LTestPattern_D(struct MCTStatStruc *pMCTstat,
1312 struct DCTStatStruc *pDCTstat, u32 addr)
1313{
1314 u32 value;
1315
1316 /* BIOS issues the remaining (Ntrain - 2) reads after checking that
1317 * F2x11C[PrefDramTrainMode] is cleared. These reads must be to
1318 * consecutive cache lines (i.e., 64 bytes apart) and must not cross
1319 * a naturally aligned 4KB boundary. These reads hit the prefetches and
1320 * read the data from the prefetch buffer.
1321 */
1322
1323 /* get data from DIMM */
1324 SetUpperFSbase(addr);
1325
1326 /* 1st move causes read fill (to exclusive or shared)*/
Zheng Bao89122852010-10-13 02:46:59 +00001327 value = read32_fs(addr << 8);
Zheng Baoeb75f652010-04-23 17:32:48 +00001328}