diff options
-rw-r--r-- | src/cpu/intel/model_206ax/chip.h | 28 | ||||
-rw-r--r-- | src/cpu/intel/model_206ax/model_206ax_init.c | 69 | ||||
-rw-r--r-- | 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 |