Chameleon

Chameleon Svn Source Tree

Root/branches/rewrite/i386/libsaio/dram_controllers.c

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

Archive Download this file

Revision: 1066