soc/intel/common/power_limit: Add option-driven PL1/PL2 overrides and locking

Add option-backed overrides for PL1 and PL2, to allow for runtime
configuration, with fallback to board programmed values. Clamp PL2
to at least PL1.

Add an option to control setting the lock bit, to prevent OS or user
tools from overriding the desired power limits.

Add a CFR object for setting the lock bit, but not for the PL1/2
overrides, as the desired values there are board specific.

TEST=tested with rest of patch train

Change-Id: I7194df93e0602b4e00d1d39e44cb0b0ed2582cb9
Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/91846
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Aralguppe, Sowmya <sowmya.aralguppe@intel.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Jérémy Compostella <jeremy.compostella@intel.com>
This commit is contained in:
Matt DeVillier 2026-03-24 14:37:56 -05:00
commit bdf757aa86
3 changed files with 22 additions and 4 deletions

View file

@ -184,4 +184,12 @@ static const struct sm_object bios_lock = SM_DECLARE_BOOL({
.default_value = CONFIG(BOOTMEDIA_SMM_BWP),
}, WITH_CALLBACK(update_smm_bwp));
static const struct sm_object pkg_power_limit_lock = SM_DECLARE_BOOL({
.opt_name = "pkg_power_limit_lock",
.ui_name = "Package power limit lock",
.ui_helptext = "Lock the package power limits after programming.\n"
"This prevents the power limits from being changed by the OS or runtime tools.",
.default_value = false,
});
#endif /* SOC_INTEL_CMN_CFR_H */

View file

@ -101,6 +101,7 @@
#define PKG_POWER_LIMIT_TIME_MASK (0x7f)
#define PKG_POWER_LIMIT_DUTYCYCLE_SHIFT 24
#define PKG_POWER_LIMIT_DUTYCYCLE_MASK (0x7f)
#define PKG_POWER_LIMIT_LOCK (1 << 31)
#define MSR_CORE_MKTME_ACTIVATION 0x9ff
/* SMM save state MSRs */

View file

@ -6,6 +6,7 @@
#include <drivers/intel/dptf/chip.h>
#include <intelblocks/cpulib.h>
#include <intelblocks/power_limit.h>
#include <option.h>
#include <soc/msr.h>
#include <soc/pci_devs.h>
#include <soc/soc_chip.h>
@ -141,8 +142,8 @@ void set_power_limits(u8 power_limit_1_time,
/* Set long term power limit to TDP */
limit.lo = 0;
tdp_pl1 = ((conf->tdp_pl1_override == 0) ?
tdp : (conf->tdp_pl1_override * power_unit));
const unsigned int tdp_pl1_override = get_uint_option("tdp_pl1_override", conf->tdp_pl1_override);
tdp_pl1 = tdp_pl1_override ? (tdp_pl1_override * power_unit) : tdp;
printk(BIOS_INFO, "CPU PL1 = %u Watts\n", tdp_pl1 / power_unit);
limit.lo |= (tdp_pl1 & PKG_POWER_LIMIT_MASK);
@ -155,13 +156,21 @@ void set_power_limits(u8 power_limit_1_time,
/* Set short term power limit to 1.25 * TDP if no config given */
limit.hi = 0;
tdp_pl2 = (conf->tdp_pl2_override == 0) ?
(tdp * 125) / 100 : (conf->tdp_pl2_override * power_unit);
const unsigned int tdp_pl2_override = get_uint_option("tdp_pl2_override", conf->tdp_pl2_override);
tdp_pl2 = tdp_pl2_override ? (tdp_pl2_override * power_unit) : ((tdp * 125) / 100);
/* Ensure PL2 isn't less than PL1 */
if (tdp_pl2 < tdp_pl1)
tdp_pl2 = tdp_pl1;
printk(BIOS_INFO, "CPU PL2 = %u Watts\n", tdp_pl2 / power_unit);
limit.hi |= (tdp_pl2) & PKG_POWER_LIMIT_MASK;
limit.hi |= PKG_POWER_LIMIT_CLAMP;
limit.hi |= PKG_POWER_LIMIT_EN;
if (get_uint_option("pkg_power_limit_lock", 0)) {
limit.hi |= PKG_POWER_LIMIT_LOCK;
printk(BIOS_INFO, "Locking package power limits\n");
}
/* Power limit 2 time is only programmable on server SKU */
wrmsr(MSR_PKG_POWER_LIMIT, limit);