blob: d30e3e2078a2d7c43a2b94ea01aba778efeecc7b [file] [log] [blame]
Martin Roth4dcd13d2016-02-24 13:53:07 -08001/*
2 * MemTest86+ V5 Specific code (GPL V2.0)
3 * By Samuel DEMEULEMEESTER, sdemeule@memtest.org
4 * http://www.canardpc.com - http://www.memtest.org
5 */
6
Ben Gardnere7c08082016-03-30 16:46:21 -05007#include "stdint.h"
Martin Roth4dcd13d2016-02-24 13:53:07 -08008#include "test.h"
9#include "io.h"
10#include "pci.h"
11#include "msr.h"
12#include "spd.h"
13#include "screen_buffer.h"
14#include "jedec_id.h"
15
16#define NULL 0
17
18#define SMBHSTSTS smbusbase
Stefan Tauner4f8ea892018-08-22 08:13:10 +020019#define SMBHSTCNT (smbusbase + 2)
20#define SMBHSTCMD (smbusbase + 3)
21#define SMBHSTADD (smbusbase + 4)
22#define SMBHSTDAT (smbusbase + 5)
Martin Roth4dcd13d2016-02-24 13:53:07 -080023
Stefan Tauner4f8ea892018-08-22 08:13:10 +020024#define AMD_INDEX_IO_PORT 0xCD6
25#define AMD_DATA_IO_PORT 0xCD7
26#define AMD_SMBUS_BASE_REG 0x2C
27#define AMD_PM_DECODE_EN_REG 0x00
Martin Roth4dcd13d2016-02-24 13:53:07 -080028
Stefan Tauner4f8ea892018-08-22 08:13:10 +020029static int smbdev, smbfun;
30static unsigned short smbusbase;
31static unsigned char spd_raw[256];
Martin Roth4dcd13d2016-02-24 13:53:07 -080032
Stefan Tauner97eacf52018-08-19 10:47:45 +020033static char *convert_hex_to_char(unsigned hex_org)
34{
35 static char buf[2] = " ";
36 if (hex_org >= 0x20 && hex_org < 0x80) {
37 buf[0] = hex_org;
38 } else {
39 //buf[0] = '\0';
40 buf[0] = ' ';
41 }
42
43 return buf;
44}
45
Martin Roth4dcd13d2016-02-24 13:53:07 -080046static void ich5_get_smb(void)
47{
Stefan Taunercc44ba62018-08-22 08:13:23 +020048 unsigned long x;
49 int result;
50 result = pci_conf_read(0, smbdev, smbfun, 0x20, 2, &x);
51 if (result == 0)
52 smbusbase = (unsigned short)x & 0xFFFE;
Martin Roth4dcd13d2016-02-24 13:53:07 -080053}
54
Stefan Tauner4f8ea892018-08-22 08:13:10 +020055static void sb800_get_smb(void)
Martin Roth4dcd13d2016-02-24 13:53:07 -080056{
Krystian Hebel746c8402018-10-31 11:10:25 +010057 int lbyte, hbyte;
Martin Roth4dcd13d2016-02-24 13:53:07 -080058
Krystian Hebel746c8402018-10-31 11:10:25 +010059 __outb(AMD_SMBUS_BASE_REG + 1, AMD_INDEX_IO_PORT);
60 hbyte = __inb(AMD_DATA_IO_PORT);
61 __outb(AMD_SMBUS_BASE_REG, AMD_INDEX_IO_PORT);
62 lbyte = __inb(AMD_DATA_IO_PORT);
Piotr Król08dd5872017-11-01 21:26:41 +010063
Krystian Hebel746c8402018-10-31 11:10:25 +010064 smbusbase = hbyte;
65 smbusbase <<= 8;
66 smbusbase += lbyte;
67 smbusbase &= 0xFFE0;
Martin Roth4dcd13d2016-02-24 13:53:07 -080068
Stefan Taunercc44ba62018-08-22 08:13:23 +020069 if (smbusbase == 0xFFE0) {
70 smbusbase = 0;
71 }
Martin Roth4dcd13d2016-02-24 13:53:07 -080072}
73
Stefan Tauner97eacf52018-08-19 10:47:45 +020074static void sb600_get_smb(void)
75{
76 unsigned long x;
77 int result;
78
HAOUAS Elyesd2519c02019-11-10 12:10:49 +000079 result = pci_conf_read(0, smbdev, smbfun, 0x08, 1, &x);
80
Stefan Tauner97eacf52018-08-19 10:47:45 +020081 if (x < 0x40) {
82 // SB600/700
83 result = pci_conf_read(0, smbdev, smbfun, 0x90, 2, &x);
84 if (result == 0)
85 smbusbase = (unsigned short)x & 0xFFFE;
86 } else {
87 // SB800
88 sb800_get_smb();
89 }
90}
91
Krystian Hebel746c8402018-10-31 11:10:25 +010092static void fch_get_smb(void)
93{
94 int lbyte;
95 unsigned long x;
96
97 pci_conf_read(0, smbdev, smbfun, 0x08, 1, &x);
98
99 /* if processor revision is ML_A0 or ML_A1 use different way for SMBus
100 * IO base calculation */
101 if (x == 0x42 || x == 0x41) {
102 /* read PMx00+1 to get SmbusAsfIoBase */
103 __outb(AMD_PM_DECODE_EN_REG + 1, AMD_INDEX_IO_PORT);
104 lbyte = __inb(AMD_DATA_IO_PORT);
105
106 /* SMBus IO base is defined as {Smbus0AsfIoBase[7:0], 0x00} */
107 smbusbase = (lbyte & 0xFF) << 8;
108 } else {
109 sb800_get_smb();
110 }
111}
112
Stefan Tauner4f8ea892018-08-22 08:13:10 +0200113static unsigned char ich5_smb_read_byte(unsigned char adr, unsigned char cmd)
Martin Roth4dcd13d2016-02-24 13:53:07 -0800114{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200115 int l1, h1, l2, h2;
116 uint64_t t;
117 uint64_t toval = 10 * v->clks_msec;
Ben Gardnere7c08082016-03-30 16:46:21 -0500118
Stefan Taunercc44ba62018-08-22 08:13:23 +0200119 __outb(0x1f, SMBHSTSTS); // reset SMBus Controller
120 __outb(0xff, SMBHSTDAT);
121 while (__inb(SMBHSTSTS) & 0x01)
122 ; // wait until ready
123 __outb(cmd, SMBHSTCMD);
124 __outb((adr << 1) | 0x01, SMBHSTADD);
125 __outb(0x48, SMBHSTCNT);
126 rdtsc(l1, h1);
127 //cprint(POP2_Y, POP2_X + 16, s + cmd % 8); // progress bar
128 while (!(__inb(SMBHSTSTS) & 0x02)) { // wait til command finished
129 rdtsc(l2, h2);
130 t = ((uint64_t) (h2 - h1) * 0xffffffff + (l2 - l1));
131 if (t > toval)
132 break; // break after 10ms
133 }
134 return __inb(SMBHSTDAT);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800135}
136
137static int ich5_read_spd(int dimmadr)
138{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200139 int x;
140 spd_raw[0] = ich5_smb_read_byte(0x50 + dimmadr, 0);
141 if (spd_raw[0] == 0xff)
142 return -1; // no spd here
143 for (x = 1; x < 256; x++) {
144 spd_raw[x] =
145 ich5_smb_read_byte(0x50 + dimmadr, (unsigned char)x);
146 }
147 return 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800148}
149
150static void us15w_get_smb(void)
151{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200152 unsigned long x;
153 int result;
154 result = pci_conf_read(0, 0x1f, 0, 0x40, 2, &x);
155 if (result == 0)
156 smbusbase = (unsigned short)x & 0xFFC0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800157}
158
Stefan Tauner4f8ea892018-08-22 08:13:10 +0200159static unsigned char us15w_smb_read_byte(unsigned char adr, unsigned char cmd)
Martin Roth4dcd13d2016-02-24 13:53:07 -0800160{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200161 int l1, h1, l2, h2;
162 uint64_t t;
163 uint64_t toval = 10 * v->clks_msec;
Ben Gardnere7c08082016-03-30 16:46:21 -0500164
Stefan Taunercc44ba62018-08-22 08:13:23 +0200165 //__outb(0x00, smbusbase + 1); // reset SMBus Controller
166 //__outb(0x00, smbusbase + 6);
167 //while((__inb(smbusbase + 1) & 0x08) != 0)
168 // ; // wait until ready
169 __outb(0x02, smbusbase + 0); // Byte read
170 __outb(cmd, smbusbase + 5); // Command
171 __outb(0x07, smbusbase + 1); // Clear status
172 __outb((adr << 1) | 0x01, smbusbase + 4); // DIMM address
173 __outb(0x12, smbusbase + 0); // Start
174 //while (((__inb(smbusbase + 1) & 0x08) == 0))
175 // ; // wait until busy
176 rdtsc(l1, h1);
177 static const char s[] = { '/', 0, '-', 0, '\\', 0, '|', 0 };
178 cprint(POP2_Y, POP2_X + 16, s + cmd % 8); // progress bar
179
180 // wait til command finished
181 while (((__inb(smbusbase + 1) & 0x01) == 0) || ((__inb(smbusbase + 1) & 0x08) != 0)) {
182 rdtsc(l2, h2);
183 t = ((uint64_t) (h2 - h1) * 0xffffffff + (l2 - l1));
184 if (t > toval)
185 break; // break after 10ms
186 }
187 return __inb(smbusbase + 6);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800188}
189
190static int us15w_read_spd(int dimmadr)
191{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200192 int x;
193 spd_raw[0] = us15w_smb_read_byte(0x50 + dimmadr, 0);
194 if (spd_raw[0] == 0xff)
195 return -1; // no spd here
196 for (x = 1; x < 256; x++) {
197 spd_raw[x] =
198 us15w_smb_read_byte(0x50 + dimmadr, (unsigned char)x);
199 }
200 return 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800201}
202
203struct pci_smbus_controller {
Stefan Taunercc44ba62018-08-22 08:13:23 +0200204 unsigned vendor;
205 unsigned device;
206 char *name;
207 void (*get_adr) (void);
208 int (*read_spd) (int dimmadr);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800209};
210
211static struct pci_smbus_controller smbcontrollers[] = {
212 // Intel SMBUS
Stefan Taunercc44ba62018-08-22 08:13:23 +0200213 {0x8086, 0x9C22, "Intel HSW-ULT", ich5_get_smb, ich5_read_spd},
214 {0x8086, 0x8C22, "Intel HSW", ich5_get_smb, ich5_read_spd},
215 {0x8086, 0x1E22, "Intel Z77", ich5_get_smb, ich5_read_spd},
216 {0x8086, 0x1C22, "Intel P67", ich5_get_smb, ich5_read_spd},
217 {0x8086, 0x3B30, "Intel P55", ich5_get_smb, ich5_read_spd},
218 {0x8086, 0x3A60, "Intel ICH10B", ich5_get_smb, ich5_read_spd},
219 {0x8086, 0x3A30, "Intel ICH10R", ich5_get_smb, ich5_read_spd},
220 {0x8086, 0x2930, "Intel ICH9", ich5_get_smb, ich5_read_spd},
221 {0x8086, 0x283E, "Intel ICH8", ich5_get_smb, ich5_read_spd},
222 {0x8086, 0x27DA, "Intel ICH7", ich5_get_smb, ich5_read_spd},
223 {0x8086, 0x266A, "Intel ICH6", ich5_get_smb, ich5_read_spd},
224 {0x8086, 0x24D3, "Intel ICH5", ich5_get_smb, ich5_read_spd},
225 {0x8086, 0x24C3, "Intel ICH4", ich5_get_smb, ich5_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800226 {0x8086, 0x25A4, "Intel 6300ESB", ich5_get_smb, ich5_read_spd},
Stefan Taunercc44ba62018-08-22 08:13:23 +0200227 {0x8086, 0x269B, "Intel ESB2", ich5_get_smb, ich5_read_spd},
228 {0x8086, 0x8119, "Intel US15W", us15w_get_smb, us15w_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800229 {0x8086, 0x5032, "Intel EP80579", ich5_get_smb, ich5_read_spd},
Ben Gardner4b07cbe2016-03-07 09:00:44 -0600230 {0x8086, 0x0f12, "Intel E3800", ich5_get_smb, ich5_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800231
232 // AMD SMBUS
Krystian Hebel746c8402018-10-31 11:10:25 +0100233 {0x1002, 0x4385, "AMD SBx00", sb600_get_smb, ich5_read_spd},
234 {0x1022, 0x780B, "AMD FCH", fch_get_smb, ich5_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800235 {0, 0, "", NULL, NULL}
236};
237
Stefan Tauner4f8ea892018-08-22 08:13:10 +0200238static int find_smb_controller(void)
Martin Roth4dcd13d2016-02-24 13:53:07 -0800239{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200240 int i = 0;
241 unsigned long valuev, valued;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800242
Stefan Taunercc44ba62018-08-22 08:13:23 +0200243 for (smbdev = 0; smbdev < 32; smbdev++) {
244 for (smbfun = 0; smbfun < 8; smbfun++) {
245 pci_conf_read(0, smbdev, smbfun, 0, 2, &valuev);
246 if (valuev != 0xFFFF) { // if there is something look what's it..
247 for (i = 0; smbcontrollers[i].vendor > 0; i++) { // check if this is a known smbus controller
248 if (valuev == smbcontrollers[i].vendor) {
249 pci_conf_read(0, smbdev, smbfun, 2, 2, &valued); // read the device id
250 if (valued == smbcontrollers[i].device) {
251 return i;
252 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800253 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200254 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800255 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200256 }
257 }
258 return -1;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800259}
260
Stefan Tauner97eacf52018-08-19 10:47:45 +0200261
262static int get_ddr3_module_size(int sdram_capacity, int prim_bus_width,
263 int sdram_width, int ranks)
264{
265 int module_size;
266
267 switch (sdram_capacity) {
268 case 0:
269 module_size = 256;
270 break;
271 case 1:
272 module_size = 512;
273 break;
274 default:
275 case 2:
276 module_size = 1024;
277 break;
278 case 3:
279 module_size = 2048;
280 break;
281 case 4:
282 module_size = 4096;
283 break;
284 case 5:
285 module_size = 8192;
286 break;
287 case 6:
288 module_size = 16384;
289 break;
290 }
291
292 module_size /= 8;
293
294 switch (prim_bus_width) {
295 case 0:
296 module_size *= 8;
297 break;
298 case 1:
299 module_size *= 16;
300 break;
301 case 2:
302 module_size *= 32;
303 break;
304 case 3:
305 module_size *= 64;
306 break;
307 }
308
309 switch (sdram_width) {
310 case 0:
311 module_size /= 4;
312 break;
313 case 1:
314 module_size /= 8;
315 break;
316 case 2:
317 module_size /= 16;
318 break;
319 case 3:
320 module_size /= 32;
321 break;
322 }
323
324 module_size *= (ranks + 1);
325
326 return module_size;
327}
328
329static int get_ddr2_module_size(int rank_density_byte, int rank_num_byte)
330{
331 int module_size;
332
333 switch (rank_density_byte) {
334 case 1:
335 module_size = 1024;
336 break;
337 case 2:
338 module_size = 2048;
339 break;
340 case 4:
341 module_size = 4096;
342 break;
343 case 8:
344 module_size = 8192;
345 break;
346 case 16:
347 module_size = 16384;
348 break;
349 case 32:
350 module_size = 128;
351 break;
352 case 64:
353 module_size = 256;
354 break;
355 default:
356 case 128:
357 module_size = 512;
358 break;
359 }
360
361 module_size *= (rank_num_byte & 7) + 1;
362
363 return module_size;
364
365}
366
Martin Roth4dcd13d2016-02-24 13:53:07 -0800367void get_spd_spec(void)
368{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200369 int index;
370 int h, i, j, z;
371 int k = 0;
372 int module_size;
373 int curcol;
374 int temp_nbd;
375 int tck;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800376
Stefan Taunercc44ba62018-08-22 08:13:23 +0200377 index = find_smb_controller();
Martin Roth4dcd13d2016-02-24 13:53:07 -0800378
Stefan Taunercc44ba62018-08-22 08:13:23 +0200379 if (index == -1) {
380 // Unknown SMBUS Controller, exit
381 return;
382 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800383
Stefan Taunercc44ba62018-08-22 08:13:23 +0200384 smbcontrollers[index].get_adr();
385 cprint(LINE_SPD - 2, 0, "Memory SPD Informations");
386 cprint(LINE_SPD - 1, 0, "--------------------------");
Martin Roth4dcd13d2016-02-24 13:53:07 -0800387
Stefan Taunercc44ba62018-08-22 08:13:23 +0200388 for (j = 0; j < 8; j++) {
389 if (smbcontrollers[index].read_spd(j) == 0) {
390 curcol = 1;
391 if (spd_raw[2] == 0x0b) {
392 // We are here if DDR3 present
Martin Roth4dcd13d2016-02-24 13:53:07 -0800393
Stefan Taunercc44ba62018-08-22 08:13:23 +0200394 // First print slot#, module capacity
395 cprint(LINE_SPD + k, curcol, " - Slot :");
396 dprint(LINE_SPD + k, curcol + 8, k, 1, 0);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800397
Stefan Taunercc44ba62018-08-22 08:13:23 +0200398 module_size =
399 get_ddr3_module_size(spd_raw[4] & 0xF,
400 spd_raw[8] & 0x7,
401 spd_raw[7] & 0x7,
402 spd_raw[7] >> 3);
403 temp_nbd = getnum(module_size);
404 curcol += 12;
405 dprint(LINE_SPD + k, curcol, module_size,
406 temp_nbd, 0);
407 curcol += temp_nbd;
408 cprint(LINE_SPD + k, curcol, " MB");
409 curcol += 4;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800410
Stefan Taunercc44ba62018-08-22 08:13:23 +0200411 // If XMP is supported, check Tck in XMP reg
412 if (spd_raw[176] == 0x0C && spd_raw[177] == 0x4A
413 && spd_raw[12]) {
414 tck = spd_raw[186];
415 } else {
416 tck = spd_raw[12];
417 }
418
419 // Then module jedec speed
420 switch (tck) {
421 default:
422 cprint(LINE_SPD + k, curcol,
423 "DDR3-????");
424 break;
425 case 20:
426 cprint(LINE_SPD + k, curcol,
427 "DDR3-800");
428 curcol--;
429 break;
430 case 15:
431 cprint(LINE_SPD + k, curcol,
432 "DDR3-1066");
433 break;
434 case 12:
435 cprint(LINE_SPD + k, curcol,
436 "DDR3-1333");
437 break;
438 case 10:
439 cprint(LINE_SPD + k, curcol,
440 "DDR3-1600");
441 break;
442 case 9:
443 cprint(LINE_SPD + k, curcol,
444 "DDR3-1866");
445 break;
446 case 8:
447 cprint(LINE_SPD + k, curcol,
448 "DDR3-2133");
449 break;
450 case 7:
451 cprint(LINE_SPD + k, curcol,
452 "DDR3-2400");
453 break;
454 case 6:
455 cprint(LINE_SPD + k, curcol,
456 "DDR3-2533");
457 break;
458 case 5:
459 cprint(LINE_SPD + k, curcol,
460 "DDR3-2666");
461 break;
462 }
463
464 curcol += 10;
465
466 if ((spd_raw[8] >> 3) == 1) {
467 cprint(LINE_SPD + k, curcol, "ECC");
468 curcol += 4;
469 }
470 // Then print module infos (manufacturer & part number)
471 spd_raw[117] &= 0x0F; // Parity odd or even
472 for (i = 0; jep106[i].cont_code < 9; i++) {
473 if (spd_raw[117] == jep106[i].cont_code &&
474 spd_raw[118] == jep106[i].hex_byte) {
475 // We are here if a Jedec manufacturer is detected
476 cprint(LINE_SPD + k,
477 curcol,
478 "-");
479 curcol += 2;
480 cprint(LINE_SPD + k,
481 curcol,
482 jep106[i].name);
483 for (z = 0; jep106[i].name[z] != '\0'; z++) {
484 curcol++;
485 }
486 curcol++;
487 // Display module serial number
488 for (h = 128; h < 146; h++) {
489 cprint(LINE_SPD + k,
490 curcol,
491 convert_hex_to_char
492 (spd_raw[h]));
493 curcol++;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800494 }
495
Stefan Taunercc44ba62018-08-22 08:13:23 +0200496 // Detect Week and Year of Manufacturing (Think to upgrade after 2015 !!!)
497 if (curcol <= 72
498 && spd_raw[120] > 3
499 && spd_raw[120] < 16
500 && spd_raw[121] < 55) {
501 cprint(LINE_SPD + k,
502 curcol, "(W");
503 dprint(LINE_SPD + k,
504 curcol + 2,
505 spd_raw[121],
506 2,
507 0);
508 if (spd_raw[121] < 10) {
509 cprint(LINE_SPD + k,
510 curcol + 2,
511 "0");
512 }
513 cprint(LINE_SPD + k,
514 curcol + 4,
515 "'");
516 dprint(LINE_SPD + k,
517 curcol + 5,
518 spd_raw[120],
519 2,
520 0);
521 if (spd_raw[120] < 10) {
522 cprint(LINE_SPD
523 + k,
524 curcol +
525 5, "0");
526 }
527 cprint(LINE_SPD + k,
528 curcol + 7, ")");
529 curcol += 9;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800530 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200531 // Detect XMP Memory
532 if (spd_raw[176] == 0x0C
533 && spd_raw[177] == 0x4A) {
534 cprint(LINE_SPD + k,
535 curcol, "*XMP*");
536 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800537 }
538 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800539 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200540 // We enter this function if DDR2 is detected
541 if (spd_raw[2] == 0x08) {
542 // First print slot#, module capacity
543 cprint(LINE_SPD + k, curcol, " - Slot :");
544 dprint(LINE_SPD + k, curcol + 8, k, 1, 0);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800545
Stefan Taunercc44ba62018-08-22 08:13:23 +0200546 module_size = get_ddr2_module_size(spd_raw[31],
547 spd_raw[5]);
548 temp_nbd = getnum(module_size);
549 curcol += 12;
550 dprint(LINE_SPD + k, curcol, module_size,
551 temp_nbd, 0);
552 curcol += temp_nbd;
553 cprint(LINE_SPD + k, curcol, " MB");
554 curcol += 4;
555
556 // Then module jedec speed
557 float ddr2_speed, byte1, byte2;
558
559 byte1 = (spd_raw[9] >> 4) * 10;
560 byte2 = spd_raw[9] & 0xF;
561
562 ddr2_speed = 1 / (byte1 + byte2) * 10000 * 2;
563
564 temp_nbd = getnum(ddr2_speed);
565 cprint(LINE_SPD + k, curcol, "DDR2-");
566 curcol += 5;
567 dprint(LINE_SPD + k, curcol, ddr2_speed,
568 temp_nbd, 0);
569 curcol += temp_nbd;
570
571 if ((spd_raw[11] >> 1) == 1) {
572 cprint(LINE_SPD + k, curcol + 1, "ECC");
573 curcol += 4;
574 }
575 // Then print module infos (manufacturer & part number)
576 int ccode = 0;
577
578 for (i = 64; i < 72; i++) {
579 if (spd_raw[i] == 0x7F) {
580 ccode++;
581 }
582 }
583
584 curcol++;
585
586 for (i = 0; jep106[i].cont_code < 9; i++) {
587 if (ccode == jep106[i].cont_code
588 && spd_raw[64 + ccode] ==
589 jep106[i].hex_byte) {
590 // We are here if a Jedec manufacturer is detected
591 cprint(LINE_SPD + k, curcol,
592 "-");
593 curcol += 2;
594 cprint(LINE_SPD + k, curcol,
595 jep106[i].name);
596 for (z = 0;
597 jep106[i].name[z] != '\0';
598 z++) {
599 curcol++;
600 }
601 curcol++;
602 // Display module serial number
603 for (h = 73; h < 91; h++) {
604 cprint(LINE_SPD + k,
605 curcol,
606 convert_hex_to_char
607 (spd_raw[h]));
608 curcol++;
609 }
610 }
611 }
612 }
613 k++;
614 }
615 }
616}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800617
618void show_spd(void)
619{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200620 int index;
621 int i, j;
622 int flag = 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800623 wait_keyup();
Stefan Taunercc44ba62018-08-22 08:13:23 +0200624 index = find_smb_controller();
625 if (index == -1) {
626 cprint(POP2_Y, POP2_X + 1, "SMBus Controller not known");
627 while (!get_key()) ;
628 wait_keyup();
629 return;
630 } else {
631 cprint(POP2_Y, POP2_X + 1, "SPD Data: Slot");
Martin Roth4dcd13d2016-02-24 13:53:07 -0800632 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200633 smbcontrollers[index].get_adr();
634 for (j = 0; j < 16; j++) {
635 if (smbcontrollers[index].read_spd(j) == 0) {
636 dprint(POP2_Y, POP2_X + 15, j, 2, 0);
637 for (i = 0; i < 256; i++) {
638 hprint2(2 + POP2_Y + i / 16,
639 3 + POP2_X + (i % 16) * 3, spd_raw[i],
640 2);
641 }
642 flag = 0;
643 while (!flag) {
644 if (get_key())
645 flag++;
646 }
647 wait_keyup();
648 }
649 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800650}