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.
19 #include "inteltool.h"
21 extern volatile uint8_t *mchbar
;
23 static uint32_t read_mchbar32(uint32_t addr
)
25 return *(volatile uint32_t *)(mchbar
+ addr
);
29 print_time(const char *string
, unsigned long long time
, unsigned long long tCK
)
31 printf(".%s = %lld /* %lld clocks = %.3lf ns */,\n",
32 string
, time
, time
, (time
* tCK
) / 256.0);
36 make_spd_time(unsigned long long time
, unsigned long long tCK
)
38 return (time
* tCK
) >> 5;
41 static u16
spd_ddr3_calc_crc(u8
* spd
)
47 /* Find the number of bytes covered by CRC */
57 while (--n_crc
>= 0) {
58 crc
= crc
^ (int)*ptr
++ << 8;
59 for (i
= 0; i
< 8; ++i
)
61 crc
= crc
<< 1 ^ 0x1021;
69 void ivybridge_dump_timings(const char *dump_spd_file
)
75 int tWR
= 0, tRFC
= 0;
76 int tFAW
[2], tWTR
[2], tCKE
[2], tRTP
[2], tRRD
[2];
78 u32 reg_4004_b30
[2] = { 0, 0 };
82 unsigned int tRCD
[2], tXP
[2], tXPDLL
[2], tRAS
[2], tCWL
[2], tRP
[2],
84 unsigned int tXSOffset
;
94 memset(slots
, 0, sizeof(slots
));
96 for (channel
= 0; channel
< 2; channel
++) {
97 rankmap
[channel
] = read_mchbar32(0xc14 + 0x100 * channel
) >> 24;
100 two_channels
= rankmap
[0] && rankmap
[1];
102 mr0
[0] = read_mchbar32(0x0004);
103 mr1
[0] = read_mchbar32(0x0008);
104 mr0
[1] = read_mchbar32(0x0104);
105 mr1
[1] = read_mchbar32(0x0108);
107 if (mr0
[0] != mr0
[1] && two_channels
)
108 printf("MR0 mismatch: %x, %x\n", mr0
[0], mr0
[1]);
109 if (mr1
[0] != mr1
[1] && two_channels
)
110 printf("MR1 mismatch: %x, %x\n", mr1
[0], mr1
[1]);
112 reg
= read_mchbar32(0x5e00) & ~0x80000000;
113 printf(" .tCK = TCK_MHZ%d,\n", 400 * reg
/ 3);
115 tCK
= (64 * 10 * 3) / reg
;
118 CAS
= ((mr0
[0] >> 4) & 0x7) + 12;
120 CAS
= ((mr0
[0] >> 4) & 0x7) + 4;
123 for (channel
= 0; channel
< 2; channel
++) {
124 mad_dimm
[channel
] = read_mchbar32(0x5004 + 4 * channel
);
127 printf(".rankmap = { 0x%x, 0x%x },\n", rankmap
[0], rankmap
[1]);
129 printf(".mad_dimm = { 0x%x, 0x%x },\n", mad_dimm
[0], mad_dimm
[1]);
131 for (channel
= 0; channel
< 2; channel
++)
132 if (rankmap
[channel
]) {
134 static const u8 mr0_wr_t
[12] =
135 { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 };
136 reg
= read_mchbar32(0x4004 + 0x400 * channel
);
138 ctWR
= (reg
>> 24) & 0x3f;
139 if (tWR
&& ctWR
!= tWR
)
140 printf("/* tWR mismatch: %d, %d */\n", tWR
,
144 if (((mr0
[channel
] >> 9) & 7) != mr0_wr_t
[tWR
- 5])
145 printf("/* encoded tWR mismatch: %d, %d */\n",
146 ((mr0
[channel
] >> 9) & 7),
148 reg_4004_b30
[channel
] = reg
>> 30;
149 tFAW
[channel
] = (reg
>> 16) & 0xff;
150 tWTR
[channel
] = (reg
>> 12) & 0xf;
151 tCKE
[channel
] = (reg
>> 8) & 0xf;
152 tRTP
[channel
] = (reg
>> 4) & 0xf;
153 tRRD
[channel
] = (reg
>> 0) & 0xf;
155 reg
= read_mchbar32(0x4000 + 0x400 * channel
);
156 tRAS
[channel
] = reg
>> 16;
157 tCWL
[channel
] = (reg
>> 12) & 0xf;
158 if (CAS
!= ((reg
>> 8) & 0xf))
159 printf("/* CAS mismatch: %d, %d. */\n", CAS
,
161 tRP
[channel
] = (reg
>> 4) & 0xf;
162 tRCD
[channel
] = reg
& 0xf;
164 reg
= read_mchbar32(0x400c + channel
* 0x400);
165 tXPDLL
[channel
] = reg
& 0x1f;
166 tXP
[channel
] = (reg
>> 5) & 7;
167 tAONPD
[channel
] = (reg
>> 8) & 0xff;
169 printf(".mobile = %d,\n", (mr0
[0] >> 12) & 1);
170 print_time("CAS", CAS
, tCK
);
171 print_time("tWR", tWR
, tCK
);
173 printf(".reg_4004_b30 = { %d, %d },\n", reg_4004_b30
[0],
175 if (tFAW
[0] != tFAW
[1] && two_channels
)
176 printf("/* tFAW mismatch: %d, %d */\n", tFAW
[0], tFAW
[1]);
177 print_time("tFAW", tFAW
[0], tCK
);
178 if (tWTR
[0] != tWTR
[1] && two_channels
)
179 printf("/* tWTR mismatch: %d, %d */\n", tWTR
[0], tWTR
[1]);
180 print_time("tWTR", tWTR
[0], tCK
);
181 if (tCKE
[0] != tCKE
[1] && two_channels
)
182 printf("/* tCKE mismatch: %d, %d */\n", tCKE
[0], tCKE
[1]);
183 print_time("tCKE", tCKE
[0], tCK
);
184 if (tRTP
[0] != tRTP
[1] && two_channels
)
185 printf("/* tRTP mismatch: %d, %d */\n", tRTP
[0], tRTP
[1]);
186 print_time("tRTP", tRTP
[0], tCK
);
187 if (tRRD
[0] != tRRD
[1] && two_channels
)
188 printf("/* tRRD mismatch: %d, %d */\n", tRRD
[0], tRRD
[1]);
189 print_time("tRRD", tRRD
[0], tCK
);
191 if (tRAS
[0] != tRAS
[1] && two_channels
)
192 printf("/* tRAS mismatch: %d, %d */\n", tRAS
[0], tRAS
[1]);
193 print_time("tRAS", tRAS
[0], tCK
);
195 if (tCWL
[0] != tCWL
[1] && two_channels
)
196 printf("/* tCWL mismatch: %d, %d */\n", tCWL
[0], tCWL
[1]);
197 print_time("tCWL", tCWL
[0], tCK
);
199 if (tRP
[0] != tRP
[1] && two_channels
)
200 printf("/* tRP mismatch: %d, %d */\n", tRP
[0], tRP
[1]);
201 print_time("tRP", tRP
[0], tCK
);
203 if (tRCD
[0] != tRCD
[1] && two_channels
)
204 printf("/* tRCD mismatch: %d, %d */\n", tRCD
[0], tRCD
[1]);
205 print_time("tRCD", tRCD
[0], tCK
);
207 if (tXPDLL
[0] != tXPDLL
[1] && two_channels
)
208 printf("/* tXPDLL mismatch: %d, %d */\n", tXPDLL
[0], tXPDLL
[1]);
209 print_time("tXPDLL", tXPDLL
[0], tCK
);
211 if (tXP
[0] != tXP
[1] && two_channels
)
212 printf("/* tXP mismatch: %d, %d */\n", tXP
[0], tXP
[1]);
213 print_time("tXP", tXP
[0], tCK
);
215 if (tAONPD
[0] != tAONPD
[1] && two_channels
)
216 printf("/* tAONPD mismatch: %d, %d */\n", tAONPD
[0], tAONPD
[1]);
217 print_time("tAONPD", tAONPD
[0], tCK
);
219 reg
= read_mchbar32(0x4298);
220 if (reg
!= read_mchbar32(0x4698) && two_channels
)
221 printf("/* 4298 mismatch: %d, %d */\n", reg
,
222 read_mchbar32(0x4698));
224 tREFI
= reg
& 0xffff;
225 print_time("tREFI", tREFI
, tCK
);
226 if ((tREFI
* 9 / 1024) != (reg
>> 25))
227 printf("/* tREFI mismatch: %d, %d */\n", tREFI
* 9 / 1024,
229 tRFC
= (reg
>> 16) & 0x1ff;
230 print_time("tRFC", tRFC
, tCK
);
232 reg
= read_mchbar32(0x42a4);
233 if (reg
!= read_mchbar32(0x46a4) && two_channels
)
234 printf("/* 42a4 mismatch: %d, %d */\n", reg
,
235 read_mchbar32(0x46a4));
237 print_time("tMOD", 8 + ((reg
>> 28) & 0xf), tCK
);
239 tXSOffset
= 512 - ((reg
>> 16) & 0x3ff);
240 print_time("tXSOffset", tXSOffset
, tCK
);
241 if (tXSOffset
!= ((reg
>> 12) & 0xf))
242 printf("/* tXSOffset mismatch: %d, %d */\n",
243 tXSOffset
, (reg
>> 12) & 0xf);
244 if (512 != (reg
& 0xfff))
245 printf("/* tDLLK mismatch: %d, %d */\n", 512, reg
& 0xfff);
247 reg
= read_mchbar32(0x5064);
248 printf(".reg5064b0 = 0x%x,\n", reg
& 0xfff);
249 if ((reg
>> 12) != 0x73)
250 printf("/* mismatch 0x%x, 0x73. */\n", reg
<< 12);
252 unsigned int ch0size
, ch1size
;
254 switch (read_mchbar32(0x5000)) {
256 reg
= read_mchbar32(0x5014);
258 if (((reg
>> 16) & 0xff) != 2 * ch1size
)
259 printf("/* ch1size mismatch: %d, %d*/\n",
260 2 * ch1size
, ((ch1size
>> 16) & 0xff));
261 printf(".channel_size_mb = { ?, %d },\n", ch1size
* 256);
264 reg
= read_mchbar32(0x5014);
266 if (((reg
>> 16) & 0xff) != 2 * ch0size
)
267 printf("/* ch0size mismatch: %d, %d*/\n",
268 2 * ch0size
, ((ch0size
>> 16) & 0xff));
269 printf(".channel_size_mb = { %d, ? },\n", ch0size
* 256);
273 for (channel
= 0; channel
< 2; channel
++) {
274 reg
= mad_dimm
[channel
];
275 int swap
= (reg
>> 16) & 1;
276 slots
[channel
][swap
].size_mb
= (reg
& 0xff) * 256;
277 slots
[channel
][swap
].ranks
= 1 + ((reg
>> 17) & 1);
278 slots
[channel
][swap
].width
= 8 + 8 * ((reg
>> 19) & 1);
279 slots
[channel
][!swap
].size_mb
= ((reg
>> 8) & 0xff) * 256;
280 slots
[channel
][!swap
].ranks
= 1 + ((reg
>> 18) & 1);
281 slots
[channel
][!swap
].width
= 8 + 8 * ((reg
>> 20) & 1);
283 /* Undetermined: rank mirror, other modes, asr, ext_temp. */
284 memset(spd
, 0, sizeof(spd
));
285 for (channel
= 0; channel
< 2; channel
++)
286 for (slot
= 0; slot
< 2; slot
++)
287 if (slots
[channel
][slot
].size_mb
) {
288 printf("/* CH%dS%d: %d MiB */\n", channel
,
289 slot
, slots
[channel
][slot
].size_mb
);
291 for (channel
= 0; channel
< 2; channel
++)
292 for (slot
= 0; slot
< 2; slot
++)
293 if (slots
[channel
][slot
].size_mb
) {
295 unsigned int ras
, rc
, rfc
, faw
;
298 ffs(slots
[channel
][slot
].size_mb
*
299 slots
[channel
][slot
].width
/
300 (slots
[channel
][slot
].ranks
* 64)) - 1 -
303 spd
[channel
][slot
][0] = 0x92;
304 spd
[channel
][slot
][1] = 0x11;
305 spd
[channel
][slot
][2] = 0xb; /* DDR3 */
306 spd
[channel
][slot
][3] = 3; /* SODIMM, should we use another type for desktop? */
307 spd
[channel
][slot
][4] = capacity_shift
| 0; /* 8 Banks. */
308 spd
[channel
][slot
][5] = 0; /* FIXME */
309 spd
[channel
][slot
][6] = 0; /* FIXME */
310 spd
[channel
][slot
][7] =
311 ((slots
[channel
][slot
].ranks
-
312 1) << 3) | (ffs(slots
[channel
][slot
].
314 spd
[channel
][slot
][8] = 3; /* Bus width 64b. No ECC yet. */
315 spd
[channel
][slot
][9] = 0x52; /* 2.5ps. FIXME: choose dynamically if needed. */
316 spd
[channel
][slot
][10] = 0x01;
317 spd
[channel
][slot
][11] = 0x08; /* 1/8 ns. FIXME: choose dynamically if needed. */
318 spd
[channel
][slot
][12] = make_spd_time(1, tCK
);
319 spd
[channel
][slot
][13] = 0;
320 spd
[channel
][slot
][14] =
321 (1 << (CAS
- 4)) & 0xff;
322 spd
[channel
][slot
][15] = (1 << (CAS
- 4)) >> 8;
323 spd
[channel
][slot
][16] =
324 make_spd_time(CAS
, tCK
);
325 spd
[channel
][slot
][17] =
326 make_spd_time(tWR
, tCK
);
327 spd
[channel
][slot
][18] =
328 make_spd_time(tRCD
[channel
], tCK
);
329 spd
[channel
][slot
][19] =
330 make_spd_time(tRRD
[channel
], tCK
);
331 spd
[channel
][slot
][20] =
332 make_spd_time(tRP
[channel
], tCK
);
333 ras
= make_spd_time(tRAS
[channel
], tCK
);
334 rc
= 0x181; /* FIXME: should be make_spd_time(tRC, tCK). */
335 spd
[channel
][slot
][22] = ras
;
336 spd
[channel
][slot
][23] = rc
;
337 spd
[channel
][slot
][21] =
338 ((ras
>> 8) & 0xf) | ((rc
>> 4) & 0xf0);
339 rfc
= make_spd_time(tRFC
, tCK
);
340 spd
[channel
][slot
][24] = rfc
;
341 spd
[channel
][slot
][25] = rfc
>> 8;
342 spd
[channel
][slot
][26] =
343 make_spd_time(tWTR
[channel
], tCK
);
344 spd
[channel
][slot
][27] =
345 make_spd_time(tRTP
[channel
], tCK
);
346 faw
= make_spd_time(tFAW
[channel
], tCK
);
347 spd
[channel
][slot
][28] = faw
>> 8;
348 spd
[channel
][slot
][29] = faw
;
349 spd
[channel
][slot
][30] = 0; /* FIXME */
350 spd
[channel
][slot
][31] = 0; /* FIXME */
351 spd
[channel
][slot
][32] = 0; /* FIXME */
352 spd
[channel
][slot
][33] = 0; /* FIXME */
353 spd
[channel
][slot
][62] = 0x65; /* Reference card F. FIXME */
354 spd
[channel
][slot
][63] = 0; /* FIXME */
355 crc
= spd_ddr3_calc_crc(spd
[channel
][slot
]);
356 spd
[channel
][slot
][126] = crc
;
357 spd
[channel
][slot
][127] = crc
>> 8;
360 printf("/* SPD matching current mode: */\n");
362 FILE *dump_spd
= NULL
;
365 dump_spd
= fopen (dump_spd_file
, "wb");
367 fprintf (stderr
, "Couldn't open file %s: %s\n", dump_spd_file
,
373 for (channel
= 0; channel
< 2; channel
++)
374 for (slot
= 0; slot
< 2; slot
++)
376 if (slots
[channel
][slot
].size_mb
) {
379 printf("/* CH%dS%d */\n", channel
, slot
);
381 for (i
= 0; i
< 256; i
++) {
382 if ((i
& 0xf) == 0x0)
384 printf("%02x ", spd
[channel
][slot
][i
]);
385 if ((i
& 0xf) == 0xf)
391 fwrite(spd
[channel
][slot
], 1, 256, dump_spd
);
396 memset (zero
, 0, 256);
397 fwrite(zero
, 1, 256, dump_spd
);