From 62535b66e64ff72229645931a7f5a08147095fc7 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Sat, 30 Mar 2024 19:06:20 +0100 Subject: [PATCH] cpu/intel/model_206ax: Allow to configure VR settings Allow to set board specific CPU voltage regulator settings. The VR12 compatible voltage regulator for the CPU can be configured by two MSRs. Currently a default value is applied, which mimics the Intel reference code and is what the BWG suggest. However most board vendors fill in the actual VR parameters to support OC or ULV board variants. When the mainboard design is too different from the Intel reference design, not updating the VR settings might result in: - unstable system behaviour - limited turbo performance - excessive battery drain - no over-clocking capability This patch adds support to set the board specific current limit for Icc and Igfx. It also allows to adjust PSI1, PSI2 and PSI3, which are powerstates used by the VR, that consume less energy when the system is idle. Test on Lenovo X220 with full CPU load after 1 minute, compared to previous code with default settings: - Limiting PP0 max current below Iccmax results in less CPU performance. RAPL readings show that less power is drawn over time. - Limiting PP0 max current to Iccmax results in equal CPU performance. RAPL readings show that the same power is drawn over time. - Setting the PP0 max current to a value >> Iccmax results in equal CPU performance. RAPL readings show that the same power is drawn over time. - Updating the MSR at runtime has no effect. Change-Id: I59edab47fc4fbe0240e1dd7d25647f7549b4def2 Signed-off-by: Patrick Rudolph Reviewed-on: https://review.coreboot.org/c/coreboot/+/81597 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- src/cpu/intel/model_206ax/chip.h | 28 +++++++++++ src/cpu/intel/model_206ax/model_206ax_init.c | 69 ++++++++++++++++++++++++---- src/mainboard/lenovo/x220/devicetree.cb | 14 ++++++ 3 files changed, 102 insertions(+), 9 deletions(-) diff --git a/src/cpu/intel/model_206ax/chip.h b/src/cpu/intel/model_206ax/chip.h index 57e145eaf5..9080e2fa12 100644 --- a/src/cpu/intel/model_206ax/chip.h +++ b/src/cpu/intel/model_206ax/chip.h @@ -14,12 +14,40 @@ enum cpu_acpi_level { CPU_ACPI_C7S, }; +/* VR12 PSI codes */ +enum vr12_phases { + VR12_KEEP_DEFAULT = 0, /* For device-trees missing the setting */ + VR12_ALL_PHASES, + VR12_2_PHASES, + VR12_1_PHASE, + VR12_LIGHT_LOAD, +}; + +/* VR12 power state listing */ +enum vr12_psi { + VR12_PSI1 = 0, + VR12_PSI2, + VR12_PSI3, + VR12_PSI_MAX, +}; + +struct psi_state { + enum vr12_phases phases; + int current; /* In Amps */ +}; + struct cpu_intel_model_206ax_config { enum cpu_acpi_level acpi_c1; enum cpu_acpi_level acpi_c2; enum cpu_acpi_level acpi_c3; int tcc_offset; /* TCC Activation Offset */ + int pp0_current_limit; /* Primary Plane Current Limit (Icc) in Amps */ + int pp1_current_limit; /* Secondary Plane Current Limit (IAXG) in Amps */ + + /* PSI states only have an effect when in Package C3 or higher */ + struct psi_state pp0_psi[3]; /* Power states for Primary Plane (Icc) */ + struct psi_state pp1_psi[3]; /* Power states for Secondary Plane (IAXG) */ }; #endif /* __CPU_INTEL_MODEL_206AX_CHIP_H__ */ diff --git a/src/cpu/intel/model_206ax/model_206ax_init.c b/src/cpu/intel/model_206ax/model_206ax_init.c index d9340ff95d..cdec3a6f46 100644 --- a/src/cpu/intel/model_206ax/model_206ax_init.c +++ b/src/cpu/intel/model_206ax/model_206ax_init.c @@ -156,8 +156,9 @@ void set_power_limits(u8 power_limit_1_time) } } -static void configure_c_states(void) +static void configure_c_states(struct device *dev) { + struct cpu_intel_model_206ax_config *conf = dev->upstream->dev->chip_info; msr_t msr; msr = rdmsr(MSR_PKG_CST_CONFIG_CONTROL); @@ -202,20 +203,70 @@ static void configure_c_states(void) msr.lo = IRTL_VALID | IRTL_1024_NS | 0x6D; wrmsr(MSR_PKGC7_IRTL, msr); - /* Primary Plane Current Limit */ + /* Primary Plane Current Limit (Icc) */ msr = rdmsr(MSR_PP0_CURRENT_CONFIG); msr.lo &= ~0x1fff; - msr.lo |= PP0_CURRENT_LIMIT; + if (conf->pp0_current_limit) { + /* Fill in board specific maximum current supported by VR */ + msr.lo |= conf->pp0_current_limit * 8; + } else { + printk(BIOS_INFO, "%s: PP0 current limit not set in devicetree\n", dev_path(dev)); + /* + * The default value might over-stress the voltage regulator or + * prevent OC on boards with regulators that can handle currents + * above the Intel recommendation. + */ + msr.lo |= PP0_CURRENT_LIMIT; + } + for (int i = 0; i < VR12_PSI_MAX; i++) { + /* + * Light load optimization. Depending on the VR output filter the + * number of phases can be reduced at light load. This is a board + * specific setting. + */ + if (conf->pp0_psi[i].phases != VR12_KEEP_DEFAULT) { + msr.hi &= ~(0x3ff << (i * 10)); + msr.hi |= (conf->pp0_psi[i].phases - 1) << (i * 10 + 7); + msr.hi |= conf->pp0_psi[i].current << (i * 10); + } else { + printk(BIOS_INFO, "%s: PP0 PSI%d not set in devicetree\n", dev_path(dev), i); + } + } msr.lo |= PP0_CURRENT_LIMIT_LOCK; wrmsr(MSR_PP0_CURRENT_CONFIG, msr); - /* Secondary Plane Current Limit */ + /* Secondary Plane Current Limit (IAXG) */ msr = rdmsr(MSR_PP1_CURRENT_CONFIG); msr.lo &= ~0x1fff; - if (IS_IVY_CPU(cpu_get_cpuid())) - msr.lo |= PP1_CURRENT_LIMIT_IVB; - else - msr.lo |= PP1_CURRENT_LIMIT_SNB; + if (conf->pp1_current_limit) { + /* Fill in board specific maximum current supported by VR */ + msr.lo |= conf->pp1_current_limit * 8; + } else { + printk(BIOS_INFO, "%s: PP1 current limit not set in devicetree\n", dev_path(dev)); + /* + * The default value might over-stress the voltage regulator or + * prevent OC on boards with regulators that can handle currents + * above the Intel recommendation. + */ + if (IS_IVY_CPU(cpu_get_cpuid())) + msr.lo |= PP1_CURRENT_LIMIT_IVB; + else + msr.lo |= PP1_CURRENT_LIMIT_SNB; + } + for (int i = 0; i < VR12_PSI_MAX; i++) { + /* + * Light load optimization. Depending on the VR output filter the + * number of phases can be reduced at light load. This is a board + * specific setting. + */ + if (conf->pp1_psi[i].phases != VR12_KEEP_DEFAULT) { + msr.hi &= ~(0x3ff << (i * 10)); + msr.hi |= (conf->pp1_psi[i].phases - 1) << (i * 10 + 7); + msr.hi |= conf->pp1_psi[i].current << (i * 10); + } else { + printk(BIOS_INFO, "%s: PP1 PSI%d not set in devicetree\n", dev_path(dev), i); + } + } msr.lo |= PP1_CURRENT_LIMIT_LOCK; wrmsr(MSR_PP1_CURRENT_CONFIG, msr); } @@ -354,7 +405,7 @@ static void model_206ax_init(struct device *cpu) set_vmx_and_lock(); /* Configure C States */ - configure_c_states(); + configure_c_states(cpu); /* Configure Enhanced SpeedStep and Thermal Sensors */ configure_misc(); diff --git a/src/mainboard/lenovo/x220/devicetree.cb b/src/mainboard/lenovo/x220/devicetree.cb index 233f69082f..dc2f4a5858 100644 --- a/src/mainboard/lenovo/x220/devicetree.cb +++ b/src/mainboard/lenovo/x220/devicetree.cb @@ -35,6 +35,20 @@ chip northbridge/intel/sandybridge { 1, 7, 0x0080 }, { 1, 6, 0x0080 },}" + chip cpu/intel/model_206ax + # Values obtained from vendor BIOS v1.46 + # schematics say 33Amps for 17W TDP, 53Amps for 35W TDP + register "pp0_current_limit" = "98" + # schematics say 33Amps for GFX + register "pp1_current_limit" = "33" + register "pp0_psi[VR12_PSI1]" = "{VR12_2_PHASES, 20}" + register "pp0_psi[VR12_PSI2]" = "{VR12_ALL_PHASES, 5}" + register "pp0_psi[VR12_PSI3]" = "{VR12_ALL_PHASES, 1}" + register "pp1_psi[VR12_PSI1]" = "{VR12_2_PHASES, 20}" + register "pp1_psi[VR12_PSI2]" = "{VR12_ALL_PHASES, 5}" + register "pp1_psi[VR12_PSI3]" = "{VR12_ALL_PHASES, 1}" + device cpu_cluster 0 on end + end device domain 0 on subsystemid 0x17aa 0x21db inherit -- 2.11.4.GIT