Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1119