nb/intel/ironlake: Split out some QuickPath init code

The platform performs a CPU-only reset after initializing QPI (QuickPath
Interconnect) and before actually performing raminit. The state is saved
in the sticky scratchpad register at MCHBAR + 0x2ca8.

Relocate some QuickPath init to a separate file. All moved functions are
only used within QPI init code, and had to be relocated in one commit.

Tested on out-of-tree HP 630, still boots.

Change-Id: I48e3517285d8fd4b448add131cd8bfb80641e7ef
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/49582
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/northbridge/intel/ironlake/Makefile.inc b/src/northbridge/intel/ironlake/Makefile.inc
index e3d41f1a..89c9e16 100644
--- a/src/northbridge/intel/ironlake/Makefile.inc
+++ b/src/northbridge/intel/ironlake/Makefile.inc
@@ -16,6 +16,7 @@
 romstage-y += raminit_tables.c
 romstage-y += early_init.c
 romstage-y += romstage.c
+romstage-y += quickpath.c
 
 smm-y += finalize.c
 
diff --git a/src/northbridge/intel/ironlake/quickpath.c b/src/northbridge/intel/ironlake/quickpath.c
new file mode 100644
index 0000000..90e62e2
--- /dev/null
+++ b/src/northbridge/intel/ironlake/quickpath.c
@@ -0,0 +1,660 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <delay.h>
+#include <device/pci_def.h>
+#include <device/pci_ops.h>
+#include <northbridge/intel/ironlake/raminit.h>
+#include <types.h>
+
+#define NORTHBRIDGE PCI_DEV(0, 0, 0)
+
+static unsigned int gcd(unsigned int a, unsigned int b)
+{
+	unsigned int t;
+	if (a > b) {
+		t = a;
+		a = b;
+		b = t;
+	}
+	/* invariant a < b.  */
+	while (a) {
+		t = b % a;
+		b = a;
+		a = t;
+	}
+	return b;
+}
+
+static inline int div_roundup(int a, int b)
+{
+	return DIV_ROUND_UP(a, b);
+}
+
+static unsigned int lcm(unsigned int a, unsigned int b)
+{
+	return (a * b) / gcd(a, b);
+}
+
+struct stru1 {
+	u8 freqs_reversed;
+	u8 freq_diff_reduced;
+	u8 freq_min_reduced;
+	u8 divisor_f4_to_fmax;
+	u8 divisor_f3_to_fmax;
+	u8 freq4_to_max_remainder;
+	u8 freq3_to_2_remainder;
+	u8 freq3_to_2_remaindera;
+	u8 freq4_to_2_remainder;
+	int divisor_f3_to_f1, divisor_f4_to_f2;
+	int common_time_unit_ps;
+	int freq_max_reduced;
+};
+
+static void
+compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
+			 int num_cycles_2, int num_cycles_1, int round_it,
+			 int add_freqs, struct stru1 *result)
+{
+	int g;
+	int common_time_unit_ps;
+	int freq1_reduced, freq2_reduced;
+	int freq_min_reduced;
+	int freq_max_reduced;
+	int freq3, freq4;
+
+	g = gcd(freq1, freq2);
+	freq1_reduced = freq1 / g;
+	freq2_reduced = freq2 / g;
+	freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
+	freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
+
+	common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
+	freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
+	freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
+	if (add_freqs) {
+		freq3 += freq2_reduced;
+		freq4 += freq1_reduced;
+	}
+
+	if (round_it) {
+		result->freq3_to_2_remainder = 0;
+		result->freq3_to_2_remaindera = 0;
+		result->freq4_to_max_remainder = 0;
+		result->divisor_f4_to_f2 = 0;
+		result->divisor_f3_to_f1 = 0;
+	} else {
+		if (freq2_reduced < freq1_reduced) {
+			result->freq3_to_2_remainder =
+			    result->freq3_to_2_remaindera =
+			    freq3 % freq1_reduced - freq1_reduced + 1;
+			result->freq4_to_max_remainder =
+			    -(freq4 % freq1_reduced);
+			result->divisor_f3_to_f1 = freq3 / freq1_reduced;
+			result->divisor_f4_to_f2 =
+			    (freq4 -
+			     (freq1_reduced - freq2_reduced)) / freq2_reduced;
+			result->freq4_to_2_remainder =
+			    -(char)((freq1_reduced - freq2_reduced) +
+				    ((u8) freq4 -
+				     (freq1_reduced -
+				      freq2_reduced)) % (u8) freq2_reduced);
+		} else {
+			if (freq2_reduced > freq1_reduced) {
+				result->freq4_to_max_remainder =
+				    (freq4 % freq2_reduced) - freq2_reduced + 1;
+				result->freq4_to_2_remainder =
+				    freq4 % freq_max_reduced -
+				    freq_max_reduced + 1;
+			} else {
+				result->freq4_to_max_remainder =
+				    -(freq4 % freq2_reduced);
+				result->freq4_to_2_remainder =
+				    -(char)(freq4 % freq_max_reduced);
+			}
+			result->divisor_f4_to_f2 = freq4 / freq2_reduced;
+			result->divisor_f3_to_f1 =
+			    (freq3 -
+			     (freq2_reduced - freq1_reduced)) / freq1_reduced;
+			result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
+			result->freq3_to_2_remaindera =
+			    -(char)((freq_max_reduced - freq_min_reduced) +
+				    (freq3 -
+				     (freq_max_reduced -
+				      freq_min_reduced)) % freq1_reduced);
+		}
+	}
+	result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
+	result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
+	if (round_it) {
+		if (freq2_reduced > freq1_reduced) {
+			if (freq3 % freq_max_reduced)
+				result->divisor_f3_to_fmax++;
+		}
+		if (freq2_reduced < freq1_reduced) {
+			if (freq4 % freq_max_reduced)
+				result->divisor_f4_to_fmax++;
+		}
+	}
+	result->freqs_reversed = (freq2_reduced < freq1_reduced);
+	result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
+	result->freq_min_reduced = freq_min_reduced;
+	result->common_time_unit_ps = common_time_unit_ps;
+	result->freq_max_reduced = freq_max_reduced;
+}
+
+static void set_274265(struct raminfo *info)
+{
+	int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
+	int delay_e_ps, delay_e_cycles, delay_f_cycles;
+	int delay_e_over_cycle_ps;
+	int cycletime_ps;
+	int channel;
+
+	delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
+	info->training.reg2ca9_bit0 = 0;
+	for (channel = 0; channel < NUM_CHANNELS; channel++) {
+		cycletime_ps =
+		    900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
+		delay_d_ps =
+		    (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
+		    - info->some_delay_3_ps_rounded + 200;
+		if (!
+		    ((info->silicon_revision == 0
+		      || info->silicon_revision == 1)
+		     && (info->revision >= 8)))
+			delay_d_ps += halfcycle_ps(info) * 2;
+		delay_d_ps +=
+		    halfcycle_ps(info) * (!info->revision_flag_1 +
+					  info->some_delay_2_halfcycles_ceil +
+					  2 * info->some_delay_1_cycle_floor +
+					  info->clock_speed_index +
+					  2 * info->cas_latency - 7 + 11);
+		delay_d_ps += info->revision >= 8 ? 2758 : 4428;
+
+		MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
+		MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
+		if ((MCHBAR8(0x144) & 0x1f) > 0x13)
+			delay_d_ps += 650;
+		delay_c_ps = delay_d_ps + 1800;
+		if (delay_c_ps <= delay_a_ps)
+			delay_e_ps = 0;
+		else
+			delay_e_ps =
+			    cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
+						       cycletime_ps);
+
+		delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
+		delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
+		delay_f_cycles =
+		    div_roundup(2500 - delay_e_over_cycle_ps,
+				2 * halfcycle_ps(info));
+		if (delay_f_cycles > delay_e_cycles) {
+			info->delay46_ps[channel] = delay_e_ps;
+			delay_e_cycles = 0;
+		} else {
+			info->delay46_ps[channel] =
+			    delay_e_over_cycle_ps +
+			    2 * halfcycle_ps(info) * delay_f_cycles;
+			delay_e_cycles -= delay_f_cycles;
+		}
+
+		if (info->delay46_ps[channel] < 2500) {
+			info->delay46_ps[channel] = 2500;
+			info->training.reg2ca9_bit0 = 1;
+		}
+		delay_b_ps = halfcycle_ps(info) + delay_c_ps;
+		if (delay_b_ps <= delay_a_ps)
+			delay_b_ps = 0;
+		else
+			delay_b_ps -= delay_a_ps;
+		info->delay54_ps[channel] =
+		    cycletime_ps * div_roundup(delay_b_ps,
+					       cycletime_ps) -
+		    2 * halfcycle_ps(info) * delay_e_cycles;
+		if (info->delay54_ps[channel] < 2500)
+			info->delay54_ps[channel] = 2500;
+		info->training.reg274265[channel][0] = delay_e_cycles;
+		if (delay_d_ps + 7 * halfcycle_ps(info) <=
+		    24 * halfcycle_ps(info))
+			info->training.reg274265[channel][1] = 0;
+		else
+			info->training.reg274265[channel][1] =
+				div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
+				4 * halfcycle_ps(info)) - 6;
+		MCHBAR32((channel << 10) + 0x274) =
+			info->training.reg274265[channel][1] |
+			(info->training.reg274265[channel][0] << 16);
+		info->training.reg274265[channel][2] =
+			div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
+			4 * halfcycle_ps(info)) + 1;
+		MCHBAR16((channel << 10) + 0x265) =
+			info->training.reg274265[channel][2] << 8;
+	}
+	if (info->training.reg2ca9_bit0)
+		MCHBAR8_OR(0x2ca9, 1);
+	else
+		MCHBAR8_AND(0x2ca9, ~1);
+}
+
+static void restore_274265(struct raminfo *info)
+{
+	int channel;
+
+	for (channel = 0; channel < NUM_CHANNELS; channel++) {
+		MCHBAR32((channel << 10) + 0x274) =
+			(info->cached_training->reg274265[channel][0] << 16) |
+			info->cached_training->reg274265[channel][1];
+		MCHBAR16((channel << 10) + 0x265) =
+			info->cached_training->reg274265[channel][2] << 8;
+	}
+	if (info->cached_training->reg2ca9_bit0)
+		MCHBAR8_OR(0x2ca9, 1);
+	else
+		MCHBAR8_AND(0x2ca9, ~1);
+}
+
+static void
+set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
+	     int num_cycles_2, int num_cycles_1, int num_cycles_3,
+	     int num_cycles_4, int reverse)
+{
+	struct stru1 vv;
+	char multiplier;
+
+	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
+				 0, 1, &vv);
+
+	multiplier =
+	    div_roundup(MAX
+			(div_roundup(num_cycles_2, vv.common_time_unit_ps) +
+			 div_roundup(num_cycles_3, vv.common_time_unit_ps),
+			 div_roundup(num_cycles_1,
+				     vv.common_time_unit_ps) +
+			 div_roundup(num_cycles_4, vv.common_time_unit_ps))
+			+ vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
+
+	u32 y =
+	    (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
+		  vv.freq_max_reduced * multiplier)
+	    | (vv.
+	       freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
+					     multiplier) << 16) | ((u8) (vv.
+									 freq_min_reduced
+									 *
+									 multiplier)
+								   << 24);
+	u32 x =
+	    vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
+									 divisor_f3_to_f1
+									 << 16)
+	    | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
+	if (reverse) {
+		MCHBAR32(reg) = y;
+		MCHBAR32(reg + 4) = x;
+	} else {
+		MCHBAR32(reg + 4) = y;
+		MCHBAR32(reg) = x;
+	}
+}
+
+static void
+set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
+	   int num_cycles_1, int num_cycles_2, int num_cycles_3,
+	   int num_cycles_4)
+{
+	struct stru1 ratios1;
+	struct stru1 ratios2;
+
+	compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
+				 0, 1, &ratios2);
+	compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
+				 0, 1, &ratios1);
+	printk(RAM_SPEW, "[%x] <= %x\n", reg,
+		       ratios1.freq4_to_max_remainder | (ratios2.
+							 freq4_to_max_remainder
+							 << 8)
+		       | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
+							       divisor_f4_to_fmax
+							       << 20));
+	MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
+		(ratios2.freq4_to_max_remainder << 8) |
+		(ratios1.divisor_f4_to_fmax << 16) |
+		(ratios2.divisor_f4_to_fmax << 20);
+}
+
+static void
+set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
+	     int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
+{
+	struct stru1 ratios;
+
+	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
+				 round_it, add_freqs, &ratios);
+	switch (mode) {
+	case 0:
+		MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
+			(ratios.freqs_reversed << 8);
+		MCHBAR32(reg) = ratios.freq3_to_2_remainder |
+			(ratios.freq4_to_max_remainder << 8) |
+			(ratios.divisor_f3_to_fmax << 16) |
+			(ratios.divisor_f4_to_fmax << 20) |
+			(ratios.freq_min_reduced << 24);
+		break;
+
+	case 1:
+		MCHBAR32(reg) = ratios.freq3_to_2_remainder |
+			(ratios.divisor_f3_to_fmax << 16);
+		break;
+
+	case 2:
+		MCHBAR32(reg) = ratios.freq3_to_2_remainder |
+			(ratios.freq4_to_max_remainder << 8) |
+			(ratios.divisor_f3_to_fmax << 16) |
+			(ratios.divisor_f4_to_fmax << 20);
+		break;
+
+	case 4:
+		MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
+			(ratios.divisor_f4_to_fmax << 8) |
+			(ratios.freqs_reversed << 12) |
+			(ratios.freq_min_reduced << 16) |
+			(ratios.freq_diff_reduced << 24);
+		break;
+	}
+}
+
+static void set_2dxx_series(struct raminfo *info, int s3resume)
+{
+	set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
+		     0, 1);
+	set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
+	set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
+		     1);
+	set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
+		     frequency_11(info), 1231, 1524, 0, 1);
+	set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
+		     frequency_11(info) / 2, 1278, 2008, 0, 1);
+	set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
+		     1167, 1539, 0, 1);
+	set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
+		     frequency_11(info) / 2, 1403, 1318, 0, 1);
+	set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
+		     1);
+	set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
+		     1);
+	set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
+		     1, 1);
+	set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
+		     1);
+	set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
+		     frequency_11(info) / 2, 4000, 0, 0, 0);
+	set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
+		     frequency_11(info) / 2, 4000, 4000, 0, 0);
+
+	if (s3resume) {
+		printk(RAM_SPEW, "[6dc] <= %x\n",
+			info->cached_training->reg_6dc);
+		MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
+	} else
+		set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
+			   info->delay46_ps[0], 0,
+			   info->delay54_ps[0]);
+	set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
+		     frequency_11(info), 2500, 0, 0, 0);
+	set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
+		     frequency_11(info) / 2, 3500, 0, 0, 0);
+	if (s3resume) {
+		printk(RAM_SPEW, "[6e8] <= %x\n",
+			info->cached_training->reg_6e8);
+		MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
+	} else
+		set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
+			   info->delay46_ps[1], 0,
+			   info->delay54_ps[1]);
+	set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
+	set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
+		     470, 0);
+	set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
+	set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
+		     454, 459, 0);
+	set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
+	set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
+		     2588, 0);
+	set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
+		     2405, 0);
+	set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
+	set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
+		     480, 0);
+	set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
+	MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
+	MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
+}
+
+void late_quickpath_init(struct raminfo *info, const int s3resume)
+{
+	const u16 deven = pci_read_config16(NORTHBRIDGE, DEVEN);
+
+	int i, j;
+	if (s3resume && info->cached_training) {
+		restore_274265(info);
+		printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
+		       info->cached_training->reg2ca9_bit0);
+		for (i = 0; i < 2; i++)
+			for (j = 0; j < 3; j++)
+				printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
+				       i, j, info->cached_training->reg274265[i][j]);
+	} else {
+		set_274265(info);
+		printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
+		       info->training.reg2ca9_bit0);
+		for (i = 0; i < 2; i++)
+			for (j = 0; j < 3; j++)
+				printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
+				       i, j, info->training.reg274265[i][j]);
+	}
+
+	set_2dxx_series(info, s3resume);
+
+	if (!(deven & 8)) {
+		MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
+	}
+
+	udelay(1000);
+
+	if (deven & 8) {
+		MCHBAR32_OR(0xff8, 0x1800);
+		MCHBAR32_AND(0x2cb0, 0x00);
+		pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
+		pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
+		pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
+
+		MCHBAR8(0x1150);
+		MCHBAR8(0x1151);
+		MCHBAR8(0x1022);
+		MCHBAR8(0x16d0);
+		MCHBAR32(0x1300) = 0x60606060;
+		MCHBAR32(0x1304) = 0x60606060;
+		MCHBAR32(0x1308) = 0x78797a7b;
+		MCHBAR32(0x130c) = 0x7c7d7e7f;
+		MCHBAR32(0x1310) = 0x60606060;
+		MCHBAR32(0x1314) = 0x60606060;
+		MCHBAR32(0x1318) = 0x60606060;
+		MCHBAR32(0x131c) = 0x60606060;
+		MCHBAR32(0x1320) = 0x50515253;
+		MCHBAR32(0x1324) = 0x54555657;
+		MCHBAR32(0x1328) = 0x58595a5b;
+		MCHBAR32(0x132c) = 0x5c5d5e5f;
+		MCHBAR32(0x1330) = 0x40414243;
+		MCHBAR32(0x1334) = 0x44454647;
+		MCHBAR32(0x1338) = 0x48494a4b;
+		MCHBAR32(0x133c) = 0x4c4d4e4f;
+		MCHBAR32(0x1340) = 0x30313233;
+		MCHBAR32(0x1344) = 0x34353637;
+		MCHBAR32(0x1348) = 0x38393a3b;
+		MCHBAR32(0x134c) = 0x3c3d3e3f;
+		MCHBAR32(0x1350) = 0x20212223;
+		MCHBAR32(0x1354) = 0x24252627;
+		MCHBAR32(0x1358) = 0x28292a2b;
+		MCHBAR32(0x135c) = 0x2c2d2e2f;
+		MCHBAR32(0x1360) = 0x10111213;
+		MCHBAR32(0x1364) = 0x14151617;
+		MCHBAR32(0x1368) = 0x18191a1b;
+		MCHBAR32(0x136c) = 0x1c1d1e1f;
+		MCHBAR32(0x1370) = 0x10203;
+		MCHBAR32(0x1374) = 0x4050607;
+		MCHBAR32(0x1378) = 0x8090a0b;
+		MCHBAR32(0x137c) = 0xc0d0e0f;
+		MCHBAR8(0x11cc) = 0x4e;
+		MCHBAR32(0x1110) = 0x73970404;
+		MCHBAR32(0x1114) = 0x72960404;
+		MCHBAR32(0x1118) = 0x6f950404;
+		MCHBAR32(0x111c) = 0x6d940404;
+		MCHBAR32(0x1120) = 0x6a930404;
+		MCHBAR32(0x1124) = 0x68a41404;
+		MCHBAR32(0x1128) = 0x66a21404;
+		MCHBAR32(0x112c) = 0x63a01404;
+		MCHBAR32(0x1130) = 0x609e1404;
+		MCHBAR32(0x1134) = 0x5f9c1404;
+		MCHBAR32(0x1138) = 0x5c961404;
+		MCHBAR32(0x113c) = 0x58a02404;
+		MCHBAR32(0x1140) = 0x54942404;
+		MCHBAR32(0x1190) = 0x900080a;
+		MCHBAR16(0x11c0) = 0xc40b;
+		MCHBAR16(0x11c2) = 0x303;
+		MCHBAR16(0x11c4) = 0x301;
+		MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
+		MCHBAR32(0x11b8) = 0x70c3000;
+		MCHBAR8(0x11ec) = 0xa;
+		MCHBAR16(0x1100) = 0x800;
+		MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
+		MCHBAR16(0x11ca) = 0xfa;
+		MCHBAR32(0x11e4) = 0x4e20;
+		MCHBAR8(0x11bc) = 0xf;
+		MCHBAR16(0x11da) = 0x19;
+		MCHBAR16(0x11ba) = 0x470c;
+		MCHBAR32(0x1680) = 0xe6ffe4ff;
+		MCHBAR32(0x1684) = 0xdeffdaff;
+		MCHBAR32(0x1688) = 0xd4ffd0ff;
+		MCHBAR32(0x168c) = 0xccffc6ff;
+		MCHBAR32(0x1690) = 0xc0ffbeff;
+		MCHBAR32(0x1694) = 0xb8ffb0ff;
+		MCHBAR32(0x1698) = 0xa8ff0000;
+		MCHBAR32(0x169c) = 0xc00;
+		MCHBAR32(0x1290) = 0x5000000;
+	}
+
+	MCHBAR32(0x124c) = 0x15040d00;
+	MCHBAR32(0x1250) = 0x7f0000;
+	MCHBAR32(0x1254) = 0x1e220004;
+	MCHBAR32(0x1258) = 0x4000004;
+	MCHBAR32(0x1278) = 0x0;
+	MCHBAR32(0x125c) = 0x0;
+	MCHBAR32(0x1260) = 0x0;
+	MCHBAR32(0x1264) = 0x0;
+	MCHBAR32(0x1268) = 0x0;
+	MCHBAR32(0x126c) = 0x0;
+	MCHBAR32(0x1270) = 0x0;
+	MCHBAR32(0x1274) = 0x0;
+
+	if (deven & 8) {
+		MCHBAR16(0x1214) = 0x320;
+		MCHBAR32(0x1600) = 0x40000000;
+		MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
+		MCHBAR16_AND_OR(0x1230, 0, 0x8000);
+		MCHBAR32(0x1400) = 0x13040020;
+		MCHBAR32(0x1404) = 0xe090120;
+		MCHBAR32(0x1408) = 0x5120220;
+		MCHBAR32(0x140c) = 0x5120330;
+		MCHBAR32(0x1410) = 0xe090220;
+		MCHBAR32(0x1414) = 0x1010001;
+		MCHBAR32(0x1418) = 0x1110000;
+		MCHBAR32(0x141c) = 0x9020020;
+		MCHBAR32(0x1420) = 0xd090220;
+		MCHBAR32(0x1424) = 0x2090220;
+		MCHBAR32(0x1428) = 0x2090330;
+		MCHBAR32(0x142c) = 0xd090220;
+		MCHBAR32(0x1430) = 0x1010001;
+		MCHBAR32(0x1434) = 0x1110000;
+		MCHBAR32(0x1438) = 0x11040020;
+		MCHBAR32(0x143c) = 0x4030220;
+		MCHBAR32(0x1440) = 0x1060220;
+		MCHBAR32(0x1444) = 0x1060330;
+		MCHBAR32(0x1448) = 0x4030220;
+		MCHBAR32(0x144c) = 0x1010001;
+		MCHBAR32(0x1450) = 0x1110000;
+		MCHBAR32(0x1454) = 0x4010020;
+		MCHBAR32(0x1458) = 0xb090220;
+		MCHBAR32(0x145c) = 0x1090220;
+		MCHBAR32(0x1460) = 0x1090330;
+		MCHBAR32(0x1464) = 0xb090220;
+		MCHBAR32(0x1468) = 0x1010001;
+		MCHBAR32(0x146c) = 0x1110000;
+		MCHBAR32(0x1470) = 0xf040020;
+		MCHBAR32(0x1474) = 0xa090220;
+		MCHBAR32(0x1478) = 0x1120220;
+		MCHBAR32(0x147c) = 0x1120330;
+		MCHBAR32(0x1480) = 0xa090220;
+		MCHBAR32(0x1484) = 0x1010001;
+		MCHBAR32(0x1488) = 0x1110000;
+		MCHBAR32(0x148c) = 0x7020020;
+		MCHBAR32(0x1490) = 0x1010220;
+		MCHBAR32(0x1494) = 0x10210;
+		MCHBAR32(0x1498) = 0x10320;
+		MCHBAR32(0x149c) = 0x1010220;
+		MCHBAR32(0x14a0) = 0x1010001;
+		MCHBAR32(0x14a4) = 0x1110000;
+		MCHBAR32(0x14a8) = 0xd040020;
+		MCHBAR32(0x14ac) = 0x8090220;
+		MCHBAR32(0x14b0) = 0x1111310;
+		MCHBAR32(0x14b4) = 0x1111420;
+		MCHBAR32(0x14b8) = 0x8090220;
+		MCHBAR32(0x14bc) = 0x1010001;
+		MCHBAR32(0x14c0) = 0x1110000;
+		MCHBAR32(0x14c4) = 0x3010020;
+		MCHBAR32(0x14c8) = 0x7090220;
+		MCHBAR32(0x14cc) = 0x1081310;
+		MCHBAR32(0x14d0) = 0x1081420;
+		MCHBAR32(0x14d4) = 0x7090220;
+		MCHBAR32(0x14d8) = 0x1010001;
+		MCHBAR32(0x14dc) = 0x1110000;
+		MCHBAR32(0x14e0) = 0xb040020;
+		MCHBAR32(0x14e4) = 0x2030220;
+		MCHBAR32(0x14e8) = 0x1051310;
+		MCHBAR32(0x14ec) = 0x1051420;
+		MCHBAR32(0x14f0) = 0x2030220;
+		MCHBAR32(0x14f4) = 0x1010001;
+		MCHBAR32(0x14f8) = 0x1110000;
+		MCHBAR32(0x14fc) = 0x5020020;
+		MCHBAR32(0x1500) = 0x5090220;
+		MCHBAR32(0x1504) = 0x2071310;
+		MCHBAR32(0x1508) = 0x2071420;
+		MCHBAR32(0x150c) = 0x5090220;
+		MCHBAR32(0x1510) = 0x1010001;
+		MCHBAR32(0x1514) = 0x1110000;
+		MCHBAR32(0x1518) = 0x7040120;
+		MCHBAR32(0x151c) = 0x2090220;
+		MCHBAR32(0x1520) = 0x70b1210;
+		MCHBAR32(0x1524) = 0x70b1310;
+		MCHBAR32(0x1528) = 0x2090220;
+		MCHBAR32(0x152c) = 0x1010001;
+		MCHBAR32(0x1530) = 0x1110000;
+		MCHBAR32(0x1534) = 0x1010110;
+		MCHBAR32(0x1538) = 0x1081310;
+		MCHBAR32(0x153c) = 0x5041200;
+		MCHBAR32(0x1540) = 0x5041310;
+		MCHBAR32(0x1544) = 0x1081310;
+		MCHBAR32(0x1548) = 0x1010001;
+		MCHBAR32(0x154c) = 0x1110000;
+		MCHBAR32(0x1550) = 0x1040120;
+		MCHBAR32(0x1554) = 0x4051210;
+		MCHBAR32(0x1558) = 0xd051200;
+		MCHBAR32(0x155c) = 0xd051200;
+		MCHBAR32(0x1560) = 0x4051210;
+		MCHBAR32(0x1564) = 0x1010001;
+		MCHBAR32(0x1568) = 0x1110000;
+		MCHBAR16(0x1222) = 0x220a;
+		MCHBAR16(0x123c) = 0x1fc0;
+		MCHBAR16(0x1220) = 0x1388;
+	}
+}
diff --git a/src/northbridge/intel/ironlake/raminit.c b/src/northbridge/intel/ironlake/raminit.c
index cfc037d..0efe176 100644
--- a/src/northbridge/intel/ironlake/raminit.c
+++ b/src/northbridge/intel/ironlake/raminit.c
@@ -55,33 +55,6 @@
       for (rank = 0; rank < NUM_RANKS; rank++)			\
 	if (info->populated_ranks[channel][slot][rank])
 
-/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
-typedef struct {
-	u8 smallest;
-	u8 largest;
-} timing_bounds_t[2][2][2][9];
-
-#define MRC_CACHE_VERSION 3
-
-struct ram_training {
-	/* [TM][CHANNEL][SLOT][RANK][LANE] */
-	u16 lane_timings[4][2][2][2][9];
-	u16 reg_178;
-	u16 reg_10b;
-
-	u8 reg178_center;
-	u8 reg178_smallest;
-	u8 reg178_largest;
-	timing_bounds_t timing_bounds[2];
-	u16 timing_offset[2][2][2][9];
-	u16 timing2_offset[2][2][2][9];
-	u16 timing2_bounds[2][2][2][9][2];
-	u8 reg274265[2][3];	/* [CHANNEL][REGISTER] */
-	u8 reg2ca9_bit0;
-	u32 reg_6dc;
-	u32 reg_6e8;
-};
-
 #include <lib.h>		/* Prototypes */
 
 typedef struct _u128 {
@@ -177,45 +150,6 @@
 
 #define gav(x) gav_real (__LINE__, (x))
 
-struct raminfo {
-	u16 clock_speed_index;	/* clock_speed (REAL, not DDR) / 133.(3) - 3 */
-	u16 fsb_frequency;	/* in 1.(1)/2 MHz.  */
-	u8 is_x16_module[2][2];	/* [CHANNEL][SLOT] */
-	u8 density[2][2];	/* [CHANNEL][SLOT] */
-	u8 populated_ranks[2][2][2];	/* [CHANNEL][SLOT][RANK] */
-	int rank_start[2][2][2];
-	u8 cas_latency;
-	u8 board_lane_delay[9];
-	u8 use_ecc;
-	u8 revision;
-	u8 max_supported_clock_speed_index;
-	u8 uma_enabled;
-	u8 spd[2][2][151];	/* [CHANNEL][SLOT][BYTE]  */
-	u8 silicon_revision;
-	u8 populated_ranks_mask[2];
-	u8 max_slots_used_in_channel;
-	u8 mode4030[2];
-	u16 avg4044[2];
-	u16 max4048[2];
-	unsigned int total_memory_mb;
-	unsigned int interleaved_part_mb;
-	unsigned int non_interleaved_part_mb;
-
-	unsigned int memory_reserved_for_heci_mb;
-
-	struct ram_training training;
-	u32 last_500_command[2];
-
-	u32 delay46_ps[2];
-	u32 delay54_ps[2];
-	u8 revision_flag_1;
-	u8 some_delay_1_cycle_floor;
-	u8 some_delay_2_halfcycles_ceil;
-	u8 some_delay_3_ps_rounded;
-
-	const struct ram_training *cached_training;
-};
-
 /* Global allocation of timings_car */
 timing_bounds_t timings_car[64];
 
@@ -351,9 +285,6 @@
 	return ret;
 }
 
-#define NUM_CHANNELS 2
-#define NUM_SLOTS 2
-#define NUM_RANKS 2
 #define RANK_SHIFT 28
 #define CHANNEL_SHIFT 10
 
@@ -768,29 +699,12 @@
 	}
 }
 
-static unsigned int fsbcycle_ps(struct raminfo *info)
-{
-	return 900000 / info->fsb_frequency;
-}
-
-/* The time of DDR transfer in ps.  */
-static unsigned int halfcycle_ps(struct raminfo *info)
-{
-	return 3750 / (info->clock_speed_index + 3);
-}
-
 /* The time of clock cycle in ps.  */
 static unsigned int cycle_ps(struct raminfo *info)
 {
 	return 2 * halfcycle_ps(info);
 }
 
-/* Frequency in 1.(1)=10/9 MHz units. */
-static unsigned int frequency_11(struct raminfo *info)
-{
-	return (info->clock_speed_index + 3) * 120;
-}
-
 /* Frequency in 0.1 MHz units. */
 static unsigned int frequency_01(struct raminfo *info)
 {
@@ -3168,318 +3082,7 @@
 	MCHBAR16(0xfc4) = saved_fc4;
 }
 
-static unsigned int gcd(unsigned int a, unsigned int b)
-{
-	unsigned int t;
-	if (a > b) {
-		t = a;
-		a = b;
-		b = t;
-	}
-	/* invariant a < b.  */
-	while (a) {
-		t = b % a;
-		b = a;
-		a = t;
-	}
-	return b;
-}
-
-static inline int div_roundup(int a, int b)
-{
-	return DIV_ROUND_UP(a, b);
-}
-
-static unsigned int lcm(unsigned int a, unsigned int b)
-{
-	return (a * b) / gcd(a, b);
-}
-
-struct stru1 {
-	u8 freqs_reversed;
-	u8 freq_diff_reduced;
-	u8 freq_min_reduced;
-	u8 divisor_f4_to_fmax;
-	u8 divisor_f3_to_fmax;
-	u8 freq4_to_max_remainder;
-	u8 freq3_to_2_remainder;
-	u8 freq3_to_2_remaindera;
-	u8 freq4_to_2_remainder;
-	int divisor_f3_to_f1, divisor_f4_to_f2;
-	int common_time_unit_ps;
-	int freq_max_reduced;
-};
-
-static void
-compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
-			 int num_cycles_2, int num_cycles_1, int round_it,
-			 int add_freqs, struct stru1 *result)
-{
-	int g;
-	int common_time_unit_ps;
-	int freq1_reduced, freq2_reduced;
-	int freq_min_reduced;
-	int freq_max_reduced;
-	int freq3, freq4;
-
-	g = gcd(freq1, freq2);
-	freq1_reduced = freq1 / g;
-	freq2_reduced = freq2 / g;
-	freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
-	freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
-
-	common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
-	freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
-	freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
-	if (add_freqs) {
-		freq3 += freq2_reduced;
-		freq4 += freq1_reduced;
-	}
-
-	if (round_it) {
-		result->freq3_to_2_remainder = 0;
-		result->freq3_to_2_remaindera = 0;
-		result->freq4_to_max_remainder = 0;
-		result->divisor_f4_to_f2 = 0;
-		result->divisor_f3_to_f1 = 0;
-	} else {
-		if (freq2_reduced < freq1_reduced) {
-			result->freq3_to_2_remainder =
-			    result->freq3_to_2_remaindera =
-			    freq3 % freq1_reduced - freq1_reduced + 1;
-			result->freq4_to_max_remainder =
-			    -(freq4 % freq1_reduced);
-			result->divisor_f3_to_f1 = freq3 / freq1_reduced;
-			result->divisor_f4_to_f2 =
-			    (freq4 -
-			     (freq1_reduced - freq2_reduced)) / freq2_reduced;
-			result->freq4_to_2_remainder =
-			    -(char)((freq1_reduced - freq2_reduced) +
-				    ((u8) freq4 -
-				     (freq1_reduced -
-				      freq2_reduced)) % (u8) freq2_reduced);
-		} else {
-			if (freq2_reduced > freq1_reduced) {
-				result->freq4_to_max_remainder =
-				    (freq4 % freq2_reduced) - freq2_reduced + 1;
-				result->freq4_to_2_remainder =
-				    freq4 % freq_max_reduced -
-				    freq_max_reduced + 1;
-			} else {
-				result->freq4_to_max_remainder =
-				    -(freq4 % freq2_reduced);
-				result->freq4_to_2_remainder =
-				    -(char)(freq4 % freq_max_reduced);
-			}
-			result->divisor_f4_to_f2 = freq4 / freq2_reduced;
-			result->divisor_f3_to_f1 =
-			    (freq3 -
-			     (freq2_reduced - freq1_reduced)) / freq1_reduced;
-			result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
-			result->freq3_to_2_remaindera =
-			    -(char)((freq_max_reduced - freq_min_reduced) +
-				    (freq3 -
-				     (freq_max_reduced -
-				      freq_min_reduced)) % freq1_reduced);
-		}
-	}
-	result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
-	result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
-	if (round_it) {
-		if (freq2_reduced > freq1_reduced) {
-			if (freq3 % freq_max_reduced)
-				result->divisor_f3_to_fmax++;
-		}
-		if (freq2_reduced < freq1_reduced) {
-			if (freq4 % freq_max_reduced)
-				result->divisor_f4_to_fmax++;
-		}
-	}
-	result->freqs_reversed = (freq2_reduced < freq1_reduced);
-	result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
-	result->freq_min_reduced = freq_min_reduced;
-	result->common_time_unit_ps = common_time_unit_ps;
-	result->freq_max_reduced = freq_max_reduced;
-}
-
-static void
-set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
-	     int num_cycles_2, int num_cycles_1, int num_cycles_3,
-	     int num_cycles_4, int reverse)
-{
-	struct stru1 vv;
-	char multiplier;
-
-	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
-				 0, 1, &vv);
-
-	multiplier =
-	    div_roundup(MAX
-			(div_roundup(num_cycles_2, vv.common_time_unit_ps) +
-			 div_roundup(num_cycles_3, vv.common_time_unit_ps),
-			 div_roundup(num_cycles_1,
-				     vv.common_time_unit_ps) +
-			 div_roundup(num_cycles_4, vv.common_time_unit_ps))
-			+ vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
-
-	u32 y =
-	    (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
-		  vv.freq_max_reduced * multiplier)
-	    | (vv.
-	       freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
-					     multiplier) << 16) | ((u8) (vv.
-									 freq_min_reduced
-									 *
-									 multiplier)
-								   << 24);
-	u32 x =
-	    vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
-									 divisor_f3_to_f1
-									 << 16)
-	    | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
-	if (reverse) {
-		MCHBAR32(reg) = y;
-		MCHBAR32(reg + 4) = x;
-	} else {
-		MCHBAR32(reg + 4) = y;
-		MCHBAR32(reg) = x;
-	}
-}
-
-static void
-set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
-	   int num_cycles_1, int num_cycles_2, int num_cycles_3,
-	   int num_cycles_4)
-{
-	struct stru1 ratios1;
-	struct stru1 ratios2;
-
-	compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
-				 0, 1, &ratios2);
-	compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
-				 0, 1, &ratios1);
-	printk(RAM_SPEW, "[%x] <= %x\n", reg,
-		       ratios1.freq4_to_max_remainder | (ratios2.
-							 freq4_to_max_remainder
-							 << 8)
-		       | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
-							       divisor_f4_to_fmax
-							       << 20));
-	MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
-		(ratios2.freq4_to_max_remainder << 8) |
-		(ratios1.divisor_f4_to_fmax << 16) |
-		(ratios2.divisor_f4_to_fmax << 20);
-}
-
-static void
-set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
-	     int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
-{
-	struct stru1 ratios;
-
-	compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
-				 round_it, add_freqs, &ratios);
-	switch (mode) {
-	case 0:
-		MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
-			(ratios.freqs_reversed << 8);
-		MCHBAR32(reg) = ratios.freq3_to_2_remainder |
-			(ratios.freq4_to_max_remainder << 8) |
-			(ratios.divisor_f3_to_fmax << 16) |
-			(ratios.divisor_f4_to_fmax << 20) |
-			(ratios.freq_min_reduced << 24);
-		break;
-
-	case 1:
-		MCHBAR32(reg) = ratios.freq3_to_2_remainder |
-			(ratios.divisor_f3_to_fmax << 16);
-		break;
-
-	case 2:
-		MCHBAR32(reg) = ratios.freq3_to_2_remainder |
-			(ratios.freq4_to_max_remainder << 8) |
-			(ratios.divisor_f3_to_fmax << 16) |
-			(ratios.divisor_f4_to_fmax << 20);
-		break;
-
-	case 4:
-		MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
-			(ratios.divisor_f4_to_fmax << 8) |
-			(ratios.freqs_reversed << 12) |
-			(ratios.freq_min_reduced << 16) |
-			(ratios.freq_diff_reduced << 24);
-		break;
-	}
-}
-
-static void set_2dxx_series(struct raminfo *info, int s3resume)
-{
-	set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
-		     0, 1);
-	set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
-	set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
-		     1);
-	set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
-		     frequency_11(info), 1231, 1524, 0, 1);
-	set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
-		     frequency_11(info) / 2, 1278, 2008, 0, 1);
-	set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
-		     1167, 1539, 0, 1);
-	set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
-		     frequency_11(info) / 2, 1403, 1318, 0, 1);
-	set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
-		     1);
-	set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
-		     1);
-	set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
-		     1, 1);
-	set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
-		     1);
-	set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
-		     frequency_11(info) / 2, 4000, 0, 0, 0);
-	set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
-		     frequency_11(info) / 2, 4000, 4000, 0, 0);
-
-	if (s3resume) {
-		printk(RAM_SPEW, "[6dc] <= %x\n",
-			info->cached_training->reg_6dc);
-		MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
-	} else
-		set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
-			   info->delay46_ps[0], 0,
-			   info->delay54_ps[0]);
-	set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
-		     frequency_11(info), 2500, 0, 0, 0);
-	set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
-		     frequency_11(info) / 2, 3500, 0, 0, 0);
-	if (s3resume) {
-		printk(RAM_SPEW, "[6e8] <= %x\n",
-			info->cached_training->reg_6e8);
-		MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
-	} else
-		set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
-			   info->delay46_ps[1], 0,
-			   info->delay54_ps[1]);
-	set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
-	set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
-		     470, 0);
-	set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
-	set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
-		     454, 459, 0);
-	set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
-	set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
-		     2588, 0);
-	set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
-		     2405, 0);
-	set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
-	set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
-		     480, 0);
-	set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
-	MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
-	MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
-}
-
-static u16 get_max_timing(struct raminfo *info, int channel)
+u16 get_max_timing(struct raminfo *info, int channel)
 {
 	int slot, rank, lane;
 	u16 ret = 0;
@@ -3501,117 +3104,6 @@
 	return ret;
 }
 
-static void set_274265(struct raminfo *info)
-{
-	int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
-	int delay_e_ps, delay_e_cycles, delay_f_cycles;
-	int delay_e_over_cycle_ps;
-	int cycletime_ps;
-	int channel;
-
-	delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
-	info->training.reg2ca9_bit0 = 0;
-	for (channel = 0; channel < NUM_CHANNELS; channel++) {
-		cycletime_ps =
-		    900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
-		delay_d_ps =
-		    (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
-		    - info->some_delay_3_ps_rounded + 200;
-		if (!
-		    ((info->silicon_revision == 0
-		      || info->silicon_revision == 1)
-		     && (info->revision >= 8)))
-			delay_d_ps += halfcycle_ps(info) * 2;
-		delay_d_ps +=
-		    halfcycle_ps(info) * (!info->revision_flag_1 +
-					  info->some_delay_2_halfcycles_ceil +
-					  2 * info->some_delay_1_cycle_floor +
-					  info->clock_speed_index +
-					  2 * info->cas_latency - 7 + 11);
-		delay_d_ps += info->revision >= 8 ? 2758 : 4428;
-
-		MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
-		MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
-		if ((MCHBAR8(0x144) & 0x1f) > 0x13)
-			delay_d_ps += 650;
-		delay_c_ps = delay_d_ps + 1800;
-		if (delay_c_ps <= delay_a_ps)
-			delay_e_ps = 0;
-		else
-			delay_e_ps =
-			    cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
-						       cycletime_ps);
-
-		delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
-		delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
-		delay_f_cycles =
-		    div_roundup(2500 - delay_e_over_cycle_ps,
-				2 * halfcycle_ps(info));
-		if (delay_f_cycles > delay_e_cycles) {
-			info->delay46_ps[channel] = delay_e_ps;
-			delay_e_cycles = 0;
-		} else {
-			info->delay46_ps[channel] =
-			    delay_e_over_cycle_ps +
-			    2 * halfcycle_ps(info) * delay_f_cycles;
-			delay_e_cycles -= delay_f_cycles;
-		}
-
-		if (info->delay46_ps[channel] < 2500) {
-			info->delay46_ps[channel] = 2500;
-			info->training.reg2ca9_bit0 = 1;
-		}
-		delay_b_ps = halfcycle_ps(info) + delay_c_ps;
-		if (delay_b_ps <= delay_a_ps)
-			delay_b_ps = 0;
-		else
-			delay_b_ps -= delay_a_ps;
-		info->delay54_ps[channel] =
-		    cycletime_ps * div_roundup(delay_b_ps,
-					       cycletime_ps) -
-		    2 * halfcycle_ps(info) * delay_e_cycles;
-		if (info->delay54_ps[channel] < 2500)
-			info->delay54_ps[channel] = 2500;
-		info->training.reg274265[channel][0] = delay_e_cycles;
-		if (delay_d_ps + 7 * halfcycle_ps(info) <=
-		    24 * halfcycle_ps(info))
-			info->training.reg274265[channel][1] = 0;
-		else
-			info->training.reg274265[channel][1] =
-				div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
-				4 * halfcycle_ps(info)) - 6;
-		MCHBAR32((channel << 10) + 0x274) =
-			info->training.reg274265[channel][1] |
-			(info->training.reg274265[channel][0] << 16);
-		info->training.reg274265[channel][2] =
-			div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
-			4 * halfcycle_ps(info)) + 1;
-		MCHBAR16((channel << 10) + 0x265) =
-			info->training.reg274265[channel][2] << 8;
-	}
-	if (info->training.reg2ca9_bit0)
-		MCHBAR8_OR(0x2ca9, 1);
-	else
-		MCHBAR8_AND(0x2ca9, ~1);
-}
-
-static void restore_274265(struct raminfo *info)
-{
-	int channel;
-
-	for (channel = 0; channel < NUM_CHANNELS; channel++) {
-		MCHBAR32((channel << 10) + 0x274) =
-			(info->cached_training->reg274265[channel][0] << 16) |
-			info->cached_training->reg274265[channel][1];
-		MCHBAR16((channel << 10) + 0x265) =
-			info->cached_training->reg274265[channel][2] << 8;
-	}
-	if (info->cached_training->reg2ca9_bit0)
-		MCHBAR8_OR(0x2ca9, 1);
-	else
-		MCHBAR8_AND(0x2ca9, ~1);
-}
-
 static void dmi_setup(void)
 {
 	gav(DMIBAR8(0x254));
@@ -3691,18 +3183,14 @@
 void raminit(const int s3resume, const u8 *spd_addrmap)
 {
 	unsigned int channel, slot, lane, rank;
-	int i;
 	struct raminfo info;
 	u8 x2ca8;
-	u16 deven;
 	int cbmem_wasnot_inited;
 
 	x2ca8 = MCHBAR8(0x2ca8);
 
 	printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
 
-	deven = pci_read_config16(NORTHBRIDGE, DEVEN);
-
 	memset(&info, 0x5a, sizeof(info));
 
 	info.last_500_command[0] = 0;
@@ -3971,230 +3459,8 @@
 
 	info.cached_training = get_cached_training();
 
-	if (x2ca8 == 0) {
-		int j;
-		if (s3resume && info.cached_training) {
-			restore_274265(&info);
-			printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
-			       info.cached_training->reg2ca9_bit0);
-			for (i = 0; i < 2; i++)
-				for (j = 0; j < 3; j++)
-					printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
-					       i, j, info.cached_training->reg274265[i][j]);
-		} else {
-			set_274265(&info);
-			printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
-			       info.training.reg2ca9_bit0);
-			for (i = 0; i < 2; i++)
-				for (j = 0; j < 3; j++)
-					printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
-					       i, j, info.training.reg274265[i][j]);
-		}
-
-		set_2dxx_series(&info, s3resume);
-
-		if (!(deven & 8)) {
-			MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
-		}
-
-		udelay(1000);
-
-		if (deven & 8) {
-			MCHBAR32_OR(0xff8, 0x1800);
-			MCHBAR32_AND(0x2cb0, 0x00);
-			pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
-			pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
-			pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
-
-			MCHBAR8(0x1150);
-			MCHBAR8(0x1151);
-			MCHBAR8(0x1022);
-			MCHBAR8(0x16d0);
-			MCHBAR32(0x1300) = 0x60606060;
-			MCHBAR32(0x1304) = 0x60606060;
-			MCHBAR32(0x1308) = 0x78797a7b;
-			MCHBAR32(0x130c) = 0x7c7d7e7f;
-			MCHBAR32(0x1310) = 0x60606060;
-			MCHBAR32(0x1314) = 0x60606060;
-			MCHBAR32(0x1318) = 0x60606060;
-			MCHBAR32(0x131c) = 0x60606060;
-			MCHBAR32(0x1320) = 0x50515253;
-			MCHBAR32(0x1324) = 0x54555657;
-			MCHBAR32(0x1328) = 0x58595a5b;
-			MCHBAR32(0x132c) = 0x5c5d5e5f;
-			MCHBAR32(0x1330) = 0x40414243;
-			MCHBAR32(0x1334) = 0x44454647;
-			MCHBAR32(0x1338) = 0x48494a4b;
-			MCHBAR32(0x133c) = 0x4c4d4e4f;
-			MCHBAR32(0x1340) = 0x30313233;
-			MCHBAR32(0x1344) = 0x34353637;
-			MCHBAR32(0x1348) = 0x38393a3b;
-			MCHBAR32(0x134c) = 0x3c3d3e3f;
-			MCHBAR32(0x1350) = 0x20212223;
-			MCHBAR32(0x1354) = 0x24252627;
-			MCHBAR32(0x1358) = 0x28292a2b;
-			MCHBAR32(0x135c) = 0x2c2d2e2f;
-			MCHBAR32(0x1360) = 0x10111213;
-			MCHBAR32(0x1364) = 0x14151617;
-			MCHBAR32(0x1368) = 0x18191a1b;
-			MCHBAR32(0x136c) = 0x1c1d1e1f;
-			MCHBAR32(0x1370) = 0x10203;
-			MCHBAR32(0x1374) = 0x4050607;
-			MCHBAR32(0x1378) = 0x8090a0b;
-			MCHBAR32(0x137c) = 0xc0d0e0f;
-			MCHBAR8(0x11cc) = 0x4e;
-			MCHBAR32(0x1110) = 0x73970404;
-			MCHBAR32(0x1114) = 0x72960404;
-			MCHBAR32(0x1118) = 0x6f950404;
-			MCHBAR32(0x111c) = 0x6d940404;
-			MCHBAR32(0x1120) = 0x6a930404;
-			MCHBAR32(0x1124) = 0x68a41404;
-			MCHBAR32(0x1128) = 0x66a21404;
-			MCHBAR32(0x112c) = 0x63a01404;
-			MCHBAR32(0x1130) = 0x609e1404;
-			MCHBAR32(0x1134) = 0x5f9c1404;
-			MCHBAR32(0x1138) = 0x5c961404;
-			MCHBAR32(0x113c) = 0x58a02404;
-			MCHBAR32(0x1140) = 0x54942404;
-			MCHBAR32(0x1190) = 0x900080a;
-			MCHBAR16(0x11c0) = 0xc40b;
-			MCHBAR16(0x11c2) = 0x303;
-			MCHBAR16(0x11c4) = 0x301;
-			MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
-			MCHBAR32(0x11b8) = 0x70c3000;
-			MCHBAR8(0x11ec) = 0xa;
-			MCHBAR16(0x1100) = 0x800;
-			MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
-			MCHBAR16(0x11ca) = 0xfa;
-			MCHBAR32(0x11e4) = 0x4e20;
-			MCHBAR8(0x11bc) = 0xf;
-			MCHBAR16(0x11da) = 0x19;
-			MCHBAR16(0x11ba) = 0x470c;
-			MCHBAR32(0x1680) = 0xe6ffe4ff;
-			MCHBAR32(0x1684) = 0xdeffdaff;
-			MCHBAR32(0x1688) = 0xd4ffd0ff;
-			MCHBAR32(0x168c) = 0xccffc6ff;
-			MCHBAR32(0x1690) = 0xc0ffbeff;
-			MCHBAR32(0x1694) = 0xb8ffb0ff;
-			MCHBAR32(0x1698) = 0xa8ff0000;
-			MCHBAR32(0x169c) = 0xc00;
-			MCHBAR32(0x1290) = 0x5000000;
-		}
-
-		MCHBAR32(0x124c) = 0x15040d00;
-		MCHBAR32(0x1250) = 0x7f0000;
-		MCHBAR32(0x1254) = 0x1e220004;
-		MCHBAR32(0x1258) = 0x4000004;
-		MCHBAR32(0x1278) = 0x0;
-		MCHBAR32(0x125c) = 0x0;
-		MCHBAR32(0x1260) = 0x0;
-		MCHBAR32(0x1264) = 0x0;
-		MCHBAR32(0x1268) = 0x0;
-		MCHBAR32(0x126c) = 0x0;
-		MCHBAR32(0x1270) = 0x0;
-		MCHBAR32(0x1274) = 0x0;
-	}
-
-	if ((deven & 8) && x2ca8 == 0) {
-		MCHBAR16(0x1214) = 0x320;
-		MCHBAR32(0x1600) = 0x40000000;
-		MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
-		MCHBAR16_AND_OR(0x1230, 0, 0x8000);
-		MCHBAR32(0x1400) = 0x13040020;
-		MCHBAR32(0x1404) = 0xe090120;
-		MCHBAR32(0x1408) = 0x5120220;
-		MCHBAR32(0x140c) = 0x5120330;
-		MCHBAR32(0x1410) = 0xe090220;
-		MCHBAR32(0x1414) = 0x1010001;
-		MCHBAR32(0x1418) = 0x1110000;
-		MCHBAR32(0x141c) = 0x9020020;
-		MCHBAR32(0x1420) = 0xd090220;
-		MCHBAR32(0x1424) = 0x2090220;
-		MCHBAR32(0x1428) = 0x2090330;
-		MCHBAR32(0x142c) = 0xd090220;
-		MCHBAR32(0x1430) = 0x1010001;
-		MCHBAR32(0x1434) = 0x1110000;
-		MCHBAR32(0x1438) = 0x11040020;
-		MCHBAR32(0x143c) = 0x4030220;
-		MCHBAR32(0x1440) = 0x1060220;
-		MCHBAR32(0x1444) = 0x1060330;
-		MCHBAR32(0x1448) = 0x4030220;
-		MCHBAR32(0x144c) = 0x1010001;
-		MCHBAR32(0x1450) = 0x1110000;
-		MCHBAR32(0x1454) = 0x4010020;
-		MCHBAR32(0x1458) = 0xb090220;
-		MCHBAR32(0x145c) = 0x1090220;
-		MCHBAR32(0x1460) = 0x1090330;
-		MCHBAR32(0x1464) = 0xb090220;
-		MCHBAR32(0x1468) = 0x1010001;
-		MCHBAR32(0x146c) = 0x1110000;
-		MCHBAR32(0x1470) = 0xf040020;
-		MCHBAR32(0x1474) = 0xa090220;
-		MCHBAR32(0x1478) = 0x1120220;
-		MCHBAR32(0x147c) = 0x1120330;
-		MCHBAR32(0x1480) = 0xa090220;
-		MCHBAR32(0x1484) = 0x1010001;
-		MCHBAR32(0x1488) = 0x1110000;
-		MCHBAR32(0x148c) = 0x7020020;
-		MCHBAR32(0x1490) = 0x1010220;
-		MCHBAR32(0x1494) = 0x10210;
-		MCHBAR32(0x1498) = 0x10320;
-		MCHBAR32(0x149c) = 0x1010220;
-		MCHBAR32(0x14a0) = 0x1010001;
-		MCHBAR32(0x14a4) = 0x1110000;
-		MCHBAR32(0x14a8) = 0xd040020;
-		MCHBAR32(0x14ac) = 0x8090220;
-		MCHBAR32(0x14b0) = 0x1111310;
-		MCHBAR32(0x14b4) = 0x1111420;
-		MCHBAR32(0x14b8) = 0x8090220;
-		MCHBAR32(0x14bc) = 0x1010001;
-		MCHBAR32(0x14c0) = 0x1110000;
-		MCHBAR32(0x14c4) = 0x3010020;
-		MCHBAR32(0x14c8) = 0x7090220;
-		MCHBAR32(0x14cc) = 0x1081310;
-		MCHBAR32(0x14d0) = 0x1081420;
-		MCHBAR32(0x14d4) = 0x7090220;
-		MCHBAR32(0x14d8) = 0x1010001;
-		MCHBAR32(0x14dc) = 0x1110000;
-		MCHBAR32(0x14e0) = 0xb040020;
-		MCHBAR32(0x14e4) = 0x2030220;
-		MCHBAR32(0x14e8) = 0x1051310;
-		MCHBAR32(0x14ec) = 0x1051420;
-		MCHBAR32(0x14f0) = 0x2030220;
-		MCHBAR32(0x14f4) = 0x1010001;
-		MCHBAR32(0x14f8) = 0x1110000;
-		MCHBAR32(0x14fc) = 0x5020020;
-		MCHBAR32(0x1500) = 0x5090220;
-		MCHBAR32(0x1504) = 0x2071310;
-		MCHBAR32(0x1508) = 0x2071420;
-		MCHBAR32(0x150c) = 0x5090220;
-		MCHBAR32(0x1510) = 0x1010001;
-		MCHBAR32(0x1514) = 0x1110000;
-		MCHBAR32(0x1518) = 0x7040120;
-		MCHBAR32(0x151c) = 0x2090220;
-		MCHBAR32(0x1520) = 0x70b1210;
-		MCHBAR32(0x1524) = 0x70b1310;
-		MCHBAR32(0x1528) = 0x2090220;
-		MCHBAR32(0x152c) = 0x1010001;
-		MCHBAR32(0x1530) = 0x1110000;
-		MCHBAR32(0x1534) = 0x1010110;
-		MCHBAR32(0x1538) = 0x1081310;
-		MCHBAR32(0x153c) = 0x5041200;
-		MCHBAR32(0x1540) = 0x5041310;
-		MCHBAR32(0x1544) = 0x1081310;
-		MCHBAR32(0x1548) = 0x1010001;
-		MCHBAR32(0x154c) = 0x1110000;
-		MCHBAR32(0x1550) = 0x1040120;
-		MCHBAR32(0x1554) = 0x4051210;
-		MCHBAR32(0x1558) = 0xd051200;
-		MCHBAR32(0x155c) = 0xd051200;
-		MCHBAR32(0x1560) = 0x4051210;
-		MCHBAR32(0x1564) = 0x1010001;
-		MCHBAR32(0x1568) = 0x1110000;
-		MCHBAR16(0x1222) = 0x220a;
-		MCHBAR16(0x123c) = 0x1fc0;
-		MCHBAR16(0x1220) = 0x1388;
-	}
+	if (x2ca8 == 0)
+		late_quickpath_init(&info, s3resume);
 
 	MCHBAR32_OR(0x2c80, (1 << 24));
 	MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27);
@@ -4214,6 +3480,7 @@
 		MCHBAR32_OR(0x1af0, 0x10);
 		halt();
 	}
+
 	MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);	// !!!!
 
 	MCHBAR32_AND(0x2c80, ~(1 << 24));
diff --git a/src/northbridge/intel/ironlake/raminit.h b/src/northbridge/intel/ironlake/raminit.h
index 5bb2f59..9967e15 100644
--- a/src/northbridge/intel/ironlake/raminit.h
+++ b/src/northbridge/intel/ironlake/raminit.h
@@ -5,6 +5,93 @@
 
 #include "ironlake.h"
 
+#define NUM_CHANNELS	2
+#define NUM_SLOTS	2
+#define NUM_RANKS	2
+
+/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
+typedef struct {
+	u8 smallest;
+	u8 largest;
+} timing_bounds_t[2][2][2][9];
+
+#define MRC_CACHE_VERSION 3
+
+struct ram_training {
+	/* [TM][CHANNEL][SLOT][RANK][LANE] */
+	u16 lane_timings[4][2][2][2][9];
+	u16 reg_178;
+	u16 reg_10b;
+
+	u8 reg178_center;
+	u8 reg178_smallest;
+	u8 reg178_largest;
+	timing_bounds_t timing_bounds[2];
+	u16 timing_offset[2][2][2][9];
+	u16 timing2_offset[2][2][2][9];
+	u16 timing2_bounds[2][2][2][9][2];
+	u8 reg274265[2][3];	/* [CHANNEL][REGISTER] */
+	u8 reg2ca9_bit0;
+	u32 reg_6dc;
+	u32 reg_6e8;
+};
+
+struct raminfo {
+	u16 clock_speed_index;	/* clock_speed (REAL, not DDR) / 133.(3) - 3 */
+	u16 fsb_frequency;	/* in 1.(1)/2 MHz.  */
+	u8 is_x16_module[2][2];	/* [CHANNEL][SLOT] */
+	u8 density[2][2];	/* [CHANNEL][SLOT] */
+	u8 populated_ranks[2][2][2];	/* [CHANNEL][SLOT][RANK] */
+	int rank_start[2][2][2];
+	u8 cas_latency;
+	u8 board_lane_delay[9];
+	u8 use_ecc;
+	u8 revision;
+	u8 max_supported_clock_speed_index;
+	u8 uma_enabled;
+	u8 spd[2][2][151];	/* [CHANNEL][SLOT][BYTE]  */
+	u8 silicon_revision;
+	u8 populated_ranks_mask[2];
+	u8 max_slots_used_in_channel;
+	u8 mode4030[2];
+	u16 avg4044[2];
+	u16 max4048[2];
+	unsigned int total_memory_mb;
+	unsigned int interleaved_part_mb;
+	unsigned int non_interleaved_part_mb;
+
+	unsigned int memory_reserved_for_heci_mb;
+
+	struct ram_training training;
+	u32 last_500_command[2];
+
+	u32 delay46_ps[2];
+	u32 delay54_ps[2];
+	u8 revision_flag_1;
+	u8 some_delay_1_cycle_floor;
+	u8 some_delay_2_halfcycles_ceil;
+	u8 some_delay_3_ps_rounded;
+
+	const struct ram_training *cached_training;
+};
+
+static inline unsigned int fsbcycle_ps(struct raminfo *info)
+{
+	return 900000 / info->fsb_frequency;
+}
+
+/* The time of DDR transfer in ps.  */
+static inline unsigned int halfcycle_ps(struct raminfo *info)
+{
+	return 3750 / (info->clock_speed_index + 3);
+}
+
+/* Frequency in 1.(1)=10/9 MHz units. */
+static inline unsigned int frequency_11(struct raminfo *info)
+{
+	return (info->clock_speed_index + 3) * 120;
+}
+
 void chipset_init(const int s3resume);
 /* spd_addrmap is array of 4 elements:
    Channel 0 Slot 0
@@ -15,4 +102,7 @@
 */
 void raminit(const int s3resume, const u8 *spd_addrmap);
 
+u16 get_max_timing(struct raminfo *info, int channel);
+void late_quickpath_init(struct raminfo *info, const int s3resume);
+
 #endif				/* RAMINIT_H */