diff options
Diffstat (limited to 'config/coreboot/haswell/patches/0008-nb-intel-haswell-Add-native-raminit-scaffolding.patch')
-rw-r--r-- | config/coreboot/haswell/patches/0008-nb-intel-haswell-Add-native-raminit-scaffolding.patch | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/config/coreboot/haswell/patches/0008-nb-intel-haswell-Add-native-raminit-scaffolding.patch b/config/coreboot/haswell/patches/0008-nb-intel-haswell-Add-native-raminit-scaffolding.patch new file mode 100644 index 00000000..6df828eb --- /dev/null +++ b/config/coreboot/haswell/patches/0008-nb-intel-haswell-Add-native-raminit-scaffolding.patch @@ -0,0 +1,407 @@ +From 46cdec8cbce15ca11ad9a49a3ee415a78f781997 Mon Sep 17 00:00:00 2001 +From: Angel Pons <th3fanbus@gmail.com> +Date: Sat, 7 May 2022 00:26:10 +0200 +Subject: [PATCH 08/26] nb/intel/haswell: Add native raminit scaffolding + +Implement some scaffolding for Haswell native raminit, like bootmode +selection, handling of MRC cache and CPU detection. + +Change-Id: Icd96649fa045ea7f0f32ae9bfe1e60498d93975b +Signed-off-by: Angel Pons <th3fanbus@gmail.com> +--- + .../intel/haswell/native_raminit/Makefile.inc | 1 + + .../haswell/native_raminit/raminit_main.c | 104 ++++++++++ + .../haswell/native_raminit/raminit_native.c | 189 +++++++++++++++++- + .../haswell/native_raminit/raminit_native.h | 34 ++++ + 4 files changed, 322 insertions(+), 6 deletions(-) + create mode 100644 src/northbridge/intel/haswell/native_raminit/raminit_main.c + create mode 100644 src/northbridge/intel/haswell/native_raminit/raminit_native.h + +diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc +index 8cfb4fb33e..90af951c5a 100644 +--- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc ++++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc +@@ -1,3 +1,4 @@ + ## SPDX-License-Identifier: GPL-2.0-or-later + ++romstage-y += raminit_main.c + romstage-y += raminit_native.c +diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c +new file mode 100644 +index 0000000000..9b42c25b40 +--- /dev/null ++++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c +@@ -0,0 +1,104 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#include <assert.h> ++#include <console/console.h> ++#include <cpu/intel/haswell/haswell.h> ++#include <delay.h> ++#include <device/pci_ops.h> ++#include <northbridge/intel/haswell/chip.h> ++#include <northbridge/intel/haswell/haswell.h> ++#include <northbridge/intel/haswell/raminit.h> ++#include <string.h> ++#include <types.h> ++ ++#include "raminit_native.h" ++ ++struct task_entry { ++ enum raminit_status (*task)(struct sysinfo *); ++ bool is_enabled; ++ const char *name; ++}; ++ ++static const struct task_entry cold_boot[] = { ++}; ++ ++/* Return a generic stepping value to make stepping checks simpler */ ++static enum generic_stepping get_stepping(const uint32_t cpuid) ++{ ++ switch (cpuid) { ++ case CPUID_HASWELL_A0: ++ die("Haswell stepping A0 is not supported\n"); ++ case CPUID_HASWELL_B0: ++ case CPUID_HASWELL_ULT_B0: ++ case CPUID_CRYSTALWELL_B0: ++ return STEPPING_B0; ++ case CPUID_HASWELL_C0: ++ case CPUID_HASWELL_ULT_C0: ++ case CPUID_CRYSTALWELL_C0: ++ return STEPPING_C0; ++ default: ++ /** TODO: Add Broadwell support someday **/ ++ die("Unknown CPUID 0x%x\n", cpuid); ++ } ++} ++ ++static void initialize_ctrl(struct sysinfo *ctrl) ++{ ++ const struct northbridge_intel_haswell_config *cfg = config_of_soc(); ++ const enum raminit_boot_mode bootmode = ctrl->bootmode; ++ ++ memset(ctrl, 0, sizeof(*ctrl)); ++ ++ ctrl->cpu = cpu_get_cpuid(); ++ ctrl->stepping = get_stepping(ctrl->cpu); ++ ctrl->dq_pins_interleaved = cfg->dq_pins_interleaved; ++ ctrl->bootmode = bootmode; ++} ++ ++static enum raminit_status try_raminit(struct sysinfo *ctrl) ++{ ++ const struct task_entry *const schedule = cold_boot; ++ const size_t length = ARRAY_SIZE(cold_boot); ++ ++ enum raminit_status status = RAMINIT_STATUS_UNSPECIFIED_ERROR; ++ ++ for (size_t i = 0; i < length; i++) { ++ const struct task_entry *const entry = &schedule[i]; ++ assert(entry); ++ assert(entry->name); ++ if (!entry->is_enabled) ++ continue; ++ ++ assert(entry->task); ++ printk(RAM_DEBUG, "\nExecuting raminit task %s\n", entry->name); ++ status = entry->task(ctrl); ++ printk(RAM_DEBUG, "\n"); ++ if (status) { ++ printk(BIOS_ERR, "raminit failed on step %s\n", entry->name); ++ break; ++ } ++ } ++ ++ return status; ++} ++ ++void raminit_main(const enum raminit_boot_mode bootmode) ++{ ++ /* ++ * The mighty_ctrl struct. Will happily nuke the pre-RAM stack ++ * if left unattended. Make it static and pass pointers to it. ++ */ ++ static struct sysinfo mighty_ctrl; ++ ++ mighty_ctrl.bootmode = bootmode; ++ initialize_ctrl(&mighty_ctrl); ++ ++ /** TODO: Try more than once **/ ++ enum raminit_status status = try_raminit(&mighty_ctrl); ++ ++ 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 b6efb6b40d..0869db3902 100644 +--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c ++++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c +@@ -1,13 +1,45 @@ + /* SPDX-License-Identifier: GPL-2.0-or-later */ + ++#include <arch/cpu.h> ++#include <assert.h> ++#include <cbmem.h> ++#include <cf9_reset.h> + #include <console/console.h> ++#include <cpu/x86/msr.h> + #include <delay.h> ++#include <device/pci_ops.h> ++#include <mrc_cache.h> + #include <northbridge/intel/haswell/haswell.h> + #include <northbridge/intel/haswell/raminit.h> + #include <southbridge/intel/lynxpoint/me.h> + #include <southbridge/intel/lynxpoint/pch.h> + #include <types.h> + ++#include "raminit_native.h" ++ ++static void wait_txt_clear(void) ++{ ++ const struct cpuid_result cpuid = cpuid_ext(1, 0); ++ ++ /* Check if TXT is supported */ ++ if (!(cpuid.ecx & BIT(6))) ++ return; ++ ++ /* Some TXT public bit */ ++ if (!(read32p(0xfed30010) & 1)) ++ return; ++ ++ /* Wait for TXT clear */ ++ do {} while (!(read8p(0xfed40000) & (1 << 7))); ++} ++ ++static enum raminit_boot_mode get_boot_mode(void) ++{ ++ const uint16_t pmcon_2 = pci_read_config16(PCH_LPC_DEV, GEN_PMCON_2); ++ const uint16_t bitmask = GEN_PMCON_2_DISB | GEN_PMCON_2_MEM_SR; ++ return (pmcon_2 & bitmask) == bitmask ? BOOTMODE_WARM : BOOTMODE_COLD; ++} ++ + static bool early_init_native(int s3resume) + { + printk(BIOS_DEBUG, "Starting native platform initialisation\n"); +@@ -24,6 +56,120 @@ static bool early_init_native(int s3resume) + return cpu_replaced; + } + ++#define MRC_CACHE_VERSION 1 ++ ++struct mrc_data { ++ const void *buffer; ++ size_t buffer_len; ++}; ++ ++static void save_mrc_data(struct mrc_data *md) ++{ ++ mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION, md->buffer, md->buffer_len); ++} ++ ++static struct mrc_data prepare_mrc_cache(void) ++{ ++ struct mrc_data md = {0}; ++ md.buffer = mrc_cache_current_mmap_leak(MRC_TRAINING_DATA, ++ MRC_CACHE_VERSION, ++ &md.buffer_len); ++ return md; ++} ++ ++static const char *const bm_names[] = { ++ "BOOTMODE_COLD", ++ "BOOTMODE_WARM", ++ "BOOTMODE_S3", ++ "BOOTMODE_FAST", ++}; ++ ++static void clear_disb(void) ++{ ++ pci_and_config16(PCH_LPC_DEV, GEN_PMCON_2, ~GEN_PMCON_2_DISB); ++} ++ ++static void raminit_reset(void) ++{ ++ clear_disb(); ++ system_reset(); ++} ++ ++static enum raminit_boot_mode do_actual_raminit( ++ struct mrc_data *md, ++ const bool s3resume, ++ const bool cpu_replaced, ++ const enum raminit_boot_mode orig_bootmode) ++{ ++ enum raminit_boot_mode bootmode = orig_bootmode; ++ ++ bool save_data_valid = md->buffer && md->buffer_len == USHRT_MAX; /** TODO: sizeof() **/ ++ ++ if (s3resume) { ++ if (bootmode == BOOTMODE_COLD) { ++ printk(BIOS_EMERG, "Memory may not be in self-refresh for S3 resume\n"); ++ printk(BIOS_EMERG, "S3 resume and cold boot are mutually exclusive\n"); ++ raminit_reset(); ++ } ++ /* Only a true mad hatter would replace a CPU in S3 */ ++ if (cpu_replaced) { ++ printk(BIOS_EMERG, "Oh no, CPU was replaced during S3\n"); ++ /* ++ * No reason to continue, memory consistency is most likely lost ++ * and ME will probably request a reset through DID response too. ++ */ ++ /** TODO: Figure out why past self commented this out **/ ++ //raminit_reset(); ++ } ++ bootmode = BOOTMODE_S3; ++ if (!save_data_valid) { ++ printk(BIOS_EMERG, "No training data, S3 resume is impossible\n"); ++ /* Failed S3 resume, reset to come up cleanly */ ++ raminit_reset(); ++ } ++ } ++ if (!s3resume && cpu_replaced) { ++ printk(BIOS_NOTICE, "CPU was replaced, forcing a cold boot\n"); ++ /* ++ * Looks like the ME will get angry if raminit takes too long. ++ * It will report that the CPU has been replaced on next boot. ++ * Try to continue anyway. This should not happen in most cases. ++ */ ++ /** TODO: Figure out why past self commented this out **/ ++ //save_data_valid = false; ++ } ++ if (bootmode == BOOTMODE_COLD) { ++ /* If possible, promote to a fast boot */ ++ if (save_data_valid) ++ bootmode = BOOTMODE_FAST; ++ ++ clear_disb(); ++ } else if (bootmode == BOOTMODE_WARM) { ++ /* If a warm reset happened before raminit is done, force a cold boot */ ++ if (mchbar_read32(SSKPD) == 0 && mchbar_read32(SSKPD + 4) == 0) { ++ printk(BIOS_NOTICE, "Warm reset occurred early in cold boot\n"); ++ save_data_valid = false; ++ } ++ if (!save_data_valid) ++ bootmode = BOOTMODE_COLD; ++ } ++ assert(save_data_valid != (bootmode == BOOTMODE_COLD)); ++ if (save_data_valid) { ++ printk(BIOS_INFO, "Using cached memory parameters\n"); ++ die("RAMINIT: Fast boot is not yet implemented\n"); ++ } ++ printk(RAM_DEBUG, "Initial bootmode: %s\n", bm_names[orig_bootmode]); ++ printk(RAM_DEBUG, "Current bootmode: %s\n", bm_names[bootmode]); ++ ++ /* ++ * And now, the actual memory initialization thing. ++ */ ++ printk(RAM_DEBUG, "\nStarting native raminit\n"); ++ raminit_main(bootmode); ++ ++ return bootmode; ++} ++ + void perform_raminit(const int s3resume) + { + /* +@@ -32,17 +178,48 @@ void perform_raminit(const int s3resume) + */ + const bool cpu_replaced = early_init_native(s3resume); + +- (void)cpu_replaced; ++ wait_txt_clear(); ++ wrmsr(0x2e6, (msr_t) {.lo = 0, .hi = 0}); ++ ++ const enum raminit_boot_mode orig_bootmode = get_boot_mode(); ++ ++ struct mrc_data md = prepare_mrc_cache(); ++ ++ const enum raminit_boot_mode bootmode = ++ do_actual_raminit(&md, s3resume, cpu_replaced, orig_bootmode); ++ ++ /** TODO: report_memory_config **/ + +- /** TODO: Move after raminit */ + if (intel_early_me_uma_size() > 0) { +- /** TODO: Update status once raminit is implemented **/ +- uint8_t me_status = ME_INIT_STATUS_ERROR; ++ /* ++ * The 'other' success value is to report loss of memory ++ * consistency to ME if warm boot was downgraded to cold. ++ */ ++ uint8_t me_status; ++ if (BOOTMODE_WARM == orig_bootmode && BOOTMODE_COLD == bootmode) ++ me_status = ME_INIT_STATUS_SUCCESS_OTHER; ++ 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); + } + ++ post_code(0x3b); ++ + intel_early_me_status(); + +- /** TODO: Implement the required magic **/ +- die("NATIVE RAMINIT: More Magic (tm) required.\n"); ++ const bool cbmem_was_initted = !cbmem_recovery(s3resume); ++ if (s3resume && !cbmem_was_initted) { ++ /* Failed S3 resume, reset to come up cleanly */ ++ printk(BIOS_CRIT, "Failed to recover CBMEM in S3 resume.\n"); ++ system_reset(); ++ } ++ ++ /* Save training data on non-S3 resumes */ ++ if (!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 +new file mode 100644 +index 0000000000..885f0184f4 +--- /dev/null ++++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef HASWELL_RAMINIT_NATIVE_H ++#define HASWELL_RAMINIT_NATIVE_H ++ ++enum raminit_boot_mode { ++ BOOTMODE_COLD, ++ BOOTMODE_WARM, ++ BOOTMODE_S3, ++ BOOTMODE_FAST, ++}; ++ ++enum raminit_status { ++ RAMINIT_STATUS_SUCCESS = 0, ++ RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/ ++}; ++ ++enum generic_stepping { ++ STEPPING_A0 = 1, ++ STEPPING_B0 = 2, ++ STEPPING_C0 = 3, ++}; ++ ++struct sysinfo { ++ enum raminit_boot_mode bootmode; ++ enum generic_stepping stepping; ++ uint32_t cpu; /* CPUID value */ ++ ++ bool dq_pins_interleaved; ++}; ++ ++void raminit_main(enum raminit_boot_mode bootmode); ++ ++#endif +-- +2.39.2 + |