diff options
author | Edwin Beasant <edwin_beasant@virtensys.com> | 2010-06-10 15:24:57 +0000 |
---|---|---|
committer | Edwin Beasant <edwin_beasant@virtensys.com> | 2010-06-10 15:24:57 +0000 |
commit | f333ba09580c00a6f27e3ee0796431f5df936ecf (patch) | |
tree | d9d961b45e248d59bf8e3e582b1619887d1921b9 /src/cpu/amd | |
parent | 1965a237124cc8e988cf760eb7e9a61efb2adabb (diff) |
This commit updates the Geode LX GLCP delay control setup from the v2 way to the v3 way.
This resolves problems with terminated DRAM modules.
Signed-off-by: Edwin Beasant <edwin_beasant@virtensys.com>
Acked-by: Roland G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5629 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/cpu/amd')
-rw-r--r-- | src/cpu/amd/model_lx/cpureginit.c | 286 | ||||
-rw-r--r-- | src/cpu/amd/model_lx/msrinit.c | 10 |
2 files changed, 124 insertions, 172 deletions
diff --git a/src/cpu/amd/model_lx/cpureginit.c b/src/cpu/amd/model_lx/cpureginit.c index 62fa973a8c..6e7de84c6a 100644 --- a/src/cpu/amd/model_lx/cpureginit.c +++ b/src/cpu/amd/model_lx/cpureginit.c @@ -1,6 +1,6 @@ /* * This file is part of the coreboot project. - * + * * Copyright (C) 2006 Indrek Kruusa <indrek.kruusa@artecdesign.ee> * Copyright (C) 2006 Ronald G. Minnich <rminnich@gmail.com> * Copyright (C) 2007 Advanced Micro Devices, Inc. @@ -25,200 +25,156 @@ ;* SetDelayControl ;* ;*************************************************************************/ -static void SetDelayControl(void) +#include "cpu/x86/msr.h" + + + + +/** + * Delay Control Settings table from AMD (MCP 0x4C00000F). + */ +static const msrinit_t delay_msr_table[] = { + {CPU_BC_MSS_ARRAY_CTL0, {.hi = 0x00000000, .lo = 0x2814D352}}, + {CPU_BC_MSS_ARRAY_CTL1, {.hi = 0x00000000, .lo = 0x1068334D}}, + {CPU_BC_MSS_ARRAY_CTL2, {.hi = 0x00000106, .lo = 0x83104104}}, +}; + + + +static const struct delay_controls { + u8 dimms; + u8 devices; + u32 slow_hi; + u32 slow_low; + u32 fast_hi; + u32 fast_low; +} delay_control_table[] = { + /* DIMMs Devs Slow (<=333MHz) Fast (>334MHz) */ + { 1, 4, 0x0837100FF, 0x056960004, 0x0827100FF, 0x056960004 }, + { 1, 8, 0x0837100AA, 0x056960004, 0x0827100AA, 0x056960004 }, + { 1, 16, 0x0837100AA, 0x056960004, 0x082710055, 0x056960004 }, + { 2, 8, 0x0837100A5, 0x056960004, 0x082710000, 0x056960004 }, + { 2, 16, 0x0937100A5, 0x056960004, 0x0C27100A5, 0x056960004 }, + { 2, 20, 0x0B37100A5, 0x056960004, 0x0B27100A5, 0x056960004 }, + { 2, 24, 0x0B37100A5, 0x056960004, 0x0B27100A5, 0x056960004 }, + { 2, 32, 0x0B37100A5, 0x056960004, 0x0B2710000, 0x056960004 }, +}; + +/* + * Bit 55 (disable SDCLK 1,3,5) should be set if there is a single DIMM + * in slot 0, but it should be clear for all 2 DIMM settings and if a + * single DIMM is in slot 1. Bits 54:52 should always be set to '111'. + * + * Settings for single DIMM and no VTT termination (like DB800 platform) + * 0xF2F100FF 0x56960004 + * ------------------------------------- + * ADDR/CTL have 22 ohm series R + * DQ/DQM/DQS have 33 ohm series R + */ + +/** + * This is Black Magic DRAM timing juju[1]. + * + * DRAM delay depends on CPU clock, memory bus clock, memory bus loading, + * memory bus termination, your middle initial (ha! caught you!), GeodeLink + * clock rate, and DRAM timing specifications. + * + * From this the code computes a number which is "known to work". No, + * hardware is not an exact science. And, finally, if an FS2 (JTAG debugger) + * is hooked up, then just don't do anything. This code was written by a master + * of the Dark Arts at AMD and should not be modified in any way. + * + * [1] (http://www.thefreedictionary.com/juju) + * + * @param dimm0 The SMBus address of DIMM 0 (mainboard dependent). + * @param dimm1 The SMBus address of DIMM 1 (mainboard dependent). + * @param terminated The bus is terminated. (mainboard dependent). + */ +static void SetDelayControl(u8 dimm0, u8 dimm1, int terminated) { - unsigned int msrnum, glspeed; - unsigned char spdbyte0, spdbyte1; + u32 glspeed; + u8 spdbyte0, spdbyte1, dimms, i; msr_t msr; glspeed = GeodeLinkSpeed(); - /* fix delay controls for DM and IM arrays */ - msrnum = CPU_BC_MSS_ARRAY_CTL0; - msr.hi = 0; - msr.lo = 0x2814D352; - wrmsr(msrnum, msr); - - msrnum = CPU_BC_MSS_ARRAY_CTL1; - msr.hi = 0; - msr.lo = 0x1068334D; - wrmsr(msrnum, msr); - - msrnum = CPU_BC_MSS_ARRAY_CTL2; - msr.hi = 0x00000106; - msr.lo = 0x83104104; - wrmsr(msrnum, msr); + /* Fix delay controls for DM and IM arrays. */ + for (i = 0; i < ARRAY_SIZE(delay_msr_table); i++) + wrmsr(delay_msr_table[i].index, delay_msr_table[i].msr); - msrnum = GLCP_FIFOCTL; - msr = rdmsr(msrnum); + msr = rdmsr(GLCP_FIFOCTL); msr.hi = 0x00000005; - wrmsr(msrnum, msr); + wrmsr(GLCP_FIFOCTL, msr); - /* Enable setting */ - msrnum = CPU_BC_MSS_ARRAY_CTL_ENA; + /* Enable setting. */ msr.hi = 0; msr.lo = 0x00000001; - wrmsr(msrnum, msr); + wrmsr(CPU_BC_MSS_ARRAY_CTL_ENA, msr); - /* Debug Delay Control Setup Check - Leave it alone if it has been setup. FS2 or something is here. */ - msrnum = GLCP_DELAY_CONTROLS; - msr = rdmsr(msrnum); - if (msr.lo & ~(0x7C0)) { + /* Debug Delay Control setup check. + * Leave it alone if it has been setup. FS2 or something is here. + */ + msr = rdmsr(GLCP_DELAY_CONTROLS); + if (msr.lo & ~(DELAY_LOWER_STATUS_MASK)) return; - } - /* - * Delay Controls based on DIMM loading. UGH! - * # of Devices = Module Width (SPD6) / Device Width(SPD13) * Physical Banks(SPD5) - * Note - We only support module width of 64. + /* Delay Controls based on DIMM loading. UGH! + * Number of devices = module width (SPD 6) / device width (SPD 13) + * * physical banks (SPD 5) + * + * Note: We only support a module width of 64. */ - spdbyte0 = spd_read_byte(DIMM0, SPD_PRIMARY_SDRAM_WIDTH); + dimms = 0; + spdbyte0 = spd_read_byte(dimm0, SPD_PRIMARY_SDRAM_WIDTH); if (spdbyte0 != 0xFF) { - spdbyte0 = (unsigned char)64 / spdbyte0 * - (unsigned char)(spd_read_byte(DIMM0, SPD_NUM_DIMM_BANKS)); + dimms++; + spdbyte0 = (u8)64 / spdbyte0 * + (u8)(spd_read_byte(dimm0, SPD_NUM_DIMM_BANKS)); } else { spdbyte0 = 0; } - spdbyte1 = spd_read_byte(DIMM1, SPD_PRIMARY_SDRAM_WIDTH); + spdbyte1 = spd_read_byte(dimm1, SPD_PRIMARY_SDRAM_WIDTH); if (spdbyte1 != 0xFF) { - spdbyte1 = (unsigned char)64 / spdbyte1 * - (unsigned char)(spd_read_byte(DIMM1, SPD_NUM_DIMM_BANKS)); + dimms++; + spdbyte1 = (u8)64 / spdbyte1 * + (u8)(spd_read_byte(dimm1, SPD_NUM_DIMM_BANKS)); } else { spdbyte1 = 0; } -/* The current thinking. Subject to change... - -; "FUTURE ROBUSTNESS" PROPOSAL -; ---------------------------- -; DIMM Max MBUS MC 0x2000001A bits 26:24 -;DIMMs devices Frequency MCP 0x4C00000F Setting vvv -;----- ------- --------- ---------------------- ---------- -;1 4 400MHz 0x82*100FF 0x56960004 4 -;1 8 400MHz 0x82*100AA 0x56960004 4 -;1 16 400MHz 0x82*10055 0x56960004 4 -; -;2 4,4 400MHz 0x82710000 0x56960004 4 -; -;1 4 <=333MHz 0x83*100FF 0x56960004 3 -;1 8 <=333MHz 0x83*100AA 0x56960004 3 -;1 16 <=333MHz 0x83*100AA 0x56960004 3 -; -;2 4,4 <=333MHz 0x837100A5 0x56960004 3 -;2 8,8 <=333MHz 0x937100A5 0x56960004 3 -; -;========================================================================= -;* - Bit 55 (disable SDCLK 1,3,5) should be set if there is a single DIMM in slot 0, -; but it should be clear for all 2 DIMM settings and if a single DIMM is in slot 1. -; Bits 54:52 should always be set to '111'. - -;No VTT termination -;------------------------------------- -;ADDR/CTL have 22 ohm series R -;DQ/DQM/DQS have 33 ohm series R -; -; DIMM Max MBUS -;DIMMs devices Frequency MCP 0x4C00000F Setting -;----- ------- --------- ---------------------- -;1 4 400MHz 0xF2F100FF 0x56960004 4 The No VTT changes improve timing. -;1 8 400MHz 0xF2F100FF 0x56960004 4 -;1 4 <=333MHz 0xF2F100FF 0x56960004 3 -;1 8 <=333MHz 0xF2F100FF 0x56960004 3 -;1 16 <=333MHz 0xF2F100FF 0x56960004 3 -*/ + /* Zero GLCP_DELAY_CONTROLS MSR */ msr.hi = msr.lo = 0; - if (spdbyte0 == 0 || spdbyte1 == 0) { - /* one dimm solution */ - if (spdbyte1 == 0) { - msr.hi |= 0x000800000; - } - spdbyte0 += spdbyte1; - if (spdbyte0 > 8) { - /* large dimm */ - if (glspeed < 334) { - msr.hi |= 0x0837100AA; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x082710055; - msr.lo |= 0x056960004; - } - } else if (spdbyte0 > 4) { - /* medium dimm */ - if (glspeed < 334) { - msr.hi |= 0x0837100AA; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0827100AA; - msr.lo |= 0x056960004; - } - } else { - /* small dimm */ - if (glspeed < 334) { - msr.hi |= 0x0837100FF; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0827100FF; - msr.lo |= 0x056960004; - } - } - } else { - /* two dimm solution */ - spdbyte0 += spdbyte1; - if (spdbyte0 > 24) { - /* huge dimms */ - if (glspeed < 334) { - msr.hi |= 0x0B37100A5; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0B2710000; - msr.lo |= 0x056960004; - } - } else if (spdbyte0 > 16) { - /* large dimms */ - if (glspeed < 334) { - msr.hi |= 0x0B37100A5; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0B27100A5; - msr.lo |= 0x056960004; - } - } else if (spdbyte0 >= 8) { - /* medium dimms */ - if (glspeed < 334) { - msr.hi |= 0x0937100A5; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0C27100A5; - msr.lo |= 0x056960004; - } - } else { - /* small dimms */ + /* Save some power, disable clock to second DIMM if it is empty. */ + if (spdbyte1 == 0) + msr.hi |= DELAY_UPPER_DISABLE_CLK135; + + spdbyte0 += spdbyte1; + + if ((dimms == 1) && (terminated == DRAM_TERMINATED)) { + msr.hi = 0xF2F100FF; + msr.lo = 0x56960004; + } else for (i = 0; i < ARRAY_SIZE(delay_control_table); i++) { + if ((dimms == delay_control_table[i].dimms) && + (spdbyte0 <= delay_control_table[i].devices)) { if (glspeed < 334) { - msr.hi |= 0x0837100A5; - msr.lo |= 0x056960004; + msr.hi |= delay_control_table[i].slow_hi; + msr.lo |= delay_control_table[i].slow_low; } else { - msr.hi |= 0x082710000; - msr.lo |= 0x056960004; + msr.hi |= delay_control_table[i].fast_hi; + msr.lo |= delay_control_table[i].fast_low; } + break; } } - 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("\n"); wrmsr(GLCP_DELAY_CONTROLS, msr); - print_debug("SetDelayControl done\n"); - return; } /* ***************************************************************************/ /* * cpuRegInit*/ /* ***************************************************************************/ -void cpuRegInit(void) +void cpuRegInit(int debug_clock_disable, u8 dimm0, u8 dimm1, int terminated) { int msrnum; msr_t msr; @@ -259,7 +215,7 @@ void cpuRegInit(void) /* Set the Delay Control in GLCP */ print_debug("Set the Delay Control in GLCP\n"); - SetDelayControl(); + SetDelayControl(dimm0, dimm1, terminated); /* Enable RSDC */ print_debug("Enable RSDC\n"); @@ -294,12 +250,12 @@ void cpuRegInit(void) /* Disable the debug clock to save power. */ /* NOTE: leave it enabled for fs2 debug */ -#if 0 - msrnum = GLCP_DBGCLKCTL; - msr.hi = 0; - msr.lo = 0; - wrmsr(msrnum, msr); -#endif + if (debug_clock_disable && 0) { + msrnum = GLCP_DBGCLKCTL; + msr.hi = 0; + msr.lo = 0; + wrmsr(msrnum, msr); + } /* Setup throttling delays to proper mode if it is ever enabled. */ print_debug("Setup throttling delays to proper mode\n"); diff --git a/src/cpu/amd/model_lx/msrinit.c b/src/cpu/amd/model_lx/msrinit.c index 53c0a851dc..35c9ae4f25 100644 --- a/src/cpu/amd/model_lx/msrinit.c +++ b/src/cpu/amd/model_lx/msrinit.c @@ -18,13 +18,9 @@ */ #include <stdlib.h> +#include "cpu/x86/msr.h" -struct msrinit { - u32 msrnum; - msr_t msr; -}; - -static const struct msrinit msr_table[] = +static const msrinit_t msr_table[] = { {CPU_RCONF_DEFAULT, {.hi = 0x24fffc02,.lo = 0x1000A000}}, /* Setup access to cache under 1MB. * Rom Properties: Write Serialize, WriteProtect. @@ -49,7 +45,7 @@ static void msr_init(void) { int i; for (i = 0; i < ARRAY_SIZE(msr_table); i++) - wrmsr(msr_table[i].msrnum, msr_table[i].msr); + wrmsr(msr_table[i].index, msr_table[i].msr); } |