From d3283ec05f51056faa18610e952ccc81cb738313 Mon Sep 17 00:00:00 2001 From: Eric Biederman Date: Wed, 18 Jun 2003 11:03:18 +0000 Subject: - A new test case for romcc - Minor romcc fixes - In smbus_wail_until_done a romcc glitch with || in romcc where it likes to run out of registers. Use | to be explicit that I don't need the short circuiting behavior. - Remove unused #defines from coherent_ht.c - Update the test in auto.c to 512M - Add definition of log2 to romcc_io.h - Implement SPD memory sizing in raminit.c - Reduce the number of memory devices back 2 to for the SOLO board. git-svn-id: svn://svn.coreboot.org/coreboot/trunk@883 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/arch/i386/include/arch/romcc_io.h | 12 ++ src/mainboard/amd/solo/auto.c | 57 +++++- src/northbridge/amd/amdk8/coherent_ht.c | 8 - src/northbridge/amd/amdk8/raminit.c | 202 +++++++++++++++++++++- src/southbridge/amd/amd8111/amd8111_early_smbus.c | 2 +- 5 files changed, 259 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h index 7d3d50e39c..d67b3b60d6 100644 --- a/src/arch/i386/include/arch/romcc_io.h +++ b/src/arch/i386/include/arch/romcc_io.h @@ -35,6 +35,18 @@ static void hlt(void) __builtin_hlt(); } +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); +} + + typedef __builtin_msr_t msr_t; static msr_t rdmsr(unsigned long index) diff --git a/src/mainboard/amd/solo/auto.c b/src/mainboard/amd/solo/auto.c index e8e3976ef2..f61b794256 100644 --- a/src/mainboard/amd/solo/auto.c +++ b/src/mainboard/amd/solo/auto.c @@ -11,6 +11,13 @@ #include "northbridge/amd/amdk8/coherent_ht.c" #include "sdram/generic_sdram.c" +#define NODE_ID 0x60 +#define HT_INIT_CONTROL 0x6c + +#define HTIC_ColdR_Detect (1<<4) +#define HTIC_BIOSR_Detect (1<<5) +#define HTIC_INIT_Detect (1<<6) + static int boot_cpu(void) { volatile unsigned long *local_apic; @@ -59,6 +66,16 @@ static int cpu_init_detected(void) } +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; @@ -72,15 +89,33 @@ static void print_pci_devices(void) (((id >> 16) & 0xffff) == 0x0000)) { continue; } - print_debug("PCI: 00:"); - print_debug_hex8(dev >> 11); - print_debug_char('.'); - print_debug_hex8((dev >> 8) & 7); + 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_spd_registers(void) { unsigned device; @@ -112,6 +147,7 @@ static void dump_spd_registers(void) } } + static void main(void) { uart_init(); @@ -132,7 +168,16 @@ static void main(void) sdram_initialize(); dump_spd_registers(); - /* Check the first 8M */ - ram_check(0x00100000, 0x00800000); + dump_pci_device(PCI_DEV(0, 0x18, 2)); + + /* Check the first 512M */ + msr_t msr; + msr = rdmsr(TOP_MEM); + print_debug("TOP_MEM: "); + print_debug_hex32(msr.hi); + print_debug_hex32(msr.lo); + print_debug("\r\n"); +#warning "FIXME if I pass msr.lo somehow I get the value 0x00000030 as stop in ram_check" + ram_check(0x00000000, 0x20000000); } } diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c index 68d8b39e36..fe2f3723ad 100644 --- a/src/northbridge/amd/amdk8/coherent_ht.c +++ b/src/northbridge/amd/amdk8/coherent_ht.c @@ -1,11 +1,3 @@ -#define COHERENT_AMD_SOLO 1 /* AMD Solo motherboard */ -#define COHERENT_ARIMA_HDAMA 2 /* Arima HDAMA motherboard */ - -#ifndef COHERENT_CONFIG -#define COHERENT_CONFIG COHERENT_AMD_SOLO -#endif - - static void setup_coherent_ht_domain(void) { static const unsigned int register_values[] = { diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c index 6c757c993e..54ca82e65a 100644 --- a/src/northbridge/amd/amdk8/raminit.c +++ b/src/northbridge/amd/amdk8/raminit.c @@ -1,3 +1,4 @@ +#include #define MEMORY_SUSE_SOLO 1 /* SuSE Solo configuration */ #define MEMORY_LNXI_SOLO 2 /* LNXI Solo configuration */ #define MEMORY_LNXI_HDAMA 3 /* LNXI HDAMA configuration */ @@ -1112,6 +1113,192 @@ static void sdram_set_registers(void) print_debug("done.\r\n"); } + +struct dimm_size { + unsigned long side1; + unsigned long side2; +}; +static struct dimm_size spd_get_dimm_size(unsigned device) +{ + /* Calculate the log base 2 size of a DIMM in bits */ + struct dimm_size sz; + int value, low; + sz.side1 = 0; + sz.side2 = 0; + + /* Note it might be easier to use byte 31 here, it has the DIMM size as + * a multiple of 4MB. The way we do it now we can size both + * sides of an assymetric dimm. + */ + value = smbus_read_byte(device, 3); /* rows */ + if (value < 0) return sz; + sz.side1 += value & 0xf; + + value = smbus_read_byte(device, 4); /* columns */ + if (value < 0) return sz; + sz.side1 += value & 0xf; + + value = smbus_read_byte(device, 17); /* banks */ + if (value < 0) return sz; + sz.side1 += log2(value & 0xff); + + /* Get the module data widht and convert it to a power of two */ + value = smbus_read_byte(device, 7); /* (high byte) */ + if (value < 0) return sz; + value &= 0xff; + value <<= 8; + + low = smbus_read_byte(device, 6); /* (low byte) */ + if (low < 0) return sz; + value = value | (low & 0xff); + sz.side1 += log2(value); + + /* side 2 */ + value = smbus_read_byte(device, 5); /* number of physical banks */ + if (value <= 1) return sz; + + /* Start with the symmetrical case */ + sz.side2 = sz.side1; + + value = smbus_read_byte(device, 3); /* rows */ + if (value < 0) return sz; + if ((value & 0xf0) == 0) return sz; /* If symmetrical we are done */ + sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */ + sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */ + + value = smbus_read_byte(device, 4); /* columns */ + if (value < 0) return sz; + sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */ + sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */ + return sz; +} + +static unsigned spd_to_dimm_side0(unsigned device) +{ + return (device - SMBUS_MEM_DEVICE_START) << 1; +} + +static unsigned spd_to_dimm_side1(unsigned device) +{ + return ((device - SMBUS_MEM_DEVICE_START) << 1) + 1; +} + +static void set_dimm_size(unsigned long size, unsigned index) +{ + unsigned value = 0; + /* Make certain the dimm is at least 32MB */ + if (size >= (25 + 3)) { + /* Place the dimm size in 32 MB quantities in the bits 31 - 21. + * The initialize dimm size is in bits. + * Set the base enable bit0. + */ + value = (1 << ((size - (25 + 3)) + 21)) | 1; + } + /* Set the appropriate DIMM base address register */ + pci_write_config32(PCI_DEV(0, 0x18, 2), 0x40 + (index << 2), value); +} + +static void spd_set_ram_size(void) +{ + unsigned device; + for(device = SMBUS_MEM_DEVICE_START; + device <= SMBUS_MEM_DEVICE_END; + device += SMBUS_MEM_DEVICE_INC) + { + struct dimm_size sz; + sz = spd_get_dimm_size(device); + set_dimm_size(sz.side1, spd_to_dimm_side0(device)); + set_dimm_size(sz.side2, spd_to_dimm_side1(device)); + } +} + +static void set_top_mem(unsigned tom_k) +{ + /* Error if I don't have memory */ + if (!tom_k) { + die("No memory"); + } + /* Now set top of memory */ + msr_t msr; + msr.lo = (tom_k & 0x003fffff) << 10; + msr.hi = (tom_k & 0xffc00000) >> 22; + wrmsr(TOP_MEM, msr); + +#if 1 + /* And report the amount of memory. (I run out of registers if i don't) */ + print_debug("RAM: 0x"); + print_debug_hex32(tom_k); + print_debug(" KB\r\n"); +#endif +} + +static void order_dimms(void) +{ + unsigned long tom; + unsigned mask; + unsigned index; + + /* Remember which registers we have used in the high 8 bits of tom */ + tom = 0; + for(;;) { + /* Find the largest remaining canidate */ + unsigned canidate; + uint32_t csbase, csmask; + unsigned size; + csbase = 0; + canidate = 0; + for(index = 0; index < 8; index++) { + uint32_t value; + value = pci_read_config32(PCI_DEV(0, 0x18, 2), 0x40 + (index << 2)); + + /* Is it enabled? */ + if (!(value & 1)) { + continue; + } + + /* Is it greater? */ + if (value <= csbase) { + continue; + } + + /* Has it already been selected */ + if (tom & (1 << (index + 24))) { + continue; + } + /* I have a new canidate */ + csbase = value; + canidate = index; + } + /* See if I have found a new canidate */ + if (csbase == 0) { + break; + } + + /* Remember I have used this register */ + tom |= (1 << (canidate + 24)); + + /* Remember the dimm size */ + size = csbase >> 21; + + /* Recompute the cs base register value */ + csbase = (tom << 21) | 1; + + /* Increment the top of memory */ + tom += size; + + /* Compute the memory mask */ + csmask = ((size -1) << 21); + csmask |= 0xfe00; /* For now don't optimize */ + + /* Write the new base register */ + pci_write_config32(PCI_DEV(0, 0x18, 2), 0x40 + (canidate << 2), csbase); + pci_write_config32(PCI_DEV(0, 0x18, 2), 0x60 + (canidate << 2), csmask); + + } + set_top_mem((tom & ~0xff000000) << 15); +} + + #define DRAM_CONFIG_LOW 0x90 #define DCL_DLL_Disable (1<<0) #define DCL_D_DRV (1<<1) @@ -1122,20 +1309,21 @@ static void sdram_set_registers(void) #define DCL_MemClrStatus (1<<11) #define DCL_DimmEcEn (1<<17) -#define NODE_ID 0x60 -#define HT_INIT_CONTROL 0x6c -#define HTIC_ColdR_Detect (1<<4) -#define HTIC_BIOSR_Detect (1<<5) -#define HTIC_INIT_Detect (1<<6) - -static void sdram_set_spd_registers(void) +static void spd_set_ecc_mode(void) { unsigned long dcl; dcl = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW); /* Until I know what is going on disable ECC support */ dcl &= ~DCL_DimmEcEn; pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW, dcl); + +} +static void sdram_set_spd_registers(void) +{ + spd_set_ram_size(); + spd_set_ecc_mode(); + order_dimms(); } #define TIMEOUT_LOOPS 300000 diff --git a/src/southbridge/amd/amd8111/amd8111_early_smbus.c b/src/southbridge/amd/amd8111/amd8111_early_smbus.c index 6b6d9ad144..33f558896e 100644 --- a/src/southbridge/amd/amd8111/amd8111_early_smbus.c +++ b/src/southbridge/amd/amd8111/amd8111_early_smbus.c @@ -53,7 +53,7 @@ static int smbus_wait_until_done(void) smbus_delay(); val = inw(SMBUS_IO_BASE + SMBGSTATUS); - if (((val & 0x8) == 0) || ((val & 0x437) != 0)) { + if (((val & 0x8) == 0) | ((val & 0x437) != 0)) { break; } } while(--loops); -- cgit v1.2.3