diff options
author | Eric Biederman <ebiederm@xmission.com> | 2003-07-21 20:13:45 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2003-07-21 20:13:45 +0000 |
commit | 2c018fba95a5f40c4eaaa20421e8c893dffdb62e (patch) | |
tree | 3b6ecc6eb72d145dd70bb549fe0130370d7e40fb /src/northbridge/amd/amdk8/raminit.c | |
parent | 6d4512cdf976fc071720dbec686cf8a1a40f1db0 (diff) |
- First pass at s2880 support.
- SMP cleanups (remove SMP only use CONFIG_SMP)
- Minor tweaks to romcc to keep it from taking forever compiling
- failover fixes
- Get a good implementation of k8_cpufixup and sizeram for the opteron
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@998 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/amd/amdk8/raminit.c')
-rw-r--r-- | src/northbridge/amd/amdk8/raminit.c | 294 |
1 files changed, 168 insertions, 126 deletions
diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c index 41a93b51e9..1b258c62ce 100644 --- a/src/northbridge/amd/amdk8/raminit.c +++ b/src/northbridge/amd/amdk8/raminit.c @@ -922,10 +922,9 @@ static void sdram_set_registers(const struct mem_controller *ctrl) }; int i; int max; -#if 1 - memreset_setup(ctrl); -#endif - print_debug("setting up CPU0 northbridge registers\r\n"); + print_debug("setting up CPU"); + print_debug_hex8(ctrl->node_id); + print_debug(" northbridge registers\r\n"); max = sizeof(register_values)/sizeof(register_values[0]); for(i = 0; i < max; i += 3) { device_t dev; @@ -1001,43 +1000,43 @@ static struct dimm_size spd_get_dimm_size(unsigned device) * a multiple of 4MB. The way we do it now we can size both * sides of an assymetric dimm. */ - value = smbus_read_byte(device, 3); /* rows */ + value = spd_read_byte(device, 3); /* rows */ if (value < 0) goto out; sz.side1 += value & 0xf; - value = smbus_read_byte(device, 4); /* columns */ + value = spd_read_byte(device, 4); /* columns */ if (value < 0) goto out; sz.side1 += value & 0xf; - value = smbus_read_byte(device, 17); /* banks */ + value = spd_read_byte(device, 17); /* banks */ if (value < 0) goto out; sz.side1 += log2(value & 0xff); /* Get the module data width and convert it to a power of two */ - value = smbus_read_byte(device, 7); /* (high byte) */ + value = spd_read_byte(device, 7); /* (high byte) */ if (value < 0) goto out; value &= 0xff; value <<= 8; - low = smbus_read_byte(device, 6); /* (low byte) */ + low = spd_read_byte(device, 6); /* (low byte) */ if (low < 0) goto out; value = value | (low & 0xff); sz.side1 += log2(value); /* side 2 */ - value = smbus_read_byte(device, 5); /* number of physical banks */ + value = spd_read_byte(device, 5); /* number of physical banks */ if (value <= 1) goto out; /* Start with the symmetrical case */ sz.side2 = sz.side1; - value = smbus_read_byte(device, 3); /* rows */ + value = spd_read_byte(device, 3); /* rows */ if (value < 0) goto out; if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */ sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */ sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */ - value = smbus_read_byte(device, 4); /* columns */ + value = spd_read_byte(device, 4); /* columns */ if (value < 0) goto out; sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */ sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */ @@ -1121,24 +1120,29 @@ static void spd_set_ram_size(const struct mem_controller *ctrl) static void route_dram_accesses(const struct mem_controller *ctrl, unsigned long base_k, unsigned long limit_k) { -#warning "FIXME this is hardcoded for one cpu" + /* Route the addresses to the controller node */ unsigned node_id; unsigned limit; unsigned base; - node_id = 0; - /* Route the addresses to node 0 */ + unsigned index; + unsigned limit_reg, base_reg; + device_t device; + node_id = ctrl->node_id; + index = (node_id << 3); limit = (limit_k << 2); limit &= 0xffff0000; limit -= 0x00010000; + limit |= ( 0 << 8) | (node_id << 0); base = (base_k << 2); base &= 0xffff0000; - pci_write_config32(ctrl->f1, 0x44, limit | (0 << 8) | (node_id << 0)); - pci_write_config32(ctrl->f1, 0x40, base | (0 << 8) | (1<<1) | (1<<0)); + base |= (0 << 8) | (1<<1) | (1<<0); -#if 1 - pci_write_config32(PCI_DEV(0, 0x19, 1), 0x44, limit | (0 << 8) | (1 << 4) | (node_id << 0)); - pci_write_config32(PCI_DEV(0, 0x19, 1), 0x40, base | (0 << 8) | (1<<1) | (1<<0)); -#endif + limit_reg = 0x44 + index; + base_reg = 0x40 + index; + for(device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); device += PCI_DEV(0, 1, 0)) { + pci_write_config32(device, limit_reg, limit); + pci_write_config32(device, base_reg, base); + } } static void set_top_mem(unsigned tom_k) @@ -1148,6 +1152,13 @@ static void set_top_mem(unsigned tom_k) die("No memory"); } +#if 1 + /* Report the amount of memory. */ + print_debug("RAM: 0x"); + print_debug_hex32(tom_k); + print_debug(" KB\r\n"); +#endif + /* Now set top of memory */ msr_t msr; msr.lo = (tom_k & 0x003fffff) << 10; @@ -1163,21 +1174,28 @@ static void set_top_mem(unsigned tom_k) msr.lo = (tom_k & 0x003fffff) << 10; msr.hi = (tom_k & 0xffc00000) >> 22; wrmsr(TOP_MEM, msr); - -#if 1 - /* And report the amount of memory. */ - print_debug("RAM: 0x"); - print_debug_hex32(tom_k); - print_debug(" KB\r\n"); -#endif } static void order_dimms(const struct mem_controller *ctrl) { - unsigned long tom, tom_k; + unsigned long tom, tom_k, base_k; + unsigned node_id; + /* Compute the memory base address address */ + base_k = 0; + for(node_id = 0; node_id < ctrl->node_id; node_id++) { + uint32_t limit, base; + unsigned index; + index = node_id << 3; + base = pci_read_config32(ctrl->f1, 0x40 + index); + /* Only look at the limit if the base is enabled */ + if ((base & 3) == 3) { + limit = pci_read_config32(ctrl->f1, 0x44 + index); + base_k = ((limit + 0x00010000) & 0xffff0000) >> 2; + } + } /* Remember which registers we have used in the high 8 bits of tom */ - tom = 0; + tom = base_k >> 15; for(;;) { /* Find the largest remaining canidate */ unsigned index, canidate; @@ -1212,12 +1230,24 @@ static void order_dimms(const struct mem_controller *ctrl) break; } - /* Remember I have used this register */ - tom |= (1 << (canidate + 24)); - /* Remember the dimm size */ size = csbase >> 21; + /* If this is the first chip select, round base_k to + * be a multiple of it's size. Then set tom to equal + * base_k. + * I assume that size is a power of two. + */ + if ((tom & 0xff000000) == 0) { + unsigned size_k; + size_k = size << 15; + base_k = (base_k + size_k -1) & ~(size_k -1); + tom = base_k >> 15; + } + + /* Remember I have used this register */ + tom |= (1 << (canidate + 24)); + /* Recompute the cs base register value */ csbase = (tom << 21) | 1; @@ -1239,11 +1269,13 @@ static void order_dimms(const struct mem_controller *ctrl) #if 0 print_debug("tom: "); print_debug_hex32(tom); + 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, 0, tom_k); + route_dram_accesses(ctrl, base_k, tom_k); set_top_mem(tom_k); } @@ -1267,7 +1299,7 @@ static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl) registered = 0; for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) { int value; - value = smbus_read_byte(ctrl->channel0[i], 21); + value = spd_read_byte(ctrl->channel0[i], 21); if (value < 0) { disable_dimm(ctrl, i); continue; @@ -1307,31 +1339,30 @@ static void spd_enable_2channels(const struct mem_controller *ctrl) { int i; uint32_t nbcap; - /* SMBUS addresses to verify are identical */ + /* SPD addresses to verify are identical */ #warning "FINISHME review and see if these are the bytes I need" /* FINISHME review and see if these are the bytes I need */ static const unsigned addresses[] = { 2, /* Type should be DDR SDRAM */ - 3, /* Row addresses */ - 4, /* Column addresses */ - 5, /* Physical Banks */ - 6, /* Module Data Width low */ - 7, /* Module Data Width high */ - 9, /* Cycle time at highest CAS Latency CL=X */ - 11, /* SDRAM Type */ - 12, /* Refresh Interval */ - 13, /* SDRAM Width */ - 15, /* Back-to-Back Random Column Access */ - 16, /* Burst Lengths */ - 17, /* Logical Banks */ - 18, /* Supported CAS Latencies */ - 23, /* Cycle time at CAS Latnecy (CLX - 0.5) */ - 26, /* Cycle time at CAS Latnecy (CLX - 1.0) */ - 27, /* tRP Row precharge time */ - 29, /* tRCD RAS to CAS */ - 30, /* tRAS Activate to Precharge */ - 31, /* Module Bank Density */ - 33, /* Address and Command Hold Time After Clock */ + 3, /* *Row addresses */ + 4, /* *Column addresses */ + 5, /* *Physical Banks */ + 6, /* *Module Data Width low */ + 7, /* *Module Data Width high */ + 9, /* *Cycle time at highest CAS Latency CL=X */ + 11, /* *SDRAM Type */ + 13, /* *SDRAM Width */ + 17, /* *Logical Banks */ + 18, /* *Supported CAS Latencies */ + 21, /* *SDRAM Module Attributes */ + 23, /* *Cycle time at CAS Latnecy (CLX - 0.5) */ + 26, /* *Cycle time at CAS Latnecy (CLX - 1.0) */ + 27, /* *tRP Row precharge time */ + 28, /* *Minimum Row Active to Row Active Delay (tRRD) */ + 29, /* *tRCD RAS to CAS */ + 30, /* *tRAS Activate to Precharge */ + 41, /* *Minimum Active to Active/Auto Refresh Time(Trc) */ + 42, /* *Minimum Auto Refresh Command Time(Trfc) */ }; nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP); if (!(nbcap & NBCAP_128Bit)) { @@ -1348,11 +1379,11 @@ static void spd_enable_2channels(const struct mem_controller *ctrl) for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) { unsigned addr; addr = addresses[j]; - value0 = smbus_read_byte(device0, addr); + value0 = spd_read_byte(device0, addr); if (value0 < 0) { break; } - value1 = smbus_read_byte(device1, addr); + value1 = spd_read_byte(device1, addr); if (value1 < 0) { return; } @@ -1498,7 +1529,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) new_cycle_time = 0xa0; new_latency = 5; - latencies = smbus_read_byte(ctrl->channel0[i], 18); + latencies = spd_read_byte(ctrl->channel0[i], 18); if (latencies <= 0) continue; /* Compute the lowest cas latency supported */ @@ -1511,7 +1542,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) (!(latencies & (1 << latency)))) { continue; } - value = smbus_read_byte(ctrl->channel0[i], latency_indicies[index]); + value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); if (value < 0) { continue; } @@ -1553,7 +1584,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) int index; int value; int dimm; - latencies = smbus_read_byte(ctrl->channel0[i], 18); + latencies = spd_read_byte(ctrl->channel0[i], 18); if (latencies <= 0) { goto dimm_err; } @@ -1575,7 +1606,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl) } /* Read the min_cycle_time for this latency */ - value = smbus_read_byte(ctrl->channel0[i], latency_indicies[index]); + value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]); /* All is good if the selected clock speed * is what I need or slower. @@ -1619,7 +1650,7 @@ static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_p unsigned clocks, old_clocks; uint32_t dtl; int value; - value = smbus_read_byte(ctrl->channel0[i], 41); + value = spd_read_byte(ctrl->channel0[i], 41); if (value < 0) return -1; if ((value == 0) || (value == 0xff)) { value = param->tRC; @@ -1648,7 +1679,7 @@ static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_ unsigned clocks, old_clocks; uint32_t dtl; int value; - value = smbus_read_byte(ctrl->channel0[i], 42); + value = spd_read_byte(ctrl->channel0[i], 42); if (value < 0) return -1; if ((value == 0) || (value == 0xff)) { value = param->tRFC; @@ -1677,7 +1708,7 @@ static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_ unsigned clocks, old_clocks; uint32_t dtl; int value; - value = smbus_read_byte(ctrl->channel0[i], 29); + value = spd_read_byte(ctrl->channel0[i], 29); if (value < 0) return -1; #if 0 clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1); @@ -1706,7 +1737,7 @@ static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_ unsigned clocks, old_clocks; uint32_t dtl; int value; - value = smbus_read_byte(ctrl->channel0[i], 28); + value = spd_read_byte(ctrl->channel0[i], 28); if (value < 0) return -1; clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1); if (clocks < DTL_TRRD_MIN) { @@ -1731,7 +1762,7 @@ static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_ unsigned clocks, old_clocks; uint32_t dtl; int value; - value = smbus_read_byte(ctrl->channel0[i], 30); + value = spd_read_byte(ctrl->channel0[i], 30); if (value < 0) return -1; clocks = ((value << 1) + param->divisor - 1)/param->divisor; if (clocks < DTL_TRAS_MIN) { @@ -1756,7 +1787,7 @@ static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_p unsigned clocks, old_clocks; uint32_t dtl; int value; - value = smbus_read_byte(ctrl->channel0[i], 27); + value = spd_read_byte(ctrl->channel0[i], 27); if (value < 0) return -1; #if 0 clocks = (value + (param->divisor << 1) - 1)/(param->divisor << 1); @@ -1813,7 +1844,7 @@ static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_ uint32_t dth; int value; unsigned tref, old_tref; - value = smbus_read_byte(ctrl->channel0[i], 3); + value = spd_read_byte(ctrl->channel0[i], 3); if (value < 0) return -1; value &= 0xf; @@ -1841,7 +1872,7 @@ static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_pa uint32_t dcl; int value; int dimm; - value = smbus_read_byte(ctrl->channel0[i], 13); + value = spd_read_byte(ctrl->channel0[i], 13); if (value < 0) { return -1; } @@ -1860,7 +1891,7 @@ static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_p { uint32_t dcl; int value; - value = smbus_read_byte(ctrl->channel0[i], 11); + value = spd_read_byte(ctrl->channel0[i], 11); if (value < 0) { return -1; } @@ -2169,78 +2200,89 @@ static void sdram_set_spd_registers(const struct mem_controller *ctrl) } #define TIMEOUT_LOOPS 300000 -static void sdram_enable(const struct mem_controller *ctrl) +static void sdram_enable(int controllers, const struct mem_controller *ctrl) { - uint32_t dcl, dch; + int i; /* Before enabling memory start the memory clocks */ - dch = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH); - dch |= DCH_MEMCLK_VALID; - pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch); + for(i = 0; i < controllers; i++) { + uint32_t dch; + dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH); + dch |= DCH_MEMCLK_VALID; + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch); + } /* And if necessary toggle the the reset on the dimms by hand */ - memreset(ctrl); - - /* Toggle DisDqsHys to get it working */ - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - print_debug("dcl: "); - print_debug_hex32(dcl); - print_debug("\r\n"); + memreset(controllers, ctrl); + for(i = 0; i < controllers; i++) { + uint32_t dcl; + /* Toggle DisDqsHys to get it working */ + dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); +#if 0 + print_debug("dcl: "); + print_debug_hex32(dcl); + print_debug("\r\n"); +#endif +#if 1 + dcl &= ~DCL_DimmEccEn; +#endif #warning "FIXME set the ECC type to perform" #warning "FIXME initialize the scrub registers" #if 0 - if (dcl & DCL_DimmEccEn) { - print_debug("ECC enabled\r\n"); - } -#endif - dcl |= DCL_DisDqsHys; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - dcl &= ~DCL_DisDqsHys; - dcl &= ~DCL_DLL_Disable; - dcl &= ~DCL_D_DRV; - dcl &= ~DCL_QFC_EN; - dcl |= DCL_DramInit; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - - print_debug("Initializing memory: "); - int loops = 0; - do { - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); - loops += 1; - if ((loops & 1023) == 0) { - print_debug("."); + if (dcl & DCL_DimmEccEn) { + print_debug("ECC enabled\r\n"); } - } while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS)); - if (loops >= TIMEOUT_LOOPS) { - print_debug(" failed\r\n"); - } else { - print_debug(" done\r\n"); - } - -#if 0 +#endif + dcl |= DCL_DisDqsHys; + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); + dcl &= ~DCL_DisDqsHys; + dcl &= ~DCL_DLL_Disable; + dcl &= ~DCL_D_DRV; + dcl &= ~DCL_QFC_EN; + dcl |= DCL_DramInit; + pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl); - if (dcl & DCL_DimmEccEn) { - print_debug("Clearing memory: "); - loops = 0; - dcl &= ~DCL_MemClrStatus; - pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl); - + } + for(i = 0; i < controllers; i++) { + uint32_t dcl; + print_debug("Initializing memory: "); + int loops = 0; do { - dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW); + dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW); loops += 1; if ((loops & 1023) == 0) { - print_debug(" "); - print_debug_hex32(loops); + print_debug("."); } - } while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS)); + } while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS)); if (loops >= TIMEOUT_LOOPS) { - print_debug("failed\r\n"); + print_debug(" failed\r\n"); } else { - print_debug("done\r\n"); + 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); + + 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"); + } + pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, 0); + pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, 0); } - pci_write_config32(ctrl->f3, SCRUB_ADDR_LOW, 0); - pci_write_config32(ctrl->f3, SCRUB_ADDR_HIGH, 0); - } #endif + } } |