Following patch adds resume (exit from self refresh) support for AMD K8 revF
[coreboot.git] / src / northbridge / amd / amdk8 / raminit_f.c
index 196209525b783e07668aa300709e9fb442cce5df..097e3b53a53c24369c165439c66379460587861d 100644 (file)
@@ -28,7 +28,7 @@
 #include <stdlib.h>
 #include "raminit.h"
 #include "amdk8_f.h"
-#include "spd_ddr2.h"
+#include <spd_ddr2.h>
 
 #ifndef QRANK_DIMM_SUPPORT
 #define QRANK_DIMM_SUPPORT 0
@@ -1655,7 +1655,7 @@ static uint8_t get_exact_divisor(int i, uint8_t divisor)
 
        /* Check for FID control support */
        struct cpuid_result cpuid1;
-       cpuid1 = cpuid(0x8000007);
+       cpuid1 = cpuid(0x80000007);
        if( cpuid1.edx & 0x02 ) {
                /* Use current FID */
                unsigned fid_cur;
@@ -1702,6 +1702,96 @@ static unsigned convert_to_linear(unsigned value)
        return value;
 }
 
+static const uint8_t latency_indicies[] = { 25, 23, 9 };
+
+int find_optimum_spd_latency(u32 spd_device, unsigned *min_latency, unsigned *min_cycle_time)
+{
+       int new_cycle_time, new_latency;
+       int index;
+       int latencies;
+       int latency;
+
+       /* First find the supported CAS latencies
+        * Byte 18 for DDR SDRAM is interpreted:
+        * bit 3 == CAS Latency = 3
+        * bit 4 == CAS Latency = 4
+        * bit 5 == CAS Latency = 5
+        * bit 6 == CAS Latency = 6
+        */
+       new_cycle_time = 0x500;
+       new_latency = 6;
+
+       latencies = spd_read_byte(spd_device, SPD_CAS_LAT);
+       if (latencies <= 0)
+               return 1;
+
+       printk_raminit("\tlatencies: %08x\n", latencies);
+       /* Compute the lowest cas latency which can be expressed in this
+        * particular SPD EEPROM. You can store at most settings for 3
+        * contiguous CAS latencies, so by taking the highest CAS
+        * latency maked as supported in the SPD and subtracting 2 you
+        * get the lowest expressable CAS latency. That latency is not
+        * necessarily supported, but a (maybe invalid) entry exists
+        * for it.
+        */
+       latency = log2(latencies) - 2;
+
+       /* Loop through and find a fast clock with a low latency */
+       for (index = 0; index < 3; index++, latency++) {
+               int value;
+               if ((latency < 3) || (latency > 6) ||
+                       (!(latencies & (1 << latency)))) {
+                       continue;
+               }
+               value = spd_read_byte(spd_device, latency_indicies[index]);
+               if (value < 0) {
+                       return -1;
+               }
+
+               printk_raminit("\tindex: %08x\n", index);
+               printk_raminit("\t\tlatency: %08x\n", latency);
+               printk_raminit("\t\tvalue1: %08x\n", value);
+
+               value = convert_to_linear(value);
+
+               printk_raminit("\t\tvalue2: %08x\n", value);
+
+               /* Only increase the latency if we decrease the clock */
+               if (value >= *min_cycle_time ) {
+                       if (value < new_cycle_time) {
+                               new_cycle_time = value;
+                               new_latency = latency;
+                       } else if (value == new_cycle_time) {
+                               if (new_latency > latency) {
+                                       new_latency = latency;
+                               }
+                       }
+               }
+               printk_raminit("\t\tnew_cycle_time: %08x\n", new_cycle_time);
+               printk_raminit("\t\tnew_latency: %08x\n", new_latency);
+
+       }
+
+       if (new_latency > 6){
+               return 1;
+       }
+
+       /* Does min_latency need to be increased? */
+       if (new_cycle_time > *min_cycle_time) {
+               *min_cycle_time = new_cycle_time;
+       }
+
+       /* Does min_cycle_time need to be increased? */
+       if (new_latency > *min_latency) {
+               *min_latency = new_latency;
+       }
+
+       printk_raminit("2 min_cycle_time: %08x\n", *min_cycle_time);
+       printk_raminit("2 min_latency: %08x\n", *min_latency);
+
+       return 0;
+}
+
 static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, struct mem_info *meminfo)
 {
        /* Compute the minimum cycle time for these dimms */
@@ -1710,8 +1800,6 @@ static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *
        int i;
        uint32_t value;
 
-       static const uint8_t latency_indicies[] = { 25, 23, 9 };
-
        static const uint16_t min_cycle_times[] = { // use full speed to compare
                [NBCAP_MEMCLK_NOLIMIT] = 0x250, /*2.5ns */
                [NBCAP_MEMCLK_333MHZ] = 0x300, /* 3.0ns */
@@ -1735,98 +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++) {
-               int new_cycle_time, new_latency;
-               int index;
-               int latencies;
-               int latency;
-               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 {
-                               continue;
-                       }
-               }
-
-               /* First find the supported CAS latencies
-                * Byte 18 for DDR SDRAM is interpreted:
-                * bit 3 == CAS Latency = 3
-                * bit 4 == CAS Latency = 4
-                * bit 5 == CAS Latency = 5
-                * bit 6 == CAS Latency = 6
-                */
-               new_cycle_time = 0x500;
-               new_latency = 6;
-
-               latencies = spd_read_byte(spd_device, SPD_CAS_LAT);
-               if (latencies <= 0) continue;
-
                printk_raminit("i: %08x\n",i);
-               printk_raminit("\tlatencies: %08x\n", latencies);
-               /* Compute the lowest cas latency which can be expressed in this
-                * particular SPD EEPROM. You can store at most settings for 3
-                * contiguous CAS latencies, so by taking the highest CAS
-                * latency maked as supported in the SPD and subtracting 2 you
-                * get the lowest expressable CAS latency. That latency is not
-                * necessarily supported, but a (maybe invalid) entry exists
-                * for it.
-                */
-               latency = log2(latencies) - 2;
 
-               /* Loop through and find a fast clock with a low latency */
-               for (index = 0; index < 3; index++, latency++) {
-                       int value;
-                       if ((latency < 3) || (latency > 6) ||
-                               (!(latencies & (1 << latency)))) {
-                               continue;
-                       }
-                       value = spd_read_byte(spd_device, latency_indicies[index]);
-                       if (value < 0) {
-                               goto hw_error;
-                       }
-
-                       printk_raminit("\tindex: %08x\n", index);
-                       printk_raminit("\t\tlatency: %08x\n", latency);
-                       printk_raminit("\t\tvalue1: %08x\n", value);
-
-                       value = convert_to_linear(value);
+               if (meminfo->dimm_mask & (1 << i)) {
+                       spd_device = ctrl->channel0[i];
+                       printk_raminit("Channel 0 settings:\n");
 
-                       printk_raminit("\t\tvalue2: %08x\n", value);
-
-                       /* Only increase the latency if we decrease the clock */
-                       if (value >= min_cycle_time ) {
-                               if (value < new_cycle_time) {
-                                       new_cycle_time = value;
-                                       new_latency = latency;
-                               } else if (value == new_cycle_time) {
-                                       if (new_latency > latency) {
-                                               new_latency = latency;
-                                       }
-                               }
+                       switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) {
+                       case -1:
+                               goto hw_error;
+                               break;
+                       case 1:
+                               continue;
                        }
-                       printk_raminit("\t\tnew_cycle_time: %08x\n", new_cycle_time);
-                       printk_raminit("\t\tnew_latency: %08x\n", new_latency);
-
                }
+               if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) {
+                       spd_device = ctrl->channel1[i];
+                       printk_raminit("Channel 1 settings:\n");
 
-               if (new_latency > 6){
-                       continue;
-               }
-
-               /* Does min_latency need to be increased? */
-               if (new_cycle_time > min_cycle_time) {
-                       min_cycle_time = new_cycle_time;
-               }
-
-               /* Does min_cycle_time need to be increased? */
-               if (new_latency > min_latency) {
-                       min_latency = new_latency;
+                       switch (find_optimum_spd_latency(spd_device, &min_latency, &min_cycle_time)) {
+                       case -1:
+                               goto hw_error;
+                               break;
+                       case 1:
+                               continue;
+                       }
                }
-
-               printk_raminit("2 min_cycle_time: %08x\n", min_cycle_time);
-               printk_raminit("2 min_latency: %08x\n", min_latency);
+               
        }
        /* Make a second pass through the dimms and disable
         * any that cannot support the selected memclk and cas latency.
@@ -1925,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;
@@ -2027,7 +2071,8 @@ static int update_dimm_TT_1_4(const struct mem_controller *ctrl, const struct me
        }
        
        if (clocks > TT_MAX) {
-               return 0;
+               printk_info("warning spd byte : %x = %x > TT_MAX: %x, setting TT_MAX", SPD_TT, value, TT_MAX);
+               clocks = TT_MAX;
        }
 
        dtl = pci_read_config32(ctrl->f2, TT_REG);
@@ -2964,12 +3009,18 @@ static void set_hw_mem_hole(int controllers, const struct mem_controller *ctrl)
 }
 #endif
 
+#include "exit_from_self.c"
 
 static void sdram_enable(int controllers, const struct mem_controller *ctrl,
                          struct sys_info *sysinfo)
 {
        int i;
-
+#ifdef ACPI_IS_WAKEUP_EARLY
+       int suspend = acpi_is_wakeup_early();
+#else
+       int suspend = 0;
+#endif
 #if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1
         unsigned cpu_f0_f1[8];
        /* FIXME: How about 32 node machine later? */
@@ -3015,6 +3066,14 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl,
        printk_debug("\n");
 #endif
 
+       /* lets override the rest of the routine */
+       if (suspend) {
+               printk_debug("Wakeup!\n");
+               exit_from_self(controllers, ctrl, sysinfo);
+               printk_debug("Mem running !\n");
+               return;
+       }
+
        for (i = 0; i < controllers; i++) {
                uint32_t dcl, dch;
                if (!sysinfo->ctrl_present[ i ])