aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdk8/raminit.c
diff options
context:
space:
mode:
authorEric Biederman <ebiederm@xmission.com>2003-10-11 06:20:25 +0000
committerEric Biederman <ebiederm@xmission.com>2003-10-11 06:20:25 +0000
commit83b991afff40e12a8b6756af06a472842edb1a66 (patch)
treea441ff0d88afcb0a07cf22dc3653db3e07a05c98 /src/northbridge/amd/amdk8/raminit.c
parent080038bfbd8fdf08bac12476a3789495e6f705ca (diff)
- O2, enums, and switch statements work in romcc
- Support for compiling romcc on non x86 platforms - new romc options -msse and -mmmx for specifying extra registers to use - Bug fixes to device the device disable/enable framework and an amd8111 implementation - Move the link specification to the chip specification instead of the path - Allow specifying devices with internal bridges. - Initial via epia support - Opteron errata fixes git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1200 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/amd/amdk8/raminit.c')
-rw-r--r--src/northbridge/amd/amdk8/raminit.c320
1 files changed, 266 insertions, 54 deletions
diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c
index 802e4318b4..437ef2655d 100644
--- a/src/northbridge/amd/amdk8/raminit.c
+++ b/src/northbridge/amd/amdk8/raminit.c
@@ -124,6 +124,9 @@
#define DCH_MEMCLK_EN3 (1 << 29)
/* Function 3 */
+#define MCA_NB_CONFIG 0x44
+#define MNC_ECC_EN (1 << 22)
+#define MNC_CHIPKILL_EN (1 << 23)
#define SCRUB_CONTROL 0x58
#define SCRUB_NONE 0
#define SCRUB_40ns 1
@@ -1127,23 +1130,6 @@ static void spd_set_ram_size(const struct mem_controller *ctrl)
}
}
-//BY LYH //Fill next base reg with right value
-static void fill_last(unsigned long node_id,unsigned long base)
-{
- unsigned i;
- unsigned base_reg;
- base &=0xffff0000;
- device_t device;
- for(device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); device
-+= PCI_DEV(0, 1, 0)) {
- for(i=node_id+1;i<=7;i++) {
- base_reg=0x40+(i<<3);
- pci_write_config32(device,base_reg,base);
- }
- }
-}
-//BY LYH END
-
static void route_dram_accesses(const struct mem_controller *ctrl,
unsigned long base_k, unsigned long limit_k)
{
@@ -1177,7 +1163,12 @@ static void set_top_mem(unsigned tom_k)
{
/* Error if I don't have memory */
if (!tom_k) {
- die("No memory");
+ set_bios_reset();
+ print_debug("No memory - reset");
+ /* enable cf9 */
+ pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1);
+ /* reset */
+ outb(0x0e, 0x0cf9);
}
#if 1
@@ -1204,15 +1195,102 @@ static void set_top_mem(unsigned tom_k)
wrmsr(TOP_MEM, msr);
}
-static void order_dimms(const struct mem_controller *ctrl)
+static unsigned long interleave_chip_selects(const struct mem_controller *ctrl)
{
- unsigned long tom, tom_k, base_k;
- unsigned node_id;
+ /* 35 - 25 */
+ static const uint32_t csbase_low[] = {
+ /* 32MB */ (1 << (13 - 4)),
+ /* 64MB */ (1 << (14 - 4)),
+ /* 128MB */ (1 << (14 - 4)),
+ /* 256MB */ (1 << (15 - 4)),
+ /* 512MB */ (1 << (15 - 4)),
+ /* 1GB */ (1 << (16 - 4)),
+ /* 2GB */ (1 << (16 - 4)),
+ };
+ uint32_t csbase_inc;
+ int chip_selects, index;
+ int bits;
+ int dual_channel;
+ unsigned common_size;
+ uint32_t csbase, csmask;
+
+ /* See if all of the memory chip selects are the same size
+ * and if so count them.
+ */
+ chip_selects = 0;
+ common_size = 0;
+ for(index = 0; index < 8; index++) {
+ unsigned size;
+ uint32_t value;
+
+ value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2));
+
+ /* Is it enabled? */
+ if (!(value & 1)) {
+ continue;
+ }
+ chip_selects++;
+ size = value >> 21;
+ if (common_size == 0) {
+ common_size = size;
+ }
+ /* The size differed fail */
+ if (common_size != size) {
+ return 0;
+ }
+ }
+ /* Chip selects can only be interleaved when there is
+ * more than one and their is a power of two of them.
+ */
+ bits = log2(chip_selects);
+ if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) {
+ return 0;
+
+ }
+ /* Also we run out of address mask bits if we try and interleave 8 4GB dimms */
+ if ((bits == 3) && (common_size == (1 << (32 - 3)))) {
+ print_debug("8 4GB chip selects cannot be interleaved\r\n");
+ return 0;
+ }
+ /* Find the bits of csbase that we need to interleave on */
+ if (is_dual_channel(ctrl)) {
+ csbase_inc = csbase_low[log2(common_size) - 1] << 1;
+ } else {
+ csbase_inc = csbase_low[log2(common_size)];
+ }
+ /* Compute the initial values for csbase and csbask.
+ * In csbase just set the enable bit and the base to zero.
+ * In csmask set the mask bits for the size and page level interleave.
+ */
+ csbase = 0 | 1;
+ csmask = (((common_size << bits) - 1) << 21);
+ csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc);
+ for(index = 0; index < 8; index++) {
+ uint32_t value;
+
+ value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2));
+ /* Is it enabled? */
+ if (!(value & 1)) {
+ continue;
+ }
+ pci_write_config32(ctrl->f2, DRAM_CSBASE + (index << 2), csbase);
+ pci_write_config32(ctrl->f2, DRAM_CSMASK + (index << 2), csmask);
+ csbase += csbase_inc;
+ }
+
+#if 1
+ print_debug("Interleaved\r\n");
+#endif
+ /* Return the memory size in K */
+ return common_size << (15 + bits);
+}
- /* Compute the memory base address address */
- base_k = 0;
+static unsigned long order_chip_selects(const struct mem_controller *ctrl)
+{
+ unsigned long tom;
+
/* Remember which registers we have used in the high 8 bits of tom */
- tom = base_k >> 15;
+ tom = 0;
for(;;) {
/* Find the largest remaining canidate */
unsigned index, canidate;
@@ -1270,8 +1348,19 @@ static void order_dimms(const struct mem_controller *ctrl)
pci_write_config32(ctrl->f2, DRAM_CSMASK + (canidate << 2), csmask);
}
- tom_k = (tom & ~0xff000000) << 15;
+ /* Return the memory size in K */
+ return (tom & ~0xff000000) << 15;
+}
+
+static void order_dimms(const struct mem_controller *ctrl)
+{
+ unsigned long tom, tom_k, base_k;
+ unsigned node_id;
+ tom_k = interleave_chip_selects(ctrl);
+ if (!tom_k) {
+ tom_k = order_chip_selects(ctrl);
+ }
/* Compute the memory base address */
base_k = 0;
for(node_id = 0; node_id < ctrl->node_id; node_id++) {
@@ -1287,18 +1376,13 @@ static void order_dimms(const struct mem_controller *ctrl)
}
tom_k += base_k;
#if 0
- print_debug("tom: ");
- print_debug_hex32(tom);
- print_debug(" base_k: ");
+ print_debug("base_k: ");
print_debug_hex32(base_k);
print_debug(" tom_k: ");
print_debug_hex32(tom_k);
print_debug("\r\n");
#endif
route_dram_accesses(ctrl, base_k, tom_k);
-//BY LYH
- fill_last(ctrl->node_id, tom_k<<2);
-//BY LYH END
set_top_mem(tom_k);
}
@@ -2063,6 +2147,10 @@ static void set_read_preamble(const struct mem_controller *ctrl, const struct me
/* 166Mhz, 7.5ns */
rdpreamble = ((7 << 1)+1);
}
+ else if (divisor == ((5 << 1)+0)) {
+ /* 200Mhz, 7ns */
+ rdpreamble = ((7 << 1)+0);
+ }
}
else {
int slots;
@@ -2175,6 +2263,8 @@ static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct
{
int dimms;
int i;
+ int rc;
+
init_Tref(ctrl, param);
for(i = 0; (i < 4) && ctrl->channel0[i]; i++) {
int rc;
@@ -2247,13 +2337,16 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
print_debug_hex32(dcl);
print_debug("\r\n");
#endif
-#warning "FIXME set the ECC type to perform"
-#warning "FIXME initialize the scrub registers"
-#if 1
if (dcl & DCL_DimmEccEn) {
+ uint32_t mnc;
print_debug("ECC enabled\r\n");
+ mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG);
+ mnc |= MNC_ECC_EN;
+ if (dcl & DCL_128BitEn) {
+ mnc |= MNC_CHIPKILL_EN;
+ }
+ pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc);
}
-#endif
dcl |= DCL_DisDqsHys;
pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
dcl &= ~DCL_DisDqsHys;
@@ -2280,29 +2373,148 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
} else {
print_debug(" done\r\n");
}
-#if 0
if (dcl & DCL_DimmEccEn) {
print_debug("Clearing memory: ");
- loops = 0;
- dcl &= ~DCL_MemClrStatus;
- pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+ if (!is_cpu_pre_c0()) {
+ /* Wait until the automatic ram scrubber is finished */
+ dcl &= ~(DCL_MemClrStatus | DCL_DramEnable);
+ pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+ do {
+ dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
+ } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) );
+ }
+ uint32_t base, last_scrub_k, scrub_k;
+ uint32_t cnt,zstart,zend;
+ msr_t msr,msr_201;
+
+ /* First make certain the scrubber is disabled */
+ pci_write_config32(ctrl[i].f3, SCRUB_CONTROL,
+ (SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0));
+
+ /* load the start and end for the memory block to clear */
+ msr_201 = rdmsr(0x201);
+ zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8));
+ zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8));
+ zstart >>= 16;
+ zend >>=16;
+#if 1
+ print_debug("addr ");
+ print_debug_hex32(zstart);
+ print_debug("-");
+ print_debug_hex32(zend);
+ print_debug("\r\n");
+#endif
- do {
- dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
- loops += 1;
- if ((loops & 1023) == 0) {
- print_debug(" ");
- print_debug_hex32(loops);
- }
- } while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS));
- if (loops >= TIMEOUT_LOOPS) {
- print_debug("failed\r\n");
- } else {
- print_debug("done\r\n");
+ /* Disable fixed mtrrs */
+ msr = rdmsr(MTRRdefType_MSR);
+ msr.lo &= ~(1<<10);
+ wrmsr(MTRRdefType_MSR, msr);
+
+ /* turn on the wrap 32 disable */
+ msr = rdmsr(0xc0010015);
+ msr.lo |= (1<<17);
+ wrmsr(0xc0010015,msr);
+
+ for(;zstart<zend;zstart+=4) {
+
+ /* test for the last 64 meg of 4 gig space */
+ if(zstart == 0x0fc)
+ continue;
+
+ /* disable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* Set the variable mtrrs to write combine */
+ msr.lo = 1 + ((zstart&0x0ff)<<24);
+ msr.hi = (zstart&0x0ff00)>>8;
+ wrmsr(0x200,msr);
+
+ /* Set the limit to 64 meg of ram */
+ msr.hi = 0x000000ff;
+ msr.lo = 0xfc000800;
+ wrmsr(0x201,msr);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+ /* Set fs base address */
+ msr.lo = (zstart&0xff) << 24;
+ msr.hi = (zstart&0xff00) >> 8;
+ wrmsr(0xc0000100,msr);
+
+ print_debug_char((zstart > 0x0ff)?'+':'-');
+
+ /* clear memory 64meg */
+ __asm__ volatile(
+ "1: \n\t"
+ "movl %0, %%fs:(%1)\n\t"
+ "addl $4,%1\n\t"
+ "subl $1,%2\n\t"
+ "jnz 1b\n\t"
+ :
+ : "a" (0), "D" (0), "c" (0x01000000)
+ );
}
- pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, 0);
- pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, 0);
+
+ /* disable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* restore msr registers */
+ msr = rdmsr(MTRRdefType_MSR);
+ msr.lo |= 0x0400;
+ wrmsr(MTRRdefType_MSR, msr);
+
+ /* Restore the variable mtrrs */
+ msr.lo = 6;
+ msr.hi = 0;
+ wrmsr(0x200,msr);
+ wrmsr(0x201,msr_201);
+
+ /* Set fs base to 0 */
+ msr.lo = 0;
+ msr.hi = 0;
+ wrmsr(0xc0000100,msr);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* turn off the wrap 32 disable */
+ msr = rdmsr(0xc0010015);
+ msr.lo &= ~(1<<17);
+ wrmsr(0xc0010015,msr);
+
+ /* Find the Srub base address for this cpu */
+ base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3));
+ base &= 0xffff0000;
+
+ /* Set the scrub base address registers */
+ pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, base << 8);
+ pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, base >> 24);
+
+ /* Enable scrubbing at the lowest possible rate */
+ pci_write_config32(ctrl[i].f3, SCRUB_CONTROL,
+ (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0));
+
+ print_debug("done\r\n");
}
-#endif
}
}