First part of heterogenous dualchannel support.
authorCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Fri, 16 Jan 2009 03:44:41 +0000 (03:44 +0000)
committerCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Fri, 16 Jan 2009 03:44:41 +0000 (03:44 +0000)
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

src/northbridge/amd/amdk8/raminit_f.c

index 8bfb08fa2559cbf0c1f0b501df6e55ca62d66ab6..419b3b437f29af4693a2799dc8b95881c2465475 100644 (file)
@@ -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;