This code gets us to a working linux boot on the alix1c. I have not tested

Ethernet yet. The fixes are a board-specific fake spd_read_byte, cleaning up 
comments, and just in general customizing for the 1c. 

The lxraminit 
change fixes a bug (&& used instead of ||), adds some debug prints which were
VERY useful debugging the alix1c, changes fatal error messages from print_debug
to print_emerg, and adds two functions: 
banner, which just prints out a string with a banner, and 
hcf, which print an emergency message and then pushes null bytes
into the uart forever, just to make sure that no bytes get lost 
for any reason. 


Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Peter Stuge <peter@stuge.se>



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2899 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Ronald G. Minnich 2007-10-26 14:57:46 +00:00
parent 3d02e1e0d8
commit 65bc460e01
3 changed files with 175 additions and 50 deletions

View File

@ -205,7 +205,13 @@ void SetDelayControl(void)
}
}
}
print_debug("Try to write GLCP_DELAY_CONTROLS: hi ");
print_debug_hex32(msr.hi);
print_debug(" and lo ");
print_debug_hex32(msr.lo);
print_debug("\r\n");
wrmsr(GLCP_DELAY_CONTROLS, msr);
print_debug("SetDelayControl done\r\n");
return;
}
@ -219,6 +225,7 @@ void cpuRegInit(void)
/* Castle 2.0 BTM periodic sync period. */
/* [40:37] 1 sync record per 256 bytes */
print_debug("Castle 2.0 BTM periodic sync period.\r\n");
msrnum = CPU_PF_CONF;
msr = rdmsr(msrnum);
msr.hi |= (0x8 << 5);
@ -228,6 +235,7 @@ void cpuRegInit(void)
* LX performance setting.
* Enable Quack for fewer re-RAS on the MC
*/
print_debug("Enable Quack for fewer re-RAS on the MC\r\n");
msrnum = GLIU0_ARB;
msr = rdmsr(msrnum);
msr.hi &= ~ARB_UPPER_DACK_EN_SET;
@ -240,22 +248,28 @@ void cpuRegInit(void)
msr.hi |= ARB_UPPER_QUACK_EN_SET;
wrmsr(msrnum, msr);
/* GLIU port active enable, limit south pole masters (AES and PCI) to one outstanding transaction. */
/* GLIU port active enable, limit south pole masters
* (AES and PCI) to one outstanding transaction.
*/
print_debug(" GLIU port active enable\r\n");
msrnum = GLIU1_PORT_ACTIVE;
msr = rdmsr(msrnum);
msr.lo &= ~0x880;
wrmsr(msrnum, msr);
/* Set the Delay Control in GLCP */
print_debug("Set the Delay Control in GLCP\r\n");
SetDelayControl();
/* Enable RSDC */
print_debug("Enable RSDC\r\n");
msrnum = CPU_AC_SMM_CTL;
msr = rdmsr(msrnum);
msr.lo |= SMM_INST_EN_SET;
wrmsr(msrnum, msr);
/* FPU imprecise exceptions bit */
print_debug("FPU imprecise exceptions bit\r\n");
msrnum = CPU_FPU_MSR_MODE;
msr = rdmsr(msrnum);
msr.lo |= FPU_IE_SET;
@ -263,12 +277,14 @@ void cpuRegInit(void)
/* Power Savers (Do after BIST) */
/* Enable Suspend on HLT & PAUSE instructions */
print_debug("Enable Suspend on HLT & PAUSE instructions\r\n");
msrnum = CPU_XC_CONFIG;
msr = rdmsr(msrnum);
msr.lo |= XC_CONFIG_SUSP_ON_HLT | XC_CONFIG_SUSP_ON_PAUSE;
wrmsr(msrnum, msr);
/* Enable SUSP and allow TSC to run in Suspend (keep speed detection happy) */
print_debug("Enable SUSP and allow TSC to run in Suspend\r\n");
msrnum = CPU_BC_CONF_0;
msr = rdmsr(msrnum);
msr.lo |= TSC_SUSP_SET | SUSP_EN_SET;
@ -286,6 +302,7 @@ void cpuRegInit(void)
#endif
/* Setup throttling delays to proper mode if it is ever enabled. */
print_debug("Setup throttling delays to proper mode\r\n");
msrnum = GLCP_TH_OD;
msr.hi = 0;
msr.lo = 0x00000603C;

View File

@ -20,6 +20,7 @@
#define ASSEMBLY 1
#include <stdint.h>
#include <spd.h>
#include <device/pci_def.h>
#include <arch/io.h>
#include <device/pnp_def.h>
@ -37,13 +38,70 @@
#define POST_CODE(x) outb(x, 0x80)
#define SERIAL_DEV PNP_DEV(0x2e, W83627HF_SP1)
#include "southbridge/amd/cs5536/cs5536_early_smbus.c"
/* The alix1c has no SMBUS; the setup is hard-wired. */
void cs5536_enable_smbus(void)
{
}
#include "southbridge/amd/cs5536/cs5536_early_setup.c"
#include "superio/winbond/w83627hf/w83627hf_early_serial.c"
static inline int spd_read_byte(unsigned device, unsigned address)
/* the part is a hynix hy5du121622ctp-d43
* HY 5D U 12 16 2 2 C <blank> T <blank> P D43
* Hynix
* DDR SDRAM (5D)
* VDD 2.5 VDDQ 2.5 (U)
* 512M 8K REFRESH (12)
* x16 (16)
* 4banks (2)
* SSTL_2 (2)
* 4th GEN die (C)
* Normal Power Consumption (<blank> )
* TSOP (T)
* Single Die (<blank>)
* Lead Free (P)
* DDR400 3-3-3 (D43)
*/
/* spd array */
static u8 spdbytes[] = {
[SPD_ACCEPTABLE_CAS_LATENCIES] = 0x10,
[SPD_BANK_DENSITY] = 0x40,
[SPD_DEVICE_ATTRIBUTES_GENERAL] = 0xff,
[SPD_MEMORY_TYPE] = 7,
[SPD_MIN_CYCLE_TIME_AT_CAS_MAX] = 10, /* This is a guess for tRAC value */
[SPD_MODULE_ATTRIBUTES] = 0xff, /* fix me later when we figure out */
[SPD_NUM_BANKS_PER_SDRAM] = 4,
[SPD_PRIMARY_SDRAM_WIDTH] = 8,
/* alix1c is 1 bank. */
[SPD_NUM_DIMM_BANKS] = 1,
[SPD_NUM_COLUMNS] = 0xa,
[SPD_NUM_ROWS] = 3,
[SPD_REFRESH] = 0x3a,
[SPD_SDRAM_CYCLE_TIME_2ND] = 60,
[SPD_SDRAM_CYCLE_TIME_3RD] = 75,
[SPD_tRAS] = 40,
[SPD_tRCD] = 15,
[SPD_tRFC] = 70,
[SPD_tRP] = 15,
[SPD_tRRD] = 10,
};
static u8 spd_read_byte(unsigned device, unsigned address)
{
return smbus_read_byte(device, address);
print_debug("spd_read_byte dev ");
print_debug_hex8(device);
if (device != (0x50<<1)){
print_debug(" returns 0xff\n");
return 0xff;
}
print_debug(" addr ");
print_debug_hex8(address);
print_debug(" returns ");
print_debug_hex8(spdbytes[address]);
print_debug("\r\n");
return spdbytes[address];
}
#define ManualConf 0 /* Do automatic strapped PLL config */
@ -83,13 +141,12 @@ static void mb_gpio_init(void)
void cache_as_ram_main(void)
{
static const struct mem_controller memctrl[] = {
{.channel0 = {0x50}},
};
extern void RestartCAR();
POST_CODE(0x01);
static const struct mem_controller memctrl [] = {
{.channel0 = {(0xa<<3)|0, (0xa<<3)|1}}
};
SystemPreInit();
msr_init();
@ -114,24 +171,34 @@ void cache_as_ram_main(void)
/* Check memory */
ram_check(0x00000000, 640 * 1024);
/* Switch from Cache as RAM to real RAM */
/* There are two ways we could think about this.
1. If we are using the auto.inc ROMCC way, the stack is going to be re-setup in the code following this code.
Just wbinvd the stack to clear the cache tags. We don't care where the stack used to be.
2. This file is built as a normal .c -> .o and linked in etc. The stack might be used to return etc.
That means we care about what is in the stack. If we are smart we set the CAR stack to the same location
as the rest of LinuxBIOS. If that is the case we can just do a wbinvd. The stack will be written into real
RAM that is now setup and we continue like nothing happened. If the stack is located somewhere other than
where LB would like it, you need to write some code to do a copy from cache to RAM
We use method 1 on Norwich and on this board too.
/* Switch from Cache as RAM to real RAM
* There are two ways we could think about this.
*
* 1. If we are using the auto.inc ROMCC way, the stack is
* going to be re-setup in the code following this code. Just
* wbinvd the stack to clear the cache tags. We don't care
* where the stack used to be.
*
* 2. This file is built as a normal .c -> .o and linked in
* etc. The stack might be used to return etc. That means we
* care about what is in the stack. If we are smart we set
* the CAR stack to the same location as the rest of
* LinuxBIOS. If that is the case we can just do a wbinvd.
* The stack will be written into real RAM that is now setup
* and we continue like nothing happened. If the stack is
* located somewhere other than where LB would like it, you
* need to write some code to do a copy from cache to RAM
*
* We use method 1 on Norwich and on this board too.
*/
POST_CODE(0x02);
print_err("POST 02\n");
__asm__("wbinvd\n");
print_err("Past wbinvd\n");
/* we are finding the return does not work on this board. Explicitly call the label that is
* after the call to us. This is gross, but sometimes at this level it is the only way out
/* we are finding the return does not work on this
* board. Explicitly call the label that is after the call to
* us. This is gross, but sometimes at this level it is the
* only way out
*/
done_cache_as_ram_main();
}

View File

@ -27,6 +27,23 @@ static const unsigned char NumColAddr[] = {
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
void banner(char *s)
{
print_emerg("===========================");
print_emerg(s);
print_emerg("======================================\r\n");
}
void hcf(void)
{
print_emerg("DIE\r\n");
/* this guarantees we flush the UART fifos (if any) and also
* ensures that things, in general, keep going so no debug output
* is lost
*/
while (1)
print_emerg_char(0);
}
static void auto_size_dimm(unsigned int dimm)
{
uint32_t dimm_setting;
@ -36,33 +53,37 @@ static void auto_size_dimm(unsigned int dimm)
dimm_setting = 0;
banner("Check present");
/* Check that we have a dimm */
if (spd_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF) {
return;
}
banner("MODBANKS");
/* Field: Module Banks per DIMM */
/* EEPROM byte usage: (5) Number of DIMM Banks */
spd_byte = spd_read_byte(dimm, SPD_NUM_DIMM_BANKS);
if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)) {
print_debug("Number of module banks not compatible\n");
if ((MIN_MOD_BANKS > spd_byte) || (spd_byte > MAX_MOD_BANKS)) {
print_emerg("Number of module banks not compatible\n");
POST_CODE(ERROR_BANK_SET);
__asm__ __volatile__("hlt\n");
hcf();
}
dimm_setting |= (spd_byte >> 1) << CF07_UPPER_D0_MB_SHIFT;
banner("FIELDBANKS");
/* Field: Banks per SDRAM device */
/* EEPROM byte usage: (17) Number of Banks on SDRAM Device */
spd_byte = spd_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM);
if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)) {
print_debug("Number of device banks not compatible\n");
if ((MIN_DEV_BANKS > spd_byte) || (spd_byte > MAX_DEV_BANKS)) {
print_emerg("Number of device banks not compatible\n");
POST_CODE(ERROR_BANK_SET);
__asm__ __volatile__("hlt\n");
hcf();
}
dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT;
banner("SPDNUMROWS");
/*; Field: DIMM size
*; EEPROM byte usage: (3) Number or Row Addresses
*; EEPROM byte usage: (3) Number of Row Addresses
*; (4) Number of Column Addresses
*; (5) Number of DIMM Banks
*; (31) Module Bank Density
@ -70,24 +91,29 @@ static void auto_size_dimm(unsigned int dimm)
*/
if ((spd_read_byte(dimm, SPD_NUM_ROWS) & 0xF0)
|| (spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) {
print_debug("Assymetirc DIMM not compatible\n");
print_emerg("Assymetirc DIMM not compatible\n");
POST_CODE(ERROR_UNSUPPORTED_DIMM);
__asm__ __volatile__("hlt\n");
hcf();
}
banner("SPDBANKDENSITY");
dimm_size = spd_read_byte(dimm, SPD_BANK_DENSITY);
banner("DIMMSIZE");
dimm_size |= (dimm_size << 8); /* align so 1GB(bit0) is bit 8, this is a little weird to get gcc to not optimize this out */
dimm_size &= 0x01FC; /* and off 2GB DIMM size : not supported and the 1GB size we just moved up to bit 8 as well as all the extra on top */
/* Module Density * Module Banks */
dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1; /* shift to multiply by # DIMM banks */
banner("BEFORT CTZ");
dimm_size = __builtin_ctz(dimm_size);
banner("TEST DIMM SIZE>8");
if (dimm_size > 8) { /* 8 is 1GB only support 1GB per DIMM */
print_debug("Only support up to 1 GB per DIMM\n");
print_emerg("Only support up to 1 GB per DIMM\n");
POST_CODE(ERROR_DENSITY_DIMM);
__asm__ __volatile__("hlt\n");
hcf();
}
dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT;
banner("PAGESIZE");
/*; Field: PAGE size
*; EEPROM byte usage: (4) Number of Column Addresses
@ -113,18 +139,22 @@ static void auto_size_dimm(unsigned int dimm)
*;it adds 3 to get 10, then does 2^10=1K. Get it?*/
spd_byte = NumColAddr[spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF];
banner("MAXCOLADDR");
if (spd_byte > MAX_COL_ADDR) {
print_debug("DIMM page size not compatible\n");
print_emerg("DIMM page size not compatible\n");
POST_CODE(ERROR_SET_PAGE);
__asm__ __volatile__("hlt\n");
hcf();
}
banner(">12address test");
spd_byte -= 7;
if (spd_byte > 5) { /* if the value is above 6 it means >12 address lines */
spd_byte = 7; /* which means >32k so set to disabled */
}
dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT; /* 0=1k,1=2k,2=4k,etc */
banner("RDMSR CF07");
msr = rdmsr(MC_CF07_DATA);
banner("WRMSR CF07");
if (dimm == DIMM0) {
msr.hi &= 0xFFFF0000;
msr.hi |= dimm_setting;
@ -133,6 +163,7 @@ static void auto_size_dimm(unsigned int dimm)
msr.hi |= dimm_setting << 16;
}
wrmsr(MC_CF07_DATA, msr);
banner("ALL DONE");
}
static void checkDDRMax(void)
@ -152,9 +183,9 @@ static void checkDDRMax(void)
/* I don't think you need this check.
if (spd_byte0 >= 0xA0 || spd_byte1 >= 0xA0){
print_debug("DIMM overclocked. Check GeodeLink Speed\n");
print_emerg("DIMM overclocked. Check GeodeLink Speed\n");
POST_CODE(POST_PLL_MEM_FAIL);
__asm__ __volatile__("hlt\n");
hcf();
} */
/* Use the slowest DIMM */
@ -167,9 +198,9 @@ static void checkDDRMax(void)
/* current speed > max speed? */
if (GeodeLinkSpeed() > speed) {
print_debug("DIMM overclocked. Check GeodeLink Speed\r\n");
print_emerg("DIMM overclocked. Check GeodeLink Speed\r\n");
POST_CODE(POST_PLL_MEM_FAIL);
__asm__ __volatile__("hlt\n");
hcf();
}
}
@ -308,9 +339,9 @@ static void setCAS(void)
} else if ((casmap0 &= casmap1)) {
spd_byte = CASDDR[__builtin_ctz((uint32_t) casmap0)];
} else {
print_debug("DIMM CAS Latencies not compatible\r\n");
print_emerg("DIMM CAS Latencies not compatible\r\n");
POST_CODE(ERROR_DIFF_DIMMS);
__asm__ __volatile__("hlt\n");
hcf();
}
msr = rdmsr(MC_CF8F_DATA);
@ -500,7 +531,7 @@ static void EnableMTest(void)
msr.lo |= CFCLK_LOWER_TRISTATE_DIS_SET;
wrmsr(MC_CFCLK_DBUG, msr);
print_debug("Enabled MTest for TLA debug\r\n");
print_info("Enabled MTest for TLA debug\r\n");
}
static void sdram_set_registers(const struct mem_controller *ctrl)
@ -537,43 +568,53 @@ static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
uint8_t spd_byte;
banner("sdram_set_spd_register\n");
POST_CODE(POST_MEM_SETUP); // post_70h
spd_byte = spd_read_byte(DIMM0, SPD_MODULE_ATTRIBUTES);
banner("Check DIMM 0");
/* Check DIMM is not Register and not Buffered DIMMs. */
if ((spd_byte != 0xFF) && (spd_byte & 3)) {
print_debug("DIMM0 NOT COMPATIBLE\r\n");
print_emerg("DIMM0 NOT COMPATIBLE\r\n");
POST_CODE(ERROR_UNSUPPORTED_DIMM);
__asm__ __volatile__("hlt\n");
hcf();
}
banner("Check DIMM 1");
spd_byte = spd_read_byte(DIMM1, SPD_MODULE_ATTRIBUTES);
if ((spd_byte != 0xFF) && (spd_byte & 3)) {
print_debug("DIMM1 NOT COMPATIBLE\n");
print_emerg("DIMM1 NOT COMPATIBLE\n");
POST_CODE(ERROR_UNSUPPORTED_DIMM);
__asm__ __volatile__("hlt\n");
hcf();
}
POST_CODE(POST_MEM_SETUP2); // post_72h
banner("Check DDR MAX");
/* Check that the memory is not overclocked. */
checkDDRMax();
/* Size the DIMMS */
POST_CODE(POST_MEM_SETUP3); // post_73h
banner("AUTOSIZE DIMM 0");
auto_size_dimm(DIMM0);
POST_CODE(POST_MEM_SETUP4); // post_74h
banner("AUTOSIZE DIMM 1");
auto_size_dimm(DIMM1);
/* Set CAS latency */
banner("set cas latency");
POST_CODE(POST_MEM_SETUP5); // post_75h
setCAS();
/* Set all the other latencies here (tRAS, tRP....) */
banner("set all latency");
set_latencies();
/* Set Extended Mode Registers */
banner("set emrs");
set_extended_mode_registers();
banner("set ref rate");
/* Set Memory Refresh Rate */
set_refresh_rate();
@ -607,9 +648,9 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
msr = rdmsr(MC_CF07_DATA);
if ((msr.hi & ((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) ==
((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) {
print_debug("No memory in the system\r\n");
print_emerg("No memory in the system\r\n");
POST_CODE(ERROR_NO_DIMMS);
__asm__ __volatile__("hlt\n");
hcf();
}
/* Set CKEs */
@ -717,7 +758,7 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
msr.lo |= (209 << 8); /* bits[15:8] = 209 */
wrmsr(msrnum, msr);
print_debug("DRAM controller init done.\n");
print_emerg("DRAM controller init done.\n");
POST_CODE(POST_MEM_SETUP_GOOD); //0x7E
/* make sure there is nothing stale in the cache */
@ -749,6 +790,6 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
msr.lo |= 1;
wrmsr(msrnum, msr);
}
print_debug("RAM DLL lock\n");
print_info("RAM DLL lock\n");
}