blob: 8a772d2dbce614b11c650f415990a09a3461f165 [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
7
8#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
19#define SMBHSTCNT smbusbase + 2
20#define SMBHSTCMD smbusbase + 3
21#define SMBHSTADD smbusbase + 4
22#define SMBHSTDAT smbusbase + 5
23
24extern void wait_keyup();
25
26int smbdev, smbfun;
27unsigned short smbusbase;
28unsigned char spd_raw[256];
29char s[] = {'/', 0, '-', 0, '\\', 0, '|', 0};
30
31static void ich5_get_smb(void)
32{
33 unsigned long x;
34 int result;
35 result = pci_conf_read(0, smbdev, smbfun, 0x20, 2, &x);
36 if (result == 0) smbusbase = (unsigned short) x & 0xFFFE;
37}
38
39static void piix4_get_smb(void)
40{
41 unsigned long x;
42 int result;
43
44 result = pci_conf_read(0, smbdev, smbfun, 0x08, 1, &x);
45
46 if(x < 0x40){
47 // SB600/700
48 result = pci_conf_read(0, smbdev, smbfun, 0x90, 2, &x);
49 if (result == 0) smbusbase = (unsigned short) x & 0xFFFE;
50 } else {
51 // SB800
52 sb800_get_smb();
53 }
54}
55
56void sb800_get_smb(void)
57{
58 int lbyte, hbyte;
59
60 __outb(AMD_SMBUS_BASE_REG + 1, AMD_INDEX_IO_PORT);
61 lbyte = __inb(AMD_DATA_IO_PORT);
62 __outb(AMD_SMBUS_BASE_REG, AMD_INDEX_IO_PORT);
63 hbyte = __inb(AMD_DATA_IO_PORT);
64
65 smbusbase = lbyte;
66 smbusbase <<= 8;
67 smbusbase += hbyte;
68 smbusbase &= 0xFFE0;
69
70 if (smbusbase == 0xFFE0) { smbusbase = 0; }
71}
72
73unsigned char ich5_smb_read_byte(unsigned char adr, unsigned char cmd)
74{
75 int l1, h1, l2, h2;
76 unsigned long long t;
77 __outb(0x1f, SMBHSTSTS); // reset SMBus Controller
78 __outb(0xff, SMBHSTDAT);
79 while(__inb(SMBHSTSTS) & 0x01); // wait until ready
80 __outb(cmd, SMBHSTCMD);
81 __outb((adr << 1) | 0x01, SMBHSTADD);
82 __outb(0x48, SMBHSTCNT);
83 rdtsc(l1, h1);
84 //cprint(POP2_Y, POP2_X + 16, s + cmd % 8); // progress bar
85 while (!(__inb(SMBHSTSTS) & 0x02)) { // wait til command finished
86 rdtsc(l2, h2);
87 t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / v->clks_msec;
88 if (t > 10) break; // break after 10ms
89 }
90 return __inb(SMBHSTDAT);
91}
92
93static int ich5_read_spd(int dimmadr)
94{
95 int x;
96 spd_raw[0] = ich5_smb_read_byte(0x50 + dimmadr, 0);
97 if (spd_raw[0] == 0xff) return -1; // no spd here
98 for (x = 1; x < 256; x++) {
99 spd_raw[x] = ich5_smb_read_byte(0x50 + dimmadr, (unsigned char) x);
100 }
101 return 0;
102}
103
104static void us15w_get_smb(void)
105{
106 unsigned long x;
107 int result;
108 result = pci_conf_read(0, 0x1f, 0, 0x40, 2, &x);
109 if (result == 0) smbusbase = (unsigned short) x & 0xFFC0;
110}
111
112unsigned char us15w_smb_read_byte(unsigned char adr, unsigned char cmd)
113{
114 int l1, h1, l2, h2;
115 unsigned long long t;
116 //__outb(0x00, smbusbase + 1); // reset SMBus Controller
117 //__outb(0x00, smbusbase + 6);
118 //while((__inb(smbusbase + 1) & 0x08) != 0); // wait until ready
119 __outb(0x02, smbusbase + 0); // Byte read
120 __outb(cmd, smbusbase + 5); // Command
121 __outb(0x07, smbusbase + 1); // Clear status
122 __outb((adr << 1) | 0x01, smbusbase + 4); // DIMM address
123 __outb(0x12, smbusbase + 0); // Start
124 //while (((__inb(smbusbase + 1) & 0x08) == 0)) {} // wait til busy
125 rdtsc(l1, h1);
126 cprint(POP2_Y, POP2_X + 16, s + cmd % 8); // progress bar
127 while (((__inb(smbusbase + 1) & 0x01) == 0) ||
128 ((__inb(smbusbase + 1) & 0x08) != 0)) { // wait til command finished
129 rdtsc(l2, h2);
130 t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / v->clks_msec;
131 if (t > 10) break; // break after 10ms
132 }
133 return __inb(smbusbase + 6);
134}
135
136static int us15w_read_spd(int dimmadr)
137{
138 int x;
139 spd_raw[0] = us15w_smb_read_byte(0x50 + dimmadr, 0);
140 if (spd_raw[0] == 0xff) return -1; // no spd here
141 for (x = 1; x < 256; x++) {
142 spd_raw[x] = us15w_smb_read_byte(0x50 + dimmadr, (unsigned char) x);
143 }
144 return 0;
145}
146
147struct pci_smbus_controller {
148 unsigned vendor;
149 unsigned device;
150 char *name;
151 void (*get_adr)(void);
152 int (*read_spd)(int dimmadr);
153};
154
155static struct pci_smbus_controller smbcontrollers[] = {
156 // Intel SMBUS
157 {0x8086, 0x9C22, "Intel HSW-ULT", ich5_get_smb, ich5_read_spd},
158 {0x8086, 0x8C22, "Intel HSW", ich5_get_smb, ich5_read_spd},
159 {0x8086, 0x1E22, "Intel Z77", ich5_get_smb, ich5_read_spd},
160 {0x8086, 0x1C22, "Intel P67", ich5_get_smb, ich5_read_spd},
161 {0x8086, 0x3B30, "Intel P55", ich5_get_smb, ich5_read_spd},
162 {0x8086, 0x3A60, "Intel ICH10B", ich5_get_smb, ich5_read_spd},
163 {0x8086, 0x3A30, "Intel ICH10R", ich5_get_smb, ich5_read_spd},
164 {0x8086, 0x2930, "Intel ICH9", ich5_get_smb, ich5_read_spd},
165 {0x8086, 0x283E, "Intel ICH8", ich5_get_smb, ich5_read_spd},
166 {0x8086, 0x27DA, "Intel ICH7", ich5_get_smb, ich5_read_spd},
167 {0x8086, 0x266A, "Intel ICH6", ich5_get_smb, ich5_read_spd},
168 {0x8086, 0x24D3, "Intel ICH5", ich5_get_smb, ich5_read_spd},
169 {0x8086, 0x24C3, "Intel ICH4", ich5_get_smb, ich5_read_spd},
170 {0x8086, 0x25A4, "Intel 6300ESB", ich5_get_smb, ich5_read_spd},
171 {0x8086, 0x269B, "Intel ESB2", ich5_get_smb, ich5_read_spd},
172 {0x8086, 0x8119, "Intel US15W", us15w_get_smb, us15w_read_spd},
173 {0x8086, 0x5032, "Intel EP80579", ich5_get_smb, ich5_read_spd},
174
175 // AMD SMBUS
176 {0x1002, 0x4385, "AMD SB600/700", piix4_get_smb, ich5_read_spd},
177 {0x1022, 0x780B, "AMD SB800/900", sb800_get_smb, ich5_read_spd},
178 {0, 0, "", NULL, NULL}
179};
180
181
182int find_smb_controller(void)
183{
184 int i = 0;
185 unsigned long valuev, valued;
186
187 for (smbdev = 0; smbdev < 32; smbdev++) {
188 for (smbfun = 0; smbfun < 8; smbfun++) {
189 pci_conf_read(0, smbdev, smbfun, 0, 2, &valuev);
190 if (valuev != 0xFFFF) { // if there is something look what's it..
191 for (i = 0; smbcontrollers[i].vendor > 0; i++) { // check if this is a known smbus controller
192 if (valuev == smbcontrollers[i].vendor) {
193 pci_conf_read(0, smbdev, smbfun, 2, 2, &valued); // read the device id
194 if (valued == smbcontrollers[i].device) {
195 return i;
196 }
197 }
198 }
199 }
200 }
201 }
202 return -1;
203}
204
205
206
207void get_spd_spec(void)
208{
209 int index;
210 int h, i, j, z;
211 int k = 0;
212 int module_size;
213 int curcol;
214 int temp_nbd;
215 int tck;
216
217 index = find_smb_controller();
218
219 if (index == -1)
220 {
221 // Unknown SMBUS Controller, exit
222 return;
223 }
224
225 smbcontrollers[index].get_adr();
226 cprint(LINE_SPD-2, 0, "Memory SPD Informations");
227 cprint(LINE_SPD-1, 0, "--------------------------");
228
229 for (j = 0; j < 8; j++) {
230 if (smbcontrollers[index].read_spd(j) == 0) {
231 curcol = 1;
232 if(spd_raw[2] == 0x0b){
233 // We are here if DDR3 present
234
235 // First print slot#, module capacity
236 cprint(LINE_SPD+k, curcol, " - Slot :");
237 dprint(LINE_SPD+k, curcol+8, k, 1, 0);
238
239 module_size = get_ddr3_module_size(spd_raw[4] & 0xF, spd_raw[8] & 0x7, spd_raw[7] & 0x7, spd_raw[7] >> 3);
240 temp_nbd = getnum(module_size); curcol += 12;
241 dprint(LINE_SPD+k, curcol, module_size, temp_nbd, 0); curcol += temp_nbd;
242 cprint(LINE_SPD+k, curcol, " MB"); curcol += 4;
243
244 // If XMP is supported, check Tck in XMP reg
245 if(spd_raw[176] == 0x0C && spd_raw[177] == 0x4A && spd_raw[12])
246 {
247 tck = spd_raw[186];
248 } else {
249 tck = spd_raw[12];
250 }
251
252 // Then module jedec speed
253 switch(tck)
254 {
255 default:
256 cprint(LINE_SPD+k, curcol, "DDR3-????");
257 break;
258 case 20:
259 cprint(LINE_SPD+k, curcol, "DDR3-800");
260 curcol--;
261 break;
262 case 15:
263 cprint(LINE_SPD+k, curcol, "DDR3-1066");
264 break;
265 case 12:
266 cprint(LINE_SPD+k, curcol, "DDR3-1333");
267 break;
268 case 10:
269 cprint(LINE_SPD+k, curcol, "DDR3-1600");
270 break;
271 case 9:
272 cprint(LINE_SPD+k, curcol, "DDR3-1866");
273 break;
274 case 8:
275 cprint(LINE_SPD+k, curcol, "DDR3-2133");
276 break;
277 case 7:
278 cprint(LINE_SPD+k, curcol, "DDR3-2400");
279 break;
280 case 6:
281 cprint(LINE_SPD+k, curcol, "DDR3-2533");
282 break;
283 case 5:
284 cprint(LINE_SPD+k, curcol, "DDR3-2666");
285 break;
286 }
287
288 curcol += 10;
289
290 if((spd_raw[8] >> 3) == 1) { cprint(LINE_SPD+k, curcol, "ECC"); curcol += 4; }
291
292 // Then print module infos (manufacturer & part number)
293 spd_raw[117] &= 0x0F; // Parity odd or even
294 for (i = 0; jep106[i].cont_code < 9; i++) {
295 if (spd_raw[117] == jep106[i].cont_code && spd_raw[118] == jep106[i].hex_byte) {
296 // We are here if a Jedec manufacturer is detected
297 cprint(LINE_SPD+k, curcol, "-"); curcol += 2;
298 cprint(LINE_SPD+k, curcol, jep106[i].name);
299 for(z = 0; jep106[i].name[z] != '\0'; z++) { curcol++; }
300 curcol++;
301 // Display module serial number
302 for (h = 128; h < 146; h++) {
303 cprint(LINE_SPD+k, curcol, convert_hex_to_char(spd_raw[h]));
304 curcol++;
305 }
306
307 // Detect Week and Year of Manufacturing (Think to upgrade after 2015 !!!)
308 if(curcol <= 72 && spd_raw[120] > 3 && spd_raw[120] < 16 && spd_raw[121] < 55)
309 {
310 cprint(LINE_SPD+k, curcol, "(W");
311 dprint(LINE_SPD+k, curcol+2, spd_raw[121], 2, 0);
312 if(spd_raw[121] < 10) { cprint(LINE_SPD+k, curcol+2, "0"); }
313 cprint(LINE_SPD+k, curcol+4, "'");
314 dprint(LINE_SPD+k, curcol+5, spd_raw[120], 2, 0);
315 if(spd_raw[120] < 10) { cprint(LINE_SPD+k, curcol+5, "0"); }
316 cprint(LINE_SPD+k, curcol+7, ")");
317 curcol += 9;
318 }
319
320 // Detect XMP Memory
321 if(spd_raw[176] == 0x0C && spd_raw[177] == 0x4A)
322 {
323 cprint(LINE_SPD+k, curcol, "*XMP*");
324 }
325 }
326 }
327 }
328 // We enter this function if DDR2 is detected
329 if(spd_raw[2] == 0x08){
330 // First print slot#, module capacity
331 cprint(LINE_SPD+k, curcol, " - Slot :");
332 dprint(LINE_SPD+k, curcol+8, k, 1, 0);
333
334 module_size = get_ddr2_module_size(spd_raw[31], spd_raw[5]);
335 temp_nbd = getnum(module_size); curcol += 12;
336 dprint(LINE_SPD+k, curcol, module_size, temp_nbd, 0); curcol += temp_nbd;
337 cprint(LINE_SPD+k, curcol, " MB"); curcol += 4;
338
339 // Then module jedec speed
340 float ddr2_speed, byte1, byte2;
341
342 byte1 = (spd_raw[9] >> 4) * 10;
343 byte2 = spd_raw[9] & 0xF;
344
345 ddr2_speed = 1 / (byte1 + byte2) * 10000 * 2;
346
347 temp_nbd = getnum(ddr2_speed);
348 cprint(LINE_SPD+k, curcol, "DDR2-"); curcol += 5;
349 dprint(LINE_SPD+k, curcol, ddr2_speed, temp_nbd, 0); curcol += temp_nbd;
350
351 if((spd_raw[11] >> 1) == 1) { cprint(LINE_SPD+k, curcol+1, "ECC"); curcol += 4; }
352
353 // Then print module infos (manufacturer & part number)
354 int ccode = 0;
355
356 for(i = 64; i < 72; i++)
357 {
358 if(spd_raw[i] == 0x7F) { ccode++; }
359 }
360
361 curcol++;
362
363 for (i = 0; jep106[i].cont_code < 9; i++) {
364 if (ccode == jep106[i].cont_code && spd_raw[64+ccode] == jep106[i].hex_byte) {
365 // We are here if a Jedec manufacturer is detected
366 cprint(LINE_SPD+k, curcol, "-"); curcol += 2;
367 cprint(LINE_SPD+k, curcol, jep106[i].name);
368 for(z = 0; jep106[i].name[z] != '\0'; z++) { curcol++; }
369 curcol++;
370 // Display module serial number
371 for (h = 73; h < 91; h++) {
372 cprint(LINE_SPD+k, curcol, convert_hex_to_char(spd_raw[h]));
373 curcol++;
374 }
375
376 }
377 }
378
379 }
380 k++;
381 }
382 }
383}
384
385
386void show_spd(void)
387{
388 int index;
389 int i, j;
390 int flag = 0;
Martin Roth03e81e12016-03-03 20:13:54 -0700391 popup(POP_SAVE_BUFFER_2);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800392 wait_keyup();
393 index = find_smb_controller();
394 if (index == -1) {
395 cprint(POP2_Y, POP2_X+1, "SMBus Controller not known");
396 while (!get_key());
397 wait_keyup();
Martin Roth03e81e12016-03-03 20:13:54 -0700398 popdown(POP_SAVE_BUFFER_2);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800399 return;
400 }
401 else cprint(POP2_Y, POP2_X+1, "SPD Data: Slot");
402 smbcontrollers[index].get_adr();
403 for (j = 0; j < 16; j++) {
404 if (smbcontrollers[index].read_spd(j) == 0) {
405 dprint(POP2_Y, POP2_X + 15, j, 2, 0);
406 for (i = 0; i < 256; i++) {
407 hprint2(2 + POP2_Y + i / 16, 3 + POP2_X + (i % 16) * 3, spd_raw[i], 2);
408 }
409 flag = 0;
410 while(!flag) {
411 if (get_key()) flag++;
412 }
413 wait_keyup();
414 }
415 }
Martin Roth03e81e12016-03-03 20:13:54 -0700416 popdown(POP_SAVE_BUFFER_2);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800417}
418
419int get_ddr3_module_size(int sdram_capacity, int prim_bus_width, int sdram_width, int ranks)
420{
421 int module_size;
422
423 switch(sdram_capacity)
424 {
425 case 0:
426 module_size = 256;
427 break;
428 case 1:
429 module_size = 512;
430 break;
431 default:
432 case 2:
433 module_size = 1024;
434 break;
435 case 3:
436 module_size = 2048;
437 break;
438 case 4:
439 module_size = 4096;
440 break;
441 case 5:
442 module_size = 8192;
443 break;
444 case 6:
445 module_size = 16384;
446 break;
447 }
448
449 module_size /= 8;
450
451 switch(prim_bus_width)
452 {
453 case 0:
454 module_size *= 8;
455 break;
456 case 1:
457 module_size *= 16;
458 break;
459 case 2:
460 module_size *= 32;
461 break;
462 case 3:
463 module_size *= 64;
464 break;
465 }
466
467 switch(sdram_width)
468 {
469 case 0:
470 module_size /= 4;
471 break;
472 case 1:
473 module_size /= 8;
474 break;
475 case 2:
476 module_size /= 16;
477 break;
478 case 3:
479 module_size /= 32;
480 break;
481
482 }
483
484 module_size *= (ranks + 1);
485
486 return module_size;
487}
488
489
490int get_ddr2_module_size(int rank_density_byte, int rank_num_byte)
491{
492 int module_size;
493
494 switch(rank_density_byte)
495 {
496 case 1:
497 module_size = 1024;
498 break;
499 case 2:
500 module_size = 2048;
501 break;
502 case 4:
503 module_size = 4096;
504 break;
505 case 8:
506 module_size = 8192;
507 break;
508 case 16:
509 module_size = 16384;
510 break;
511 case 32:
512 module_size = 128;
513 break;
514 case 64:
515 module_size = 256;
516 break;
517 default:
518 case 128:
519 module_size = 512;
520 break;
521 }
522
523 module_size *= (rank_num_byte & 7) + 1;
524
525 return module_size;
526
527}
528
529
530struct ascii_map {
531 unsigned hex_code;
532 char *name;
533};
534
535
536char* convert_hex_to_char(unsigned hex_org) {
537 static char buf[2] = " ";
538 if (hex_org >= 0x20 && hex_org < 0x80) {
539 buf[0] = hex_org;
540 } else {
541 //buf[0] = '\0';
542 buf[0] = ' ';
543 }
544
545 return buf;
Martin Roth03e81e12016-03-03 20:13:54 -0700546}