soc/intel/fsp_broadwell_de: Populate SMBIOS tables with memory information

Add code to read SPD data, parse it and save into SMBIOS table. This is
implemented for socketed DDR4 chips only. For soldered-down memory this
is not implemented and probably won't be ever needed.

TEST=tested on OCP Monolake mainboard, and found dmidecode -t memory to
work. The stack has also been tested on an out-of-tree board.

Signed-off-by: Andrey Petrov <anpetrov@fb.com>
Change-Id: I1162eb4484dab46f1ab9fe3426eecc4d9378e8e2
Reviewed-on: https://review.coreboot.org/c/coreboot/+/34681
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Matt DeVillier <matt.devillier@gmail.com>
This commit is contained in:
Andrey Petrov 2019-08-01 15:09:37 -07:00 committed by Martin Roth
parent 3f85edbcc5
commit 4a73bf8378
6 changed files with 105 additions and 0 deletions

View File

@ -88,6 +88,10 @@ config SERIRQ_CONTINUOUS_MODE
If you set this option to y, the serial IRQ machine will be If you set this option to y, the serial IRQ machine will be
operated in continuous mode. operated in continuous mode.
config DIMM_SPD_SIZE
int
default 512
## Broadwell-DE Specific FSP Kconfig ## Broadwell-DE Specific FSP Kconfig
source src/soc/intel/fsp_broadwell_de/fsp/Kconfig source src/soc/intel/fsp_broadwell_de/fsp/Kconfig

View File

@ -0,0 +1,30 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2019 Facebook, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _SOC_MEMORY_H_
#define _SOC_MEMORY_H_
/* EDS vol 2, 9.2.24 */
#define REG_MC_BIOS_REQ 0x98
#define REG_MC_BIOS_REQ_FREQ_MSK ((1u << 6) - 1)
#define REG_MC_MULTIPLIER 133.33f
#define IMC_MAX_CHANNELS 2
#define SPD_SLAVE_ADDR(chan, slot) (2 * chan + slot)
void save_dimm_info(void);
#endif

View File

@ -131,4 +131,9 @@
#define IMC_DEV PCI_DEV(QPI_BUS, IMC_DEV0, IMC_FUNC0) #define IMC_DEV PCI_DEV(QPI_BUS, IMC_DEV0, IMC_FUNC0)
#define PCU1_DEV 30
#define PCU1_FUNC 01
#define UBOX_DEV 16
#define UBOX_FUNC 7
#endif /* _SOC_PCI_DEVS_H_ */ #endif /* _SOC_PCI_DEVS_H_ */

View File

@ -1,3 +1,4 @@
romstage-y += romstage.c romstage-y += romstage.c
romstage-y += memory.c
$(obj)/soc/intel/fsp_broadwell_de/romstage/romstage.romstage.o : $(obj)/build.h $(obj)/soc/intel/fsp_broadwell_de/romstage/romstage.romstage.o : $(obj)/build.h

View File

@ -0,0 +1,61 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2019 Facebook, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stddef.h>
#include <device/pci_ops.h>
#include <device/dram/ddr4.h>
#include <soc/pci_devs.h>
#include <soc/memory.h>
#include <spd_bin.h>
static uint32_t get_memory_dclk(void)
{
uint32_t reg32 =
pci_mmio_read_config32(PCI_DEV(QPI_BUS, PCU1_DEV, PCU1_FUNC), REG_MC_BIOS_REQ);
return (reg32 & REG_MC_BIOS_REQ_FREQ_MSK) * REG_MC_MULTIPLIER;
}
void save_dimm_info(void)
{
int index = 0;
uint32_t dclk_mhz = 0;
/*
* When talking to SPD chips through IMC slave offset of 0x50 is automagically added
* by hardware. Real-world slave numbers translate to: 0xa0, 0xa2, 0xa4, 0xa6.
*/
struct spd_block blk = {.addr_map = {SPD_SLAVE_ADDR(0, 0), SPD_SLAVE_ADDR(0, 1),
SPD_SLAVE_ADDR(1, 0), SPD_SLAVE_ADDR(1, 1)} };
get_spd_smbus(&blk);
dump_spd_info(&blk);
dclk_mhz = get_memory_dclk();
/*
* The platform is limited to 2 channels and max 2 dimms per channel.
* It doesn't look like DDR3 is supported so we assume memory is all DDR4.
*/
for (int channel = 0; channel < IMC_MAX_CHANNELS; channel++) {
for (int slot = 0; slot < CONFIG_DIMM_MAX / IMC_MAX_CHANNELS; slot++) {
dimm_attr dimm = {0};
u8 *spd_data = blk.spd_array[index];
if (spd_decode_ddr4(&dimm, spd_data) == SPD_STATUS_OK)
spd_add_smbios17_ddr4(channel, index, dclk_mhz, &dimm);
index++;
}
}
}

View File

@ -29,6 +29,7 @@
#include <pc80/mc146818rtc.h> #include <pc80/mc146818rtc.h>
#include <soc/iomap.h> #include <soc/iomap.h>
#include <soc/lpc.h> #include <soc/lpc.h>
#include <soc/memory.h>
#include <soc/pci_devs.h> #include <soc/pci_devs.h>
#include <soc/romstage.h> #include <soc/romstage.h>
#include <soc/gpio.h> #include <soc/gpio.h>
@ -165,6 +166,9 @@ void romstage_main_continue(EFI_STATUS status, void *hob_list_ptr)
die("Could not allocate cbmem for HOB pointer"); die("Could not allocate cbmem for HOB pointer");
*(u32 *)cbmem_hob_ptr = (u32)hob_list_ptr; *(u32 *)cbmem_hob_ptr = (u32)hob_list_ptr;
if (!CONFIG(FSP_MEMORY_DOWN))
save_dimm_info();
/* Load the ramstage. */ /* Load the ramstage. */
post_code(0x4e); post_code(0x4e);
run_ramstage(); run_ramstage();