blob: d91a24236d98ef7d390020d6bd500a760a681b4d [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{
Piotr Król08dd5872017-11-01 21:26:41 +010057 int lbyte, hbyte, result;
58 unsigned long x;
Martin Roth4dcd13d2016-02-24 13:53:07 -080059
Piotr Król08dd5872017-11-01 21:26:41 +010060 result = pci_conf_read(0, smbdev, smbfun, 0x08, 1, &x);
61
62 /* if processor revision is ML_A0 or ML_A1 use different way for SMBus
63 * IO base calculation */
64 if (x == 0x42 || x == 0x41) {
65 /* read PMx00+1 to get SmbusAsfIoBase */
Stefan Taunercc44ba62018-08-22 08:13:23 +020066 __outb(AMD_PM_DECODE_EN_REG + 1, AMD_INDEX_IO_PORT);
Piotr Król08dd5872017-11-01 21:26:41 +010067 lbyte = __inb(AMD_DATA_IO_PORT);
68
69 /* SMBus IO base is defined as {Smbus0AsfIoBase[7:0], 0x00} */
70 smbusbase = (lbyte & 0xF) << 8;
71 } else {
Martin Roth4dcd13d2016-02-24 13:53:07 -080072 __outb(AMD_SMBUS_BASE_REG + 1, AMD_INDEX_IO_PORT);
73 lbyte = __inb(AMD_DATA_IO_PORT);
74 __outb(AMD_SMBUS_BASE_REG, AMD_INDEX_IO_PORT);
75 hbyte = __inb(AMD_DATA_IO_PORT);
76
77 smbusbase = lbyte;
78 smbusbase <<= 8;
79 smbusbase += hbyte;
80 smbusbase &= 0xFFE0;
Piotr Król08dd5872017-11-01 21:26:41 +010081 }
Martin Roth4dcd13d2016-02-24 13:53:07 -080082
Stefan Taunercc44ba62018-08-22 08:13:23 +020083 if (smbusbase == 0xFFE0) {
84 smbusbase = 0;
85 }
Martin Roth4dcd13d2016-02-24 13:53:07 -080086}
87
Stefan Tauner97eacf52018-08-19 10:47:45 +020088static void sb600_get_smb(void)
89{
90 unsigned long x;
91 int result;
92
93 result = pci_conf_read(0, smbdev, smbfun, 0x08, 1, &x);
94
95 if (x < 0x40) {
96 // SB600/700
97 result = pci_conf_read(0, smbdev, smbfun, 0x90, 2, &x);
98 if (result == 0)
99 smbusbase = (unsigned short)x & 0xFFFE;
100 } else {
101 // SB800
102 sb800_get_smb();
103 }
104}
105
Stefan Tauner4f8ea892018-08-22 08:13:10 +0200106static unsigned char ich5_smb_read_byte(unsigned char adr, unsigned char cmd)
Martin Roth4dcd13d2016-02-24 13:53:07 -0800107{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200108 int l1, h1, l2, h2;
109 uint64_t t;
110 uint64_t toval = 10 * v->clks_msec;
Ben Gardnere7c08082016-03-30 16:46:21 -0500111
Stefan Taunercc44ba62018-08-22 08:13:23 +0200112 __outb(0x1f, SMBHSTSTS); // reset SMBus Controller
113 __outb(0xff, SMBHSTDAT);
114 while (__inb(SMBHSTSTS) & 0x01)
115 ; // wait until ready
116 __outb(cmd, SMBHSTCMD);
117 __outb((adr << 1) | 0x01, SMBHSTADD);
118 __outb(0x48, SMBHSTCNT);
119 rdtsc(l1, h1);
120 //cprint(POP2_Y, POP2_X + 16, s + cmd % 8); // progress bar
121 while (!(__inb(SMBHSTSTS) & 0x02)) { // wait til command finished
122 rdtsc(l2, h2);
123 t = ((uint64_t) (h2 - h1) * 0xffffffff + (l2 - l1));
124 if (t > toval)
125 break; // break after 10ms
126 }
127 return __inb(SMBHSTDAT);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800128}
129
130static int ich5_read_spd(int dimmadr)
131{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200132 int x;
133 spd_raw[0] = ich5_smb_read_byte(0x50 + dimmadr, 0);
134 if (spd_raw[0] == 0xff)
135 return -1; // no spd here
136 for (x = 1; x < 256; x++) {
137 spd_raw[x] =
138 ich5_smb_read_byte(0x50 + dimmadr, (unsigned char)x);
139 }
140 return 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800141}
142
143static void us15w_get_smb(void)
144{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200145 unsigned long x;
146 int result;
147 result = pci_conf_read(0, 0x1f, 0, 0x40, 2, &x);
148 if (result == 0)
149 smbusbase = (unsigned short)x & 0xFFC0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800150}
151
Stefan Tauner4f8ea892018-08-22 08:13:10 +0200152static unsigned char us15w_smb_read_byte(unsigned char adr, unsigned char cmd)
Martin Roth4dcd13d2016-02-24 13:53:07 -0800153{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200154 int l1, h1, l2, h2;
155 uint64_t t;
156 uint64_t toval = 10 * v->clks_msec;
Ben Gardnere7c08082016-03-30 16:46:21 -0500157
Stefan Taunercc44ba62018-08-22 08:13:23 +0200158 //__outb(0x00, smbusbase + 1); // reset SMBus Controller
159 //__outb(0x00, smbusbase + 6);
160 //while((__inb(smbusbase + 1) & 0x08) != 0)
161 // ; // wait until ready
162 __outb(0x02, smbusbase + 0); // Byte read
163 __outb(cmd, smbusbase + 5); // Command
164 __outb(0x07, smbusbase + 1); // Clear status
165 __outb((adr << 1) | 0x01, smbusbase + 4); // DIMM address
166 __outb(0x12, smbusbase + 0); // Start
167 //while (((__inb(smbusbase + 1) & 0x08) == 0))
168 // ; // wait until busy
169 rdtsc(l1, h1);
170 static const char s[] = { '/', 0, '-', 0, '\\', 0, '|', 0 };
171 cprint(POP2_Y, POP2_X + 16, s + cmd % 8); // progress bar
172
173 // wait til command finished
174 while (((__inb(smbusbase + 1) & 0x01) == 0) || ((__inb(smbusbase + 1) & 0x08) != 0)) {
175 rdtsc(l2, h2);
176 t = ((uint64_t) (h2 - h1) * 0xffffffff + (l2 - l1));
177 if (t > toval)
178 break; // break after 10ms
179 }
180 return __inb(smbusbase + 6);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800181}
182
183static int us15w_read_spd(int dimmadr)
184{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200185 int x;
186 spd_raw[0] = us15w_smb_read_byte(0x50 + dimmadr, 0);
187 if (spd_raw[0] == 0xff)
188 return -1; // no spd here
189 for (x = 1; x < 256; x++) {
190 spd_raw[x] =
191 us15w_smb_read_byte(0x50 + dimmadr, (unsigned char)x);
192 }
193 return 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800194}
195
196struct pci_smbus_controller {
Stefan Taunercc44ba62018-08-22 08:13:23 +0200197 unsigned vendor;
198 unsigned device;
199 char *name;
200 void (*get_adr) (void);
201 int (*read_spd) (int dimmadr);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800202};
203
204static struct pci_smbus_controller smbcontrollers[] = {
205 // Intel SMBUS
Stefan Taunercc44ba62018-08-22 08:13:23 +0200206 {0x8086, 0x9C22, "Intel HSW-ULT", ich5_get_smb, ich5_read_spd},
207 {0x8086, 0x8C22, "Intel HSW", ich5_get_smb, ich5_read_spd},
208 {0x8086, 0x1E22, "Intel Z77", ich5_get_smb, ich5_read_spd},
209 {0x8086, 0x1C22, "Intel P67", ich5_get_smb, ich5_read_spd},
210 {0x8086, 0x3B30, "Intel P55", ich5_get_smb, ich5_read_spd},
211 {0x8086, 0x3A60, "Intel ICH10B", ich5_get_smb, ich5_read_spd},
212 {0x8086, 0x3A30, "Intel ICH10R", ich5_get_smb, ich5_read_spd},
213 {0x8086, 0x2930, "Intel ICH9", ich5_get_smb, ich5_read_spd},
214 {0x8086, 0x283E, "Intel ICH8", ich5_get_smb, ich5_read_spd},
215 {0x8086, 0x27DA, "Intel ICH7", ich5_get_smb, ich5_read_spd},
216 {0x8086, 0x266A, "Intel ICH6", ich5_get_smb, ich5_read_spd},
217 {0x8086, 0x24D3, "Intel ICH5", ich5_get_smb, ich5_read_spd},
218 {0x8086, 0x24C3, "Intel ICH4", ich5_get_smb, ich5_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800219 {0x8086, 0x25A4, "Intel 6300ESB", ich5_get_smb, ich5_read_spd},
Stefan Taunercc44ba62018-08-22 08:13:23 +0200220 {0x8086, 0x269B, "Intel ESB2", ich5_get_smb, ich5_read_spd},
221 {0x8086, 0x8119, "Intel US15W", us15w_get_smb, us15w_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800222 {0x8086, 0x5032, "Intel EP80579", ich5_get_smb, ich5_read_spd},
Ben Gardner4b07cbe2016-03-07 09:00:44 -0600223 {0x8086, 0x0f12, "Intel E3800", ich5_get_smb, ich5_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800224
225 // AMD SMBUS
Stefan Tauner97eacf52018-08-19 10:47:45 +0200226 {0x1002, 0x4385, "AMD SB600/700", sb600_get_smb, ich5_read_spd},
Martin Roth4dcd13d2016-02-24 13:53:07 -0800227 {0x1022, 0x780B, "AMD SB800/900", sb800_get_smb, ich5_read_spd},
228 {0, 0, "", NULL, NULL}
229};
230
Stefan Tauner4f8ea892018-08-22 08:13:10 +0200231static int find_smb_controller(void)
Martin Roth4dcd13d2016-02-24 13:53:07 -0800232{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200233 int i = 0;
234 unsigned long valuev, valued;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800235
Stefan Taunercc44ba62018-08-22 08:13:23 +0200236 for (smbdev = 0; smbdev < 32; smbdev++) {
237 for (smbfun = 0; smbfun < 8; smbfun++) {
238 pci_conf_read(0, smbdev, smbfun, 0, 2, &valuev);
239 if (valuev != 0xFFFF) { // if there is something look what's it..
240 for (i = 0; smbcontrollers[i].vendor > 0; i++) { // check if this is a known smbus controller
241 if (valuev == smbcontrollers[i].vendor) {
242 pci_conf_read(0, smbdev, smbfun, 2, 2, &valued); // read the device id
243 if (valued == smbcontrollers[i].device) {
244 return i;
245 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800246 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200247 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800248 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200249 }
250 }
251 return -1;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800252}
253
Stefan Tauner97eacf52018-08-19 10:47:45 +0200254
255static int get_ddr3_module_size(int sdram_capacity, int prim_bus_width,
256 int sdram_width, int ranks)
257{
258 int module_size;
259
260 switch (sdram_capacity) {
261 case 0:
262 module_size = 256;
263 break;
264 case 1:
265 module_size = 512;
266 break;
267 default:
268 case 2:
269 module_size = 1024;
270 break;
271 case 3:
272 module_size = 2048;
273 break;
274 case 4:
275 module_size = 4096;
276 break;
277 case 5:
278 module_size = 8192;
279 break;
280 case 6:
281 module_size = 16384;
282 break;
283 }
284
285 module_size /= 8;
286
287 switch (prim_bus_width) {
288 case 0:
289 module_size *= 8;
290 break;
291 case 1:
292 module_size *= 16;
293 break;
294 case 2:
295 module_size *= 32;
296 break;
297 case 3:
298 module_size *= 64;
299 break;
300 }
301
302 switch (sdram_width) {
303 case 0:
304 module_size /= 4;
305 break;
306 case 1:
307 module_size /= 8;
308 break;
309 case 2:
310 module_size /= 16;
311 break;
312 case 3:
313 module_size /= 32;
314 break;
315 }
316
317 module_size *= (ranks + 1);
318
319 return module_size;
320}
321
322static int get_ddr2_module_size(int rank_density_byte, int rank_num_byte)
323{
324 int module_size;
325
326 switch (rank_density_byte) {
327 case 1:
328 module_size = 1024;
329 break;
330 case 2:
331 module_size = 2048;
332 break;
333 case 4:
334 module_size = 4096;
335 break;
336 case 8:
337 module_size = 8192;
338 break;
339 case 16:
340 module_size = 16384;
341 break;
342 case 32:
343 module_size = 128;
344 break;
345 case 64:
346 module_size = 256;
347 break;
348 default:
349 case 128:
350 module_size = 512;
351 break;
352 }
353
354 module_size *= (rank_num_byte & 7) + 1;
355
356 return module_size;
357
358}
359
Martin Roth4dcd13d2016-02-24 13:53:07 -0800360void get_spd_spec(void)
361{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200362 int index;
363 int h, i, j, z;
364 int k = 0;
365 int module_size;
366 int curcol;
367 int temp_nbd;
368 int tck;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800369
Stefan Taunercc44ba62018-08-22 08:13:23 +0200370 index = find_smb_controller();
Martin Roth4dcd13d2016-02-24 13:53:07 -0800371
Stefan Taunercc44ba62018-08-22 08:13:23 +0200372 if (index == -1) {
373 // Unknown SMBUS Controller, exit
374 return;
375 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800376
Stefan Taunercc44ba62018-08-22 08:13:23 +0200377 smbcontrollers[index].get_adr();
378 cprint(LINE_SPD - 2, 0, "Memory SPD Informations");
379 cprint(LINE_SPD - 1, 0, "--------------------------");
Martin Roth4dcd13d2016-02-24 13:53:07 -0800380
Stefan Taunercc44ba62018-08-22 08:13:23 +0200381 for (j = 0; j < 8; j++) {
382 if (smbcontrollers[index].read_spd(j) == 0) {
383 curcol = 1;
384 if (spd_raw[2] == 0x0b) {
385 // We are here if DDR3 present
Martin Roth4dcd13d2016-02-24 13:53:07 -0800386
Stefan Taunercc44ba62018-08-22 08:13:23 +0200387 // First print slot#, module capacity
388 cprint(LINE_SPD + k, curcol, " - Slot :");
389 dprint(LINE_SPD + k, curcol + 8, k, 1, 0);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800390
Stefan Taunercc44ba62018-08-22 08:13:23 +0200391 module_size =
392 get_ddr3_module_size(spd_raw[4] & 0xF,
393 spd_raw[8] & 0x7,
394 spd_raw[7] & 0x7,
395 spd_raw[7] >> 3);
396 temp_nbd = getnum(module_size);
397 curcol += 12;
398 dprint(LINE_SPD + k, curcol, module_size,
399 temp_nbd, 0);
400 curcol += temp_nbd;
401 cprint(LINE_SPD + k, curcol, " MB");
402 curcol += 4;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800403
Stefan Taunercc44ba62018-08-22 08:13:23 +0200404 // If XMP is supported, check Tck in XMP reg
405 if (spd_raw[176] == 0x0C && spd_raw[177] == 0x4A
406 && spd_raw[12]) {
407 tck = spd_raw[186];
408 } else {
409 tck = spd_raw[12];
410 }
411
412 // Then module jedec speed
413 switch (tck) {
414 default:
415 cprint(LINE_SPD + k, curcol,
416 "DDR3-????");
417 break;
418 case 20:
419 cprint(LINE_SPD + k, curcol,
420 "DDR3-800");
421 curcol--;
422 break;
423 case 15:
424 cprint(LINE_SPD + k, curcol,
425 "DDR3-1066");
426 break;
427 case 12:
428 cprint(LINE_SPD + k, curcol,
429 "DDR3-1333");
430 break;
431 case 10:
432 cprint(LINE_SPD + k, curcol,
433 "DDR3-1600");
434 break;
435 case 9:
436 cprint(LINE_SPD + k, curcol,
437 "DDR3-1866");
438 break;
439 case 8:
440 cprint(LINE_SPD + k, curcol,
441 "DDR3-2133");
442 break;
443 case 7:
444 cprint(LINE_SPD + k, curcol,
445 "DDR3-2400");
446 break;
447 case 6:
448 cprint(LINE_SPD + k, curcol,
449 "DDR3-2533");
450 break;
451 case 5:
452 cprint(LINE_SPD + k, curcol,
453 "DDR3-2666");
454 break;
455 }
456
457 curcol += 10;
458
459 if ((spd_raw[8] >> 3) == 1) {
460 cprint(LINE_SPD + k, curcol, "ECC");
461 curcol += 4;
462 }
463 // Then print module infos (manufacturer & part number)
464 spd_raw[117] &= 0x0F; // Parity odd or even
465 for (i = 0; jep106[i].cont_code < 9; i++) {
466 if (spd_raw[117] == jep106[i].cont_code &&
467 spd_raw[118] == jep106[i].hex_byte) {
468 // We are here if a Jedec manufacturer is detected
469 cprint(LINE_SPD + k,
470 curcol,
471 "-");
472 curcol += 2;
473 cprint(LINE_SPD + k,
474 curcol,
475 jep106[i].name);
476 for (z = 0; jep106[i].name[z] != '\0'; z++) {
477 curcol++;
478 }
479 curcol++;
480 // Display module serial number
481 for (h = 128; h < 146; h++) {
482 cprint(LINE_SPD + k,
483 curcol,
484 convert_hex_to_char
485 (spd_raw[h]));
486 curcol++;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800487 }
488
Stefan Taunercc44ba62018-08-22 08:13:23 +0200489 // Detect Week and Year of Manufacturing (Think to upgrade after 2015 !!!)
490 if (curcol <= 72
491 && spd_raw[120] > 3
492 && spd_raw[120] < 16
493 && spd_raw[121] < 55) {
494 cprint(LINE_SPD + k,
495 curcol, "(W");
496 dprint(LINE_SPD + k,
497 curcol + 2,
498 spd_raw[121],
499 2,
500 0);
501 if (spd_raw[121] < 10) {
502 cprint(LINE_SPD + k,
503 curcol + 2,
504 "0");
505 }
506 cprint(LINE_SPD + k,
507 curcol + 4,
508 "'");
509 dprint(LINE_SPD + k,
510 curcol + 5,
511 spd_raw[120],
512 2,
513 0);
514 if (spd_raw[120] < 10) {
515 cprint(LINE_SPD
516 + k,
517 curcol +
518 5, "0");
519 }
520 cprint(LINE_SPD + k,
521 curcol + 7, ")");
522 curcol += 9;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800523 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200524 // Detect XMP Memory
525 if (spd_raw[176] == 0x0C
526 && spd_raw[177] == 0x4A) {
527 cprint(LINE_SPD + k,
528 curcol, "*XMP*");
529 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800530 }
531 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800532 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200533 // We enter this function if DDR2 is detected
534 if (spd_raw[2] == 0x08) {
535 // First print slot#, module capacity
536 cprint(LINE_SPD + k, curcol, " - Slot :");
537 dprint(LINE_SPD + k, curcol + 8, k, 1, 0);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800538
Stefan Taunercc44ba62018-08-22 08:13:23 +0200539 module_size = get_ddr2_module_size(spd_raw[31],
540 spd_raw[5]);
541 temp_nbd = getnum(module_size);
542 curcol += 12;
543 dprint(LINE_SPD + k, curcol, module_size,
544 temp_nbd, 0);
545 curcol += temp_nbd;
546 cprint(LINE_SPD + k, curcol, " MB");
547 curcol += 4;
548
549 // Then module jedec speed
550 float ddr2_speed, byte1, byte2;
551
552 byte1 = (spd_raw[9] >> 4) * 10;
553 byte2 = spd_raw[9] & 0xF;
554
555 ddr2_speed = 1 / (byte1 + byte2) * 10000 * 2;
556
557 temp_nbd = getnum(ddr2_speed);
558 cprint(LINE_SPD + k, curcol, "DDR2-");
559 curcol += 5;
560 dprint(LINE_SPD + k, curcol, ddr2_speed,
561 temp_nbd, 0);
562 curcol += temp_nbd;
563
564 if ((spd_raw[11] >> 1) == 1) {
565 cprint(LINE_SPD + k, curcol + 1, "ECC");
566 curcol += 4;
567 }
568 // Then print module infos (manufacturer & part number)
569 int ccode = 0;
570
571 for (i = 64; i < 72; i++) {
572 if (spd_raw[i] == 0x7F) {
573 ccode++;
574 }
575 }
576
577 curcol++;
578
579 for (i = 0; jep106[i].cont_code < 9; i++) {
580 if (ccode == jep106[i].cont_code
581 && spd_raw[64 + ccode] ==
582 jep106[i].hex_byte) {
583 // We are here if a Jedec manufacturer is detected
584 cprint(LINE_SPD + k, curcol,
585 "-");
586 curcol += 2;
587 cprint(LINE_SPD + k, curcol,
588 jep106[i].name);
589 for (z = 0;
590 jep106[i].name[z] != '\0';
591 z++) {
592 curcol++;
593 }
594 curcol++;
595 // Display module serial number
596 for (h = 73; h < 91; h++) {
597 cprint(LINE_SPD + k,
598 curcol,
599 convert_hex_to_char
600 (spd_raw[h]));
601 curcol++;
602 }
603 }
604 }
605 }
606 k++;
607 }
608 }
609}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800610
611void show_spd(void)
612{
Stefan Taunercc44ba62018-08-22 08:13:23 +0200613 int index;
614 int i, j;
615 int flag = 0;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800616 wait_keyup();
Stefan Taunercc44ba62018-08-22 08:13:23 +0200617 index = find_smb_controller();
618 if (index == -1) {
619 cprint(POP2_Y, POP2_X + 1, "SMBus Controller not known");
620 while (!get_key()) ;
621 wait_keyup();
622 return;
623 } else {
624 cprint(POP2_Y, POP2_X + 1, "SPD Data: Slot");
Martin Roth4dcd13d2016-02-24 13:53:07 -0800625 }
Stefan Taunercc44ba62018-08-22 08:13:23 +0200626 smbcontrollers[index].get_adr();
627 for (j = 0; j < 16; j++) {
628 if (smbcontrollers[index].read_spd(j) == 0) {
629 dprint(POP2_Y, POP2_X + 15, j, 2, 0);
630 for (i = 0; i < 256; i++) {
631 hprint2(2 + POP2_Y + i / 16,
632 3 + POP2_X + (i % 16) * 3, spd_raw[i],
633 2);
634 }
635 flag = 0;
636 while (!flag) {
637 if (get_key())
638 flag++;
639 }
640 wait_keyup();
641 }
642 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800643}