Chameleon

Chameleon Svn Source Tree

Root/tags/2.3/i386/libsaio/dram_controllers.c

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

Archive Download this file

Revision: HEAD