summaryrefslogtreecommitdiffstats
path: root/src/northbridge
diff options
context:
space:
mode:
authorKeith Hui <buurin@gmail.com>2023-07-15 12:08:51 -0400
committerFelix Held <felix-coreboot@felixheld.de>2023-11-13 20:30:33 +0000
commit1e9601c5ef80a5b2eea52e512c7933e2daebd337 (patch)
treed3a2b4689e2b7ad651c36c74d34b4e4427ff1ed2 /src/northbridge
parent9e345c8400ce9233b31c28a2450cca6347cc186b (diff)
downloadcoreboot-1e9601c5ef80a5b2eea52e512c7933e2daebd337.tar.gz
coreboot-1e9601c5ef80a5b2eea52e512c7933e2daebd337.tar.bz2
coreboot-1e9601c5ef80a5b2eea52e512c7933e2daebd337.zip
nb/intel/sandybridge: Standardize MRC vs. native SPD mapping API
Changes both MRC and native raminit code path to get SPD mapping from one place. Boards with all memory socketed specify their mappings in a devicetree setting introduced in commit 5709e03613b3 ("nb/intel/sandybridge: Migrate MRC settings to devicetree") back in May 2019 but remains unused as of this patch. This setting will now hold raw SMBus addresses, and MRC raminit gets code to translate them into a representation MRC expects. Boards with soldered down memory (specifically with HAVE_SPD_IN_CBFS in their board Kconfig), with or without socketed memory, specify their layouts in mb_get_spd_map() as used by Haswell boards, where they access hardware GPIO straps to select which SPD data to use. This harmonizes the way boards specify their SPD layouts across Haswell/SNB/IVB boards whether using MRC or native raminit. Going forward they only need to specify the layout in one place. (Going forward the devicetree setting should be backported to Haswell, once we get native raminit working there.) With this, northbridge code is now fully responsible for loading all SPD data, be it from CBFS or SMBus. To avoid breakage, transition will happen in stages: 1. This patch gets all the code in, and implements weak stubs that maintain existing code and data flow (i.e. mainboards still populate final SPD layout data). At this point devicetree already uses new representation, but is still unused meaning no breakage. 2. Follow-up patch(es) remove mainboard_get_spd() from mainboards, and replace it with mb_get_spd_map() or devicetree values (as appropriate) with converted SPD info. The "weak" mainboard_get_spd() with new logic takes over. Boards go Haswell Style at this point. Boards with MRC raminit also lose code to fill in SPD data, allowing new data to take hold. 3. Clean-up patch removes the weak functions and public prototypes re mainboard_get_spd(), making it internal to northbridge. Changeover is complete. Change-Id: I1a75279d981e46505930a9ce1aae894ccc4e1f24 Signed-off-by: Keith Hui <buurin@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/76965 Reviewed-by: Martin L Roth <gaumless@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/northbridge')
-rw-r--r--src/northbridge/intel/sandybridge/chip.h2
-rw-r--r--src/northbridge/intel/sandybridge/raminit.c54
-rw-r--r--src/northbridge/intel/sandybridge/raminit.h29
-rw-r--r--src/northbridge/intel/sandybridge/raminit_mrc.c63
4 files changed, 137 insertions, 11 deletions
diff --git a/src/northbridge/intel/sandybridge/chip.h b/src/northbridge/intel/sandybridge/chip.h
index 99d976324169..82e58f61869d 100644
--- a/src/northbridge/intel/sandybridge/chip.h
+++ b/src/northbridge/intel/sandybridge/chip.h
@@ -45,7 +45,7 @@ struct northbridge_intel_sandybridge_config {
/* Data for RAM init */
- /* DIMM SPD address. Use 8bit notation where BIT0 is always zero. */
+ /* DIMM SPD address. */
u8 spd_addresses[4];
/* PEI data for RAM init and early silicon init */
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c
index 82931da3d969..2575a9c6fc08 100644
--- a/src/northbridge/intel/sandybridge/raminit.c
+++ b/src/northbridge/intel/sandybridge/raminit.c
@@ -4,7 +4,10 @@
#include <commonlib/region.h>
#include <cf9_reset.h>
#include <string.h>
+#include <cbfs.h>
#include <arch/cpu.h>
+#include <device/device.h>
+#include <device/dram/ddr3.h>
#include <device/mmio.h>
#include <device/pci_ops.h>
#include <device/smbus_host.h>
@@ -16,9 +19,11 @@
#include <cpu/x86/msr.h>
#include <types.h>
+#include "raminit.h"
#include "raminit_native.h"
#include "raminit_common.h"
#include "sandybridge.h"
+#include "chip.h"
/* FIXME: no support for 3-channel chipsets */
@@ -139,14 +144,59 @@ void read_spd(spd_raw_data * spd, u8 addr, bool id_only)
{
int j;
if (id_only) {
- for (j = 117; j < 128; j++)
+ for (j = SPD_DIMM_MOD_ID1; j < 128; j++)
(*spd)[j] = smbus_read_byte(addr, j);
} else {
- for (j = 0; j < 256; j++)
+ for (j = 0; j < SPD_SIZE_MAX_DDR3; j++)
(*spd)[j] = smbus_read_byte(addr, j);
}
}
+/* Temporary stub */
+__weak void mb_get_spd_map(struct spd_info *spdi) {}
+
+__weak void mainboard_get_spd(spd_raw_data *spd, bool id_only)
+{
+ const struct northbridge_intel_sandybridge_config *cfg = config_of_soc();
+ unsigned int i;
+
+ if (CONFIG(HAVE_SPD_IN_CBFS)) {
+ struct spd_info spdi = {0};
+
+ mb_get_spd_map(&spdi);
+
+ size_t spd_file_len;
+ uint8_t *spd_file = cbfs_map("spd.bin", &spd_file_len);
+
+ printk(BIOS_DEBUG, "SPD index %d\n", spdi.spd_index);
+
+ /* SPD file sanity check */
+ if (!spd_file)
+ die("SPD data %s!", "not found");
+
+ if (spd_file_len < ((spdi.spd_index + 1) * SPD_SIZE_MAX_DDR3))
+ die("SPD data %s!", "incomplete");
+
+ /*
+ * Copy SPD data specified by spd_info.spd_index to all slots marked as
+ * SPD_MEMORY_DOWN.
+ *
+ * Read SPD data from slots with a real SMBus address.
+ */
+ for (i = 0; i < ARRAY_SIZE(spdi.addresses); i++) {
+ if (spdi.addresses[i] == SPD_MEMORY_DOWN)
+ memcpy(&spd[i], spd_file + (spdi.spd_index * SPD_SIZE_MAX_DDR3), SPD_SIZE_MAX_DDR3);
+ else if (spdi.addresses[i] != 0)
+ read_spd(&spd[i], spdi.addresses[i], id_only);
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(cfg->spd_addresses); i++) {
+ if (cfg->spd_addresses[i] != 0)
+ read_spd(&spd[i], cfg->spd_addresses[i], id_only);
+ }
+ } /* CONFIG(HAVE_SPD_IN_CBFS) */
+}
+
static void dram_find_spds_ddr3(spd_raw_data *spd, ramctr_timing *ctrl)
{
int dimms = 0, ch_dimms;
diff --git a/src/northbridge/intel/sandybridge/raminit.h b/src/northbridge/intel/sandybridge/raminit.h
index fa9fa986801f..8e87fdf402c0 100644
--- a/src/northbridge/intel/sandybridge/raminit.h
+++ b/src/northbridge/intel/sandybridge/raminit.h
@@ -11,4 +11,33 @@
void mainboard_fill_pei_data(struct pei_data *pei_data);
+/*
+ * SPD information API adopted from nb/intel/haswell.
+ *
+ * This applies to both MRC and native raminit, only for boards with
+ * CONFIG(HAVE_SPD_IN_CBFS).
+ *
+ * spd_info.addresses is an array of 4 bytes representing the SMBus addresses
+ * of the SPD EEPROM of (respectively) Channel 0 Slot 0, C0S1, C1S0, C1S1.
+ * Boards with onboard memory for the slot without actual SPD EEPROM enter
+ * SPD_MEMORY_DOWN in that position and enter in spd_info.spd_index a 0-based index into
+ * spd.bin file in CBFS, which is a concatenation of 256-byte SPD data blobs.
+ *
+ * Only one set of SPD data is supported.
+ */
+
+#define SPD_MEMORY_DOWN 0xFF
+
+struct spd_info {
+ uint8_t addresses[4];
+ unsigned int spd_index;
+};
+
+/*
+ * Mainboard callback to fill in the SPD addresses.
+ *
+ * @param spdi Pointer to spd_info struct to be populated by mainboard.
+ */
+void mb_get_spd_map(struct spd_info *spdi);
+
#endif /* RAMINIT_H */
diff --git a/src/northbridge/intel/sandybridge/raminit_mrc.c b/src/northbridge/intel/sandybridge/raminit_mrc.c
index 69baf4427066..de41ae590f69 100644
--- a/src/northbridge/intel/sandybridge/raminit_mrc.c
+++ b/src/northbridge/intel/sandybridge/raminit_mrc.c
@@ -264,13 +264,7 @@ static void southbridge_fill_pei_data(struct pei_data *pei_data)
static void devicetree_fill_pei_data(struct pei_data *pei_data)
{
- const struct northbridge_intel_sandybridge_config *cfg;
-
- const struct device *dev = pcidev_on_root(0, 0);
- if (!dev || !dev->chip_info)
- return;
-
- cfg = dev->chip_info;
+ const struct northbridge_intel_sandybridge_config *cfg = config_of_soc();
switch (cfg->max_mem_clock_mhz) {
/* MRC only supports fixed numbers of frequencies */
@@ -292,7 +286,15 @@ static void devicetree_fill_pei_data(struct pei_data *pei_data)
}
- memcpy(pei_data->spd_addresses, cfg->spd_addresses, sizeof(pei_data->spd_addresses));
+ /*
+ * SPD addresses are listed in devicetree as actual addresses,
+ * and for MRC need to be shifted left so bit 0 is always zero.
+ */
+ if (!CONFIG(HAVE_SPD_IN_CBFS)) {
+ for (unsigned int i = 0; i < ARRAY_SIZE(cfg->spd_addresses); i++) {
+ pei_data->spd_addresses[i] = cfg->spd_addresses[i] << 1;
+ }
+ }
memcpy(pei_data->ts_addresses, cfg->ts_addresses, sizeof(pei_data->ts_addresses));
pei_data->ec_present = cfg->ec_present;
@@ -310,6 +312,49 @@ static void devicetree_fill_pei_data(struct pei_data *pei_data)
pei_data->usb3.xhci_streams = cfg->usb3.xhci_streams;
}
+/* Temporary stub */
+__weak void mb_get_spd_map(struct spd_info *spdi) {}
+
+static void spd_fill_pei_data(struct pei_data *pei_data)
+{
+ struct spd_info spdi = {0};
+ unsigned int i, have_memory_down;
+
+ mb_get_spd_map(&spdi);
+
+ for (i = 0; i < ARRAY_SIZE(spdi.addresses); i++) {
+ if (spdi.addresses[i] == SPD_MEMORY_DOWN) {
+ pei_data->spd_addresses[i] = 0;
+ have_memory_down = 1;
+ } else {
+ /* MRC expects left-aligned SMBus addresses. */
+ pei_data->spd_addresses[i] = spdi.addresses[i] << 1;
+ }
+ }
+ /* Copy SPD data from CBFS for on-board memory */
+ if (have_memory_down) {
+ printk(BIOS_DEBUG, "SPD index %d\n", spdi.spd_index);
+
+ size_t spd_file_len;
+ uint8_t *spd_file = cbfs_map("spd.bin", &spd_file_len);
+
+ if (!spd_file)
+ die("SPD data %s!", "not found");
+
+ if (spd_file_len < ((spdi.spd_index + 1) * SPD_SIZE_MAX_DDR3))
+ die("SPD data %s!", "incomplete");
+
+ /* MRC only uses index 0... */
+ memcpy(pei_data->spd_data[0], spd_file + (spdi.spd_index * SPD_SIZE_MAX_DDR3), SPD_SIZE_MAX_DDR3);
+
+ /* but coreboot uses the other indices */
+ for (i = 1; i < ARRAY_SIZE(spdi.addresses); i++) {
+ if (spdi.addresses[i] == SPD_MEMORY_DOWN)
+ memcpy(pei_data->spd_data[i], pei_data->spd_data[0], SPD_SIZE_MAX_DDR3);
+ }
+ }
+}
+
static void disable_p2p(void)
{
/* Disable PCI-to-PCI bridge early to prevent probing by MRC */
@@ -337,6 +382,8 @@ void perform_raminit(int s3resume)
northbridge_fill_pei_data(&pei_data);
southbridge_fill_pei_data(&pei_data);
devicetree_fill_pei_data(&pei_data);
+ if (CONFIG(HAVE_SPD_IN_CBFS))
+ spd_fill_pei_data(&pei_data);
mainboard_fill_pei_data(&pei_data);
post_code(0x3a);