blob: 2ac6a4d5f44d18d87d2859d9003dc575f1935e83 [file] [log] [blame]
Eric Biedermanb138ac82003-04-22 18:44:01 +00001#define HAVE_STRING_SUPPORT 1
2#define HAVE_CAST_SUPPORT 1
3#define HAVE_STATIC_ARRAY_SUPPORT 1
4#define HAVE_POINTER_SUPPORT 1
Eric Biedermanba8c25a2003-05-08 00:31:34 +00005#define HAVE_CONSTANT_PROPOGATION 0
Eric Biedermanb138ac82003-04-22 18:44:01 +00006#define CALCULATE_DRB_REG 1
7
8void outb(unsigned char value, unsigned short port)
9{
10 __builtin_outb(value, port);
11}
12
13void outw(unsigned short value, unsigned short port)
14{
15 __builtin_outw(value, port);
16}
17
18void outl(unsigned int value, unsigned short port)
19{
20 __builtin_outl(value, port);
21}
22
23unsigned char inb(unsigned short port)
24{
25 return __builtin_inb(port);
26}
27
28unsigned char inw(unsigned short port)
29{
30 return __builtin_inw(port);
31}
32
33unsigned char inl(unsigned short port)
34{
35 return __builtin_inl(port);
36}
37
38static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where)
39{
40 return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3);
41}
42
43static unsigned char pcibios_read_config_byte(
44 unsigned char bus, unsigned devfn, unsigned where)
45{
46 outl(config_cmd(bus, devfn, where), 0xCF8);
47 return inb(0xCFC + (where & 3));
48}
49
50static unsigned short pcibios_read_config_word(
51 unsigned char bus, unsigned devfn, unsigned where)
52{
53 outl(config_cmd(bus, devfn, where), 0xCF8);
54 return inw(0xCFC + (where & 2));
55}
56
57static unsigned int pcibios_read_config_dword(
58 unsigned char bus, unsigned devfn, unsigned where)
59{
60 outl(config_cmd(bus, devfn, where), 0xCF8);
61 return inl(0xCFC);
62}
63
64
65static void pcibios_write_config_byte(
66 unsigned char bus, unsigned devfn, unsigned where, unsigned char value)
67{
68 outl(config_cmd(bus, devfn, where), 0xCF8);
69 outb(value, 0xCFC + (where & 3));
70}
71
72static void pcibios_write_config_word(
73 unsigned char bus, unsigned devfn, unsigned where, unsigned short value)
74{
75 outl(config_cmd(bus, devfn, where), 0xCF8);
76 outw(value, 0xCFC + (where & 2));
77}
78
79static void pcibios_write_config_dword(
80 unsigned char bus, unsigned devfn, unsigned where, unsigned int value)
81{
82 outl(config_cmd(bus, devfn, where), 0xCF8);
83 outl(value, 0xCFC);
84}
85
86int log2(int value)
87{
88 /* __builtin_bsr is a exactly equivalent to the x86 machine
Stefan Reinauer14e22772010-04-27 06:56:47 +000089 * instruction with the exception that it returns -1
Eric Biedermanb138ac82003-04-22 18:44:01 +000090 * when the value presented to it is zero.
91 * Otherwise __builtin_bsr returns the zero based index of
92 * the highest bit set.
93 */
94 return __builtin_bsr(value);
95}
96
97
98/* Base Address */
Stefan Reinauer08670622009-06-30 15:17:49 +000099#ifndef CONFIG_TTYS0_BASE
100#define CONFIG_TTYS0_BASE 0x3f8
Eric Biedermanb138ac82003-04-22 18:44:01 +0000101#endif
102
Stefan Reinauer08670622009-06-30 15:17:49 +0000103#ifndef CONFIG_TTYS0_BAUD
104#define CONFIG_TTYS0_BAUD 115200
Eric Biedermanb138ac82003-04-22 18:44:01 +0000105#endif
106
Stefan Reinauer08670622009-06-30 15:17:49 +0000107#if ((115200%CONFIG_TTYS0_BAUD) != 0)
Eric Biedermanb138ac82003-04-22 18:44:01 +0000108#error Bad ttys0 baud rate
109#endif
110
Stefan Reinauer08670622009-06-30 15:17:49 +0000111#define CONFIG_TTYS0_DIV (115200/CONFIG_TTYS0_BAUD)
Eric Biedermanb138ac82003-04-22 18:44:01 +0000112
113/* Line Control Settings */
Stefan Reinauer08670622009-06-30 15:17:49 +0000114#ifndef CONFIG_TTYS0_LCS
Eric Biedermanb138ac82003-04-22 18:44:01 +0000115/* Set 8bit, 1 stop bit, no parity */
Stefan Reinauer08670622009-06-30 15:17:49 +0000116#define CONFIG_TTYS0_LCS 0x3
Eric Biedermanb138ac82003-04-22 18:44:01 +0000117#endif
118
Stefan Reinauer08670622009-06-30 15:17:49 +0000119#define UART_LCS CONFIG_TTYS0_LCS
Eric Biedermanb138ac82003-04-22 18:44:01 +0000120
121/* Data */
122#define UART_RBR 0x00
123#define UART_TBR 0x00
124
125/* Control */
126#define UART_IER 0x01
127#define UART_IIR 0x02
128#define UART_FCR 0x02
129#define UART_LCR 0x03
130#define UART_MCR 0x04
131#define UART_DLL 0x00
132#define UART_DLM 0x01
133
134/* Status */
135#define UART_LSR 0x05
136#define UART_MSR 0x06
137#define UART_SCR 0x07
138
139int uart_can_tx_byte(void)
140{
Stefan Reinauer08670622009-06-30 15:17:49 +0000141 return inb(CONFIG_TTYS0_BASE + UART_LSR) & 0x20;
Eric Biedermanb138ac82003-04-22 18:44:01 +0000142}
143
144void uart_wait_to_tx_byte(void)
145{
146 while(!uart_can_tx_byte())
147 ;
148}
149
150void uart_wait_until_sent(void)
151{
Stefan Reinauer14e22772010-04-27 06:56:47 +0000152 while(!(inb(CONFIG_TTYS0_BASE + UART_LSR) & 0x40))
Eric Biedermanb138ac82003-04-22 18:44:01 +0000153 ;
154}
155
156void uart_tx_byte(unsigned char data)
157{
158 uart_wait_to_tx_byte();
Stefan Reinauer08670622009-06-30 15:17:49 +0000159 outb(data, CONFIG_TTYS0_BASE + UART_TBR);
Eric Biedermanb138ac82003-04-22 18:44:01 +0000160 /* Make certain the data clears the fifos */
161 uart_wait_until_sent();
162}
163
164void uart_init(void)
165{
166 /* disable interrupts */
Stefan Reinauer08670622009-06-30 15:17:49 +0000167 outb(0x0, CONFIG_TTYS0_BASE + UART_IER);
Eric Biedermanb138ac82003-04-22 18:44:01 +0000168 /* enable fifo's */
Stefan Reinauer08670622009-06-30 15:17:49 +0000169 outb(0x01, CONFIG_TTYS0_BASE + UART_FCR);
Eric Biedermanb138ac82003-04-22 18:44:01 +0000170 /* Set Baud Rate Divisor to 12 ==> 115200 Baud */
Stefan Reinauer08670622009-06-30 15:17:49 +0000171 outb(0x80 | UART_LCS, CONFIG_TTYS0_BASE + UART_LCR);
172 outb(CONFIG_TTYS0_DIV & 0xFF, CONFIG_TTYS0_BASE + UART_DLL);
173 outb((CONFIG_TTYS0_DIV >> 8) & 0xFF, CONFIG_TTYS0_BASE + UART_DLM);
174 outb(UART_LCS, CONFIG_TTYS0_BASE + UART_LCR);
Eric Biedermanb138ac82003-04-22 18:44:01 +0000175}
176
177void __console_tx_char(unsigned char byte)
178{
179 uart_tx_byte(byte);
180}
181void __console_tx_nibble(unsigned nibble)
182{
183 unsigned char digit;
184 digit = nibble + '0';
185 if (digit > '9') {
186 digit += 39;
187 }
188 __console_tx_char(digit);
189}
190void __console_tx_hex8(unsigned char byte)
191{
192 __console_tx_nibble(byte >> 4);
193 __console_tx_nibble(byte & 0x0f);
194}
195
196void __console_tx_hex32(unsigned char value)
197{
198 __console_tx_nibble((value >> 28) & 0x0f);
199 __console_tx_nibble((value >> 24) & 0x0f);
200 __console_tx_nibble((value >> 20) & 0x0f);
201 __console_tx_nibble((value >> 16) & 0x0f);
202 __console_tx_nibble((value >> 12) & 0x0f);
203 __console_tx_nibble((value >> 8) & 0x0f);
204 __console_tx_nibble((value >> 4) & 0x0f);
205 __console_tx_nibble(value & 0x0f);
206}
207
208#if HAVE_STRING_SUPPORT
209void __console_tx_string(char *str)
210{
211 unsigned char ch;
212 while((ch = *str++) != '\0') {
213 __console_tx_char(ch);
214 }
215}
216#else
217void __console_tx_string(char *str)
218{
219}
220#endif
221
222
223void print_emerg_char(unsigned char byte) { __console_tx_char(byte); }
224void print_emerg_hex8(unsigned char value) { __console_tx_hex8(value); }
225void print_emerg_hex32(unsigned int value) { __console_tx_hex32(value); }
226void print_emerg(char *str) { __console_tx_string(str); }
227
228void print_alert_char(unsigned char byte) { __console_tx_char(byte); }
229void print_alert_hex8(unsigned char value) { __console_tx_hex8(value); }
230void print_alert_hex32(unsigned int value) { __console_tx_hex32(value); }
231void print_alert(char *str) { __console_tx_string(str); }
232
233void print_crit_char(unsigned char byte) { __console_tx_char(byte); }
234void print_crit_hex8(unsigned char value) { __console_tx_hex8(value); }
235void print_crit_hex32(unsigned int value) { __console_tx_hex32(value); }
236void print_crit(char *str) { __console_tx_string(str); }
237
238void print_err_char(unsigned char byte) { __console_tx_char(byte); }
239void print_err_hex8(unsigned char value) { __console_tx_hex8(value); }
240void print_err_hex32(unsigned int value) { __console_tx_hex32(value); }
241void print_err(char *str) { __console_tx_string(str); }
242
243void print_warning_char(unsigned char byte) { __console_tx_char(byte); }
244void print_warning_hex8(unsigned char value) { __console_tx_hex8(value); }
245void print_warning_hex32(unsigned int value) { __console_tx_hex32(value); }
246void print_warning(char *str) { __console_tx_string(str); }
247
248void print_notice_char(unsigned char byte) { __console_tx_char(byte); }
249void print_notice_hex8(unsigned char value) { __console_tx_hex8(value); }
250void print_notice_hex32(unsigned int value) { __console_tx_hex32(value); }
251void print_notice(char *str) { __console_tx_string(str); }
252
253void print_info_char(unsigned char byte) { __console_tx_char(byte); }
254void print_info_hex8(unsigned char value) { __console_tx_hex8(value); }
255void print_info_hex32(unsigned int value) { __console_tx_hex32(value); }
256void print_info(char *str) { __console_tx_string(str); }
257
258void print_debug_char(unsigned char byte) { __console_tx_char(byte); }
259void print_debug_hex8(unsigned char value) { __console_tx_hex8(value); }
260void print_debug_hex32(unsigned int value) { __console_tx_hex32(value); }
261void print_debug(char *str) { __console_tx_string(str); }
262
263void print_spew_char(unsigned char byte) { __console_tx_char(byte); }
264void print_spew_hex8(unsigned char value) { __console_tx_hex8(value); }
265void print_spew_hex32(unsigned int value) { __console_tx_hex32(value); }
266void print_spew(char *str) { __console_tx_string(str); }
267
268#define PIIX4_DEVFN 0x90
269#define SMBUS_MEM_DEVICE_START 0x50
270#define SMBUS_MEM_DEVICE_END 0x53
271#define SMBUS_MEM_DEVICE_INC 1
272
273
274#define PM_BUS 0
275#define PM_DEVFN (PIIX4_DEVFN+3)
276
Stefan Reinauer14e22772010-04-27 06:56:47 +0000277#if HAVE_CONSTANT_PROPOGATION
Eric Biedermanb138ac82003-04-22 18:44:01 +0000278#define SMBUS_IO_BASE 0x1000
279#define SMBHSTSTAT 0
280#define SMBHSTCTL 2
281#define SMBHSTCMD 3
282#define SMBHSTADD 4
283#define SMBHSTDAT0 5
284#define SMBHSTDAT1 6
285#define SMBBLKDAT 7
286
287static void smbus_wait_until_ready(void)
288{
289 while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
290 /* nop */
291 }
292}
293
294static void smbus_wait_until_done(void)
295{
296 unsigned char byte;
297 do {
298 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
299 }while((byte &1) == 1);
300 while( (byte & ~1) == 0) {
301 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
302 }
303}
304
305int smbus_read_byte(unsigned device, unsigned address)
306{
307 unsigned char host_status_register;
308 unsigned char byte;
309 int result;
310
311 smbus_wait_until_ready();
312
313 /* setup transaction */
314 /* disable interrupts */
315 outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
316 /* set the device I'm talking too */
317 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD);
318 /* set the command/address... */
319 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
320 /* set up for a byte data read */
321 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
322
323 /* clear any lingering errors, so the transaction will run */
324 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
325
326 /* clear the data byte...*/
327 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
328
329 /* start the command */
330 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
331
332 /* poll for transaction completion */
333 smbus_wait_until_done();
334
335 host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
336
337 /* read results of transaction */
338 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
339
340 result = byte;
341 if (host_status_register != 0x02) {
342 result = -1;
343 }
344 return result;
345}
346
347#else /* !HAVE_CONSTANT_PROPOGATION */
348
349#define SMBUS_IO_HSTSTAT 0x1000
350#define SMBUS_IO_HSTCTL 0x1002
351#define SMBUS_IO_HSTCMD 0x1003
352#define SMBUS_IO_HSTADD 0x1004
353#define SMBUS_IO_HSTDAT0 0x1005
354#define SMBUS_IO_HSTDAT1 0x1006
355#define SMBUS_IO_HSTBLKDAT 0x1007
356
357
358static void smbus_wait_until_ready(void)
359{
360 while((inb(SMBUS_IO_HSTSTAT) & 1) == 1) {
361 /* nop */
362 }
363}
364
365static void smbus_wait_until_done(void)
366{
367 unsigned char byte;
368 do {
369 byte = inb(SMBUS_IO_HSTSTAT);
370 }while((byte &1) == 1);
371 while( (byte & ~1) == 0) {
372 byte = inb(SMBUS_IO_HSTSTAT);
373 }
374}
375
376short smbus_read_byte(unsigned char device, unsigned char address)
377{
378 unsigned char host_status_register;
379 short result;
380
381 smbus_wait_until_ready();
382
383 /* setup transaction */
384 /* disable interrupts */
385 outb(inb(SMBUS_IO_HSTCTL) & (~1), SMBUS_IO_HSTCTL);
386 /* set the device I'm talking too */
387 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_HSTADD);
388 /* set the command/address... */
389 outb(address & 0xFF, SMBUS_IO_HSTCMD);
390 /* set up for a byte data read */
391 outb((inb(SMBUS_IO_HSTCTL) & 0xE3) | 8, SMBUS_IO_HSTCTL);
392
393 /* clear any lingering errors, so the transaction will run */
394 outb(inb(SMBUS_IO_HSTSTAT), SMBUS_IO_HSTSTAT);
395
396 /* clear the data byte...*/
397 outb(0, SMBUS_IO_HSTDAT0);
398
399 /* start the command */
400 outb((inb(SMBUS_IO_HSTCTL) | 0x40), SMBUS_IO_HSTCTL);
401
402 /* poll for transaction completion */
403 smbus_wait_until_done();
404
405 host_status_register = inb(SMBUS_IO_HSTSTAT);
406
407 /* read results of transaction */
408 result = inb(SMBUS_IO_HSTDAT0);
409
410 if (host_status_register != 0x02) {
411 result = -1;
412 }
413 return result;
414}
415#endif /* HAVE_CONSTANT_PROPOGATION */
416
417#define I440GX_BUS 0
418#define I440GX_DEVFN ((0x00 << 3) + 0)
419
420
421static void spd_set_drb(void)
422{
423 /*
424 * Effects: Uses serial presence detect to set the
425 * DRB registers which holds the ending memory address assigned
426 * to each DIMM.
427 */
428 unsigned end_of_memory;
429 unsigned char device;
430 unsigned char drb_reg;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000431
Eric Biedermanb138ac82003-04-22 18:44:01 +0000432 end_of_memory = 0; /* in multiples of 8MiB */
433 device = SMBUS_MEM_DEVICE_START;
434#if !CALCULATE_DRB_REG
435 drb_reg = 0x60;
436#endif
437 while (device <= SMBUS_MEM_DEVICE_END) {
438 unsigned side1_bits, side2_bits;
439 int byte, byte2;
440
441 side1_bits = side2_bits = -1;
442
443 /* rows */
444 byte = smbus_read_byte(device, 3);
445 if (byte >= 0) {
446 side1_bits += byte & 0xf;
447
448 /* columns */
449 byte = smbus_read_byte(device, 4);
450 side1_bits += byte & 0xf;
451
452 /* banks */
453 byte = smbus_read_byte(device, 17);
454 side1_bits += log2(byte);
455
456 /* Get the module data width and convert it to a power of two */
457 /* low byte */
458 byte = smbus_read_byte(device, 6);
459
460 /* high byte */
461 byte2 = smbus_read_byte(device, 7);
462#if HAVE_CAST_SUPPORT
463 side1_bits += log2((((unsigned long)byte2 << 8)| byte));
464#else
465 side1_bits += log2((((byte2 << 8) | byte));
466#endif
Stefan Reinauer14e22772010-04-27 06:56:47 +0000467
Eric Biedermanb138ac82003-04-22 18:44:01 +0000468 /* now I have the ram size in bits as a power of two (less 1) */
469 /* Make it mulitples of 8MB */
470 side1_bits -= 25;
471
472 /* side two */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000473
Eric Biedermanb138ac82003-04-22 18:44:01 +0000474 /* number of physical banks */
475 byte = smbus_read_byte(device, 5);
476 if (byte > 1) {
477 /* for now only handle the symmetrical case */
478 side2_bits = side1_bits;
479 }
480 }
481
482 /* Compute the end address for the DRB register */
483 /* Only process dimms < 2GB (2^8 * 8MB) */
484 if (side1_bits < 8) {
485 end_of_memory += (1 << side1_bits);
486 }
487#if CALCULATE_DRB_REG
488 drb_reg = ((device - SMBUS_MEM_DEVICE_START) << 1) + 0x60;
489#endif
Stefan Reinauer14e22772010-04-27 06:56:47 +0000490
Eric Biedermanb138ac82003-04-22 18:44:01 +0000491#if HAVE_STRING_SUPPORT
492 print_debug("end_of_memory: "); print_debug_hex32(end_of_memory); print_debug("\n");
493#endif
494 pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, drb_reg, end_of_memory);
495
496 if (side2_bits < 8 ) {
497 end_of_memory += (1 << side2_bits);
498 }
499#if HAVE_STRING_SUPPORT
500 print_debug("end_of_memory: "); print_debug_hex32(end_of_memory); print_debug("\n");
501#endif
502 pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, drb_reg +1, end_of_memory);
503
504#if !CALCULATE_DRB_REG
505 drb_reg += 2;
506#endif
507 device += SMBUS_MEM_DEVICE_INC;
508 }
509}