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 <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/74122
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Christian Walter <christian.walter@9elements.com>
This commit is contained in:
Angel Pons 2023-03-30 23:56:51 +02:00 committed by Lean Sheng Tan
commit 97923aebe1
6 changed files with 287 additions and 10 deletions

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,264 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <boot/coreboot_tables.h>
#include <commonlib/coreboot_tables.h>
#include <drivers/option/cfr_frontend.h>
#include <intelblocks/pmclib.h>
#include <inttypes.h>
#include <soc/pm.h>
#include <stdio.h>
#include <string.h>
#include <types.h>
#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);
}

View file

@ -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" = "{

View file

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <option.h>
#include <soc/ramstage.h>
#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;
}
}

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <fsp/api.h>
#include <option.h>
#include <soc/romstage.h>
#include <soc/meminit.h>
@ -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: