2 * Copyright (C) 2014 Vladimir Serbinenko
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 or (at your option) any later version of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "inteltool.h"
24 extern volatile uint8_t *mchbar
;
26 static uint32_t read_mchbar32(uint32_t addr
)
28 return *(volatile uint32_t *)(mchbar
+ addr
);
32 print_time(const char *string
, unsigned long long time
, unsigned long long tCK
)
34 printf(".%s = %lld /* %lld clocks = %.3lf ns */,\n",
35 string
, time
, time
, (time
* tCK
) / 256.0);
39 make_spd_time(unsigned long long time
, unsigned long long tCK
)
41 return (time
* tCK
) >> 5;
44 static u16
spd_ddr3_calc_crc(u8
* spd
)
50 /* Find the number of bytes covered by CRC */
60 while (--n_crc
>= 0) {
61 crc
= crc
^ (int)*ptr
++ << 8;
62 for (i
= 0; i
< 8; ++i
)
64 crc
= crc
<< 1 ^ 0x1021;
72 void ivybridge_dump_timings(void)
78 int tWR
= 0, tRFC
= 0;
79 int tFAW
[2], tWTR
[2], tCKE
[2], tRTP
[2], tRRD
[2];
81 u32 reg_4004_b30
[2] = { 0, 0 };
85 unsigned int tRCD
[2], tXP
[2], tXPDLL
[2], tRAS
[2], tCWL
[2], tRP
[2],
87 unsigned int tXSOffset
;
97 memset(slots
, 0, sizeof(slots
));
99 for (channel
= 0; channel
< 2; channel
++) {
100 rankmap
[channel
] = read_mchbar32(0xc14 + 0x100 * channel
) >> 24;
103 two_channels
= rankmap
[0] && rankmap
[1];
105 mr0
[0] = read_mchbar32(0x0004);
106 mr1
[0] = read_mchbar32(0x0008);
107 mr0
[1] = read_mchbar32(0x0104);
108 mr1
[1] = read_mchbar32(0x0108);
110 if (mr0
[0] != mr0
[1] && two_channels
)
111 printf("MR0 mismatch: %x, %x\n", mr0
[0], mr0
[1]);
112 if (mr1
[0] != mr1
[1] && two_channels
)
113 printf("MR1 mismatch: %x, %x\n", mr1
[0], mr1
[1]);
115 reg
= read_mchbar32(0x5e00) & ~0x80000000;
116 printf(" .tCK = TCK_MHZ%d,\n", 400 * reg
/ 3);
118 tCK
= (64 * 10 * 3) / reg
;
121 CAS
= ((mr0
[0] >> 4) & 0x7) + 12;
123 CAS
= ((mr0
[0] >> 4) & 0x7) + 4;
126 for (channel
= 0; channel
< 2; channel
++) {
127 mad_dimm
[channel
] = read_mchbar32(0x5004 + 4 * channel
);
130 printf(".rankmap = { 0x%x, 0x%x }, \n", rankmap
[0], rankmap
[1]);
132 printf(".mad_dimm = { 0x%x, 0x%x }, \n", mad_dimm
[0], mad_dimm
[1]);
134 for (channel
= 0; channel
< 2; channel
++)
135 if (rankmap
[channel
]) {
137 static const u8 mr0_wr_t
[12] =
138 { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 };
139 reg
= read_mchbar32(0x4004 + 0x400 * channel
);
141 ctWR
= (reg
>> 24) & 0x3f;
142 if (tWR
&& ctWR
!= tWR
)
143 printf("/* tWR mismatch: %d, %d */\n", tWR
,
147 if (((mr0
[channel
] >> 9) & 7) != mr0_wr_t
[tWR
- 5])
148 printf("/* encoded tWR mismatch: %d, %d */\n",
149 ((mr0
[channel
] >> 9) & 7),
151 reg_4004_b30
[channel
] = reg
>> 30;
152 tFAW
[channel
] = (reg
>> 16) & 0xff;
153 tWTR
[channel
] = (reg
>> 12) & 0xf;
154 tCKE
[channel
] = (reg
>> 8) & 0xf;
155 tRTP
[channel
] = (reg
>> 4) & 0xf;
156 tRRD
[channel
] = (reg
>> 0) & 0xf;
158 reg
= read_mchbar32(0x4000 + 0x400 * channel
);
159 tRAS
[channel
] = reg
>> 16;
160 tCWL
[channel
] = (reg
>> 12) & 0xf;
161 if (CAS
!= ((reg
>> 8) & 0xf))
162 printf("/* CAS mismatch: %d, %d. */\n", CAS
,
164 tRP
[channel
] = (reg
>> 4) & 0xf;
165 tRCD
[channel
] = reg
& 0xf;
167 reg
= read_mchbar32(0x400c + channel
* 0x400);
168 tXPDLL
[channel
] = reg
& 0x1f;
169 tXP
[channel
] = (reg
>> 5) & 7;
170 tAONPD
[channel
] = (reg
>> 8) & 0xff;
172 printf(".mobile = %d,\n", (mr0
[0] >> 12) & 1);
173 print_time("CAS", CAS
, tCK
);
174 print_time("tWR", tWR
, tCK
);
176 printf(".reg_4004_b30 = { %d, %d },\n", reg_4004_b30
[0],
178 if (tFAW
[0] != tFAW
[1] && two_channels
)
179 printf("/* tFAW mismatch: %d, %d */\n", tFAW
[0], tFAW
[1]);
180 print_time("tFAW", tFAW
[0], tCK
);
181 if (tWTR
[0] != tWTR
[1] && two_channels
)
182 printf("/* tWTR mismatch: %d, %d */\n", tWTR
[0], tWTR
[1]);
183 print_time("tWTR", tWTR
[0], tCK
);
184 if (tCKE
[0] != tCKE
[1] && two_channels
)
185 printf("/* tCKE mismatch: %d, %d */\n", tCKE
[0], tCKE
[1]);
186 print_time("tCKE", tCKE
[0], tCK
);
187 if (tRTP
[0] != tRTP
[1] && two_channels
)
188 printf("/* tRTP mismatch: %d, %d */\n", tRTP
[0], tRTP
[1]);
189 print_time("tRTP", tRTP
[0], tCK
);
190 if (tRRD
[0] != tRRD
[1] && two_channels
)
191 printf("/* tRRD mismatch: %d, %d */\n", tRRD
[0], tRRD
[1]);
192 print_time("tRRD", tRRD
[0], tCK
);
194 if (tRAS
[0] != tRAS
[1] && two_channels
)
195 printf("/* tRAS mismatch: %d, %d */\n", tRAS
[0], tRAS
[1]);
196 print_time("tRAS", tRAS
[0], tCK
);
198 if (tCWL
[0] != tCWL
[1] && two_channels
)
199 printf("/* tCWL mismatch: %d, %d */\n", tCWL
[0], tCWL
[1]);
200 print_time("tCWL", tCWL
[0], tCK
);
202 if (tRP
[0] != tRP
[1] && two_channels
)
203 printf("/* tRP mismatch: %d, %d */\n", tRP
[0], tRP
[1]);
204 print_time("tRP", tRP
[0], tCK
);
206 if (tRCD
[0] != tRCD
[1] && two_channels
)
207 printf("/* tRCD mismatch: %d, %d */\n", tRCD
[0], tRCD
[1]);
208 print_time("tRCD", tRCD
[0], tCK
);
210 if (tXPDLL
[0] != tXPDLL
[1] && two_channels
)
211 printf("/* tXPDLL mismatch: %d, %d */\n", tXPDLL
[0], tXPDLL
[1]);
212 print_time("tXPDLL", tXPDLL
[0], tCK
);
214 if (tXP
[0] != tXP
[1] && two_channels
)
215 printf("/* tXP mismatch: %d, %d */\n", tXP
[0], tXP
[1]);
216 print_time("tXP", tXP
[0], tCK
);
218 if (tAONPD
[0] != tAONPD
[1] && two_channels
)
219 printf("/* tAONPD mismatch: %d, %d */\n", tAONPD
[0], tAONPD
[1]);
220 print_time("tAONPD", tAONPD
[0], tCK
);
222 reg
= read_mchbar32(0x4298);
223 if (reg
!= read_mchbar32(0x4698) && two_channels
)
224 printf("/* 4298 mismatch: %d, %d */\n", reg
,
225 read_mchbar32(0x4698));
227 tREFI
= reg
& 0xffff;
228 print_time("tREFI", tREFI
, tCK
);
229 if ((tREFI
* 9 / 1024) != (reg
>> 25))
230 printf("/* tREFI mismatch: %d, %d */\n", tREFI
* 9 / 1024,
232 tRFC
= (reg
>> 16) & 0x1ff;
233 print_time("tRFC", tRFC
, tCK
);
235 reg
= read_mchbar32(0x42a4);
236 if (reg
!= read_mchbar32(0x46a4) && two_channels
)
237 printf("/* 42a4 mismatch: %d, %d */\n", reg
,
238 read_mchbar32(0x46a4));
240 print_time("tMOD", 8 + ((reg
>> 28) & 0xf), tCK
);
242 tXSOffset
= 512 - ((reg
>> 16) & 0x3ff);
243 print_time("tXSOffset", tXSOffset
, tCK
);
244 if (tXSOffset
!= ((reg
>> 12) & 0xf))
245 printf("/* tXSOffset mismatch: %d, %d */\n",
246 tXSOffset
, (reg
>> 12) & 0xf);
247 if (512 != (reg
& 0xfff))
248 printf("/* tDLLK mismatch: %d, %d */\n", 512, reg
& 0xfff);
250 reg
= read_mchbar32(0x5064);
251 printf(".reg5064b0 = 0x%x,\n", reg
& 0xfff);
252 if ((reg
>> 12) != 0x73)
253 printf("/* mismatch 0x%x, 0x73. */\n", reg
<< 12);
255 unsigned int ch0size
, ch1size
;
257 switch (read_mchbar32(0x5000)) {
259 reg
= read_mchbar32(0x5014);
261 if (((reg
>> 16) & 0xff) != 2 * ch1size
)
262 printf("/* ch1size mismatch: %d, %d*/\n",
263 2 * ch1size
, ((ch1size
>> 16) & 0xff));
264 printf(".channel_size_mb = { ?, %d },\n", ch1size
* 256);
267 reg
= read_mchbar32(0x5014);
269 if (((reg
>> 16) & 0xff) != 2 * ch0size
)
270 printf("/* ch0size mismatch: %d, %d*/\n",
271 2 * ch0size
, ((ch0size
>> 16) & 0xff));
272 printf(".channel_size_mb = { %d, ? },\n", ch0size
* 256);
276 for (channel
= 0; channel
< 2; channel
++) {
277 reg
= mad_dimm
[channel
];
278 int swap
= (reg
>> 16) & 1;
279 slots
[channel
][swap
].size_mb
= (reg
& 0xff) * 256;
280 slots
[channel
][swap
].ranks
= 1 + ((reg
>> 17) & 1);
281 slots
[channel
][swap
].width
= 8 + 8 * ((reg
>> 19) & 1);
282 slots
[channel
][!swap
].size_mb
= ((reg
>> 8) & 0xff) * 256;
283 slots
[channel
][!swap
].ranks
= 1 + ((reg
>> 18) & 1);
284 slots
[channel
][!swap
].width
= 8 + 8 * ((reg
>> 20) & 1);
286 /* Undetermined: rank mirror, other modes, asr, ext_temp. */
287 memset(spd
, 0, sizeof(spd
));
288 for (channel
= 0; channel
< 2; channel
++)
289 for (slot
= 0; slot
< 2; slot
++)
290 if (slots
[channel
][slot
].size_mb
) {
291 printf("/* CH%dS%d: %d MiB */\n", channel
,
292 slot
, slots
[channel
][slot
].size_mb
);
294 for (channel
= 0; channel
< 2; channel
++)
295 for (slot
= 0; slot
< 2; slot
++)
296 if (slots
[channel
][slot
].size_mb
) {
298 unsigned int ras
, rc
, rfc
, faw
;
301 ffs(slots
[channel
][slot
].size_mb
*
302 slots
[channel
][slot
].width
/
303 (slots
[channel
][slot
].ranks
* 64)) - 1 -
306 spd
[channel
][slot
][0] = 0x92;
307 spd
[channel
][slot
][1] = 0x11;
308 spd
[channel
][slot
][2] = 0xb; /* DDR3 */
309 spd
[channel
][slot
][3] = 3; /* SODIMM, should we use another type for desktop? */
310 spd
[channel
][slot
][4] = capacity_shift
| 0; /* 8 Banks. */
311 spd
[channel
][slot
][5] = 0; /* FIXME */
312 spd
[channel
][slot
][6] = 0; /* FIXME */
313 spd
[channel
][slot
][7] =
314 ((slots
[channel
][slot
].ranks
-
315 1) << 3) | (ffs(slots
[channel
][slot
].
317 spd
[channel
][slot
][8] = 3; /* Bus width 64b. No ECC yet. */
318 spd
[channel
][slot
][9] = 0x52; /* 2.5ps. FIXME: choose dynamically if needed. */
319 spd
[channel
][slot
][10] = 0x01;
320 spd
[channel
][slot
][11] = 0x08; /* 1/8 ns. FIXME: choose dynamically if needed. */
321 spd
[channel
][slot
][12] = make_spd_time(1, tCK
);
322 spd
[channel
][slot
][13] = 0;
323 spd
[channel
][slot
][14] =
324 (1 << (CAS
- 4)) & 0xff;
325 spd
[channel
][slot
][15] = (1 << (CAS
- 4)) >> 8;
326 spd
[channel
][slot
][16] =
327 make_spd_time(CAS
, tCK
);
328 spd
[channel
][slot
][17] =
329 make_spd_time(tWR
, tCK
);
330 spd
[channel
][slot
][18] =
331 make_spd_time(tRCD
[channel
], tCK
);
332 spd
[channel
][slot
][19] =
333 make_spd_time(tRRD
[channel
], tCK
);
334 spd
[channel
][slot
][20] =
335 make_spd_time(tRP
[channel
], tCK
);
336 ras
= make_spd_time(tRAS
[channel
], tCK
);
337 rc
= 0x181; /* FIXME: should be make_spd_time(tRC, tCK). */
338 spd
[channel
][slot
][22] = ras
;
339 spd
[channel
][slot
][23] = rc
;
340 spd
[channel
][slot
][21] =
341 ((ras
>> 8) & 0xf) | ((rc
>> 4) & 0xf0);
342 rfc
= make_spd_time(tRFC
, tCK
);
343 spd
[channel
][slot
][24] = rfc
;
344 spd
[channel
][slot
][25] = rfc
>> 8;
345 spd
[channel
][slot
][26] =
346 make_spd_time(tWTR
[channel
], tCK
);
347 spd
[channel
][slot
][27] =
348 make_spd_time(tRTP
[channel
], tCK
);
349 faw
= make_spd_time(tFAW
[channel
], tCK
);
350 spd
[channel
][slot
][28] = faw
>> 8;
351 spd
[channel
][slot
][29] = faw
;
352 spd
[channel
][slot
][30] = 0; /* FIXME */
353 spd
[channel
][slot
][31] = 0; /* FIXME */
354 spd
[channel
][slot
][32] = 0; /* FIXME */
355 spd
[channel
][slot
][33] = 0; /* FIXME */
356 spd
[channel
][slot
][62] = 0x65; /* Reference card F. FIXME */
357 spd
[channel
][slot
][63] = 0; /* FIXME */
358 crc
= spd_ddr3_calc_crc(spd
[channel
][slot
]);
359 spd
[channel
][slot
][126] = crc
;
360 spd
[channel
][slot
][127] = crc
>> 8;
363 printf("/* SPD matching current mode: */\n");
365 for (channel
= 0; channel
< 2; channel
++)
366 for (slot
= 0; slot
< 2; slot
++)
367 if (slots
[channel
][slot
].size_mb
) {
370 printf("/* CH%dS%d */\n", channel
, slot
);
372 for (i
= 0; i
< 256; i
++) {
373 if ((i
& 0xf) == 0x0)
375 printf("%02x ", spd
[channel
][slot
][i
]);
376 if ((i
& 0xf) == 0xf)