summaryrefslogtreecommitdiff
path: root/resources/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.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/0010-haswell-NRI-Collect-SPD-info.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/0010-haswell-NRI-Collect-SPD-info.patch')
-rw-r--r--resources/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch344
1 files changed, 344 insertions, 0 deletions
diff --git a/resources/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch b/resources/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch
new file mode 100644
index 00000000..4c2a2670
--- /dev/null
+++ b/resources/coreboot/haswell/patches/0010-haswell-NRI-Collect-SPD-info.patch
@@ -0,0 +1,344 @@
+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
+