| #define HAVE_STRING_SUPPORT 0 |
| #define HAVE_CAST_SUPPORT 1 |
| #define HAVE_STATIC_ARRAY_SUPPORT 1 |
| #define HAVE_POINTER_SUPPORT 1 |
| #define HAVE_MACRO_ARG_SUPPORT 0 |
| |
| void outb(unsigned char value, unsigned short port) |
| { |
| __builtin_outb(value, port); |
| } |
| |
| void outw(unsigned short value, unsigned short port) |
| { |
| __builtin_outw(value, port); |
| } |
| |
| void outl(unsigned int value, unsigned short port) |
| { |
| __builtin_outl(value, port); |
| } |
| |
| unsigned char inb(unsigned short port) |
| { |
| return __builtin_inb(port); |
| } |
| |
| unsigned char inw(unsigned short port) |
| { |
| return __builtin_inw(port); |
| } |
| |
| unsigned char inl(unsigned short port) |
| { |
| return __builtin_inl(port); |
| } |
| |
| static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where) |
| { |
| return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3); |
| } |
| |
| static unsigned char pcibios_read_config_byte( |
| unsigned char bus, unsigned devfn, unsigned where) |
| { |
| outl(config_cmd(bus, devfn, where), 0xCF8); |
| return inb(0xCFC + (where & 3)); |
| } |
| |
| static unsigned short pcibios_read_config_word( |
| unsigned char bus, unsigned devfn, unsigned where) |
| { |
| outl(config_cmd(bus, devfn, where), 0xCF8); |
| return inw(0xCFC + (where & 2)); |
| } |
| |
| static unsigned int pcibios_read_config_dword( |
| unsigned char bus, unsigned devfn, unsigned where) |
| { |
| outl(config_cmd(bus, devfn, where), 0xCF8); |
| return inl(0xCFC); |
| } |
| |
| |
| static void pcibios_write_config_byte( |
| unsigned char bus, unsigned devfn, unsigned where, unsigned char value) |
| { |
| outl(config_cmd(bus, devfn, where), 0xCF8); |
| outb(value, 0xCFC + (where & 3)); |
| } |
| |
| static void pcibios_write_config_word( |
| unsigned char bus, unsigned devfn, unsigned where, unsigned short value) |
| { |
| outl(config_cmd(bus, devfn, where), 0xCF8); |
| outw(value, 0xCFC + (where & 2)); |
| } |
| |
| static void pcibios_write_config_dword( |
| unsigned char bus, unsigned devfn, unsigned where, unsigned int value) |
| { |
| outl(config_cmd(bus, devfn, where), 0xCF8); |
| outl(value, 0xCFC); |
| } |
| |
| /* Base Address */ |
| #ifndef CONFIG_TTYS0_BASE |
| #define CONFIG_TTYS0_BASE 0x3f8 |
| #endif |
| |
| #ifndef CONFIG_TTYS0_BAUD |
| #define CONFIG_TTYS0_BAUD 115200 |
| #endif |
| |
| #if ((115200%CONFIG_TTYS0_BAUD) != 0) |
| #error Bad ttys0 baud rate |
| #endif |
| |
| #define CONFIG_TTYS0_DIV (115200/CONFIG_TTYS0_BAUD) |
| |
| /* Line Control Settings */ |
| #ifndef CONFIG_TTYS0_LCS |
| /* Set 8bit, 1 stop bit, no parity */ |
| #define CONFIG_TTYS0_LCS 0x3 |
| #endif |
| |
| #define UART_LCS CONFIG_TTYS0_LCS |
| |
| /* Data */ |
| #define UART_RBR 0x00 |
| #define UART_TBR 0x00 |
| |
| /* Control */ |
| #define UART_IER 0x01 |
| #define UART_IIR 0x02 |
| #define UART_FCR 0x02 |
| #define UART_LCR 0x03 |
| #define UART_MCR 0x04 |
| #define UART_DLL 0x00 |
| #define UART_DLM 0x01 |
| |
| /* Status */ |
| #define UART_LSR 0x05 |
| #define UART_MSR 0x06 |
| #define UART_SCR 0x07 |
| |
| int uart_can_tx_byte(void) |
| { |
| return inb(CONFIG_TTYS0_BASE + UART_LSR) & 0x20; |
| } |
| |
| void uart_wait_to_tx_byte(void) |
| { |
| while(!uart_can_tx_byte()) |
| ; |
| } |
| |
| void uart_wait_until_sent(void) |
| { |
| while(!(inb(CONFIG_TTYS0_BASE + UART_LSR) & 0x40)) |
| ; |
| } |
| |
| void uart_tx_byte(unsigned char data) |
| { |
| uart_wait_to_tx_byte(); |
| outb(data, CONFIG_TTYS0_BASE + UART_TBR); |
| /* Make certain the data clears the fifos */ |
| uart_wait_until_sent(); |
| } |
| |
| void uart_init(void) |
| { |
| /* disable interrupts */ |
| outb(0x0, CONFIG_TTYS0_BASE + UART_IER); |
| /* enable fifo's */ |
| outb(0x01, CONFIG_TTYS0_BASE + UART_FCR); |
| /* Set Baud Rate Divisor to 12 ==> 115200 Baud */ |
| outb(0x80 | UART_LCS, CONFIG_TTYS0_BASE + UART_LCR); |
| outb(CONFIG_TTYS0_DIV & 0xFF, CONFIG_TTYS0_BASE + UART_DLL); |
| outb((CONFIG_TTYS0_DIV >> 8) & 0xFF, CONFIG_TTYS0_BASE + UART_DLM); |
| outb(UART_LCS, CONFIG_TTYS0_BASE + UART_LCR); |
| } |
| |
| void __console_tx_char(unsigned char byte) |
| { |
| uart_tx_byte(byte); |
| } |
| void __console_tx_nibble(unsigned nibble) |
| { |
| unsigned char digit; |
| digit = nibble + '0'; |
| if (digit > '9') { |
| digit += 39; |
| } |
| __console_tx_char(digit); |
| } |
| void __console_tx_hex8(unsigned char byte) |
| { |
| __console_tx_nibble(byte >> 4); |
| __console_tx_nibble(byte & 0x0f); |
| } |
| |
| void __console_tx_hex32(unsigned char value) |
| { |
| __console_tx_nibble((value >> 28) & 0x0f); |
| __console_tx_nibble((value >> 24) & 0x0f); |
| __console_tx_nibble((value >> 20) & 0x0f); |
| __console_tx_nibble((value >> 16) & 0x0f); |
| __console_tx_nibble((value >> 12) & 0x0f); |
| __console_tx_nibble((value >> 8) & 0x0f); |
| __console_tx_nibble((value >> 4) & 0x0f); |
| __console_tx_nibble(value & 0x0f); |
| } |
| |
| #if HAVE_STRING_SUPPORT |
| void __console_tx_string(char *str) |
| { |
| unsigned char ch; |
| while((ch = *str++) != '\0') { |
| __console_tx_char(ch); |
| } |
| } |
| #else |
| void __console_tx_string(char *str) |
| { |
| } |
| #endif |
| |
| |
| void print_emerg_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_emerg_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_emerg_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_emerg(char *str) { __console_tx_string(str); } |
| |
| void print_alert_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_alert_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_alert_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_alert(char *str) { __console_tx_string(str); } |
| |
| void print_crit_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_crit_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_crit_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_crit(char *str) { __console_tx_string(str); } |
| |
| void print_err_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_err_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_err_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_err(char *str) { __console_tx_string(str); } |
| |
| void print_warning_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_warning_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_warning_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_warning(char *str) { __console_tx_string(str); } |
| |
| void print_notice_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_notice_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_notice_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_notice(char *str) { __console_tx_string(str); } |
| |
| void print_info_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_info_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_info_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_info(char *str) { __console_tx_string(str); } |
| |
| void print_debug_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_debug_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_debug_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_debug(char *str) { __console_tx_string(str); } |
| |
| void print_spew_char(unsigned char byte) { __console_tx_char(byte); } |
| void print_spew_hex8(unsigned char value) { __console_tx_hex8(value); } |
| void print_spew_hex32(unsigned int value) { __console_tx_hex32(value); } |
| void print_spew(char *str) { __console_tx_string(str); } |
| |
| #define PIIX4_DEVFN 0x90 |
| #define SMBUS_MEM_DEVICE_START 0x50 |
| #define SMBUS_MEM_DEVICE_END 0x53 |
| #define SMBUS_MEM_DEVICE_INC 1 |
| |
| |
| #define PM_BUS 0 |
| #define PM_DEVFN (PIIX4_DEVFN+3) |
| |
| #define SMBUS_IO_BASE 0x1000 |
| #define SMBHSTSTAT 0 |
| #define SMBHSTCTL 2 |
| #define SMBHSTCMD 3 |
| #define SMBHSTADD 4 |
| #define SMBHSTDAT0 5 |
| #define SMBHSTDAT1 6 |
| #define SMBBLKDAT 7 |
| |
| void smbus_enable(void) |
| { |
| /* iobase addr */ |
| pcibios_write_config_dword(PM_BUS, PM_DEVFN, 0x90, SMBUS_IO_BASE | 1); |
| /* smbus enable */ |
| pcibios_write_config_byte(PM_BUS, PM_DEVFN, 0xd2, (0x4 << 1) | 1); |
| /* iospace enable */ |
| pcibios_write_config_word(PM_BUS, PM_DEVFN, 0x4, 1); |
| } |
| |
| void smbus_setup(void) |
| { |
| outb(0, SMBUS_IO_BASE + SMBHSTSTAT); |
| } |
| |
| static void smbus_wait_until_ready(void) |
| { |
| while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) { |
| /* nop */ |
| } |
| } |
| |
| static void smbus_wait_until_done(void) |
| { |
| unsigned char byte; |
| do { |
| byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); |
| }while((byte &1) == 1); |
| while( (byte & ~1) == 0) { |
| byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); |
| } |
| } |
| |
| int smbus_read_byte(unsigned device, unsigned address) |
| { |
| unsigned char host_status_register; |
| unsigned char byte; |
| int result; |
| |
| smbus_wait_until_ready(); |
| |
| /* setup transaction */ |
| /* disable interrupts */ |
| outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); |
| /* set the device I'm talking too */ |
| outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD); |
| /* set the command/address... */ |
| outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); |
| /* set up for a byte data read */ |
| outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL); |
| |
| /* clear any lingering errors, so the transaction will run */ |
| outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); |
| |
| /* clear the data byte...*/ |
| outb(0, SMBUS_IO_BASE + SMBHSTDAT0); |
| |
| /* start the command */ |
| outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL); |
| |
| /* poll for transaction completion */ |
| smbus_wait_until_done(); |
| |
| host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT); |
| |
| /* read results of transaction */ |
| byte = inb(SMBUS_IO_BASE + SMBHSTDAT0); |
| |
| result = byte; |
| if (host_status_register != 0x02) { |
| result = -1; |
| } |
| return result; |
| } |
| |
| #define I440GX_BUS 0 |
| #define I440GX_DEVFN ((0x00 << 3) + 0) |
| |
| #define USE_ECC 0 |
| |
| #define CAS_LATENCY 3 |
| |
| /* CAS latency 2 */ |
| #if (CAS_LATENCY == 2) |
| #define CAS_NB 0x17 |
| /* |
| * 7 == 0111 |
| * 1 == 0001 |
| */ |
| #define CAS_MODE 0x2a |
| /* |
| * a == 1010 |
| * 2 == 0010 |
| */ |
| #endif |
| |
| /* CAS latency 3 */ |
| #if (CAS_LATENCY == 3) |
| #define CAS_NB 0x13 |
| /* |
| * 3 == 0011 |
| * 1 == 0001 |
| */ |
| #define CAS_MODE 0x3a |
| /* |
| * a == 1010 |
| * 3 == 0011 |
| */ |
| #endif |
| |
| #ifndef CAS_NB |
| #error "Nothing defined" |
| #endif |
| |
| /* Default values for config registers */ |
| |
| static void set_nbxcfg(void) |
| { |
| /* NBXCFG 0x50 - 0x53 */ |
| /* f == 1111 |
| * 0 == 0000 |
| * 0 == 0000 |
| * 0 == 0000 |
| * 0 == 0000 |
| * 1 == 0001 |
| * 8 == 1000 |
| * c == 1100 |
| * SDRAM Row without ECC: |
| * row 0 == 1 No ECC |
| * row 1 == 1 No ECC |
| * row 2 == 1 No ECC |
| * row 3 == 1 No ECC |
| * row 4 == 1 No ECC |
| * row 5 == 1 No ECC |
| * row 6 == 1 No ECC |
| * row 7 == 1 No ECC |
| * Host Bus Fast Data Ready Enable == 0 Disabled |
| * IDSEL_REDIRECT == 0 (430TX compatibility disable?) |
| * WSC# Hanshake Disable == 0 enable (Use External IOAPIC) |
| * Host/DRAM Frequence == 00 100Mhz |
| * AGP to PCI Access Enable == 0 Disable |
| * PCI Agent to Aperture Access Disable == 0 Enable (Ignored) |
| * Aperture Access Global Enable == 0 Disable |
| * DRAM Data Integrity Mode == 11 (Error Checking/Correction) |
| * ECC Diagnostic Mode Enable == 0 Not Enabled |
| * MDA present == 0 Not Present |
| * USWC Write Post During During I/O Bridge Access Enable == 1 Enabled |
| * In Order Queue Depth (IQD) (RO) == ?? |
| */ |
| pcibios_write_config_dword(I440GX_BUS, I440GX_DEVFN, 0x50, 0xff00000c); |
| } |
| |
| static void set_dramc(void) |
| { |
| /* 0 == 0000 |
| * 8 == 1000 |
| * Not registered SDRAM |
| * refresh disabled |
| */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57, 0x8); |
| } |
| |
| static void set_pam(void) |
| { |
| /* PAM - Programmable Attribute Map Registers */ |
| /* Ideally we want to enable all of these as DRAM and teach |
| * linux it is o.k. to use them... |
| */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x59, 0x00); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5a, 0x00); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5b, 0x00); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5d, 0x00); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5e, 0x00); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x5f, 0x00); |
| } |
| |
| static void set_drb(void) |
| { |
| /* DRB - DRAM Row Boundary Registers */ |
| /* Conservative setting 8MB of ram on first DIMM... */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x60, 0x01); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x61, 0x01); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x62, 0x01); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x63, 0x01); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x64, 0x01); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x65, 0x01); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x66, 0x01); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x67, 0x01); |
| } |
| |
| static void set_fdhc(void) |
| { |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x68, 0x00); |
| } |
| static void set_mbsc(void) |
| { |
| /* MBSC - Memory Buffer Strength Control */ |
| /* 00c00003e820 |
| * [47:44] 0 == 0000 |
| * [43:40] 0 == 0000 |
| * [39:36] c == 1100 |
| * [35:32] 0 == 0000 |
| * [31:28] 0 == 0000 |
| * [27:24] 0 == 0000 |
| * [23:20] 0 == 0000 |
| * [19:16] 3 == 0011 |
| * [15:12] e == 1110 |
| * [11: 8] 8 == 1000 |
| * [ 7: 4] 2 == 0010 |
| * [ 3: 0] 0 == 0000 |
| * MAA[14:0]#, WEA#, SRASA#, SCASA# Buffer Strengths == 3x |
| * MAB[14,13,10,12:11,9:0]#, WEB#, SRASB#, SCASB# Buffer Strengths == 3x |
| * MD[63:0]# Buffer Strength Control 2 == 3x |
| * MD[63:0]# Buffer Strength Control 1 == 3x |
| * MECC[7:0] Buffer Strength Control 2 == 3x |
| * MECC[7:0] Buffer Strength Control 1 == 3x |
| * CSB7# Buffer Strength == 3x |
| * CSA7# Buffer Strength == 3x |
| * CSB6# Buffer Strength == 3x |
| * CSA6# Buffer Strength == 3x |
| * CSA5#/CSB5# Buffer Strength == 2x |
| * CSA4#/CSB4# Buffer Strength == 2x |
| * CSA3#/CSB3# Buffer Strength == 2x |
| * CSA2#/CSB2# Buffer Strength == 2x |
| * CSA1#/CSB1# Buffer Strength == 2x |
| * CSA0#/CSB0# Buffer Strength == 2x |
| * DQMA5 Buffer Strength == 2x |
| * DQMA1 Buffer Strength == 3x |
| * DQMB5 Buffer Strength == 2x |
| * DQMB1 Buffer Strength == 2x |
| * DQMA[7:6,4:2,0] Buffer Strength == 3x |
| * GCKE Buffer Strength == 1x |
| * FENA Buffer Strength == 3x |
| */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x69, 0xB3); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6a, 0xee); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6b, 0xff); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6c, 0xff); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6d, 0xff); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x6e, 0x03); |
| } |
| |
| static void set_smram(void) |
| { |
| /* 0x72 SMRAM */ |
| /* 1 == 0001 |
| * a == 1010 |
| * SMM Compatible base segment == 010 (Hardcoded value) |
| */ |
| } |
| |
| static void set_esramc(void) |
| { |
| /* 0x73 ESMRAMC */ |
| } |
| |
| static void set_rps(void) |
| { |
| /* RPS - Row Page Size Register */ |
| /* 0x0055 |
| * [15:12] 0 == 0000 |
| * [11: 8] 0 == 0000 |
| * [ 7: 4] 5 == 0101 |
| * [ 3: 0] 5 == 0101 |
| * DRB[0] == 4KB |
| * DRB[1] == 4KB |
| * DRB[2] == 4KB |
| * DRB[3] == 4KB |
| * DRB[4] == 2KB |
| * DRB[5] == 2KB |
| * DRB[6] == 2KB |
| * DRB[7] == 2KB |
| */ |
| pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x74, 0x5555); |
| } |
| |
| static void set_sdramc(void) |
| { |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76, CAS_NB); |
| } |
| |
| static void set_pgpol(void) |
| { |
| /* PGPOL - Paging Policy Register */ |
| /* 0xff07 |
| * [15:12] f == 1111 |
| * [11: 8] f == 1111 |
| * [ 7: 4] 0 == 0000 |
| * [ 3: 0] 7 == 0111 |
| * row0 == 4banks |
| * row1 == 4banks |
| * row2 == 4banks |
| * row3 == 4banks |
| * row4 == 4banks |
| * row5 == 4banks |
| * row6 == 4banks |
| * row7 == 4banks |
| * Dram Idle Timer (DIT) == 32 clocks |
| */ |
| pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x78, 0xff07); |
| } |
| |
| static void set_mbfs(void) |
| { |
| /* MBFS - Memory Buffer Frequencey Select Register */ |
| /* 0xffff7f |
| * [23:20] f == 1111 |
| * [19:16] f == 1111 |
| * [15:12] f == 1111 |
| * [11: 8] f == 1111 |
| * [ 7: 4] 7 == 0111 |
| * [ 3: 0] f == 1111 |
| * MAA[14:0], WEA#, SRASA#, SCASA# == 100Mhz Buffers Enabled |
| * MAB[14,13,10,12:11,9:0], WEB#, SRASB#, SCASB# == 100Mhz Buffers Enabled |
| * MD[63:0] Control 2 == 100 Mhz Buffer Enable |
| * MD[63:0] Control 1 == 100 Mhz B |
| * MECC[7:0] Control 2 == 100 Mhz B |
| * |
| */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xca, 0xff); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcb, 0xff); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcc, 0x7f); |
| } |
| |
| static void set_dwtc(void) |
| { |
| /* DWTC - DRAM Write Thermal Throttle Control */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe0, 0xb4); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe1, 0xbe); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe2, 0xff); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe3, 0xd7); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe4, 0x97); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe5, 0x3e); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe6, 0x00); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe7, 0x80); |
| } |
| |
| static void set_drtc(void) |
| { |
| /* DRTC - DRAM Read Thermal Throttle Control */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe8, 0x2c); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xe9, 0xd3); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xea, 0xf7); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xeb, 0xcf); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xec, 0x9d); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xed, 0x3e); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xee, 0x00); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xef, 0x00); |
| } |
| |
| static void set_pmcr(void) |
| { |
| /* PMCR -- BIOS sets 0x90 into it. |
| * 0x10 is REQUIRED. |
| * we have never used it. So why did this ever work? |
| */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x7a, 0x90); |
| |
| } |
| void sdram_set_registers(void) |
| { |
| set_nbxcfg(); |
| set_dramc(); |
| set_pam(); |
| set_drb(); |
| set_fdhc(); |
| set_mbsc(); |
| set_smram(); |
| set_esramc(); |
| set_rps(); |
| set_sdramc(); |
| set_pgpol(); |
| set_mbfs(); |
| set_dwtc(); |
| set_drtc(); |
| set_pmcr(); |
| } |
| |
| int log2(int value) |
| { |
| /* __builtin_bsr is a exactly equivalent to the x86 machine |
| * instruction with the exception that it returns -1 |
| * when the value presented to it is zero. |
| * Otherwise __builtin_bsr returns the zero based index of |
| * the highest bit set. |
| */ |
| return __builtin_bsr(value); |
| } |
| |
| |
| static void spd_set_drb(void) |
| { |
| /* |
| * Effects: Uses serial presence detect to set the |
| * DRB registers which holds the ending memory address assigned |
| * to each DIMM. |
| */ |
| unsigned end_of_memory; |
| unsigned device; |
| unsigned drb_reg; |
| |
| end_of_memory = 0; /* in multiples of 8MiB */ |
| device = SMBUS_MEM_DEVICE_START; |
| drb_reg = 0x60; |
| while (device <= SMBUS_MEM_DEVICE_END) { |
| unsigned side1_bits, side2_bits; |
| int byte, byte2; |
| |
| side1_bits = side2_bits = -1; |
| |
| /* rows */ |
| byte = smbus_read_byte(device, 3); |
| if (byte >= 0) { |
| side1_bits += byte & 0xf; |
| |
| /* columns */ |
| byte = smbus_read_byte(device, 4); |
| side1_bits += byte & 0xf; |
| |
| /* banks */ |
| byte = smbus_read_byte(device, 17); |
| side1_bits += log2(byte); |
| |
| /* Get the moduel data width and convert it to a power of two */ |
| /* low byte */ |
| byte = smbus_read_byte(device, 6); |
| |
| /* high byte */ |
| byte2 = smbus_read_byte(device, 7); |
| #if HAVE_CAST_SUPPORT |
| side1_bits += log2((((unsigned long)byte2 << 8)| byte)); |
| #else |
| side1_bits += log2((byte2 << 8) | byte); |
| #endif |
| |
| /* now I have the ram size in bits as a power of two (less 1) */ |
| /* Make it mulitples of 8MB */ |
| side1_bits -= 25; |
| |
| /* side two */ |
| |
| /* number of physical banks */ |
| byte = smbus_read_byte(device, 5); |
| if (byte > 1) { |
| /* for now only handle the symmetrical case */ |
| side2_bits = side1_bits; |
| } |
| } |
| |
| /* Compute the end address for the DRB register */ |
| /* Only process dimms < 2GB (2^8 * 8MB) */ |
| if (side1_bits < 8) { |
| end_of_memory += (1 << side1_bits); |
| } |
| #if HAVE_STRING_SUPPORT |
| print_debug("end_of_memory: "); print_debug_hex32(end_of_memory); print_debug("\n"); |
| #endif |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, drb_reg, end_of_memory); |
| |
| if (side2_bits < 8 ) { |
| end_of_memory += (1 << side2_bits); |
| } |
| #if HAVE_STRING_SUPPORT |
| print_debug("end_of_memory: "); print_debug_hex32(end_of_memory); print_debug("\n"); |
| #endif |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, drb_reg +1, end_of_memory); |
| |
| drb_reg += 2; |
| device += SMBUS_MEM_DEVICE_INC; |
| } |
| } |
| |
| void sdram_no_memory(void) |
| { |
| #if HAVE_STRING_SUPPORT |
| print_err("No memory!!\n"); |
| #endif |
| while(1) ; |
| } |
| |
| static void spd_set_dramc(void) |
| { |
| /* |
| * Effects: Uses serial presence detect to set the |
| * DRAMC register, which records if ram is registerd or not, |
| * and controls the refresh rate. |
| * The refresh rate is not set here, as memory refresh |
| * cannot be enbaled until after memory is initialized. |
| * see spd_enable_refresh. |
| */ |
| /* auto detect if ram is registered or not. */ |
| /* The DRAMC register also contorls the refresh rate but we can't |
| * set that here because we must leave refresh disabled. |
| * see: spd_enable_refresh |
| */ |
| /* Find the first dimm and assume the rest are the same */ |
| /* FIXME Check for illegal/unsupported ram configurations and abort */ |
| unsigned device; |
| int byte; |
| unsigned dramc; |
| byte = -1; |
| device = SMBUS_MEM_DEVICE_START; |
| |
| while ((byte < 0) && (device <= SMBUS_MEM_DEVICE_END)) { |
| byte = smbus_read_byte(device, 21); |
| device += SMBUS_MEM_DEVICE_INC; |
| } |
| if (byte < 0) { |
| /* We couldn't find anything we must have no memory */ |
| sdram_no_memory(); |
| } |
| dramc = 0x8; |
| if ((byte & 0x12) != 0) { |
| /* this is a registered part. |
| * observation: for register parts, BIOS zeros (!) |
| * registers CA-CC. This has an undocumented meaning. |
| */ |
| /* But it does make sense the oppisite of registered |
| * sdram is buffered and 0xca - 0xcc control the buffers. |
| * Clearing them aparently disables them. |
| */ |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xca, 0); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcb, 0); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0xcc, 0); |
| dramc = 0x10; |
| } |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57, dramc); |
| } |
| |
| static void spd_enable_refresh(void) |
| { |
| /* |
| * Effects: Uses serial presence detect to set the |
| * refresh rate in the DRAMC register. |
| * see spd_set_dramc for the other values. |
| * FIXME: Check for illegal/unsupported ram configurations and abort |
| */ |
| #if HAVE_STATIC_ARRAY_SUPPORT |
| static const unsigned char refresh_rates[] = { |
| 0x01, /* Normal 15.625 us -> 15.6 us */ |
| 0x05, /* Reduced(.25X) 3.9 us -> 7.8 us */ |
| 0x05, /* Reduced(.5X) 7.8 us -> 7.8 us */ |
| 0x02, /* Extended(2x) 31.3 us -> 31.2 us */ |
| 0x03, /* Extended(4x) 62.5 us -> 62.4 us */ |
| 0x04, /* Extended(8x) 125 us -> 124.8 us */ |
| }; |
| #endif |
| /* Find the first dimm and assume the rest are the same */ |
| int status; |
| int byte; |
| unsigned device; |
| unsigned refresh_rate; |
| byte = -1; |
| status = -1; |
| device = SMBUS_MEM_DEVICE_START; |
| while ((byte < 0) && (device <= SMBUS_MEM_DEVICE_END)) { |
| byte = smbus_read_byte(device, 12); |
| device += SMBUS_MEM_DEVICE_INC; |
| } |
| if (byte < 0) { |
| /* We couldn't find anything we must have no memory */ |
| sdram_no_memory(); |
| } |
| byte &= 0x7f; |
| /* Default refresh rate be conservative */ |
| refresh_rate = 5; |
| /* see if the ram refresh is a supported one */ |
| if (byte < 6) { |
| #if HAVE_STATIC_ARRAY_SUPPORT |
| refresh_rate = refresh_rates[byte]; |
| #endif |
| } |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57); |
| byte &= 0xf8; |
| byte |= refresh_rate; |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57, byte); |
| } |
| |
| static void spd_set_sdramc(void) |
| { |
| return; |
| } |
| |
| static void spd_set_rps(void) |
| { |
| /* |
| * Effects: Uses serial presence detect to set the row size |
| * on a given DIMM |
| * FIXME: Check for illegal/unsupported ram configurations and abort |
| */ |
| /* The RPS register holds the size of a ``page'' of DRAM on each DIMM */ |
| unsigned page_sizes; |
| unsigned index; |
| unsigned device; |
| unsigned char dramc; |
| /* default all page sizes to 2KB */ |
| page_sizes = 0; |
| index = 0; |
| device = SMBUS_MEM_DEVICE_START; |
| for(; device <= SMBUS_MEM_DEVICE_END; index += 4, device += SMBUS_MEM_DEVICE_INC) { |
| unsigned int status; |
| unsigned int byte; |
| int page_size; |
| |
| byte = smbus_read_byte(device, 3); |
| if (byte < 0) continue; |
| |
| /* I now have the row page size as a power of 2 */ |
| page_size = byte & 0xf; |
| /* make it in multiples of 2Kb */ |
| page_size -= 11; |
| |
| if (page_size <= 0) continue; |
| |
| /* FIXME: do something with page sizes greather than 8KB!! */ |
| page_sizes |= (page_size << index); |
| |
| /* side two */ |
| byte = smbus_read_byte(device, 5); |
| if (byte <= 1) continue; |
| |
| /* For now only handle the symmetrical case */ |
| page_sizes |= (page_size << (index +2)); |
| } |
| /* next block is for Ron's attempt to get registered to work. */ |
| /* we have just verified that we have to have this code. It appears that |
| * the registered SDRAMs do indeed set the RPS wrong. sheesh. |
| */ |
| /* at this point, page_sizes holds the RPS for all ram. |
| * we have verified that for registered DRAM the values are |
| * 1/2 the size they should be. So we test for registered |
| * and then double the sizes if needed. |
| */ |
| |
| dramc = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x57); |
| if (dramc & 0x10) { |
| /* registered */ |
| |
| /* BIOS makes weird page size for registered! */ |
| /* what we have found is you need to set the EVEN banks to |
| * twice the size. Fortunately there is a very easy way to |
| * do this. First, read the WORD value of register 0x74. |
| */ |
| page_sizes += 0x1111; |
| } |
| |
| pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x74, page_sizes); |
| } |
| |
| static void spd_set_pgpol(void) |
| { |
| /* |
| * Effects: Uses serial presence detect to set the number of banks |
| * on a given DIMM |
| * FIXME: Check for illegal/unsupported ram configurations and abort |
| */ |
| /* The PGPOL register stores the number of logical banks per DIMM, |
| * and number of clocks the DRAM controller waits in the idle |
| * state. |
| */ |
| unsigned device; |
| unsigned bank_sizes; |
| unsigned bank; |
| unsigned reg; |
| /* default all bank counts 2 */ |
| bank_sizes = 0; |
| bank = 0; |
| device = SMBUS_MEM_DEVICE_START; |
| for(; device <= SMBUS_MEM_DEVICE_END; |
| bank += 2, device += SMBUS_MEM_DEVICE_INC) { |
| int byte; |
| |
| /* logical banks */ |
| byte = smbus_read_byte(device, 17); |
| if (byte < 0) continue; |
| if (byte < 4) continue; |
| bank_sizes |= (1 << bank); |
| |
| /* side 2 */ |
| /* Number of physical banks */ |
| byte = smbus_read_byte(device, 5); |
| if (byte <= 1) continue; |
| /* for now only handle the symmetrical case */ |
| bank_sizes |= (1 << (bank +1)); |
| } |
| reg = bank_sizes << 8; |
| reg |= 0x7; /* 32 clocks idle time */ |
| pcibios_write_config_word(I440GX_BUS, I440GX_DEVFN, 0x78, reg); |
| } |
| |
| static void spd_set_nbxcfg(void) |
| { |
| /* |
| * Effects: Uses serial presence detect to set the |
| * ECC support flags in the NBXCFG register |
| * FIXME: Check for illegal/unsupported ram configurations and abort |
| */ |
| unsigned reg; |
| unsigned index; |
| unsigned device; |
| |
| /* Say all dimms have no ECC support */ |
| reg = 0xff; |
| index = 0; |
| |
| device = SMBUS_MEM_DEVICE_START; |
| for(; device <= SMBUS_MEM_DEVICE_END; index += 2, device += SMBUS_MEM_DEVICE_INC) { |
| int byte; |
| |
| byte = smbus_read_byte(device, 11); |
| if (byte < 0) continue; |
| #if !USE_ECC |
| byte = 0; /* Disable ECC */ |
| #endif |
| /* 0 == None, 1 == Parity, 2 == ECC */ |
| if (byte != 2) continue; |
| reg ^= (1 << index); |
| |
| /* side two */ |
| /* number of physical banks */ |
| byte = smbus_read_byte(device, 5); |
| if (byte <= 1) continue; |
| /* There is only the symmetrical case */ |
| reg ^= (1 << (index +1)); |
| } |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x53, reg); |
| /* Now see if reg is 0xff. If it is we are done. If not, |
| * we need to set 0x18 into regster 0x50.l |
| * we will do this in two steps, first or in 0x80 to 0x50.b, |
| * then or in 0x1 to 0x51.b |
| */ |
| #if HAVE_STRING_SUPPORT |
| print_debug("spd_set_nbxcfg reg="); print_debug_hex8(reg); print_debug("\n"); |
| #endif |
| if (reg != 0xff) { |
| unsigned char byte; |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x50); |
| byte |= 0x80; |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x50, byte); |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x51); |
| byte |= 1; |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x51, byte); |
| /* try this. |
| * We should be setting bit 2 in register 76 and we're not |
| * technically we should see if CL=2 for the ram, |
| * but registered is so screwed up that it's kind of a lost |
| * cause. |
| */ |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76); |
| byte |= 4; |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76, byte); |
| #if HAVE_STRING_SUPPORT |
| print_debug("spd_set_nbxcfg 0x76.b="); print_debug_hex8(byte); print_debug("\n"); |
| #endif |
| } |
| } |
| |
| void sdram_set_spd_registers(void) |
| { |
| spd_set_drb(); |
| spd_set_dramc(); |
| spd_set_rps(); |
| spd_set_sdramc(); |
| spd_set_pgpol(); |
| spd_set_nbxcfg(); |
| } |
| |
| void sdram_first_normal_reference(void) |
| { |
| return; |
| } |
| |
| void sdram_special_finishup(void) |
| { |
| return; |
| } |
| |
| static void set_ram_command(unsigned command) |
| { |
| unsigned char byte; |
| command &= 0x7; |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76); |
| byte &= 0x1f; |
| byte |= (command << 5); |
| pcibios_write_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76, byte); |
| #if HAVE_STRING_SUPPORT |
| print_debug("set_ram_command 0x76.b="); print_debug_hex8(byte); print_debug("\n"); |
| #endif |
| } |
| |
| #define RAM_COMMAND_NONE 0x0 |
| #define RAM_COMMAND_NOOP 0x1 |
| #define RAM_COMMAND_PRECHARGE 0x2 |
| #define RAM_COMMAND_MRS 0x3 |
| #define RAM_COMMAND_CBR 0x4 |
| |
| void sdram_set_command_none(void) |
| { |
| set_ram_command(RAM_COMMAND_NONE); |
| } |
| void sdram_set_command_noop(void) |
| { |
| set_ram_command(RAM_COMMAND_NOOP); |
| } |
| void sdram_set_command_precharge(void) |
| { |
| set_ram_command(RAM_COMMAND_PRECHARGE); |
| } |
| |
| static unsigned long dimm_base(int n) |
| { |
| unsigned char byte; |
| unsigned long result; |
| if (n == 0) { |
| return 0; |
| } |
| |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x60 + (n - 1)); |
| result = byte; |
| result <<= 23; |
| return result; |
| } |
| |
| static void dimms_read(unsigned long offset) |
| { |
| int i; |
| for(i = 0; i < 8; i++) { |
| unsigned long dummy; |
| unsigned long addr; |
| unsigned long next_base; |
| |
| next_base = dimm_base(i +1); |
| addr = dimm_base(i); |
| if (addr == next_base) { |
| continue; |
| } |
| addr += offset; |
| #if HAVE_STRING_SUPPORT |
| print_debug("Reading "); |
| print_debug_hex32(addr); |
| print_debug("\n"); |
| #endif |
| #if HAVE_POINTER_SUPPORT |
| #if HAVE_MACRO_ARG_SUPPORT |
| dummy = RAM(unsigned long, addr); |
| #else |
| dummy = *((volatile unsigned long *)(addr)); |
| #endif |
| #endif |
| #if HAVE_STRING_SUPPORT |
| print_debug("Reading "); |
| print_debug_hex32(addr ^ 0xddf8); |
| print_debug("\n"); |
| #endif |
| #if HAVE_POINTER_SUPPORT |
| #if HAVE_MACRO_ARG_SUPPORT |
| dummy = RAM(unsigned long, addr ^ 0xdff8); |
| #else |
| dummy = *((volatile unsigned long *)(addr ^ 0xdff8)); |
| #endif |
| #endif |
| #if HAVE_STRING_SUPPORT |
| print_debug("Read "); |
| print_debug_hex32(addr); |
| print_debug_hex32(addr ^ 0xddf8); |
| print_debug("\n"); |
| #endif |
| } |
| } |
| |
| void sdram_set_command_cbr(void) |
| { |
| set_ram_command(RAM_COMMAND_CBR); |
| } |
| |
| void sdram_assert_command(void) |
| { |
| dimms_read(0x400); |
| } |
| |
| void sdram_set_mode_register(void) |
| { |
| unsigned char byte; |
| unsigned cas_mode; |
| set_ram_command(RAM_COMMAND_MRS); |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x76); |
| cas_mode = byte & 0x4; |
| cas_mode ^= 4; |
| cas_mode <<= 2; |
| cas_mode |= 0x2a; |
| cas_mode <<= 3; |
| dimms_read(cas_mode); |
| } |
| |
| void sdram_enable_refresh(void) |
| { |
| spd_enable_refresh(); |
| } |
| |
| |
| unsigned long sdram_get_ecc_size_bytes(void) |
| { |
| unsigned char byte; |
| unsigned long size; |
| /* FIXME handle the no ram case. */ |
| /* Read the RAM SIZE */ |
| byte = pcibios_read_config_byte(I440GX_BUS, I440GX_DEVFN, 0x67); |
| /* Convert it to bytes */ |
| size = byte; |
| size <<= 23; |
| #if !USE_ECC |
| size = 0; |
| #endif |
| return size; |
| } |
| |
| /* Dummy udelay code acting as a place holder... */ |
| void udelay(int count) |
| { |
| int i; |
| i = 5; |
| } |
| |
| void sdram_enable(void) |
| { |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram Enable 1\n"); |
| #endif |
| |
| /* noop command */ |
| sdram_set_command_noop(); |
| udelay(200); |
| sdram_assert_command(); |
| |
| /* Precharge all */ |
| sdram_set_command_precharge(); |
| sdram_assert_command(); |
| |
| /* wait until the all banks idle state... */ |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram Enable 2\n"); |
| #endif |
| |
| /* Now we need 8 AUTO REFRESH / CBR cycles to be performed */ |
| |
| sdram_set_command_cbr(); |
| sdram_assert_command(); |
| sdram_assert_command(); |
| sdram_assert_command(); |
| sdram_assert_command(); |
| sdram_assert_command(); |
| sdram_assert_command(); |
| sdram_assert_command(); |
| sdram_assert_command(); |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram Enable 3\n"); |
| #endif |
| |
| /* mode register set */ |
| sdram_set_mode_register(); |
| /* MAx[14:0] lines, |
| * MAx[2:0 ] 010 == burst mode of 4 |
| * MAx[3:3 ] 1 == interleave wrap type |
| * MAx[4:4 ] == CAS# latency bit |
| * MAx[6:5 ] == 01 |
| * MAx[12:7] == 0 |
| */ |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram Enable 4\n"); |
| #endif |
| |
| /* normal operation */ |
| sdram_set_command_none(); |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram Enable 5\n"); |
| #endif |
| } |
| |
| /* Setup SDRAM */ |
| void sdram_initialize(void) |
| { |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram1\n"); |
| #endif |
| /* Set the registers we can set once to reasonable values */ |
| sdram_set_registers(); |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram2\n"); |
| #endif |
| /* Now setup those things we can auto detect */ |
| sdram_set_spd_registers(); |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram3\n"); |
| #endif |
| /* Now that everything is setup enable the SDRAM. |
| * Some chipsets do the work for use while on others |
| * we need to it by hand. |
| */ |
| sdram_enable(); |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram4\n"); |
| #endif |
| sdram_first_normal_reference(); |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram5\n"); |
| #endif |
| sdram_enable_refresh(); |
| sdram_special_finishup(); |
| |
| #if HAVE_STRING_SUPPORT |
| print_debug("Ram6\n"); |
| #endif |
| } |