From 97923aebe192c766497619da630028c919e15a82 Mon Sep 17 00:00:00 2001 From: Angel Pons Date: Thu, 30 Mar 2023 23:56:51 +0200 Subject: [PATCH] mb/prodrive/atlas: Add initial support for options The plan is to have a setup menu in edk2 to configure coreboot options without having to describe the options in both coreboot and edk2; that would be a maintenance nightmare. Options are passed to edk2 using CFR structures, edk2 stores the values in the variable store in flash, and coreboot reads the option values using the EFI variable store backend. Change-Id: I47585a9a6f94ab5005f2ab63a0df267c0caef231 Signed-off-by: Angel Pons Reviewed-on: https://review.coreboot.org/c/coreboot/+/74122 Tested-by: build bot (Jenkins) Reviewed-by: Christian Walter --- src/mainboard/prodrive/atlas/Kconfig | 8 +- src/mainboard/prodrive/atlas/Makefile.mk | 1 + src/mainboard/prodrive/atlas/cfr.c | 264 ++++++++++++++++++ src/mainboard/prodrive/atlas/devicetree.cb | 3 - .../prodrive/atlas/ramstage_fsp_params.c | 13 + .../prodrive/atlas/romstage_fsp_params.c | 8 + 6 files changed, 287 insertions(+), 10 deletions(-) create mode 100644 src/mainboard/prodrive/atlas/cfr.c diff --git a/src/mainboard/prodrive/atlas/Kconfig b/src/mainboard/prodrive/atlas/Kconfig index b40e2b796b..cbd625cf4f 100644 --- a/src/mainboard/prodrive/atlas/Kconfig +++ b/src/mainboard/prodrive/atlas/Kconfig @@ -13,6 +13,7 @@ config BOARD_PRODRIVE_ATLAS_BASEBOARD select MEMORY_MAPPED_TPM select PCIEXP_SUPPORT_RESIZABLE_BARS select SOC_INTEL_ALDERLAKE_PCH_P + select DRIVERS_OPTION_CFR_ENABLED config BOARD_PRODRIVE_ATLAS select BOARD_PRODRIVE_ATLAS_BASEBOARD @@ -23,13 +24,6 @@ config ATLAS_ENABLE_SAGV bool "Enable SaGv" default n -config ATLAS_ENABLE_IBECC - bool "Enable IBECC" - help - Enables In Band Error Correction Code. It's only needed for endurance testing - and therefore not always required. - default n - config D3COLD_SUPPORT default n diff --git a/src/mainboard/prodrive/atlas/Makefile.mk b/src/mainboard/prodrive/atlas/Makefile.mk index b31f03a7fc..df7af1c0a1 100644 --- a/src/mainboard/prodrive/atlas/Makefile.mk +++ b/src/mainboard/prodrive/atlas/Makefile.mk @@ -8,6 +8,7 @@ bootblock-y += early_gpio.c romstage-y += romstage_fsp_params.c +ramstage-$(CONFIG_DRIVERS_OPTION_CFR) += cfr.c ramstage-y += gpio.c ramstage-y += mainboard.c ramstage-y += ramstage_fsp_params.c diff --git a/src/mainboard/prodrive/atlas/cfr.c b/src/mainboard/prodrive/atlas/cfr.c new file mode 100644 index 0000000000..f5700e2ba0 --- /dev/null +++ b/src/mainboard/prodrive/atlas/cfr.c @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpd.h" + +static void update_rt_perf(const struct sm_object *obj, struct sm_object *new) +{ + const bool rt_perf = get_emi_eeprom_vpd()->profile == ATLAS_PROF_REALTIME_PERFORMANCE; + + if (!rt_perf) + return; + + if (obj->kind == SM_OBJ_BOOL) { + new->sm_bool.flags = CFR_OPTFLAG_SUPPRESS; + new->sm_bool.default_value = false; + } else if (obj->kind == SM_OBJ_ENUM) { + new->sm_enum.flags = CFR_OPTFLAG_SUPPRESS; + new->sm_enum.default_value = 0; + } +} + +static void update_bad_profile(const struct sm_object *obj, struct sm_object *new) +{ + const bool pf_ok = get_emi_eeprom_vpd()->profile != 0; + + if (!pf_ok) + return; + new->sm_comment.flags |= CFR_OPTFLAG_SUPPRESS; +} + +static void update_serial(const struct sm_object *obj, struct sm_object *new) +{ + new->sm_varchar.default_value = get_emi_eeprom_vpd()->serial_number; +} + +static void update_part_number(const struct sm_object *obj, struct sm_object *new) +{ + new->sm_varchar.default_value = get_emi_eeprom_vpd()->part_number; +} + +static void update_profile(const struct sm_object *obj, struct sm_object *new) +{ + new->sm_number.default_value = get_emi_eeprom_vpd()->profile; +} + +/* TODO: Suppress option if carrier board is known to not have a RTC battery */ +static const struct sm_enum_value pwr_after_g3_values[] = { + { "Power off (S5)", MAINBOARD_POWER_STATE_OFF }, + { "Power on (S0)", MAINBOARD_POWER_STATE_ON }, + /* No support for previous/last power state */ + SM_ENUM_VALUE_END, +}; + +static const struct sm_object power_on_after_fail = SM_DECLARE_ENUM({ + .opt_name = "power_on_after_fail", + .ui_name = "Restore AC Power Loss", + .ui_helptext = "Specify what to do when power is re-applied " + "after a power loss. This option has no effect " + "on systems without a RTC battery.", + .default_value = CONFIG_MAINBOARD_POWER_FAILURE_STATE, + .values = pwr_after_g3_values, +}); + +static const struct sm_enum_value primary_display_values[] = { + { "Intel iGPU", 0 }, + { "CPU PEG dGPU", 1 }, + { "PCH PCIe dGPU", 2 }, + { "Auto", 3 }, + SM_ENUM_VALUE_END, +}; + +static const struct sm_object primary_display = SM_DECLARE_ENUM({ + .opt_name = "primary_display", + .ui_name = "Primary display device", + .ui_helptext = "Specify which display device to use as primary.", + .default_value = CONFIG(ONBOARD_VGA_IS_PRIMARY) ? 0 : 3, + .values = primary_display_values, +}); + +static const struct sm_enum_value pkg_c_state_limit_values[] = { + { "C0/C1", 0 }, + { "C2", 1 }, + { "C3", 2 }, + { "C6", 3 }, + { "C7", 4 }, + { "C7S", 5 }, + { "C8", 6 }, + { "C9", 7 }, + { "C10", 8 }, + { "Default", 254 }, + { "Auto", 255 }, + SM_ENUM_VALUE_END, +}; + +static const struct sm_object turbo_mode = SM_DECLARE_BOOL({ + .opt_name = "turbo_mode", + .ui_name = "Turbo Boost", + /* No help text */ + .default_value = true, +}); + +static const struct sm_object vmx = SM_DECLARE_BOOL({ + .opt_name = "vmx", + .ui_name = "Intel Virtualization Technology (VT-x)", + /* No help text */ + .default_value = false, +}); + +static const struct sm_object vtd = SM_DECLARE_BOOL({ + .opt_name = "vtd", + .ui_name = "Intel Virtualization Technology for Directed I/O (VT-d)", + /* No help text */ + .default_value = false, +}); + +static const struct sm_object ibecc = SM_DECLARE_BOOL({ + .opt_name = "ibecc", + .ui_name = "In-Band ECC", + .ui_helptext = "Specify whether In-Band error checking and " + "correction is to be enabled. Enabling this " + "option will reduce the amount of available " + "RAM because some memory is needed to store " + "ECC codes.", + .default_value = false, +}); + +static const struct sm_object serial_number = SM_DECLARE_VARCHAR({ + .flags = CFR_OPTFLAG_READONLY | CFR_OPTFLAG_VOLATILE, + .opt_name = "serial_number", + .ui_name = "Serial Number", +}, WITH_CALLBACK(update_serial)); + +static const struct sm_object part_number = SM_DECLARE_VARCHAR({ + .flags = CFR_OPTFLAG_READONLY | CFR_OPTFLAG_VOLATILE, + .opt_name = "part_number", + .ui_name = "Part Number", +}, WITH_CALLBACK(update_part_number)); + +static const struct sm_object bad_profile = SM_DECLARE_COMMENT({ + .flags = CFR_OPTFLAG_READONLY, + .ui_name = "WARNING: Profile code is invalid", +}, WITH_CALLBACK(update_bad_profile)); + +static const struct sm_object profile = SM_DECLARE_NUMBER({ + .flags = CFR_OPTFLAG_READONLY | CFR_OPTFLAG_VOLATILE, + .opt_name = "profile", + .ui_name = "Profile code", + .ui_helptext = "The profile code obtained from the EEPROM", +}, WITH_CALLBACK(update_profile)); + +static const struct sm_object energy_eff_turbo = SM_DECLARE_BOOL({ + .flags = 0, + .opt_name = "energy_eff_turbo", + .ui_name = "Energy Efficient Turbo", + /* No help text */ + .default_value = false, +}, WITH_CALLBACK(update_rt_perf)); + +static const struct sm_object pkg_c_state_limit = SM_DECLARE_ENUM({ + .flags = 0, + .opt_name = "pkg_c_state_limit", + .ui_name = "Package C-state limit", + .ui_helptext = "", /* TODO: write something */ + .default_value = 255, + .values = pkg_c_state_limit_values, +}, WITH_CALLBACK(update_rt_perf)); + +#define NUM_PCIE_SSC_SETTINGS 21 +static struct sm_enum_value pch_pm_pcie_pll_ssc_values[] = { + [NUM_PCIE_SSC_SETTINGS] = { "Auto", 0xff }, + SM_ENUM_VALUE_END, +}; + +static void update_pll_ssc_values(const struct sm_object *obj, struct sm_object *new) +{ + for (size_t i = 0; i < NUM_PCIE_SSC_SETTINGS; i++) { + char buffer[16]; + snprintf(buffer, sizeof(buffer), "%u.%u%%", i / 10, i % 10); + pch_pm_pcie_pll_ssc_values[i].ui_name = strdup(buffer); + pch_pm_pcie_pll_ssc_values[i].value = i; + } +} + +static const struct sm_object pch_pcie_pll_ssc = SM_DECLARE_ENUM({ + .opt_name = "pch_pcie_pll_ssc", + .ui_name = "PCH PCIe PLL Spread Spectrum Clocking", + /* No help text */ + .default_value = 0xff, + .values = pch_pm_pcie_pll_ssc_values, +}, WITH_CALLBACK(update_pll_ssc_values)); + +static const struct sm_object c_states = SM_DECLARE_BOOL({ + .flags = 0, + .opt_name = "c_states", + .ui_name = "CPU power states (C-states)", + .ui_helptext = "Specify whether C-states are supported.", + .default_value = true, +}, WITH_CALLBACK(update_rt_perf)); + +static const struct sm_object hyper_threading = SM_DECLARE_BOOL({ + .flags = 0, + .opt_name = "hyper_threading", + .ui_name = "Hyper-Threading Technology", + /* No help text */ + .default_value = true, +}, WITH_CALLBACK(update_rt_perf)); + +static struct sm_obj_form cpu = { + .ui_name = "CPU", + .obj_list = (const struct sm_object *[]) { + &c_states, + &hyper_threading, + &turbo_mode, + &energy_eff_turbo, + &vmx, + &vtd, + NULL + }, +}; + +static struct sm_obj_form main = { + .ui_name = "Main", + .obj_list = (const struct sm_object *[]) { + &serial_number, + &part_number, + &bad_profile, + &profile, + &power_on_after_fail, + &primary_display, + &pkg_c_state_limit, + &pch_pcie_pll_ssc, + &ibecc, + NULL + }, +}; + +static struct sm_obj_form *sm_root[] = { + &main, + &cpu, + NULL +}; + +/* + * TODO: Writing this by hand is extremely tedious. Introducing a DSL + * (Domain-Specific Language) to describe options which is translated + * into code at build time may be the way to go. Maybe expand SCONFIG + * so that these can be devicetree options? + */ +void lb_board(struct lb_header *header) +{ + char *current = (char *)lb_new_record(header); + struct lb_cfr *cfr_root = (struct lb_cfr *)current; + + cfr_write_setup_menu(cfr_root, sm_root); +} diff --git a/src/mainboard/prodrive/atlas/devicetree.cb b/src/mainboard/prodrive/atlas/devicetree.cb index 580ca7671d..baca59d576 100644 --- a/src/mainboard/prodrive/atlas/devicetree.cb +++ b/src/mainboard/prodrive/atlas/devicetree.cb @@ -52,9 +52,6 @@ chip soc/intel/alderlake register "usb3_ports[2]" = "USB3_PORT_DEFAULT(OC1)" register "usb3_ports[3]" = "USB3_PORT_DEFAULT(OC1)" - register "ibecc.enable" = "CONFIG(ATLAS_ENABLE_IBECC)" - register "ibecc.mode" = "CONFIG(ATLAS_ENABLE_IBECC) ? IBECC_MODE_ALL : IBECC_MODE_NONE" - register "sata_salp_support" = "1" register "sata_ports_enable" = "{ diff --git a/src/mainboard/prodrive/atlas/ramstage_fsp_params.c b/src/mainboard/prodrive/atlas/ramstage_fsp_params.c index e3c11e9127..786f345862 100644 --- a/src/mainboard/prodrive/atlas/ramstage_fsp_params.c +++ b/src/mainboard/prodrive/atlas/ramstage_fsp_params.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include "vpd.h" @@ -37,5 +38,17 @@ void mainboard_silicon_init_params(FSP_S_CONFIG *params) params->PmcV1p05PhyExtFetControlEn = 0; params->PmcV1p05IsExtFetControlEn = 0; break; + default: + if (get_uint_option("c_states", 1) == 0) { + params->Cx = 0; + params->C1e = 0; + params->C1StateUnDemotion = 0; + params->C1StateAutoDemotion = 0; + } + params->PkgCStateLimit = get_uint_option("pkg_c_state_limit", 255); + params->PchPmPciePllSsc = get_uint_option("pch_pcie_pll_ssc", 255); + params->EnergyEfficientTurbo = get_uint_option("energy_eff_turbo", 0); + params->TurboMode = get_uint_option("turbo_mode", 1); + break; } } diff --git a/src/mainboard/prodrive/atlas/romstage_fsp_params.c b/src/mainboard/prodrive/atlas/romstage_fsp_params.c index 7d3d9b51f3..4a4c48d355 100644 --- a/src/mainboard/prodrive/atlas/romstage_fsp_params.c +++ b/src/mainboard/prodrive/atlas/romstage_fsp_params.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include @@ -48,6 +49,13 @@ void mainboard_memory_init_params(FSPM_UPD *memupd) memcfg_init(memupd, mem_config, &dimm_module_spd_info, half_populated); + const unsigned int def_prim_display = CONFIG(ONBOARD_VGA_IS_PRIMARY) ? 0 : 3; + mcfg->PrimaryDisplay = get_uint_option("primary_display", def_prim_display); + mcfg->VmxEnable = get_uint_option("vmx", mcfg->VmxEnable); + mcfg->VtdDisable = !get_uint_option("vtd", !mcfg->VtdDisable); + mcfg->Ibecc = get_uint_option("ibecc", false); + mcfg->IbeccOperationMode = mcfg->Ibecc ? 2 : 0; + /* Apply profile-specific settings */ switch (get_emi_eeprom_vpd()->profile) { case ATLAS_PROF_REALTIME_PERFORMANCE: