summaryrefslogtreecommitdiff
path: root/src/northbridge
diff options
context:
space:
mode:
authorCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>2009-01-16 03:44:41 +0000
committerCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>2009-01-16 03:44:41 +0000
commit734d09e05b54d75a190685345fa81a2de0560d78 (patch)
tree129142ae2c7e7020adfa66edcbbdad02de4ae11a /src/northbridge
parent1d72e10bb4475f30423f7937fcdfc7940ba3fb5c (diff)
First part of heterogenous dualchannel support.
Do not allow non-identical DIMMs yet, but prepare the code. Calculate tCL related settings per DIMM in a dual channel setup. The check for compatibility will come in a later patch, but since DIMMs still have to be identical, this does not hurt. Factor out tRC calculation to prepare for per-DIMM calculation. Add diagnostic messages to tRC code. Test booted to FILO, behaviour is identical if you ignore the added debug messages (which are switched off by default). Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> Acked-by: Peter Stuge <peter@stuge.se> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3867 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge')
-rw-r--r--src/northbridge/amd/amdk8/raminit_f.c82
1 files changed, 55 insertions, 27 deletions
diff --git a/src/northbridge/amd/amdk8/raminit_f.c b/src/northbridge/amd/amdk8/raminit_f.c
index 8bfb08fa25..419b3b437f 100644
--- a/src/northbridge/amd/amdk8/raminit_f.c
+++ b/src/northbridge/amd/amdk8/raminit_f.c
@@ -1823,26 +1823,36 @@ static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *
* by both the memory controller and the dimms.
*/
for (i = 0; i < DIMM_SOCKETS; i++) {
- u32 spd_device = ctrl->channel0[i];
+ u32 spd_device;
printk_raminit("1.1 dimm_mask: %08x\n", meminfo->dimm_mask);
- if (!(meminfo->dimm_mask & (1 << i))) {
- if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */
- spd_device = ctrl->channel1[i];
- } else {
+ printk_raminit("i: %08x\n",i);
+
+ if (meminfo->dimm_mask & (1 << i)) {
+ spd_device = ctrl->channel0[i];
+ printk_raminit("Channel 0 settings:\n");
+
+ switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) {
+ case -1:
+ goto hw_error;
+ break;
+ case 1:
continue;
}
}
+ if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) {
+ spd_device = ctrl->channel1[i];
+ printk_raminit("Channel 1 settings:\n");
- printk_raminit("i: %08x\n",i);
-
- switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) {
- case -1:
- goto hw_error;
- break;
- case 1:
- continue;
- }
+ switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) {
+ case -1:
+ goto hw_error;
+ break;
+ case 1:
+ continue;
+ }
+ }
+
}
/* Make a second pass through the dimms and disable
* any that cannot support the selected memclk and cas latency.
@@ -1941,37 +1951,55 @@ static unsigned convert_to_1_4(unsigned value)
valuex = fraction [value & 0x7];
return valuex;
}
-static int update_dimm_Trc(const struct mem_controller *ctrl,
- const struct mem_param *param,
- int i, long dimm_mask)
+
+int get_dimm_Trc_clocks(u32 spd_device, const struct mem_param *param)
{
- unsigned clocks, old_clocks;
- uint32_t dtl;
int value;
int value2;
- u32 spd_device = ctrl->channel0[i];
-
- if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */
- spd_device = ctrl->channel1[i];
- }
-
+ int clocks;
value = spd_read_byte(spd_device, SPD_TRC);
- if (value < 0) return -1;
+ if (value < 0)
+ return -1;
+ printk_raminit("update_dimm_Trc: tRC (41) = %08x\n", value);
value2 = spd_read_byte(spd_device, SPD_TRC -1);
value <<= 2;
value += convert_to_1_4(value2>>4);
- value *=10;
+ value *= 10;
+ printk_raminit("update_dimm_Trc: tRC final value = %i\n", value);
clocks = (value + param->divisor - 1)/param->divisor;
+ printk_raminit("update_dimm_Trc: clocks = %i\n", clocks);
if (clocks < DTL_TRC_MIN) {
+#warning We should die here or at least disable this bank.
+ printk_notice("update_dimm_Trc: can't refresh fast enough, "
+ "want %i clocks, can %i clocks\n", clocks, DTL_TRC_MIN);
clocks = DTL_TRC_MIN;
}
+ return clocks;
+}
+
+static int update_dimm_Trc(const struct mem_controller *ctrl,
+ const struct mem_param *param,
+ int i, long dimm_mask)
+{
+ int clocks, old_clocks;
+ uint32_t dtl;
+ u32 spd_device = ctrl->channel0[i];
+
+ if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */
+ spd_device = ctrl->channel1[i];
+ }
+
+ clocks = get_dimm_Trc_clocks(spd_device, param);
+ if (clocks == -1)
+ return clocks;
if (clocks > DTL_TRC_MAX) {
return 0;
}
+ printk_raminit("update_dimm_Trc: clocks after adjustment = %i\n", clocks);
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRC_SHIFT) & DTL_TRC_MASK) + DTL_TRC_BASE;