diff options
author | Nico Huber <nico.huber@secunet.com> | 2012-10-02 11:46:11 +0200 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2012-11-06 21:52:44 +0100 |
commit | 68d7c7aa8ba8a8bc17b3cebf1b7086cf8a4fa94d (patch) | |
tree | 28132fff40728a7480718c5b1fc859d7073dda94 /src | |
parent | bf10bc3e44ae0d85a9db189c7c84e380a1ec8aa7 (diff) |
cpu/intel/model_1067x: Add proper c-state/p-state/thermal support
Change-Id: I853454e8f5617fb7af5dddd7288bdeeacc7b1b8e
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com>
Reviewed-on: http://review.coreboot.org/1663
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu/intel/model_1067x/chip.h | 24 | ||||
-rw-r--r-- | src/cpu/intel/model_1067x/model_1067x_init.c | 232 | ||||
-rw-r--r-- | src/cpu/intel/speedstep/Makefile.inc | 1 |
3 files changed, 226 insertions, 31 deletions
diff --git a/src/cpu/intel/model_1067x/chip.h b/src/cpu/intel/model_1067x/chip.h new file mode 100644 index 0000000000..1731c504de --- /dev/null +++ b/src/cpu/intel/model_1067x/chip.h @@ -0,0 +1,24 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +struct cpu_intel_model_1067x_config { + int c5 : 1; + int c6 : 1; + int slfm : 1; +}; diff --git a/src/cpu/intel/model_1067x/model_1067x_init.c b/src/cpu/intel/model_1067x/model_1067x_init.c index c6d716d958..2b7839be2c 100644 --- a/src/cpu/intel/model_1067x/model_1067x_init.c +++ b/src/cpu/intel/model_1067x/model_1067x_init.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2007-2009 coresystems GmbH + * 2012 secunet Security Networks AG * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +34,8 @@ #include <cpu/x86/cache.h> #include <cpu/x86/name.h> +#include "chip.h" + static const uint32_t microcode_updates[] = { #include "microcode-2618-m441067AA07.h" #include "microcode-2626-m1010677705.h" @@ -98,20 +101,45 @@ static void enable_vmx(void) #define PMG_CST_CONFIG_CONTROL 0xe2 #define PMG_IO_BASE_ADDR 0xe3 #define PMG_IO_CAPTURE_ADDR 0xe4 +#define MSR_BBL_CR_CTL3 0x11e +#define MSR_FSB_FREQ 0xcd -#define CST_RANGE 2 -static void configure_c_states(void) +static void configure_c_states(const int quad) { msr_t msr; - msr = rdmsr(PMG_CST_CONFIG_CONTROL); + /* Find pointer to CPU configuration. */ + const device_t lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC); + const struct cpu_intel_model_1067x_config *const conf = + (lapic && lapic->chip_info) ? lapic->chip_info : NULL; - msr.lo |= (1 << 15); // config lock until next reset - msr.lo |= (1 << 14); // Deeper Sleep - msr.lo |= (1 << 10); // Enable IO MWAIT redirection - msr.lo &= ~(1 << 9); // Issue a single stop grant cycle upon stpclk - msr.lo |= (1 << 3); // Dynamic L2 + /* Is C5 requested and supported? */ + const int c5 = conf && conf->c5 && + (rdmsr(MSR_BBL_CR_CTL3).lo & (3 << 30)) && + !(rdmsr(MSR_FSB_FREQ).lo & (1 << 31)); + /* Is C6 requested and supported? */ + const int c6 = conf && conf->c6 && + ((cpuid_edx(5) >> (6 * 4)) & 0xf) && c5; + const int cst_range = (c6 ? 6 : (c5 ? 5 : 4)) - 2; /* zero means lvl2 */ + + msr = rdmsr(PMG_CST_CONFIG_CONTROL); + msr.lo &= ~(1 << 9); // Issue a single stop grant cycle upon stpclk + msr.lo |= (1 << 8); + if (quad) { + msr.lo = (msr.lo & ~(7 << 0)) | (4 << 0); + } + if (c5) { + msr.lo &= ~(1 << 13); + msr.lo &= ~(7 << 0); + msr.lo |= (1 << 3); /* Enable dynamic L2. */ + msr.lo |= (1 << 14); /* Enable deeper sleep */ + } + /* Next two fields seem to be mutually exclusive: */ + msr.lo &= ~(7 << 4); + msr.lo |= (1 << 10); /* Enable IO MWAIT redirection. */ + if (c6) + msr.lo |= (1 << 25); wrmsr(PMG_CST_CONFIG_CONTROL, msr); /* Set Processor MWAIT IO BASE */ @@ -121,52 +149,160 @@ static void configure_c_states(void) /* Set IO Capture Address */ msr.hi = 0; - msr.lo = ((PMB0_BASE + 4) & 0xffff) | (( CST_RANGE & 0xffff) << 16); + msr.lo = ((PMB0_BASE + 4) & 0xffff) | ((cst_range & 0xffff) << 16); wrmsr(PMG_IO_CAPTURE_ADDR, msr); + + if (c5) { + msr = rdmsr(MSR_BBL_CR_CTL3); + msr.lo &= ~(7 << 25); + msr.lo |= (2 << 25); + msr.lo &= ~(3 << 30); + msr.lo |= (1 << 30); + wrmsr(MSR_BBL_CR_CTL3, msr); + } +} + +static void configure_p_states(const char stepping, const char cores) +{ + msr_t msr; + + /* Find pointer to CPU configuration. */ + const device_t lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC); + struct cpu_intel_model_1067x_config *const conf = + (lapic && lapic->chip_info) ? lapic->chip_info : NULL; + + msr = rdmsr(MSR_EXTENDED_CONFIG); + if (conf->slfm && (msr.lo & (1 << 27))) /* Super LFM supported? */ + msr.lo |= (1 << 28); /* Enable Super LFM. */ + wrmsr(MSR_EXTENDED_CONFIG, msr); + + if (rdmsr(MSR_FSB_CLOCK_VCC).hi & (1 << (63 - 32))) { + /* Turbo supported? */ + if ((stepping == 0xa) && (cores < 4)) { + msr = rdmsr(MSR_FSB_FREQ); + msr.lo |= (1 << 3); /* Enable hysteresis. */ + wrmsr(MSR_FSB_FREQ, msr); + } + msr = rdmsr(IA32_PERF_CTL); + msr.hi &= ~(1 << (32 - 32)); /* Clear turbo disable. */ + wrmsr(IA32_PERF_CTL, msr); + } + + msr = rdmsr(PMG_CST_CONFIG_CONTROL); + msr.lo &= ~(1 << 11); /* Enable hw coordination. */ + msr.lo |= (1 << 15); /* Lock config until next reset. */ + wrmsr(PMG_CST_CONFIG_CONTROL, msr); +} + +#define MSR_EMTTM_CR_TABLE(x) (0xa8 + (x)) +#define MSR_EMTTM_TABLE_NUM 6 +static void configure_emttm_tables(void) +{ + int i; + int num_states, pstate_idx; + msr_t msr; + sst_table_t pstates; + + /* Gather p-state information. */ + speedstep_gen_pstates(&pstates); + + /* Never turbo mode or Super LFM. */ + num_states = pstates.num_states; + if (pstates.states[0].is_turbo) + --num_states; + if (pstates.states[pstates.num_states - 1].is_slfm) + --num_states; + /* Repeat lowest p-state if we haven't enough states. */ + const int num_lowest_pstate = + (num_states < MSR_EMTTM_TABLE_NUM) + ? (MSR_EMTTM_TABLE_NUM - num_states) + 1 + : 1; + /* Start from the lowest entry but skip Super LFM. */ + if (pstates.states[pstates.num_states - 1].is_slfm) + pstate_idx = pstates.num_states - 2; + else + pstate_idx = pstates.num_states - 1; + for (i = 0; i < MSR_EMTTM_TABLE_NUM; ++i) { + if (i >= num_lowest_pstate) + --pstate_idx; + const sst_state_t *const pstate = &pstates.states[pstate_idx]; + printk(BIOS_DEBUG, "writing P-State %d: %d, %d, " + "%2d, 0x%02x, %d; encoded: 0x%04x\n", + pstate_idx, pstate->dynfsb, pstate->nonint, + pstate->ratio, pstate->vid, pstate->power, + SPEEDSTEP_ENCODE_STATE(*pstate)); + msr.hi = 0; + msr.lo = SPEEDSTEP_ENCODE_STATE(pstates.states[pstate_idx]) & + /* Don't set half ratios. */ + ~SPEEDSTEP_RATIO_NONINT; + wrmsr(MSR_EMTTM_CR_TABLE(i), msr); + } + + msr = rdmsr(MSR_EMTTM_CR_TABLE(5)); + msr.lo |= (1 << 31); /* lock tables */ + wrmsr(MSR_EMTTM_CR_TABLE(5), msr); } -#define IA32_MISC_ENABLE 0x1a0 -static void configure_misc(void) +static void configure_misc(const int eist, const int tm2, const int emttm) { msr_t msr; - msr = rdmsr(IA32_MISC_ENABLE); - msr.lo |= (1 << 3); /* TM1 enable */ - msr.lo |= (1 << 13); /* TM2 enable */ + const u32 sub_cstates = cpuid_edx(5); + + msr = rdmsr(IA32_MISC_ENABLES); + msr.lo |= (1 << 3); /* TM1 enable */ + if (tm2) + msr.lo |= (1 << 13); /* TM2 enable */ msr.lo |= (1 << 17); /* Bidirectional PROCHOT# */ + msr.lo |= (1 << 18); /* MONITOR/MWAIT enable */ msr.lo |= (1 << 10); /* FERR# multiplexing */ - // TODO: Only if IA32_PLATFORM_ID[17] = 0 and IA32_PLATFORM_ID[50] = 1 - msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */ + if (eist) + msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */ /* Enable C2E */ - msr.lo |= (1 << 26); + if (((sub_cstates >> (2 * 4)) & 0xf) >= 2) { + msr.lo |= (1 << 26); + } /* Enable C4E */ - /* TODO This should only be done on mobile CPUs, see cpuid 5 */ - msr.hi |= (1 << (32 - 32)); // C4E - msr.hi |= (1 << (33 - 32)); // Hard C4E + if (((sub_cstates >> (4 * 4)) & 0xf) >= 2) { + msr.hi |= (1 << (32 - 32)); // C4E + msr.hi |= (1 << (33 - 32)); // Hard C4E + } - /* Enable EMTTM. */ - /* NOTE: We leave the EMTTM_CR_TABLE0-5 at their default values */ - msr.hi |= (1 << (36 - 32)); + /* Enable EMTTM */ + if (emttm) + msr.hi |= (1 << (36 - 32)); - wrmsr(IA32_MISC_ENABLE, msr); + /* Enable turbo mode */ + if (rdmsr(MSR_FSB_CLOCK_VCC).hi & (1 << (63 - 32))) + msr.hi &= ~(1 << (38 - 32)); - msr.lo |= (1 << 20); /* Lock Enhanced SpeedStep Enable */ - wrmsr(IA32_MISC_ENABLE, msr); + wrmsr(IA32_MISC_ENABLES, msr); + + if (eist) { + msr.lo |= (1 << 20); /* Lock Enhanced SpeedStep Enable */ + wrmsr(IA32_MISC_ENABLES, msr); + } } #define PIC_SENS_CFG 0x1aa -static void configure_pic_thermal_sensors(void) +static void configure_pic_thermal_sensors(const int tm2, const int quad) { msr_t msr; msr = rdmsr(PIC_SENS_CFG); + if (quad) + msr.lo |= (1 << 31); + else + msr.lo &= ~(1 << 31); + if (tm2) + msr.lo |= (1 << 20); /* Enable TM1 if TM2 fails. */ msr.lo |= (1 << 21); // inter-core lock TM1 - msr.lo |= (1 << 4); // Enable bypass filter + msr.lo |= (1 << 4); // Enable bypass filter /* What does it do? */ wrmsr(PIC_SENS_CFG, msr); } @@ -179,6 +315,30 @@ static void model_1067x_init(device_t cpu) { char processor_name[49]; + + /* Gather some information: */ + + const struct cpuid_result cpuid1 = cpuid(1); + + /* Read stepping. */ + const char stepping = cpuid1.eax & 0xf; + /* Read number of cores. */ + const char cores = (cpuid1.ebx >> 16) & 0xf; + /* Is this a quad core? */ + const char quad = cores > 2; + /* Is this even a multiprocessor? */ + const char mp = cores > 1; + + /* Enable EMTTM on uni- and on multi-processors if it's not disabled. */ + const char emttm = !mp || !(rdmsr(MSR_EXTENDED_CONFIG).lo & 4); + + /* Is enhanced speedstep supported? */ + const char eist = (cpuid1.ecx & (1 << 7)) && + !(rdmsr(IA32_PLATFORM_ID).lo & (1 << 17)); + /* Test for TM2 only if EIST is available. */ + const char tm2 = eist && (cpuid1.ecx & (1 << 8)); + + /* Turn on caching if we haven't already */ x86_enable_cache(); @@ -214,13 +374,20 @@ static void model_1067x_init(device_t cpu) enable_vmx(); /* Configure C States */ - configure_c_states(); + configure_c_states(quad); + + /* Configure P States */ + configure_p_states(stepping, cores); + + /* EMTTM */ + if (emttm) + configure_emttm_tables(); /* Configure Enhanced SpeedStep and Thermal Sensors */ - configure_misc(); + configure_misc(eist, tm2, emttm); /* PIC thermal sensor control */ - configure_pic_thermal_sensors(); + configure_pic_thermal_sensors(tm2, quad); /* Start up my cpu siblings */ intel_sibling_init(cpu); @@ -242,3 +409,6 @@ static const struct cpu_driver driver __cpu_driver = { .id_table = cpu_table, }; +struct chip_operations cpu_intel_model_1067x_ops = { + CHIP_NAME("Intel Penryn CPU") +}; diff --git a/src/cpu/intel/speedstep/Makefile.inc b/src/cpu/intel/speedstep/Makefile.inc index 753dbcd6a9..130eb0c79d 100644 --- a/src/cpu/intel/speedstep/Makefile.inc +++ b/src/cpu/intel/speedstep/Makefile.inc @@ -1 +1,2 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c speedstep.c +ramstage-$(CONFIG_CPU_INTEL_MODEL_1067X) += speedstep.c |