summaryrefslogtreecommitdiff
path: root/resources/coreboot/haswell/patches/0025-haswell-NRI-Add-final-raminit-steps.patch
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2023-03-18 00:36:27 +0000
committerLeah Rowe <leah@libreboot.org>2023-03-18 00:55:10 +0000
commit548872ce8e84fe10d52417acab9b3cf886821386 (patch)
treeb549ad51c9c693a323f0f8edc9a11eab92220013 /resources/coreboot/haswell/patches/0025-haswell-NRI-Add-final-raminit-steps.patch
parenta942bd6590dd450140fc0af8549ca470a065adf5 (diff)
haswell boards: use libre mrc.bin replacement
courtesy of Angel Pons from the coreboot project this uses the following patch set from gerrit, as yet unmerged (in coreboot master) on this date: https://review.coreboot.org/c/coreboot/+/64198/5 logic for downloading mrc blobs has been deleted from lbmk, as this is now completely obsolete (for haswell boards) if other platforms are added later that need mrc.bin, then logic will be re-added again for that
Diffstat (limited to 'resources/coreboot/haswell/patches/0025-haswell-NRI-Add-final-raminit-steps.patch')
-rw-r--r--resources/coreboot/haswell/patches/0025-haswell-NRI-Add-final-raminit-steps.patch570
1 files changed, 570 insertions, 0 deletions
diff --git a/resources/coreboot/haswell/patches/0025-haswell-NRI-Add-final-raminit-steps.patch b/resources/coreboot/haswell/patches/0025-haswell-NRI-Add-final-raminit-steps.patch
new file mode 100644
index 00000000..d15ea5d1
--- /dev/null
+++ b/resources/coreboot/haswell/patches/0025-haswell-NRI-Add-final-raminit-steps.patch
@@ -0,0 +1,570 @@
+From d041b14f3af69db5f4598c84e3f53c9cd572ffb5 Mon Sep 17 00:00:00 2001
+From: Angel Pons <th3fanbus@gmail.com>
+Date: Sun, 8 May 2022 14:29:05 +0200
+Subject: [PATCH 25/26] 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.inc | 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 b659bf6d98..61f2a3c64c 100644
+--- a/src/northbridge/intel/haswell/Kconfig
++++ b/src/northbridge/intel/haswell/Kconfig
+@@ -10,12 +10,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.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
+index 40c2f5e014..d97da72890 100644
+--- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc
++++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
+@@ -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 bd9bc8e692..1ea729b23d 100644
+--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
++++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
+@@ -200,8 +200,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);
+ }
+
+@@ -217,7 +215,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 666b233c45..98e39cb76e 100644
+--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h
++++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
+@@ -449,6 +449,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
+