]>
Commit | Line | Data |
---|---|---|
c7de829c WD |
1 | /* |
2 | * (C) Copyright 2002 | |
8bde7f77 | 3 | * Hyperion Entertainment, ThomasF@hyperion-entertainment.com |
c7de829c WD |
4 | * |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <pci.h> | |
26 | #include <asm/processor.h> | |
27 | #include "memio.h" | |
28 | #include "articiaS.h" | |
29 | #include "smbus.h" | |
30 | #include "via686.h" | |
31 | ||
32 | #undef DEBUG | |
33 | ||
34 | struct dimm_bank { | |
35 | uint8 used; /* Bank is populated */ | |
36 | uint32 rows; /* Number of row addresses */ | |
37 | uint32 columns; /* Number of column addresses */ | |
38 | uint8 registered; /* SIMM is registered */ | |
39 | uint8 ecc; /* SIMM has ecc */ | |
40 | uint8 burst_len; /* Supported burst lengths */ | |
41 | uint32 cas_lat; /* Supported CAS latencies */ | |
42 | uint32 cas_used; /* CAS to use (not set by user) */ | |
43 | uint32 trcd; /* RAS to CAS latency */ | |
44 | uint32 trp; /* Precharge latency */ | |
45 | uint32 tclk_hi; /* SDRAM cycle time (highest CAS latency) */ | |
46 | uint32 tclk_2hi; /* SDRAM second highest CAS latency */ | |
47 | uint32 size; /* Size of bank in bytes */ | |
48 | uint8 auto_refresh; /* Module supports auto refresh */ | |
49 | uint32 refresh_time; /* Refresh time (in ns) */ | |
50 | }; | |
51 | ||
52 | ||
53 | /* | |
54 | ** Based in part on the evb64260 code | |
55 | */ | |
56 | ||
57 | /* | |
58 | * translate ns.ns/10 coding of SPD timing values | |
59 | * into 10 ps unit values | |
60 | */ | |
61 | static inline unsigned short NS10to10PS (unsigned char spd_byte) | |
62 | { | |
63 | unsigned short ns, ns10; | |
64 | ||
65 | /* isolate upper nibble */ | |
66 | ns = (spd_byte >> 4) & 0x0F; | |
67 | /* isolate lower nibble */ | |
68 | ns10 = (spd_byte & 0x0F); | |
69 | ||
70 | return (ns * 100 + ns10 * 10); | |
71 | } | |
72 | ||
73 | /* | |
74 | * translate ns coding of SPD timing values | |
75 | * into 10 ps unit values | |
76 | */ | |
77 | static inline unsigned short NSto10PS (unsigned char spd_byte) | |
78 | { | |
79 | return (spd_byte * 100); | |
80 | } | |
81 | ||
82 | ||
83 | long detect_sdram (uint8 * rom, int dimmNum, struct dimm_bank *banks) | |
84 | { | |
7c7a23bd | 85 | DECLARE_GLOBAL_DATA_PTR; |
c7de829c | 86 | int dimm_address = (dimmNum == 0) ? SM_DIMM0_ADDR : SM_DIMM1_ADDR; |
7c7a23bd | 87 | uint32 busclock = gd->bus_clk; |
c7de829c WD |
88 | uint32 memclock = busclock; |
89 | uint32 tmemclock = 1000000000 / (memclock / 100); | |
90 | uint32 datawidth; | |
91 | ||
92 | if (sm_get_data (rom, dimm_address) == 0) { | |
93 | /* Nothing in slot, make both banks empty */ | |
94 | debug ("Slot %d: vacant\n", dimmNum); | |
95 | banks[0].used = 0; | |
96 | banks[1].used = 0; | |
97 | return 0; | |
98 | } | |
99 | ||
100 | if (rom[2] != 0x04) { | |
101 | debug ("Slot %d: No SDRAM\n", dimmNum); | |
102 | banks[0].used = 0; | |
103 | banks[1].used = 0; | |
104 | return 0; | |
105 | } | |
106 | ||
107 | /* Determine number of banks/rows */ | |
108 | if (rom[5] == 1) { | |
109 | banks[0].used = 1; | |
110 | banks[1].used = 0; | |
111 | } else { | |
112 | banks[0].used = 1; | |
113 | banks[1].used = 1; | |
114 | } | |
115 | ||
116 | /* Determine number of row addresses */ | |
117 | if (rom[3] & 0xf0) { | |
118 | /* Different banks sizes */ | |
119 | banks[0].rows = rom[3] & 0x0f; | |
120 | banks[1].rows = (rom[3] & 0xf0) >> 4; | |
121 | } else { | |
122 | /* Equal sized banks */ | |
123 | banks[0].rows = rom[3] & 0x0f; | |
124 | banks[1].rows = banks[0].rows; | |
125 | } | |
126 | ||
127 | /* Determine number of column addresses */ | |
128 | if (rom[4] & 0xf0) { | |
129 | /* Different bank sizes */ | |
130 | banks[0].columns = rom[4] & 0x0f; | |
131 | banks[1].columns = (rom[4] & 0xf0) >> 4; | |
132 | } else { | |
133 | banks[0].columns = rom[4] & 0x0f; | |
134 | banks[1].columns = banks[0].columns; | |
135 | } | |
136 | ||
137 | /* Check Jedec revision, and modify row/column accordingly */ | |
138 | if (rom[62] > 0x10) { | |
139 | if (banks[0].rows <= 3) | |
140 | banks[0].rows += 15; | |
141 | if (banks[1].rows <= 3) | |
142 | banks[1].rows += 15; | |
143 | if (banks[0].columns <= 3) | |
144 | banks[0].columns += 15; | |
145 | if (banks[0].columns <= 3) | |
146 | banks[0].columns += 15; | |
147 | } | |
148 | ||
149 | /* Check registered/unregisterd */ | |
150 | if (rom[21] & 0x12) { | |
151 | banks[0].registered = 1; | |
152 | banks[1].registered = 1; | |
153 | } else { | |
154 | banks[0].registered = 0; | |
155 | banks[1].registered = 0; | |
156 | } | |
157 | ||
158 | #ifdef CONFIG_ECC | |
159 | /* Check parity/ECC */ | |
160 | banks[0].ecc = (rom[11] == 0x02); | |
161 | banks[1].ecc = (rom[11] == 0x02); | |
162 | #endif | |
163 | ||
164 | /* Find burst lengths supported */ | |
165 | banks[0].burst_len = rom[16] & 0x8f; | |
166 | banks[1].burst_len = rom[16] & 0x8f; | |
167 | ||
168 | /* Find possible cas latencies */ | |
169 | banks[0].cas_lat = rom[18] & 0x7F; | |
170 | banks[1].cas_lat = rom[18] & 0x7F; | |
171 | ||
172 | /* RAS/CAS latency */ | |
173 | banks[0].trcd = (NSto10PS (rom[29]) + (tmemclock - 1)) / tmemclock; | |
174 | banks[1].trcd = (NSto10PS (rom[29]) + (tmemclock - 1)) / tmemclock; | |
175 | ||
176 | /* Precharge latency */ | |
177 | banks[0].trp = (NSto10PS (rom[27]) + (tmemclock - 1)) / tmemclock; | |
178 | banks[1].trp = (NSto10PS (rom[27]) + (tmemclock - 1)) / tmemclock; | |
179 | ||
180 | /* highest CAS latency */ | |
181 | banks[0].tclk_hi = NS10to10PS (rom[9]); | |
182 | banks[1].tclk_hi = NS10to10PS (rom[9]); | |
183 | ||
184 | /* second highest CAS latency */ | |
185 | banks[0].tclk_2hi = NS10to10PS (rom[23]); | |
186 | banks[1].tclk_2hi = NS10to10PS (rom[23]); | |
187 | ||
188 | /* bank sizes */ | |
189 | datawidth = rom[13] & 0x7f; | |
190 | banks[0].size = | |
191 | (1L << (banks[0].rows + banks[0].columns)) * | |
192 | /* FIXME datawidth */ 8 * rom[17]; | |
193 | if (rom[13] & 0x80) | |
194 | banks[1].size = 2 * banks[0].size; | |
195 | else | |
196 | banks[1].size = (1L << (banks[1].rows + banks[1].columns)) * | |
197 | /* FIXME datawidth */ 8 * rom[17]; | |
198 | ||
199 | /* Refresh */ | |
200 | if (rom[12] & 0x80) { | |
201 | banks[0].auto_refresh = 1; | |
202 | banks[1].auto_refresh = 1; | |
203 | } else { | |
204 | banks[0].auto_refresh = 0; | |
205 | banks[1].auto_refresh = 0; | |
206 | } | |
207 | ||
208 | switch (rom[12] & 0x7f) { | |
209 | case 0: | |
210 | banks[0].refresh_time = (1562500 + (tmemclock - 1)) / tmemclock; | |
211 | banks[1].refresh_time = (1562500 + (tmemclock - 1)) / tmemclock; | |
212 | break; | |
213 | case 1: | |
214 | banks[0].refresh_time = (390600 + (tmemclock - 1)) / tmemclock; | |
215 | banks[1].refresh_time = (390600 + (tmemclock - 1)) / tmemclock; | |
216 | break; | |
217 | case 2: | |
218 | banks[0].refresh_time = (781200 + (tmemclock - 1)) / tmemclock; | |
219 | banks[1].refresh_time = (781200 + (tmemclock - 1)) / tmemclock; | |
220 | break; | |
221 | case 3: | |
222 | banks[0].refresh_time = (3125000 + (tmemclock - 1)) / tmemclock; | |
223 | banks[1].refresh_time = (3125000 + (tmemclock - 1)) / tmemclock; | |
224 | break; | |
225 | case 4: | |
226 | banks[0].refresh_time = (6250000 + (tmemclock - 1)) / tmemclock; | |
227 | banks[1].refresh_time = (6250000 + (tmemclock - 1)) / tmemclock; | |
228 | break; | |
229 | case 5: | |
230 | banks[0].refresh_time = (12500000 + (tmemclock - 1)) / tmemclock; | |
231 | banks[1].refresh_time = (12500000 + (tmemclock - 1)) / tmemclock; | |
232 | break; | |
233 | default: | |
234 | banks[0].refresh_time = 0x100; /* Default of Articia S */ | |
235 | banks[1].refresh_time = 0x100; | |
236 | break; | |
237 | } | |
238 | ||
239 | #ifdef DEBUG | |
240 | printf ("\nInformation for SIMM bank %ld:\n", dimmNum); | |
241 | printf ("Number of banks: %ld\n", banks[0].used + banks[1].used); | |
242 | printf ("Number of row addresses: %ld\n", banks[0].rows); | |
243 | printf ("Number of coumns addresses: %ld\n", banks[0].columns); | |
244 | printf ("SIMM is %sregistered\n", | |
245 | banks[0].registered == 0 ? "not " : ""); | |
246 | #ifdef CONFIG_ECC | |
247 | printf ("SIMM %s ECC\n", | |
248 | banks[0].ecc == 1 ? "supports" : "doesn't support"); | |
249 | #endif | |
250 | printf ("Supported burst lenghts: %s %s %s %s %s\n", | |
251 | banks[0].burst_len & 0x08 ? "8" : " ", | |
252 | banks[0].burst_len & 0x04 ? "4" : " ", | |
253 | banks[0].burst_len & 0x02 ? "2" : " ", | |
254 | banks[0].burst_len & 0x01 ? "1" : " ", | |
255 | banks[0].burst_len & 0x80 ? "PAGE" : " "); | |
256 | printf ("Supported CAS latencies: %s %s %s\n", | |
257 | banks[0].cas_lat & 0x04 ? "CAS 3" : " ", | |
258 | banks[0].cas_lat & 0x02 ? "CAS 2" : " ", | |
259 | banks[0].cas_lat & 0x01 ? "CAS 1" : " "); | |
260 | printf ("RAS to CAS latency: %ld\n", banks[0].trcd); | |
261 | printf ("Precharge latency: %ld\n", banks[0].trp); | |
262 | printf ("SDRAM highest CAS latency: %ld\n", banks[0].tclk_hi); | |
263 | printf ("SDRAM 2nd highest CAS latency: %ld\n", banks[0].tclk_2hi); | |
264 | printf ("SDRAM data width: %ld\n", datawidth); | |
265 | printf ("Auto Refresh %ssupported\n", | |
266 | banks[0].auto_refresh ? "" : "not "); | |
267 | printf ("Refresh time: %ld clocks\n", banks[0].refresh_time); | |
268 | if (banks[0].used) | |
269 | printf ("Bank 0 size: %ld MB\n", banks[0].size / 1024 / 1024); | |
270 | if (banks[1].used) | |
271 | printf ("Bank 1 size: %ld MB\n", banks[1].size / 1024 / 1024); | |
272 | ||
273 | printf ("\n"); | |
274 | #endif | |
275 | ||
276 | sm_term (); | |
277 | return 1; | |
278 | } | |
279 | ||
280 | void select_cas (struct dimm_bank *banks, uint8 fast) | |
281 | { | |
282 | if (!banks[0].used) { | |
283 | banks[0].cas_used = 0; | |
284 | banks[0].cas_used = 0; | |
285 | return; | |
286 | } | |
287 | ||
288 | if (fast) { | |
289 | /* Search for fast CAS */ | |
290 | uint32 i; | |
291 | uint32 c = 0x01; | |
292 | ||
293 | for (i = 1; i < 5; i++) { | |
294 | if (banks[0].cas_lat & c) { | |
295 | banks[0].cas_used = i; | |
296 | banks[1].cas_used = i; | |
297 | debug ("Using CAS %d (fast)\n", i); | |
298 | return; | |
299 | } | |
300 | c <<= 1; | |
301 | } | |
302 | ||
303 | /* Default to CAS 3 */ | |
304 | banks[0].cas_used = 3; | |
305 | banks[1].cas_used = 3; | |
306 | debug ("Using CAS 3 (fast)\n"); | |
307 | ||
308 | return; | |
309 | } else { | |
310 | /* Search for slow cas */ | |
311 | uint32 i; | |
312 | uint32 c = 0x08; | |
313 | ||
314 | for (i = 4; i > 1; i--) { | |
315 | if (banks[0].cas_lat & c) { | |
316 | banks[0].cas_used = i; | |
317 | banks[1].cas_used = i; | |
318 | debug ("Using CAS %d (slow)\n", i); | |
319 | return; | |
320 | } | |
321 | c >>= 1; | |
322 | } | |
323 | ||
324 | /* Default to CAS 3 */ | |
325 | banks[0].cas_used = 3; | |
326 | banks[1].cas_used = 3; | |
327 | debug ("Using CAS 3 (slow)\n"); | |
328 | ||
329 | return; | |
330 | } | |
331 | ||
332 | banks[0].cas_used = 3; | |
333 | banks[1].cas_used = 3; | |
334 | debug ("Using CAS 3\n"); | |
335 | ||
336 | return; | |
337 | } | |
338 | ||
339 | uint32 get_reg_setting (uint32 banks, uint32 rows, uint32 columns, uint32 size) | |
340 | { | |
341 | uint32 i; | |
342 | ||
343 | struct RowColumnSize { | |
344 | uint32 banks; | |
345 | uint32 rows; | |
346 | uint32 columns; | |
347 | uint32 size; | |
348 | uint32 register_value; | |
349 | }; | |
350 | ||
351 | struct RowColumnSize rcs_map[] = { | |
352 | /* Sbk Radr Cadr MB Value */ | |
353 | {1, 11, 8, 8, 0x00840f00}, | |
354 | {1, 11, 9, 16, 0x00925f00}, | |
355 | {1, 11, 10, 32, 0x00a64f00}, | |
356 | {2, 12, 8, 32, 0x00c55f00}, | |
357 | {2, 12, 9, 64, 0x00d66f00}, | |
358 | {2, 12, 10, 128, 0x00e77f00}, | |
359 | {2, 12, 11, 256, 0x00ff8f00}, | |
360 | {2, 13, 11, 512, 0x00ff9f00}, | |
361 | {0, 0, 0, 0, 0x00000000} | |
362 | }; | |
363 | ||
364 | ||
365 | i = 0; | |
366 | ||
367 | while (rcs_map[i].banks != 0) { | |
368 | if (rows == rcs_map[i].rows | |
369 | && columns == rcs_map[i].columns | |
370 | && (size / 1024 / 1024) == rcs_map[i].size) | |
371 | return rcs_map[i].register_value; | |
372 | ||
373 | i++; | |
374 | } | |
375 | ||
376 | return 0; | |
377 | } | |
378 | ||
379 | uint32 burst_to_len (uint32 support) | |
380 | { | |
381 | if (support & 0x80) | |
382 | return 0x7; | |
383 | else if (support & 0x8) | |
384 | return 0x3; | |
385 | else if (support & 0x4) | |
386 | return 0x2; | |
387 | else if (support & 0x2) | |
388 | return 0x1; | |
389 | else if (support & 0x1) | |
390 | return 0x0; | |
391 | ||
392 | return 0; | |
393 | } | |
394 | ||
395 | long articiaS_ram_init (void) | |
396 | { | |
397 | DECLARE_GLOBAL_DATA_PTR; | |
398 | ||
399 | register uint32 i; | |
400 | register uint32 value1; | |
401 | register uint32 value2; | |
402 | uint8 rom[128]; | |
403 | uint32 burst_len; | |
404 | uint32 burst_support; | |
405 | uint32 total_ram = 0; | |
406 | ||
407 | struct dimm_bank banks[4]; /* FIXME: Move to initram */ | |
7c7a23bd | 408 | uint32 busclock = gd->bus_clk; |
c7de829c WD |
409 | uint32 memclock = busclock; |
410 | uint32 reg32; | |
411 | uint32 refresh_clocks; | |
412 | uint8 auto_refresh; | |
413 | ||
414 | memset (banks, 0, sizeof (struct dimm_bank) * 4); | |
415 | ||
416 | detect_sdram (rom, 0, &banks[0]); | |
417 | detect_sdram (rom, 1, &banks[2]); | |
418 | ||
419 | for (i = 0; i < 4; i++) { | |
420 | total_ram = total_ram + (banks[i].used * banks[i].size); | |
421 | } | |
422 | ||
423 | pci_write_cfg_long (0, 0, GLOBALINFO0, 0x117430c0); | |
424 | pci_write_cfg_long (0, 0, HBUSACR0, 0x1f0100b0); | |
425 | pci_write_cfg_long (0, 0, SRAM_CR, 0x00f12000); /* Note: Might also try 0x00f10000 (original: 0x00f12000) */ | |
426 | pci_write_cfg_byte (0, 0, DRAM_RAS_CTL0, 0x3f); | |
427 | pci_write_cfg_byte (0, 0, DRAM_RAS_CTL1, 0x00); /* was: 0x04); */ | |
428 | pci_write_cfg_word (0, 0, DRAM_ECC0, 0x2020); /* was: 0x2400); No ECC yet */ | |
429 | ||
430 | /* FIXME: Move this stuff to seperate function, like setup_dimm_bank */ | |
431 | if (banks[0].used) { | |
432 | value1 = get_reg_setting (banks[0].used + banks[1].used, | |
433 | banks[0].rows, banks[0].columns, | |
434 | banks[0].size); | |
435 | } else { | |
436 | value1 = 0; | |
437 | } | |
438 | ||
439 | if (banks[1].used) { | |
440 | value2 = get_reg_setting (banks[0].used + banks[1].used, | |
441 | banks[1].rows, banks[1].columns, | |
442 | banks[1].size); | |
443 | } else { | |
444 | value2 = 0; | |
445 | } | |
446 | ||
447 | pci_write_cfg_long (0, 0, DIMM0_B0_SCR0, value1); | |
448 | pci_write_cfg_long (0, 0, DIMM0_B1_SCR0, value2); | |
449 | ||
450 | debug ("DIMM0_B0_SCR0 = 0x%08x\n", value1); | |
451 | debug ("DIMM0_B1_SCR0 = 0x%08x\n", value2); | |
452 | ||
453 | if (banks[2].used) { | |
454 | value1 = get_reg_setting (banks[2].used + banks[3].used, | |
455 | banks[2].rows, banks[2].columns, | |
456 | banks[2].size); | |
457 | } else { | |
458 | value1 = 0; | |
459 | } | |
460 | ||
461 | if (banks[3].used) { | |
462 | value2 = get_reg_setting (banks[2].used + banks[3].used, | |
463 | banks[3].rows, banks[3].columns, | |
464 | banks[3].size); | |
465 | } else { | |
466 | value2 = 0; | |
467 | } | |
468 | ||
469 | pci_write_cfg_long (0, 0, DIMM1_B2_SCR0, value1); | |
470 | pci_write_cfg_long (0, 0, DIMM1_B3_SCR0, value2); | |
471 | ||
472 | debug ("DIMM0_B2_SCR0 = 0x%08x\n", value1); | |
473 | debug ("DIMM0_B3_SCR0 = 0x%08x\n", value2); | |
474 | ||
475 | pci_write_cfg_long (0, 0, DIMM2_B4_SCR0, 0); | |
476 | pci_write_cfg_long (0, 0, DIMM2_B5_SCR0, 0); | |
477 | pci_write_cfg_long (0, 0, DIMM3_B6_SCR0, 0); | |
478 | pci_write_cfg_long (0, 0, DIMM3_B7_SCR0, 0); | |
479 | ||
480 | /* Determine timing */ | |
481 | select_cas (&banks[0], 0); | |
482 | select_cas (&banks[2], 0); | |
483 | ||
484 | /* FIXME: What about write recovery */ | |
485 | /* Auto refresh Precharge */ | |
486 | #if 0 | |
487 | reg32 = (0x3 << 13) | (0x7 << 10) | ((banks[0].trp - 2) << 8) | | |
488 | /* Write recovery CAS Latency */ | |
489 | (0x1 << 6) | (banks[0].cas_used << 4) | | |
490 | /* RAS/CAS latency */ | |
491 | ((banks[0].trcd - 1) << 0); | |
492 | ||
493 | reg32 |= ((0x3 << 13) | (0x7 << 10) | ((banks[2].trp - 2) << 8) | | |
494 | (0x1 << 6) | (banks[2].cas_used << 4) | | |
495 | ((banks[2].trcd - 1) << 0)) << 16; | |
496 | #else | |
497 | if (100000000 == gd->bus_clk) | |
498 | reg32 = 0x71737173; | |
499 | else | |
500 | reg32 = 0x69736973; | |
501 | #endif | |
502 | pci_write_cfg_long (0, 0, DIMM0_TCR0, reg32); | |
503 | debug ("DIMM0_TCR0 = 0x%08x\n", reg32); | |
504 | ||
505 | /* Write default in DIMM2/3 (not used on A1) */ | |
506 | pci_write_cfg_long (0, 0, DIMM2_TCR0, 0x7d737d73); | |
507 | ||
508 | ||
509 | /* Determine buffered/unbuffered mode for each SIMM. Uses first bank as reference (second, if present, uses the same) */ | |
510 | reg32 = pci_read_cfg_long (0, 0, DRAM_GCR0); | |
511 | reg32 &= 0xFF00FFFF; | |
512 | ||
513 | #if 0 | |
514 | if (banks[0].used && banks[0].registered) | |
515 | reg32 |= 0x1 << 16; | |
516 | ||
517 | if (banks[2].used && banks[2].registered) | |
518 | reg32 |= 0x1 << 18; | |
519 | #else | |
520 | if (banks[0].registered || banks[2].registered) | |
521 | reg32 |= 0x55 << 16; | |
522 | #endif | |
523 | pci_write_cfg_long (0, 0, DRAM_GCR0, reg32); | |
524 | debug ("DRAM_GCR0 = 0x%08x\n", reg32); | |
525 | ||
526 | /* Determine refresh */ | |
527 | refresh_clocks = 0xffffffff; | |
528 | auto_refresh = 1; | |
529 | ||
530 | for (i = 0; i < 4; i++) { | |
531 | if (banks[i].used) { | |
532 | if (banks[i].auto_refresh == 0) | |
533 | auto_refresh = 0; | |
534 | if (banks[i].refresh_time < refresh_clocks) | |
535 | refresh_clocks = banks[i].refresh_time; | |
536 | } | |
537 | } | |
538 | ||
539 | ||
540 | #if 1 | |
541 | /* It seems this is suggested by the ArticiaS data book */ | |
542 | if (100000000 == gd->bus_clk) | |
543 | refresh_clocks = 1561; | |
544 | else | |
545 | refresh_clocks = 2083; | |
546 | #endif | |
547 | ||
548 | ||
549 | debug ("Refresh set to %ld clocks, auto refresh %s\n", | |
550 | refresh_clocks, auto_refresh ? "on" : "off"); | |
551 | ||
552 | pci_write_cfg_long (0, 0, DRAM_REFRESH0, | |
553 | (1 << 16) | (1 << 15) | (auto_refresh << 12) | | |
554 | (refresh_clocks)); | |
555 | debug ("DRAM_REFRESH0 = 0x%08x\n", | |
556 | (1 << 16) | (1 << 15) | (auto_refresh << 12) | | |
557 | (refresh_clocks)); | |
558 | ||
559 | /* pci_write_cfg_long(0, 0, DRAM_REFRESH0, 0x00019400); */ | |
560 | ||
561 | /* Set mode registers */ | |
562 | /* FIXME: For now, set same burst len for all modules. Dunno if that's necessary */ | |
563 | /* Find a common burst len */ | |
564 | burst_support = 0xff; | |
565 | ||
566 | if (banks[0].used) | |
567 | burst_support = banks[0].burst_len; | |
568 | if (banks[1].used) | |
569 | burst_support = banks[1].burst_len; | |
570 | if (banks[2].used) | |
571 | burst_support = banks[2].burst_len; | |
572 | if (banks[3].used) | |
573 | burst_support = banks[3].burst_len; | |
574 | ||
8bde7f77 | 575 | /* |
c7de829c WD |
576 | ** Mode register: |
577 | ** Bits Use | |
578 | ** 0-2 Burst len | |
579 | ** 3 Burst type (0 = sequential, 1 = interleave) | |
580 | ** 4-6 CAS latency | |
581 | ** 7-8 Operation mode (0 = default, all others invalid) | |
582 | ** 9 Write burst | |
583 | ** 10-11 Reserved | |
584 | ** | |
585 | ** Mode register burst table: | |
586 | ** A2 A1 A0 lenght | |
587 | ** 0 0 0 1 | |
588 | ** 0 0 1 2 | |
589 | ** 0 1 0 4 | |
590 | ** 0 1 1 8 | |
591 | ** 1 0 0 invalid | |
592 | ** 1 0 1 invalid | |
593 | ** 1 1 0 invalid | |
594 | ** 1 1 1 page (only valid for non-interleaved) | |
595 | */ | |
596 | ||
597 | burst_len = burst_to_len (burst_support); | |
598 | burst_len = 2; /* FIXME */ | |
599 | ||
600 | if (banks[0].used) { | |
601 | pci_write_cfg_word (0, 0, DRAM_PCR0, | |
602 | 0x8000 | burst_len | (banks[0].cas_used << 4)); | |
603 | debug ("Mode bank 0: 0x%08x\n", | |
604 | 0x8000 | burst_len | (banks[0].cas_used << 4)); | |
605 | } else { | |
606 | /* Seems to be needed to disable the bank */ | |
607 | pci_write_cfg_word (0, 0, DRAM_PCR0, 0x0000 | 0x032); | |
608 | } | |
609 | ||
610 | if (banks[1].used) { | |
611 | pci_write_cfg_word (0, 0, DRAM_PCR0, | |
612 | 0x9000 | burst_len | (banks[1].cas_used << 4)); | |
613 | debug ("Mode bank 1: 0x%08x\n", | |
614 | 0x8000 | burst_len | (banks[1].cas_used << 4)); | |
615 | } else { | |
616 | /* Seems to be needed to disable the bank */ | |
617 | pci_write_cfg_word (0, 0, DRAM_PCR0, 0x1000 | 0x032); | |
618 | } | |
619 | ||
620 | ||
621 | if (banks[2].used) { | |
622 | pci_write_cfg_word (0, 0, DRAM_PCR0, | |
623 | 0xa000 | burst_len | (banks[2].cas_used << 4)); | |
624 | debug ("Mode bank 2: 0x%08x\n", | |
625 | 0x8000 | burst_len | (banks[2].cas_used << 4)); | |
626 | } else { | |
627 | /* Seems to be needed to disable the bank */ | |
628 | pci_write_cfg_word (0, 0, DRAM_PCR0, 0x2000 | 0x032); | |
629 | } | |
630 | ||
631 | ||
632 | if (banks[3].used) { | |
633 | pci_write_cfg_word (0, 0, DRAM_PCR0, | |
634 | 0xb000 | burst_len | (banks[3].cas_used << 4)); | |
635 | debug ("Mode bank 3: 0x%08x\n", | |
636 | 0x8000 | burst_len | (banks[3].cas_used << 4)); | |
637 | } else { | |
638 | /* Seems to be needed to disable the bank */ | |
639 | pci_write_cfg_word (0, 0, DRAM_PCR0, 0x3000 | 0x032); | |
640 | } | |
641 | ||
642 | ||
643 | pci_write_cfg_word (0, 0, 0xba, 0x00); | |
644 | ||
645 | return total_ram; | |
646 | } | |
647 | ||
648 | extern int drv_isa_kbd_init (void); | |
649 | ||
650 | int last_stage_init (void) | |
651 | { | |
652 | drv_isa_kbd_init (); | |
653 | return 0; | |
654 | } | |
655 | ||
656 | int overwrite_console (void) | |
657 | { | |
658 | return (0); | |
659 | } | |
660 | ||
661 | #define in_8 read_byte | |
662 | #define out_8 write_byte | |
663 | ||
664 | static __inline__ unsigned long get_msr (void) | |
665 | { | |
666 | unsigned long msr; | |
667 | ||
668 | asm volatile ("mfmsr %0":"=r" (msr):); | |
669 | ||
670 | return msr; | |
671 | } | |
672 | ||
673 | static __inline__ void set_msr (unsigned long msr) | |
674 | { | |
675 | asm volatile ("mtmsr %0"::"r" (msr)); | |
676 | } | |
677 | ||
678 | int board_pre_init (void) | |
679 | { | |
680 | unsigned char c_value = 0; | |
681 | unsigned long msr; | |
682 | ||
683 | /* Basic init of PS/2 keyboard (needed for some reason)... */ | |
684 | /* Ripped from John's code */ | |
685 | while ((in_8 ((unsigned char *) 0xfe000064) & 0x02) != 0); | |
686 | out_8 ((unsigned char *) 0xfe000064, 0xaa); | |
687 | while ((in_8 ((unsigned char *) 0xfe000064) & 0x01) == 0); | |
688 | c_value = in_8 ((unsigned char *) 0xfe000060); | |
689 | while ((in_8 ((unsigned char *) 0xfe000064) & 0x02) != 0); | |
690 | out_8 ((unsigned char *) 0xfe000064, 0xab); | |
691 | while ((in_8 ((unsigned char *) 0xfe000064) & 0x01) == 0); | |
692 | c_value = in_8 ((unsigned char *) 0xfe000060); | |
693 | while ((in_8 ((unsigned char *) 0xfe000064) & 0x02) != 0); | |
694 | out_8 ((unsigned char *) 0xfe000064, 0xae); | |
695 | /* while ((in_8((unsigned char *)0xfe000064) & 0x01) == 0); */ | |
696 | /* c_value = in_8((unsigned char *)0xfe000060); */ | |
697 | ||
698 | /* Enable FPU */ | |
699 | msr = get_msr (); | |
700 | set_msr (msr | MSR_FP); | |
701 | ||
702 | via_calibrate_bus_freq (); | |
703 | ||
704 | return 0; | |
705 | } |