Chameleon

Chameleon Svn Source Tree

Root/trunk/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 original :
4 *
5 * memtest86
6 *
7 * Released under version 2 of the Gnu Public License.
8 * By Chris Brady, cbrady@sgi.com
9 * ----------------------------------------------------
10 * MemTest86+ V4.00 Specific code (GPL V2.0)
11 * By Samuel DEMEULEMEESTER, sdemeule@memtest.org
12 * http://www.canardpc.com - http://www.memtest.org
13 */
14
15#include "libsaio.h"
16#include "bootstruct.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), 0x00);
60did = pci_config_read16(PCIADDR(possible_nhm_bus[i], 3, 4), 0x02);
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;
93 default:
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 = 133553; break; // 1.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;
188}
189
190switch (mch_fsb)
191{
192case 533:
193switch ((mch_cfg >> 4) & 7)
194{
195case 1:mch_ratio = 125000; break;
196case 2:mch_ratio = 150000; break;
197case 3:mch_ratio = 200000; break;
198}
199break;
200
201case 667:
202switch ((mch_cfg >> 4)& 7)
203{
204case 1:mch_ratio = 100000; break;
205case 2:mch_ratio = 120000; break;
206case 3:mch_ratio = 160000; break;
207case 4:mch_ratio = 200000; break;
208case 5:mch_ratio = 240000; break;
209}
210break;
211
212default:
213case 800:
214switch ((mch_cfg >> 4) & 7)
215{
216case 1:mch_ratio = 83000; break; // 0.833333333
217case 2:mch_ratio = 100000; break;
218case 3:mch_ratio = 133333; break; // 1.333333333
219case 4:mch_ratio = 166667; break; // 1.666666667
220case 5:mch_ratio = 200000; break;
221}
222break;
223
224}
225
226// Compute RAM Frequency
227Platform.RAM.Frequency = (Platform.CPU.FSBFrequency * mch_ratio) / 100000;
228}
229
230
231// Get iCore7 Memory Speed
232static void get_fsb_nhm(pci_dt_t *dram_dev)
233{
234uint32_t mch_ratio, mc_dimm_clk_ratio;
235
236// Get the clock ratio
237mc_dimm_clk_ratio = pci_config_read16(PCIADDR(nhm_bus, 3, 4), 0x54 );
238mch_ratio = (mc_dimm_clk_ratio & 0x1F);
239
240// Compute RAM Frequency
241Platform.RAM.Frequency = Platform.CPU.FSBFrequency * mch_ratio / 2;
242}
243
244/*
245 * Retrieve memory controller info functions
246 */
247
248// Get i965 Memory Timings
249static void get_timings_i965(pci_dt_t *dram_dev)
250{
251// Thanks for CDH optis
252uint32_t dev0, c0ckectrl, c1ckectrl, offset;
253uint32_t ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register;
254
255long *ptr;
256
257// Read MMR Base Address
258dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
259dev0 &= 0xFFFFC000;
260
261ptr = (long*)(dev0 + 0x260);
262c0ckectrl = *ptr & 0xFFFFFFFF;
263
264ptr = (long*)(dev0 + 0x660);
265c1ckectrl = *ptr & 0xFFFFFFFF;
266
267// If DIMM 0 not populated, check DIMM 1
268((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x400);
269
270ptr = (long*)(dev0 + offset + 0x29C);
271ODT_Control_Register = *ptr & 0xFFFFFFFF;
272
273ptr = (long*)(dev0 + offset + 0x250);
274Precharge_Register = *ptr & 0xFFFFFFFF;
275
276ptr = (long*)(dev0 + offset + 0x252);
277ACT_Register = *ptr & 0xFFFFFFFF;
278
279ptr = (long*)(dev0 + offset + 0x258);
280Read_Register = *ptr & 0xFFFFFFFF;
281
282ptr = (long*)(dev0 + offset + 0x244);
283Misc_Register = *ptr & 0xFFFFFFFF;
284
285// 965 Series only support DDR2
286Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
287
288// CAS Latency (tCAS)
289Platform.RAM.CAS = ((ODT_Control_Register >> 17) & 7) + 3;
290
291// RAS-To-CAS (tRCD)
292Platform.RAM.TRC = (Read_Register >> 16) & 0xF;
293
294// RAS Precharge (tRP)
295Platform.RAM.TRP = (ACT_Register >> 13) & 0xF;
296
297// RAS Active to precharge (tRAS)
298Platform.RAM.RAS = (Precharge_Register >> 11) & 0x1F;
299
300if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF))
301Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
302else
303Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
304}
305
306// Get im965 Memory Timings
307static void get_timings_im965(pci_dt_t *dram_dev)
308{
309// Thanks for CDH optis
310uint32_t dev0, c0ckectrl, c1ckectrl, offset, ODT_Control_Register, Precharge_Register;
311long *ptr;
312
313// Read MMR Base Address
314dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
315dev0 &= 0xFFFFC000;
316
317ptr = (long*)(dev0 + 0x1200);
318c0ckectrl = *ptr & 0xFFFFFFFF;
319
320ptr = (long*)(dev0 + 0x1300);
321c1ckectrl = *ptr & 0xFFFFFFFF;
322
323// If DIMM 0 not populated, check DIMM 1
324((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x100);
325
326ptr = (long*)(dev0 + offset + 0x121C);
327ODT_Control_Register = *ptr & 0xFFFFFFFF;
328
329ptr = (long*)(dev0 + offset + 0x1214);
330Precharge_Register = *ptr & 0xFFFFFFFF;
331
332// Series only support DDR2
333Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
334
335// CAS Latency (tCAS)
336Platform.RAM.CAS = ((ODT_Control_Register >> 23) & 7) + 3;
337
338// RAS-To-CAS (tRCD)
339Platform.RAM.TRC = ((Precharge_Register >> 5) & 7) + 2;
340
341// RAS Precharge (tRP)
342Platform.RAM.TRP= (Precharge_Register & 7) + 2;
343
344// RAS Active to precharge (tRAS)
345Platform.RAM.RAS = (Precharge_Register >> 21) & 0x1F;
346
347if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF))
348Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
349else
350Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
351}
352
353// Get P35 Memory Timings
354static void get_timings_p35(pci_dt_t *dram_dev)
355{
356// Thanks for CDH optis
357unsigned long dev0, Memory_Check, c0ckectrl, c1ckectrl, offset;
358unsigned long ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register;
359long *ptr;
360
361//Device_ID = pci_config_read16(dram_dev->dev.addr, 0x02);
362//Device_ID &= 0xFFFF;
363
364// Now, read MMR Base Address
365dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
366dev0 &= 0xFFFFC000;
367
368ptr = (long*)(dev0 + 0x260);
369c0ckectrl = *ptr & 0xFFFFFFFF;
370
371ptr = (long*)(dev0 + 0x660);
372c1ckectrl = *ptr & 0xFFFFFFFF;
373
374// If DIMM 0 not populated, check DIMM 1
375((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x400);
376
377ptr = (long*)(dev0 + offset + 0x265);
378ODT_Control_Register = *ptr & 0xFFFFFFFF;
379
380ptr = (long*)(dev0 + offset + 0x25D);
381Precharge_Register = *ptr & 0xFFFFFFFF;
382
383ptr = (long*)(dev0 + offset + 0x252);
384ACT_Register = *ptr & 0xFFFFFFFF;
385
386ptr = (long*)(dev0 + offset + 0x258);
387Read_Register = *ptr & 0xFFFFFFFF;
388
389ptr = (long*)(dev0 + offset + 0x244);
390Misc_Register = *ptr & 0xFFFFFFFF;
391
392ptr = (long*)(dev0 + offset + 0x1E8);
393Memory_Check = *ptr & 0xFFFFFFFF;
394
395// On P45, check 1A8
396if(dram_dev->device_id > 0x2E00) {
397ptr = (long*)(dev0 + offset + 0x1A8);
398Memory_Check = *ptr & 0xFFFFFFFF;
399Memory_Check >>= 2;
400Memory_Check &= 1;
401Memory_Check = !Memory_Check;
402} else {
403ptr = (long*)(dev0 + offset + 0x1E8);
404Memory_Check = *ptr & 0xFFFFFFFF;
405}
406
407// Determine DDR-II or DDR-III
408if (Memory_Check & 1)
409Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
410else
411Platform.RAM.Type = SMB_MEM_TYPE_DDR3;
412
413// CAS Latency (tCAS)
414if(dram_dev->device_id > 0x2E00)
415Platform.RAM.CAS = ((ODT_Control_Register >> 8) & 0x3F) - 6;
416else
417Platform.RAM.CAS = ((ODT_Control_Register >> 8) & 0x3F) - 9;
418
419// RAS-To-CAS (tRCD)
420Platform.RAM.TRC = (Read_Register >> 17) & 0xF;
421
422// RAS Precharge (tRP)
423Platform.RAM.TRP = (ACT_Register >> 13) & 0xF;
424
425// RAS Active to precharge (tRAS)
426Platform.RAM.RAS = Precharge_Register & 0x3F;
427
428// Channel configuration
429if (((c0ckectrl >> 20) & 0xF) && ((c1ckectrl >> 20) & 0xF))
430Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
431else
432Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
433}
434
435// Get Nehalem Memory Timings
436static void get_timings_nhm(pci_dt_t *dram_dev)
437{
438unsigned long mc_channel_bank_timing, mc_control, mc_channel_mrs_value;
439int fvc_bn = 4;
440
441// Find which channels are populated
442mc_control = pci_config_read16(PCIADDR(nhm_bus, 3, 0), 0x48);
443mc_control = (mc_control >> 8) & 0x7;
444
445// DDR-III
446Platform.RAM.Type = SMB_MEM_TYPE_DDR3;
447
448// Get the first valid channel
449if(mc_control & 1)
450fvc_bn = 4;
451else if(mc_control & 2)
452fvc_bn = 5;
453else if(mc_control & 7)
454fvc_bn = 6;
455
456// Now, detect timings
457mc_channel_bank_timing = pci_config_read32(PCIADDR(nhm_bus, fvc_bn, 0), 0x88);
458mc_channel_mrs_value = pci_config_read32(PCIADDR(nhm_bus, fvc_bn, 0), 0x70);
459
460// CAS Latency (tCAS)
461Platform.RAM.CAS = ((mc_channel_mrs_value >> 4) & 0xF ) + 4;
462
463// RAS-To-CAS (tRCD)
464Platform.RAM.TRC = (mc_channel_bank_timing >> 9) & 0xF;
465
466// RAS Precharge (tRP)
467Platform.RAM.CAS = (mc_channel_bank_timing >> 4) & 0x1F;
468
469// RAS Active to precharge (tRAS)
470Platform.RAM.TRP = mc_channel_bank_timing & 0xF;
471
472// Single , Dual or Triple Channels
473if (mc_control == 1 || mc_control == 2 || mc_control == 4 )
474Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
475else if (mc_control == 7)
476Platform.RAM.Channels = SMB_MEM_CHANNEL_TRIPLE;
477else
478Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
479}
480
481static struct mem_controller_t dram_controllers[] = {
482
483// Default unknown chipset
484{ 0, 0, "",NULL, NULL, NULL },
485
486// Intel
487{ 0x8086, 0x7190, "VMWare",NULL, NULL, NULL },
488
489{ 0x8086, 0x1A30, "i845",NULL, NULL, NULL },
490
491{ 0x8086, 0x2970, "i946PL/GZ",setup_p35, get_fsb_i965, get_timings_i965 },
492{ 0x8086, 0x2990, "Q963/Q965",setup_p35, get_fsb_i965, get_timings_i965 },
493{ 0x8086, 0x29A0, "P965/G965",setup_p35, get_fsb_i965, get_timings_i965 },
494
495{ 0x8086, 0x2A00, "GM965/GL960",setup_p35, get_fsb_im965, get_timings_im965 },
496{ 0x8086, 0x2A10, "GME965/GLE960",setup_p35, get_fsb_im965, get_timings_im965 },
497{ 0x8086, 0x2A40, "PM/GM45/47",setup_p35, get_fsb_im965, get_timings_im965 },
498
499{ 0x8086, 0x29B0, "Q35",setup_p35, get_fsb_i965, get_timings_p35 },
500{ 0x8086, 0x29C0, "P35/G33",setup_p35, get_fsb_i965, get_timings_p35 },
501{ 0x8086, 0x29D0, "Q33",setup_p35, get_fsb_i965, get_timings_p35 },
502{ 0x8086, 0x29E0, "X38/X48",setup_p35, get_fsb_i965, get_timings_p35 },
503{ 0x8086, 0x2E00, "Eaglelake",setup_p35, get_fsb_i965, get_timings_p35 },
504{ 0x8086, 0x2E10, "Q45/Q43",setup_p35, get_fsb_i965, get_timings_p35 },
505{ 0x8086, 0x2E20, "P45/G45",setup_p35, get_fsb_i965, get_timings_p35 },
506{ 0x8086, 0x2E30, "G41",setup_p35, get_fsb_i965, get_timings_p35 },
507
508{ 0x8086, 0xD131, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
509{ 0x8086, 0xD132, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
510{ 0x8086, 0x3400, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
511{ 0x8086, 0x3401, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
512{ 0x8086, 0x3402, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
513{ 0x8086, 0x3403, "NHM IMC",setup_nhm, get_fsb_nhm, get_timings_nhm },
514
515};
516
517static const char *memory_channel_types[] =
518{
519"Unknown", "Single", "Dual", "Triple"
520};
521
522void scan_dram_controller(pci_dt_t *dram_dev)
523{
524int i;
525for(i = 1; i < sizeof(dram_controllers) / sizeof(dram_controllers[0]); i++)
526if ((dram_controllers[i].vendor == dram_dev->vendor_id)
527&& (dram_controllers[i].device == dram_dev->device_id))
528{
529verbose("%s%s DRAM Controller [%4x:%4x] at %02x:%02x.%x\n",
530(dram_dev->vendor_id == 0x8086) ? "Intel " : "" ,
531dram_controllers[i].name, dram_dev->vendor_id, dram_dev->device_id,
532dram_dev->dev.bits.bus, dram_dev->dev.bits.dev, dram_dev->dev.bits.func);
533
534if (dram_controllers[i].initialise != NULL)
535dram_controllers[i].initialise(dram_dev);
536
537if (dram_controllers[i].poll_timings != NULL)
538dram_controllers[i].poll_timings(dram_dev);
539
540if (dram_controllers[i].poll_speed != NULL)
541dram_controllers[i].poll_speed(dram_dev);
542
543verbose("Frequency detected: %d MHz (%d) %s Channel %d-%d-%d-%d\n",
544(uint32_t)Platform.RAM.Frequency / 1000000,
545(uint32_t)Platform.RAM.Frequency / 500000,
546memory_channel_types[Platform.RAM.Channels],
547Platform.RAM.CAS, Platform.RAM.TRC, Platform.RAM.TRP, Platform.RAM.RAS
548 );
549
550}
551}
552

Archive Download this file

Revision: 233