xref: /aosp_15_r20/external/coreboot/util/inteltool/ivy_memory.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <inttypes.h>
7 #include <errno.h>
8 #include "inteltool.h"
9 
10 extern volatile uint8_t *mchbar;
11 
read_mchbar32(uint32_t addr)12 static uint32_t read_mchbar32(uint32_t addr)
13 {
14 	return *(volatile uint32_t *)(mchbar + addr);
15 }
16 
17 static void
print_time(const char * string,unsigned long long time,unsigned long long tCK)18 print_time(const char *string, unsigned long long time, unsigned long long tCK)
19 {
20 	printf(".%s = %lld /* %lld clocks = %.3lf ns */,\n",
21 	       string, time, time, (time * tCK) / 256.0);
22 }
23 
24 static unsigned int
make_spd_time(unsigned long long time,unsigned long long tCK)25 make_spd_time(unsigned long long time, unsigned long long tCK)
26 {
27 	return (time * tCK) >> 5;
28 }
29 
spd_ddr3_calc_crc(u8 * spd)30 static u16 spd_ddr3_calc_crc(u8 * spd)
31 {
32 	int n_crc, i;
33 	u8 *ptr;
34 	u16 crc;
35 
36 	/* Find the number of bytes covered by CRC */
37 	if (spd[0] & 0x80) {
38 		n_crc = 117;
39 	} else {
40 		n_crc = 126;
41 	}
42 
43 	/* Compute the CRC */
44 	crc = 0;
45 	ptr = spd;
46 	while (--n_crc >= 0) {
47 		crc = crc ^ (int)*ptr++ << 8;
48 		for (i = 0; i < 8; ++i)
49 			if (crc & 0x8000) {
50 				crc = crc << 1 ^ 0x1021;
51 			} else {
52 				crc = crc << 1;
53 			}
54 	}
55 	return crc;
56 }
57 
ivybridge_dump_timings(const char * dump_spd_file)58 void ivybridge_dump_timings(const char *dump_spd_file)
59 {
60 	u32 mr0[2];
61 	u32 mr1[2];
62 	u32 reg;
63 	unsigned int CAS[2] = { 0 };
64 	int tWR = 0, tRFC = 0;
65 	int tFAW[2], tWTR[2], tCKE[2], tRTP[2], tRRD[2];
66 	int channel, slot;
67 	u32 reg_4004_b30[2] = { 0, 0 };
68 	unsigned int tREFI;
69 	int rankmap[2];
70 	u32 mad_dimm[2];
71 	unsigned int tRCD[2], tXP[2], tXPDLL[2], tRAS[2], tCWL[2], tRP[2],
72 	    tAONPD[2];
73 	unsigned int tXSOffset;
74 	int two_channels = 1;
75 	struct slot_info {
76 		unsigned int size_mb;
77 		unsigned int ranks;
78 		unsigned int width;
79 	} slots[2][2];
80 	unsigned int tCK;
81 	u8 spd[2][2][256];
82 
83 	memset(slots, 0, sizeof(slots));
84 
85 	for (channel = 0; channel < 2; channel++) {
86 		rankmap[channel] = read_mchbar32(0xc14 + 0x100 * channel) >> 24;
87 	}
88 
89 	if ((rankmap[0] == 0) && (rankmap[1] == 0)) {
90 		fputs("Error: no memory channels found\n", stderr);
91 		exit(1);
92 	}
93 
94 	two_channels = rankmap[0] && rankmap[1];
95 
96 	mr0[0] = read_mchbar32(0x0004);
97 	mr1[0] = read_mchbar32(0x0008);
98 	mr0[1] = read_mchbar32(0x0104);
99 	mr1[1] = read_mchbar32(0x0108);
100 
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]);
105 
106 	reg = read_mchbar32(0x5e00) & ~0x80000000;
107 	printf(" .tCK = TCK_MHZ%d,\n", 400 * reg / 3);
108 
109 	tCK = (64 * 10 * 3) / reg;
110 
111 	for (channel = 0; channel < 2; channel++) {
112 		mad_dimm[channel] = read_mchbar32(0x5004 + 4 * channel);
113 
114 		if (mr0[channel]) {
115 			if (mr0[channel] & 1) {
116 				CAS[channel] = ((mr0[channel] >> 4) & 0x7) + 12;
117 			} else {
118 				CAS[channel] = ((mr0[channel] >> 4) & 0x7) + 4;
119 			}
120 		}
121 	}
122 
123 	printf(".rankmap = { 0x%x, 0x%x },\n", rankmap[0], rankmap[1]);
124 
125 	printf(".mad_dimm = { 0x%x, 0x%x },\n", mad_dimm[0], mad_dimm[1]);
126 
127 	for (channel = 0; channel < 2; channel++)
128 		if (rankmap[channel]) {
129 			int ctWR;
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);
133 
134 			ctWR = (reg >> 24) & 0x3f;
135 			if (tWR && ctWR != tWR)
136 				printf("/* tWR mismatch: %d, %d */\n", tWR,
137 				       ctWR);
138 			if (!tWR)
139 				tWR = ctWR;
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),
143 				       mr0_wr_t[tWR - 5]);
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;
150 
151 			reg = read_mchbar32(0x4000 + 0x400 * channel);
152 			tRAS[channel] = reg >> 16;
153 			tCWL[channel] = (reg >> 12) & 0xf;
154 			if (CAS[channel]) {
155 				if (CAS[channel] != ((reg >> 8) & 0xf))
156 					printf("/* CAS mismatch: %d, %d. */\n", CAS[channel],
157 					       (reg >> 8) & 0xf);
158 			} else {
159 				CAS[channel] = (reg >> 8) & 0xf;
160 			}
161 			tRP[channel] = (reg >> 4) & 0xf;
162 			tRCD[channel] = reg & 0xf;
163 
164 			reg = read_mchbar32(0x400c + channel * 0x400);
165 			tXPDLL[channel] = reg & 0x1f;
166 			tXP[channel] = (reg >> 5) & 7;
167 			tAONPD[channel] = (reg >> 8) & 0xf;
168 		}
169 	printf(".mobile = %d,\n", (mr0[0] >> 12) & 1);
170 
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);
175 
176 	printf(".reg_4004_b30 = { %d, %d },\n", reg_4004_b30[0],
177 	       reg_4004_b30[1]);
178 
179 	channel = (rankmap[0] != 0) ? 0 : 1;
180 
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);
196 
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);
200 
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);
204 
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);
208 
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);
212 
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);
216 
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);
220 
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);
224 
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));
229 
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,
234 		       (reg >> 25));
235 	tRFC = (reg >> 16) & 0x1ff;
236 	print_time("tRFC", tRFC, tCK);
237 
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));
242 
243 	print_time("tMOD", 8 + ((reg >> 28) & 0xf), tCK);
244 
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);
252 
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);
257 
258 	unsigned int ch0size, ch1size;
259 
260 	switch (read_mchbar32(0x5000)) {
261 	case 0x24:
262 		reg = read_mchbar32(0x5014);
263 		ch1size = reg >> 24;
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);
268 		break;
269 	case 0x21:
270 		reg = read_mchbar32(0x5014);
271 		ch0size = reg >> 24;
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);
276 		break;
277 	}
278 
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);
288 	}
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);
296 			}
297 	for (channel = 0; channel < 2; channel++)
298 		for (slot = 0; slot < 2; slot++)
299 			if (slots[channel][slot].size_mb) {
300 				int capacity_shift;
301 				unsigned int ras, rc, rfc, faw;
302 				u16 crc;
303 				capacity_shift =
304 				    ffs(slots[channel][slot].size_mb *
305 					slots[channel][slot].width /
306 					(slots[channel][slot].ranks * 64)) - 1 -
307 				    5;
308 
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].
319 						      width) - 1 - 2);
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;
364 			}
365 
366 	printf("/* SPD matching current mode:  */\n");
367 
368 	FILE *dump_spd = NULL;
369 
370 	if (dump_spd_file) {
371 		dump_spd = fopen (dump_spd_file, "wb");
372 		if (!dump_spd) {
373 			fprintf (stderr, "Couldn't open file %s: %s\n", dump_spd_file,
374 				 strerror (errno));
375 			exit (1);
376 		}
377 	}
378 
379 	for (channel = 0; channel < 2; channel++)
380 		for (slot = 0; slot < 2; slot++)
381 		{
382 			if (slots[channel][slot].size_mb) {
383 				int i;
384 
385 				printf("/* CH%dS%d  */\n", channel, slot);
386 
387 				for (i = 0; i < 256; i++) {
388 					if ((i & 0xf) == 0x0)
389 						printf("%02x: ", i);
390 					printf("%02x ", spd[channel][slot][i]);
391 					if ((i & 0xf) == 0xf)
392 						printf("\n");
393 				}
394 				printf("\n");
395 
396 				if (dump_spd) {
397 					fwrite(spd[channel][slot], 1, 256, dump_spd);
398 				}
399 			} else {
400 				if (dump_spd) {
401 					char zero[256];
402 					memset (zero, 0, 256);
403 					fwrite(zero, 1, 256, dump_spd);
404 				}
405 			}
406 		}
407 	if (dump_spd) {
408 		fclose (dump_spd);
409 	}
410 
411 }
412