blob: 184e912fffff7161e581a184085e70f24cbd2a9b [file] [log] [blame]
Eric Biederman90089602004-05-28 14:11:54 +00001typedef unsigned char uint8_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002typedef signed char int8_t;
Eric Biederman90089602004-05-28 14:11:54 +00003typedef unsigned short uint16_t;
4typedef signed short int16_t;
5typedef unsigned int uint32_t;
6typedef signed int int32_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +00007
Eric Biederman90089602004-05-28 14:11:54 +00008typedef unsigned char uint_least8_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +00009typedef signed char int_least8_t;
Eric Biederman90089602004-05-28 14:11:54 +000010typedef unsigned short uint_least16_t;
11typedef signed short int_least16_t;
12typedef unsigned int uint_least32_t;
13typedef signed int int_least32_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +000014
Eric Biederman90089602004-05-28 14:11:54 +000015typedef unsigned char uint_fast8_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +000016typedef signed char int_fast8_t;
Eric Biederman90089602004-05-28 14:11:54 +000017typedef unsigned int uint_fast16_t;
18typedef signed int int_fast16_t;
19typedef unsigned int uint_fast32_t;
20typedef signed int int_fast32_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +000021
Eric Biederman90089602004-05-28 14:11:54 +000022typedef int intptr_t;
23typedef unsigned int uintptr_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +000024
Eric Biederman90089602004-05-28 14:11:54 +000025typedef long int intmax_t;
26typedef unsigned long int uintmax_t;
Stefan Reinauer14e22772010-04-27 06:56:47 +000027
Eric Biederman90089602004-05-28 14:11:54 +000028static inline unsigned long apic_read(unsigned long reg)
29{
30 return *((volatile unsigned long *)(0xfee00000 +reg));
31}
32static inline void apic_write(unsigned long reg, unsigned long v)
33{
34 *((volatile unsigned long *)(0xfee00000 +reg)) = v;
35}
36static inline void apic_wait_icr_idle(void)
37{
38 do { } while ( apic_read( 0x300 ) & 0x01000 );
39}
Stefan Reinauer14e22772010-04-27 06:56:47 +000040
Eric Biederman90089602004-05-28 14:11:54 +000041static void outb(unsigned char value, unsigned short port)
42{
43 __builtin_outb(value, port);
44}
45static void outw(unsigned short value, unsigned short port)
46{
47 __builtin_outw(value, port);
48}
49static void outl(unsigned int value, unsigned short port)
50{
51 __builtin_outl(value, port);
52}
53static unsigned char inb(unsigned short port)
54{
55 return __builtin_inb(port);
56}
57static unsigned char inw(unsigned short port)
58{
59 return __builtin_inw(port);
60}
61static unsigned char inl(unsigned short port)
62{
63 return __builtin_inl(port);
64}
65static inline void outsb(uint16_t port, const void *addr, unsigned long count)
66{
67 __asm__ __volatile__ (
Stefan Reinauer14e22772010-04-27 06:56:47 +000068 "cld ; rep ; outsb "
Eric Biederman90089602004-05-28 14:11:54 +000069 : "=S" (addr), "=c" (count)
70 : "d"(port), "0"(addr), "1" (count)
71 );
72}
73static inline void outsw(uint16_t port, const void *addr, unsigned long count)
74{
75 __asm__ __volatile__ (
Stefan Reinauer14e22772010-04-27 06:56:47 +000076 "cld ; rep ; outsw "
Eric Biederman90089602004-05-28 14:11:54 +000077 : "=S" (addr), "=c" (count)
78 : "d"(port), "0"(addr), "1" (count)
79 );
80}
81static inline void outsl(uint16_t port, const void *addr, unsigned long count)
82{
83 __asm__ __volatile__ (
Stefan Reinauer14e22772010-04-27 06:56:47 +000084 "cld ; rep ; outsl "
Eric Biederman90089602004-05-28 14:11:54 +000085 : "=S" (addr), "=c" (count)
86 : "d"(port), "0"(addr), "1" (count)
87 );
88}
89static inline void insb(uint16_t port, void *addr, unsigned long count)
90{
91 __asm__ __volatile__ (
Stefan Reinauer14e22772010-04-27 06:56:47 +000092 "cld ; rep ; insb "
Eric Biederman90089602004-05-28 14:11:54 +000093 : "=D" (addr), "=c" (count)
94 : "d"(port), "0"(addr), "1" (count)
95 );
96}
97static inline void insw(uint16_t port, void *addr, unsigned long count)
98{
99 __asm__ __volatile__ (
Stefan Reinauer14e22772010-04-27 06:56:47 +0000100 "cld ; rep ; insw "
Eric Biederman90089602004-05-28 14:11:54 +0000101 : "=D" (addr), "=c" (count)
102 : "d"(port), "0"(addr), "1" (count)
103 );
104}
105static inline void insl(uint16_t port, void *addr, unsigned long count)
106{
107 __asm__ __volatile__ (
Stefan Reinauer14e22772010-04-27 06:56:47 +0000108 "cld ; rep ; insl "
Eric Biederman90089602004-05-28 14:11:54 +0000109 : "=D" (addr), "=c" (count)
110 : "d"(port), "0"(addr), "1" (count)
111 );
112}
113static inline void pnp_write_config(unsigned char port, unsigned char value, unsigned char reg)
114{
115 outb(reg, port);
116 outb(value, port +1);
117}
118static inline unsigned char pnp_read_config(unsigned char port, unsigned char reg)
119{
120 outb(reg, port);
121 return inb(port +1);
122}
123static inline void pnp_set_logical_device(unsigned char port, int device)
124{
125 pnp_write_config(port, device, 0x07);
126}
127static inline void pnp_set_enable(unsigned char port, int enable)
128{
129 pnp_write_config(port, enable?0x1:0x0, 0x30);
130}
131static inline int pnp_read_enable(unsigned char port)
132{
133 return !!pnp_read_config(port, 0x30);
134}
135static inline void pnp_set_iobase0(unsigned char port, unsigned iobase)
136{
137 pnp_write_config(port, (iobase >> 8) & 0xff, 0x60);
138 pnp_write_config(port, iobase & 0xff, 0x61);
139}
140static inline void pnp_set_iobase1(unsigned char port, unsigned iobase)
141{
142 pnp_write_config(port, (iobase >> 8) & 0xff, 0x62);
143 pnp_write_config(port, iobase & 0xff, 0x63);
144}
145static inline void pnp_set_irq0(unsigned char port, unsigned irq)
146{
147 pnp_write_config(port, irq, 0x70);
148}
149static inline void pnp_set_irq1(unsigned char port, unsigned irq)
150{
151 pnp_write_config(port, irq, 0x72);
152}
153static inline void pnp_set_drq(unsigned char port, unsigned drq)
154{
155 pnp_write_config(port, drq & 0xff, 0x74);
156}
157static void hlt(void)
158{
159 __builtin_hlt();
160}
161typedef __builtin_div_t div_t;
162typedef __builtin_ldiv_t ldiv_t;
163typedef __builtin_udiv_t udiv_t;
164typedef __builtin_uldiv_t uldiv_t;
165static div_t div(int numer, int denom)
166{
167 return __builtin_div(numer, denom);
168}
169static ldiv_t ldiv(long numer, long denom)
170{
171 return __builtin_ldiv(numer, denom);
172}
173static udiv_t udiv(unsigned numer, unsigned denom)
174{
175 return __builtin_udiv(numer, denom);
176}
177static uldiv_t uldiv(unsigned long numer, unsigned long denom)
178{
179 return __builtin_uldiv(numer, denom);
180}
181int log2(int value)
182{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000183
Eric Biederman90089602004-05-28 14:11:54 +0000184 return __builtin_bsr(value);
185}
186typedef unsigned device_t;
187static unsigned char pci_read_config8(device_t dev, unsigned where)
188{
189 unsigned addr;
190 addr = dev | where;
191 outl(0x80000000 | (addr & ~3), 0xCF8);
192 return inb(0xCFC + (addr & 3));
193}
194static unsigned short pci_read_config16(device_t dev, unsigned where)
195{
196 unsigned addr;
197 addr = dev | where;
198 outl(0x80000000 | (addr & ~3), 0xCF8);
199 return inw(0xCFC + (addr & 2));
200}
201static unsigned int pci_read_config32(device_t dev, unsigned where)
202{
203 unsigned addr;
204 addr = dev | where;
205 outl(0x80000000 | (addr & ~3), 0xCF8);
206 return inl(0xCFC);
207}
208static void pci_write_config8(device_t dev, unsigned where, unsigned char value)
209{
210 unsigned addr;
211 addr = dev | where;
212 outl(0x80000000 | (addr & ~3), 0xCF8);
213 outb(value, 0xCFC + (addr & 3));
214}
215static void pci_write_config16(device_t dev, unsigned where, unsigned short value)
216{
217 unsigned addr;
218 addr = dev | where;
219 outl(0x80000000 | (addr & ~3), 0xCF8);
220 outw(value, 0xCFC + (addr & 2));
221}
222static void pci_write_config32(device_t dev, unsigned where, unsigned int value)
223{
224 unsigned addr;
225 addr = dev | where;
226 outl(0x80000000 | (addr & ~3), 0xCF8);
227 outl(value, 0xCFC);
228}
229static device_t pci_locate_device(unsigned pci_id, device_t dev)
230{
231 for(; dev <= ( ((( 255 ) & 0xFF) << 16) | ((( 31 ) & 0x1f) << 11) | ((( 7 ) & 0x7) << 8)) ; dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) {
232 unsigned int id;
233 id = pci_read_config32(dev, 0);
234 if (id == pci_id) {
235 return dev;
236 }
237 }
238 return (0xffffffffU) ;
239}
Stefan Reinauer14e22772010-04-27 06:56:47 +0000240
241
242
243
244
Eric Biederman90089602004-05-28 14:11:54 +0000245static int uart_can_tx_byte(void)
246{
247 return inb(1016 + 0x05 ) & 0x20;
248}
249static void uart_wait_to_tx_byte(void)
250{
251 while(!uart_can_tx_byte())
252 ;
253}
254static void uart_wait_until_sent(void)
255{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000256 while(!(inb(1016 + 0x05 ) & 0x40))
Eric Biederman90089602004-05-28 14:11:54 +0000257 ;
258}
259static void uart_tx_byte(unsigned char data)
260{
261 uart_wait_to_tx_byte();
262 outb(data, 1016 + 0x00 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000263
Eric Biederman90089602004-05-28 14:11:54 +0000264 uart_wait_until_sent();
265}
266static void uart_init(void)
267{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000268
Eric Biederman90089602004-05-28 14:11:54 +0000269 outb(0x0, 1016 + 0x01 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000270
Eric Biederman90089602004-05-28 14:11:54 +0000271 outb(0x01, 1016 + 0x02 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000272
Eric Biederman90089602004-05-28 14:11:54 +0000273 outb(0x80 | 3 , 1016 + 0x03 );
274 outb((115200/ 115200 ) & 0xFF, 1016 + 0x00 );
275 outb(((115200/ 115200 ) >> 8) & 0xFF, 1016 + 0x01 );
276 outb(3 , 1016 + 0x03 );
277}
Stefan Reinauer14e22772010-04-27 06:56:47 +0000278
Eric Biederman90089602004-05-28 14:11:54 +0000279static void __console_tx_byte(unsigned char byte)
280{
281 uart_tx_byte(byte);
282}
283static void __console_tx_nibble(unsigned nibble)
284{
285 unsigned char digit;
286 digit = nibble + '0';
287 if (digit > '9') {
288 digit += 39;
289 }
290 __console_tx_byte(digit);
291}
292static void __console_tx_char(int loglevel, unsigned char byte)
293{
294 if (8 > loglevel) {
295 uart_tx_byte(byte);
296 }
297}
298static void __console_tx_hex8(int loglevel, unsigned char value)
299{
300 if (8 > loglevel) {
301 __console_tx_nibble((value >> 4U) & 0x0fU);
302 __console_tx_nibble(value & 0x0fU);
303 }
304}
305static void __console_tx_hex16(int loglevel, unsigned short value)
306{
307 if (8 > loglevel) {
308 __console_tx_nibble((value >> 12U) & 0x0fU);
309 __console_tx_nibble((value >> 8U) & 0x0fU);
310 __console_tx_nibble((value >> 4U) & 0x0fU);
311 __console_tx_nibble(value & 0x0fU);
312 }
313}
314static void __console_tx_hex32(int loglevel, unsigned int value)
315{
316 if (8 > loglevel) {
317 __console_tx_nibble((value >> 28U) & 0x0fU);
318 __console_tx_nibble((value >> 24U) & 0x0fU);
319 __console_tx_nibble((value >> 20U) & 0x0fU);
320 __console_tx_nibble((value >> 16U) & 0x0fU);
321 __console_tx_nibble((value >> 12U) & 0x0fU);
322 __console_tx_nibble((value >> 8U) & 0x0fU);
323 __console_tx_nibble((value >> 4U) & 0x0fU);
324 __console_tx_nibble(value & 0x0fU);
325 }
326}
327
328static void do_console_tx_string(const char *str) __attribute__((noinline))
329{
330 unsigned char ch;
331 while((ch = *str++) != '\0') {
332 __console_tx_byte(ch);
333 }
334}
335static void __console_tx_string(int loglevel, const char *str)
336{
337 if (8 > loglevel) {
338 do_console_tx_string(str);
339 }
340}
341static void print_emerg_char(unsigned char byte) { __console_tx_char(0 , byte); }
342static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(0 , value); }
343static void print_emerg_hex16(unsigned short value){ __console_tx_hex16(0 , value); }
344static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(0 , value); }
345static void print_emerg(const char *str) { __console_tx_string(0 , str); }
346static void print_alert_char(unsigned char byte) { __console_tx_char(1 , byte); }
347static void print_alert_hex8(unsigned char value) { __console_tx_hex8(1 , value); }
348static void print_alert_hex16(unsigned short value){ __console_tx_hex16(1 , value); }
349static void print_alert_hex32(unsigned int value) { __console_tx_hex32(1 , value); }
350static void print_alert(const char *str) { __console_tx_string(1 , str); }
351static void print_crit_char(unsigned char byte) { __console_tx_char(2 , byte); }
352static void print_crit_hex8(unsigned char value) { __console_tx_hex8(2 , value); }
353static void print_crit_hex16(unsigned short value){ __console_tx_hex16(2 , value); }
354static void print_crit_hex32(unsigned int value) { __console_tx_hex32(2 , value); }
355static void print_crit(const char *str) { __console_tx_string(2 , str); }
356static void print_err_char(unsigned char byte) { __console_tx_char(3 , byte); }
357static void print_err_hex8(unsigned char value) { __console_tx_hex8(3 , value); }
358static void print_err_hex16(unsigned short value){ __console_tx_hex16(3 , value); }
359static void print_err_hex32(unsigned int value) { __console_tx_hex32(3 , value); }
360static void print_err(const char *str) { __console_tx_string(3 , str); }
361static void print_warning_char(unsigned char byte) { __console_tx_char(4 , byte); }
362static void print_warning_hex8(unsigned char value) { __console_tx_hex8(4 , value); }
363static void print_warning_hex16(unsigned short value){ __console_tx_hex16(4 , value); }
364static void print_warning_hex32(unsigned int value) { __console_tx_hex32(4 , value); }
365static void print_warning(const char *str) { __console_tx_string(4 , str); }
366static void print_notice_char(unsigned char byte) { __console_tx_char(5 , byte); }
367static void print_notice_hex8(unsigned char value) { __console_tx_hex8(5 , value); }
368static void print_notice_hex16(unsigned short value){ __console_tx_hex16(5 , value); }
369static void print_notice_hex32(unsigned int value) { __console_tx_hex32(5 , value); }
370static void print_notice(const char *str) { __console_tx_string(5 , str); }
371static void print_info_char(unsigned char byte) { __console_tx_char(6 , byte); }
372static void print_info_hex8(unsigned char value) { __console_tx_hex8(6 , value); }
373static void print_info_hex16(unsigned short value){ __console_tx_hex16(6 , value); }
374static void print_info_hex32(unsigned int value) { __console_tx_hex32(6 , value); }
375static void print_info(const char *str) { __console_tx_string(6 , str); }
376static void print_debug_char(unsigned char byte) { __console_tx_char(7 , byte); }
377static void print_debug_hex8(unsigned char value) { __console_tx_hex8(7 , value); }
378static void print_debug_hex16(unsigned short value){ __console_tx_hex16(7 , value); }
379static void print_debug_hex32(unsigned int value) { __console_tx_hex32(7 , value); }
380static void print_debug(const char *str) { __console_tx_string(7 , str); }
381static void print_spew_char(unsigned char byte) { __console_tx_char(8 , byte); }
382static void print_spew_hex8(unsigned char value) { __console_tx_hex8(8 , value); }
383static void print_spew_hex16(unsigned short value){ __console_tx_hex16(8 , value); }
384static void print_spew_hex32(unsigned int value) { __console_tx_hex32(8 , value); }
385static void print_spew(const char *str) { __console_tx_string(8 , str); }
386static void console_init(void)
387{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000388 static const char console_test[] =
Eric Biederman90089602004-05-28 14:11:54 +0000389 "\r\n\r\nLinuxBIOS-"
Stefan Reinauer14e22772010-04-27 06:56:47 +0000390 "1.1.4"
391 ".0Fallback"
Eric Biederman90089602004-05-28 14:11:54 +0000392 " "
Stefan Reinauer14e22772010-04-27 06:56:47 +0000393 "Thu Oct 9 20:29:48 MDT 2003"
Eric Biederman90089602004-05-28 14:11:54 +0000394 " starting...\r\n";
395 print_info(console_test);
396}
397static void die(const char *str)
398{
399 print_emerg(str);
400 do {
401 hlt();
402 } while(1);
403}
404static void write_phys(unsigned long addr, unsigned long value)
405{
406 asm volatile(
407 "movnti %1, (%0)"
Stefan Reinauer14e22772010-04-27 06:56:47 +0000408 :
409 : "r" (addr), "r" (value)
410 :
Eric Biederman90089602004-05-28 14:11:54 +0000411 );
412}
413static unsigned long read_phys(unsigned long addr)
414{
415 volatile unsigned long *ptr;
416 ptr = (void *)addr;
417 return *ptr;
418}
419static void ram_fill(unsigned long start, unsigned long stop)
420{
421 unsigned long addr;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000422
Eric Biederman90089602004-05-28 14:11:54 +0000423 print_debug("DRAM fill: ");
424 print_debug_hex32(start);
425 print_debug("-");
426 print_debug_hex32(stop);
427 print_debug("\r\n");
428 for(addr = start; addr < stop ; addr += 4) {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000429
Eric Biederman90089602004-05-28 14:11:54 +0000430 if (!(addr & 0xffff)) {
431 print_debug_hex32(addr);
432 print_debug("\r");
433 }
434 write_phys(addr, addr);
435 };
Stefan Reinauer14e22772010-04-27 06:56:47 +0000436
Eric Biederman90089602004-05-28 14:11:54 +0000437 print_debug_hex32(addr);
438 print_debug("\r\nDRAM filled\r\n");
439}
440static void ram_verify(unsigned long start, unsigned long stop)
441{
442 unsigned long addr;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000443
Eric Biederman90089602004-05-28 14:11:54 +0000444 print_debug("DRAM verify: ");
445 print_debug_hex32(start);
446 print_debug_char('-');
447 print_debug_hex32(stop);
448 print_debug("\r\n");
449 for(addr = start; addr < stop ; addr += 4) {
450 unsigned long value;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000451
Eric Biederman90089602004-05-28 14:11:54 +0000452 if (!(addr & 0xffff)) {
453 print_debug_hex32(addr);
454 print_debug("\r");
455 }
456 value = read_phys(addr);
457 if (value != addr) {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000458
Eric Biederman90089602004-05-28 14:11:54 +0000459 print_err_hex32(addr);
460 print_err_char(':');
461 print_err_hex32(value);
462 print_err("\r\n");
463 }
464 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000465
Eric Biederman90089602004-05-28 14:11:54 +0000466 print_debug_hex32(addr);
467 print_debug("\r\nDRAM verified\r\n");
468}
469void ram_check(unsigned long start, unsigned long stop)
470{
471 int result;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000472
Eric Biederman90089602004-05-28 14:11:54 +0000473 print_debug("Testing DRAM : ");
474 print_debug_hex32(start);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000475 print_debug("-");
Eric Biederman90089602004-05-28 14:11:54 +0000476 print_debug_hex32(stop);
477 print_debug("\r\n");
478 ram_fill(start, stop);
479 ram_verify(start, stop);
480 print_debug("Done.\r\n");
481}
482static int enumerate_ht_chain(unsigned link)
483{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000484
Eric Biederman90089602004-05-28 14:11:54 +0000485 unsigned next_unitid, last_unitid;
486 int reset_needed = 0;
487 next_unitid = 1;
488 do {
489 uint32_t id;
490 uint8_t hdr_type, pos;
491 last_unitid = next_unitid;
492 id = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x00 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000493
Eric Biederman90089602004-05-28 14:11:54 +0000494 if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
495 (((id >> 16) & 0xffff) == 0xffff) ||
496 (((id >> 16) & 0xffff) == 0x0000)) {
497 break;
498 }
499 hdr_type = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x0e );
500 pos = 0;
501 hdr_type &= 0x7f;
502 if ((hdr_type == 0 ) ||
503 (hdr_type == 1 )) {
504 pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x34 );
505 }
506 while(pos != 0) {
507 uint8_t cap;
508 cap = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 0 );
509 if (cap == 0x08 ) {
510 uint16_t flags;
511 flags = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 2 );
512 if ((flags >> 13) == 0) {
513 unsigned count;
514 flags &= ~0x1f;
515 flags |= next_unitid & 0x1f;
516 count = (flags >> 5) & 0x1f;
517 pci_write_config16(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 2 , flags);
518 next_unitid += count;
519 break;
520 }
521 }
522 pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 1 );
523 }
524 } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
525 return reset_needed;
526}
527static void enable_smbus(void)
528{
529 device_t dev;
530 dev = pci_locate_device((((( 0x746b ) & 0xFFFF) << 16) | (( 0x1022 ) & 0xFFFF)) , 0);
531 if (dev == (0xffffffffU) ) {
532 die("SMBUS controller not found\r\n");
533 }
534 uint8_t enable;
535 print_debug("SMBus controller enabled\r\n");
536 pci_write_config32(dev, 0x58, 0x0f00 | 1);
537 enable = pci_read_config8(dev, 0x41);
538 pci_write_config8(dev, 0x41, enable | (1 << 7));
Stefan Reinauer14e22772010-04-27 06:56:47 +0000539
Eric Biederman90089602004-05-28 14:11:54 +0000540 outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 );
541}
542static inline void smbus_delay(void)
543{
544 outb(0x80, 0x80);
545}
546static int smbus_wait_until_ready(void)
547{
548 unsigned long loops;
549 loops = (100*1000*10) ;
550 do {
551 unsigned short val;
552 smbus_delay();
553 val = inw(0x0f00 + 0xe0 );
554 if ((val & 0x800) == 0) {
555 break;
556 }
557 if(loops == ((100*1000*10) / 2)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000558 outw(inw(0x0f00 + 0xe0 ),
Eric Biederman90089602004-05-28 14:11:54 +0000559 0x0f00 + 0xe0 );
560 }
561 } while(--loops);
562 return loops?0:-2;
563}
564static int smbus_wait_until_done(void)
565{
566 unsigned long loops;
567 loops = (100*1000*10) ;
568 do {
569 unsigned short val;
570 smbus_delay();
Stefan Reinauer14e22772010-04-27 06:56:47 +0000571
Eric Biederman90089602004-05-28 14:11:54 +0000572 val = inw(0x0f00 + 0xe0 );
573 if (((val & 0x8) == 0) | ((val & 0x437) != 0)) {
574 break;
575 }
576 } while(--loops);
577 return loops?0:-3;
578}
579static int smbus_read_byte(unsigned device, unsigned address)
580{
581 unsigned char global_control_register;
582 unsigned char global_status_register;
583 unsigned char byte;
584 if (smbus_wait_until_ready() < 0) {
585 return -2;
586 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000587
588
589
Eric Biederman90089602004-05-28 14:11:54 +0000590 outw(inw(0x0f00 + 0xe2 ) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), 0x0f00 + 0xe2 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000591
Eric Biederman90089602004-05-28 14:11:54 +0000592 outw(((device & 0x7f) << 1) | 1, 0x0f00 + 0xe4 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000593
Eric Biederman90089602004-05-28 14:11:54 +0000594 outb(address & 0xFF, 0x0f00 + 0xe8 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000595
Eric Biederman90089602004-05-28 14:11:54 +0000596 outw((inw(0x0f00 + 0xe2 ) & ~7) | (0x2), 0x0f00 + 0xe2 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000597
598
Eric Biederman90089602004-05-28 14:11:54 +0000599 outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000600
Eric Biederman90089602004-05-28 14:11:54 +0000601 outw(0, 0x0f00 + 0xe6 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000602
Eric Biederman90089602004-05-28 14:11:54 +0000603 outw((inw(0x0f00 + 0xe2 ) | (1 << 3)), 0x0f00 + 0xe2 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000604
Eric Biederman90089602004-05-28 14:11:54 +0000605 if (smbus_wait_until_done() < 0) {
606 return -3;
607 }
608 global_status_register = inw(0x0f00 + 0xe0 );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000609
Eric Biederman90089602004-05-28 14:11:54 +0000610 byte = inw(0x0f00 + 0xe6 ) & 0xff;
611 if (global_status_register != (1 << 4)) {
612 return -1;
613 }
614 return byte;
615}
616static void smbus_write_byte(unsigned device, unsigned address, unsigned char val)
617{
618 return;
619}
620struct mem_controller {
621 unsigned node_id;
622 device_t f0, f1, f2, f3;
623 uint8_t channel0[4];
624 uint8_t channel1[4];
625};
626typedef __builtin_msr_t msr_t;
627static msr_t rdmsr(unsigned long index)
628{
629 return __builtin_rdmsr(index);
630}
631static void wrmsr(unsigned long index, msr_t msr)
632{
633 __builtin_wrmsr(index, msr.lo, msr.hi);
634}
635struct tsc_struct {
636 unsigned lo;
637 unsigned hi;
638};
639typedef struct tsc_struct tsc_t;
640static tsc_t rdtsc(void)
641{
642 tsc_t res;
643 asm ("rdtsc"
Stefan Reinauer14e22772010-04-27 06:56:47 +0000644 : "=a" (res.lo), "=d"(res.hi)
645 :
646 :
Eric Biederman90089602004-05-28 14:11:54 +0000647 );
648 return res;
649}
650void init_timer(void)
651{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000652
Eric Biederman90089602004-05-28 14:11:54 +0000653 apic_write(0x320 , (1 << 17)|(1<< 16)|(0 << 12)|(0 << 0));
Stefan Reinauer14e22772010-04-27 06:56:47 +0000654
Eric Biederman90089602004-05-28 14:11:54 +0000655 apic_write(0x3E0 , 0xB );
Stefan Reinauer14e22772010-04-27 06:56:47 +0000656
Eric Biederman90089602004-05-28 14:11:54 +0000657 apic_write(0x380 , 0xffffffff);
658}
659void udelay(unsigned usecs)
660{
661 uint32_t start, value, ticks;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000662
Eric Biederman90089602004-05-28 14:11:54 +0000663 ticks = usecs * 200;
664 start = apic_read(0x390 );
665 do {
666 value = apic_read(0x390 );
667 } while((start - value) < ticks);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000668
Eric Biederman90089602004-05-28 14:11:54 +0000669}
670void mdelay(unsigned msecs)
671{
672 unsigned i;
673 for(i = 0; i < msecs; i++) {
674 udelay(1000);
675 }
676}
677void delay(unsigned secs)
678{
679 unsigned i;
680 for(i = 0; i < secs; i++) {
681 mdelay(1000);
682 }
683}
684int boot_cpu(void)
685{
686 volatile unsigned long *local_apic;
687 unsigned long apic_id;
688 int bsp;
689 msr_t msr;
690 msr = rdmsr(0x1b);
691 bsp = !!(msr.lo & (1 << 8));
692 return bsp;
693}
694static int cpu_init_detected(void)
695{
696 unsigned long htic;
697 htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
698 return !!(htic & (1<<6) );
699}
700static int bios_reset_detected(void)
701{
702 unsigned long htic;
703 htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
704 return (htic & (1<<4) ) && !(htic & (1<<5) );
705}
706static int cold_reset_detected(void)
707{
708 unsigned long htic;
709 htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
710 return !(htic & (1<<4) );
711}
712static void distinguish_cpu_resets(unsigned node_id)
713{
714 uint32_t htic;
715 device_t device;
716 device = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 + node_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ;
717 htic = pci_read_config32(device, 0x6c );
718 htic |= (1<<4) | (1<<5) | (1<<6) ;
719 pci_write_config32(device, 0x6c , htic);
720}
721static void set_bios_reset(void)
722{
723 unsigned long htic;
724 htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c );
725 htic &= ~(1<<5) ;
726 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c , htic);
727}
728static void print_debug_pci_dev(unsigned dev)
729{
730 print_debug("PCI: ");
731 print_debug_hex8((dev >> 16) & 0xff);
732 print_debug_char(':');
733 print_debug_hex8((dev >> 11) & 0x1f);
734 print_debug_char('.');
735 print_debug_hex8((dev >> 8) & 7);
736}
737static void print_pci_devices(void)
738{
739 device_t dev;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000740 for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ;
741 dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ;
Eric Biederman90089602004-05-28 14:11:54 +0000742 dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) {
743 uint32_t id;
744 id = pci_read_config32(dev, 0x00 );
745 if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
746 (((id >> 16) & 0xffff) == 0xffff) ||
747 (((id >> 16) & 0xffff) == 0x0000)) {
748 continue;
749 }
750 print_debug_pci_dev(dev);
751 print_debug("\r\n");
752 }
753}
754static void dump_pci_device(unsigned dev)
755{
756 int i;
757 print_debug_pci_dev(dev);
758 print_debug("\r\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +0000759
Eric Biederman90089602004-05-28 14:11:54 +0000760 for(i = 0; i <= 255; i++) {
761 unsigned char val;
762 if ((i & 0x0f) == 0) {
763 print_debug_hex8(i);
764 print_debug_char(':');
765 }
766 val = pci_read_config8(dev, i);
767 print_debug_char(' ');
768 print_debug_hex8(val);
769 if ((i & 0x0f) == 0x0f) {
770 print_debug("\r\n");
771 }
772 }
773}
774static void dump_pci_devices(void)
775{
776 device_t dev;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000777 for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ;
778 dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ;
Eric Biederman90089602004-05-28 14:11:54 +0000779 dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) {
780 uint32_t id;
781 id = pci_read_config32(dev, 0x00 );
782 if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
783 (((id >> 16) & 0xffff) == 0xffff) ||
784 (((id >> 16) & 0xffff) == 0x0000)) {
785 continue;
786 }
787 dump_pci_device(dev);
788 }
789}
790static void dump_spd_registers(const struct mem_controller *ctrl)
791{
792 int i;
793 print_debug("\r\n");
794 for(i = 0; i < 4; i++) {
795 unsigned device;
796 device = ctrl->channel0[i];
797 if (device) {
798 int j;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000799 print_debug("dimm: ");
800 print_debug_hex8(i);
Eric Biederman90089602004-05-28 14:11:54 +0000801 print_debug(".0: ");
802 print_debug_hex8(device);
803 for(j = 0; j < 256; j++) {
804 int status;
805 unsigned char byte;
806 if ((j & 0xf) == 0) {
807 print_debug("\r\n");
808 print_debug_hex8(j);
809 print_debug(": ");
810 }
811 status = smbus_read_byte(device, j);
812 if (status < 0) {
813 print_debug("bad device\r\n");
814 break;
815 }
816 byte = status & 0xff;
817 print_debug_hex8(byte);
818 print_debug_char(' ');
819 }
820 print_debug("\r\n");
821 }
822 device = ctrl->channel1[i];
823 if (device) {
824 int j;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000825 print_debug("dimm: ");
826 print_debug_hex8(i);
Eric Biederman90089602004-05-28 14:11:54 +0000827 print_debug(".1: ");
828 print_debug_hex8(device);
829 for(j = 0; j < 256; j++) {
830 int status;
831 unsigned char byte;
832 if ((j & 0xf) == 0) {
833 print_debug("\r\n");
834 print_debug_hex8(j);
835 print_debug(": ");
836 }
837 status = smbus_read_byte(device, j);
838 if (status < 0) {
839 print_debug("bad device\r\n");
840 break;
841 }
842 byte = status & 0xff;
843 print_debug_hex8(byte);
844 print_debug_char(' ');
845 }
846 print_debug("\r\n");
847 }
848 }
849}
Stefan Reinauer14e22772010-04-27 06:56:47 +0000850
Eric Biederman90089602004-05-28 14:11:54 +0000851static unsigned int cpuid(unsigned int op)
852{
853 unsigned int ret;
854 unsigned dummy2,dummy3,dummy4;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000855 asm volatile (
856 "cpuid"
Eric Biederman90089602004-05-28 14:11:54 +0000857 : "=a" (ret), "=b" (dummy2), "=c" (dummy3), "=d" (dummy4)
858 : "a" (op)
859 );
860 return ret;
861}
862static int is_cpu_rev_a0(void)
863{
864 return (cpuid(1) & 0xffff) == 0x0f10;
865}
866static int is_cpu_pre_c0(void)
867{
868 return (cpuid(1) & 0xffef) < 0x0f48;
869}
870static void memreset_setup(void)
871{
872 if (is_cpu_pre_c0()) {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000873
Eric Biederman90089602004-05-28 14:11:54 +0000874 outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 28);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000875
Eric Biederman90089602004-05-28 14:11:54 +0000876 outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 29);
877 }
878 else {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000879
Eric Biederman90089602004-05-28 14:11:54 +0000880 outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 29);
881 }
882}
883static void memreset(int controllers, const struct mem_controller *ctrl)
884{
885 if (is_cpu_pre_c0()) {
886 udelay(800);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000887
Eric Biederman90089602004-05-28 14:11:54 +0000888 outb((0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 28);
889 udelay(90);
890 }
891}
892static unsigned int generate_row(uint8_t node, uint8_t row, uint8_t maxnodes)
893{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000894
895 uint32_t ret=0x00010101;
Eric Biederman90089602004-05-28 14:11:54 +0000896 static const unsigned int rows_2p[2][2] = {
897 { 0x00050101, 0x00010404 },
898 { 0x00010404, 0x00050101 }
899 };
900 if(maxnodes>2) {
901 print_debug("this mainboard is only designed for 2 cpus\r\n");
902 maxnodes=2;
903 }
904 if (!(node>=maxnodes || row>=maxnodes)) {
905 ret=rows_2p[node][row];
906 }
907 return ret;
908}
909static inline int spd_read_byte(unsigned device, unsigned address)
910{
911 return smbus_read_byte(device, address);
912}
Stefan Reinauer14e22772010-04-27 06:56:47 +0000913
Eric Biederman90089602004-05-28 14:11:54 +0000914static void coherent_ht_mainboard(unsigned cpus)
915{
916}
Stefan Reinauer14e22772010-04-27 06:56:47 +0000917
Eric Biederman90089602004-05-28 14:11:54 +0000918void cpu_ldtstop(unsigned cpus)
919{
920 uint32_t tmp;
921 device_t dev;
922 unsigned cnt;
923 for(cnt=0; cnt<cpus; cnt++) {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000924
Eric Biederman90089602004-05-28 14:11:54 +0000925 pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0x81,0x23);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000926
Eric Biederman90089602004-05-28 14:11:54 +0000927 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd4,0x00000701);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000928
Eric Biederman90089602004-05-28 14:11:54 +0000929 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd8,0x00000000);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000930
Eric Biederman90089602004-05-28 14:11:54 +0000931 tmp=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90);
932 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90, tmp | (1<<24) );
933 }
934}
Stefan Reinauer14e22772010-04-27 06:56:47 +0000935
936
937
938
939
Eric Biederman90089602004-05-28 14:11:54 +0000940static void setup_resource_map(const unsigned int *register_values, int max)
941{
942 int i;
943 print_debug("setting up resource map....\r\n");
944 for(i = 0; i < max; i += 3) {
945 device_t dev;
946 unsigned where;
947 unsigned long reg;
948 dev = register_values[i] & ~0xff;
949 where = register_values[i] & 0xff;
950 reg = pci_read_config32(dev, where);
951 reg &= register_values[i+1];
952 reg |= register_values[i+2];
953 pci_write_config32(dev, where, reg);
954 }
955 print_debug("done.\r\n");
956}
957static void setup_default_resource_map(void)
958{
959 static const unsigned int register_values[] = {
Stefan Reinauer14e22772010-04-27 06:56:47 +0000960
961
Eric Biederman90089602004-05-28 14:11:54 +0000962 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000,
963 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x0000f8f8, 0x00000001,
964 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x0000f8f8, 0x00000002,
965 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000f8f8, 0x00000003,
966 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0x0000f8f8, 0x00000004,
967 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0x0000f8f8, 0x00000005,
968 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0x0000f8f8, 0x00000006,
969 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0x0000f8f8, 0x00000007,
Stefan Reinauer14e22772010-04-27 06:56:47 +0000970
Eric Biederman90089602004-05-28 14:11:54 +0000971 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
972 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
973 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
974 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
975 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
976 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
977 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
978 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +0000979
Eric Biederman90089602004-05-28 14:11:54 +0000980 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x84 ) & 0xFF)) , 0x00000048, 0x00000000,
981 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x8C ) & 0xFF)) , 0x00000048, 0x00000000,
982 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0x00000048, 0x00000000,
983 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x9C ) & 0xFF)) , 0x00000048, 0x00000000,
984 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA4 ) & 0xFF)) , 0x00000048, 0x00000000,
985 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xAC ) & 0xFF)) , 0x00000048, 0x00000000,
986 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB4 ) & 0xFF)) , 0x00000048, 0x00000000,
987 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xBC ) & 0xFF)) , 0x00000048, 0x00ffff00,
Stefan Reinauer14e22772010-04-27 06:56:47 +0000988
Eric Biederman90089602004-05-28 14:11:54 +0000989 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0x000000f0, 0x00000000,
990 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0x000000f0, 0x00000000,
991 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0x000000f0, 0x00000000,
992 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0x000000f0, 0x00000000,
993 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA0 ) & 0xFF)) , 0x000000f0, 0x00000000,
994 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA8 ) & 0xFF)) , 0x000000f0, 0x00000000,
995 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB0 ) & 0xFF)) , 0x000000f0, 0x00000000,
996 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB8 ) & 0xFF)) , 0x000000f0, 0x00fc0003,
Stefan Reinauer14e22772010-04-27 06:56:47 +0000997
Eric Biederman90089602004-05-28 14:11:54 +0000998 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC4 ) & 0xFF)) , 0xFE000FC8, 0x01fff000,
999 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xCC ) & 0xFF)) , 0xFE000FC8, 0x00000000,
1000 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD4 ) & 0xFF)) , 0xFE000FC8, 0x00000000,
1001 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xDC ) & 0xFF)) , 0xFE000FC8, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001002
Eric Biederman90089602004-05-28 14:11:54 +00001003 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC0 ) & 0xFF)) , 0xFE000FCC, 0x00000003,
1004 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC8 ) & 0xFF)) , 0xFE000FCC, 0x00000000,
1005 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD0 ) & 0xFF)) , 0xFE000FCC, 0x00000000,
1006 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD8 ) & 0xFF)) , 0xFE000FCC, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001007
Eric Biederman90089602004-05-28 14:11:54 +00001008 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE0 ) & 0xFF)) , 0x0000FC88, 0xff000003,
1009 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE4 ) & 0xFF)) , 0x0000FC88, 0x00000000,
1010 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE8 ) & 0xFF)) , 0x0000FC88, 0x00000000,
1011 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xEC ) & 0xFF)) , 0x0000FC88, 0x00000000,
1012 };
1013 int max;
1014 max = sizeof(register_values)/sizeof(register_values[0]);
1015 setup_resource_map(register_values, max);
1016}
1017static void sdram_set_registers(const struct mem_controller *ctrl)
1018{
1019 static const unsigned int register_values[] = {
Stefan Reinauer14e22772010-04-27 06:56:47 +00001020
1021
Eric Biederman90089602004-05-28 14:11:54 +00001022 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000,
1023 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x0000f8f8, 0x00000001,
1024 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x0000f8f8, 0x00000002,
1025 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000f8f8, 0x00000003,
1026 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0x0000f8f8, 0x00000004,
1027 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0x0000f8f8, 0x00000005,
1028 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0x0000f8f8, 0x00000006,
1029 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0x0000f8f8, 0x00000007,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001030
Eric Biederman90089602004-05-28 14:11:54 +00001031 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
1032 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
1033 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
1034 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
1035 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
1036 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
1037 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
1038 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001039
Eric Biederman90089602004-05-28 14:11:54 +00001040 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x001f01fe, 0x00000000,
1041 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x001f01fe, 0x00000000,
1042 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x001f01fe, 0x00000000,
1043 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x001f01fe, 0x00000000,
1044 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x001f01fe, 0x00000000,
1045 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x001f01fe, 0x00000000,
1046 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x001f01fe, 0x00000000,
1047 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x001f01fe, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001048
Eric Biederman90089602004-05-28 14:11:54 +00001049 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
1050 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
1051 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
1052 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0xC01f01ff, 0x00000000,
1053 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
1054 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
1055 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0xC01f01ff, 0x00000000,
1056 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0xC01f01ff, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001057
Eric Biederman90089602004-05-28 14:11:54 +00001058 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0xffff8888, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001059
Eric Biederman90089602004-05-28 14:11:54 +00001060 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0xe8088008, 0x02522001 ,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001061
Eric Biederman90089602004-05-28 14:11:54 +00001062 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x8c ) & 0xFF)) , 0xff8fe08e, (0 << 20)|(0 << 8)|(0 << 4)|(0 << 0),
Stefan Reinauer14e22772010-04-27 06:56:47 +00001063
1064 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0xf0000000,
1065 (4 << 25)|(0 << 24)|
1066 (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)|
1067 (1 << 19)|(0 << 18)|(1 << 17)|(0 << 16)|
1068 (2 << 14)|(0 << 13)|(0 << 12)|
1069 (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)|
Eric Biederman90089602004-05-28 14:11:54 +00001070 (0 << 3) |(0 << 1) |(0 << 0),
Stefan Reinauer14e22772010-04-27 06:56:47 +00001071
Eric Biederman90089602004-05-28 14:11:54 +00001072 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xc180f0f0,
1073 (0 << 29)|(0 << 28)|(0 << 27)|(0 << 26)|(0 << 25)|
1074 (0 << 20)|(0 << 19)|(3 << 16)|(0 << 8)|(0 << 0),
Stefan Reinauer14e22772010-04-27 06:56:47 +00001075
Eric Biederman90089602004-05-28 14:11:54 +00001076 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0xfc00ffff, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001077
Eric Biederman90089602004-05-28 14:11:54 +00001078 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0xffe0e0e0, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001079
Eric Biederman90089602004-05-28 14:11:54 +00001080 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000003e, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001081
Eric Biederman90089602004-05-28 14:11:54 +00001082 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0xffffff00, 0x00000000,
Stefan Reinauer14e22772010-04-27 06:56:47 +00001083
Eric Biederman90089602004-05-28 14:11:54 +00001084 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xffff8000, 0x00000f70,
1085 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0xffffff80, 0x00000002,
1086 ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0x0000000f, 0x00068300,
1087 };
1088 int i;
1089 int max;
1090 print_debug("setting up CPU");
1091 print_debug_hex8(ctrl->node_id);
1092 print_debug(" northbridge registers\r\n");
1093 max = sizeof(register_values)/sizeof(register_values[0]);
1094 for(i = 0; i < max; i += 3) {
1095 device_t dev;
1096 unsigned where;
1097 unsigned long reg;
1098 dev = (register_values[i] & ~0xff) - ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) + ctrl->f0;
1099 where = register_values[i] & 0xff;
1100 reg = pci_read_config32(dev, where);
1101 reg &= register_values[i+1];
1102 reg |= register_values[i+2];
1103 pci_write_config32(dev, where, reg);
1104 }
1105 print_debug("done.\r\n");
1106}
1107static int is_dual_channel(const struct mem_controller *ctrl)
1108{
1109 uint32_t dcl;
1110 dcl = pci_read_config32(ctrl->f2, 0x90 );
1111 return dcl & (1<<16) ;
1112}
1113static int is_opteron(const struct mem_controller *ctrl)
1114{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001115
Eric Biederman90089602004-05-28 14:11:54 +00001116 uint32_t nbcap;
1117 nbcap = pci_read_config32(ctrl->f3, 0xE8 );
1118 return !!(nbcap & 0x0001 );
1119}
1120static int is_registered(const struct mem_controller *ctrl)
1121{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001122
Eric Biederman90089602004-05-28 14:11:54 +00001123 uint32_t dcl;
1124 dcl = pci_read_config32(ctrl->f2, 0x90 );
1125 return !(dcl & (1<<18) );
1126}
1127struct dimm_size {
1128 unsigned long side1;
1129 unsigned long side2;
1130};
1131static struct dimm_size spd_get_dimm_size(unsigned device)
1132{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001133
Eric Biederman90089602004-05-28 14:11:54 +00001134 struct dimm_size sz;
1135 int value, low;
1136 sz.side1 = 0;
1137 sz.side2 = 0;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001138
1139 value = spd_read_byte(device, 3);
Eric Biederman90089602004-05-28 14:11:54 +00001140 if (value < 0) goto out;
1141 sz.side1 += value & 0xf;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001142 value = spd_read_byte(device, 4);
Eric Biederman90089602004-05-28 14:11:54 +00001143 if (value < 0) goto out;
1144 sz.side1 += value & 0xf;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001145 value = spd_read_byte(device, 17);
Eric Biederman90089602004-05-28 14:11:54 +00001146 if (value < 0) goto out;
1147 sz.side1 += log2(value & 0xff);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001148
1149 value = spd_read_byte(device, 7);
Eric Biederman90089602004-05-28 14:11:54 +00001150 if (value < 0) goto out;
1151 value &= 0xff;
1152 value <<= 8;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001153
1154 low = spd_read_byte(device, 6);
Eric Biederman90089602004-05-28 14:11:54 +00001155 if (low < 0) goto out;
1156 value = value | (low & 0xff);
1157 sz.side1 += log2(value);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001158
1159 value = spd_read_byte(device, 5);
Eric Biederman90089602004-05-28 14:11:54 +00001160 if (value <= 1) goto out;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001161
Eric Biederman90089602004-05-28 14:11:54 +00001162 sz.side2 = sz.side1;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001163 value = spd_read_byte(device, 3);
Eric Biederman90089602004-05-28 14:11:54 +00001164 if (value < 0) goto out;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001165 if ((value & 0xf0) == 0) goto out;
1166 sz.side2 -= (value & 0x0f);
1167 sz.side2 += ((value >> 4) & 0x0f);
1168 value = spd_read_byte(device, 4);
Eric Biederman90089602004-05-28 14:11:54 +00001169 if (value < 0) goto out;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001170 sz.side2 -= (value & 0x0f);
1171 sz.side2 += ((value >> 4) & 0x0f);
Eric Biederman90089602004-05-28 14:11:54 +00001172 out:
1173 return sz;
1174}
1175static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz, unsigned index)
1176{
1177 uint32_t base0, base1, map;
1178 uint32_t dch;
1179 if (sz.side1 != sz.side2) {
1180 sz.side2 = 0;
1181 }
1182 map = pci_read_config32(ctrl->f2, 0x80 );
1183 map &= ~(0xf << (index + 4));
Stefan Reinauer14e22772010-04-27 06:56:47 +00001184
1185
Eric Biederman90089602004-05-28 14:11:54 +00001186 base0 = base1 = 0;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001187
Eric Biederman90089602004-05-28 14:11:54 +00001188 if (sz.side1 >= (25 +3)) {
1189 map |= (sz.side1 - (25 + 3)) << (index *4);
1190 base0 = (1 << ((sz.side1 - (25 + 3)) + 21)) | 1;
1191 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001192
Eric Biederman90089602004-05-28 14:11:54 +00001193 if (sz.side2 >= (25 + 3)) {
1194 base1 = (1 << ((sz.side2 - (25 + 3)) + 21)) | 1;
1195 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001196
Eric Biederman90089602004-05-28 14:11:54 +00001197 if (is_dual_channel(ctrl)) {
1198 base0 = (base0 << 1) | (base0 & 1);
1199 base1 = (base1 << 1) | (base1 & 1);
1200 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001201
Eric Biederman90089602004-05-28 14:11:54 +00001202 base0 &= ~0x001ffffe;
1203 base1 &= ~0x001ffffe;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001204
Eric Biederman90089602004-05-28 14:11:54 +00001205 pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), base0);
1206 pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), base1);
1207 pci_write_config32(ctrl->f2, 0x80 , map);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001208
1209
Eric Biederman90089602004-05-28 14:11:54 +00001210 if (base0) {
1211 dch = pci_read_config32(ctrl->f2, 0x94 );
1212 dch |= (1 << 26) << index;
1213 pci_write_config32(ctrl->f2, 0x94 , dch);
1214 }
1215}
1216static void spd_set_ram_size(const struct mem_controller *ctrl)
1217{
1218 int i;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001219
Eric Biederman90089602004-05-28 14:11:54 +00001220 for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
1221 struct dimm_size sz;
1222 sz = spd_get_dimm_size(ctrl->channel0[i]);
1223 set_dimm_size(ctrl, sz, i);
1224 }
1225}
1226static void route_dram_accesses(const struct mem_controller *ctrl,
1227 unsigned long base_k, unsigned long limit_k)
1228{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001229
Eric Biederman90089602004-05-28 14:11:54 +00001230 unsigned node_id;
1231 unsigned limit;
1232 unsigned base;
1233 unsigned index;
1234 unsigned limit_reg, base_reg;
1235 device_t device;
1236 node_id = ctrl->node_id;
1237 index = (node_id << 3);
1238 limit = (limit_k << 2);
1239 limit &= 0xffff0000;
1240 limit -= 0x00010000;
1241 limit |= ( 0 << 8) | (node_id << 0);
1242 base = (base_k << 2);
1243 base &= 0xffff0000;
1244 base |= (0 << 8) | (1<<1) | (1<<0);
1245 limit_reg = 0x44 + index;
1246 base_reg = 0x40 + index;
1247 for(device = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ; device <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ; device += ( ((( 0 ) & 0xFF) << 16) | ((( 1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ) {
1248 pci_write_config32(device, limit_reg, limit);
1249 pci_write_config32(device, base_reg, base);
1250 }
1251}
1252static void set_top_mem(unsigned tom_k)
1253{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001254
Eric Biederman90089602004-05-28 14:11:54 +00001255 if (!tom_k) {
1256 set_bios_reset();
1257 print_debug("No memory - reset");
Stefan Reinauer14e22772010-04-27 06:56:47 +00001258
Eric Biederman90089602004-05-28 14:11:54 +00001259 pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0x04 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0x41, 0xf1);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001260
Eric Biederman90089602004-05-28 14:11:54 +00001261 outb(0x0e, 0x0cf9);
1262 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001263
Eric Biederman90089602004-05-28 14:11:54 +00001264 print_debug("RAM: 0x");
1265 print_debug_hex32(tom_k);
1266 print_debug(" KB\r\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +00001267
Eric Biederman90089602004-05-28 14:11:54 +00001268 msr_t msr;
1269 msr.lo = (tom_k & 0x003fffff) << 10;
1270 msr.hi = (tom_k & 0xffc00000) >> 22;
1271 wrmsr(0xC001001D , msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001272
Eric Biederman90089602004-05-28 14:11:54 +00001273 if (tom_k >= 0x003f0000) {
1274 tom_k = 0x3f0000;
1275 }
1276 msr.lo = (tom_k & 0x003fffff) << 10;
1277 msr.hi = (tom_k & 0xffc00000) >> 22;
1278 wrmsr(0xC001001A , msr);
1279}
1280static unsigned long interleave_chip_selects(const struct mem_controller *ctrl)
1281{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001282
1283 static const uint32_t csbase_low[] = {
Eric Biederman90089602004-05-28 14:11:54 +00001284 (1 << (13 - 4)),
1285 (1 << (14 - 4)),
Stefan Reinauer14e22772010-04-27 06:56:47 +00001286 (1 << (14 - 4)),
Eric Biederman90089602004-05-28 14:11:54 +00001287 (1 << (15 - 4)),
1288 (1 << (15 - 4)),
1289 (1 << (16 - 4)),
Stefan Reinauer14e22772010-04-27 06:56:47 +00001290 (1 << (16 - 4)),
Eric Biederman90089602004-05-28 14:11:54 +00001291 };
1292 uint32_t csbase_inc;
1293 int chip_selects, index;
1294 int bits;
1295 int dual_channel;
1296 unsigned common_size;
1297 uint32_t csbase, csmask;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001298
Eric Biederman90089602004-05-28 14:11:54 +00001299 chip_selects = 0;
1300 common_size = 0;
1301 for(index = 0; index < 8; index++) {
1302 unsigned size;
1303 uint32_t value;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001304
Eric Biederman90089602004-05-28 14:11:54 +00001305 value = pci_read_config32(ctrl->f2, 0x40 + (index << 2));
Stefan Reinauer14e22772010-04-27 06:56:47 +00001306
1307
Eric Biederman90089602004-05-28 14:11:54 +00001308 if (!(value & 1)) {
1309 continue;
1310 }
1311 chip_selects++;
1312 size = value >> 21;
1313 if (common_size == 0) {
1314 common_size = size;
1315 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001316
Eric Biederman90089602004-05-28 14:11:54 +00001317 if (common_size != size) {
1318 return 0;
1319 }
1320 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001321
Eric Biederman90089602004-05-28 14:11:54 +00001322 bits = log2(chip_selects);
1323 if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) {
1324 return 0;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001325
Eric Biederman90089602004-05-28 14:11:54 +00001326 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001327
Eric Biederman90089602004-05-28 14:11:54 +00001328 if ((bits == 3) && (common_size == (1 << (32 - 3)))) {
1329 print_debug("8 4GB chip selects cannot be interleaved\r\n");
1330 return 0;
1331 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001332
Eric Biederman90089602004-05-28 14:11:54 +00001333 if (is_dual_channel(ctrl)) {
1334 csbase_inc = csbase_low[log2(common_size) - 1] << 1;
1335 } else {
1336 csbase_inc = csbase_low[log2(common_size)];
1337 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001338
Eric Biederman90089602004-05-28 14:11:54 +00001339 csbase = 0 | 1;
1340 csmask = (((common_size << bits) - 1) << 21);
1341 csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc);
1342 for(index = 0; index < 8; index++) {
1343 uint32_t value;
1344 value = pci_read_config32(ctrl->f2, 0x40 + (index << 2));
Stefan Reinauer14e22772010-04-27 06:56:47 +00001345
Eric Biederman90089602004-05-28 14:11:54 +00001346 if (!(value & 1)) {
1347 continue;
1348 }
1349 pci_write_config32(ctrl->f2, 0x40 + (index << 2), csbase);
1350 pci_write_config32(ctrl->f2, 0x60 + (index << 2), csmask);
1351 csbase += csbase_inc;
1352 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001353
Eric Biederman90089602004-05-28 14:11:54 +00001354 print_debug("Interleaved\r\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +00001355
Eric Biederman90089602004-05-28 14:11:54 +00001356 return common_size << (15 + bits);
1357}
1358static unsigned long order_chip_selects(const struct mem_controller *ctrl)
1359{
1360 unsigned long tom;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001361
1362
Eric Biederman90089602004-05-28 14:11:54 +00001363 tom = 0;
1364 for(;;) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00001365
Eric Biederman90089602004-05-28 14:11:54 +00001366 unsigned index, canidate;
1367 uint32_t csbase, csmask;
1368 unsigned size;
1369 csbase = 0;
1370 canidate = 0;
1371 for(index = 0; index < 8; index++) {
1372 uint32_t value;
1373 value = pci_read_config32(ctrl->f2, 0x40 + (index << 2));
Stefan Reinauer14e22772010-04-27 06:56:47 +00001374
Eric Biederman90089602004-05-28 14:11:54 +00001375 if (!(value & 1)) {
1376 continue;
1377 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001378
1379
Eric Biederman90089602004-05-28 14:11:54 +00001380 if (value <= csbase) {
1381 continue;
1382 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001383
1384
Eric Biederman90089602004-05-28 14:11:54 +00001385 if (tom & (1 << (index + 24))) {
1386 continue;
1387 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001388
Eric Biederman90089602004-05-28 14:11:54 +00001389 csbase = value;
1390 canidate = index;
1391 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001392
Eric Biederman90089602004-05-28 14:11:54 +00001393 if (csbase == 0) {
1394 break;
1395 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001396
Eric Biederman90089602004-05-28 14:11:54 +00001397 size = csbase >> 21;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001398
Eric Biederman90089602004-05-28 14:11:54 +00001399 tom |= (1 << (canidate + 24));
Stefan Reinauer14e22772010-04-27 06:56:47 +00001400
Eric Biederman90089602004-05-28 14:11:54 +00001401 csbase = (tom << 21) | 1;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001402
Eric Biederman90089602004-05-28 14:11:54 +00001403 tom += size;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001404
Eric Biederman90089602004-05-28 14:11:54 +00001405 csmask = ((size -1) << 21);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001406 csmask |= 0xfe00;
1407
Eric Biederman90089602004-05-28 14:11:54 +00001408 pci_write_config32(ctrl->f2, 0x40 + (canidate << 2), csbase);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001409
Eric Biederman90089602004-05-28 14:11:54 +00001410 pci_write_config32(ctrl->f2, 0x60 + (canidate << 2), csmask);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001411
Eric Biederman90089602004-05-28 14:11:54 +00001412 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001413
Eric Biederman90089602004-05-28 14:11:54 +00001414 return (tom & ~0xff000000) << 15;
1415}
1416static void order_dimms(const struct mem_controller *ctrl)
1417{
1418 unsigned long tom, tom_k, base_k;
1419 unsigned node_id;
1420 tom_k = interleave_chip_selects(ctrl);
1421 if (!tom_k) {
1422 tom_k = order_chip_selects(ctrl);
1423 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001424
Eric Biederman90089602004-05-28 14:11:54 +00001425 base_k = 0;
1426 for(node_id = 0; node_id < ctrl->node_id; node_id++) {
1427 uint32_t limit, base;
1428 unsigned index;
1429 index = node_id << 3;
1430 base = pci_read_config32(ctrl->f1, 0x40 + index);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001431
Eric Biederman90089602004-05-28 14:11:54 +00001432 if ((base & 3) == 3) {
1433 limit = pci_read_config32(ctrl->f1, 0x44 + index);
1434 base_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
1435 }
1436 }
1437 tom_k += base_k;
1438 route_dram_accesses(ctrl, base_k, tom_k);
1439 set_top_mem(tom_k);
1440}
1441static void disable_dimm(const struct mem_controller *ctrl, unsigned index)
1442{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001443 print_debug("disabling dimm");
1444 print_debug_hex8(index);
Eric Biederman90089602004-05-28 14:11:54 +00001445 print_debug("\r\n");
1446 pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), 0);
1447 pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), 0);
1448}
1449static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl)
1450{
1451 int i;
1452 int registered;
1453 int unbuffered;
1454 uint32_t dcl;
1455 unbuffered = 0;
1456 registered = 0;
1457 for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
1458 int value;
1459 value = spd_read_byte(ctrl->channel0[i], 21);
1460 if (value < 0) {
1461 disable_dimm(ctrl, i);
1462 continue;
1463 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001464
Eric Biederman90089602004-05-28 14:11:54 +00001465 if (value & (1 << 1)) {
1466 registered = 1;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001467 }
1468
Eric Biederman90089602004-05-28 14:11:54 +00001469 else {
1470 unbuffered = 1;
1471 }
1472 }
1473 if (unbuffered && registered) {
1474 die("Mixed buffered and registered dimms not supported");
1475 }
1476 if (unbuffered && is_opteron(ctrl)) {
1477 die("Unbuffered Dimms not supported on Opteron");
1478 }
1479 dcl = pci_read_config32(ctrl->f2, 0x90 );
1480 dcl &= ~(1<<18) ;
1481 if (unbuffered) {
1482 dcl |= (1<<18) ;
1483 }
1484 pci_write_config32(ctrl->f2, 0x90 , dcl);
1485}
1486static void spd_enable_2channels(const struct mem_controller *ctrl)
1487{
1488 int i;
1489 uint32_t nbcap;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001490
1491
Eric Biederman90089602004-05-28 14:11:54 +00001492 static const unsigned addresses[] = {
Stefan Reinauer14e22772010-04-27 06:56:47 +00001493 2,
1494 3,
1495 4,
1496 5,
1497 6,
1498 7,
1499 9,
1500 11,
1501 13,
1502 17,
1503 18,
1504 21,
1505 23,
1506 26,
1507 27,
1508 28,
1509 29,
1510 30,
1511 41,
1512 42,
Eric Biederman90089602004-05-28 14:11:54 +00001513 };
1514 nbcap = pci_read_config32(ctrl->f3, 0xE8 );
1515 if (!(nbcap & 0x0001 )) {
1516 return;
1517 }
1518 for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
1519 unsigned device0, device1;
1520 int value0, value1;
1521 int j;
1522 device0 = ctrl->channel0[i];
1523 device1 = ctrl->channel1[i];
1524 if (!device1)
1525 return;
1526 for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) {
1527 unsigned addr;
1528 addr = addresses[j];
1529 value0 = spd_read_byte(device0, addr);
1530 if (value0 < 0) {
1531 break;
1532 }
1533 value1 = spd_read_byte(device1, addr);
1534 if (value1 < 0) {
1535 return;
1536 }
1537 if (value0 != value1) {
1538 return;
1539 }
1540 }
1541 }
1542 print_debug("Enabling dual channel memory\r\n");
1543 uint32_t dcl;
1544 dcl = pci_read_config32(ctrl->f2, 0x90 );
1545 dcl &= ~(1<<19) ;
1546 dcl |= (1<<16) ;
1547 pci_write_config32(ctrl->f2, 0x90 , dcl);
1548}
1549struct mem_param {
1550 uint8_t cycle_time;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001551 uint8_t divisor;
Eric Biederman90089602004-05-28 14:11:54 +00001552 uint8_t tRC;
1553 uint8_t tRFC;
1554 uint32_t dch_memclk;
1555 uint16_t dch_tref4k, dch_tref8k;
1556 uint8_t dtl_twr;
1557 char name[9];
1558};
1559static const struct mem_param *get_mem_param(unsigned min_cycle_time)
1560{
1561 static const struct mem_param speed[] = {
1562 {
1563 .name = "100Mhz\r\n",
1564 .cycle_time = 0xa0,
1565 .divisor = (10 <<1),
1566 .tRC = 0x46,
1567 .tRFC = 0x50,
1568 .dch_memclk = 0 << 20 ,
1569 .dch_tref4k = 0x00 ,
1570 .dch_tref8k = 0x08 ,
1571 .dtl_twr = 2,
1572 },
1573 {
1574 .name = "133Mhz\r\n",
1575 .cycle_time = 0x75,
1576 .divisor = (7<<1)+1,
1577 .tRC = 0x41,
1578 .tRFC = 0x4B,
1579 .dch_memclk = 2 << 20 ,
1580 .dch_tref4k = 0x01 ,
1581 .dch_tref8k = 0x09 ,
1582 .dtl_twr = 2,
1583 },
1584 {
1585 .name = "166Mhz\r\n",
1586 .cycle_time = 0x60,
1587 .divisor = (6<<1),
1588 .tRC = 0x3C,
1589 .tRFC = 0x48,
1590 .dch_memclk = 5 << 20 ,
1591 .dch_tref4k = 0x02 ,
1592 .dch_tref8k = 0x0A ,
1593 .dtl_twr = 3,
1594 },
1595 {
1596 .name = "200Mhz\r\n",
1597 .cycle_time = 0x50,
1598 .divisor = (5<<1),
1599 .tRC = 0x37,
1600 .tRFC = 0x46,
1601 .dch_memclk = 7 << 20 ,
1602 .dch_tref4k = 0x03 ,
1603 .dch_tref8k = 0x0B ,
1604 .dtl_twr = 3,
1605 },
1606 {
1607 .cycle_time = 0x00,
1608 },
1609 };
1610 const struct mem_param *param;
1611 for(param = &speed[0]; param->cycle_time ; param++) {
1612 if (min_cycle_time > (param+1)->cycle_time) {
1613 break;
1614 }
1615 }
1616 if (!param->cycle_time) {
1617 die("min_cycle_time to low");
1618 }
1619 print_debug(param->name);
1620 return param;
1621}
1622static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
1623{
Stefan Reinauer14e22772010-04-27 06:56:47 +00001624
Eric Biederman90089602004-05-28 14:11:54 +00001625 const struct mem_param *param;
1626 unsigned min_cycle_time, min_latency;
1627 int i;
1628 uint32_t value;
1629 static const int latency_indicies[] = { 26, 23, 9 };
1630 static const unsigned char min_cycle_times[] = {
Stefan Reinauer14e22772010-04-27 06:56:47 +00001631 [0 ] = 0x50,
1632 [1 ] = 0x60,
1633 [2 ] = 0x75,
1634 [3 ] = 0xa0,
Eric Biederman90089602004-05-28 14:11:54 +00001635 };
1636 value = pci_read_config32(ctrl->f3, 0xE8 );
1637 min_cycle_time = min_cycle_times[(value >> 5 ) & 3 ];
1638 min_latency = 2;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001639
Eric Biederman90089602004-05-28 14:11:54 +00001640 for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
1641 int new_cycle_time, new_latency;
1642 int index;
1643 int latencies;
1644 int latency;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001645
Eric Biederman90089602004-05-28 14:11:54 +00001646 new_cycle_time = 0xa0;
1647 new_latency = 5;
1648 latencies = spd_read_byte(ctrl->channel0[i], 18);
1649 if (latencies <= 0) continue;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001650
Eric Biederman90089602004-05-28 14:11:54 +00001651 latency = log2(latencies) -2;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001652
Eric Biederman90089602004-05-28 14:11:54 +00001653 for(index = 0; index < 3; index++, latency++) {
1654 int value;
1655 if ((latency < 2) || (latency > 4) ||
1656 (!(latencies & (1 << latency)))) {
1657 continue;
1658 }
1659 value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
1660 if (value < 0) {
1661 continue;
1662 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001663
Eric Biederman90089602004-05-28 14:11:54 +00001664 if ((value >= min_cycle_time) && (value < new_cycle_time)) {
1665 new_cycle_time = value;
1666 new_latency = latency;
1667 }
1668 }
1669 if (new_latency > 4){
1670 continue;
1671 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001672
Eric Biederman90089602004-05-28 14:11:54 +00001673 if (new_cycle_time > min_cycle_time) {
1674 min_cycle_time = new_cycle_time;
1675 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001676
Eric Biederman90089602004-05-28 14:11:54 +00001677 if (new_latency > min_latency) {
1678 min_latency = new_latency;
1679 }
1680 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001681
1682
Eric Biederman90089602004-05-28 14:11:54 +00001683 for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
1684 int latencies;
1685 int latency;
1686 int index;
1687 int value;
1688 int dimm;
1689 latencies = spd_read_byte(ctrl->channel0[i], 18);
1690 if (latencies <= 0) {
1691 goto dimm_err;
1692 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001693
Eric Biederman90089602004-05-28 14:11:54 +00001694 latency = log2(latencies) -2;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001695
Eric Biederman90089602004-05-28 14:11:54 +00001696 for(index = 0; index < 3; index++, latency++) {
1697 if (!(latencies & (1 << latency))) {
1698 continue;
1699 }
1700 if (latency == min_latency)
1701 break;
1702 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001703
Eric Biederman90089602004-05-28 14:11:54 +00001704 if ((latency != min_latency) || (index >= 3)) {
1705 goto dimm_err;
1706 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001707
1708
Eric Biederman90089602004-05-28 14:11:54 +00001709 value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001710
1711
Eric Biederman90089602004-05-28 14:11:54 +00001712 if (value <= min_cycle_time) {
1713 continue;
1714 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001715
Eric Biederman90089602004-05-28 14:11:54 +00001716 dimm_err:
1717 disable_dimm(ctrl, i);
1718 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00001719
Eric Biederman90089602004-05-28 14:11:54 +00001720 param = get_mem_param(min_cycle_time);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001721
Eric Biederman90089602004-05-28 14:11:54 +00001722 value = pci_read_config32(ctrl->f2, 0x94 );
1723 value &= ~(0x7 << 20 );
1724 value |= param->dch_memclk;
1725 pci_write_config32(ctrl->f2, 0x94 , value);
1726 static const unsigned latencies[] = { 1 , 5 , 2 };
Stefan Reinauer14e22772010-04-27 06:56:47 +00001727
Eric Biederman90089602004-05-28 14:11:54 +00001728 value = pci_read_config32(ctrl->f2, 0x88 );
1729 value &= ~(0x7 << 0 );
1730 value |= latencies[min_latency - 2] << 0 ;
1731 pci_write_config32(ctrl->f2, 0x88 , value);
Stefan Reinauer14e22772010-04-27 06:56:47 +00001732
Eric Biederman90089602004-05-28 14:11:54 +00001733 return param;
1734}
1735static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1736{
1737 unsigned clocks, old_clocks;
1738 uint32_t dtl;
1739 int value;
1740 value = spd_read_byte(ctrl->channel0[i], 41);
1741 if (value < 0) return -1;
1742 if ((value == 0) || (value == 0xff)) {
1743 value = param->tRC;
1744 }
1745 clocks = ((value << 1) + param->divisor - 1)/param->divisor;
1746 if (clocks < 7 ) {
1747 clocks = 7 ;
1748 }
1749 if (clocks > 22 ) {
1750 return -1;
1751 }
1752 dtl = pci_read_config32(ctrl->f2, 0x88 );
1753 old_clocks = ((dtl >> 4 ) & 0xf ) + 7 ;
1754 if (old_clocks > clocks) {
1755 clocks = old_clocks;
1756 }
1757 dtl &= ~(0xf << 4 );
1758 dtl |= ((clocks - 7 ) << 4 );
1759 pci_write_config32(ctrl->f2, 0x88 , dtl);
1760 return 0;
1761}
1762static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1763{
1764 unsigned clocks, old_clocks;
1765 uint32_t dtl;
1766 int value;
1767 value = spd_read_byte(ctrl->channel0[i], 42);
1768 if (value < 0) return -1;
1769 if ((value == 0) || (value == 0xff)) {
1770 value = param->tRFC;
1771 }
1772 clocks = ((value << 1) + param->divisor - 1)/param->divisor;
1773 if (clocks < 9 ) {
1774 clocks = 9 ;
1775 }
1776 if (clocks > 24 ) {
1777 return -1;
1778 }
1779 dtl = pci_read_config32(ctrl->f2, 0x88 );
1780 old_clocks = ((dtl >> 8 ) & 0xf ) + 9 ;
1781 if (old_clocks > clocks) {
1782 clocks = old_clocks;
1783 }
1784 dtl &= ~(0xf << 8 );
1785 dtl |= ((clocks - 9 ) << 8 );
1786 pci_write_config32(ctrl->f2, 0x88 , dtl);
1787 return 0;
1788}
1789static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1790{
1791 unsigned clocks, old_clocks;
1792 uint32_t dtl;
1793 int value;
1794 value = spd_read_byte(ctrl->channel0[i], 29);
1795 if (value < 0) return -1;
1796 clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
1797 if (clocks < 2 ) {
1798 clocks = 2 ;
1799 }
1800 if (clocks > 6 ) {
1801 return -1;
1802 }
1803 dtl = pci_read_config32(ctrl->f2, 0x88 );
1804 old_clocks = ((dtl >> 12 ) & 0x7 ) + 0 ;
1805 if (old_clocks > clocks) {
1806 clocks = old_clocks;
1807 }
1808 dtl &= ~(0x7 << 12 );
1809 dtl |= ((clocks - 0 ) << 12 );
1810 pci_write_config32(ctrl->f2, 0x88 , dtl);
1811 return 0;
1812}
1813static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1814{
1815 unsigned clocks, old_clocks;
1816 uint32_t dtl;
1817 int value;
1818 value = spd_read_byte(ctrl->channel0[i], 28);
1819 if (value < 0) return -1;
1820 clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
1821 if (clocks < 2 ) {
1822 clocks = 2 ;
1823 }
1824 if (clocks > 4 ) {
1825 return -1;
1826 }
1827 dtl = pci_read_config32(ctrl->f2, 0x88 );
1828 old_clocks = ((dtl >> 16 ) & 0x7 ) + 0 ;
1829 if (old_clocks > clocks) {
1830 clocks = old_clocks;
1831 }
1832 dtl &= ~(0x7 << 16 );
1833 dtl |= ((clocks - 0 ) << 16 );
1834 pci_write_config32(ctrl->f2, 0x88 , dtl);
1835 return 0;
1836}
1837static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1838{
1839 unsigned clocks, old_clocks;
1840 uint32_t dtl;
1841 int value;
1842 value = spd_read_byte(ctrl->channel0[i], 30);
1843 if (value < 0) return -1;
1844 clocks = ((value << 1) + param->divisor - 1)/param->divisor;
1845 if (clocks < 5 ) {
1846 clocks = 5 ;
1847 }
1848 if (clocks > 15 ) {
1849 return -1;
1850 }
1851 dtl = pci_read_config32(ctrl->f2, 0x88 );
1852 old_clocks = ((dtl >> 20 ) & 0xf ) + 0 ;
1853 if (old_clocks > clocks) {
1854 clocks = old_clocks;
1855 }
1856 dtl &= ~(0xf << 20 );
1857 dtl |= ((clocks - 0 ) << 20 );
1858 pci_write_config32(ctrl->f2, 0x88 , dtl);
1859 return 0;
1860}
1861static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1862{
1863 unsigned clocks, old_clocks;
1864 uint32_t dtl;
1865 int value;
1866 value = spd_read_byte(ctrl->channel0[i], 27);
1867 if (value < 0) return -1;
1868 clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1);
1869 if (clocks < 2 ) {
1870 clocks = 2 ;
1871 }
1872 if (clocks > 6 ) {
1873 return -1;
1874 }
1875 dtl = pci_read_config32(ctrl->f2, 0x88 );
1876 old_clocks = ((dtl >> 24 ) & 0x7 ) + 0 ;
1877 if (old_clocks > clocks) {
1878 clocks = old_clocks;
1879 }
1880 dtl &= ~(0x7 << 24 );
1881 dtl |= ((clocks - 0 ) << 24 );
1882 pci_write_config32(ctrl->f2, 0x88 , dtl);
1883 return 0;
1884}
1885static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param)
1886{
1887 uint32_t dtl;
1888 dtl = pci_read_config32(ctrl->f2, 0x88 );
1889 dtl &= ~(0x1 << 28 );
1890 dtl |= (param->dtl_twr - 2 ) << 28 ;
1891 pci_write_config32(ctrl->f2, 0x88 , dtl);
1892}
1893static void init_Tref(const struct mem_controller *ctrl, const struct mem_param *param)
1894{
1895 uint32_t dth;
1896 dth = pci_read_config32(ctrl->f2, 0x8c );
1897 dth &= ~(0x1f << 8 );
1898 dth |= (param->dch_tref4k << 8 );
1899 pci_write_config32(ctrl->f2, 0x8c , dth);
1900}
1901static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1902{
1903 uint32_t dth;
1904 int value;
1905 unsigned tref, old_tref;
1906 value = spd_read_byte(ctrl->channel0[i], 3);
1907 if (value < 0) return -1;
1908 value &= 0xf;
1909 tref = param->dch_tref8k;
1910 if (value == 12) {
1911 tref = param->dch_tref4k;
1912 }
1913 dth = pci_read_config32(ctrl->f2, 0x8c );
1914 old_tref = (dth >> 8 ) & 0x1f ;
1915 if ((value == 12) && (old_tref == param->dch_tref4k)) {
1916 tref = param->dch_tref4k;
1917 } else {
1918 tref = param->dch_tref8k;
1919 }
1920 dth &= ~(0x1f << 8 );
1921 dth |= (tref << 8 );
1922 pci_write_config32(ctrl->f2, 0x8c , dth);
1923 return 0;
1924}
1925static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1926{
1927 uint32_t dcl;
1928 int value;
1929 int dimm;
1930 value = spd_read_byte(ctrl->channel0[i], 13);
1931 if (value < 0) {
1932 return -1;
1933 }
1934 dimm = i;
1935 dimm += 20 ;
1936 dcl = pci_read_config32(ctrl->f2, 0x90 );
1937 dcl &= ~(1 << dimm);
1938 if (value == 4) {
1939 dcl |= (1 << dimm);
1940 }
1941 pci_write_config32(ctrl->f2, 0x90 , dcl);
1942 return 0;
1943}
1944static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
1945{
1946 uint32_t dcl;
1947 int value;
1948 value = spd_read_byte(ctrl->channel0[i], 11);
1949 if (value < 0) {
1950 return -1;
1951 }
1952 if (value != 2) {
1953 dcl = pci_read_config32(ctrl->f2, 0x90 );
1954 dcl &= ~(1<<17) ;
1955 pci_write_config32(ctrl->f2, 0x90 , dcl);
1956 }
1957 return 0;
1958}
1959static int count_dimms(const struct mem_controller *ctrl)
1960{
1961 int dimms;
1962 unsigned index;
1963 dimms = 0;
1964 for(index = 0; index < 8; index += 2) {
1965 uint32_t csbase;
1966 csbase = pci_read_config32(ctrl->f2, (0x40 + index << 2));
1967 if (csbase & 1) {
1968 dimms += 1;
1969 }
1970 }
1971 return dimms;
1972}
1973static void set_Twtr(const struct mem_controller *ctrl, const struct mem_param *param)
1974{
1975 uint32_t dth;
1976 unsigned clocks;
Stefan Reinauer14e22772010-04-27 06:56:47 +00001977 clocks = 1;
Eric Biederman90089602004-05-28 14:11:54 +00001978 dth = pci_read_config32(ctrl->f2, 0x8c );
1979 dth &= ~(0x1 << 0 );
1980 dth |= ((clocks - 1 ) << 0 );
1981 pci_write_config32(ctrl->f2, 0x8c , dth);
1982}
1983static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param *param)
1984{
1985 uint32_t dth, dtl;
1986 unsigned divisor;
1987 unsigned latency;
1988 unsigned clocks;
1989 clocks = 0;
1990 dtl = pci_read_config32(ctrl->f2, 0x88 );
1991 latency = (dtl >> 0 ) & 0x7 ;
1992 divisor = param->divisor;
1993 if (is_opteron(ctrl)) {
1994 if (latency == 1 ) {
1995 if (divisor == ((6 << 0) + 0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00001996
Eric Biederman90089602004-05-28 14:11:54 +00001997 clocks = 3;
1998 }
1999 else if (divisor > ((6 << 0)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002000
Eric Biederman90089602004-05-28 14:11:54 +00002001 clocks = 2;
2002 }
2003 }
2004 else if (latency == 5 ) {
2005 clocks = 3;
2006 }
2007 else if (latency == 2 ) {
2008 if (divisor == ((6 << 0)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002009
Eric Biederman90089602004-05-28 14:11:54 +00002010 clocks = 4;
2011 }
2012 else if (divisor > ((6 << 0)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002013
Eric Biederman90089602004-05-28 14:11:54 +00002014 clocks = 3;
2015 }
2016 }
2017 }
2018 else {
2019 if (is_registered(ctrl)) {
2020 if (latency == 1 ) {
2021 clocks = 2;
2022 }
2023 else if (latency == 5 ) {
2024 clocks = 3;
2025 }
2026 else if (latency == 2 ) {
2027 clocks = 3;
2028 }
2029 }
2030 else {
2031 if (latency == 1 ) {
2032 clocks = 3;
2033 }
2034 else if (latency == 5 ) {
2035 clocks = 4;
2036 }
2037 else if (latency == 2 ) {
2038 clocks = 4;
2039 }
2040 }
2041 }
2042 if ((clocks < 1 ) || (clocks > 6 )) {
2043 die("Unknown Trwt");
2044 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002045
Eric Biederman90089602004-05-28 14:11:54 +00002046 dth = pci_read_config32(ctrl->f2, 0x8c );
2047 dth &= ~(0x7 << 4 );
2048 dth |= ((clocks - 1 ) << 4 );
2049 pci_write_config32(ctrl->f2, 0x8c , dth);
2050 return;
2051}
2052static void set_Twcl(const struct mem_controller *ctrl, const struct mem_param *param)
2053{
Stefan Reinauer14e22772010-04-27 06:56:47 +00002054
Eric Biederman90089602004-05-28 14:11:54 +00002055 uint32_t dth;
2056 unsigned clocks;
2057 if (is_registered(ctrl)) {
2058 clocks = 2;
2059 } else {
2060 clocks = 1;
2061 }
2062 dth = pci_read_config32(ctrl->f2, 0x8c );
2063 dth &= ~(0x7 << 20 );
2064 dth |= ((clocks - 1 ) << 20 );
2065 pci_write_config32(ctrl->f2, 0x8c , dth);
2066}
2067static void set_read_preamble(const struct mem_controller *ctrl, const struct mem_param *param)
2068{
2069 uint32_t dch;
2070 unsigned divisor;
2071 unsigned rdpreamble;
2072 divisor = param->divisor;
2073 dch = pci_read_config32(ctrl->f2, 0x94 );
2074 dch &= ~(0xf << 8 );
2075 rdpreamble = 0;
2076 if (is_registered(ctrl)) {
2077 if (divisor == ((10 << 1)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002078
Eric Biederman90089602004-05-28 14:11:54 +00002079 rdpreamble = ((9 << 1)+ 0);
2080 }
2081 else if (divisor == ((7 << 1)+1)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002082
Eric Biederman90089602004-05-28 14:11:54 +00002083 rdpreamble = ((8 << 1)+0);
2084 }
2085 else if (divisor == ((6 << 1)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002086
Eric Biederman90089602004-05-28 14:11:54 +00002087 rdpreamble = ((7 << 1)+1);
2088 }
2089 else if (divisor == ((5 << 1)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002090
Eric Biederman90089602004-05-28 14:11:54 +00002091 rdpreamble = ((7 << 1)+0);
2092 }
2093 }
2094 else {
2095 int slots;
2096 int i;
2097 slots = 0;
2098 for(i = 0; i < 4; i++) {
2099 if (ctrl->channel0[i]) {
2100 slots += 1;
2101 }
2102 }
2103 if (divisor == ((10 << 1)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002104
Eric Biederman90089602004-05-28 14:11:54 +00002105 if (slots <= 2) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002106
Eric Biederman90089602004-05-28 14:11:54 +00002107 rdpreamble = ((9 << 1)+0);
2108 } else {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002109
Eric Biederman90089602004-05-28 14:11:54 +00002110 rdpreamble = ((14 << 1)+0);
2111 }
2112 }
2113 else if (divisor == ((7 << 1)+1)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002114
Eric Biederman90089602004-05-28 14:11:54 +00002115 if (slots <= 2) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002116
Eric Biederman90089602004-05-28 14:11:54 +00002117 rdpreamble = ((7 << 1)+0);
2118 } else {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002119
Eric Biederman90089602004-05-28 14:11:54 +00002120 rdpreamble = ((11 << 1)+0);
2121 }
2122 }
2123 else if (divisor == ((6 << 1)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002124
Eric Biederman90089602004-05-28 14:11:54 +00002125 if (slots <= 2) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002126
Eric Biederman90089602004-05-28 14:11:54 +00002127 rdpreamble = ((7 << 1)+0);
2128 } else {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002129
Eric Biederman90089602004-05-28 14:11:54 +00002130 rdpreamble = ((9 << 1)+0);
2131 }
2132 }
2133 else if (divisor == ((5 << 1)+0)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002134
Eric Biederman90089602004-05-28 14:11:54 +00002135 if (slots <= 2) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002136
Eric Biederman90089602004-05-28 14:11:54 +00002137 rdpreamble = ((5 << 1)+0);
2138 } else {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002139
Eric Biederman90089602004-05-28 14:11:54 +00002140 rdpreamble = ((7 << 1)+0);
2141 }
2142 }
2143 }
2144 if ((rdpreamble < ((2<<1)+0) ) || (rdpreamble > ((9<<1)+1) )) {
2145 die("Unknown rdpreamble");
2146 }
2147 dch |= (rdpreamble - ((2<<1)+0) ) << 8 ;
2148 pci_write_config32(ctrl->f2, 0x94 , dch);
2149}
2150static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param)
2151{
2152 uint32_t dch;
2153 int i;
2154 unsigned async_lat;
2155 int dimms;
2156 dimms = count_dimms(ctrl);
2157 dch = pci_read_config32(ctrl->f2, 0x94 );
2158 dch &= ~(0xf << 0 );
2159 async_lat = 0;
2160 if (is_registered(ctrl)) {
2161 if (dimms == 4) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002162
Eric Biederman90089602004-05-28 14:11:54 +00002163 async_lat = 9;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002164 }
Eric Biederman90089602004-05-28 14:11:54 +00002165 else {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002166
Eric Biederman90089602004-05-28 14:11:54 +00002167 async_lat = 8;
2168 }
2169 }
2170 else {
2171 if (dimms > 3) {
2172 die("Too many unbuffered dimms");
2173 }
2174 else if (dimms == 3) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002175
Eric Biederman90089602004-05-28 14:11:54 +00002176 async_lat = 7;
2177 }
2178 else {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002179
Eric Biederman90089602004-05-28 14:11:54 +00002180 async_lat = 6;
2181 }
2182 }
2183 dch |= ((async_lat - 0 ) << 0 );
2184 pci_write_config32(ctrl->f2, 0x94 , dch);
2185}
2186static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct mem_param *param)
2187{
2188 uint32_t dch;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002189
Eric Biederman90089602004-05-28 14:11:54 +00002190 dch = pci_read_config32(ctrl->f2, 0x94 );
2191 dch &= ~(0x7 << 16 );
2192 dch |= 3 << 16 ;
2193 dch |= (1 << 19) ;
2194 pci_write_config32(ctrl->f2, 0x94 , dch);
2195}
2196static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param)
2197{
2198 int dimms;
2199 int i;
2200 int rc;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002201
Eric Biederman90089602004-05-28 14:11:54 +00002202 init_Tref(ctrl, param);
2203 for(i = 0; (i < 4) && ctrl->channel0[i]; i++) {
2204 int rc;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002205
Eric Biederman90089602004-05-28 14:11:54 +00002206 if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err;
2207 if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err;
2208 if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err;
2209 if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err;
2210 if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err;
2211 if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002212
Eric Biederman90089602004-05-28 14:11:54 +00002213 if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002214
Eric Biederman90089602004-05-28 14:11:54 +00002215 if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err;
2216 if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err;
2217 continue;
2218 dimm_err:
2219 disable_dimm(ctrl, i);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002220
Eric Biederman90089602004-05-28 14:11:54 +00002221 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002222
Eric Biederman90089602004-05-28 14:11:54 +00002223 set_Twr(ctrl, param);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002224
Eric Biederman90089602004-05-28 14:11:54 +00002225 set_Twtr(ctrl, param);
2226 set_Trwt(ctrl, param);
2227 set_Twcl(ctrl, param);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002228
Eric Biederman90089602004-05-28 14:11:54 +00002229 set_read_preamble(ctrl, param);
2230 set_max_async_latency(ctrl, param);
2231 set_idle_cycle_limit(ctrl, param);
2232}
Stefan Reinauer14e22772010-04-27 06:56:47 +00002233static void sdram_set_spd_registers(const struct mem_controller *ctrl)
Eric Biederman90089602004-05-28 14:11:54 +00002234{
2235 const struct mem_param *param;
2236 spd_enable_2channels(ctrl);
2237 spd_set_ram_size(ctrl);
2238 spd_handle_unbuffered_dimms(ctrl);
2239 param = spd_set_memclk(ctrl);
2240 spd_set_dram_timing(ctrl, param);
2241 order_dimms(ctrl);
2242}
2243static void sdram_enable(int controllers, const struct mem_controller *ctrl)
2244{
2245 int i;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002246
Eric Biederman90089602004-05-28 14:11:54 +00002247 for(i = 0; i < controllers; i++) {
2248 uint32_t dch;
2249 dch = pci_read_config32(ctrl[i].f2, 0x94 );
2250 dch |= (1 << 25) ;
2251 pci_write_config32(ctrl[i].f2, 0x94 , dch);
2252 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002253
Eric Biederman90089602004-05-28 14:11:54 +00002254 memreset(controllers, ctrl);
2255 for(i = 0; i < controllers; i++) {
2256 uint32_t dcl;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002257
Eric Biederman90089602004-05-28 14:11:54 +00002258 dcl = pci_read_config32(ctrl[i].f2, 0x90 );
2259 if (dcl & (1<<17) ) {
2260 uint32_t mnc;
2261 print_debug("ECC enabled\r\n");
2262 mnc = pci_read_config32(ctrl[i].f3, 0x44 );
2263 mnc |= (1 << 22) ;
2264 if (dcl & (1<<16) ) {
2265 mnc |= (1 << 23) ;
2266 }
2267 pci_write_config32(ctrl[i].f3, 0x44 , mnc);
2268 }
2269 dcl |= (1<<3) ;
2270 pci_write_config32(ctrl[i].f2, 0x90 , dcl);
2271 dcl &= ~(1<<3) ;
2272 dcl &= ~(1<<0) ;
2273 dcl &= ~(1<<1) ;
2274 dcl &= ~(1<<2) ;
2275 dcl |= (1<<8) ;
2276 pci_write_config32(ctrl[i].f2, 0x90 , dcl);
2277 }
2278 for(i = 0; i < controllers; i++) {
2279 uint32_t dcl;
2280 print_debug("Initializing memory: ");
2281 int loops = 0;
2282 do {
2283 dcl = pci_read_config32(ctrl[i].f2, 0x90 );
2284 loops += 1;
2285 if ((loops & 1023) == 0) {
2286 print_debug(".");
2287 }
2288 } while(((dcl & (1<<8) ) != 0) && (loops < 300000 ));
2289 if (loops >= 300000 ) {
2290 print_debug(" failed\r\n");
2291 } else {
2292 print_debug(" done\r\n");
2293 }
2294 if (dcl & (1<<17) ) {
2295 print_debug("Clearing memory: ");
2296 if (!is_cpu_pre_c0()) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002297
Eric Biederman90089602004-05-28 14:11:54 +00002298 dcl &= ~((1<<11) | (1<<10) );
2299 pci_write_config32(ctrl[i].f2, 0x90 , dcl);
2300 do {
2301 dcl = pci_read_config32(ctrl[i].f2, 0x90 );
2302 } while(((dcl & (1<<11) ) == 0) || ((dcl & (1<<10) ) == 0) );
2303 }
2304 uint32_t base, last_scrub_k, scrub_k;
2305 uint32_t cnt,zstart,zend;
2306 msr_t msr,msr_201;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002307
Eric Biederman90089602004-05-28 14:11:54 +00002308 pci_write_config32(ctrl[i].f3, 0x58 ,
2309 (0 << 16) | (0 << 8) | (0 << 0));
Stefan Reinauer14e22772010-04-27 06:56:47 +00002310
Eric Biederman90089602004-05-28 14:11:54 +00002311 msr_201 = rdmsr(0x201);
2312 zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8));
2313 zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8));
2314 zstart >>= 16;
2315 zend >>=16;
2316 print_debug("addr ");
2317 print_debug_hex32(zstart);
2318 print_debug("-");
2319 print_debug_hex32(zend);
2320 print_debug("\r\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +00002321
2322
Eric Biederman90089602004-05-28 14:11:54 +00002323 msr = rdmsr(0x2ff );
2324 msr.lo &= ~(1<<10);
2325 wrmsr(0x2ff , msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002326
Eric Biederman90089602004-05-28 14:11:54 +00002327 msr = rdmsr(0xc0010015);
2328 msr.lo |= (1<<17);
2329 wrmsr(0xc0010015,msr);
2330 for(;zstart<zend;zstart+=4) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002331
Eric Biederman90089602004-05-28 14:11:54 +00002332 if(zstart == 0x0fc)
2333 continue;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002334
2335
Eric Biederman90089602004-05-28 14:11:54 +00002336 __asm__ volatile(
2337 "movl %%cr0, %0\n\t"
2338 "orl $0x40000000, %0\n\t"
2339 "movl %0, %%cr0\n\t"
2340 :"=r" (cnt)
2341 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002342
2343
Eric Biederman90089602004-05-28 14:11:54 +00002344 msr.lo = 1 + ((zstart&0x0ff)<<24);
2345 msr.hi = (zstart&0x0ff00)>>8;
2346 wrmsr(0x200,msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002347
Eric Biederman90089602004-05-28 14:11:54 +00002348 msr.hi = 0x000000ff;
2349 msr.lo = 0xfc000800;
2350 wrmsr(0x201,msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002351
Eric Biederman90089602004-05-28 14:11:54 +00002352 __asm__ volatile(
2353 "movl %%cr0, %0\n\t"
2354 "andl $0x9fffffff, %0\n\t"
Stefan Reinauer14e22772010-04-27 06:56:47 +00002355 "movl %0, %%cr0\n\t"
2356 :"=r" (cnt)
Eric Biederman90089602004-05-28 14:11:54 +00002357 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002358
Eric Biederman90089602004-05-28 14:11:54 +00002359 msr.lo = (zstart&0xff) << 24;
2360 msr.hi = (zstart&0xff00) >> 8;
2361 wrmsr(0xc0000100,msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002362 print_debug_char((zstart > 0x0ff)?'+':'-');
2363
2364
Eric Biederman90089602004-05-28 14:11:54 +00002365 __asm__ volatile(
2366 "1: \n\t"
2367 "movl %0, %%fs:(%1)\n\t"
2368 "addl $4,%1\n\t"
2369 "subl $1,%2\n\t"
2370 "jnz 1b\n\t"
2371 :
2372 : "a" (0), "D" (0), "c" (0x01000000)
Stefan Reinauer14e22772010-04-27 06:56:47 +00002373 );
Eric Biederman90089602004-05-28 14:11:54 +00002374 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002375
2376
Eric Biederman90089602004-05-28 14:11:54 +00002377 __asm__ volatile(
2378 "movl %%cr0, %0\n\t"
2379 "orl $0x40000000, %0\n\t"
2380 "movl %0, %%cr0\n\t"
Stefan Reinauer14e22772010-04-27 06:56:47 +00002381 :"=r" (cnt)
Eric Biederman90089602004-05-28 14:11:54 +00002382 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002383
2384
Eric Biederman90089602004-05-28 14:11:54 +00002385 msr = rdmsr(0x2ff );
2386 msr.lo |= 0x0400;
2387 wrmsr(0x2ff , msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002388
Eric Biederman90089602004-05-28 14:11:54 +00002389 msr.lo = 6;
2390 msr.hi = 0;
2391 wrmsr(0x200,msr);
2392 wrmsr(0x201,msr_201);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002393
Eric Biederman90089602004-05-28 14:11:54 +00002394 msr.lo = 0;
2395 msr.hi = 0;
2396 wrmsr(0xc0000100,msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002397
Eric Biederman90089602004-05-28 14:11:54 +00002398 __asm__ volatile(
2399 "movl %%cr0, %0\n\t"
2400 "andl $0x9fffffff, %0\n\t"
Stefan Reinauer14e22772010-04-27 06:56:47 +00002401 "movl %0, %%cr0\n\t"
2402 :"=r" (cnt)
Eric Biederman90089602004-05-28 14:11:54 +00002403 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002404
2405
Eric Biederman90089602004-05-28 14:11:54 +00002406 msr = rdmsr(0xc0010015);
2407 msr.lo &= ~(1<<17);
2408 wrmsr(0xc0010015,msr);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002409
Eric Biederman90089602004-05-28 14:11:54 +00002410 base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3));
2411 base &= 0xffff0000;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002412
Eric Biederman90089602004-05-28 14:11:54 +00002413 pci_write_config32(ctrl[i].f3, 0x5C , base << 8);
2414 pci_write_config32(ctrl[i].f3, 0x60 , base >> 24);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002415
2416 pci_write_config32(ctrl[i].f3, 0x58 ,
Eric Biederman90089602004-05-28 14:11:54 +00002417 (22 << 16) | (22 << 8) | (22 << 0));
2418 print_debug("done\r\n");
2419 }
2420 }
2421}
Stefan Reinauer14e22772010-04-27 06:56:47 +00002422
2423
2424
2425
2426
Eric Biederman90089602004-05-28 14:11:54 +00002427typedef uint8_t u8;
2428typedef uint32_t u32;
2429typedef int8_t bool;
2430static void disable_probes(void)
2431{
Stefan Reinauer14e22772010-04-27 06:56:47 +00002432
2433
Eric Biederman90089602004-05-28 14:11:54 +00002434 u32 val;
2435 print_debug("Disabling read/write/fill probes for UP... ");
2436 val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68);
2437 val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0);
2438 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68, val);
2439 print_debug("done.\r\n");
2440}
Stefan Reinauer14e22772010-04-27 06:56:47 +00002441
2442static void wait_ap_stop(u8 node)
Eric Biederman90089602004-05-28 14:11:54 +00002443{
2444 unsigned long reg;
2445 unsigned long i;
2446 for(i=0;i< 1000 ;i++) {
2447 unsigned long regx;
2448 regx = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c);
2449 if((regx & (1<<4))==1) break;
2450 }
2451 reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002452 reg &= ~(1<<4);
Eric Biederman90089602004-05-28 14:11:54 +00002453 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, reg);
2454}
2455static void notify_bsp_ap_is_stopped(void)
2456{
2457 unsigned long reg;
2458 unsigned long apic_id;
2459 apic_id = *((volatile unsigned long *)(0xfee00000 + 0x020 ));
2460 apic_id >>= 24;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002461
Eric Biederman90089602004-05-28 14:11:54 +00002462 if(apic_id != 0) {
Stefan Reinauer14e22772010-04-27 06:56:47 +00002463
Eric Biederman90089602004-05-28 14:11:54 +00002464 reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C);
2465 reg |= 1<<4;
2466 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C, reg);
2467 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002468
Eric Biederman90089602004-05-28 14:11:54 +00002469}
Stefan Reinauer14e22772010-04-27 06:56:47 +00002470
Eric Biederman90089602004-05-28 14:11:54 +00002471static void enable_routing(u8 node)
2472{
2473 u32 val;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002474
2475
Eric Biederman90089602004-05-28 14:11:54 +00002476 print_debug("Enabling routing table for node ");
2477 print_debug_hex32(node);
2478 val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c);
2479 val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
2480 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, val);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002481
Eric Biederman90089602004-05-28 14:11:54 +00002482 if(node!=0) {
2483 wait_ap_stop(node);
2484 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002485
Eric Biederman90089602004-05-28 14:11:54 +00002486 print_debug(" done.\r\n");
2487}
2488static void rename_temp_node(u8 node)
2489{
2490 uint32_t val;
2491 print_debug("Renaming current temp node to ");
2492 print_debug_hex32(node);
2493 val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002494 val &= (~7);
2495 val |= node;
Eric Biederman90089602004-05-28 14:11:54 +00002496 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60, val);
2497 print_debug(" done.\r\n");
2498}
2499static bool check_connection(u8 src, u8 dest, u8 link)
2500{
Stefan Reinauer14e22772010-04-27 06:56:47 +00002501
Eric Biederman90089602004-05-28 14:11:54 +00002502 u32 val;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002503
2504
Eric Biederman90089602004-05-28 14:11:54 +00002505 val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ src ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x98+link);
2506 if ( (val&0x17) != 0x03)
2507 return 0;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002508
Eric Biederman90089602004-05-28 14:11:54 +00002509 val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ dest ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0);
2510 if(val != 0x11001022)
2511 return 0;
2512 return 1;
2513}
2514static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2)
2515{
2516 static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
2517 static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
2518 uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask;
2519 uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2;
2520 uint8_t freq;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002521
2522
Eric Biederman90089602004-05-28 14:11:54 +00002523 freq_cap1 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x0a );
2524 freq_cap2 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x0a );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002525
2526
Eric Biederman90089602004-05-28 14:11:54 +00002527 freq = log2(freq_cap1 & freq_cap2 & 0xff);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002528
Eric Biederman90089602004-05-28 14:11:54 +00002529 pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x09 , freq);
2530 pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x09 , freq);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002531
Eric Biederman90089602004-05-28 14:11:54 +00002532 width_cap1 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 );
2533 width_cap2 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002534
Eric Biederman90089602004-05-28 14:11:54 +00002535 ln_width1 = link_width_to_pow2[width_cap1 & 7];
2536 ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7];
2537 if (ln_width1 > ln_width2) {
2538 ln_width1 = ln_width2;
2539 }
2540 width = pow2_to_link_width[ln_width1];
Stefan Reinauer14e22772010-04-27 06:56:47 +00002541
Eric Biederman90089602004-05-28 14:11:54 +00002542 ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7];
2543 ln_width2 = link_width_to_pow2[width_cap2 & 7];
2544 if (ln_width1 > ln_width2) {
2545 ln_width1 = ln_width2;
2546 }
2547 width |= pow2_to_link_width[ln_width1] << 4;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002548
2549
Eric Biederman90089602004-05-28 14:11:54 +00002550 pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 + 1, width);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002551
Eric Biederman90089602004-05-28 14:11:54 +00002552 width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
2553 pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 + 1, width);
2554}
2555static void fill_row(u8 node, u8 row, u32 value)
2556{
2557 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x40+(row<<2), value);
2558}
2559static void setup_row(u8 source, u8 dest, u8 cpus)
2560{
2561 fill_row(source,dest,generate_row(source,dest,cpus));
2562}
2563static void setup_temp_row(u8 source, u8 dest, u8 cpus)
2564{
2565 fill_row(source,7,((generate_row( source,dest,cpus )&(~0x0f0000))|0x010000) );
2566}
2567static void setup_node(u8 node, u8 cpus)
2568{
2569 u8 row;
2570 for(row=0; row<cpus; row++)
2571 setup_row(node, row, cpus);
2572}
2573static void setup_remote_row(u8 source, u8 dest, u8 cpus)
2574{
2575 fill_row(7, dest, generate_row(source, dest, cpus));
2576}
2577static void setup_remote_node(u8 node, u8 cpus)
2578{
Stefan Reinauer14e22772010-04-27 06:56:47 +00002579 static const uint8_t pci_reg[] = {
2580 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c,
Eric Biederman90089602004-05-28 14:11:54 +00002581 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78,
2582 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc,
2583 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8,
2584 0xc4, 0xcc, 0xd4, 0xdc,
2585 0xc0, 0xc8, 0xd0, 0xd8,
2586 0xe0, 0xe4, 0xe8, 0xec,
2587 };
2588 uint8_t row;
2589 int i;
2590 print_debug("setup_remote_node\r\n");
2591 for(row=0; row<cpus; row++)
2592 setup_remote_row(node, row, cpus);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002593
Eric Biederman90089602004-05-28 14:11:54 +00002594 for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) {
2595 uint32_t value;
2596 uint8_t reg;
2597 reg = pci_reg[i];
2598 value = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg);
2599 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg, value);
2600 }
2601 print_debug("setup_remote_done\r\n");
2602}
2603static u8 setup_uniprocessor(void)
2604{
2605 print_debug("Enabling UP settings\r\n");
2606 disable_probes();
2607 return 1;
2608}
2609static u8 setup_smp(void)
2610{
2611 u8 cpus=2;
2612 print_debug("Enabling SMP settings\r\n");
2613 setup_row(0,0,cpus);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002614
Eric Biederman90089602004-05-28 14:11:54 +00002615 setup_temp_row(0,1,cpus);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002616
Eric Biederman90089602004-05-28 14:11:54 +00002617 if (!check_connection(0, 7, 0x20 )) {
2618 print_debug("No connection to Node 1.\r\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +00002619 fill_row( 0 ,7,0x00010101 ) ;
2620 setup_uniprocessor();
Eric Biederman90089602004-05-28 14:11:54 +00002621 return 1;
2622 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002623
Eric Biederman90089602004-05-28 14:11:54 +00002624 optimize_connection(0, 0x20 , 7, 0x20 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002625 setup_node(0, cpus);
2626 setup_remote_node(1, cpus);
2627 rename_temp_node(1);
2628 enable_routing(1);
2629
2630 fill_row( 0 ,7,0x00010101 ) ;
2631
Eric Biederman90089602004-05-28 14:11:54 +00002632 print_debug_hex32(cpus);
2633 print_debug(" nodes initialized.\r\n");
2634 return cpus;
2635}
2636static unsigned detect_mp_capabilities(unsigned cpus)
2637{
2638 unsigned node, row, mask;
2639 bool mp_cap= (-1) ;
2640 print_debug("detect_mp_capabilities: ");
2641 print_debug_hex32(cpus);
2642 print_debug("\r\n");
2643 if (cpus>2)
Stefan Reinauer14e22772010-04-27 06:56:47 +00002644 mask=0x06;
Eric Biederman90089602004-05-28 14:11:54 +00002645 else
Stefan Reinauer14e22772010-04-27 06:56:47 +00002646 mask=0x02;
Eric Biederman90089602004-05-28 14:11:54 +00002647 for (node=0; node<cpus; node++) {
2648 if ((pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0xe8) & mask)!=mask)
2649 mp_cap= (0) ;
2650 }
2651 if (mp_cap)
2652 return cpus;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002653
Eric Biederman90089602004-05-28 14:11:54 +00002654 print_debug("One of the CPUs is not MP capable. Going back to UP\r\n");
2655 for (node=cpus; node>0; node--)
2656 for (row=cpus; row>0; row--)
2657 fill_row(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node-1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , row-1, 0x00010101 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002658
Eric Biederman90089602004-05-28 14:11:54 +00002659 return setup_uniprocessor();
2660}
2661static void coherent_ht_finalize(unsigned cpus)
2662{
2663 int node;
2664 bool rev_a0;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002665
2666
Eric Biederman90089602004-05-28 14:11:54 +00002667 print_debug("coherent_ht_finalize\r\n");
2668 rev_a0= is_cpu_rev_a0();
2669 for (node=0; node<cpus; node++) {
2670 u32 val;
2671 val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60);
2672 val &= (~0x000F0070);
2673 val |= ((cpus-1)<<16)|((cpus-1)<<4);
2674 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x60,val);
2675 val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68);
2676 val |= 0x00008000;
2677 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x68,val);
2678 if (rev_a0) {
2679 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x94,0);
2680 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xb4,0);
2681 pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xd4,0);
2682 }
2683 }
2684 print_debug("done\r\n");
2685}
2686static int setup_coherent_ht_domain(void)
2687{
2688 unsigned cpus;
2689 int reset_needed = 0;
2690 enable_routing(0) ;
2691 cpus=setup_smp();
2692 cpus=detect_mp_capabilities(cpus);
2693 coherent_ht_finalize(cpus);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002694
Eric Biederman90089602004-05-28 14:11:54 +00002695 coherent_ht_mainboard(cpus);
2696 return reset_needed;
2697}
2698void sdram_no_memory(void)
2699{
2700 print_err("No memory!!\r\n");
Stefan Reinauer14e22772010-04-27 06:56:47 +00002701 while(1) {
2702 hlt();
Eric Biederman90089602004-05-28 14:11:54 +00002703 }
2704}
Stefan Reinauer14e22772010-04-27 06:56:47 +00002705
Eric Biederman90089602004-05-28 14:11:54 +00002706void sdram_initialize(int controllers, const struct mem_controller *ctrl)
2707{
2708 int i;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002709
Eric Biederman90089602004-05-28 14:11:54 +00002710 for(i = 0; i < controllers; i++) {
2711 print_debug("Ram1.");
2712 print_debug_hex8(i);
2713 print_debug("\r\n");
2714 sdram_set_registers(ctrl + i);
2715 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002716
Eric Biederman90089602004-05-28 14:11:54 +00002717 for(i = 0; i < controllers; i++) {
2718 print_debug("Ram2.");
2719 print_debug_hex8(i);
2720 print_debug("\r\n");
2721 sdram_set_spd_registers(ctrl + i);
2722 }
Stefan Reinauer14e22772010-04-27 06:56:47 +00002723
Eric Biederman90089602004-05-28 14:11:54 +00002724 print_debug("Ram3\r\n");
2725 sdram_enable(controllers, ctrl);
2726 print_debug("Ram4\r\n");
2727}
2728static void enable_lapic(void)
2729{
2730 msr_t msr;
2731 msr = rdmsr(0x1b);
2732 msr.hi &= 0xffffff00;
2733 msr.lo &= 0x000007ff;
2734 msr.lo |= 0xfee00000 | (1 << 11);
2735 wrmsr(0x1b, msr);
2736}
2737static void stop_this_cpu(void)
2738{
2739 unsigned apicid;
2740 apicid = apic_read(0x020 ) >> 24;
Stefan Reinauer14e22772010-04-27 06:56:47 +00002741
Eric Biederman90089602004-05-28 14:11:54 +00002742 apic_write(0x310 , (( apicid )<<24) );
2743 apic_write(0x300 , 0x08000 | 0x04000 | 0x00500 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002744
Eric Biederman90089602004-05-28 14:11:54 +00002745 apic_wait_icr_idle();
Stefan Reinauer14e22772010-04-27 06:56:47 +00002746
Eric Biederman90089602004-05-28 14:11:54 +00002747 apic_write(0x310 , (( apicid )<<24) );
2748 apic_write(0x300 , 0x08000 | 0x00500 );
Stefan Reinauer14e22772010-04-27 06:56:47 +00002749
Eric Biederman90089602004-05-28 14:11:54 +00002750 apic_wait_icr_idle();
Stefan Reinauer14e22772010-04-27 06:56:47 +00002751
Eric Biederman90089602004-05-28 14:11:54 +00002752 for(;;) {
2753 hlt();
2754 }
2755}
2756static void pc87360_enable_serial(void)
2757{
2758 pnp_set_logical_device(0x2e , 0x03 );
2759 pnp_set_enable(0x2e , 1);
2760 pnp_set_iobase0(0x2e , 0x3f8);
2761}
2762static void main(void)
2763{
Stefan Reinauer14e22772010-04-27 06:56:47 +00002764
Eric Biederman90089602004-05-28 14:11:54 +00002765 static const struct mem_controller cpu[] = {
2766 {
2767 .node_id = 0,
2768 .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,
2769 .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ,
2770 .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,
2771 .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,
2772 .channel0 = { (0xa<<3)|0, (0xa<<3)|2, 0, 0 },
2773 .channel1 = { (0xa<<3)|1, (0xa<<3)|3, 0, 0 },
2774 },
2775 {
2776 .node_id = 1,
2777 .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,
2778 .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ,
2779 .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,
2780 .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,
2781 .channel0 = { (0xa<<3)|4, (0xa<<3)|6, 0, 0 },
2782 .channel1 = { (0xa<<3)|5, (0xa<<3)|7, 0, 0 },
2783 },
2784 };
2785 if (cpu_init_detected()) {
2786 asm("jmp __cpu_reset");
2787 }
2788 enable_lapic();
2789 init_timer();
2790 if (!boot_cpu()) {
2791 stop_this_cpu();
2792 }
2793 pc87360_enable_serial();
2794 uart_init();
2795 console_init();
2796 setup_default_resource_map();
2797 setup_coherent_ht_domain();
2798 enumerate_ht_chain(0);
2799 distinguish_cpu_resets(0);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002800
Eric Biederman90089602004-05-28 14:11:54 +00002801 enable_smbus();
2802 memreset_setup();
2803 sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu);
Stefan Reinauer14e22772010-04-27 06:56:47 +00002804
Eric Biederman90089602004-05-28 14:11:54 +00002805}