Skip to content

Commit

Permalink
nb/intel/sandybridge: Standardize MRC vs. native SPD mapping API
Browse files Browse the repository at this point in the history
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 5709e03
("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>
  • Loading branch information
Keith Hui authored and felixheld committed Nov 13, 2023
1 parent 9e345c8 commit 1e9601c
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/northbridge/intel/sandybridge/chip.h
Expand Up @@ -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 */
Expand Down
54 changes: 52 additions & 2 deletions src/northbridge/intel/sandybridge/raminit.c
Expand Up @@ -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>
Expand All @@ -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 */

Expand Down Expand Up @@ -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;
Expand Down
29 changes: 29 additions & 0 deletions src/northbridge/intel/sandybridge/raminit.h
Expand Up @@ -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 */
63 changes: 55 additions & 8 deletions src/northbridge/intel/sandybridge/raminit_mrc.c
Expand Up @@ -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 */
Expand All @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1e9601c

Please sign in to comment.