diff options
Diffstat (limited to 'config/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch')
-rw-r--r-- | config/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch | 344 |
1 files changed, 0 insertions, 344 deletions
diff --git a/config/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch b/config/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch deleted file mode 100644 index 4c2a2670..00000000 --- a/config/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch +++ /dev/null @@ -1,344 +0,0 @@ -From 354969af4361bcc7dc240ef5871d169728f7f0cc Mon Sep 17 00:00:00 2001 -From: Angel Pons <th3fanbus@gmail.com> -Date: Sat, 7 May 2022 13:48:53 +0200 -Subject: [PATCH 10/26] haswell NRI: Collect SPD info - -Collect SPD data from DIMMs and memory-down, and find the common -supported settings. - -Change-Id: I4e6a1408a638a463ecae37a447cfed1d6556e44a -Signed-off-by: Angel Pons <th3fanbus@gmail.com> ---- - .../intel/haswell/native_raminit/Makefile.inc | 1 + - .../haswell/native_raminit/raminit_main.c | 1 + - .../haswell/native_raminit/raminit_native.h | 57 +++++ - .../haswell/native_raminit/spd_bitmunching.c | 206 ++++++++++++++++++ - 4 files changed, 265 insertions(+) - create mode 100644 src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c - -diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc -index 90af951c5a..ebf7abc6ec 100644 ---- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc -+++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc -@@ -2,3 +2,4 @@ - - romstage-y += raminit_main.c - romstage-y += raminit_native.c -+romstage-y += spd_bitmunching.c -diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c -index 9b42c25b40..2d2cfa48bb 100644 ---- a/src/northbridge/intel/haswell/native_raminit/raminit_main.c -+++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c -@@ -20,6 +20,7 @@ struct task_entry { - }; - - static const struct task_entry cold_boot[] = { -+ { collect_spd_info, true, "PROCSPD", }, - }; - - /* Return a generic stepping value to make stepping checks simpler */ -diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h -index 885f0184f4..1a0793947e 100644 ---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.h -+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h -@@ -3,6 +3,15 @@ - #ifndef HASWELL_RAMINIT_NATIVE_H - #define HASWELL_RAMINIT_NATIVE_H - -+#include <device/dram/ddr3.h> -+#include <northbridge/intel/haswell/haswell.h> -+ -+#define SPD_LEN 256 -+ -+/* 8 data lanes + 1 ECC lane */ -+#define NUM_LANES 9 -+#define NUM_LANES_NO_ECC 8 -+ - enum raminit_boot_mode { - BOOTMODE_COLD, - BOOTMODE_WARM, -@@ -12,6 +21,8 @@ enum raminit_boot_mode { - - enum raminit_status { - RAMINIT_STATUS_SUCCESS = 0, -+ RAMINIT_STATUS_NO_MEMORY_INSTALLED, -+ RAMINIT_STATUS_UNSUPPORTED_MEMORY, - RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/ - }; - -@@ -21,14 +32,60 @@ enum generic_stepping { - STEPPING_C0 = 3, - }; - -+struct raminit_dimm_info { -+ spd_raw_data raw_spd; -+ struct dimm_attr_ddr3_st data; -+ uint8_t spd_addr; -+ bool valid; -+}; -+ - struct sysinfo { - enum raminit_boot_mode bootmode; - enum generic_stepping stepping; - uint32_t cpu; /* CPUID value */ - - bool dq_pins_interleaved; -+ -+ /** TODO: ECC support untested **/ -+ bool is_ecc; -+ -+ /** -+ * FIXME: LPDDR support is incomplete. The largest chunks are missing, -+ * but some LPDDR-specific variations in algorithms have been handled. -+ * LPDDR-specific functions have stubs which will halt upon execution. -+ */ -+ bool lpddr; -+ -+ struct raminit_dimm_info dimms[NUM_CHANNELS][NUM_SLOTS]; -+ union dimm_flags_ddr3_st flags; -+ uint16_t cas_supported; -+ -+ /* Except for tCK, everything is eventually stored in DCLKs */ -+ uint32_t tCK; -+ uint32_t tAA; /* Also known as tCL */ -+ uint32_t tWR; -+ uint32_t tRCD; -+ uint32_t tRRD; -+ uint32_t tRP; -+ uint32_t tRAS; -+ uint32_t tRC; -+ uint32_t tRFC; -+ uint32_t tWTR; -+ uint32_t tRTP; -+ uint32_t tFAW; -+ uint32_t tCWL; -+ uint32_t tCMD; -+ -+ uint8_t lanes; /* 8 or 9 */ -+ uint8_t chanmap; -+ uint8_t dpc[NUM_CHANNELS]; /* DIMMs per channel */ -+ uint8_t rankmap[NUM_CHANNELS]; -+ uint8_t rank_mirrored[NUM_CHANNELS]; -+ uint32_t channel_size_mb[NUM_CHANNELS]; - }; - - void raminit_main(enum raminit_boot_mode bootmode); - -+enum raminit_status collect_spd_info(struct sysinfo *ctrl); -+ - #endif -diff --git a/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c b/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c -new file mode 100644 -index 0000000000..dbe02c72d0 ---- /dev/null -+++ b/src/northbridge/intel/haswell/native_raminit/spd_bitmunching.c -@@ -0,0 +1,206 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+ -+#include <cbfs.h> -+#include <commonlib/clamp.h> -+#include <console/console.h> -+#include <device/dram/ddr3.h> -+#include <device/smbus_host.h> -+#include <northbridge/intel/haswell/haswell.h> -+#include <northbridge/intel/haswell/raminit.h> -+#include <string.h> -+#include <types.h> -+ -+#include "raminit_native.h" -+ -+static const uint8_t *get_spd_data_from_cbfs(struct spd_info *spdi) -+{ -+ if (!CONFIG(HAVE_SPD_IN_CBFS)) -+ return NULL; -+ -+ printk(RAM_DEBUG, "SPD index %u\n", spdi->spd_index); -+ -+ size_t spd_file_len; -+ uint8_t *spd_file = cbfs_map("spd.bin", &spd_file_len); -+ -+ if (!spd_file) { -+ printk(BIOS_ERR, "SPD data not found in CBFS\n"); -+ return NULL; -+ } -+ -+ if (spd_file_len < ((spdi->spd_index + 1) * SPD_LEN)) { -+ printk(BIOS_ERR, "SPD index override to 0 - old hardware?\n"); -+ spdi->spd_index = 0; -+ } -+ -+ if (spd_file_len < SPD_LEN) { -+ printk(BIOS_ERR, "Invalid SPD data in CBFS\n"); -+ return NULL; -+ } -+ -+ return spd_file + (spdi->spd_index * SPD_LEN); -+} -+ -+static void get_spd_for_dimm(struct raminit_dimm_info *const dimm, const uint8_t *cbfs_spd) -+{ -+ if (dimm->spd_addr == SPD_MEMORY_DOWN) { -+ if (cbfs_spd) { -+ memcpy(dimm->raw_spd, cbfs_spd, SPD_LEN); -+ dimm->valid = true; -+ printk(RAM_DEBUG, "memory-down\n"); -+ return; -+ } else { -+ printk(RAM_DEBUG, "memory-down but no CBFS SPD data, ignoring\n"); -+ return; -+ } -+ } -+ printk(RAM_DEBUG, "slotted "); -+ const uint8_t spd_mem_type = smbus_read_byte(dimm->spd_addr, SPD_MEMORY_TYPE); -+ if (spd_mem_type != SPD_MEMORY_TYPE_SDRAM_DDR3) { -+ printk(RAM_DEBUG, "and not DDR3, ignoring\n"); -+ return; -+ } -+ printk(RAM_DEBUG, "and DDR3\n"); -+ if (i2c_eeprom_read(dimm->spd_addr, 0, SPD_LEN, dimm->raw_spd) != SPD_LEN) { -+ printk(BIOS_WARNING, "I2C block read failed, trying SMBus byte reads\n"); -+ for (uint32_t i = 0; i < SPD_LEN; i++) -+ dimm->raw_spd[i] = smbus_read_byte(dimm->spd_addr, i); -+ } -+ dimm->valid = true; -+} -+ -+static void get_spd_data(struct sysinfo *ctrl) -+{ -+ struct spd_info spdi = {0}; -+ mb_get_spd_map(&spdi); -+ const uint8_t *cbfs_spd = get_spd_data_from_cbfs(&spdi); -+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) { -+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) { -+ struct raminit_dimm_info *const dimm = &ctrl->dimms[channel][slot]; -+ dimm->spd_addr = spdi.addresses[channel + channel + slot]; -+ if (!dimm->spd_addr) -+ continue; -+ -+ printk(RAM_DEBUG, "CH%uS%u is ", channel, slot); -+ get_spd_for_dimm(dimm, cbfs_spd); -+ } -+ } -+} -+ -+static void decode_spd(struct raminit_dimm_info *const dimm) -+{ -+ /** TODO: Hook up somewhere, and handle lack of XMP data **/ -+ const bool enable_xmp = false; -+ memset(&dimm->data, 0, sizeof(dimm->data)); -+ if (enable_xmp) -+ spd_xmp_decode_ddr3(&dimm->data, dimm->raw_spd, DDR3_XMP_PROFILE_1); -+ else -+ spd_decode_ddr3(&dimm->data, dimm->raw_spd); -+ -+ if (CONFIG(DEBUG_RAM_SETUP)) -+ dram_print_spd_ddr3(&dimm->data); -+} -+ -+static enum raminit_status find_common_spd_parameters(struct sysinfo *ctrl) -+{ -+ ctrl->cas_supported = 0xffff; -+ ctrl->flags.raw = 0xffffffff; -+ -+ ctrl->tCK = 0; -+ ctrl->tAA = 0; -+ ctrl->tWR = 0; -+ ctrl->tRCD = 0; -+ ctrl->tRRD = 0; -+ ctrl->tRP = 0; -+ ctrl->tRAS = 0; -+ ctrl->tRC = 0; -+ ctrl->tRFC = 0; -+ ctrl->tWTR = 0; -+ ctrl->tRTP = 0; -+ ctrl->tFAW = 0; -+ ctrl->tCWL = 0; -+ ctrl->tCMD = 0; -+ ctrl->chanmap = 0; -+ -+ bool yes_ecc = false; -+ bool not_ecc = false; -+ -+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) { -+ ctrl->dpc[channel] = 0; -+ ctrl->rankmap[channel] = 0; -+ ctrl->rank_mirrored[channel] = 0; -+ ctrl->channel_size_mb[channel] = 0; -+ for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) { -+ struct raminit_dimm_info *const dimm = &ctrl->dimms[channel][slot]; -+ if (!dimm->valid) -+ continue; -+ -+ printk(RAM_DEBUG, "\nCH%uS%u SPD:\n", channel, slot); -+ decode_spd(dimm); -+ -+ ctrl->chanmap |= BIT(channel); -+ ctrl->dpc[channel]++; -+ ctrl->channel_size_mb[channel] += dimm->data.size_mb; -+ -+ /* The first rank of a populated slot is always present */ -+ const uint8_t rank = slot + slot; -+ assert(dimm->data.ranks); -+ ctrl->rankmap[channel] |= (BIT(dimm->data.ranks) - 1) << rank; -+ -+ if (dimm->data.flags.pins_mirrored) -+ ctrl->rank_mirrored[channel] |= BIT(rank + 1); -+ -+ /* Find common settings */ -+ ctrl->cas_supported &= dimm->data.cas_supported; -+ ctrl->flags.raw &= dimm->data.flags.raw; -+ ctrl->tCK = MAX(ctrl->tCK, dimm->data.tCK); -+ ctrl->tAA = MAX(ctrl->tAA, dimm->data.tAA); -+ ctrl->tWR = MAX(ctrl->tWR, dimm->data.tWR); -+ ctrl->tRCD = MAX(ctrl->tRCD, dimm->data.tRCD); -+ ctrl->tRRD = MAX(ctrl->tRRD, dimm->data.tRRD); -+ ctrl->tRP = MAX(ctrl->tRP, dimm->data.tRP); -+ ctrl->tRAS = MAX(ctrl->tRAS, dimm->data.tRAS); -+ ctrl->tRC = MAX(ctrl->tRC, dimm->data.tRC); -+ ctrl->tRFC = MAX(ctrl->tRFC, dimm->data.tRFC); -+ ctrl->tWTR = MAX(ctrl->tWTR, dimm->data.tWTR); -+ ctrl->tRTP = MAX(ctrl->tRTP, dimm->data.tRTP); -+ ctrl->tFAW = MAX(ctrl->tFAW, dimm->data.tFAW); -+ ctrl->tCWL = MAX(ctrl->tCWL, dimm->data.tCWL); -+ ctrl->tCMD = MAX(ctrl->tCMD, dimm->data.tCMD); -+ -+ yes_ecc |= dimm->data.flags.is_ecc; -+ not_ecc |= !dimm->data.flags.is_ecc; -+ } -+ } -+ -+ if (!ctrl->chanmap) { -+ printk(BIOS_ERR, "No DIMMs were found\n"); -+ return RAMINIT_STATUS_NO_MEMORY_INSTALLED; -+ } -+ if (!ctrl->cas_supported) { -+ printk(BIOS_ERR, "Could not resolve common CAS latency\n"); -+ return RAMINIT_STATUS_UNSUPPORTED_MEMORY; -+ } -+ /** TODO: Properly handle ECC support and ECC forced **/ -+ if (yes_ecc && not_ecc) { -+ /** TODO: Test if the ECC DIMMs can be operated as non-ECC DIMMs **/ -+ printk(BIOS_ERR, "Both ECC and non-ECC DIMMs present, this is unsupported\n"); -+ return RAMINIT_STATUS_UNSUPPORTED_MEMORY; -+ } -+ if (yes_ecc) -+ ctrl->lanes = NUM_LANES; -+ else -+ ctrl->lanes = NUM_LANES_NO_ECC; -+ -+ ctrl->is_ecc = yes_ecc; -+ -+ /** TODO: Complete LPDDR support **/ -+ ctrl->lpddr = false; -+ -+ return RAMINIT_STATUS_SUCCESS; -+} -+ -+enum raminit_status collect_spd_info(struct sysinfo *ctrl) -+{ -+ get_spd_data(ctrl); -+ return find_common_spd_parameters(ctrl); -+} --- -2.39.2 - |