1 /* SPDX-License-Identifier: GPL-2.0-or-later */
10 extern volatile uint8_t *mchbar
;
12 static uint32_t read_mchbar32(uint32_t addr
)
14 return *(volatile uint32_t *)(mchbar
+ addr
);
18 print_time(const char *string
, unsigned long long time
, unsigned long long tCK
)
20 printf(".%s = %lld /* %lld clocks = %.3lf ns */,\n",
21 string
, time
, time
, (time
* tCK
) / 256.0);
25 make_spd_time(unsigned long long time
, unsigned long long tCK
)
27 return (time
* tCK
) >> 5;
30 static u16
spd_ddr3_calc_crc(u8
* spd
)
36 /* Find the number of bytes covered by CRC */
46 while (--n_crc
>= 0) {
47 crc
= crc
^ (int)*ptr
++ << 8;
48 for (i
= 0; i
< 8; ++i
)
50 crc
= crc
<< 1 ^ 0x1021;
58 void ivybridge_dump_timings(const char *dump_spd_file
)
63 unsigned int CAS
[2] = { 0 };
64 int tWR
= 0, tRFC
= 0;
65 int tFAW
[2], tWTR
[2], tCKE
[2], tRTP
[2], tRRD
[2];
67 u32 reg_4004_b30
[2] = { 0, 0 };
71 unsigned int tRCD
[2], tXP
[2], tXPDLL
[2], tRAS
[2], tCWL
[2], tRP
[2],
73 unsigned int tXSOffset
;
83 memset(slots
, 0, sizeof(slots
));
85 for (channel
= 0; channel
< 2; channel
++) {
86 rankmap
[channel
] = read_mchbar32(0xc14 + 0x100 * channel
) >> 24;
89 if ((rankmap
[0] == 0) && (rankmap
[1] == 0)) {
90 fputs("Error: no memory channels found\n", stderr
);
94 two_channels
= rankmap
[0] && rankmap
[1];
96 mr0
[0] = read_mchbar32(0x0004);
97 mr1
[0] = read_mchbar32(0x0008);
98 mr0
[1] = read_mchbar32(0x0104);
99 mr1
[1] = read_mchbar32(0x0108);
101 if (mr0
[0] != mr0
[1] && two_channels
)
102 printf("MR0 mismatch: %x, %x\n", mr0
[0], mr0
[1]);
103 if (mr1
[0] != mr1
[1] && two_channels
)
104 printf("MR1 mismatch: %x, %x\n", mr1
[0], mr1
[1]);
106 reg
= read_mchbar32(0x5e00) & ~0x80000000;
107 printf(" .tCK = TCK_MHZ%d,\n", 400 * reg
/ 3);
109 tCK
= (64 * 10 * 3) / reg
;
111 for (channel
= 0; channel
< 2; channel
++) {
112 mad_dimm
[channel
] = read_mchbar32(0x5004 + 4 * channel
);
115 if (mr0
[channel
] & 1) {
116 CAS
[channel
] = ((mr0
[channel
] >> 4) & 0x7) + 12;
118 CAS
[channel
] = ((mr0
[channel
] >> 4) & 0x7) + 4;
123 printf(".rankmap = { 0x%x, 0x%x },\n", rankmap
[0], rankmap
[1]);
125 printf(".mad_dimm = { 0x%x, 0x%x },\n", mad_dimm
[0], mad_dimm
[1]);
127 for (channel
= 0; channel
< 2; channel
++)
128 if (rankmap
[channel
]) {
130 static const u8 mr0_wr_t
[12] =
131 { 1, 2, 3, 4, 0, 5, 0, 6, 0, 7, 0, 0 };
132 reg
= read_mchbar32(0x4004 + 0x400 * channel
);
134 ctWR
= (reg
>> 24) & 0x3f;
135 if (tWR
&& ctWR
!= tWR
)
136 printf("/* tWR mismatch: %d, %d */\n", tWR
,
140 if (mr0
[channel
] && ((mr0
[channel
] >> 9) & 7) != mr0_wr_t
[tWR
- 5])
141 printf("/* encoded tWR mismatch: %d, %d */\n",
142 ((mr0
[channel
] >> 9) & 7),
144 reg_4004_b30
[channel
] = reg
>> 30;
145 tFAW
[channel
] = (reg
>> 16) & 0xff;
146 tWTR
[channel
] = (reg
>> 12) & 0xf;
147 tCKE
[channel
] = (reg
>> 8) & 0xf;
148 tRTP
[channel
] = (reg
>> 4) & 0xf;
149 tRRD
[channel
] = (reg
>> 0) & 0xf;
151 reg
= read_mchbar32(0x4000 + 0x400 * channel
);
152 tRAS
[channel
] = reg
>> 16;
153 tCWL
[channel
] = (reg
>> 12) & 0xf;
155 if (CAS
[channel
] != ((reg
>> 8) & 0xf))
156 printf("/* CAS mismatch: %d, %d. */\n", CAS
[channel
],
159 CAS
[channel
] = (reg
>> 8) & 0xf;
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) & 0xf;
169 printf(".mobile = %d,\n", (mr0
[0] >> 12) & 1);
171 if (two_channels
&& CAS
[0] != CAS
[1])
172 printf("/* CAS mismatch: %d, %d */\n", CAS
[0], CAS
[1]);
173 print_time("CAS", CAS
[0], tCK
);
174 print_time("tWR", tWR
, tCK
);
176 printf(".reg_4004_b30 = { %d, %d },\n", reg_4004_b30
[0],
179 channel
= (rankmap
[0] != 0) ? 0 : 1;
181 if (two_channels
&& tFAW
[0] != tFAW
[1])
182 printf("/* tFAW mismatch: %d, %d */\n", tFAW
[0], tFAW
[1]);
183 print_time("tFAW", tFAW
[channel
], tCK
);
184 if (two_channels
&& tWTR
[0] != tWTR
[1])
185 printf("/* tWTR mismatch: %d, %d */\n", tWTR
[0], tWTR
[1]);
186 print_time("tWTR", tWTR
[channel
], tCK
);
187 if (two_channels
&& tCKE
[0] != tCKE
[1])
188 printf("/* tCKE mismatch: %d, %d */\n", tCKE
[0], tCKE
[1]);
189 print_time("tCKE", tCKE
[channel
], tCK
);
190 if (two_channels
&& tRTP
[0] != tRTP
[1])
191 printf("/* tRTP mismatch: %d, %d */\n", tRTP
[0], tRTP
[1]);
192 print_time("tRTP", tRTP
[channel
], tCK
);
193 if (two_channels
&& tRRD
[0] != tRRD
[1])
194 printf("/* tRRD mismatch: %d, %d */\n", tRRD
[0], tRRD
[1]);
195 print_time("tRRD", tRRD
[channel
], tCK
);
197 if (two_channels
&& tRAS
[0] != tRAS
[1])
198 printf("/* tRAS mismatch: %d, %d */\n", tRAS
[0], tRAS
[1]);
199 print_time("tRAS", tRAS
[channel
], tCK
);
201 if (two_channels
&& tCWL
[0] != tCWL
[1])
202 printf("/* tCWL mismatch: %d, %d */\n", tCWL
[0], tCWL
[1]);
203 print_time("tCWL", tCWL
[channel
], tCK
);
205 if (two_channels
&& tRP
[0] != tRP
[1])
206 printf("/* tRP mismatch: %d, %d */\n", tRP
[0], tRP
[1]);
207 print_time("tRP", tRP
[channel
], tCK
);
209 if (two_channels
&& tRCD
[0] != tRCD
[1])
210 printf("/* tRCD mismatch: %d, %d */\n", tRCD
[0], tRCD
[1]);
211 print_time("tRCD", tRCD
[channel
], tCK
);
213 if (two_channels
&& tXPDLL
[0] != tXPDLL
[1])
214 printf("/* tXPDLL mismatch: %d, %d */\n", tXPDLL
[0], tXPDLL
[1]);
215 print_time("tXPDLL", tXPDLL
[channel
], tCK
);
217 if (two_channels
&& tXP
[0] != tXP
[1])
218 printf("/* tXP mismatch: %d, %d */\n", tXP
[0], tXP
[1]);
219 print_time("tXP", tXP
[channel
], tCK
);
221 if (two_channels
&& tAONPD
[0] != tAONPD
[1])
222 printf("/* tAONPD mismatch: %d, %d */\n", tAONPD
[0], tAONPD
[1]);
223 print_time("tAONPD", tAONPD
[channel
], tCK
);
225 reg
= read_mchbar32(0x4298);
226 if (reg
!= read_mchbar32(0x4698) && two_channels
)
227 printf("/* 4298 mismatch: %d, %d */\n", reg
,
228 read_mchbar32(0x4698));
230 tREFI
= reg
& 0xffff;
231 print_time("tREFI", tREFI
, tCK
);
232 if ((tREFI
* 9 / 1024) != (reg
>> 25))
233 printf("/* tREFI mismatch: %d, %d */\n", tREFI
* 9 / 1024,
235 tRFC
= (reg
>> 16) & 0x1ff;
236 print_time("tRFC", tRFC
, tCK
);
238 reg
= read_mchbar32(0x42a4);
239 if (reg
!= read_mchbar32(0x46a4) && two_channels
)
240 printf("/* 42a4 mismatch: %d, %d */\n", reg
,
241 read_mchbar32(0x46a4));
243 print_time("tMOD", 8 + ((reg
>> 28) & 0xf), tCK
);
245 tXSOffset
= 512 - ((reg
>> 16) & 0x3ff);
246 print_time("tXSOffset", tXSOffset
, tCK
);
247 if (tXSOffset
!= ((reg
>> 12) & 0xf))
248 printf("/* tXSOffset mismatch: %d, %d */\n",
249 tXSOffset
, (reg
>> 12) & 0xf);
250 if (512 != (reg
& 0xfff))
251 printf("/* tDLLK mismatch: %d, %d */\n", 512, reg
& 0xfff);
253 reg
= read_mchbar32(0x5064);
254 printf(".reg5064b0 = 0x%x,\n", reg
& 0xfff);
255 if ((reg
>> 12) != 0x73)
256 printf("/* mismatch 0x%x, 0x73. */\n", reg
<< 12);
258 unsigned int ch0size
, ch1size
;
260 switch (read_mchbar32(0x5000)) {
262 reg
= read_mchbar32(0x5014);
264 if (((reg
>> 16) & 0xff) != 2 * ch1size
)
265 printf("/* ch1size mismatch: %d, %d*/\n",
266 2 * ch1size
, ((ch1size
>> 16) & 0xff));
267 printf(".channel_size_mb = { ?, %d },\n", ch1size
* 256);
270 reg
= read_mchbar32(0x5014);
272 if (((reg
>> 16) & 0xff) != 2 * ch0size
)
273 printf("/* ch0size mismatch: %d, %d*/\n",
274 2 * ch0size
, ((ch0size
>> 16) & 0xff));
275 printf(".channel_size_mb = { %d, ? },\n", ch0size
* 256);
279 for (channel
= 0; channel
< 2; channel
++) {
280 reg
= mad_dimm
[channel
];
281 int swap
= (reg
>> 16) & 1;
282 slots
[channel
][swap
].size_mb
= (reg
& 0xff) * 256;
283 slots
[channel
][swap
].ranks
= 1 + ((reg
>> 17) & 1);
284 slots
[channel
][swap
].width
= 8 + 8 * ((reg
>> 19) & 1);
285 slots
[channel
][!swap
].size_mb
= ((reg
>> 8) & 0xff) * 256;
286 slots
[channel
][!swap
].ranks
= 1 + ((reg
>> 18) & 1);
287 slots
[channel
][!swap
].width
= 8 + 8 * ((reg
>> 20) & 1);
289 /* Undetermined: rank mirror, other modes, asr, ext_temp. */
290 memset(spd
, 0, sizeof(spd
));
291 for (channel
= 0; channel
< 2; channel
++)
292 for (slot
= 0; slot
< 2; slot
++)
293 if (slots
[channel
][slot
].size_mb
) {
294 printf("/* CH%dS%d: %d MiB */\n", channel
,
295 slot
, slots
[channel
][slot
].size_mb
);
297 for (channel
= 0; channel
< 2; channel
++)
298 for (slot
= 0; slot
< 2; slot
++)
299 if (slots
[channel
][slot
].size_mb
) {
301 unsigned int ras
, rc
, rfc
, faw
;
304 ffs(slots
[channel
][slot
].size_mb
*
305 slots
[channel
][slot
].width
/
306 (slots
[channel
][slot
].ranks
* 64)) - 1 -
309 spd
[channel
][slot
][0] = 0x92;
310 spd
[channel
][slot
][1] = 0x11;
311 spd
[channel
][slot
][2] = 0xb; /* DDR3 */
312 spd
[channel
][slot
][3] = 3; /* SODIMM, should we use another type for desktop? */
313 spd
[channel
][slot
][4] = capacity_shift
| 0; /* 8 Banks. */
314 spd
[channel
][slot
][5] = 0; /* FIXME */
315 spd
[channel
][slot
][6] = 0; /* FIXME */
316 spd
[channel
][slot
][7] =
317 ((slots
[channel
][slot
].ranks
-
318 1) << 3) | (ffs(slots
[channel
][slot
].
320 spd
[channel
][slot
][8] = 3; /* Bus width 64b. No ECC yet. */
321 spd
[channel
][slot
][9] = 0x52; /* 2.5ps. FIXME: choose dynamically if needed. */
322 spd
[channel
][slot
][10] = 0x01;
323 spd
[channel
][slot
][11] = 0x08; /* 1/8 ns. FIXME: choose dynamically if needed. */
324 spd
[channel
][slot
][12] = make_spd_time(1, tCK
);
325 spd
[channel
][slot
][13] = 0;
326 spd
[channel
][slot
][14] =
327 (1 << (CAS
[channel
] - 4)) & 0xff;
328 spd
[channel
][slot
][15] = (1 << (CAS
[channel
] - 4)) >> 8;
329 spd
[channel
][slot
][16] =
330 make_spd_time(CAS
[channel
], tCK
);
331 spd
[channel
][slot
][17] =
332 make_spd_time(tWR
, tCK
);
333 spd
[channel
][slot
][18] =
334 make_spd_time(tRCD
[channel
], tCK
);
335 spd
[channel
][slot
][19] =
336 make_spd_time(tRRD
[channel
], tCK
);
337 spd
[channel
][slot
][20] =
338 make_spd_time(tRP
[channel
], tCK
);
339 ras
= make_spd_time(tRAS
[channel
], tCK
);
340 rc
= 0x181; /* FIXME: should be make_spd_time(tRC, tCK). */
341 spd
[channel
][slot
][22] = ras
;
342 spd
[channel
][slot
][23] = rc
;
343 spd
[channel
][slot
][21] =
344 ((ras
>> 8) & 0xf) | ((rc
>> 4) & 0xf0);
345 rfc
= make_spd_time(tRFC
, tCK
);
346 spd
[channel
][slot
][24] = rfc
;
347 spd
[channel
][slot
][25] = rfc
>> 8;
348 spd
[channel
][slot
][26] =
349 make_spd_time(tWTR
[channel
], tCK
);
350 spd
[channel
][slot
][27] =
351 make_spd_time(tRTP
[channel
], tCK
);
352 faw
= make_spd_time(tFAW
[channel
], tCK
);
353 spd
[channel
][slot
][28] = faw
>> 8;
354 spd
[channel
][slot
][29] = faw
;
355 spd
[channel
][slot
][30] = 0; /* FIXME */
356 spd
[channel
][slot
][31] = 0; /* FIXME */
357 spd
[channel
][slot
][32] = 0; /* FIXME */
358 spd
[channel
][slot
][33] = 0; /* FIXME */
359 spd
[channel
][slot
][62] = 0x65; /* Reference card F. FIXME */
360 spd
[channel
][slot
][63] = 0; /* FIXME */
361 crc
= spd_ddr3_calc_crc(spd
[channel
][slot
]);
362 spd
[channel
][slot
][126] = crc
;
363 spd
[channel
][slot
][127] = crc
>> 8;
366 printf("/* SPD matching current mode: */\n");
368 FILE *dump_spd
= NULL
;
371 dump_spd
= fopen (dump_spd_file
, "wb");
373 fprintf (stderr
, "Couldn't open file %s: %s\n", dump_spd_file
,
379 for (channel
= 0; channel
< 2; channel
++)
380 for (slot
= 0; slot
< 2; slot
++)
382 if (slots
[channel
][slot
].size_mb
) {
385 printf("/* CH%dS%d */\n", channel
, slot
);
387 for (i
= 0; i
< 256; i
++) {
388 if ((i
& 0xf) == 0x0)
390 printf("%02x ", spd
[channel
][slot
][i
]);
391 if ((i
& 0xf) == 0xf)
397 fwrite(spd
[channel
][slot
], 1, 256, dump_spd
);
402 memset (zero
, 0, 256);
403 fwrite(zero
, 1, 256, dump_spd
);