Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Chazi/i386/libsaio/dram_controllers.c

1/*
2 * dram controller access and scan from the pci host controller
3 * Integrated and adapted for chameleon 2.0 RC5 by Rekursor from bs0d work
4 * original source comes from:
5 *
6 * memtest86
7 *
8 * Released under version 2 of the Gnu Public License.
9 * By Chris Brady, cbrady@sgi.com
10 * ----------------------------------------------------
11 * MemTest86+ V4.00 Specific code (GPL V2.0)
12 * By Samuel DEMEULEMEESTER, sdemeule@memtest.org
13 * http://www.canardpc.com - http://www.memtest.org
14 */
15
16#include "libsaio.h"
17#include "bootstruct.h"
18#include "pci.h"
19#include "platform.h"
20#include "dram_controllers.h"
21
22#ifndef DEBUG_DRAM
23#define DEBUG_DRAM 0
24#endif
25
26#if DEBUG_DRAM
27#define DBG(x...) printf(x)
28#else
29#define DBG(x...)
30#endif
31
32/*
33 * Initialise memory controller functions
34 */
35
36// Setup P35 Memory Controller
37static void setup_p35(pci_dt_t *dram_dev)
38{
39uint32_t dev0;
40
41// Activate MMR I/O
42dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
43if (!(dev0 & 0x1))
44pci_config_write8(dram_dev->dev.addr, 0x48, (dev0 | 1));
45}
46
47int nhm_bus = 0x3F;
48
49// Setup Nehalem Integrated Memory Controller
50static void setup_nhm(pci_dt_t *dram_dev)
51{
52static long possible_nhm_bus[] = {0xFF, 0x7F, 0x3F};
53unsigned long did, vid;
54int i;
55
56// Nehalem supports Scrubbing
57// First, locate the PCI bus where the MCH is located
58for(i = 0; i < sizeof(possible_nhm_bus); i++)
59{
60vid = pci_config_read16(PCIADDR(possible_nhm_bus[i], 3, 4), 0x00);
61did = pci_config_read16(PCIADDR(possible_nhm_bus[i], 3, 4), 0x02);
62vid &= 0xFFFF;
63did &= 0xFF00;
64
65if(vid == 0x8086 && did >= 0x2C00)
66nhm_bus = possible_nhm_bus[i];
67}
68}
69
70/*
71 * Retrieve memory controller fsb functions
72 */
73
74
75// Get i965 Memory Speed
76static void get_fsb_i965(pci_dt_t *dram_dev)
77{
78uint32_t dev0, mch_ratio, mch_cfg, mch_fsb;
79
80long *ptr;
81
82// Find Ratio
83dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
84dev0 &= 0xFFFFC000;
85ptr = (long*)(dev0 + 0xC00);
86mch_cfg = *ptr & 0xFFFF;
87
88mch_ratio = 100000;
89
90switch (mch_cfg & 7)
91{
92case 0: mch_fsb = 1066; break;
93case 1: mch_fsb = 533; break;
94 default:
95case 2: mch_fsb = 800; break;
96case 3: mch_fsb = 667; break;
97case 4: mch_fsb = 1333; break;
98case 6: mch_fsb = 1600; break;
99}
100
101DBG("mch_fsb %d\n", mch_fsb);
102
103switch (mch_fsb)
104{
105case 533:
106switch ((mch_cfg >> 4) & 7)
107{
108case 1:mch_ratio = 200000; break;
109case 2:mch_ratio = 250000; break;
110case 3:mch_ratio = 300000; break;
111}
112break;
113
114default:
115case 800:
116switch ((mch_cfg >> 4) & 7)
117{
118case 0:mch_ratio = 100000; break;
119case 1:mch_ratio = 125000; break;
120case 2:mch_ratio = 166667; break; // 1.666666667
121case 3:mch_ratio = 200000; break;
122case 4:mch_ratio = 266667; break; // 2.666666667
123case 5:mch_ratio = 333333; break; // 3.333333333
124}
125break;
126
127case 1066:
128switch ((mch_cfg >> 4) & 7)
129{
130case 1:mch_ratio = 100000; break;
131case 2:mch_ratio = 125000; break;
132case 3:mch_ratio = 150000; break;
133case 4:mch_ratio = 200000; break;
134case 5:mch_ratio = 250000; break;
135}
136break;
137
138case 1333:
139switch ((mch_cfg >> 4) & 7)
140{
141case 2:mch_ratio = 100000; break;
142case 3:mch_ratio = 120000; break;
143case 4:mch_ratio = 160000; break;
144case 5:mch_ratio = 200000; break;
145}
146break;
147
148case 1600:
149switch ((mch_cfg >> 4) & 7)
150{
151case 3:mch_ratio = 100000; break;
152case 4:mch_ratio = 133333; break; // 1.333333333
153case 5:mch_ratio = 150000; break;
154case 6:mch_ratio = 200000; break;
155}
156break;
157}
158
159DBG("mch_ratio %d\n", mch_ratio);
160
161// Compute RAM Frequency
162Platform.RAM.Frequency = (Platform.CPU.FSBFrequency * mch_ratio) / 100000;
163
164DBG("ram_fsb %d\n", Platform.RAM.Frequency);
165
166}
167
168// Get i965m Memory Speed
169static void get_fsb_im965(pci_dt_t *dram_dev)
170{
171uint32_t dev0, mch_ratio, mch_cfg, mch_fsb;
172
173long *ptr;
174
175// Find Ratio
176dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
177dev0 &= 0xFFFFC000;
178ptr = (long*)(dev0 + 0xC00);
179mch_cfg = *ptr & 0xFFFF;
180
181mch_ratio = 100000;
182
183switch (mch_cfg & 7)
184{
185case 1: mch_fsb = 533; break;
186default:
187case 2:mch_fsb = 800; break;
188case 3:mch_fsb = 667; break;
189case 6:mch_fsb = 1066; break;
190}
191
192switch (mch_fsb)
193{
194case 533:
195switch ((mch_cfg >> 4) & 7)
196{
197case 1:mch_ratio = 125000; break;
198case 2:mch_ratio = 150000; break;
199case 3:mch_ratio = 200000; break;
200}
201break;
202
203case 667:
204switch ((mch_cfg >> 4)& 7)
205{
206case 1:mch_ratio = 100000; break;
207case 2:mch_ratio = 120000; break;
208case 3:mch_ratio = 160000; break;
209case 4:mch_ratio = 200000; break;
210case 5:mch_ratio = 240000; break;
211}
212break;
213
214default:
215case 800:
216switch ((mch_cfg >> 4) & 7)
217{
218case 1:mch_ratio = 83333; break; // 0.833333333
219case 2:mch_ratio = 100000; break;
220case 3:mch_ratio = 133333; break; // 1.333333333
221case 4:mch_ratio = 166667; break; // 1.666666667
222case 5:mch_ratio = 200000; break;
223}
224break;
225case 1066:
226switch ((mch_cfg >> 4)&7) {
227case 5:mch_ratio = 150000; break;
228case 6:mch_ratio = 200000; break;
229}
230
231}
232
233// Compute RAM Frequency
234Platform.RAM.Frequency = (Platform.CPU.FSBFrequency * mch_ratio) / 100000;
235}
236
237
238// Get iCore7 Memory Speed
239static void get_fsb_nhm(pci_dt_t *dram_dev)
240{
241uint32_t mch_ratio, mc_dimm_clk_ratio;
242
243// Get the clock ratio
244mc_dimm_clk_ratio = pci_config_read16(PCIADDR(nhm_bus, 3, 4), 0x54 );
245mch_ratio = (mc_dimm_clk_ratio & 0x1F);
246
247// Compute RAM Frequency
248Platform.RAM.Frequency = Platform.CPU.FSBFrequency * mch_ratio / 2;
249}
250
251/*
252 * Retrieve memory controller info functions
253 */
254
255// Get i965 Memory Timings
256static void get_timings_i965(pci_dt_t *dram_dev)
257{
258// Thanks for CDH optis
259uint32_t dev0, c0ckectrl, c1ckectrl, offset;
260uint32_t ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register;
261
262long *ptr;
263
264// Read MMR Base Address
265dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
266dev0 &= 0xFFFFC000;
267
268ptr = (long*)(dev0 + 0x260);
269c0ckectrl = *ptr & 0xFFFFFFFF;
270
271ptr = (long*)(dev0 + 0x660);
272c1ckectrl = *ptr & 0xFFFFFFFF;
273
274// If DIMM 0 not populated, check DIMM 1
275((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x400);
276
277ptr = (long*)(dev0 + offset + 0x29C);
278ODT_Control_Register = *ptr & 0xFFFFFFFF;
279
280ptr = (long*)(dev0 + offset + 0x250);
281Precharge_Register = *ptr & 0xFFFFFFFF;
282
283ptr = (long*)(dev0 + offset + 0x252);
284ACT_Register = *ptr & 0xFFFFFFFF;
285
286ptr = (long*)(dev0 + offset + 0x258);
287Read_Register = *ptr & 0xFFFFFFFF;
288
289ptr = (long*)(dev0 + offset + 0x244);
290Misc_Register = *ptr & 0xFFFFFFFF;
291
292// 965 Series only support DDR2
293Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
294
295// CAS Latency (tCAS)
296Platform.RAM.CAS = ((ODT_Control_Register >> 17) & 7) + 3;
297
298// RAS-To-CAS (tRCD)
299Platform.RAM.TRC = (Read_Register >> 16) & 0xF;
300
301// RAS Precharge (tRP)
302Platform.RAM.TRP = (ACT_Register >> 13) & 0xF;
303
304// RAS Active to precharge (tRAS)
305Platform.RAM.RAS = (Precharge_Register >> 11) & 0x1F;
306
307if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF))
308Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
309else
310Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
311}
312
313// Get im965 Memory Timings
314static void get_timings_im965(pci_dt_t *dram_dev)
315{
316// Thanks for CDH optis
317uint32_t dev0, c0ckectrl, c1ckectrl, offset, ODT_Control_Register, Precharge_Register;
318long *ptr;
319
320// Read MMR Base Address
321dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
322dev0 &= 0xFFFFC000;
323
324ptr = (long*)(dev0 + 0x1200);
325c0ckectrl = *ptr & 0xFFFFFFFF;
326
327ptr = (long*)(dev0 + 0x1300);
328c1ckectrl = *ptr & 0xFFFFFFFF;
329
330// If DIMM 0 not populated, check DIMM 1
331((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x100);
332
333ptr = (long*)(dev0 + offset + 0x121C);
334ODT_Control_Register = *ptr & 0xFFFFFFFF;
335
336ptr = (long*)(dev0 + offset + 0x1214);
337Precharge_Register = *ptr & 0xFFFFFFFF;
338
339// Series only support DDR2
340Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
341
342// CAS Latency (tCAS)
343Platform.RAM.CAS = ((ODT_Control_Register >> 23) & 7) + 3;
344
345// RAS-To-CAS (tRCD)
346Platform.RAM.TRC = ((Precharge_Register >> 5) & 7) + 2;
347
348// RAS Precharge (tRP)
349Platform.RAM.TRP= (Precharge_Register & 7) + 2;
350
351// RAS Active to precharge (tRAS)
352Platform.RAM.RAS = (Precharge_Register >> 21) & 0x1F;
353
354if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF))
355Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
356else
357Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
358}
359
360// Get P35 Memory Timings
361static void get_timings_p35(pci_dt_t *dram_dev)
362{
363// Thanks for CDH optis
364unsigned long dev0, Memory_Check, c0ckectrl, c1ckectrl, offset;
365unsigned long ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register;
366long *ptr;
367
368//Device_ID = pci_config_read16(dram_dev->dev.addr, 0x02);
369//Device_ID &= 0xFFFF;
370
371// Now, read MMR Base Address
372dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
373dev0 &= 0xFFFFC000;
374
375ptr = (long*)(dev0 + 0x260);
376c0ckectrl = *ptr & 0xFFFFFFFF;
377
378ptr = (long*)(dev0 + 0x660);
379c1ckectrl = *ptr & 0xFFFFFFFF;
380
381// If DIMM 0 not populated, check DIMM 1
382((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x400);
383
384ptr = (long*)(dev0 + offset + 0x265);
385ODT_Control_Register = *ptr & 0xFFFFFFFF;
386
387ptr = (long*)(dev0 + offset + 0x25D);
388Precharge_Register = *ptr & 0xFFFFFFFF;
389
390ptr = (long*)(dev0 + offset + 0x252);
391ACT_Register = *ptr & 0xFFFFFFFF;
392
393ptr = (long*)(dev0 + offset + 0x258);
394Read_Register = *ptr & 0xFFFFFFFF;
395
396ptr = (long*)(dev0 + offset + 0x244);
397Misc_Register = *ptr & 0xFFFFFFFF;
398
399ptr = (long*)(dev0 + offset + 0x1E8);
400Memory_Check = *ptr & 0xFFFFFFFF;
401
402// On P45, check 1A8
403if(dram_dev->device_id > 0x2E00) {
404ptr = (long*)(dev0 + offset + 0x1A8);
405Memory_Check = *ptr & 0xFFFFFFFF;
406Memory_Check >>= 2;
407Memory_Check &= 1;
408Memory_Check = !Memory_Check;
409} else {
410ptr = (long*)(dev0 + offset + 0x1E8);
411Memory_Check = *ptr & 0xFFFFFFFF;
412}
413
414// Determine DDR-II or DDR-III
415if (Memory_Check & 1)
416Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
417else
418Platform.RAM.Type = SMB_MEM_TYPE_DDR3;
419
420// CAS Latency (tCAS)
421if(dram_dev->device_id > 0x2E00)
422Platform.RAM.CAS = ((ODT_Control_Register >> 8) & 0x3F) - 6;
423else
424Platform.RAM.CAS = ((ODT_Control_Register >> 8) & 0x3F) - 9;
425
426// RAS-To-CAS (tRCD)
427Platform.RAM.TRC = (Read_Register >> 17) & 0xF;
428
429// RAS Precharge (tRP)
430Platform.RAM.TRP = (ACT_Register >> 13) & 0xF;
431
432// RAS Active to precharge (tRAS)
433Platform.RAM.RAS = Precharge_Register & 0x3F;
434
435// Channel configuration
436if (((c0ckectrl >> 20) & 0xF) && ((c1ckectrl >> 20) & 0xF))
437Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
438else
439Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
440}
441
442// Get Nehalem Memory Timings
443static void get_timings_nhm(pci_dt_t *dram_dev)
444{
445unsigned long mc_channel_bank_timing, mc_control, mc_channel_mrs_value;
446int fvc_bn = 4;
447
448// Find which channels are populated
449mc_control = pci_config_read16(PCIADDR(nhm_bus, 3, 0), 0x48);
450mc_control = (mc_control >> 8) & 0x7;
451
452// DDR-III
453Platform.RAM.Type = SMB_MEM_TYPE_DDR3;
454
455// Get the first valid channel
456if(mc_control & 1)
457fvc_bn = 4;
458else if(mc_control & 2)
459fvc_bn = 5;
460else if(mc_control & 7)
461fvc_bn = 6;
462
463// Now, detect timings
464mc_channel_bank_timing = pci_config_read32(PCIADDR(nhm_bus, fvc_bn, 0), 0x88);
465mc_channel_mrs_value = pci_config_read32(PCIADDR(nhm_bus, fvc_bn, 0), 0x70);
466
467// CAS Latency (tCAS)
468Platform.RAM.CAS = ((mc_channel_mrs_value >> 4) & 0xF ) + 4;
469
470// RAS-To-CAS (tRCD)
471Platform.RAM.TRC = (mc_channel_bank_timing >> 9) & 0xF;
472
473// RAS Precharge (tRP)
474Platform.RAM.CAS = (mc_channel_bank_timing >> 4) & 0x1F;
475
476// RAS Active to precharge (tRAS)
477Platform.RAM.TRP = mc_channel_bank_timing & 0xF;
478
479// Single , Dual or Triple Channels
480if (mc_control == 1 || mc_control == 2 || mc_control == 4 )
481Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
482else if (mc_control == 7)
483Platform.RAM.Channels = SMB_MEM_CHANNEL_TRIPLE;
484else
485Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
486}
487
488static struct mem_controller_t dram_controllers[] = {
489
490// Default unknown chipset
491{ 0, 0, "",NULL, NULL, NULL },
492
493// Intel
494{ 0x8086, 0x7190, "VMWare",NULL, NULL, NULL },
495
496{ 0x8086, 0x1A30, "i845",NULL, NULL, NULL },
497
498{ 0x8086, 0x2970, "i946PL/GZ",setup_p35, get_fsb_i965, get_timings_i965 },
499{ 0x8086, 0x2990, "Q963/Q965",setup_p35, get_fsb_i965, get_timings_i965 },
500{ 0x8086, 0x29A0, "P965/G965",setup_p35, get_fsb_i965, get_timings_i965 },
501
502{ 0x8086, 0x2A00, "GM965/GL960",setup_p35, get_fsb_im965, get_timings_im965 },
503{ 0x8086, 0x2A10, "GME965/GLE960",setup_p35, get_fsb_im965, get_timings_im965 },
504{ 0x8086, 0x2A40, "PM/GM45/47",setup_p35, get_fsb_im965, get_timings_im965 },
505
506{ 0x8086, 0x29B0, "Q35",setup_p35, get_fsb_i965, get_timings_p35 },
507{ 0x8086, 0x29C0, "P35/G33",setup_p35, get_fsb_i965, get_timings_p35 },
508{ 0x8086, 0x29D0, "Q33",setup_p35, get_fsb_i965, get_timings_p35 },
509{ 0x8086, 0x29E0, "X38/X48",setup_p35, get_fsb_i965, get_timings_p35 },
510{ 0x8086, 0x2E00, "Eaglelake",setup_p35, get_fsb_i965, get_timings_p35 },
511{ 0x8086, 0x2E10, "Q45/Q43",setup_p35, get_fsb_i965, get_timings_p35 },
512{ 0x8086, 0x2E20, "P45/G45",setup_p35, get_fsb_i965, get_timings_p35 },
513{ 0x8086, 0x2E30, "G41",setup_p35, get_fsb_i965, get_timings_p35 },
514
515{ 0x8086, 0xD131, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
516{ 0x8086, 0xD132, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
517{ 0x8086, 0x3400, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
518{ 0x8086, 0x3401, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
519{ 0x8086, 0x3402, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
520{ 0x8086, 0x3403, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
521{ 0x8086, 0x3404, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
522{ 0x8086, 0x3405, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
523{ 0x8086, 0x3406, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
524{ 0x8086, 0x3407, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
525
526};
527
528static const char *memory_channel_types[] =
529{
530"Unknown", "Single", "Dual", "Triple"
531};
532
533void scan_dram_controller(pci_dt_t *dram_dev)
534{
535int i;
536for(i = 1; i < sizeof(dram_controllers) / sizeof(dram_controllers[0]); i++)
537if ((dram_controllers[i].vendor == dram_dev->vendor_id)
538&& (dram_controllers[i].device == dram_dev->device_id))
539{
540verbose("%s%s DRAM Controller [%4x:%4x] at %02x:%02x.%x\n",
541(dram_dev->vendor_id == 0x8086) ? "Intel " : "" ,
542dram_controllers[i].name, dram_dev->vendor_id, dram_dev->device_id,
543dram_dev->dev.bits.bus, dram_dev->dev.bits.dev, dram_dev->dev.bits.func);
544
545if (dram_controllers[i].initialise != NULL)
546dram_controllers[i].initialise(dram_dev);
547
548if (dram_controllers[i].poll_timings != NULL)
549dram_controllers[i].poll_timings(dram_dev);
550
551if (dram_controllers[i].poll_speed != NULL)
552dram_controllers[i].poll_speed(dram_dev);
553
554verbose("Frequency detected: %d MHz (%d) %s Channel %d-%d-%d-%d\n",
555(uint32_t)Platform.RAM.Frequency / 1000000,
556(uint32_t)Platform.RAM.Frequency / 500000,
557memory_channel_types[Platform.RAM.Channels],
558Platform.RAM.CAS, Platform.RAM.TRC, Platform.RAM.TRP, Platform.RAM.RAS
559 );
560
561}
562}
563

Archive Download this file

Revision: 463