summaryrefslogtreecommitdiff
path: root/config/coreboot/haswell/patches/0008-nb-intel-haswell-Add-native-raminit-scaffolding.patch
diff options
context:
space:
mode:
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.patch407
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
+