summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cpu/intel/model_206ax/chip.h28
-rw-r--r--src/cpu/intel/model_206ax/model_206ax_init.c69
-rw-r--r--src/mainboard/lenovo/x220/devicetree.cb14
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