Sumeet R Pawnikar has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30907
Change subject: soc/intel/cannonlake: Add processor power limits control support ......................................................................
soc/intel/cannonlake: Add processor power limits control support
Add processor power limits control support to configure values.
BRANCH=None BUG=b:122343940 TEST=Built and tested on Arcada system
Change-Id: I5990dc05b51481a0074855914cef20cf07378cde Signed-off-by: Sumeet Pawnikar sumeet.r.pawnikar@intel.com --- M src/soc/intel/cannonlake/chip.h M src/soc/intel/cannonlake/cpu.c M src/soc/intel/cannonlake/include/soc/msr.h M src/soc/intel/cannonlake/systemagent.c 4 files changed, 220 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/07/30907/1
diff --git a/src/soc/intel/cannonlake/chip.h b/src/soc/intel/cannonlake/chip.h index 6517b9e..63cbaf7 100644 --- a/src/soc/intel/cannonlake/chip.h +++ b/src/soc/intel/cannonlake/chip.h @@ -197,8 +197,22 @@ /* HeciEnabled decides the state of Heci1 at end of boot * Setting to 0 (default) disables Heci1 and hides the device from OS */ uint8_t HeciEnabled; + + /* PL1 Override value in Watts */ + uint32_t tdp_pl1_override; /* PL2 Override value in Watts */ uint32_t tdp_pl2_override; + /* SysPL2 Value in Watts */ + uint32_t tdp_psyspl2; + /* SysPL3 Value in Watts */ + uint32_t tdp_psyspl3; + /* SysPL3 window size */ + uint32_t tdp_psyspl3_time; + /* SysPL3 duty cycle */ + uint32_t tdp_psyspl3_dutycycle; + /* PL4 Value in Watts */ + uint32_t tdp_pl4; + /* Intel Speed Shift Technology */ uint8_t speed_shift_enable; /* Enable VR specific mailbox command diff --git a/src/soc/intel/cannonlake/cpu.c b/src/soc/intel/cannonlake/cpu.c index 9601863..8f83db6 100644 --- a/src/soc/intel/cannonlake/cpu.c +++ b/src/soc/intel/cannonlake/cpu.c @@ -30,6 +30,198 @@ #include <soc/pci_devs.h> #include <soc/pm.h> #include <soc/smm.h> +#include <soc/systemagent.h> + +/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */ +static const u8 power_limit_time_sec_to_msr[] = { + [0] = 0x00, + [1] = 0x0a, + [2] = 0x0b, + [3] = 0x4b, + [4] = 0x0c, + [5] = 0x2c, + [6] = 0x4c, + [7] = 0x6c, + [8] = 0x0d, + [10] = 0x2d, + [12] = 0x4d, + [14] = 0x6d, + [16] = 0x0e, + [20] = 0x2e, + [24] = 0x4e, + [28] = 0x6e, + [32] = 0x0f, + [40] = 0x2f, + [48] = 0x4f, + [56] = 0x6f, + [64] = 0x10, + [80] = 0x30, + [96] = 0x50, + [112] = 0x70, + [128] = 0x11, +}; + +/* Convert POWER_LIMIT_1_TIME MSR value to seconds */ +static const u8 power_limit_time_msr_to_sec[] = { + [0x00] = 0, + [0x0a] = 1, + [0x0b] = 2, + [0x4b] = 3, + [0x0c] = 4, + [0x2c] = 5, + [0x4c] = 6, + [0x6c] = 7, + [0x0d] = 8, + [0x2d] = 10, + [0x4d] = 12, + [0x6d] = 14, + [0x0e] = 16, + [0x2e] = 20, + [0x4e] = 24, + [0x6e] = 28, + [0x0f] = 32, + [0x2f] = 40, + [0x4f] = 48, + [0x6f] = 56, + [0x10] = 64, + [0x30] = 80, + [0x50] = 96, + [0x70] = 112, + [0x11] = 128, +}; + +/* + * Configure processor power limits if possible + * This must be done AFTER set of BIOS_RESET_CPL + */ +void set_power_limits(u8 power_limit_1_time) +{ + msr_t msr = rdmsr(MSR_PLATFORM_INFO); + msr_t limit; + unsigned int power_unit; + unsigned int tdp, min_power, max_power, max_time, tdp_pl2, tdp_pl1; + u8 power_limit_1_val; + struct device *dev = SA_DEV_ROOT; + config_t *conf = dev->chip_info; + + if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr)) + power_limit_1_time = 28; + + if (!(msr.lo & PLATFORM_INFO_SET_TDP)) + return; + + /* Get units */ + msr = rdmsr(MSR_PKG_POWER_SKU_UNIT); + power_unit = 1 << (msr.lo & 0xf); + + /* Get power defaults for this SKU */ + msr = rdmsr(MSR_PKG_POWER_SKU); + tdp = msr.lo & 0x7fff; + min_power = (msr.lo >> 16) & 0x7fff; + max_power = msr.hi & 0x7fff; + max_time = (msr.hi >> 16) & 0x7f; + + printk(BIOS_DEBUG, "CPU TDP: %u Watts\n", tdp / power_unit); + + if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time) + power_limit_1_time = power_limit_time_msr_to_sec[max_time]; + + if (min_power > 0 && tdp < min_power) + tdp = min_power; + + if (max_power > 0 && tdp > max_power) + tdp = max_power; + + power_limit_1_val = power_limit_time_sec_to_msr[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)); + limit.lo |= (tdp_pl1 & PKG_POWER_LIMIT_MASK); + + /* Set PL1 Pkg Power clamp bit */ + limit.lo |= PKG_POWER_LIMIT_CLAMP; + + limit.lo |= PKG_POWER_LIMIT_EN; + limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) << + PKG_POWER_LIMIT_TIME_SHIFT; + + /* 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); + printk(BIOS_DEBUG, "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; + + /* Power limit 2 time is only programmable on server SKU */ + wrmsr(MSR_PKG_POWER_LIMIT, limit); + + /* Set PL2 power limit values in MCHBAR and disable PL1 */ + MCHBAR32(MCH_PKG_POWER_LIMIT_LO) = limit.lo & (~(PKG_POWER_LIMIT_EN)); + MCHBAR32(MCH_PKG_POWER_LIMIT_HI) = limit.hi; + + /* Set PsysPl2 */ + if (conf->tdp_psyspl2) { + limit = rdmsr(MSR_PLATFORM_POWER_LIMIT); + limit.hi = 0; + printk(BIOS_DEBUG, "CPU PsysPL2 = %u Watts\n", + conf->tdp_psyspl2); + limit.hi |= (conf->tdp_psyspl2 * power_unit) & + PKG_POWER_LIMIT_MASK; + limit.hi |= PKG_POWER_LIMIT_CLAMP; + limit.hi |= PKG_POWER_LIMIT_EN; + + wrmsr(MSR_PLATFORM_POWER_LIMIT, limit); + } + + /* Set PsysPl3 */ + if (conf->tdp_psyspl3) { + limit = rdmsr(MSR_PL3_CONTROL); + limit.lo = 0; + printk(BIOS_DEBUG, "CPU PsysPL3 = %u Watts\n", + conf->tdp_psyspl3); + limit.lo |= (conf->tdp_psyspl3 * power_unit) & + PKG_POWER_LIMIT_MASK; + /* Enable PsysPl3 */ + limit.lo |= PKG_POWER_LIMIT_EN; + /* set PsysPl3 time window */ + limit.lo |= (conf->tdp_psyspl3_time & + PKG_POWER_LIMIT_TIME_MASK) << + PKG_POWER_LIMIT_TIME_SHIFT; + /* set PsysPl3 duty cycle */ + limit.lo |= (conf->tdp_psyspl3_dutycycle & + PKG_POWER_LIMIT_DUTYCYCLE_MASK) << + PKG_POWER_LIMIT_DUTYCYCLE_SHIFT; + wrmsr(MSR_PL3_CONTROL, limit); + } + + /* Set Pl4 */ + if (conf->tdp_pl4) { + limit = rdmsr(MSR_VR_CURRENT_CONFIG); + limit.lo = 0; + printk(BIOS_DEBUG, "CPU PL4 = %u Watts\n", + conf->tdp_pl4); + limit.lo |= (conf->tdp_pl4 * power_unit) & + PKG_POWER_LIMIT_MASK; + wrmsr(MSR_VR_CURRENT_CONFIG, limit); + } + + /* Set DDR RAPL power limit by copying from MMIO to MSR */ + msr.lo = MCHBAR32(MCH_DDR_POWER_LIMIT_LO); + msr.hi = MCHBAR32(MCH_DDR_POWER_LIMIT_HI); + wrmsr(MSR_DDR_RAPL_LIMIT, msr); + + /* Use nominal TDP values for CPUs with configurable TDP */ + if (cpu_config_tdp_levels()) { + msr = rdmsr(MSR_CONFIG_TDP_NOMINAL); + limit.hi = 0; + limit.lo = cpu_get_tdp_nominal_ratio(); + wrmsr(MSR_TURBO_ACTIVATION_RATIO, limit); + } +}
static void soc_fsp_load(void) { @@ -65,6 +257,10 @@ static void configure_misc(void) { struct device *dev = SA_DEV_ROOT; + if (!dev) { + printk(BIOS_ERR, "SA_DEV_ROOT device not found!\n"); + return; + } config_t *conf = dev->chip_info; msr_t msr;
diff --git a/src/soc/intel/cannonlake/include/soc/msr.h b/src/soc/intel/cannonlake/include/soc/msr.h index e3bd5f6..63595f3 100644 --- a/src/soc/intel/cannonlake/include/soc/msr.h +++ b/src/soc/intel/cannonlake/include/soc/msr.h @@ -20,6 +20,9 @@ #include <intelblocks/msr.h>
#define MSR_PIC_MSG_CONTROL 0x2e +#define MSR_VR_CURRENT_CONFIG 0x601 +#define MSR_PL3_CONTROL 0x615 #define MSR_VR_MISC_CONFIG2 0x636 +#define MSR_PLATFORM_POWER_LIMIT 0x65c
#endif diff --git a/src/soc/intel/cannonlake/systemagent.c b/src/soc/intel/cannonlake/systemagent.c index e6310c0..26f8d9e 100644 --- a/src/soc/intel/cannonlake/systemagent.c +++ b/src/soc/intel/cannonlake/systemagent.c @@ -16,8 +16,10 @@ */
#include <device/device.h> +#include <delay.h> #include <device/pci.h> #include <intelblocks/systemagent.h> +#include <soc/cpu.h> #include <soc/iomap.h> #include <soc/systemagent.h>
@@ -52,6 +54,7 @@
sa_add_fixed_mmio_resources(dev, index, soc_fixed_resources, ARRAY_SIZE(soc_fixed_resources)); + }
/* @@ -66,4 +69,8 @@
/* Enable BIOS Reset CPL */ enable_bios_reset_cpl(); + + /* Configure turbo power limits 1ms after reset complete bit */ + mdelay(1); + set_power_limits(28); }
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/30907 )
Change subject: soc/intel/cannonlake: Add processor power limits control support ......................................................................
Patch Set 1:
(7 comments)
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h File src/soc/intel/cannonlake/chip.h:
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h@206 PS1, Line 206: uint32_t tdp_psyspl2; code indent should use tabs where possible
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h@206 PS1, Line 206: uint32_t tdp_psyspl2; please, no spaces at the start of a line
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h@208 PS1, Line 208: uint32_t tdp_psyspl3; code indent should use tabs where possible
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h@208 PS1, Line 208: uint32_t tdp_psyspl3; please, no spaces at the start of a line
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h@209 PS1, Line 209: /* SysPL3 window size */ code indent should use tabs where possible
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h@210 PS1, Line 210: uint32_t tdp_psyspl3_time; code indent should use tabs where possible
https://review.coreboot.org/#/c/30907/1/src/soc/intel/cannonlake/chip.h@210 PS1, Line 210: uint32_t tdp_psyspl3_time; please, no spaces at the start of a line
Hello Patrick Rudolph, build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/30907
to look at the new patch set (#2).
Change subject: soc/intel/cannonlake: Add processor power limits control support ......................................................................
soc/intel/cannonlake: Add processor power limits control support
Add processor power limits control support to configure values.
BRANCH=None BUG=b:122343940 TEST=Built and tested on Arcada system
Change-Id: I5990dc05b51481a0074855914cef20cf07378cde Signed-off-by: Sumeet Pawnikar sumeet.r.pawnikar@intel.com --- M src/soc/intel/cannonlake/chip.h M src/soc/intel/cannonlake/cpu.c M src/soc/intel/cannonlake/include/soc/msr.h M src/soc/intel/cannonlake/systemagent.c 4 files changed, 220 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/07/30907/2
Duncan Laurie has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/30907 )
Change subject: soc/intel/cannonlake: Add processor power limits control support ......................................................................
Patch Set 2:
(1 comment)
it would be nice to generalize this across big core devices but I don't know if that is premature given future platforms that may change these fields..
https://review.coreboot.org/#/c/30907/2/src/soc/intel/cannonlake/systemagent... File src/soc/intel/cannonlake/systemagent.c:
https://review.coreboot.org/#/c/30907/2/src/soc/intel/cannonlake/systemagent... PS2, Line 57: extra newline
Sumeet R Pawnikar has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/30907 )
Change subject: soc/intel/cannonlake: Add processor power limits control support ......................................................................
Patch Set 2:
Patch Set 2:
(1 comment)
it would be nice to generalize this across big core devices but I don't know if that is premature given future platforms that may change these fields..
Currently, common implementation for this is not tested across multiple platforms. We will look into generalizing this during ICL/upcoming platform.