diff --git a/src/cpu/intel/model_206ax/acpi.c b/src/cpu/intel/model_206ax/acpi.c index 5d3f3a02bb..7b495558d4 100644 --- a/src/cpu/intel/model_206ax/acpi.c +++ b/src/cpu/intel/model_206ax/acpi.c @@ -229,7 +229,16 @@ static int generate_P_state_entries(int core, int cores_per_package) /* Get bus ratio limits and calculate clock speeds */ msr = rdmsr(MSR_PLATFORM_INFO); ratio_min = (msr.hi >> (40-32)) & 0xff; /* Max Efficiency Ratio */ - ratio_max = (msr.lo >> 8) & 0xff; /* Max Non-Turbo Ratio */ + + /* Determine if this CPU has configurable TDP */ + if (cpu_config_tdp_levels()) { + /* Set max ratio to nominal TDP ratio */ + msr = rdmsr(MSR_CONFIG_TDP_NOMINAL); + ratio_max = msr.lo & 0xff; + } else { + /* Max Non-Turbo Ratio */ + ratio_max = (msr.lo >> 8) & 0xff; + } clock_max = ratio_max * SANDYBRIDGE_BCLK; /* Calculate CPU TDP in mW */ diff --git a/src/cpu/intel/model_206ax/model_206ax.h b/src/cpu/intel/model_206ax/model_206ax.h index 3343d1129b..d482ff0108 100644 --- a/src/cpu/intel/model_206ax/model_206ax.h +++ b/src/cpu/intel/model_206ax/model_206ax.h @@ -81,6 +81,13 @@ #define MSR_PP0_POWER_LIMIT 0x638 #define MSR_PP1_POWER_LIMIT 0x640 +#define IVB_CONFIG_TDP_MIN_CPUID 0x306a2 +#define MSR_CONFIG_TDP_NOMINAL 0x648 +#define MSR_CONFIG_TDP_LEVEL1 0x649 +#define MSR_CONFIG_TDP_LEVEL2 0x64a +#define MSR_CONFIG_TDP_CONTROL 0x64b +#define MSR_TURBO_ACTIVATION_RATIO 0x64c + /* P-state configuration */ #define PSS_MAX_ENTRIES 8 #define PSS_RATIO_STEP 2 @@ -93,6 +100,7 @@ void intel_model_206ax_finalize_smm(void); #else /* Configure power limits for turbo mode */ void set_power_limits(u8 power_limit_1_time); +int cpu_config_tdp_levels(void); #endif #endif diff --git a/src/cpu/intel/model_206ax/model_206ax_init.c b/src/cpu/intel/model_206ax/model_206ax_init.c index 87bc585d86..0958fe366e 100644 --- a/src/cpu/intel/model_206ax/model_206ax_init.c +++ b/src/cpu/intel/model_206ax/model_206ax_init.c @@ -179,6 +179,19 @@ static const u8 power_limit_time_msr_to_sec[] = { [0x11] = 128, }; +int cpu_config_tdp_levels(void) +{ + msr_t platform_info; + + /* Minimum CPU revision */ + if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID) + return 0; + + /* Bits 34:33 indicate how many levels supported */ + platform_info = rdmsr(MSR_PLATFORM_INFO); + return (platform_info.hi >> 1) & 3; +} + /* * Configure processor power limits if possible * This must be done AFTER set of BIOS_RESET_CPL @@ -235,6 +248,14 @@ void set_power_limits(u8 power_limit_1_time) /* Power limit 2 time is only programmable on SNB EP/EX */ wrmsr(MSR_PKG_POWER_LIMIT, limit); + + /* 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 = msr.lo & 0xff; + wrmsr(MSR_TURBO_ACTIVATION_RATIO, limit); + } } static void configure_c_states(void) @@ -340,16 +361,24 @@ static void configure_dca_cap(void) static void set_max_ratio(void) { - msr_t msr; + msr_t msr, perf_ctl; - /* Platform Info bits 15:8 give max ratio */ - msr = rdmsr(MSR_PLATFORM_INFO); - msr.hi = 0; - msr.lo &= 0xff00; - wrmsr(IA32_PERF_CTL, msr); + perf_ctl.hi = 0; + + /* Check for configurable TDP option */ + if (cpu_config_tdp_levels()) { + /* Set to nominal TDP ratio */ + msr = rdmsr(MSR_CONFIG_TDP_NOMINAL); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else { + /* Platform Info bits 15:8 give max ratio */ + msr = rdmsr(MSR_PLATFORM_INFO); + perf_ctl.lo = msr.lo & 0xff00; + } + wrmsr(IA32_PERF_CTL, perf_ctl); printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n", - ((msr.lo >> 8) & 0xff) * 100); + ((perf_ctl.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK); } static void set_energy_perf_bias(u8 policy) diff --git a/src/northbridge/intel/sandybridge/northbridge.c b/src/northbridge/intel/sandybridge/northbridge.c index 756aacfbb4..baf4348f96 100644 --- a/src/northbridge/intel/sandybridge/northbridge.c +++ b/src/northbridge/intel/sandybridge/northbridge.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -403,6 +404,16 @@ static void northbridge_init(struct device *dev) mdelay(1); set_power_limits(28); + /* + * CPUs with configurable TDP also need power limits set + * in MCHBAR. Use same values from MSR_PKG_POWER_LIMIT. + */ + if (cpu_config_tdp_levels()) { + msr_t msr = rdmsr(MSR_PKG_POWER_LIMIT); + MCHBAR32(0x59A0) = msr.lo; + MCHBAR32(0x59A4) = msr.hi; + } + /* Set here before graphics PM init */ MCHBAR32(0x5500) = 0x00100001; }