This patch set allows disable_car to return. Comments welcome. Thanks to Carl-Daniel and Stefan for not accepting my earlier patches, and arguing me into the ground. They were right.
[I hope :-) we still have not solved opteron.] This discussion began quite some time ago. I thought it would never end. But I think we're there. Sometimes, no matter how much sense you think you are making, you've got to listen to other people to get it right ... and it doesn't always get done as soon as you might wish. thanks ron
These changes implement a fixed Geode LX Cache As Ram that allows a return from disable_car. These changes include my console changes since I need them to build the alix 1c now. The changes: - add a banner function to lib/console.c that is SHARED so all code can use it. - move the cache as ram memory to 0x80000 instead of 0xc8000, as the C range is really tricky to get right :-) - change die() to make it JTAG friendly - remove the banner function defined in the geodelx raminit - remove some defines from a geode .S file and add them to the geodelx.h file - modify the geode disable_car to ensure the cache is flushed to ram on the wbinvd. With these changes, I get a payload loaded. the payload does not work, but that's another story. Signed-off-by: Ronald G. Minnich <[EMAIL PROTECTED]> Index: include/console.h =================================================================== --- include/console.h (revision 542) +++ include/console.h (working copy) @@ -48,5 +48,6 @@ SHARED_WITH_ATTRIBUTES(printk, int, __attribute__((format (printf, 2, 3))), int msg_level, const char *fmt, ...); +SHARED(banner, void, int msg_level, const char *msg); #endif /* CONSOLE_H */ Index: include/arch/x86/amd_geodelx.h =================================================================== --- include/arch/x86/amd_geodelx.h (revision 542) +++ include/arch/x86/amd_geodelx.h (working copy) @@ -566,8 +566,26 @@ /* ------------------------ */ #define DCACHE_RAM_SIZE 0x08000 -#define DCACHE_RAM_BASE 0xc8000 +//#define DCACHE_RAM_BASE 0xc8000 +#define DCACHE_RAM_BASE 0x80000 +/* This is where the DCache will be mapped and be used as stack. It would be + * cool if it was the same base as LinuxBIOS normal stack. + */ +#define LX_STACK_BASE DCACHE_RAM_BASE +#define LX_STACK_END LX_STACK_BASE + (DCACHE_RAM_SIZE - 4) +#define LX_NUM_CACHELINES 0x080 /* There are 128 lines per way. */ +#define LX_CACHELINE_SIZE 0x020 /* There are 32 bytes per line. */ +#define LX_CACHEWAY_SIZE (LX_NUM_CACHELINES * LX_CACHELINE_SIZE) +#define CR0_CD 0x40000000 /* Bit 30 = Cache Disable */ +#define CR0_NW 0x20000000 /* Bit 29 = Not Write Through */ + +#define ROM_CODE_SEG 0x08 +#define ROM_DATA_SEG 0x10 + +#define CACHE_RAM_CODE_SEG 0x18 +#define CACHE_RAM_DATA_SEG 0x20 + /* POST CODES */ /* standard AMD post definitions -- might as well use them. */ Index: lib/console.c =================================================================== --- lib/console.c (revision 542) +++ lib/console.c (working copy) @@ -46,6 +46,29 @@ return i; } +/** + * Print a nice banner so we know what step we died on. + * + * @param level The printk level (e.g. BIOS_EMERG) + * @param s String to put in the middle of the banner + */ + +void banner(int level, const char *s) +{ + int i; + /* 10 = signs and a space. */ + printk(level, "========== "); + for(i = 11; *s; i++, s++) + printk(level, "%c", *s); + /* trailing space */ + printk(level, " "); + i++; + /* fill it up to 80 columns */ + for(; i < 80; i++) + printk(level, "="); + printk(level, "\n"); +} + void console_init(void) { static const char console_test[] = @@ -59,9 +82,31 @@ printk(BIOS_INFO, console_test); } +/** + * Halt and loop due to a fatal error. + * There have been several iterations of this function. + * The first simply did a hlt(). Doing a hlt() can make jtag debugging + * very difficult as one can not break into a hlt instruction on some CPUs. + * Second was to do a console_tx_byte of a NULL character. + * A number of concerns were raised about doing this idea. + * Third idea was to do an inb from port 0x80, the POST port. That design + * makes us very CPU-specific. + * The fourth idea was just POSTING the same + * code over and over. That would erase the most recent POST code, + * hindering diagnosis. + * + * For now, for lack of a good alternative, + * we will continue to call console_tx_byte. We call with a NULL since + * it will clear any FIFOs in the path and won't clutter up the output, + * since NULL doesn't print a visible character on most terminal + * emulators. + * + * @param str A string to print for the error + * + */ void die(const char *str) { printk(BIOS_EMERG, str); while (1) - hlt(); + console_tx_byte(0, (void *)0); } Index: northbridge/amd/geodelx/raminit.c =================================================================== --- northbridge/amd/geodelx/raminit.c (revision 542) +++ northbridge/amd/geodelx/raminit.c (working copy) @@ -36,19 +36,6 @@ u8 spd_read_byte(u16 device, u8 address); /** - * Print a nice banner so we know what step we died on. - * - * @param s String to put in the middle of the banner - */ - -void banner(char *s) -{ - printk(BIOS_DEBUG, "==========================="); - printk(BIOS_DEBUG, s); - printk(BIOS_DEBUG, "======================================\n"); -} - -/** * Halt and Catch Fire. Print an error, then loop, sending NULLs on serial port, * to ensure the message is visible. * @@ -83,14 +70,14 @@ dimm_setting = 0; - banner("Check present"); + banner(BIOS_DEBUG, "Check present"); /* Check that we have a DIMM. */ if (spd_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF) return; /* Field: Module Banks per DIMM */ /* EEPROM byte usage: (5) Number of DIMM Banks */ - banner("MODBANKS"); + banner(BIOS_DEBUG, "MODBANKS"); spd_byte = spd_read_byte(dimm, SPD_NUM_DIMM_BANKS); if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)) { printk(BIOS_EMERG, "Number of module banks not compatible\n"); @@ -101,7 +88,7 @@ /* Field: Banks per SDRAM device */ /* EEPROM byte usage: (17) Number of Banks on SDRAM Device */ - banner("FIELDBANKS"); + banner(BIOS_DEBUG, "FIELDBANKS"); spd_byte = spd_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM); if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)) { printk(BIOS_EMERG, "Number of device banks not compatible\n"); @@ -117,7 +104,7 @@ *; (31) Module Bank Density *; Size = Module Density * Module Banks */ - banner("SPDNUMROWS"); + banner(BIOS_DEBUG, "SPDNUMROWS"); if ((spd_read_byte(dimm, SPD_NUM_ROWS) & 0xF0) || (spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) { @@ -127,7 +114,7 @@ } /* Size = Module Density * Module Banks */ - banner("SPDBANKDENSITY"); + banner(BIOS_DEBUG, "SPDBANKDENSITY"); dimm_size = spd_read_byte(dimm, SPD_BANK_DENSITY); /* Align so 1 GB (bit 0) is bit 8. This is a little weird to get gcc @@ -143,9 +130,9 @@ /* Module Density * Module Banks */ /* Shift to multiply by the number of DIMM banks. */ dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1; - banner("BEFORT CTZ"); + banner(BIOS_DEBUG, "BEFORT CTZ"); dimm_size = __builtin_ctz(dimm_size); - banner("TEST DIMM SIZE>8"); + banner(BIOS_DEBUG, "TEST DIMM SIZE>8"); if (dimm_size > 8) { /* 8 is 1 GB only support 1 GB per DIMM */ printk(BIOS_EMERG, "Only support up to 1 GB per DIMM\n"); post_code(ERROR_DENSITY_DIMM); @@ -177,9 +164,9 @@ * example, #col_addr_bits = 7 (06h), it adds 3 to get 10, then does * 2^10=1K. Get it? */ - banner("PAGESIZE"); + banner(BIOS_DEBUG, "PAGESIZE"); spd_byte = num_col_addr[spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF]; - banner("MAXCOLADDR"); + banner(BIOS_DEBUG, "MAXCOLADDR"); if (spd_byte > MAX_COL_ADDR) { printk(BIOS_EMERG, "DIMM page size not compatible\n"); post_code(ERROR_SET_PAGE); @@ -193,9 +180,9 @@ /* 0 = 1k, 1 = 2k, 2 = 4k, etc. */ dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT; - banner("RDMSR CF07"); + banner(BIOS_DEBUG, "RDMSR CF07"); msr = rdmsr(MC_CF07_DATA); - banner("WRMSR CF07"); + banner(BIOS_DEBUG, "WRMSR CF07"); if (dimm == dimm0) { msr.hi &= 0xFFFF0000; msr.hi |= dimm_setting; @@ -203,7 +190,7 @@ msr.hi &= 0x0000FFFF; msr.hi |= dimm_setting << 16; } - banner("ALL DONE"); + banner(BIOS_DEBUG, "ALL DONE"); wrmsr(MC_CF07_DATA, msr); } Index: arch/x86/geodelx/stage0.S =================================================================== --- arch/x86/geodelx/stage0.S (revision 542) +++ arch/x86/geodelx/stage0.S (working copy) @@ -28,24 +28,6 @@ #include "../macros.h" #include <amd_geodelx.h> -/* This is where the DCache will be mapped and be used as stack. It would be - * cool if it was the same base as LinuxBIOS normal stack. - */ -#define LX_STACK_BASE DCACHE_RAM_BASE -#define LX_STACK_END LX_STACK_BASE + (DCACHE_RAM_SIZE - 4) - -#define LX_NUM_CACHELINES 0x080 /* There are 128 lines per way. */ -#define LX_CACHELINE_SIZE 0x020 /* There are 32 bytes per line. */ -#define LX_CACHEWAY_SIZE (LX_NUM_CACHELINES * LX_CACHELINE_SIZE) -#define CR0_CD 0x40000000 /* Bit 30 = Cache Disable */ -#define CR0_NW 0x20000000 /* Bit 29 = Not Write Through */ - -#define ROM_CODE_SEG 0x08 -#define ROM_DATA_SEG 0x10 - -#define CACHE_RAM_CODE_SEG 0x18 -#define CACHE_RAM_DATA_SEG 0x20 - .code16 .globl _stage0 _stage0: Index: arch/x86/geodelx/stage1.c =================================================================== --- arch/x86/geodelx/stage1.c (revision 542) +++ arch/x86/geodelx/stage1.c (working copy) @@ -22,6 +22,8 @@ #include <lib.h> #include <msr.h> #include <amd_geodelx.h> +#include <console.h> static const struct msrinit msr_table[] = { /* Setup access to cache under 1MB. */ @@ -59,5 +61,12 @@ for (i = 0; i < ARRAY_SIZE(msr_table); i++) wrmsr(msr_table[i].msrnum, msr_table[i].msr); - __asm__("wbinvd\n"); + /* OK, here is the theory: we should be able to copy + * the data back over itself, and the wbinvd should then + * flush to memory. Let's see. + */ + __asm__ __volatile__("cld; rep movsl" ::"D" (DCACHE_RAM_BASE), "S" (DCACHE_RAM_BASE), "c" (DCACHE_RAM_SIZE/4): "memory"); + __asm__ __volatile__ ("wbinvd\n"); + banner(BIOS_DEBUG, "Disable_car: done wbinvd"); + banner(BIOS_DEBUG, "disable_car: done"); }
-- linuxbios mailing list linuxbios@linuxbios.org http://www.linuxbios.org/mailman/listinfo/linuxbios