Author: uwe Date: Mon Nov 1 16:20:27 2010 New Revision: 6011 URL: https://tracker.coreboot.org/trac/coreboot/changeset/6011
Log: Change Geode GX2 to use the auto DRAM detect code from Geode LX.
Also, change the GX2 boards to use it.
Add a processor speed setting function in human readable MHz and remove the useless and broken PLLMSR settings (the processor speed was hardcoded to 366MHz in pll_reset.c).
Signed-off-by: Nils Jacobs njacobs8@hetnet.nl Acked-by: Uwe Hermann uwe@hermann-uwe.de
Modified: trunk/src/include/cpu/amd/gx2def.h trunk/src/mainboard/amd/rumba/romstage.c trunk/src/mainboard/lippert/frontrunner/Kconfig trunk/src/mainboard/lippert/frontrunner/romstage.c trunk/src/mainboard/wyse/s50/romstage.c trunk/src/northbridge/amd/gx2/Kconfig trunk/src/northbridge/amd/gx2/pll_reset.c trunk/src/northbridge/amd/gx2/raminit.c
Modified: trunk/src/include/cpu/amd/gx2def.h ============================================================================== --- trunk/src/include/cpu/amd/gx2def.h Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/include/cpu/amd/gx2def.h Mon Nov 1 16:20:27 2010 (r6011) @@ -413,6 +413,13 @@ #define AES_GLD_MSR_PM (MSR_AES + 0x2004) #define AES_CONTROL (MSR_AES + 0x2006)
+/* from MC spec */ +#define MIN_MOD_BANKS 1 +#define MAX_MOD_BANKS 2 +#define MIN_DEV_BANKS 2 +#define MAX_DEV_BANKS 4 +#define MAX_COL_ADDR 17 + /* more fun stuff */ #define BM 1 /* Base Mask - map power of 2 size aligned region */ #define BMO 2 /* BM with an offset */
Modified: trunk/src/mainboard/amd/rumba/romstage.c ============================================================================== --- trunk/src/mainboard/amd/rumba/romstage.c Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/mainboard/amd/rumba/romstage.c Mon Nov 1 16:20:27 2010 (r6011) @@ -15,87 +15,21 @@ #include "southbridge/amd/cs5536/cs5536_early_smbus.c" #include "southbridge/amd/cs5536/cs5536_early_setup.c"
-static inline int spd_read_byte(unsigned device, unsigned address) -{ - return smbus_read_byte(device, address); -} +#define DIMM0 0xA0 +#define DIMM1 0xA2
-#include "northbridge/amd/gx2/raminit.h" - -static inline unsigned int fls(unsigned int x) -{ - int r; - - __asm__("bsfl %1,%0\n\t" - "jnz 1f\n\t" - "movl $32,%0\n" - "1:" : "=r" (r) : "g" (x)); - return r; -} - -static void sdram_set_spd_registers(const struct mem_controller *ctrl) +static inline int spd_read_byte(unsigned device, unsigned address) { - /* Total size of DIMM = 2^row address (byte 3) * 2^col address (byte 4) * - * component Banks (byte 17) * module banks, side (byte 5) * - * width in bits (byte 6,7) - * = Density per side (byte 31) * number of sides (byte 5) */ - /* 1. Initialize GLMC registers base on SPD values, do one DIMM for now */ - msr_t msr; - unsigned char module_banks, val; - - msr = rdmsr(MC_CF07_DATA); - - /* get module banks (sides) per dimm, SPD byte 5 */ - module_banks = spd_read_byte(0xA0, 5); - if (module_banks < 1 || module_banks > 2) - print_err("Module banks per dimm\n"); - module_banks >>= 1; - msr.hi &= ~(1 << CF07_UPPER_D0_MB_SHIFT); - msr.hi |= (module_banks << CF07_UPPER_D0_MB_SHIFT); - - /* get component banks per module bank, SPD byte 17 */ - val = spd_read_byte(0xA0, 17); - if (val < 2 || val > 4) - print_err("Component banks per module bank\n"); - val >>= 2; - msr.hi &= ~(0x1 << CF07_UPPER_D0_CB_SHIFT); - msr.hi |= (val << CF07_UPPER_D0_CB_SHIFT); - - /* get the module bank density, SPD byte 31 */ - val = spd_read_byte(0xA0, 31); - val = fls(val); - val <<= module_banks; - msr.hi &= ~(0xf << CF07_UPPER_D0_SZ_SHIFT); - msr.hi |= (val << CF07_UPPER_D0_SZ_SHIFT); - - /* page size = 2^col address */ - val = spd_read_byte(0xA0, 4); - val -= 7; - msr.hi &= ~(0x7 << CF07_UPPER_D0_PSZ_SHIFT); - msr.hi |= (val << CF07_UPPER_D0_PSZ_SHIFT); - - print_debug("computed msr.hi "); - print_debug_hex32(msr.hi); - print_debug("\n"); - - msr.lo = 0x00003000; - wrmsr(MC_CF07_DATA, msr); - - msr = rdmsr(0x20000019); - msr.hi = 0x18000108; - msr.lo = 0x696332a3; - wrmsr(0x20000019, msr); + if (device != DIMM0) + return 0xFF; /* No DIMM1, don't even try. */
+ return smbus_read_byte(device, address); }
+#include "northbridge/amd/gx2/raminit.h" +#include "northbridge/amd/gx2/pll_reset.c" #include "northbridge/amd/gx2/raminit.c" #include "lib/generic_sdram.c" - -#define PLLMSRhi 0x00001490 -#define PLLMSRlo 0x02000030 -#define PLLMSRlo1 ((0xde << 16) | (1 << 26) | (1 << 24)) -#define PLLMSRlo2 ((1<<14) |(1<<13) | (1<<0)) -#include "northbridge/amd/gx2/pll_reset.c" #include "cpu/amd/model_gx2/cpureginit.c" #include "cpu/amd/model_gx2/syspreinit.c" #include "cpu/amd/model_lx/msrinit.c"
Modified: trunk/src/mainboard/lippert/frontrunner/Kconfig ============================================================================== --- trunk/src/mainboard/lippert/frontrunner/Kconfig Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/mainboard/lippert/frontrunner/Kconfig Mon Nov 1 16:20:27 2010 (r6011) @@ -6,6 +6,7 @@ select CPU_AMD_GX2 select NORTHBRIDGE_AMD_GX2 select SOUTHBRIDGE_AMD_CS5535 + select HAVE_DEBUG_SMBUS select UDELAY_TSC select HAVE_PIRQ_TABLE select BOARD_ROMSIZE_KB_256
Modified: trunk/src/mainboard/lippert/frontrunner/romstage.c ============================================================================== --- trunk/src/mainboard/lippert/frontrunner/romstage.c Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/mainboard/lippert/frontrunner/romstage.c Mon Nov 1 16:20:27 2010 (r6011) @@ -1,4 +1,5 @@ #include <stdint.h> +#include <spd.h> #include <device/pci_def.h> #include <arch/io.h> #include <device/pnp_def.h> @@ -15,35 +16,61 @@
#include "southbridge/amd/cs5535/cs5535_early_smbus.c" #include "southbridge/amd/cs5535/cs5535_early_setup.c" -#include "northbridge/amd/gx2/raminit.h"
-/* this has to be done on a per-mainboard basis, esp. if you don't have smbus */ -static void sdram_set_spd_registers(const struct mem_controller *ctrl) +#define DIMM0 0xA0 +#define DIMM1 0xA2 + +static const unsigned char spdbytes[] = { /* 4x Qimonda HYB25DC512160CF-6 */ + 0xFF, 0xFF, /* only values used by raminit.c are set */ + [SPD_MEMORY_TYPE] = SPD_MEMORY_TYPE_SDRAM_DDR, /* (Fundamental) memory type */ + [SPD_NUM_ROWS] = 0x0D, /* Number of row address bits [13] */ + [SPD_NUM_COLUMNS] = 0x0A, /* Number of column address bits [10] */ + [SPD_NUM_DIMM_BANKS] = 1, /* Number of module rows (banks) */ + 0xFF, 0xFF, 0xFF, + [SPD_MIN_CYCLE_TIME_AT_CAS_MAX] = 0x60, /* SDRAM cycle time (highest CAS latency), RAS access time (tRAC) [6.0 ns in BCD] */ + 0xFF, 0xFF, + [SPD_REFRESH] = 0x82, /* Refresh rate/type [Self Refresh, 7.8 us] */ + [SPD_PRIMARY_SDRAM_WIDTH] = 64, /* SDRAM width (primary SDRAM) [64 bits] */ + 0xFF, 0xFF, 0xFF, + [SPD_NUM_BANKS_PER_SDRAM] = 4, /* SDRAM device attributes, number of banks on SDRAM device */ + [SPD_ACCEPTABLE_CAS_LATENCIES] = 0x1C, /* SDRAM device attributes, CAS latency [3, 2.5, 2] */ + 0xFF, 0xFF, + [SPD_MODULE_ATTRIBUTES] = 0x20, /* SDRAM module attributes [differential clk] */ + [SPD_DEVICE_ATTRIBUTES_GENERAL] = 0x40, /* SDRAM device attributes, general [Concurrent AP] */ + [SPD_SDRAM_CYCLE_TIME_2ND] = 0x60, /* SDRAM cycle time (2nd highest CAS latency) [6.0 ns in BCD] */ + 0xFF, + [SPD_SDRAM_CYCLE_TIME_3RD] = 0x75, /* SDRAM cycle time (3rd highest CAS latency) [7.5 ns in BCD] */ + 0xFF, + [SPD_tRP] = 72, /* Min. row precharge time [18 ns in units of 0.25 ns] */ + [SPD_tRRD] = 48, /* Min. row active to row active [12 ns in units of 0.25 ns] */ + [SPD_tRCD] = 72, /* Min. RAS to CAS delay [18 ns in units of 0.25 ns] */ + [SPD_tRAS] = 42, /* Min. RAS pulse width = active to precharge delay [42 ns] */ + [SPD_BANK_DENSITY] = 0x40, /* Density of each row on module [256 MB] */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + [SPD_tRFC] = 72 /* SDRAM Device Minimum Auto Refresh to Active/Auto Refresh [72 ns] */ +}; + +static inline int spd_read_byte(unsigned int device, unsigned int address) { - msr_t msr; - /* 1. Initialize GLMC registers base on SPD values, - * Hard coded as XpressROM for now */ - //print_debug("sdram_enable step 1\n"); - msr = rdmsr(0x20000018); - msr.hi = 0x10076013; - msr.lo = 0x3400; - wrmsr(0x20000018, msr); - - msr = rdmsr(0x20000019); - msr.hi = 0x18000008; - msr.lo = 0x696332a3; - wrmsr(0x20000019, msr); + if (device != DIMM0) + return 0xFF; /* No DIMM1, don't even try. */ + +#if CONFIG_DEBUG_SMBUS + if (address >= sizeof(spdbytes) || spdbytes[address] == 0xFF) { + print_err("ERROR: spd_read_byte(DIMM0, 0x"); + print_err_hex8(address); + print_err(") returns 0xff\n"); + } +#endif
+ /* Fake SPD ROM value */ + return (address < sizeof(spdbytes)) ? spdbytes[address] : 0xFF; }
+#include "northbridge/amd/gx2/raminit.h" +#include "northbridge/amd/gx2/pll_reset.c" #include "northbridge/amd/gx2/raminit.c" #include "lib/generic_sdram.c" - -#define PLLMSRhi 0x00000226 -#define PLLMSRlo 0x00000008 -#define PLLMSRlo1 ((0xde << 16) | (1 << 26) | (1 << 24)) -#define PLLMSRlo2 ((1<<14) |(1<<13) | (1<<0)) -#include "northbridge/amd/gx2/pll_reset.c" #include "cpu/amd/model_gx2/cpureginit.c" #include "cpu/amd/model_gx2/syspreinit.c" #include "cpu/amd/model_lx/msrinit.c"
Modified: trunk/src/mainboard/wyse/s50/romstage.c ============================================================================== --- trunk/src/mainboard/wyse/s50/romstage.c Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/mainboard/wyse/s50/romstage.c Mon Nov 1 16:20:27 2010 (r6011) @@ -34,92 +34,21 @@ #include "southbridge/amd/cs5536/cs5536_early_smbus.c" #include "southbridge/amd/cs5536/cs5536_early_setup.c"
-static inline int spd_read_byte(unsigned device, unsigned address) -{ - return smbus_read_byte(device, address); -} +#define DIMM0 0xA0 +#define DIMM1 0xA2
-#include "northbridge/amd/gx2/raminit.h" - - /* This is needed because ROMCC doesn`t now the ctz bitop */ -static inline unsigned int ctz(unsigned int n) +static inline int spd_read_byte(unsigned int device, unsigned int address) { - int zeros; - - n = (n ^ (n - 1)) >> 1; - for (zeros = 0; n; zeros++) - { - n >>= 1; - } - return zeros; -} - -static void sdram_set_spd_registers(const struct mem_controller *ctrl) -{ - /* Total size of DIMM = 2^row address (byte 3) * 2^col address (byte 4) * - * component Banks (byte 17) * module banks, side (byte 5) * - * width in bits (byte 6,7) - * = Density per side (byte 31) * number of sides (byte 5) */ - /* 1. Initialize GLMC registers base on SPD values, do one DIMM for now */ - msr_t msr; - unsigned char module_banks, val; - uint16_t dimm_size; - - msr = rdmsr(MC_CF07_DATA); - - /* get module banks (sides) per dimm, SPD byte 5 */ - module_banks = spd_read_byte(0xA0, 5); - if (module_banks < 1 || module_banks > 2) - print_err("Module banks per dimm\n"); - module_banks >>= 1; - msr.hi &= ~(1 << CF07_UPPER_D0_MB_SHIFT); - msr.hi |= (module_banks << CF07_UPPER_D0_MB_SHIFT); - - /* get component banks per module bank, SPD byte 17 */ - val = spd_read_byte(0xA0, 17); - if (val < 2 || val > 4) - print_err("Component banks per module bank\n"); - val >>= 2; - msr.hi &= ~(0x1 << CF07_UPPER_D0_CB_SHIFT); - msr.hi |= (val << CF07_UPPER_D0_CB_SHIFT); - - dimm_size = spd_read_byte(0xA0, 31); - 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 <<= (0 >> CF07_UPPER_D0_MB_SHIFT) & 1; /* shift to multiply by # DIMM banks */ - if (dimm_size != 0) { - dimm_size = ctz(dimm_size); - } - if (dimm_size > 7) { /* 7 is 512MB only support 512MB per DIMM */ - print_err("Only support up to 512MB \n"); - hlt(); - } - msr.hi |= dimm_size << CF07_UPPER_D0_SZ_SHIFT; - - /* page size = 2^col address */ - val = spd_read_byte(0xA0, 4); - val -= 7; - msr.hi &= ~(0x7 << CF07_UPPER_D0_PSZ_SHIFT); - msr.hi |= (val << CF07_UPPER_D0_PSZ_SHIFT); - - print_debug("computed msr.hi "); - print_debug_hex32(msr.hi); - print_debug("\n"); - - msr.lo = 0x00003400; - wrmsr(MC_CF07_DATA, msr); - - msr = rdmsr(MC_CF8F_DATA); - msr.hi = 0x18000008; - msr.lo = 0x296332a3; - wrmsr(MC_CF8F_DATA, msr); + if (device != DIMM0) + return 0xFF; /* No DIMM1, don't even try. */
+ return smbus_read_byte(device, address); }
+#include "northbridge/amd/gx2/raminit.h" +#include "northbridge/amd/gx2/pll_reset.c" #include "northbridge/amd/gx2/raminit.c" #include "lib/generic_sdram.c" -#include "northbridge/amd/gx2/pll_reset.c" #include "cpu/amd/model_gx2/cpureginit.c" #include "cpu/amd/model_gx2/syspreinit.c" #include "cpu/amd/model_lx/msrinit.c"
Modified: trunk/src/northbridge/amd/gx2/Kconfig ============================================================================== --- trunk/src/northbridge/amd/gx2/Kconfig Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/northbridge/amd/gx2/Kconfig Mon Nov 1 16:20:27 2010 (r6011) @@ -21,3 +21,9 @@ bool select GEODE_VSA
+# Valid PROCESSOR_MHZ options: 300/366/400 MHz. +config PROCESSOR_MHZ + int + default 366 + depends on NORTHBRIDGE_AMD_GX2 +
Modified: trunk/src/northbridge/amd/gx2/pll_reset.c ============================================================================== --- trunk/src/northbridge/amd/gx2/pll_reset.c Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/northbridge/amd/gx2/pll_reset.c Mon Nov 1 16:20:27 2010 (r6011) @@ -63,13 +63,25 @@
#define DEFAULT_MDIV 3 #define DEFAULT_VDIV 2 -#define DEFAULT_FBDIV 22 // 366/244 ; 24 400/266 018 ;300/200
static void pll_reset(void) { msr_t msrGlcpSysRstpll; unsigned MDIV_VDIV_FBDIV; unsigned SyncBits; /* store the sync bits in up ebx */ + unsigned DEFAULT_FBDIV; + + if (CONFIG_PROCESSOR_MHZ == 400) { + DEFAULT_FBDIV = 24; + } else if (CONFIG_PROCESSOR_MHZ == 366) { + DEFAULT_FBDIV = 22; + } else if (CONFIG_PROCESSOR_MHZ == 300) { + DEFAULT_FBDIV = 18; + } else { + printk(BIOS_ERR, "Unsupported PROCESSOR_MHZ setting!\n"); + post_code(POST_PLL_CPU_VER_FAIL); + __asm__ __volatile__("hlt\n"); + }
/* clear the Bypass bit */
@@ -179,3 +191,10 @@ } /* we haven't configured the PLL; do it now */
} + +static unsigned int GeodeLinkSpeed(void) +{ + unsigned geodelinkspeed; + geodelinkspeed = ((CONFIG_PROCESSOR_MHZ * DEFAULT_VDIV) / DEFAULT_MDIV); + return (geodelinkspeed); +}
Modified: trunk/src/northbridge/amd/gx2/raminit.c ============================================================================== --- trunk/src/northbridge/amd/gx2/raminit.c Mon Nov 1 15:39:49 2010 (r6010) +++ trunk/src/northbridge/amd/gx2/raminit.c Mon Nov 1 16:20:27 2010 (r6011) @@ -1,7 +1,521 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2010 Nils Jacobs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include <cpu/amd/gx2def.h> +#include <spd.h> + +static const unsigned char NumColAddr[] = { + 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +}; + +static void banner(const char *s) +{ + printk(BIOS_DEBUG, " * %s\n", s); +} + +static void hcf(void) +{ + print_emerg("DIE\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; + uint16_t dimm_size; + uint8_t spd_byte; + msr_t msr; + + 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_emerg("Number of module banks not compatible\n"); + post_code(ERROR_BANK_SET); + 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_emerg("Number of device banks not compatible\n"); + post_code(ERROR_BANK_SET); + hcf(); + } + dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT; + banner("SPDNUMROWS"); + + /*; Field: DIMM size + *; EEPROM byte usage: (3) Number of Row Addresses + *; (4) Number of Column Addresses + *; (5) Number of DIMM Banks + *; (31) Module Bank Density + *; Size = Module Density * Module Banks + */ + if ((spd_read_byte(dimm, SPD_NUM_ROWS) & 0xF0) + || (spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) { + print_emerg("Assymetirc DIMM not compatible\n"); + post_code(ERROR_UNSUPPORTED_DIMM); + 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>7"); + if (dimm_size > 7) { /* 7 is 512MB only support 512MB per DIMM */ + print_emerg("Only support up to 512MB per DIMM\n"); + post_code(ERROR_DENSITY_DIMM); + hcf(); + } + dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT; + banner("PAGESIZE"); + +/*; Field: PAGE size +*; EEPROM byte usage: (4) Number of Column Addresses +*; PageSize = 2^# Column Addresses * Data width in bytes (should be 8bytes for a normal DIMM) +* +*; But this really works by magic. +*; If ma[11:0] is the memory address pins, and pa[13:0] is the physical column address +*; that MC generates, here is how the MC assigns the pa onto the ma pins: +* +*;ma 11 10 09 08 07 06 05 04 03 02 01 00 +*;-------------------------------------------------------------------------------------------------------------------------------------- +*;pa 09 08 07 06 05 04 03 (7 col addr bits = 1K page size) +*;pa 10 09 08 07 06 05 04 03 (8 col addr bits = 2K page size) +*;pa 11 10 09 08 07 06 05 04 03 (9 col addr bits = 4K page size) +*;pa 12 11 10 09 08 07 06 05 04 03 (10 col addr bits = 8K page size) +*;pa 13 AP 12 11 10 09 08 07 06 05 04 03 (11 col addr bits = 16K page size) +*; *AP=autoprecharge bit +* +*; Remember that pa[2:0] are zeroed out since it's a 64-bit data bus (8 bytes), +*; so lower 3 address bits are dont_cares.So from the table above, +*; it's easier to see what the old code is doing: if for example,#col_addr_bits=7(06h), +*; 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_emerg("DIMM page size not compatible\n"); + post_code(ERROR_SET_PAGE); + hcf(); + } + banner(">11address test"); + spd_byte -= 7; + if (spd_byte > 4) { /* if the value is above 4 it means >11 col address lines */ + spd_byte = 7; /* which means >16k 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; + } else { + msr.hi &= 0x0000FFFF; + msr.hi |= dimm_setting << 16; + } + wrmsr(MC_CF07_DATA, msr); + banner("ALL DONE"); +} + +static void checkDDRMax(void) +{ + uint8_t spd_byte0, spd_byte1; + uint16_t speed; + + /* PC133 identifier */ + spd_byte0 = spd_read_byte(DIMM0, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); + if (spd_byte0 == 0xFF) { + spd_byte0 = 0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); + if (spd_byte1 == 0xFF) { + spd_byte1 = 0; + } + + /* Use the slowest DIMM */ + if (spd_byte0 < spd_byte1) { + spd_byte0 = spd_byte1; + } + + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + speed = 20000 / (((spd_byte0 >> 4) * 10) + (spd_byte0 & 0x0F)); + + /* current speed > max speed? */ + if (GeodeLinkSpeed() > speed) { + print_emerg("DIMM overclocked. Check GeodeLink Speed\n"); + post_code(POST_PLL_MEM_FAIL); + hcf(); + } +} + +const uint16_t REF_RATE[] = { 15, 3, 7, 31, 62, 125 }; /* ns */ + +static void set_refresh_rate(void) +{ + uint8_t spd_byte0, spd_byte1; + uint16_t rate0, rate1; + msr_t msr; + + spd_byte0 = spd_read_byte(DIMM0, SPD_REFRESH); + spd_byte0 &= 0xF; + if (spd_byte0 > 5) { + spd_byte0 = 5; + } + rate0 = REF_RATE[spd_byte0]; + + spd_byte1 = spd_read_byte(DIMM1, SPD_REFRESH); + spd_byte1 &= 0xF; + if (spd_byte1 > 5) { + spd_byte1 = 5; + } + rate1 = REF_RATE[spd_byte1]; + + /* Use the faster rate (lowest number) */ + if (rate0 > rate1) { + rate0 = rate1; + } + + msr = rdmsr(MC_CF07_DATA); + msr.lo |= ((rate0 * (GeodeLinkSpeed() / 2)) / 16) + << CF07_LOWER_REF_INT_SHIFT; + wrmsr(MC_CF07_DATA, msr); +} + +const uint8_t CASDDR[] = { 5, 5, 2, 6, 0 }; /* 1(1.5), 1.5, 2, 2.5, 0 */ + +static u8 getcasmap(u32 dimm, u16 glspeed) +{ + u16 dimm_speed; + u8 spd_byte, casmap, casmap_shift=0; + + /************************** DIMM0 **********************************/ + casmap = spd_read_byte(dimm, SPD_ACCEPTABLE_CAS_LATENCIES); + if (casmap != 0xFF) { + /* IF -.5 timing is supported, check -.5 timing > GeodeLink */ + spd_byte = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_2ND); + if (spd_byte != 0) { + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + dimm_speed = 20000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)); + if (dimm_speed >= glspeed) { + casmap_shift = 1; /* -.5 is a shift of 1 */ + /* IF -1 timing is supported, check -1 timing > GeodeLink */ + spd_byte = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_3RD); + if (spd_byte != 0) { + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + dimm_speed = 20000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)); + if (dimm_speed >= glspeed) { + casmap_shift = 2; /* -1 is a shift of 2 */ + } + } /* SPD_SDRAM_CYCLE_TIME_3RD (-1) !=0 */ + } else { + casmap_shift = 0; + } + } /* SPD_SDRAM_CYCLE_TIME_2ND (-.5) !=0 */ + /* set the casmap based on the shift to limit possible CAS settings */ + spd_byte = 31 - __builtin_clz((uint32_t) casmap); + /* just want bits in the lower byte since we have to cast to a 32 */ + casmap &= 0xFF << (spd_byte - casmap_shift); + } else { /* No DIMM */ + casmap = 0; + } + return casmap; +} + +static void setCAS(void) +{ +/*;***************************************************************************** +;* +;* setCAS +;* EEPROM byte usage: (18) SDRAM device attributes - CAS latency +;* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5 +;* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1 +;* +;* The CAS setting is based on the information provided in each DIMMs SPD. +;* The speed at which a DIMM can run is described relative to the slowest +;* CAS the DIMM supports. Each speed for the relative CAS settings is +;* checked that it is within the GeodeLink speed. If it isn't within the GeodeLink +;* speed, the CAS setting is removed from the list of good settings for +;* the DIMM. This is done for both DIMMs and the lists are compared to +;* find the lowest common CAS latency setting. If there are no CAS settings +;* in common we out a ERROR_DIFF_DIMMS (78h) to port 80h and halt. +;* +;* Entry: +;* Exit: Set fastest CAS Latency based on GeodeLink speed and SPD information. +;* Destroys: We really use everything ! +;*****************************************************************************/ + uint16_t glspeed; + uint8_t spd_byte, casmap0, casmap1; + msr_t msr; + + glspeed = GeodeLinkSpeed(); + + casmap0 = getcasmap(DIMM0, glspeed); + casmap1 = getcasmap(DIMM1, glspeed); + + /********************* CAS_LAT MAP COMPARE ***************************/ + if (casmap0 == 0) { + spd_byte = CASDDR[__builtin_ctz(casmap1)]; + } else if (casmap1 == 0) { + spd_byte = CASDDR[__builtin_ctz(casmap0)]; + } else if ((casmap0 &= casmap1)) { + spd_byte = CASDDR[__builtin_ctz(casmap0)]; + } else { + print_emerg("DIMM CAS Latencies not compatible\n"); + post_code(ERROR_DIFF_DIMMS); + hcf(); + } + + msr = rdmsr(MC_CF8F_DATA); + msr.lo &= ~(7 << CF8F_LOWER_CAS_LAT_SHIFT); + msr.lo |= spd_byte << CF8F_LOWER_CAS_LAT_SHIFT; + wrmsr(MC_CF8F_DATA, msr); +} + +static void set_latencies(void) +{ + uint32_t memspeed, dimm_setting; + uint8_t spd_byte0, spd_byte1; + msr_t msr; + + memspeed = GeodeLinkSpeed() / 2; + dimm_setting = 0; + + /* MC_CF8F setup */ + /* tRAS */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRAS); + if (spd_byte0 == 0xFF) { + spd_byte0 = 0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRAS); + if (spd_byte1 == 0xFF) { + spd_byte1 = 0; + } + if (spd_byte0 < spd_byte1) { + spd_byte0 = spd_byte1; + } + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = (spd_byte0 * memspeed) / 1000; + if (((spd_byte0 * memspeed) % 1000)) { + ++spd_byte1; + } + if (spd_byte1 > 6) { + --spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT; + + /* tRP */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRP); + if (spd_byte0 == 0xFF) { + spd_byte0 = 0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRP); + if (spd_byte1 == 0xFF) { + spd_byte1 = 0; + } + if (spd_byte0 < spd_byte1) { + spd_byte0 = spd_byte1; + } + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000; + if ((((spd_byte0 >> 2) * memspeed) % 1000)) { + ++spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_PRE2ACT_SHIFT; + + /* tRCD */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRCD); + if (spd_byte0 == 0xFF) { + spd_byte0 = 0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRCD); + if (spd_byte1 == 0xFF) { + spd_byte1 = 0; + } + if (spd_byte0 < spd_byte1) { + spd_byte0 = spd_byte1; + } + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000; + if ((((spd_byte0 >> 2) * memspeed) % 1000)) { + ++spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2CMD_SHIFT; + + /* tRRD */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRRD); + if (spd_byte0 == 0xFF) { + spd_byte0 = 0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRRD); + if (spd_byte1 == 0xFF) { + spd_byte1 = 0; + } + if (spd_byte0 < spd_byte1) { + spd_byte0 = spd_byte1; + } + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000; + if ((((spd_byte0 >> 2) * memspeed) % 1000)) { + ++spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2ACT_SHIFT; + + /* tRC = tRP + tRAS */ + dimm_setting |= (((dimm_setting >> CF8F_LOWER_ACT2PRE_SHIFT) & 0x0F) + + ((dimm_setting >> CF8F_LOWER_PRE2ACT_SHIFT) & 0x07)) + << CF8F_LOWER_REF2ACT_SHIFT; + + msr = rdmsr(MC_CF8F_DATA); + msr.lo &= 0xF00000FF; + msr.lo |= dimm_setting; + msr.hi |= CF8F_UPPER_REORDER_DIS_SET; + wrmsr(MC_CF8F_DATA, msr); + printk(BIOS_DEBUG, "MSR MC_CF8F_DATA (%08x) value is %08x:%08x\n", + MC_CF8F_DATA, msr.hi, msr.lo); +} + +static void set_extended_mode_registers(void) +{ + uint8_t spd_byte0, spd_byte1; + msr_t msr; + spd_byte0 = spd_read_byte(DIMM0, SPD_DEVICE_ATTRIBUTES_GENERAL); + if (spd_byte0 == 0xFF) { + spd_byte0 = 0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_DEVICE_ATTRIBUTES_GENERAL); + if (spd_byte1 == 0xFF) { + spd_byte1 = 0; + } + spd_byte1 &= spd_byte0; + + msr = rdmsr(MC_CF07_DATA); + if (spd_byte1 & 1) { /* Drive Strength Control */ + msr.lo |= CF07_LOWER_EMR_DRV_SET; + } + if (spd_byte1 & 2) { /* FET Control */ + msr.lo |= CF07_LOWER_EMR_QFC_SET; + } + wrmsr(MC_CF07_DATA, msr); +}
static void sdram_set_registers(const struct mem_controller *ctrl) { + msr_t msr; + uint32_t msrnum; + + /* Set Refresh Staggering */ + msrnum = MC_CF07_DATA; + msr = rdmsr(msrnum); + msr.lo &= ~0xC0; + msr.lo |= 0x0; /* set refresh to 4SDRAM clocks */ + wrmsr(msrnum, msr); + + /* Memory Interleave: Set HOI here otherwise default is LOI */ + /* msrnum = MC_CF8F_DATA; + msr = rdmsr(msrnum); + msr.hi |= CF8F_UPPER_HOI_LOI_SET; + wrmsr(msrnum, msr); */ +} + +static void sdram_set_spd_registers(const struct mem_controller *ctrl) +{ + uint8_t spd_byte; + + banner("sdram_set_spd_register"); + 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_emerg("DIMM0 NOT COMPATIBLE\n"); + post_code(ERROR_UNSUPPORTED_DIMM); + hcf(); + } + banner("Check DIMM 1"); + spd_byte = spd_read_byte(DIMM1, SPD_MODULE_ATTRIBUTES); + if ((spd_byte != 0xFF) && (spd_byte & 3)) { + print_emerg("DIMM1 NOT COMPATIBLE\n"); + post_code(ERROR_UNSUPPORTED_DIMM); + 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(); }
/* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence @@ -40,18 +554,6 @@ } //print_debug("sdram_enable step 4\n");
- /* 5. set refresh interval */ - msr = rdmsr(0x20000018); - msr.lo &= ~(0xffff << 8); - msr.lo |= (0x34 << 8); - wrmsr(0x20000018, msr); - /* set refresh staggering to 4 SDRAM clocks */ - msr = rdmsr(0x20000018); - msr.lo &= ~(0x03 << 6); - msr.lo |= (0x00 << 6); - wrmsr(0x20000018, msr); - //print_debug("sdram_enable step 5\n"); - /* 6. enable DLL, load Extended Mode Register by set and clear PROG_DRAM */ msr = rdmsr(MC_CF07_DATA); msr.lo |= ((0x01 << 28) | 0x01);