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