| typedef unsigned char uint8_t; |
| typedef signed char int8_t; |
| typedef unsigned short uint16_t; |
| typedef signed short int16_t; |
| typedef unsigned int uint32_t; |
| typedef signed int int32_t; |
| |
| typedef unsigned char uint_least8_t; |
| typedef signed char int_least8_t; |
| typedef unsigned short uint_least16_t; |
| typedef signed short int_least16_t; |
| typedef unsigned int uint_least32_t; |
| typedef signed int int_least32_t; |
| |
| typedef unsigned char uint_fast8_t; |
| typedef signed char int_fast8_t; |
| typedef unsigned int uint_fast16_t; |
| typedef signed int int_fast16_t; |
| typedef unsigned int uint_fast32_t; |
| typedef signed int int_fast32_t; |
| |
| typedef int intptr_t; |
| typedef unsigned int uintptr_t; |
| |
| typedef long int intmax_t; |
| typedef unsigned long int uintmax_t; |
| |
| static inline unsigned long apic_read(unsigned long reg) |
| { |
| return *((volatile unsigned long *)(0xfee00000 +reg)); |
| } |
| static inline void apic_write(unsigned long reg, unsigned long v) |
| { |
| *((volatile unsigned long *)(0xfee00000 +reg)) = v; |
| } |
| static inline void apic_wait_icr_idle(void) |
| { |
| do { } while ( apic_read( 0x300 ) & 0x01000 ); |
| } |
| |
| static void outb(unsigned char value, unsigned short port) |
| { |
| __builtin_outb(value, port); |
| } |
| static void outw(unsigned short value, unsigned short port) |
| { |
| __builtin_outw(value, port); |
| } |
| static void outl(unsigned int value, unsigned short port) |
| { |
| __builtin_outl(value, port); |
| } |
| static unsigned char inb(unsigned short port) |
| { |
| return __builtin_inb(port); |
| } |
| static unsigned char inw(unsigned short port) |
| { |
| return __builtin_inw(port); |
| } |
| static unsigned char inl(unsigned short port) |
| { |
| return __builtin_inl(port); |
| } |
| static inline void outsb(uint16_t port, const void *addr, unsigned long count) |
| { |
| __asm__ __volatile__ ( |
| "cld ; rep ; outsb " |
| : "=S" (addr), "=c" (count) |
| : "d"(port), "0"(addr), "1" (count) |
| ); |
| } |
| static inline void outsw(uint16_t port, const void *addr, unsigned long count) |
| { |
| __asm__ __volatile__ ( |
| "cld ; rep ; outsw " |
| : "=S" (addr), "=c" (count) |
| : "d"(port), "0"(addr), "1" (count) |
| ); |
| } |
| static inline void outsl(uint16_t port, const void *addr, unsigned long count) |
| { |
| __asm__ __volatile__ ( |
| "cld ; rep ; outsl " |
| : "=S" (addr), "=c" (count) |
| : "d"(port), "0"(addr), "1" (count) |
| ); |
| } |
| static inline void insb(uint16_t port, void *addr, unsigned long count) |
| { |
| __asm__ __volatile__ ( |
| "cld ; rep ; insb " |
| : "=D" (addr), "=c" (count) |
| : "d"(port), "0"(addr), "1" (count) |
| ); |
| } |
| static inline void insw(uint16_t port, void *addr, unsigned long count) |
| { |
| __asm__ __volatile__ ( |
| "cld ; rep ; insw " |
| : "=D" (addr), "=c" (count) |
| : "d"(port), "0"(addr), "1" (count) |
| ); |
| } |
| static inline void insl(uint16_t port, void *addr, unsigned long count) |
| { |
| __asm__ __volatile__ ( |
| "cld ; rep ; insl " |
| : "=D" (addr), "=c" (count) |
| : "d"(port), "0"(addr), "1" (count) |
| ); |
| } |
| static inline void pnp_write_config(unsigned char port, unsigned char value, unsigned char reg) |
| { |
| outb(reg, port); |
| outb(value, port +1); |
| } |
| static inline unsigned char pnp_read_config(unsigned char port, unsigned char reg) |
| { |
| outb(reg, port); |
| return inb(port +1); |
| } |
| static inline void pnp_set_logical_device(unsigned char port, int device) |
| { |
| pnp_write_config(port, device, 0x07); |
| } |
| static inline void pnp_set_enable(unsigned char port, int enable) |
| { |
| pnp_write_config(port, enable?0x1:0x0, 0x30); |
| } |
| static inline int pnp_read_enable(unsigned char port) |
| { |
| return !!pnp_read_config(port, 0x30); |
| } |
| static inline void pnp_set_iobase0(unsigned char port, unsigned iobase) |
| { |
| pnp_write_config(port, (iobase >> 8) & 0xff, 0x60); |
| pnp_write_config(port, iobase & 0xff, 0x61); |
| } |
| static inline void pnp_set_iobase1(unsigned char port, unsigned iobase) |
| { |
| pnp_write_config(port, (iobase >> 8) & 0xff, 0x62); |
| pnp_write_config(port, iobase & 0xff, 0x63); |
| } |
| static inline void pnp_set_irq0(unsigned char port, unsigned irq) |
| { |
| pnp_write_config(port, irq, 0x70); |
| } |
| static inline void pnp_set_irq1(unsigned char port, unsigned irq) |
| { |
| pnp_write_config(port, irq, 0x72); |
| } |
| static inline void pnp_set_drq(unsigned char port, unsigned drq) |
| { |
| pnp_write_config(port, drq & 0xff, 0x74); |
| } |
| static void hlt(void) |
| { |
| __builtin_hlt(); |
| } |
| typedef __builtin_div_t div_t; |
| typedef __builtin_ldiv_t ldiv_t; |
| typedef __builtin_udiv_t udiv_t; |
| typedef __builtin_uldiv_t uldiv_t; |
| static div_t div(int numer, int denom) |
| { |
| return __builtin_div(numer, denom); |
| } |
| static ldiv_t ldiv(long numer, long denom) |
| { |
| return __builtin_ldiv(numer, denom); |
| } |
| static udiv_t udiv(unsigned numer, unsigned denom) |
| { |
| return __builtin_udiv(numer, denom); |
| } |
| static uldiv_t uldiv(unsigned long numer, unsigned long denom) |
| { |
| return __builtin_uldiv(numer, denom); |
| } |
| int log2(int value) |
| { |
| |
| return __builtin_bsr(value); |
| } |
| typedef unsigned device_t; |
| static unsigned char pci_read_config8(device_t dev, unsigned where) |
| { |
| unsigned addr; |
| addr = dev | where; |
| outl(0x80000000 | (addr & ~3), 0xCF8); |
| return inb(0xCFC + (addr & 3)); |
| } |
| static unsigned short pci_read_config16(device_t dev, unsigned where) |
| { |
| unsigned addr; |
| addr = dev | where; |
| outl(0x80000000 | (addr & ~3), 0xCF8); |
| return inw(0xCFC + (addr & 2)); |
| } |
| static unsigned int pci_read_config32(device_t dev, unsigned where) |
| { |
| unsigned addr; |
| addr = dev | where; |
| outl(0x80000000 | (addr & ~3), 0xCF8); |
| return inl(0xCFC); |
| } |
| static void pci_write_config8(device_t dev, unsigned where, unsigned char value) |
| { |
| unsigned addr; |
| addr = dev | where; |
| outl(0x80000000 | (addr & ~3), 0xCF8); |
| outb(value, 0xCFC + (addr & 3)); |
| } |
| static void pci_write_config16(device_t dev, unsigned where, unsigned short value) |
| { |
| unsigned addr; |
| addr = dev | where; |
| outl(0x80000000 | (addr & ~3), 0xCF8); |
| outw(value, 0xCFC + (addr & 2)); |
| } |
| static void pci_write_config32(device_t dev, unsigned where, unsigned int value) |
| { |
| unsigned addr; |
| addr = dev | where; |
| outl(0x80000000 | (addr & ~3), 0xCF8); |
| outl(value, 0xCFC); |
| } |
| static device_t pci_locate_device(unsigned pci_id, device_t dev) |
| { |
| for(; dev <= ( ((( 255 ) & 0xFF) << 16) | ((( 31 ) & 0x1f) << 11) | ((( 7 ) & 0x7) << 8)) ; dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) { |
| unsigned int id; |
| id = pci_read_config32(dev, 0); |
| if (id == pci_id) { |
| return dev; |
| } |
| } |
| return (0xffffffffU) ; |
| } |
| |
| |
| |
| |
| |
| static int uart_can_tx_byte(void) |
| { |
| return inb(1016 + 0x05 ) & 0x20; |
| } |
| static void uart_wait_to_tx_byte(void) |
| { |
| while(!uart_can_tx_byte()) |
| ; |
| } |
| static void uart_wait_until_sent(void) |
| { |
| while(!(inb(1016 + 0x05 ) & 0x40)) |
| ; |
| } |
| static void uart_tx_byte(unsigned char data) |
| { |
| uart_wait_to_tx_byte(); |
| outb(data, 1016 + 0x00 ); |
| |
| uart_wait_until_sent(); |
| } |
| static void uart_init(void) |
| { |
| |
| outb(0x0, 1016 + 0x01 ); |
| |
| outb(0x01, 1016 + 0x02 ); |
| |
| outb(0x80 | 3 , 1016 + 0x03 ); |
| outb((115200/ 115200 ) & 0xFF, 1016 + 0x00 ); |
| outb(((115200/ 115200 ) >> 8) & 0xFF, 1016 + 0x01 ); |
| outb(3 , 1016 + 0x03 ); |
| } |
| |
| static void __console_tx_byte(unsigned char byte) |
| { |
| uart_tx_byte(byte); |
| } |
| static void __console_tx_nibble(unsigned nibble) |
| { |
| unsigned char digit; |
| digit = nibble + '0'; |
| if (digit > '9') { |
| digit += 39; |
| } |
| __console_tx_byte(digit); |
| } |
| static void __console_tx_char(int loglevel, unsigned char byte) |
| { |
| if (8 > loglevel) { |
| uart_tx_byte(byte); |
| } |
| } |
| static void __console_tx_hex8(int loglevel, unsigned char value) |
| { |
| if (8 > loglevel) { |
| __console_tx_nibble((value >> 4U) & 0x0fU); |
| __console_tx_nibble(value & 0x0fU); |
| } |
| } |
| static void __console_tx_hex16(int loglevel, unsigned short value) |
| { |
| if (8 > loglevel) { |
| __console_tx_nibble((value >> 12U) & 0x0fU); |
| __console_tx_nibble((value >> 8U) & 0x0fU); |
| __console_tx_nibble((value >> 4U) & 0x0fU); |
| __console_tx_nibble(value & 0x0fU); |
| } |
| } |
| static void __console_tx_hex32(int loglevel, unsigned int value) |
| { |
| if (8 > loglevel) { |
| __console_tx_nibble((value >> 28U) & 0x0fU); |
| __console_tx_nibble((value >> 24U) & 0x0fU); |
| __console_tx_nibble((value >> 20U) & 0x0fU); |
| __console_tx_nibble((value >> 16U) & 0x0fU); |
| __console_tx_nibble((value >> 12U) & 0x0fU); |
| __console_tx_nibble((value >> 8U) & 0x0fU); |
| __console_tx_nibble((value >> 4U) & 0x0fU); |
| __console_tx_nibble(value & 0x0fU); |
| } |
| } |
| static void __console_tx_string(int loglevel, const char *str) |
| { |
| if (8 > loglevel) { |
| unsigned char ch; |
| while((ch = *str++) != '\0') { |
| __console_tx_byte(ch); |
| } |
| } |
| } |
| static void print_emerg_char(unsigned char byte) { __console_tx_char(0 , byte); } |
| static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(0 , value); } |
| static void print_emerg_hex16(unsigned short value){ __console_tx_hex16(0 , value); } |
| static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(0 , value); } |
| static void print_emerg(const char *str) { __console_tx_string(0 , str); } |
| static void print_alert_char(unsigned char byte) { __console_tx_char(1 , byte); } |
| static void print_alert_hex8(unsigned char value) { __console_tx_hex8(1 , value); } |
| static void print_alert_hex16(unsigned short value){ __console_tx_hex16(1 , value); } |
| static void print_alert_hex32(unsigned int value) { __console_tx_hex32(1 , value); } |
| static void print_alert(const char *str) { __console_tx_string(1 , str); } |
| static void print_crit_char(unsigned char byte) { __console_tx_char(2 , byte); } |
| static void print_crit_hex8(unsigned char value) { __console_tx_hex8(2 , value); } |
| static void print_crit_hex16(unsigned short value){ __console_tx_hex16(2 , value); } |
| static void print_crit_hex32(unsigned int value) { __console_tx_hex32(2 , value); } |
| static void print_crit(const char *str) { __console_tx_string(2 , str); } |
| static void print_err_char(unsigned char byte) { __console_tx_char(3 , byte); } |
| static void print_err_hex8(unsigned char value) { __console_tx_hex8(3 , value); } |
| static void print_err_hex16(unsigned short value){ __console_tx_hex16(3 , value); } |
| static void print_err_hex32(unsigned int value) { __console_tx_hex32(3 , value); } |
| static void print_err(const char *str) { __console_tx_string(3 , str); } |
| static void print_warning_char(unsigned char byte) { __console_tx_char(4 , byte); } |
| static void print_warning_hex8(unsigned char value) { __console_tx_hex8(4 , value); } |
| static void print_warning_hex16(unsigned short value){ __console_tx_hex16(4 , value); } |
| static void print_warning_hex32(unsigned int value) { __console_tx_hex32(4 , value); } |
| static void print_warning(const char *str) { __console_tx_string(4 , str); } |
| static void print_notice_char(unsigned char byte) { __console_tx_char(5 , byte); } |
| static void print_notice_hex8(unsigned char value) { __console_tx_hex8(5 , value); } |
| static void print_notice_hex16(unsigned short value){ __console_tx_hex16(5 , value); } |
| static void print_notice_hex32(unsigned int value) { __console_tx_hex32(5 , value); } |
| static void print_notice(const char *str) { __console_tx_string(5 , str); } |
| static void print_info_char(unsigned char byte) { __console_tx_char(6 , byte); } |
| static void print_info_hex8(unsigned char value) { __console_tx_hex8(6 , value); } |
| static void print_info_hex16(unsigned short value){ __console_tx_hex16(6 , value); } |
| static void print_info_hex32(unsigned int value) { __console_tx_hex32(6 , value); } |
| static void print_info(const char *str) { __console_tx_string(6 , str); } |
| static void print_debug_char(unsigned char byte) { __console_tx_char(7 , byte); } |
| static void print_debug_hex8(unsigned char value) { __console_tx_hex8(7 , value); } |
| static void print_debug_hex16(unsigned short value){ __console_tx_hex16(7 , value); } |
| static void print_debug_hex32(unsigned int value) { __console_tx_hex32(7 , value); } |
| static void print_debug(const char *str) { __console_tx_string(7 , str); } |
| static void print_spew_char(unsigned char byte) { __console_tx_char(8 , byte); } |
| static void print_spew_hex8(unsigned char value) { __console_tx_hex8(8 , value); } |
| static void print_spew_hex16(unsigned short value){ __console_tx_hex16(8 , value); } |
| static void print_spew_hex32(unsigned int value) { __console_tx_hex32(8 , value); } |
| static void print_spew(const char *str) { __console_tx_string(8 , str); } |
| static void console_init(void) |
| { |
| static const char console_test[] = |
| "\r\n\r\nLinuxBIOS-" |
| "1.1.4" |
| ".0Fallback" |
| " " |
| "Thu Oct 9 20:29:48 MDT 2003" |
| " starting...\r\n"; |
| print_info(console_test); |
| } |
| static void die(const char *str) |
| { |
| print_emerg(str); |
| do { |
| hlt(); |
| } while(1); |
| } |
| static void write_phys(unsigned long addr, unsigned long value) |
| { |
| asm volatile( |
| "movnti %1, (%0)" |
| : |
| : "r" (addr), "r" (value) |
| : |
| ); |
| } |
| static unsigned long read_phys(unsigned long addr) |
| { |
| volatile unsigned long *ptr; |
| ptr = (void *)addr; |
| return *ptr; |
| } |
| static void ram_fill(unsigned long start, unsigned long stop) |
| { |
| unsigned long addr; |
| |
| print_debug("DRAM fill: "); |
| print_debug_hex32(start); |
| print_debug("-"); |
| print_debug_hex32(stop); |
| print_debug("\r\n"); |
| for(addr = start; addr < stop ; addr += 4) { |
| |
| if (!(addr & 0xffff)) { |
| print_debug_hex32(addr); |
| print_debug("\r"); |
| } |
| write_phys(addr, addr); |
| }; |
| |
| print_debug_hex32(addr); |
| print_debug("\r\nDRAM filled\r\n"); |
| } |
| static void ram_verify(unsigned long start, unsigned long stop) |
| { |
| unsigned long addr; |
| |
| print_debug("DRAM verify: "); |
| print_debug_hex32(start); |
| print_debug_char('-'); |
| print_debug_hex32(stop); |
| print_debug("\r\n"); |
| for(addr = start; addr < stop ; addr += 4) { |
| unsigned long value; |
| |
| if (!(addr & 0xffff)) { |
| print_debug_hex32(addr); |
| print_debug("\r"); |
| } |
| value = read_phys(addr); |
| if (value != addr) { |
| |
| print_err_hex32(addr); |
| print_err_char(':'); |
| print_err_hex32(value); |
| print_err("\r\n"); |
| } |
| } |
| |
| print_debug_hex32(addr); |
| print_debug("\r\nDRAM verified\r\n"); |
| } |
| void ram_check(unsigned long start, unsigned long stop) |
| { |
| int result; |
| |
| print_debug("Testing DRAM : "); |
| print_debug_hex32(start); |
| print_debug("-"); |
| print_debug_hex32(stop); |
| print_debug("\r\n"); |
| ram_fill(start, stop); |
| ram_verify(start, stop); |
| print_debug("Done.\r\n"); |
| } |
| static int enumerate_ht_chain(unsigned link) |
| { |
| |
| unsigned next_unitid, last_unitid; |
| int reset_needed = 0; |
| next_unitid = 1; |
| do { |
| uint32_t id; |
| uint8_t hdr_type, pos; |
| last_unitid = next_unitid; |
| id = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x00 ); |
| |
| if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || |
| (((id >> 16) & 0xffff) == 0xffff) || |
| (((id >> 16) & 0xffff) == 0x0000)) { |
| break; |
| } |
| hdr_type = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x0e ); |
| pos = 0; |
| hdr_type &= 0x7f; |
| if ((hdr_type == 0 ) || |
| (hdr_type == 1 )) { |
| pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x34 ); |
| } |
| while(pos != 0) { |
| uint8_t cap; |
| cap = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 0 ); |
| if (cap == 0x08 ) { |
| uint16_t flags; |
| flags = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 2 ); |
| if ((flags >> 13) == 0) { |
| unsigned count; |
| flags &= ~0x1f; |
| flags |= next_unitid & 0x1f; |
| count = (flags >> 5) & 0x1f; |
| pci_write_config16(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 2 , flags); |
| next_unitid += count; |
| break; |
| } |
| } |
| pos = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , pos + 1 ); |
| } |
| } while((last_unitid != next_unitid) && (next_unitid <= 0x1f)); |
| return reset_needed; |
| } |
| static void enable_smbus(void) |
| { |
| device_t dev; |
| dev = pci_locate_device((((( 0x746b ) & 0xFFFF) << 16) | (( 0x1022 ) & 0xFFFF)) , 0); |
| if (dev == (0xffffffffU) ) { |
| die("SMBUS controller not found\r\n"); |
| } |
| uint8_t enable; |
| print_debug("SMBus controller enabled\r\n"); |
| pci_write_config32(dev, 0x58, 0x0f00 | 1); |
| enable = pci_read_config8(dev, 0x41); |
| pci_write_config8(dev, 0x41, enable | (1 << 7)); |
| |
| outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 ); |
| } |
| static inline void smbus_delay(void) |
| { |
| outb(0x80, 0x80); |
| } |
| static int smbus_wait_until_ready(void) |
| { |
| unsigned long loops; |
| loops = (100*1000*10) ; |
| do { |
| unsigned short val; |
| smbus_delay(); |
| val = inw(0x0f00 + 0xe0 ); |
| if ((val & 0x800) == 0) { |
| break; |
| } |
| if(loops == ((100*1000*10) / 2)) { |
| outw(inw(0x0f00 + 0xe0 ), |
| 0x0f00 + 0xe0 ); |
| } |
| } while(--loops); |
| return loops?0:-2; |
| } |
| static int smbus_wait_until_done(void) |
| { |
| unsigned long loops; |
| loops = (100*1000*10) ; |
| do { |
| unsigned short val; |
| smbus_delay(); |
| |
| val = inw(0x0f00 + 0xe0 ); |
| if (((val & 0x8) == 0) | ((val & 0x437) != 0)) { |
| break; |
| } |
| } while(--loops); |
| return loops?0:-3; |
| } |
| static int smbus_read_byte(unsigned device, unsigned address) |
| { |
| unsigned char global_control_register; |
| unsigned char global_status_register; |
| unsigned char byte; |
| if (smbus_wait_until_ready() < 0) { |
| return -2; |
| } |
| |
| |
| |
| outw(inw(0x0f00 + 0xe2 ) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), 0x0f00 + 0xe2 ); |
| |
| outw(((device & 0x7f) << 1) | 1, 0x0f00 + 0xe4 ); |
| |
| outb(address & 0xFF, 0x0f00 + 0xe8 ); |
| |
| outw((inw(0x0f00 + 0xe2 ) & ~7) | (0x2), 0x0f00 + 0xe2 ); |
| |
| |
| outw(inw(0x0f00 + 0xe0 ), 0x0f00 + 0xe0 ); |
| |
| outw(0, 0x0f00 + 0xe6 ); |
| |
| outw((inw(0x0f00 + 0xe2 ) | (1 << 3)), 0x0f00 + 0xe2 ); |
| |
| if (smbus_wait_until_done() < 0) { |
| return -3; |
| } |
| global_status_register = inw(0x0f00 + 0xe0 ); |
| |
| byte = inw(0x0f00 + 0xe6 ) & 0xff; |
| if (global_status_register != (1 << 4)) { |
| return -1; |
| } |
| return byte; |
| } |
| static void smbus_write_byte(unsigned device, unsigned address, unsigned char val) |
| { |
| return; |
| } |
| struct mem_controller { |
| unsigned node_id; |
| device_t f0, f1, f2, f3; |
| uint8_t channel0[4]; |
| uint8_t channel1[4]; |
| }; |
| typedef __builtin_msr_t msr_t; |
| static msr_t rdmsr(unsigned long index) |
| { |
| return __builtin_rdmsr(index); |
| } |
| static void wrmsr(unsigned long index, msr_t msr) |
| { |
| __builtin_wrmsr(index, msr.lo, msr.hi); |
| } |
| struct tsc_struct { |
| unsigned lo; |
| unsigned hi; |
| }; |
| typedef struct tsc_struct tsc_t; |
| static tsc_t rdtsc(void) |
| { |
| tsc_t res; |
| asm ("rdtsc" |
| : "=a" (res.lo), "=d"(res.hi) |
| : |
| : |
| ); |
| return res; |
| } |
| void init_timer(void) |
| { |
| |
| apic_write(0x320 , (1 << 17)|(1<< 16)|(0 << 12)|(0 << 0)); |
| |
| apic_write(0x3E0 , 0xB ); |
| |
| apic_write(0x380 , 0xffffffff); |
| } |
| void udelay(unsigned usecs) |
| { |
| uint32_t start, value, ticks; |
| |
| ticks = usecs * 200; |
| start = apic_read(0x390 ); |
| do { |
| value = apic_read(0x390 ); |
| } while((start - value) < ticks); |
| |
| } |
| void mdelay(unsigned msecs) |
| { |
| unsigned i; |
| for(i = 0; i < msecs; i++) { |
| udelay(1000); |
| } |
| } |
| void delay(unsigned secs) |
| { |
| unsigned i; |
| for(i = 0; i < secs; i++) { |
| mdelay(1000); |
| } |
| } |
| int boot_cpu(void) |
| { |
| volatile unsigned long *local_apic; |
| unsigned long apic_id; |
| int bsp; |
| msr_t msr; |
| msr = rdmsr(0x1b); |
| bsp = !!(msr.lo & (1 << 8)); |
| return bsp; |
| } |
| static int cpu_init_detected(void) |
| { |
| unsigned long htic; |
| htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); |
| return !!(htic & (1<<6) ); |
| } |
| static int bios_reset_detected(void) |
| { |
| unsigned long htic; |
| htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); |
| return (htic & (1<<4) ) && !(htic & (1<<5) ); |
| } |
| static int cold_reset_detected(void) |
| { |
| unsigned long htic; |
| htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); |
| return !(htic & (1<<4) ); |
| } |
| static void distinguish_cpu_resets(unsigned node_id) |
| { |
| uint32_t htic; |
| device_t device; |
| device = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 + node_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ; |
| htic = pci_read_config32(device, 0x6c ); |
| htic |= (1<<4) | (1<<5) | (1<<6) ; |
| pci_write_config32(device, 0x6c , htic); |
| } |
| static void set_bios_reset(void) |
| { |
| unsigned long htic; |
| htic = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c ); |
| htic &= ~(1<<5) ; |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c , htic); |
| } |
| static void print_debug_pci_dev(unsigned dev) |
| { |
| print_debug("PCI: "); |
| print_debug_hex8((dev >> 16) & 0xff); |
| print_debug_char(':'); |
| print_debug_hex8((dev >> 11) & 0x1f); |
| print_debug_char('.'); |
| print_debug_hex8((dev >> 8) & 7); |
| } |
| static void print_pci_devices(void) |
| { |
| device_t dev; |
| for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ; |
| dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ; |
| dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) { |
| uint32_t id; |
| id = pci_read_config32(dev, 0x00 ); |
| if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || |
| (((id >> 16) & 0xffff) == 0xffff) || |
| (((id >> 16) & 0xffff) == 0x0000)) { |
| continue; |
| } |
| print_debug_pci_dev(dev); |
| print_debug("\r\n"); |
| } |
| } |
| static void dump_pci_device(unsigned dev) |
| { |
| int i; |
| print_debug_pci_dev(dev); |
| print_debug("\r\n"); |
| |
| for(i = 0; i <= 255; i++) { |
| unsigned char val; |
| if ((i & 0x0f) == 0) { |
| print_debug_hex8(i); |
| print_debug_char(':'); |
| } |
| val = pci_read_config8(dev, i); |
| print_debug_char(' '); |
| print_debug_hex8(val); |
| if ((i & 0x0f) == 0x0f) { |
| print_debug("\r\n"); |
| } |
| } |
| } |
| static void dump_pci_devices(void) |
| { |
| device_t dev; |
| for(dev = ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ; |
| dev <= ( ((( 0 ) & 0xFF) << 16) | ((( 0x1f ) & 0x1f) << 11) | ((( 0x7 ) & 0x7) << 8)) ; |
| dev += ( ((( 0 ) & 0xFF) << 16) | ((( 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) ) { |
| uint32_t id; |
| id = pci_read_config32(dev, 0x00 ); |
| if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || |
| (((id >> 16) & 0xffff) == 0xffff) || |
| (((id >> 16) & 0xffff) == 0x0000)) { |
| continue; |
| } |
| dump_pci_device(dev); |
| } |
| } |
| static void dump_spd_registers(const struct mem_controller *ctrl) |
| { |
| int i; |
| print_debug("\r\n"); |
| for(i = 0; i < 4; i++) { |
| unsigned device; |
| device = ctrl->channel0[i]; |
| if (device) { |
| int j; |
| print_debug("dimm: "); |
| print_debug_hex8(i); |
| print_debug(".0: "); |
| print_debug_hex8(device); |
| for(j = 0; j < 256; j++) { |
| int status; |
| unsigned char byte; |
| if ((j & 0xf) == 0) { |
| print_debug("\r\n"); |
| print_debug_hex8(j); |
| print_debug(": "); |
| } |
| status = smbus_read_byte(device, j); |
| if (status < 0) { |
| print_debug("bad device\r\n"); |
| break; |
| } |
| byte = status & 0xff; |
| print_debug_hex8(byte); |
| print_debug_char(' '); |
| } |
| print_debug("\r\n"); |
| } |
| device = ctrl->channel1[i]; |
| if (device) { |
| int j; |
| print_debug("dimm: "); |
| print_debug_hex8(i); |
| print_debug(".1: "); |
| print_debug_hex8(device); |
| for(j = 0; j < 256; j++) { |
| int status; |
| unsigned char byte; |
| if ((j & 0xf) == 0) { |
| print_debug("\r\n"); |
| print_debug_hex8(j); |
| print_debug(": "); |
| } |
| status = smbus_read_byte(device, j); |
| if (status < 0) { |
| print_debug("bad device\r\n"); |
| break; |
| } |
| byte = status & 0xff; |
| print_debug_hex8(byte); |
| print_debug_char(' '); |
| } |
| print_debug("\r\n"); |
| } |
| } |
| } |
| |
| static unsigned int cpuid(unsigned int op) |
| { |
| unsigned int ret; |
| unsigned dummy2,dummy3,dummy4; |
| asm volatile ( |
| "cpuid" |
| : "=a" (ret), "=b" (dummy2), "=c" (dummy3), "=d" (dummy4) |
| : "a" (op) |
| ); |
| return ret; |
| } |
| static int is_cpu_rev_a0(void) |
| { |
| return (cpuid(1) & 0xffff) == 0x0f10; |
| } |
| static int is_cpu_pre_c0(void) |
| { |
| return (cpuid(1) & 0xffef) < 0x0f48; |
| } |
| static void memreset_setup(void) |
| { |
| if (is_cpu_pre_c0()) { |
| |
| outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 28); |
| |
| outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0x0f00 + 0xc0 + 29); |
| } |
| else { |
| |
| outb((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 29); |
| } |
| } |
| static void memreset(int controllers, const struct mem_controller *ctrl) |
| { |
| if (is_cpu_pre_c0()) { |
| udelay(800); |
| |
| outb((0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0x0f00 + 0xc0 + 28); |
| udelay(90); |
| } |
| } |
| static unsigned int generate_row(uint8_t node, uint8_t row, uint8_t maxnodes) |
| { |
| |
| uint32_t ret=0x00010101; |
| static const unsigned int rows_2p[2][2] = { |
| { 0x00050101, 0x00010404 }, |
| { 0x00010404, 0x00050101 } |
| }; |
| if(maxnodes>2) { |
| print_debug("this mainboard is only designed for 2 cpus\r\n"); |
| maxnodes=2; |
| } |
| if (!(node>=maxnodes || row>=maxnodes)) { |
| ret=rows_2p[node][row]; |
| } |
| return ret; |
| } |
| static inline int spd_read_byte(unsigned device, unsigned address) |
| { |
| return smbus_read_byte(device, address); |
| } |
| |
| static void coherent_ht_mainboard(unsigned cpus) |
| { |
| } |
| |
| void cpu_ldtstop(unsigned cpus) |
| { |
| uint32_t tmp; |
| device_t dev; |
| unsigned cnt; |
| for(cnt=0; cnt<cpus; cnt++) { |
| |
| pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0x81,0x23); |
| |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd4,0x00000701); |
| |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) ,0xd8,0x00000000); |
| |
| tmp=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) ,0x90, tmp | (1<<24) ); |
| } |
| } |
| |
| |
| |
| |
| |
| static void setup_resource_map(const unsigned int *register_values, int max) |
| { |
| int i; |
| print_debug("setting up resource map....\r\n"); |
| for(i = 0; i < max; i += 3) { |
| device_t dev; |
| unsigned where; |
| unsigned long reg; |
| dev = register_values[i] & ~0xff; |
| where = register_values[i] & 0xff; |
| reg = pci_read_config32(dev, where); |
| reg &= register_values[i+1]; |
| reg |= register_values[i+2]; |
| pci_write_config32(dev, where, reg); |
| } |
| print_debug("done.\r\n"); |
| } |
| static void setup_default_resource_map(void) |
| { |
| static const unsigned int register_values[] = { |
| |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x0000f8f8, 0x00000001, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x0000f8f8, 0x00000002, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000f8f8, 0x00000003, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0x0000f8f8, 0x00000004, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0x0000f8f8, 0x00000005, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0x0000f8f8, 0x00000006, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0x0000f8f8, 0x00000007, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x84 ) & 0xFF)) , 0x00000048, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x8C ) & 0xFF)) , 0x00000048, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0x00000048, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x9C ) & 0xFF)) , 0x00000048, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA4 ) & 0xFF)) , 0x00000048, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xAC ) & 0xFF)) , 0x00000048, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB4 ) & 0xFF)) , 0x00000048, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xBC ) & 0xFF)) , 0x00000048, 0x00ffff00, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0x000000f0, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0x000000f0, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0x000000f0, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0x000000f0, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA0 ) & 0xFF)) , 0x000000f0, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xA8 ) & 0xFF)) , 0x000000f0, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB0 ) & 0xFF)) , 0x000000f0, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xB8 ) & 0xFF)) , 0x000000f0, 0x00fc0003, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC4 ) & 0xFF)) , 0xFE000FC8, 0x01fff000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xCC ) & 0xFF)) , 0xFE000FC8, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD4 ) & 0xFF)) , 0xFE000FC8, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xDC ) & 0xFF)) , 0xFE000FC8, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC0 ) & 0xFF)) , 0xFE000FCC, 0x00000003, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xC8 ) & 0xFF)) , 0xFE000FCC, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD0 ) & 0xFF)) , 0xFE000FCC, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xD8 ) & 0xFF)) , 0xFE000FCC, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE0 ) & 0xFF)) , 0x0000FC88, 0xff000003, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE4 ) & 0xFF)) , 0x0000FC88, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xE8 ) & 0xFF)) , 0x0000FC88, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0xEC ) & 0xFF)) , 0x0000FC88, 0x00000000, |
| }; |
| int max; |
| max = sizeof(register_values)/sizeof(register_values[0]); |
| setup_resource_map(register_values, max); |
| } |
| static void sdram_set_registers(const struct mem_controller *ctrl) |
| { |
| static const unsigned int register_values[] = { |
| |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x0000f8f8, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x0000f8f8, 0x00000001, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x0000f8f8, 0x00000002, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000f8f8, 0x00000003, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0x0000f8f8, 0x00000004, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0x0000f8f8, 0x00000005, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0x0000f8f8, 0x00000006, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0x0000f8f8, 0x00000007, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0x0000f8fc, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x40 ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x44 ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x48 ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x4C ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x50 ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x54 ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x001f01fe, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x64 ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x68 ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x6C ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x70 ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x74 ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x78 ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x7C ) & 0xFF)) , 0xC01f01ff, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x80 ) & 0xFF)) , 0xffff8888, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x88 ) & 0xFF)) , 0xe8088008, 0x02522001 , |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x8c ) & 0xFF)) , 0xff8fe08e, (0 << 20)|(0 << 8)|(0 << 4)|(0 << 0), |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0xf0000000, |
| (4 << 25)|(0 << 24)| |
| (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)| |
| (1 << 19)|(0 << 18)|(1 << 17)|(0 << 16)| |
| (2 << 14)|(0 << 13)|(0 << 12)| |
| (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)| |
| (0 << 3) |(0 << 1) |(0 << 0), |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xc180f0f0, |
| (0 << 29)|(0 << 28)|(0 << 27)|(0 << 26)|(0 << 25)| |
| (0 << 20)|(0 << 19)|(3 << 16)|(0 << 8)|(0 << 0), |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0xfc00ffff, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x58 ) & 0xFF)) , 0xffe0e0e0, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x5C ) & 0xFF)) , 0x0000003e, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x60 ) & 0xFF)) , 0xffffff00, 0x00000000, |
| |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x94 ) & 0xFF)) , 0xffff8000, 0x00000f70, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x90 ) & 0xFF)) , 0xffffff80, 0x00000002, |
| ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x07) << 8) | (( 0x98 ) & 0xFF)) , 0x0000000f, 0x00068300, |
| }; |
| int i; |
| int max; |
| print_debug("setting up CPU"); |
| print_debug_hex8(ctrl->node_id); |
| print_debug(" northbridge registers\r\n"); |
| max = sizeof(register_values)/sizeof(register_values[0]); |
| for(i = 0; i < max; i += 3) { |
| device_t dev; |
| unsigned where; |
| unsigned long reg; |
| dev = (register_values[i] & ~0xff) - ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) + ctrl->f0; |
| where = register_values[i] & 0xff; |
| reg = pci_read_config32(dev, where); |
| reg &= register_values[i+1]; |
| reg |= register_values[i+2]; |
| pci_write_config32(dev, where, reg); |
| } |
| print_debug("done.\r\n"); |
| } |
| static int is_dual_channel(const struct mem_controller *ctrl) |
| { |
| uint32_t dcl; |
| dcl = pci_read_config32(ctrl->f2, 0x90 ); |
| return dcl & (1<<16) ; |
| } |
| static int is_opteron(const struct mem_controller *ctrl) |
| { |
| |
| uint32_t nbcap; |
| nbcap = pci_read_config32(ctrl->f3, 0xE8 ); |
| return !!(nbcap & 0x0001 ); |
| } |
| static int is_registered(const struct mem_controller *ctrl) |
| { |
| |
| uint32_t dcl; |
| dcl = pci_read_config32(ctrl->f2, 0x90 ); |
| return !(dcl & (1<<18) ); |
| } |
| struct dimm_size { |
| unsigned long side1; |
| unsigned long side2; |
| }; |
| static struct dimm_size spd_get_dimm_size(unsigned device) |
| { |
| |
| struct dimm_size sz; |
| int value, low; |
| sz.side1 = 0; |
| sz.side2 = 0; |
| |
| value = spd_read_byte(device, 3); |
| if (value < 0) goto out; |
| sz.side1 += value & 0xf; |
| value = spd_read_byte(device, 4); |
| if (value < 0) goto out; |
| sz.side1 += value & 0xf; |
| value = spd_read_byte(device, 17); |
| if (value < 0) goto out; |
| sz.side1 += log2(value & 0xff); |
| |
| value = spd_read_byte(device, 7); |
| if (value < 0) goto out; |
| value &= 0xff; |
| value <<= 8; |
| |
| low = spd_read_byte(device, 6); |
| if (low < 0) goto out; |
| value = value | (low & 0xff); |
| sz.side1 += log2(value); |
| |
| value = spd_read_byte(device, 5); |
| if (value <= 1) goto out; |
| |
| sz.side2 = sz.side1; |
| value = spd_read_byte(device, 3); |
| if (value < 0) goto out; |
| if ((value & 0xf0) == 0) goto out; |
| sz.side2 -= (value & 0x0f); |
| sz.side2 += ((value >> 4) & 0x0f); |
| value = spd_read_byte(device, 4); |
| if (value < 0) goto out; |
| sz.side2 -= (value & 0x0f); |
| sz.side2 += ((value >> 4) & 0x0f); |
| out: |
| return sz; |
| } |
| static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz, unsigned index) |
| { |
| uint32_t base0, base1, map; |
| uint32_t dch; |
| if (sz.side1 != sz.side2) { |
| sz.side2 = 0; |
| } |
| map = pci_read_config32(ctrl->f2, 0x80 ); |
| map &= ~(0xf << (index + 4)); |
| |
| |
| base0 = base1 = 0; |
| |
| if (sz.side1 >= (25 +3)) { |
| map |= (sz.side1 - (25 + 3)) << (index *4); |
| base0 = (1 << ((sz.side1 - (25 + 3)) + 21)) | 1; |
| } |
| |
| if (sz.side2 >= (25 + 3)) { |
| base1 = (1 << ((sz.side2 - (25 + 3)) + 21)) | 1; |
| } |
| |
| if (is_dual_channel(ctrl)) { |
| base0 = (base0 << 1) | (base0 & 1); |
| base1 = (base1 << 1) | (base1 & 1); |
| } |
| |
| base0 &= ~0x001ffffe; |
| base1 &= ~0x001ffffe; |
| |
| pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), base0); |
| pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), base1); |
| pci_write_config32(ctrl->f2, 0x80 , map); |
| |
| |
| if (base0) { |
| dch = pci_read_config32(ctrl->f2, 0x94 ); |
| dch |= (1 << 26) << index; |
| pci_write_config32(ctrl->f2, 0x94 , dch); |
| } |
| } |
| static void spd_set_ram_size(const struct mem_controller *ctrl) |
| { |
| int i; |
| |
| for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { |
| struct dimm_size sz; |
| sz = spd_get_dimm_size(ctrl->channel0[i]); |
| set_dimm_size(ctrl, sz, i); |
| } |
| } |
| static void route_dram_accesses(const struct mem_controller *ctrl, |
| unsigned long base_k, unsigned long limit_k) |
| { |
| |
| unsigned node_id; |
| unsigned limit; |
| unsigned base; |
| unsigned index; |
| unsigned limit_reg, base_reg; |
| device_t device; |
| node_id = ctrl->node_id; |
| index = (node_id << 3); |
| limit = (limit_k << 2); |
| limit &= 0xffff0000; |
| limit -= 0x00010000; |
| limit |= ( 0 << 8) | (node_id << 0); |
| base = (base_k << 2); |
| base &= 0xffff0000; |
| base |= (0 << 8) | (1<<1) | (1<<0); |
| limit_reg = 0x44 + index; |
| base_reg = 0x40 + index; |
| 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)) ) { |
| pci_write_config32(device, limit_reg, limit); |
| pci_write_config32(device, base_reg, base); |
| } |
| } |
| static void set_top_mem(unsigned tom_k) |
| { |
| |
| if (!tom_k) { |
| set_bios_reset(); |
| print_debug("No memory - reset"); |
| |
| pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 0x04 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0x41, 0xf1); |
| |
| outb(0x0e, 0x0cf9); |
| } |
| |
| print_debug("RAM: 0x"); |
| print_debug_hex32(tom_k); |
| print_debug(" KB\r\n"); |
| |
| msr_t msr; |
| msr.lo = (tom_k & 0x003fffff) << 10; |
| msr.hi = (tom_k & 0xffc00000) >> 22; |
| wrmsr(0xC001001D , msr); |
| |
| if (tom_k >= 0x003f0000) { |
| tom_k = 0x3f0000; |
| } |
| msr.lo = (tom_k & 0x003fffff) << 10; |
| msr.hi = (tom_k & 0xffc00000) >> 22; |
| wrmsr(0xC001001A , msr); |
| } |
| static unsigned long interleave_chip_selects(const struct mem_controller *ctrl) |
| { |
| |
| static const uint32_t csbase_low[] = { |
| (1 << (13 - 4)), |
| (1 << (14 - 4)), |
| (1 << (14 - 4)), |
| (1 << (15 - 4)), |
| (1 << (15 - 4)), |
| (1 << (16 - 4)), |
| (1 << (16 - 4)), |
| }; |
| uint32_t csbase_inc; |
| int chip_selects, index; |
| int bits; |
| int dual_channel; |
| unsigned common_size; |
| uint32_t csbase, csmask; |
| |
| chip_selects = 0; |
| common_size = 0; |
| for(index = 0; index < 8; index++) { |
| unsigned size; |
| uint32_t value; |
| |
| value = pci_read_config32(ctrl->f2, 0x40 + (index << 2)); |
| |
| |
| if (!(value & 1)) { |
| continue; |
| } |
| chip_selects++; |
| size = value >> 21; |
| if (common_size == 0) { |
| common_size = size; |
| } |
| |
| if (common_size != size) { |
| return 0; |
| } |
| } |
| |
| bits = log2(chip_selects); |
| if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) { |
| return 0; |
| |
| } |
| |
| if ((bits == 3) && (common_size == (1 << (32 - 3)))) { |
| print_debug("8 4GB chip selects cannot be interleaved\r\n"); |
| return 0; |
| } |
| |
| if (is_dual_channel(ctrl)) { |
| csbase_inc = csbase_low[log2(common_size) - 1] << 1; |
| } else { |
| csbase_inc = csbase_low[log2(common_size)]; |
| } |
| |
| csbase = 0 | 1; |
| csmask = (((common_size << bits) - 1) << 21); |
| csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc); |
| for(index = 0; index < 8; index++) { |
| uint32_t value; |
| value = pci_read_config32(ctrl->f2, 0x40 + (index << 2)); |
| |
| if (!(value & 1)) { |
| continue; |
| } |
| pci_write_config32(ctrl->f2, 0x40 + (index << 2), csbase); |
| pci_write_config32(ctrl->f2, 0x60 + (index << 2), csmask); |
| csbase += csbase_inc; |
| } |
| |
| print_debug("Interleaved\r\n"); |
| |
| return common_size << (15 + bits); |
| } |
| static unsigned long order_chip_selects(const struct mem_controller *ctrl) |
| { |
| unsigned long tom; |
| |
| |
| tom = 0; |
| for(;;) { |
| |
| unsigned index, canidate; |
| uint32_t csbase, csmask; |
| unsigned size; |
| csbase = 0; |
| canidate = 0; |
| for(index = 0; index < 8; index++) { |
| uint32_t value; |
| value = pci_read_config32(ctrl->f2, 0x40 + (index << 2)); |
| |
| if (!(value & 1)) { |
| continue; |
| } |
| |
| |
| if (value <= csbase) { |
| continue; |
| } |
| |
| |
| if (tom & (1 << (index + 24))) { |
| continue; |
| } |
| |
| csbase = value; |
| canidate = index; |
| } |
| |
| if (csbase == 0) { |
| break; |
| } |
| |
| size = csbase >> 21; |
| |
| tom |= (1 << (canidate + 24)); |
| |
| csbase = (tom << 21) | 1; |
| |
| tom += size; |
| |
| csmask = ((size -1) << 21); |
| csmask |= 0xfe00; |
| |
| pci_write_config32(ctrl->f2, 0x40 + (canidate << 2), csbase); |
| |
| pci_write_config32(ctrl->f2, 0x60 + (canidate << 2), csmask); |
| |
| } |
| |
| return (tom & ~0xff000000) << 15; |
| } |
| static void order_dimms(const struct mem_controller *ctrl) |
| { |
| unsigned long tom, tom_k, base_k; |
| unsigned node_id; |
| tom_k = interleave_chip_selects(ctrl); |
| if (!tom_k) { |
| tom_k = order_chip_selects(ctrl); |
| } |
| |
| base_k = 0; |
| for(node_id = 0; node_id < ctrl->node_id; node_id++) { |
| uint32_t limit, base; |
| unsigned index; |
| index = node_id << 3; |
| base = pci_read_config32(ctrl->f1, 0x40 + index); |
| |
| if ((base & 3) == 3) { |
| limit = pci_read_config32(ctrl->f1, 0x44 + index); |
| base_k = ((limit + 0x00010000) & 0xffff0000) >> 2; |
| } |
| } |
| tom_k += base_k; |
| route_dram_accesses(ctrl, base_k, tom_k); |
| set_top_mem(tom_k); |
| } |
| static void disable_dimm(const struct mem_controller *ctrl, unsigned index) |
| { |
| print_debug("disabling dimm"); |
| print_debug_hex8(index); |
| print_debug("\r\n"); |
| pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+0)<<2), 0); |
| pci_write_config32(ctrl->f2, 0x40 + (((index << 1)+1)<<2), 0); |
| } |
| static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl) |
| { |
| int i; |
| int registered; |
| int unbuffered; |
| uint32_t dcl; |
| unbuffered = 0; |
| registered = 0; |
| for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 21); |
| if (value < 0) { |
| disable_dimm(ctrl, i); |
| continue; |
| } |
| |
| if (value & (1 << 1)) { |
| registered = 1; |
| } |
| |
| else { |
| unbuffered = 1; |
| } |
| } |
| if (unbuffered && registered) { |
| die("Mixed buffered and registered dimms not supported"); |
| } |
| if (unbuffered && is_opteron(ctrl)) { |
| die("Unbuffered Dimms not supported on Opteron"); |
| } |
| dcl = pci_read_config32(ctrl->f2, 0x90 ); |
| dcl &= ~(1<<18) ; |
| if (unbuffered) { |
| dcl |= (1<<18) ; |
| } |
| pci_write_config32(ctrl->f2, 0x90 , dcl); |
| } |
| static void spd_enable_2channels(const struct mem_controller *ctrl) |
| { |
| int i; |
| uint32_t nbcap; |
| |
| |
| static const unsigned addresses[] = { |
| 2, |
| 3, |
| 4, |
| 5, |
| 6, |
| 7, |
| 9, |
| 11, |
| 13, |
| 17, |
| 18, |
| 21, |
| 23, |
| 26, |
| 27, |
| 28, |
| 29, |
| 30, |
| 41, |
| 42, |
| }; |
| nbcap = pci_read_config32(ctrl->f3, 0xE8 ); |
| if (!(nbcap & 0x0001 )) { |
| return; |
| } |
| for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { |
| unsigned device0, device1; |
| int value0, value1; |
| int j; |
| device0 = ctrl->channel0[i]; |
| device1 = ctrl->channel1[i]; |
| if (!device1) |
| return; |
| for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) { |
| unsigned addr; |
| addr = addresses[j]; |
| value0 = spd_read_byte(device0, addr); |
| if (value0 < 0) { |
| break; |
| } |
| value1 = spd_read_byte(device1, addr); |
| if (value1 < 0) { |
| return; |
| } |
| if (value0 != value1) { |
| return; |
| } |
| } |
| } |
| print_debug("Enabling dual channel memory\r\n"); |
| uint32_t dcl; |
| dcl = pci_read_config32(ctrl->f2, 0x90 ); |
| dcl &= ~(1<<19) ; |
| dcl |= (1<<16) ; |
| pci_write_config32(ctrl->f2, 0x90 , dcl); |
| } |
| struct mem_param { |
| uint8_t cycle_time; |
| uint8_t divisor; |
| uint8_t tRC; |
| uint8_t tRFC; |
| uint32_t dch_memclk; |
| uint16_t dch_tref4k, dch_tref8k; |
| uint8_t dtl_twr; |
| char name[9]; |
| }; |
| static const struct mem_param *get_mem_param(unsigned min_cycle_time) |
| { |
| static const struct mem_param speed[] = { |
| { |
| .name = "100Mhz\r\n", |
| .cycle_time = 0xa0, |
| .divisor = (10 <<1), |
| .tRC = 0x46, |
| .tRFC = 0x50, |
| .dch_memclk = 0 << 20 , |
| .dch_tref4k = 0x00 , |
| .dch_tref8k = 0x08 , |
| .dtl_twr = 2, |
| }, |
| { |
| .name = "133Mhz\r\n", |
| .cycle_time = 0x75, |
| .divisor = (7<<1)+1, |
| .tRC = 0x41, |
| .tRFC = 0x4B, |
| .dch_memclk = 2 << 20 , |
| .dch_tref4k = 0x01 , |
| .dch_tref8k = 0x09 , |
| .dtl_twr = 2, |
| }, |
| { |
| .name = "166Mhz\r\n", |
| .cycle_time = 0x60, |
| .divisor = (6<<1), |
| .tRC = 0x3C, |
| .tRFC = 0x48, |
| .dch_memclk = 5 << 20 , |
| .dch_tref4k = 0x02 , |
| .dch_tref8k = 0x0A , |
| .dtl_twr = 3, |
| }, |
| { |
| .name = "200Mhz\r\n", |
| .cycle_time = 0x50, |
| .divisor = (5<<1), |
| .tRC = 0x37, |
| .tRFC = 0x46, |
| .dch_memclk = 7 << 20 , |
| .dch_tref4k = 0x03 , |
| .dch_tref8k = 0x0B , |
| .dtl_twr = 3, |
| }, |
| { |
| .cycle_time = 0x00, |
| }, |
| }; |
| const struct mem_param *param; |
| for(param = &speed[0]; param->cycle_time ; param++) { |
| if (min_cycle_time > (param+1)->cycle_time) { |
| break; |
| } |
| } |
| if (!param->cycle_time) { |
| die("min_cycle_time to low"); |
| } |
| print_debug(param->name); |
| return param; |
| } |
| static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) |
| { |
| |
| const struct mem_param *param; |
| unsigned min_cycle_time, min_latency; |
| int i; |
| uint32_t value; |
| static const int latency_indicies[] = { 26, 23, 9 }; |
| static const unsigned char min_cycle_times[] = { |
| [0 ] = 0x50, |
| [1 ] = 0x60, |
| [2 ] = 0x75, |
| [3 ] = 0xa0, |
| }; |
| value = pci_read_config32(ctrl->f3, 0xE8 ); |
| min_cycle_time = min_cycle_times[(value >> 5 ) & 3 ]; |
| min_latency = 2; |
| |
| for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { |
| int new_cycle_time, new_latency; |
| int index; |
| int latencies; |
| int latency; |
| |
| new_cycle_time = 0xa0; |
| new_latency = 5; |
| latencies = spd_read_byte(ctrl->channel0[i], 18); |
| if (latencies <= 0) continue; |
| |
| latency = log2(latencies) -2; |
| |
| for(index = 0; index < 3; index++, latency++) { |
| int value; |
| if ((latency < 2) || (latency > 4) || |
| (!(latencies & (1 << latency)))) { |
| continue; |
| } |
| value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); |
| if (value < 0) { |
| continue; |
| } |
| |
| if ((value >= min_cycle_time) && (value < new_cycle_time)) { |
| new_cycle_time = value; |
| new_latency = latency; |
| } |
| } |
| if (new_latency > 4){ |
| continue; |
| } |
| |
| if (new_cycle_time > min_cycle_time) { |
| min_cycle_time = new_cycle_time; |
| } |
| |
| if (new_latency > min_latency) { |
| min_latency = new_latency; |
| } |
| } |
| |
| |
| for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { |
| int latencies; |
| int latency; |
| int index; |
| int value; |
| int dimm; |
| latencies = spd_read_byte(ctrl->channel0[i], 18); |
| if (latencies <= 0) { |
| goto dimm_err; |
| } |
| |
| latency = log2(latencies) -2; |
| |
| for(index = 0; index < 3; index++, latency++) { |
| if (!(latencies & (1 << latency))) { |
| continue; |
| } |
| if (latency == min_latency) |
| break; |
| } |
| |
| if ((latency != min_latency) || (index >= 3)) { |
| goto dimm_err; |
| } |
| |
| |
| value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); |
| |
| |
| if (value <= min_cycle_time) { |
| continue; |
| } |
| |
| dimm_err: |
| disable_dimm(ctrl, i); |
| } |
| |
| param = get_mem_param(min_cycle_time); |
| |
| value = pci_read_config32(ctrl->f2, 0x94 ); |
| value &= ~(0x7 << 20 ); |
| value |= param->dch_memclk; |
| pci_write_config32(ctrl->f2, 0x94 , value); |
| static const unsigned latencies[] = { 1 , 5 , 2 }; |
| |
| value = pci_read_config32(ctrl->f2, 0x88 ); |
| value &= ~(0x7 << 0 ); |
| value |= latencies[min_latency - 2] << 0 ; |
| pci_write_config32(ctrl->f2, 0x88 , value); |
| |
| return param; |
| } |
| static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| unsigned clocks, old_clocks; |
| uint32_t dtl; |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 41); |
| if (value < 0) return -1; |
| if ((value == 0) || (value == 0xff)) { |
| value = param->tRC; |
| } |
| clocks = ((value << 1) + param->divisor - 1)/param->divisor; |
| if (clocks < 7 ) { |
| clocks = 7 ; |
| } |
| if (clocks > 22 ) { |
| return -1; |
| } |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| old_clocks = ((dtl >> 4 ) & 0xf ) + 7 ; |
| if (old_clocks > clocks) { |
| clocks = old_clocks; |
| } |
| dtl &= ~(0xf << 4 ); |
| dtl |= ((clocks - 7 ) << 4 ); |
| pci_write_config32(ctrl->f2, 0x88 , dtl); |
| return 0; |
| } |
| static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| unsigned clocks, old_clocks; |
| uint32_t dtl; |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 42); |
| if (value < 0) return -1; |
| if ((value == 0) || (value == 0xff)) { |
| value = param->tRFC; |
| } |
| clocks = ((value << 1) + param->divisor - 1)/param->divisor; |
| if (clocks < 9 ) { |
| clocks = 9 ; |
| } |
| if (clocks > 24 ) { |
| return -1; |
| } |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| old_clocks = ((dtl >> 8 ) & 0xf ) + 9 ; |
| if (old_clocks > clocks) { |
| clocks = old_clocks; |
| } |
| dtl &= ~(0xf << 8 ); |
| dtl |= ((clocks - 9 ) << 8 ); |
| pci_write_config32(ctrl->f2, 0x88 , dtl); |
| return 0; |
| } |
| static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| unsigned clocks, old_clocks; |
| uint32_t dtl; |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 29); |
| if (value < 0) return -1; |
| clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1); |
| if (clocks < 2 ) { |
| clocks = 2 ; |
| } |
| if (clocks > 6 ) { |
| return -1; |
| } |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| old_clocks = ((dtl >> 12 ) & 0x7 ) + 0 ; |
| if (old_clocks > clocks) { |
| clocks = old_clocks; |
| } |
| dtl &= ~(0x7 << 12 ); |
| dtl |= ((clocks - 0 ) << 12 ); |
| pci_write_config32(ctrl->f2, 0x88 , dtl); |
| return 0; |
| } |
| static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| unsigned clocks, old_clocks; |
| uint32_t dtl; |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 28); |
| if (value < 0) return -1; |
| clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1); |
| if (clocks < 2 ) { |
| clocks = 2 ; |
| } |
| if (clocks > 4 ) { |
| return -1; |
| } |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| old_clocks = ((dtl >> 16 ) & 0x7 ) + 0 ; |
| if (old_clocks > clocks) { |
| clocks = old_clocks; |
| } |
| dtl &= ~(0x7 << 16 ); |
| dtl |= ((clocks - 0 ) << 16 ); |
| pci_write_config32(ctrl->f2, 0x88 , dtl); |
| return 0; |
| } |
| static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| unsigned clocks, old_clocks; |
| uint32_t dtl; |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 30); |
| if (value < 0) return -1; |
| clocks = ((value << 1) + param->divisor - 1)/param->divisor; |
| if (clocks < 5 ) { |
| clocks = 5 ; |
| } |
| if (clocks > 15 ) { |
| return -1; |
| } |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| old_clocks = ((dtl >> 20 ) & 0xf ) + 0 ; |
| if (old_clocks > clocks) { |
| clocks = old_clocks; |
| } |
| dtl &= ~(0xf << 20 ); |
| dtl |= ((clocks - 0 ) << 20 ); |
| pci_write_config32(ctrl->f2, 0x88 , dtl); |
| return 0; |
| } |
| static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| unsigned clocks, old_clocks; |
| uint32_t dtl; |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 27); |
| if (value < 0) return -1; |
| clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1); |
| if (clocks < 2 ) { |
| clocks = 2 ; |
| } |
| if (clocks > 6 ) { |
| return -1; |
| } |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| old_clocks = ((dtl >> 24 ) & 0x7 ) + 0 ; |
| if (old_clocks > clocks) { |
| clocks = old_clocks; |
| } |
| dtl &= ~(0x7 << 24 ); |
| dtl |= ((clocks - 0 ) << 24 ); |
| pci_write_config32(ctrl->f2, 0x88 , dtl); |
| return 0; |
| } |
| static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| uint32_t dtl; |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| dtl &= ~(0x1 << 28 ); |
| dtl |= (param->dtl_twr - 2 ) << 28 ; |
| pci_write_config32(ctrl->f2, 0x88 , dtl); |
| } |
| static void init_Tref(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| uint32_t dth; |
| dth = pci_read_config32(ctrl->f2, 0x8c ); |
| dth &= ~(0x1f << 8 ); |
| dth |= (param->dch_tref4k << 8 ); |
| pci_write_config32(ctrl->f2, 0x8c , dth); |
| } |
| static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| uint32_t dth; |
| int value; |
| unsigned tref, old_tref; |
| value = spd_read_byte(ctrl->channel0[i], 3); |
| if (value < 0) return -1; |
| value &= 0xf; |
| tref = param->dch_tref8k; |
| if (value == 12) { |
| tref = param->dch_tref4k; |
| } |
| dth = pci_read_config32(ctrl->f2, 0x8c ); |
| old_tref = (dth >> 8 ) & 0x1f ; |
| if ((value == 12) && (old_tref == param->dch_tref4k)) { |
| tref = param->dch_tref4k; |
| } else { |
| tref = param->dch_tref8k; |
| } |
| dth &= ~(0x1f << 8 ); |
| dth |= (tref << 8 ); |
| pci_write_config32(ctrl->f2, 0x8c , dth); |
| return 0; |
| } |
| static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| uint32_t dcl; |
| int value; |
| int dimm; |
| value = spd_read_byte(ctrl->channel0[i], 13); |
| if (value < 0) { |
| return -1; |
| } |
| dimm = i; |
| dimm += 20 ; |
| dcl = pci_read_config32(ctrl->f2, 0x90 ); |
| dcl &= ~(1 << dimm); |
| if (value == 4) { |
| dcl |= (1 << dimm); |
| } |
| pci_write_config32(ctrl->f2, 0x90 , dcl); |
| return 0; |
| } |
| static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i) |
| { |
| uint32_t dcl; |
| int value; |
| value = spd_read_byte(ctrl->channel0[i], 11); |
| if (value < 0) { |
| return -1; |
| } |
| if (value != 2) { |
| dcl = pci_read_config32(ctrl->f2, 0x90 ); |
| dcl &= ~(1<<17) ; |
| pci_write_config32(ctrl->f2, 0x90 , dcl); |
| } |
| return 0; |
| } |
| static int count_dimms(const struct mem_controller *ctrl) |
| { |
| int dimms; |
| unsigned index; |
| dimms = 0; |
| for(index = 0; index < 8; index += 2) { |
| uint32_t csbase; |
| csbase = pci_read_config32(ctrl->f2, (0x40 + index << 2)); |
| if (csbase & 1) { |
| dimms += 1; |
| } |
| } |
| return dimms; |
| } |
| static void set_Twtr(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| uint32_t dth; |
| unsigned clocks; |
| clocks = 1; |
| dth = pci_read_config32(ctrl->f2, 0x8c ); |
| dth &= ~(0x1 << 0 ); |
| dth |= ((clocks - 1 ) << 0 ); |
| pci_write_config32(ctrl->f2, 0x8c , dth); |
| } |
| static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| uint32_t dth, dtl; |
| unsigned divisor; |
| unsigned latency; |
| unsigned clocks; |
| clocks = 0; |
| dtl = pci_read_config32(ctrl->f2, 0x88 ); |
| latency = (dtl >> 0 ) & 0x7 ; |
| divisor = param->divisor; |
| if (is_opteron(ctrl)) { |
| if (latency == 1 ) { |
| if (divisor == ((6 << 0) + 0)) { |
| |
| clocks = 3; |
| } |
| else if (divisor > ((6 << 0)+0)) { |
| |
| clocks = 2; |
| } |
| } |
| else if (latency == 5 ) { |
| clocks = 3; |
| } |
| else if (latency == 2 ) { |
| if (divisor == ((6 << 0)+0)) { |
| |
| clocks = 4; |
| } |
| else if (divisor > ((6 << 0)+0)) { |
| |
| clocks = 3; |
| } |
| } |
| } |
| else { |
| if (is_registered(ctrl)) { |
| if (latency == 1 ) { |
| clocks = 2; |
| } |
| else if (latency == 5 ) { |
| clocks = 3; |
| } |
| else if (latency == 2 ) { |
| clocks = 3; |
| } |
| } |
| else { |
| if (latency == 1 ) { |
| clocks = 3; |
| } |
| else if (latency == 5 ) { |
| clocks = 4; |
| } |
| else if (latency == 2 ) { |
| clocks = 4; |
| } |
| } |
| } |
| if ((clocks < 1 ) || (clocks > 6 )) { |
| die("Unknown Trwt"); |
| } |
| |
| dth = pci_read_config32(ctrl->f2, 0x8c ); |
| dth &= ~(0x7 << 4 ); |
| dth |= ((clocks - 1 ) << 4 ); |
| pci_write_config32(ctrl->f2, 0x8c , dth); |
| return; |
| } |
| static void set_Twcl(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| |
| uint32_t dth; |
| unsigned clocks; |
| if (is_registered(ctrl)) { |
| clocks = 2; |
| } else { |
| clocks = 1; |
| } |
| dth = pci_read_config32(ctrl->f2, 0x8c ); |
| dth &= ~(0x7 << 20 ); |
| dth |= ((clocks - 1 ) << 20 ); |
| pci_write_config32(ctrl->f2, 0x8c , dth); |
| } |
| static void set_read_preamble(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| uint32_t dch; |
| unsigned divisor; |
| unsigned rdpreamble; |
| divisor = param->divisor; |
| dch = pci_read_config32(ctrl->f2, 0x94 ); |
| dch &= ~(0xf << 8 ); |
| rdpreamble = 0; |
| if (is_registered(ctrl)) { |
| if (divisor == ((10 << 1)+0)) { |
| |
| rdpreamble = ((9 << 1)+ 0); |
| } |
| else if (divisor == ((7 << 1)+1)) { |
| |
| rdpreamble = ((8 << 1)+0); |
| } |
| else if (divisor == ((6 << 1)+0)) { |
| |
| rdpreamble = ((7 << 1)+1); |
| } |
| else if (divisor == ((5 << 1)+0)) { |
| |
| rdpreamble = ((7 << 1)+0); |
| } |
| } |
| else { |
| int slots; |
| int i; |
| slots = 0; |
| for(i = 0; i < 4; i++) { |
| if (ctrl->channel0[i]) { |
| slots += 1; |
| } |
| } |
| if (divisor == ((10 << 1)+0)) { |
| |
| if (slots <= 2) { |
| |
| rdpreamble = ((9 << 1)+0); |
| } else { |
| |
| rdpreamble = ((14 << 1)+0); |
| } |
| } |
| else if (divisor == ((7 << 1)+1)) { |
| |
| if (slots <= 2) { |
| |
| rdpreamble = ((7 << 1)+0); |
| } else { |
| |
| rdpreamble = ((11 << 1)+0); |
| } |
| } |
| else if (divisor == ((6 << 1)+0)) { |
| |
| if (slots <= 2) { |
| |
| rdpreamble = ((7 << 1)+0); |
| } else { |
| |
| rdpreamble = ((9 << 1)+0); |
| } |
| } |
| else if (divisor == ((5 << 1)+0)) { |
| |
| if (slots <= 2) { |
| |
| rdpreamble = ((5 << 1)+0); |
| } else { |
| |
| rdpreamble = ((7 << 1)+0); |
| } |
| } |
| } |
| if ((rdpreamble < ((2<<1)+0) ) || (rdpreamble > ((9<<1)+1) )) { |
| die("Unknown rdpreamble"); |
| } |
| dch |= (rdpreamble - ((2<<1)+0) ) << 8 ; |
| pci_write_config32(ctrl->f2, 0x94 , dch); |
| } |
| static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| uint32_t dch; |
| int i; |
| unsigned async_lat; |
| int dimms; |
| dimms = count_dimms(ctrl); |
| dch = pci_read_config32(ctrl->f2, 0x94 ); |
| dch &= ~(0xf << 0 ); |
| async_lat = 0; |
| if (is_registered(ctrl)) { |
| if (dimms == 4) { |
| |
| async_lat = 9; |
| } |
| else { |
| |
| async_lat = 8; |
| } |
| } |
| else { |
| if (dimms > 3) { |
| die("Too many unbuffered dimms"); |
| } |
| else if (dimms == 3) { |
| |
| async_lat = 7; |
| } |
| else { |
| |
| async_lat = 6; |
| } |
| } |
| dch |= ((async_lat - 0 ) << 0 ); |
| pci_write_config32(ctrl->f2, 0x94 , dch); |
| } |
| static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| uint32_t dch; |
| |
| dch = pci_read_config32(ctrl->f2, 0x94 ); |
| dch &= ~(0x7 << 16 ); |
| dch |= 3 << 16 ; |
| dch |= (1 << 19) ; |
| pci_write_config32(ctrl->f2, 0x94 , dch); |
| } |
| static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param) |
| { |
| int dimms; |
| int i; |
| int rc; |
| |
| init_Tref(ctrl, param); |
| for(i = 0; (i < 4) && ctrl->channel0[i]; i++) { |
| int rc; |
| |
| if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err; |
| if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err; |
| if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err; |
| if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err; |
| if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err; |
| if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err; |
| |
| if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err; |
| |
| if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err; |
| if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err; |
| continue; |
| dimm_err: |
| disable_dimm(ctrl, i); |
| |
| } |
| |
| set_Twr(ctrl, param); |
| |
| set_Twtr(ctrl, param); |
| set_Trwt(ctrl, param); |
| set_Twcl(ctrl, param); |
| |
| set_read_preamble(ctrl, param); |
| set_max_async_latency(ctrl, param); |
| set_idle_cycle_limit(ctrl, param); |
| } |
| static void sdram_set_spd_registers(const struct mem_controller *ctrl) |
| { |
| const struct mem_param *param; |
| spd_enable_2channels(ctrl); |
| spd_set_ram_size(ctrl); |
| spd_handle_unbuffered_dimms(ctrl); |
| param = spd_set_memclk(ctrl); |
| spd_set_dram_timing(ctrl, param); |
| order_dimms(ctrl); |
| } |
| static void sdram_enable(int controllers, const struct mem_controller *ctrl) |
| { |
| int i; |
| |
| for(i = 0; i < controllers; i++) { |
| uint32_t dch; |
| dch = pci_read_config32(ctrl[i].f2, 0x94 ); |
| dch |= (1 << 25) ; |
| pci_write_config32(ctrl[i].f2, 0x94 , dch); |
| } |
| |
| memreset(controllers, ctrl); |
| for(i = 0; i < controllers; i++) { |
| uint32_t dcl; |
| |
| dcl = pci_read_config32(ctrl[i].f2, 0x90 ); |
| if (dcl & (1<<17) ) { |
| uint32_t mnc; |
| print_debug("ECC enabled\r\n"); |
| mnc = pci_read_config32(ctrl[i].f3, 0x44 ); |
| mnc |= (1 << 22) ; |
| if (dcl & (1<<16) ) { |
| mnc |= (1 << 23) ; |
| } |
| pci_write_config32(ctrl[i].f3, 0x44 , mnc); |
| } |
| dcl |= (1<<3) ; |
| pci_write_config32(ctrl[i].f2, 0x90 , dcl); |
| dcl &= ~(1<<3) ; |
| dcl &= ~(1<<0) ; |
| dcl &= ~(1<<1) ; |
| dcl &= ~(1<<2) ; |
| dcl |= (1<<8) ; |
| pci_write_config32(ctrl[i].f2, 0x90 , dcl); |
| } |
| for(i = 0; i < controllers; i++) { |
| uint32_t dcl; |
| print_debug("Initializing memory: "); |
| int loops = 0; |
| do { |
| dcl = pci_read_config32(ctrl[i].f2, 0x90 ); |
| loops += 1; |
| if ((loops & 1023) == 0) { |
| print_debug("."); |
| } |
| } while(((dcl & (1<<8) ) != 0) && (loops < 300000 )); |
| if (loops >= 300000 ) { |
| print_debug(" failed\r\n"); |
| } else { |
| print_debug(" done\r\n"); |
| } |
| if (dcl & (1<<17) ) { |
| print_debug("Clearing memory: "); |
| if (!is_cpu_pre_c0()) { |
| |
| dcl &= ~((1<<11) | (1<<10) ); |
| pci_write_config32(ctrl[i].f2, 0x90 , dcl); |
| do { |
| dcl = pci_read_config32(ctrl[i].f2, 0x90 ); |
| } while(((dcl & (1<<11) ) == 0) || ((dcl & (1<<10) ) == 0) ); |
| } |
| uint32_t base, last_scrub_k, scrub_k; |
| uint32_t cnt,zstart,zend; |
| msr_t msr,msr_201; |
| |
| pci_write_config32(ctrl[i].f3, 0x58 , |
| (0 << 16) | (0 << 8) | (0 << 0)); |
| |
| msr_201 = rdmsr(0x201); |
| zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8)); |
| zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8)); |
| zstart >>= 16; |
| zend >>=16; |
| print_debug("addr "); |
| print_debug_hex32(zstart); |
| print_debug("-"); |
| print_debug_hex32(zend); |
| print_debug("\r\n"); |
| |
| |
| msr = rdmsr(0x2ff ); |
| msr.lo &= ~(1<<10); |
| wrmsr(0x2ff , msr); |
| |
| msr = rdmsr(0xc0010015); |
| msr.lo |= (1<<17); |
| wrmsr(0xc0010015,msr); |
| for(;zstart<zend;zstart+=4) { |
| |
| if(zstart == 0x0fc) |
| continue; |
| |
| |
| __asm__ volatile( |
| "movl %%cr0, %0\n\t" |
| "orl $0x40000000, %0\n\t" |
| "movl %0, %%cr0\n\t" |
| :"=r" (cnt) |
| ); |
| |
| |
| msr.lo = 1 + ((zstart&0x0ff)<<24); |
| msr.hi = (zstart&0x0ff00)>>8; |
| wrmsr(0x200,msr); |
| |
| msr.hi = 0x000000ff; |
| msr.lo = 0xfc000800; |
| wrmsr(0x201,msr); |
| |
| __asm__ volatile( |
| "movl %%cr0, %0\n\t" |
| "andl $0x9fffffff, %0\n\t" |
| "movl %0, %%cr0\n\t" |
| :"=r" (cnt) |
| ); |
| |
| msr.lo = (zstart&0xff) << 24; |
| msr.hi = (zstart&0xff00) >> 8; |
| wrmsr(0xc0000100,msr); |
| print_debug_char((zstart > 0x0ff)?'+':'-'); |
| |
| |
| __asm__ volatile( |
| "1: \n\t" |
| "movl %0, %%fs:(%1)\n\t" |
| "addl $4,%1\n\t" |
| "subl $1,%2\n\t" |
| "jnz 1b\n\t" |
| : |
| : "a" (0), "D" (0), "c" (0x01000000) |
| ); |
| } |
| |
| |
| __asm__ volatile( |
| "movl %%cr0, %0\n\t" |
| "orl $0x40000000, %0\n\t" |
| "movl %0, %%cr0\n\t" |
| :"=r" (cnt) |
| ); |
| |
| |
| msr = rdmsr(0x2ff ); |
| msr.lo |= 0x0400; |
| wrmsr(0x2ff , msr); |
| |
| msr.lo = 6; |
| msr.hi = 0; |
| wrmsr(0x200,msr); |
| wrmsr(0x201,msr_201); |
| |
| msr.lo = 0; |
| msr.hi = 0; |
| wrmsr(0xc0000100,msr); |
| |
| __asm__ volatile( |
| "movl %%cr0, %0\n\t" |
| "andl $0x9fffffff, %0\n\t" |
| "movl %0, %%cr0\n\t" |
| :"=r" (cnt) |
| ); |
| |
| |
| msr = rdmsr(0xc0010015); |
| msr.lo &= ~(1<<17); |
| wrmsr(0xc0010015,msr); |
| |
| base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3)); |
| base &= 0xffff0000; |
| |
| pci_write_config32(ctrl[i].f3, 0x5C , base << 8); |
| pci_write_config32(ctrl[i].f3, 0x60 , base >> 24); |
| |
| pci_write_config32(ctrl[i].f3, 0x58 , |
| (22 << 16) | (22 << 8) | (22 << 0)); |
| print_debug("done\r\n"); |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| typedef uint8_t u8; |
| typedef uint32_t u32; |
| typedef int8_t bool; |
| static void disable_probes(void) |
| { |
| |
| |
| u32 val; |
| print_debug("Disabling read/write/fill probes for UP... "); |
| val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68); |
| val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68, val); |
| print_debug("done.\r\n"); |
| } |
| |
| static void wait_ap_stop(u8 node) |
| { |
| unsigned long reg; |
| unsigned long i; |
| for(i=0;i< 1000 ;i++) { |
| unsigned long regx; |
| regx = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c); |
| if((regx & (1<<4))==1) break; |
| } |
| reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x6c); |
| reg &= ~(1<<4); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, reg); |
| } |
| static void notify_bsp_ap_is_stopped(void) |
| { |
| unsigned long reg; |
| unsigned long apic_id; |
| apic_id = *((volatile unsigned long *)(0xfee00000 + 0x020 )); |
| apic_id >>= 24; |
| |
| if(apic_id != 0) { |
| |
| reg = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C); |
| reg |= 1<<4; |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ apic_id ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6C, reg); |
| } |
| |
| } |
| |
| static void enable_routing(u8 node) |
| { |
| u32 val; |
| |
| |
| print_debug("Enabling routing table for node "); |
| print_debug_hex32(node); |
| val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c); |
| val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x6c, val); |
| |
| if(node!=0) { |
| wait_ap_stop(node); |
| } |
| |
| print_debug(" done.\r\n"); |
| } |
| static void rename_temp_node(u8 node) |
| { |
| uint32_t val; |
| print_debug("Renaming current temp node to "); |
| print_debug_hex32(node); |
| val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60); |
| val &= (~7); |
| val |= node; |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60, val); |
| print_debug(" done.\r\n"); |
| } |
| static bool check_connection(u8 src, u8 dest, u8 link) |
| { |
| |
| u32 val; |
| |
| |
| val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ src ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x98+link); |
| if ( (val&0x17) != 0x03) |
| return 0; |
| |
| val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ dest ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0); |
| if(val != 0x11001022) |
| return 0; |
| return 1; |
| } |
| static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2) |
| { |
| static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 }; |
| static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 }; |
| uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask; |
| uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2; |
| uint8_t freq; |
| |
| |
| freq_cap1 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x0a ); |
| freq_cap2 = pci_read_config16(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x0a ); |
| |
| |
| freq = log2(freq_cap1 & freq_cap2 & 0xff); |
| |
| pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 0x09 , freq); |
| pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 0x09 , freq); |
| |
| width_cap1 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 ); |
| width_cap2 = pci_read_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 ); |
| |
| ln_width1 = link_width_to_pow2[width_cap1 & 7]; |
| ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7]; |
| if (ln_width1 > ln_width2) { |
| ln_width1 = ln_width2; |
| } |
| width = pow2_to_link_width[ln_width1]; |
| |
| ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7]; |
| ln_width2 = link_width_to_pow2[width_cap2 & 7]; |
| if (ln_width1 > ln_width2) { |
| ln_width1 = ln_width2; |
| } |
| width |= pow2_to_link_width[ln_width1] << 4; |
| |
| |
| pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link1 + 6 + 1, width); |
| |
| width = ((width & 0x70) >> 4) | ((width & 0x7) << 4); |
| pci_write_config8(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node2 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x80 + link2 + 6 + 1, width); |
| } |
| static void fill_row(u8 node, u8 row, u32 value) |
| { |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x40+(row<<2), value); |
| } |
| static void setup_row(u8 source, u8 dest, u8 cpus) |
| { |
| fill_row(source,dest,generate_row(source,dest,cpus)); |
| } |
| static void setup_temp_row(u8 source, u8 dest, u8 cpus) |
| { |
| fill_row(source,7,((generate_row( source,dest,cpus )&(~0x0f0000))|0x010000) ); |
| } |
| static void setup_node(u8 node, u8 cpus) |
| { |
| u8 row; |
| for(row=0; row<cpus; row++) |
| setup_row(node, row, cpus); |
| } |
| static void setup_remote_row(u8 source, u8 dest, u8 cpus) |
| { |
| fill_row(7, dest, generate_row(source, dest, cpus)); |
| } |
| static void setup_remote_node(u8 node, u8 cpus) |
| { |
| static const uint8_t pci_reg[] = { |
| 0x44, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x74, 0x7c, |
| 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, |
| 0x84, 0x8c, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbc, |
| 0x80, 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, |
| 0xc4, 0xcc, 0xd4, 0xdc, |
| 0xc0, 0xc8, 0xd0, 0xd8, |
| 0xe0, 0xe4, 0xe8, 0xec, |
| }; |
| uint8_t row; |
| int i; |
| print_debug("setup_remote_node\r\n"); |
| for(row=0; row<cpus; row++) |
| setup_remote_row(node, row, cpus); |
| |
| for(i = 0; i < sizeof(pci_reg)/sizeof(pci_reg[0]); i++) { |
| uint32_t value; |
| uint8_t reg; |
| reg = pci_reg[i]; |
| value = pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 0 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ 7 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , reg, value); |
| } |
| print_debug("setup_remote_done\r\n"); |
| } |
| static u8 setup_uniprocessor(void) |
| { |
| print_debug("Enabling UP settings\r\n"); |
| disable_probes(); |
| return 1; |
| } |
| static u8 setup_smp(void) |
| { |
| u8 cpus=2; |
| print_debug("Enabling SMP settings\r\n"); |
| setup_row(0,0,cpus); |
| |
| setup_temp_row(0,1,cpus); |
| |
| if (!check_connection(0, 7, 0x20 )) { |
| print_debug("No connection to Node 1.\r\n"); |
| fill_row( 0 ,7,0x00010101 ) ; |
| setup_uniprocessor(); |
| return 1; |
| } |
| |
| optimize_connection(0, 0x20 , 7, 0x20 ); |
| setup_node(0, cpus); |
| setup_remote_node(1, cpus); |
| rename_temp_node(1); |
| enable_routing(1); |
| |
| fill_row( 0 ,7,0x00010101 ) ; |
| |
| print_debug_hex32(cpus); |
| print_debug(" nodes initialized.\r\n"); |
| return cpus; |
| } |
| static unsigned detect_mp_capabilities(unsigned cpus) |
| { |
| unsigned node, row, mask; |
| bool mp_cap= (-1) ; |
| print_debug("detect_mp_capabilities: "); |
| print_debug_hex32(cpus); |
| print_debug("\r\n"); |
| if (cpus>2) |
| mask=0x06; |
| else |
| mask=0x02; |
| for (node=0; node<cpus; node++) { |
| if ((pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , 0xe8) & mask)!=mask) |
| mp_cap= (0) ; |
| } |
| if (mp_cap) |
| return cpus; |
| |
| print_debug("One of the CPUs is not MP capable. Going back to UP\r\n"); |
| for (node=cpus; node>0; node--) |
| for (row=cpus; row>0; row--) |
| fill_row(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node-1 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , row-1, 0x00010101 ); |
| |
| return setup_uniprocessor(); |
| } |
| static void coherent_ht_finalize(unsigned cpus) |
| { |
| int node; |
| bool rev_a0; |
| |
| |
| print_debug("coherent_ht_finalize\r\n"); |
| rev_a0= is_cpu_rev_a0(); |
| for (node=0; node<cpus; node++) { |
| u32 val; |
| val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x60); |
| val &= (~0x000F0070); |
| val |= ((cpus-1)<<16)|((cpus-1)<<4); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x60,val); |
| val=pci_read_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , 0x68); |
| val |= 0x00008000; |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x68,val); |
| if (rev_a0) { |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0x94,0); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xb4,0); |
| pci_write_config32(( ((( 0 ) & 0xFF) << 16) | ((( 24+ node ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) ,0xd4,0); |
| } |
| } |
| print_debug("done\r\n"); |
| } |
| static int setup_coherent_ht_domain(void) |
| { |
| unsigned cpus; |
| int reset_needed = 0; |
| enable_routing(0) ; |
| cpus=setup_smp(); |
| cpus=detect_mp_capabilities(cpus); |
| coherent_ht_finalize(cpus); |
| |
| coherent_ht_mainboard(cpus); |
| return reset_needed; |
| } |
| void sdram_no_memory(void) |
| { |
| print_err("No memory!!\r\n"); |
| while(1) { |
| hlt(); |
| } |
| } |
| |
| void sdram_initialize(int controllers, const struct mem_controller *ctrl) |
| { |
| int i; |
| |
| for(i = 0; i < controllers; i++) { |
| print_debug("Ram1."); |
| print_debug_hex8(i); |
| print_debug("\r\n"); |
| sdram_set_registers(ctrl + i); |
| } |
| |
| for(i = 0; i < controllers; i++) { |
| print_debug("Ram2."); |
| print_debug_hex8(i); |
| print_debug("\r\n"); |
| sdram_set_spd_registers(ctrl + i); |
| } |
| |
| print_debug("Ram3\r\n"); |
| sdram_enable(controllers, ctrl); |
| print_debug("Ram4\r\n"); |
| } |
| static void enable_lapic(void) |
| { |
| msr_t msr; |
| msr = rdmsr(0x1b); |
| msr.hi &= 0xffffff00; |
| msr.lo &= 0x000007ff; |
| msr.lo |= 0xfee00000 | (1 << 11); |
| wrmsr(0x1b, msr); |
| } |
| static void stop_this_cpu(void) |
| { |
| unsigned apicid; |
| apicid = apic_read(0x020 ) >> 24; |
| |
| apic_write(0x310 , (( apicid )<<24) ); |
| apic_write(0x300 , 0x08000 | 0x04000 | 0x00500 ); |
| |
| apic_wait_icr_idle(); |
| |
| apic_write(0x310 , (( apicid )<<24) ); |
| apic_write(0x300 , 0x08000 | 0x00500 ); |
| |
| apic_wait_icr_idle(); |
| |
| for(;;) { |
| hlt(); |
| } |
| } |
| static void pc87360_enable_serial(void) |
| { |
| pnp_set_logical_device(0x2e , 0x03 ); |
| pnp_set_enable(0x2e , 1); |
| pnp_set_iobase0(0x2e , 0x3f8); |
| } |
| static void main(void) |
| { |
| |
| static const struct mem_controller cpu[] = { |
| { |
| .node_id = 0, |
| .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , |
| .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , |
| .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) , |
| .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x18 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , |
| .channel0 = { (0xa<<3)|0, (0xa<<3)|2, 0, 0 }, |
| .channel1 = { (0xa<<3)|1, (0xa<<3)|3, 0, 0 }, |
| }, |
| { |
| .node_id = 1, |
| .f0 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 0 ) & 0x7) << 8)) , |
| .f1 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 1 ) & 0x7) << 8)) , |
| .f2 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 2 ) & 0x7) << 8)) , |
| .f3 = ( ((( 0 ) & 0xFF) << 16) | ((( 0x19 ) & 0x1f) << 11) | ((( 3 ) & 0x7) << 8)) , |
| .channel0 = { (0xa<<3)|4, (0xa<<3)|6, 0, 0 }, |
| .channel1 = { (0xa<<3)|5, (0xa<<3)|7, 0, 0 }, |
| }, |
| }; |
| if (cpu_init_detected()) { |
| asm("jmp __cpu_reset"); |
| } |
| enable_lapic(); |
| init_timer(); |
| if (!boot_cpu()) { |
| stop_this_cpu(); |
| } |
| pc87360_enable_serial(); |
| uart_init(); |
| console_init(); |
| setup_default_resource_map(); |
| setup_coherent_ht_domain(); |
| enumerate_ht_chain(0); |
| distinguish_cpu_resets(0); |
| |
| enable_smbus(); |
| memreset_setup(); |
| sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); |
| |
| } |