Eric Biederman | b138ac8 | 2003-04-22 18:44:01 +0000 | [diff] [blame] | 1 | #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 Biederman | ba8c25a | 2003-05-08 00:31:34 +0000 | [diff] [blame^] | 5 | #define HAVE_CONSTANT_PROPOGATION 0 |
Eric Biederman | b138ac8 | 2003-04-22 18:44:01 +0000 | [diff] [blame] | 6 | #define CALCULATE_DRB_REG 1 |
| 7 | |
| 8 | void outb(unsigned char value, unsigned short port) |
| 9 | { |
| 10 | __builtin_outb(value, port); |
| 11 | } |
| 12 | |
| 13 | void outw(unsigned short value, unsigned short port) |
| 14 | { |
| 15 | __builtin_outw(value, port); |
| 16 | } |
| 17 | |
| 18 | void outl(unsigned int value, unsigned short port) |
| 19 | { |
| 20 | __builtin_outl(value, port); |
| 21 | } |
| 22 | |
| 23 | unsigned char inb(unsigned short port) |
| 24 | { |
| 25 | return __builtin_inb(port); |
| 26 | } |
| 27 | |
| 28 | unsigned char inw(unsigned short port) |
| 29 | { |
| 30 | return __builtin_inw(port); |
| 31 | } |
| 32 | |
| 33 | unsigned char inl(unsigned short port) |
| 34 | { |
| 35 | return __builtin_inl(port); |
| 36 | } |
| 37 | |
| 38 | static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where) |
| 39 | { |
| 40 | return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3); |
| 41 | } |
| 42 | |
| 43 | static 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 | |
| 50 | static 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 | |
| 57 | static 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 | |
| 65 | static 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 | |
| 72 | static 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 | |
| 79 | static 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 | |
| 86 | int log2(int value) |
| 87 | { |
| 88 | /* __builtin_bsr is a exactly equivalent to the x86 machine |
| 89 | * instruction with the exception that it returns -1 |
| 90 | * 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 */ |
| 99 | #ifndef TTYS0_BASE |
| 100 | #define TTYS0_BASE 0x3f8 |
| 101 | #endif |
| 102 | |
| 103 | #ifndef TTYS0_BAUD |
| 104 | #define TTYS0_BAUD 115200 |
| 105 | #endif |
| 106 | |
| 107 | #if ((115200%TTYS0_BAUD) != 0) |
| 108 | #error Bad ttys0 baud rate |
| 109 | #endif |
| 110 | |
| 111 | #define TTYS0_DIV (115200/TTYS0_BAUD) |
| 112 | |
| 113 | /* Line Control Settings */ |
| 114 | #ifndef TTYS0_LCS |
| 115 | /* Set 8bit, 1 stop bit, no parity */ |
| 116 | #define TTYS0_LCS 0x3 |
| 117 | #endif |
| 118 | |
| 119 | #define UART_LCS TTYS0_LCS |
| 120 | |
| 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 | |
| 139 | int uart_can_tx_byte(void) |
| 140 | { |
| 141 | return inb(TTYS0_BASE + UART_LSR) & 0x20; |
| 142 | } |
| 143 | |
| 144 | void uart_wait_to_tx_byte(void) |
| 145 | { |
| 146 | while(!uart_can_tx_byte()) |
| 147 | ; |
| 148 | } |
| 149 | |
| 150 | void uart_wait_until_sent(void) |
| 151 | { |
| 152 | while(!(inb(TTYS0_BASE + UART_LSR) & 0x40)) |
| 153 | ; |
| 154 | } |
| 155 | |
| 156 | void uart_tx_byte(unsigned char data) |
| 157 | { |
| 158 | uart_wait_to_tx_byte(); |
| 159 | outb(data, TTYS0_BASE + UART_TBR); |
| 160 | /* Make certain the data clears the fifos */ |
| 161 | uart_wait_until_sent(); |
| 162 | } |
| 163 | |
| 164 | void uart_init(void) |
| 165 | { |
| 166 | /* disable interrupts */ |
| 167 | outb(0x0, TTYS0_BASE + UART_IER); |
| 168 | /* enable fifo's */ |
| 169 | outb(0x01, TTYS0_BASE + UART_FCR); |
| 170 | /* Set Baud Rate Divisor to 12 ==> 115200 Baud */ |
| 171 | outb(0x80 | UART_LCS, TTYS0_BASE + UART_LCR); |
| 172 | outb(TTYS0_DIV & 0xFF, TTYS0_BASE + UART_DLL); |
| 173 | outb((TTYS0_DIV >> 8) & 0xFF, TTYS0_BASE + UART_DLM); |
| 174 | outb(UART_LCS, TTYS0_BASE + UART_LCR); |
| 175 | } |
| 176 | |
| 177 | void __console_tx_char(unsigned char byte) |
| 178 | { |
| 179 | uart_tx_byte(byte); |
| 180 | } |
| 181 | void __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 | } |
| 190 | void __console_tx_hex8(unsigned char byte) |
| 191 | { |
| 192 | __console_tx_nibble(byte >> 4); |
| 193 | __console_tx_nibble(byte & 0x0f); |
| 194 | } |
| 195 | |
| 196 | void __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 |
| 209 | void __console_tx_string(char *str) |
| 210 | { |
| 211 | unsigned char ch; |
| 212 | while((ch = *str++) != '\0') { |
| 213 | __console_tx_char(ch); |
| 214 | } |
| 215 | } |
| 216 | #else |
| 217 | void __console_tx_string(char *str) |
| 218 | { |
| 219 | } |
| 220 | #endif |
| 221 | |
| 222 | |
| 223 | void print_emerg_char(unsigned char byte) { __console_tx_char(byte); } |
| 224 | void print_emerg_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 225 | void print_emerg_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 226 | void print_emerg(char *str) { __console_tx_string(str); } |
| 227 | |
| 228 | void print_alert_char(unsigned char byte) { __console_tx_char(byte); } |
| 229 | void print_alert_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 230 | void print_alert_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 231 | void print_alert(char *str) { __console_tx_string(str); } |
| 232 | |
| 233 | void print_crit_char(unsigned char byte) { __console_tx_char(byte); } |
| 234 | void print_crit_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 235 | void print_crit_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 236 | void print_crit(char *str) { __console_tx_string(str); } |
| 237 | |
| 238 | void print_err_char(unsigned char byte) { __console_tx_char(byte); } |
| 239 | void print_err_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 240 | void print_err_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 241 | void print_err(char *str) { __console_tx_string(str); } |
| 242 | |
| 243 | void print_warning_char(unsigned char byte) { __console_tx_char(byte); } |
| 244 | void print_warning_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 245 | void print_warning_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 246 | void print_warning(char *str) { __console_tx_string(str); } |
| 247 | |
| 248 | void print_notice_char(unsigned char byte) { __console_tx_char(byte); } |
| 249 | void print_notice_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 250 | void print_notice_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 251 | void print_notice(char *str) { __console_tx_string(str); } |
| 252 | |
| 253 | void print_info_char(unsigned char byte) { __console_tx_char(byte); } |
| 254 | void print_info_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 255 | void print_info_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 256 | void print_info(char *str) { __console_tx_string(str); } |
| 257 | |
| 258 | void print_debug_char(unsigned char byte) { __console_tx_char(byte); } |
| 259 | void print_debug_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 260 | void print_debug_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 261 | void print_debug(char *str) { __console_tx_string(str); } |
| 262 | |
| 263 | void print_spew_char(unsigned char byte) { __console_tx_char(byte); } |
| 264 | void print_spew_hex8(unsigned char value) { __console_tx_hex8(value); } |
| 265 | void print_spew_hex32(unsigned int value) { __console_tx_hex32(value); } |
| 266 | void 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 | |
| 277 | #if HAVE_CONSTANT_PROPOGATION |
| 278 | #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 | |
| 287 | static void smbus_wait_until_ready(void) |
| 288 | { |
| 289 | while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) { |
| 290 | /* nop */ |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | static 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 | |
| 305 | int 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 | |
| 358 | static void smbus_wait_until_ready(void) |
| 359 | { |
| 360 | while((inb(SMBUS_IO_HSTSTAT) & 1) == 1) { |
| 361 | /* nop */ |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | static 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 | |
| 376 | short 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 | |
| 421 | static 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; |
| 431 | |
| 432 | 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 |
| 467 | |
| 468 | /* 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 */ |
| 473 | |
| 474 | /* 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 |
| 490 | |
| 491 | #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 | } |