Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/47521 )
Change subject: [WIP]mb/prodrive/hermes: Write board layout ......................................................................
[WIP]mb/prodrive/hermes: Write board layout
Change-Id: I11782cf2363be94983fbdd0b156a2213f9ee80f6 Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/mainboard/prodrive/hermes/eeprom.c M src/mainboard/prodrive/hermes/mainboard.c M src/mainboard/prodrive/hermes/variants/baseboard/include/eeprom.h 3 files changed, 136 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/47521/1
diff --git a/src/mainboard/prodrive/hermes/eeprom.c b/src/mainboard/prodrive/hermes/eeprom.c index f371b64..e374c60 100644 --- a/src/mainboard/prodrive/hermes/eeprom.c +++ b/src/mainboard/prodrive/hermes/eeprom.c @@ -95,3 +95,69 @@
return ret; } + +/* Write a single byte into the EEPROM at specified offset */ +static bool write_byte_eeprom(uint8_t data, uint16_t write_offset) +{ + int ret; + uint8_t buffer[2]; +#if ENV_ROMSTAGE + pci_devfn_t dev = PCI_DEV(0, PCH_DEV_SLOT_LPC, 4); +#else + const struct device *dev = pcidev_on_root(PCH_DEV_SLOT_LPC, 4); +#endif + + u32 smb_ctrl_reg = pci_read_config32(dev, HOSTC); + pci_write_config32(dev, HOSTC, smb_ctrl_reg | I2C_EN); + + /* + * The EEPROM expects two address bytes. + * Use the first byte of the block as second address byte. + */ + buffer[0] = write_offset & 0xff; + buffer[1] = data; + ret = do_smbus_block_write(SMBUS_IO_BASE, I2C_ADDR_EEPROM, (write_offset >> 8) & 0xff, + sizeof(buffer), buffer); + + /* Restore I2C_EN bit */ + pci_write_config32(dev, HOSTC, smb_ctrl_reg); + + return ret == 0; +} + +/* + * Write board layout if it has changed into EEPROM. + * Return true on error, false on success. + */ +bool write_board_settings(const struct eeprom_board_layout *l) +{ + const size_t off = offsetof(struct eeprom_layout, BoardLayout); + struct eeprom_board_layout cmp; + bool ret = false; + bool changed = false; + + /* Read old settings */ + if (read_write_config(&cmp, off, 0, sizeof(*l))) { + printk(BIOS_ERR, "CFG EEPROM: Read operation failed\n"); + return true; + } + + /* Compare with new settings */ + for (size_t i = 0; i < sizeof(*l); i++) { + uint8_t data = ((uint8_t *)l)[i]; + uint8_t ref = ((uint8_t *)&cmp)[i]; + if (ref != data) { + changed = true; + if (write_byte_eeprom(data, off + i)) { + printk(BIOS_ERR, "CFG EEPROM: Write operation failed\n"); + ret = true; + break; + } + } + } + + printk(BIOS_DEBUG, "CFG EEPROM: Board Layout up%s\n", + changed ? "dated": " to date"); + + return ret; +} diff --git a/src/mainboard/prodrive/hermes/mainboard.c b/src/mainboard/prodrive/hermes/mainboard.c index 7063c3e..e2182bc 100644 --- a/src/mainboard/prodrive/hermes/mainboard.c +++ b/src/mainboard/prodrive/hermes/mainboard.c @@ -3,6 +3,9 @@ #include <acpi/acpigen.h> #include <device/device.h> #include <soc/soc_chip.h> +#include <crc_byte.h> +#include <cbmem.h> +#include <console/console.h> #include "variants/baseboard/include/eeprom.h" #include "gpio.h"
@@ -129,6 +132,51 @@ #endif }
+static void update_board_layout(void) +{ + struct eeprom_board_layout l = {0}; + struct memory_info *m; + struct device *cpu; + + printk(BIOS_DEBUG, "MB: Collecting Board Layout information\n"); + + /* Update CPU fields */ + for (cpu = all_devices; cpu; cpu = cpu->next) { + if ((cpu->path.type != DEVICE_PATH_APIC) || + (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) + continue; + if (!cpu->enabled) + continue; + l.cpu_count ++; + if (l.cpu[0] == 0) + strcpy(l.cpu, cpu->name); + } + + /* PCH */ + strcpy(l.pch, "Cannonlake-H C246"); + + /* DRAM */ + m = cbmem_find(CBMEM_ID_MEMINFO); + for (size_t i = 0; m != NULL && i < m->dimm_cnt && i < ARRAY_SIZE(m->dimm) && + i < ARRAY_SIZE(l.dram_size); i++) { + struct dimm_info *dimm; + dimm = &m->dimm[i]; + if (dimm->dimm_size == 0) + continue; + + l.dram_size[i] = 1; + l.dram_ecc |= 1 << i; + } + /* Update CRC */ + + l.signature = CRC(((uint8_t *)&l) + sizeof(uint32_t), + sizeof(l) - sizeof(uint32_t), crc32_byte); + + if (write_board_settings(&l)) + printk(BIOS_ERR, "MB: Failed to update Board Layout\n"); +} + + static void mainboard_init(void *chip_info) { uint8_t value = 0; @@ -144,9 +192,16 @@ config_t *config = config_of_soc(); config->deep_s5_enable_ac = value; config->deep_s5_enable_dc = value; + +} + +static void mainboard_final(void *chip_info) +{ + update_board_layout(); }
struct chip_operations mainboard_ops = { .init = mainboard_init, + .final = mainboard_final, .enable_dev = mainboard_enable, }; diff --git a/src/mainboard/prodrive/hermes/variants/baseboard/include/eeprom.h b/src/mainboard/prodrive/hermes/variants/baseboard/include/eeprom.h index f9e9a71..f3a143c 100644 --- a/src/mainboard/prodrive/hermes/variants/baseboard/include/eeprom.h +++ b/src/mainboard/prodrive/hermes/variants/baseboard/include/eeprom.h @@ -11,11 +11,24 @@ uint8_t usb_powered_in_s5; } __packed;
+struct eeprom_board_layout { + uint32_t signature; + char cpu[50]; + uint8_t cpu_count; + char pch[50]; + uint8_t dram_size[4]; /* byte mask. 1 if slot is populated */ + uint8_t dram_ecc; /* bit mask. 1 if ECC is supported */ +} __packed; + + /* The EEPROM on address 0x57 has the following vendor defined layout: */ struct eeprom_layout { uint8_t FSPM_UPD[0x600]; uint8_t FSPS_UPD[0x600]; - uint8_t BoardLayout[0x400]; + union { + uint8_t RawBoardLayout[0x400]; + struct eeprom_board_layout BoardLayout; + }; uint8_t BootOrder[0xF00]; union { uint8_t RawBoardSetting[0x100]; @@ -49,3 +62,4 @@ size_t size); int check_fsp_signature(size_t offset, uint64_t fsp_signature); int check_board_settings_signature(void); +bool write_board_settings(const struct eeprom_board_layout *l);