summaryrefslogtreecommitdiff
path: root/config/coreboot/haswell/patches/0015-haswell-NRI-Add-final-raminit-steps.patch
blob: 3626bf6dccc75d564718b1e8fe773e18efb75f98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
From eba8680d618db95028e3f984f25881df0e67abf7 Mon Sep 17 00:00:00 2001
From: Angel Pons <th3fanbus@gmail.com>
Date: Sun, 8 May 2022 14:29:05 +0200
Subject: [PATCH 15/20] haswell NRI: Add final raminit steps

Implement the remaining raminit steps. Although many training steps are
missing, this is enough to boot on the Asrock B85M Pro4.

Change-Id: I94f3b65f0218d4da4fda4d84592dfd91f77f8f21
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
---
 src/northbridge/intel/haswell/Kconfig         |   4 +-
 .../intel/haswell/native_raminit/Makefile.mk  |   1 +
 .../haswell/native_raminit/activate_mc.c      | 388 ++++++++++++++++++
 .../haswell/native_raminit/raminit_main.c     |   5 +-
 .../haswell/native_raminit/raminit_native.c   |   5 +-
 .../haswell/native_raminit/raminit_native.h   |   2 +
 .../haswell/native_raminit/reg_structs.h      |  12 +
 .../intel/haswell/registers/mchbar.h          |   7 +
 8 files changed, 416 insertions(+), 8 deletions(-)
 create mode 100644 src/northbridge/intel/haswell/native_raminit/activate_mc.c

diff --git a/src/northbridge/intel/haswell/Kconfig b/src/northbridge/intel/haswell/Kconfig
index 4b83a25bc1..c6ab27184e 100644
--- a/src/northbridge/intel/haswell/Kconfig
+++ b/src/northbridge/intel/haswell/Kconfig
@@ -11,12 +11,12 @@ config NORTHBRIDGE_INTEL_HASWELL
 if NORTHBRIDGE_INTEL_HASWELL
 
 config USE_NATIVE_RAMINIT
-	bool "[NOT WORKING] Use native raminit"
+	bool "[NOT COMPLETE] Use native raminit"
 	default n
 	select HAVE_DEBUG_RAM_SETUP
 	help
 	  Select if you want to use coreboot implementation of raminit rather than
-	  MRC.bin. Currently incomplete and does not boot.
+	  MRC.bin. Currently incomplete and does not support S3 resume.
 
 config HASWELL_VBOOT_IN_BOOTBLOCK
 	depends on VBOOT
diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.mk b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
index 40c2f5e014..d97da72890 100644
--- a/src/northbridge/intel/haswell/native_raminit/Makefile.mk
+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.mk
@@ -1,5 +1,6 @@
 ## SPDX-License-Identifier: GPL-2.0-or-later
 
+romstage-y += activate_mc.c
 romstage-y += change_margin.c
 romstage-y += configure_mc.c
 romstage-y += ddr3.c
diff --git a/src/northbridge/intel/haswell/native_raminit/activate_mc.c b/src/northbridge/intel/haswell/native_raminit/activate_mc.c
new file mode 100644
index 0000000000..78a7ad27ef
--- /dev/null
+++ b/src/northbridge/intel/haswell/native_raminit/activate_mc.c
@@ -0,0 +1,388 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <console/console.h>
+#include <delay.h>
+#include <device/pci_ops.h>
+#include <northbridge/intel/haswell/haswell.h>
+#include <timer.h>
+#include <types.h>
+
+#include "raminit_native.h"
+
+static void update_internal_clocks_on(struct sysinfo *ctrl)
+{
+	for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+		if (!does_ch_exist(ctrl, channel))
+			continue;
+
+		bool clocks_on = false;
+		for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
+			const union ddr_data_control_1_reg data_control_1 = {
+				.raw = ctrl->dq_control_1[channel][byte],
+			};
+			const int8_t o_on = data_control_1.odt_delay;
+			const int8_t s_on = data_control_1.sense_amp_delay;
+			const int8_t o_off = data_control_1.odt_duration;
+			const int8_t s_off = data_control_1.sense_amp_duration;
+			if (o_on + o_off >= 7 || s_on + s_off >= 7) {
+				clocks_on = true;
+				break;
+			}
+		}
+		union ddr_data_control_0_reg data_control_0 = {
+			.raw = ctrl->dq_control_0[channel],
+		};
+		data_control_0.internal_clocks_on = clocks_on;
+		ctrl->dq_control_0[channel] = data_control_0.raw;
+		mchbar_write32(DDR_DATA_ch_CONTROL_0(channel), data_control_0.raw);
+	}
+}
+
+/* Switch off unused segments of the SDLL to save power */
+static void update_sdll_length(struct sysinfo *ctrl)
+{
+	for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+		if (!does_ch_exist(ctrl, channel))
+			continue;
+
+		for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
+			uint8_t max_pi = 0;
+			for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
+				if (!rank_in_ch(ctrl, rank, channel))
+					continue;
+
+				const uint8_t rx_dqs_p = ctrl->rxdqsp[channel][rank][byte];
+				const uint8_t rx_dqs_n = ctrl->rxdqsn[channel][rank][byte];
+				max_pi = MAX(max_pi, MAX(rx_dqs_p, rx_dqs_n));
+			}
+			/* Update SDLL length for power savings */
+			union ddr_data_control_1_reg data_control_1 = {
+				.raw = ctrl->dq_control_1[channel][byte],
+			};
+			/* Calculate which segments to turn off */
+			data_control_1.sdll_segment_disable = (7 - (max_pi >> 3)) & ~1;
+			ctrl->dq_control_1[channel][byte] = data_control_1.raw;
+			mchbar_write32(DQ_CONTROL_1(channel, byte), data_control_1.raw);
+		}
+	}
+}
+
+static void set_rx_clk_stg_num(struct sysinfo *ctrl, const uint8_t channel)
+{
+	const uint8_t rcven_drift = ctrl->lpddr ? DIV_ROUND_UP(tDQSCK_DRIFT, ctrl->qclkps) : 1;
+	uint8_t max_rcven = 0;
+	for (uint8_t rank = 0; rank < NUM_SLOTRANKS; rank++) {
+		if (!rank_in_ch(ctrl, rank, channel))
+			continue;
+
+		for (uint8_t byte = 0; byte < ctrl->lanes; byte++)
+			max_rcven = MAX(max_rcven, ctrl->rcven[channel][rank][byte] / 64);
+	}
+	const union ddr_data_control_1_reg ddr_data_control_1 = {
+		.raw = ctrl->dq_control_1[channel][0],
+	};
+	const bool lpddr_long_odt = ddr_data_control_1.lpddr_long_odt_en;
+	const uint8_t rcven_turnoff = max_rcven + 18 + 2 * rcven_drift + lpddr_long_odt;
+	const union ddr_data_control_0_reg ddr_data_control_0 = {
+		.raw = ctrl->dq_control_0[channel],
+	};
+	for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
+		union ddr_data_control_2_reg ddr_data_control_2 = {
+			.raw = ctrl->dq_control_2[channel][byte],
+		};
+		if (ddr_data_control_0.odt_samp_extend_en) {
+			if (ddr_data_control_2.rx_clk_stg_num < rcven_turnoff)
+				ddr_data_control_2.rx_clk_stg_num = rcven_turnoff;
+		} else {
+			const int8_t o_on = ddr_data_control_1.odt_delay;
+			const int8_t o_off = ddr_data_control_1.odt_duration;
+			ddr_data_control_2.rx_clk_stg_num = MAX(17, o_on + o_off + 14);
+		}
+		ctrl->dq_control_2[channel][byte] = ddr_data_control_2.raw;
+		mchbar_write32(DQ_CONTROL_2(channel, byte), ddr_data_control_2.raw);
+	}
+}
+
+#define SELF_REFRESH_IDLE_COUNT 0x200
+
+static void enter_sr(void)
+{
+	mchbar_write32(PM_SREF_CONFIG, SELF_REFRESH_IDLE_COUNT | BIT(16));
+	udelay(1);
+}
+
+enum power_down_mode {
+	PDM_NO_PD	= 0,
+	PDM_APD		= 1,
+	PDM_PPD		= 2,
+	PDM_PPD_DLL_OFF	= 6,
+};
+
+static void power_down_config(struct sysinfo *ctrl)
+{
+	const enum power_down_mode pd_mode = ctrl->lpddr ? PDM_PPD : PDM_PPD_DLL_OFF;
+	mchbar_write32(PM_PDWN_CONFIG, pd_mode << 12 | 0x40);
+}
+
+static void train_power_modes_post(struct sysinfo *ctrl)
+{
+	for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+		if (!does_ch_exist(ctrl, channel))
+			continue;
+
+		/* Adjust tCPDED and tPRPDEN */
+		if (ctrl->mem_clock_mhz >= 933)
+			ctrl->tc_bankrank_d[channel].tCPDED = 2;
+
+		if (ctrl->mem_clock_mhz >= 1066)
+			ctrl->tc_bankrank_d[channel].tPRPDEN = 2;
+
+		mchbar_write32(TC_BANK_RANK_D_ch(channel), ctrl->tc_bankrank_d[channel].raw);
+	}
+	power_down_config(ctrl);
+	mchbar_write32(MCDECS_CBIT, BIT(30));	/* dis_msg_clk_gate */
+}
+
+static uint8_t compute_burst_end_odt_delay(const struct sysinfo *const ctrl)
+{
+	/* Must be disabled for LPDDR */
+	if (ctrl->lpddr)
+		return 0;
+
+	const uint8_t beod = MIN(7, DIV_ROUND_CLOSEST(14300 * 20 / 100, ctrl->qclkps));
+	if (beod < 3)
+		return 0;
+
+	if (beod < 4)
+		return 4;
+
+	return beod;
+}
+
+static void program_burst_end_odt_delay(struct sysinfo *ctrl)
+{
+	/* Program burst_end_odt_delay - it should be zero during training steps */
+	const uint8_t beod = compute_burst_end_odt_delay(ctrl);
+	for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+		if (!does_ch_exist(ctrl, channel))
+			continue;
+
+		for (uint8_t byte = 0; byte < ctrl->lanes; byte++) {
+			union ddr_data_control_1_reg ddr_data_control_1 = {
+				.raw = ctrl->dq_control_1[channel][byte],
+			};
+			ddr_data_control_1.burst_end_odt_delay = beod;
+			ctrl->dq_control_1[channel][byte] = ddr_data_control_1.raw;
+			mchbar_write32(DQ_CONTROL_1(channel, byte), ddr_data_control_1.raw);
+		}
+	}
+}
+
+/*
+ * Return a random value to use for scrambler seeds. Try to use RDRAND
+ * first and fall back to hardcoded values if RDRAND does not succeed.
+ */
+static uint16_t get_random_number(const uint8_t channel)
+{
+	/* The RDRAND instruction is only available 100k cycles after reset */
+	for (size_t i = 0; i < 100000; i++) {
+		uint32_t status;
+		uint32_t random;
+		/** TODO: Clean up asm **/
+		__asm__ __volatile__(
+			"\n\t .byte 0x0F, 0xC7, 0xF0"
+			"\n\t movl %%eax, %0"
+			"\n\t pushf"
+			"\n\t pop %%eax"
+			"\n\t movl %%eax, %1"
+			: "=m"(random),
+			  "=m"(status)
+			: /* No inputs */
+			: "eax", "cc");
+
+		/* Only consider non-zero random values as valid */
+		if (status & 1 && random)
+			return random;
+	}
+
+	/* https://xkcd.com/221 */
+	if (channel)
+		return 0x28f4;
+	else
+		return 0x893e;
+}
+
+/* Work around "error: 'typeof' applied to a bit-field" */
+static inline uint32_t max(const uint32_t a, const uint32_t b)
+{
+	return MAX(a, b);
+}
+
+enum raminit_status activate_mc(struct sysinfo *ctrl)
+{
+	const bool enable_scrambling = true;
+	const bool enable_cmd_tristate = true;
+	for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+		if (!does_ch_exist(ctrl, channel))
+			continue;
+
+		if (enable_scrambling && ctrl->stepping < STEPPING_C0) {
+			/* Make sure tRDRD_(sr, dr, dd) are at least 6 for scrambler W/A */
+			union tc_bank_rank_a_reg tc_bank_rank_a = {
+				.raw = mchbar_read32(TC_BANK_RANK_A_ch(channel)),
+			};
+			tc_bank_rank_a.tRDRD_sr = max(tc_bank_rank_a.tRDRD_sr, 6);
+			tc_bank_rank_a.tRDRD_dr = max(tc_bank_rank_a.tRDRD_dr, 6);
+			tc_bank_rank_a.tRDRD_dd = max(tc_bank_rank_a.tRDRD_dd, 6);
+			mchbar_write32(TC_BANK_RANK_A_ch(channel), tc_bank_rank_a.raw);
+		}
+		if (enable_scrambling) {
+			const union ddr_scramble_reg ddr_scramble = {
+				.scram_key = get_random_number(channel),
+				.scram_en  = 1,
+			};
+			mchbar_write32(DDR_SCRAMBLE_ch(channel), ddr_scramble.raw);
+		}
+		if (ctrl->tCMD == 1) {
+			/* If we are in 1N mode, enable and set command rate limit to 3 */
+			union mcmain_command_rate_limit_reg cmd_rate_limit = {
+				.raw = mchbar_read32(COMMAND_RATE_LIMIT_ch(channel)),
+			};
+			cmd_rate_limit.enable_cmd_limit = 1;
+			cmd_rate_limit.cmd_rate_limit   = 3;
+			mchbar_write32(COMMAND_RATE_LIMIT_ch(channel), cmd_rate_limit.raw);
+		}
+		if (enable_cmd_tristate) {
+			/* Enable command tri-state at the end of training */
+			union tc_bank_rank_a_reg tc_bank_rank_a = {
+				.raw = mchbar_read32(TC_BANK_RANK_A_ch(channel)),
+			};
+			tc_bank_rank_a.cmd_3st_dis = 0;
+			mchbar_write32(TC_BANK_RANK_A_ch(channel), tc_bank_rank_a.raw);
+		}
+		/* Set MC to normal mode and clean the ODT and CKE */
+		mchbar_write32(REUT_ch_SEQ_CFG(channel), REUT_MODE_NOP << 12);
+		/* Set again the rank occupancy */
+		mchbar_write8(MC_INIT_STATE_ch(channel), ctrl->rankmap[channel]);
+		if (ctrl->is_ecc) {
+			/* Enable ECC I/O and logic */
+			union mad_dimm_reg mad_dimm = {
+				.raw = mchbar_read32(MAD_DIMM(channel)),
+			};
+			mad_dimm.ecc_mode = 3;
+			mchbar_write32(MAD_DIMM(channel), mad_dimm.raw);
+		}
+	}
+
+	if (!is_hsw_ult())
+		update_internal_clocks_on(ctrl);
+
+	update_sdll_length(ctrl);
+
+	program_burst_end_odt_delay(ctrl);
+
+	if (is_hsw_ult()) {
+		for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+			if (!does_ch_exist(ctrl, channel))
+				continue;
+
+			set_rx_clk_stg_num(ctrl, channel);
+		}
+		/** TODO: Program DDRPL_CR_DDR_TX_DELAY if Memory Trace is enabled **/
+	}
+
+	/* Enable periodic COMP */
+	mchbar_write32(M_COMP, (union pcu_comp_reg) {
+		.comp_interval = COMP_INT,
+	}.raw);
+
+	/* Enable the power mode before PCU starts working */
+	train_power_modes_post(ctrl);
+
+	/* Set idle timer and self refresh enable bits */
+	enter_sr();
+
+	/** FIXME: Do not hardcode power weights and RAPL settings **/
+	mchbar_write32(0x5888, 0x00000d0d);
+	mchbar_write32(0x5884, 0x00000004);	/* 58.2 pJ */
+
+	mchbar_write32(0x58e0, 0);
+	mchbar_write32(0x58e4, 0);
+
+	mchbar_write32(0x5890, 0xffff);
+	mchbar_write32(0x5894, 0xffff);
+	mchbar_write32(0x5898, 0xffff);
+	mchbar_write32(0x589c, 0xffff);
+	mchbar_write32(0x58d0, 0xffff);
+	mchbar_write32(0x58d4, 0xffff);
+	mchbar_write32(0x58d8, 0xffff);
+	mchbar_write32(0x58dc, 0xffff);
+
+	/* Overwrite thermal parameters */
+	for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+		mchbar_write32(_MCMAIN_C(0x42ec, channel), 0x0000000f);
+		mchbar_write32(_MCMAIN_C(0x42f0, channel), 0x00000009);
+		mchbar_write32(_MCMAIN_C(0x42f4, channel), 0x00000093);
+		mchbar_write32(_MCMAIN_C(0x42f8, channel), 0x00000087);
+		mchbar_write32(_MCMAIN_C(0x42fc, channel), 0x000000de);
+
+		/** TODO: Differs for LPDDR **/
+		mchbar_write32(PM_THRT_CKE_MIN_ch(channel), 0x30);
+	}
+	mchbar_write32(PCU_DDR_PTM_CTL, 0x40);
+	return RAMINIT_STATUS_SUCCESS;
+}
+
+static void mc_lockdown(void)
+{
+	/* Lock memory controller registers */
+	mchbar_write32(MC_LOCK, 0x8f);
+
+	/* MPCOHTRK_GDXC_OCLA_ADDRESS_HI_LOCK is set when programming the memory map */
+
+	/* Lock memory map registers */
+	pci_or_config16(HOST_BRIDGE, GGC,         1 <<  0);
+	pci_or_config32(HOST_BRIDGE, DPR,         1 <<  0);
+	pci_or_config32(HOST_BRIDGE, MESEG_LIMIT, 1 << 10);
+	pci_or_config32(HOST_BRIDGE, REMAPBASE,   1 <<  0);
+	pci_or_config32(HOST_BRIDGE, REMAPLIMIT,  1 <<  0);
+	pci_or_config32(HOST_BRIDGE, TOM,         1 <<  0);
+	pci_or_config32(HOST_BRIDGE, TOUUD,       1 <<  0);
+	pci_or_config32(HOST_BRIDGE, BDSM,        1 <<  0);
+	pci_or_config32(HOST_BRIDGE, BGSM,        1 <<  0);
+	pci_or_config32(HOST_BRIDGE, TOLUD,       1 <<  0);
+}
+
+enum raminit_status raminit_done(struct sysinfo *ctrl)
+{
+	union mc_init_state_g_reg mc_init_state_g = {
+		.raw = mchbar_read32(MC_INIT_STATE_G),
+	};
+	mc_init_state_g.refresh_enable = 1;
+	mc_init_state_g.pu_mrc_done    = 1;
+	mc_init_state_g.mrc_done       = 1;
+	mchbar_write32(MC_INIT_STATE_G, mc_init_state_g.raw);
+
+	/* Lock the memory controller to enable normal operation */
+	mc_lockdown();
+
+	/* Poll for mc_init_done_ack to make sure memory initialization is complete */
+	printk(BIOS_DEBUG, "Waiting for mc_init_done acknowledgement... ");
+
+	struct stopwatch timer;
+	stopwatch_init_msecs_expire(&timer, 2000);
+	do {
+		mc_init_state_g.raw = mchbar_read32(MC_INIT_STATE_G);
+
+		/* DRAM will NOT work without the acknowledgement. There is no hope. */
+		if (stopwatch_expired(&timer))
+			die("\nTimed out waiting for mc_init_done acknowledgement\n");
+
+	} while (mc_init_state_g.mc_init_done_ack == 0);
+	printk(BIOS_DEBUG, "DONE!\n");
+
+	/* Provide some data for the graphics driver. Yes, it's hardcoded. */
+	mchbar_write32(SSKPD + 0, 0x05a2404f);
+	mchbar_write32(SSKPD + 4, 0x140000a0);
+	return RAMINIT_STATUS_SUCCESS;
+}
diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
index 1ff23be615..3a65fb01fb 100644
--- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c
+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
@@ -63,6 +63,8 @@ static const struct task_entry cold_boot[] = {
 	{ train_receive_enable,                                   true, "RCVET",      },
 	{ train_read_mpr,                                         true, "RDMPRT",     },
 	{ train_jedec_write_leveling,                             true, "JWRL",       },
+	{ activate_mc,                                            true, "ACTIVATE",   },
+	{ raminit_done,                                           true, "RAMINITEND", },
 };
 
 /* Return a generic stepping value to make stepping checks simpler */
@@ -143,7 +145,4 @@ void raminit_main(const enum raminit_boot_mode bootmode)
 
 	if (status != RAMINIT_STATUS_SUCCESS)
 		die("Memory initialization was met with utmost failure and misery\n");
-
-	/** TODO: Implement the required magic **/
-	die("NATIVE RAMINIT: More Magic (tm) required.\n");
 }
diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
index 2fed93de5b..5f7ceec222 100644
--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
@@ -199,8 +199,6 @@ void perform_raminit(const int s3resume)
 		else
 			me_status = ME_INIT_STATUS_SUCCESS;
 
-		/** TODO: Remove this once raminit is implemented **/
-		me_status = ME_INIT_STATUS_ERROR;
 		intel_early_me_init_done(me_status);
 	}
 
@@ -214,7 +212,8 @@ void perform_raminit(const int s3resume)
 	}
 
 	/* Save training data on non-S3 resumes */
-	if (!s3resume)
+	/** TODO: Enable this once training data is populated **/
+	if (0 && !s3resume)
 		save_mrc_data(&md);
 
 	/** TODO: setup_sdram_meminfo **/
diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
index 86d89f2120..9bab57b518 100644
--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
@@ -447,6 +447,8 @@ enum raminit_status do_jedec_init(struct sysinfo *ctrl);
 enum raminit_status train_receive_enable(struct sysinfo *ctrl);
 enum raminit_status train_read_mpr(struct sysinfo *ctrl);
 enum raminit_status train_jedec_write_leveling(struct sysinfo *ctrl);
+enum raminit_status activate_mc(struct sysinfo *ctrl);
+enum raminit_status raminit_done(struct sysinfo *ctrl);
 
 void configure_timings(struct sysinfo *ctrl);
 void configure_refresh(struct sysinfo *ctrl);
diff --git a/src/northbridge/intel/haswell/native_raminit/reg_structs.h b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
index a0e36ed082..0d9aaa1f7c 100644
--- a/src/northbridge/intel/haswell/native_raminit/reg_structs.h
+++ b/src/northbridge/intel/haswell/native_raminit/reg_structs.h
@@ -294,6 +294,18 @@ union ddr_cke_ctl_controls_reg {
 	uint32_t raw;
 };
 
+union ddr_scramble_reg {
+	struct __packed {
+		uint32_t scram_en    :  1; // Bits  0:0
+		uint32_t scram_key   : 16; // Bits 16:1
+		uint32_t clk_gate_ab :  2; // Bits 18:17
+		uint32_t clk_gate_c  :  2; // Bits 20:19
+		uint32_t en_dbi_ab   :  1; // Bits 21:21
+		uint32_t             : 10; // Bits 31:17
+	};
+	uint32_t raw;
+};
+
 union ddr_scram_misc_control_reg {
 	struct __packed {
 		uint32_t wl_wake_cycles       :  2; // Bits  1:0
diff --git a/src/northbridge/intel/haswell/registers/mchbar.h b/src/northbridge/intel/haswell/registers/mchbar.h
index 7c0b5a49de..49a215aa71 100644
--- a/src/northbridge/intel/haswell/registers/mchbar.h
+++ b/src/northbridge/intel/haswell/registers/mchbar.h
@@ -20,6 +20,7 @@
 
 #define DDR_DATA_TRAIN_FEEDBACK(ch, byte)	_DDRIO_C_R_B(0x0054, ch, 0, byte)
 
+#define DQ_CONTROL_1(ch, byte)			_DDRIO_C_R_B(0x0060, ch, 0, byte)
 #define DQ_CONTROL_2(ch, byte)			_DDRIO_C_R_B(0x0064, ch, 0, byte)
 #define DDR_DATA_OFFSET_TRAIN_ch_b(ch, byte)	_DDRIO_C_R_B(0x0070, ch, 0, byte)
 #define DQ_CONTROL_0(ch, byte)			_DDRIO_C_R_B(0x0074, ch, 0, byte)
@@ -147,6 +148,8 @@
 #define QCLK_ch_LDAT_SDAT(ch)			_MCMAIN_C(0x42d4, ch)
 #define QCLK_ch_LDAT_DATA_IN_x(ch, x)		_MCMAIN_C_X(0x42dc, ch, x) /* x in 0 .. 1 */
 
+#define PM_THRT_CKE_MIN_ch(ch)			_MCMAIN_C(0x4328, ch)
+
 #define REUT_GLOBAL_CTL				0x4800
 #define REUT_GLOBAL_ERR				0x4804
 
@@ -175,6 +178,8 @@
 
 #define MCSCHEDS_DFT_MISC	0x4c30
 
+#define PM_PDWN_CONFIG		0x4cb0
+
 #define REUT_ERR_DATA_STATUS	0x4ce0
 
 #define REUT_MISC_CKE_CTRL	0x4d90
@@ -186,8 +191,10 @@
 #define MAD_CHNL		0x5000 /* Address Decoder Channel Configuration */
 #define MAD_DIMM(ch)		(0x5004 + (ch) * 4)
 #define MAD_ZR			0x5014
+#define MCDECS_CBIT		0x501c
 #define MC_INIT_STATE_G		0x5030
 #define MRC_REVISION		0x5034 /* MRC Revision */
+#define PM_SREF_CONFIG		0x5060
 
 #define RCOMP_TIMER		0x5084
 
-- 
2.39.2