x86: Add Intel speedstep and turbo mode code
Intel chips have a turbo mode where they can run faster for a short period until they reach thermal limits. Add code to adjust and query this feature. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
		
							parent
							
								
									a6d4c45306
								
							
						
					
					
						commit
						18739e2ccc
					
				|  | @ -16,3 +16,4 @@ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ | |||
| obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ | ||||
| obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ | ||||
| obj-$(CONFIG_PCI) += pci.o | ||||
| obj-y += turbo.o | ||||
|  |  | |||
|  | @ -0,0 +1,98 @@ | |||
| /*
 | ||||
|  * From Coreboot file of the same name | ||||
|  * | ||||
|  * Copyright (C) 2011 The Chromium Authors. | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0 | ||||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <asm/cpu.h> | ||||
| #include <asm/msr.h> | ||||
| #include <asm/processor.h> | ||||
| #include <asm/turbo.h> | ||||
| 
 | ||||
| #if CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED | ||||
| static inline int get_global_turbo_state(void) | ||||
| { | ||||
| 	return TURBO_UNKNOWN; | ||||
| } | ||||
| 
 | ||||
| static inline void set_global_turbo_state(int state) | ||||
| { | ||||
| } | ||||
| #else | ||||
| static int g_turbo_state = TURBO_UNKNOWN; | ||||
| 
 | ||||
| static inline int get_global_turbo_state(void) | ||||
| { | ||||
| 	return g_turbo_state; | ||||
| } | ||||
| 
 | ||||
| static inline void set_global_turbo_state(int state) | ||||
| { | ||||
| 	g_turbo_state = state; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static const char *const turbo_state_desc[] = { | ||||
| 	[TURBO_UNKNOWN]		= "unknown", | ||||
| 	[TURBO_UNAVAILABLE]	= "unavailable", | ||||
| 	[TURBO_DISABLED]	= "available but hidden", | ||||
| 	[TURBO_ENABLED]		= "available and visible" | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Determine the current state of Turbo and cache it for later. | ||||
|  * Turbo is a package level config so it does not need to be | ||||
|  * enabled on every core. | ||||
|  */ | ||||
| int turbo_get_state(void) | ||||
| { | ||||
| 	struct cpuid_result cpuid_regs; | ||||
| 	int turbo_en, turbo_cap; | ||||
| 	msr_t msr; | ||||
| 	int turbo_state = get_global_turbo_state(); | ||||
| 
 | ||||
| 	/* Return cached state if available */ | ||||
| 	if (turbo_state != TURBO_UNKNOWN) | ||||
| 		return turbo_state; | ||||
| 
 | ||||
| 	cpuid_regs = cpuid(CPUID_LEAF_PM); | ||||
| 	turbo_cap = !!(cpuid_regs.eax & PM_CAP_TURBO_MODE); | ||||
| 
 | ||||
| 	msr = msr_read(MSR_IA32_MISC_ENABLES); | ||||
| 	turbo_en = !(msr.hi & H_MISC_DISABLE_TURBO); | ||||
| 
 | ||||
| 	if (!turbo_cap && turbo_en) { | ||||
| 		/* Unavailable */ | ||||
| 		turbo_state = TURBO_UNAVAILABLE; | ||||
| 	} else if (!turbo_cap && !turbo_en) { | ||||
| 		/* Available but disabled */ | ||||
| 		turbo_state = TURBO_DISABLED; | ||||
| 	} else if (turbo_cap && turbo_en) { | ||||
| 		/* Available */ | ||||
| 		turbo_state = TURBO_ENABLED; | ||||
| 	} | ||||
| 
 | ||||
| 	set_global_turbo_state(turbo_state); | ||||
| 	debug("Turbo is %s\n", turbo_state_desc[turbo_state]); | ||||
| 	return turbo_state; | ||||
| } | ||||
| 
 | ||||
| void turbo_enable(void) | ||||
| { | ||||
| 	msr_t msr; | ||||
| 
 | ||||
| 	/* Only possible if turbo is available but hidden */ | ||||
| 	if (turbo_get_state() == TURBO_DISABLED) { | ||||
| 		/* Clear Turbo Disable bit in Misc Enables */ | ||||
| 		msr = msr_read(MSR_IA32_MISC_ENABLES); | ||||
| 		msr.hi &= ~H_MISC_DISABLE_TURBO; | ||||
| 		msr_write(MSR_IA32_MISC_ENABLES, msr); | ||||
| 
 | ||||
| 		/* Update cached turbo state */ | ||||
| 		set_global_turbo_state(TURBO_ENABLED); | ||||
| 		debug("Turbo has been enabled\n"); | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,89 @@ | |||
| /*
 | ||||
|  * From Coreboot file of same name | ||||
|  * | ||||
|  * Copyright (C) 2007-2009 coresystems GmbH | ||||
|  *               2012 secunet Security Networks AG | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _ASM_SPEEDSTEP_H | ||||
| #define _ASM_SPEEDSTEP_H | ||||
| 
 | ||||
| /* Magic value used to locate speedstep configuration in the device tree */ | ||||
| #define SPEEDSTEP_APIC_MAGIC 0xACAC | ||||
| 
 | ||||
| /* MWAIT coordination I/O base address. This must match
 | ||||
|  * the \_PR_.CPU0 PM base address. | ||||
|  */ | ||||
| #define PMB0_BASE 0x510 | ||||
| 
 | ||||
| /* PMB1: I/O port that triggers SMI once cores are in the same state.
 | ||||
|  * See CSM Trigger, at PMG_CST_CONFIG_CONTROL[6:4] | ||||
|  */ | ||||
| #define PMB1_BASE 0x800 | ||||
| 
 | ||||
| struct sst_state { | ||||
| 	uint8_t dynfsb:1; /* whether this is SLFM */ | ||||
| 	uint8_t nonint:1; /* add .5 to ratio */ | ||||
| 	uint8_t ratio:6; | ||||
| 	uint8_t vid; | ||||
| 	uint8_t is_turbo; | ||||
| 	uint8_t is_slfm; | ||||
| 	uint32_t power; | ||||
| }; | ||||
| #define SPEEDSTEP_RATIO_SHIFT		8 | ||||
| #define SPEEDSTEP_RATIO_DYNFSB_SHIFT	(7 + SPEEDSTEP_RATIO_SHIFT) | ||||
| #define SPEEDSTEP_RATIO_DYNFSB		(1 << SPEEDSTEP_RATIO_DYNFSB_SHIFT) | ||||
| #define SPEEDSTEP_RATIO_NONINT_SHIFT	(6 + SPEEDSTEP_RATIO_SHIFT) | ||||
| #define SPEEDSTEP_RATIO_NONINT		(1 << SPEEDSTEP_RATIO_NONINT_SHIFT) | ||||
| #define SPEEDSTEP_RATIO_VALUE_MASK	(0x1f << SPEEDSTEP_RATIO_SHIFT) | ||||
| #define SPEEDSTEP_VID_MASK		0x3f | ||||
| #define SPEEDSTEP_STATE_FROM_MSR(val, mask) ((struct sst_state){	\ | ||||
| 		0, /* dynfsb won't be read. */				\ | ||||
| 		((val & mask) & SPEEDSTEP_RATIO_NONINT) ? 1 : 0,	\ | ||||
| 		(((val & mask) & SPEEDSTEP_RATIO_VALUE_MASK)		\ | ||||
| 					>> SPEEDSTEP_RATIO_SHIFT),	\ | ||||
| 		(val & mask) & SPEEDSTEP_VID_MASK,			\ | ||||
| 		0, /* not turbo by default */				\ | ||||
| 		0, /* not slfm by default */				\ | ||||
| 		0  /* power is hardcoded in software. */		\ | ||||
| 	}) | ||||
| #define SPEEDSTEP_ENCODE_STATE(state)	(				\ | ||||
| 	((uint16_t)(state).dynfsb << SPEEDSTEP_RATIO_DYNFSB_SHIFT) |	\ | ||||
| 	((uint16_t)(state).nonint << SPEEDSTEP_RATIO_NONINT_SHIFT) |	\ | ||||
| 	((uint16_t)(state).ratio << SPEEDSTEP_RATIO_SHIFT) |		\ | ||||
| 	((uint16_t)(state).vid & SPEEDSTEP_VID_MASK)) | ||||
| #define SPEEDSTEP_DOUBLE_RATIO(state)	(				\ | ||||
| 	((uint8_t)(state).ratio * 2) + (state).nonint) | ||||
| 
 | ||||
| struct sst_params { | ||||
| 	struct sst_state slfm; | ||||
| 	struct sst_state min; | ||||
| 	struct sst_state max; | ||||
| 	struct sst_state turbo; | ||||
| }; | ||||
| 
 | ||||
| /* Looking at core2's spec, the highest normal bus ratio for an eist enabled
 | ||||
|    processor is 14, the lowest is always 6. This makes 5 states with the | ||||
|    minimal step width of 2. With turbo mode and super LFM we have at most 7. */ | ||||
| #define SPEEDSTEP_MAX_NORMAL_STATES	5 | ||||
| #define SPEEDSTEP_MAX_STATES		(SPEEDSTEP_MAX_NORMAL_STATES + 2) | ||||
| struct sst_table { | ||||
| 	/* Table of p-states for EMTTM and ACPI by decreasing performance. */ | ||||
| 	struct sst_state states[SPEEDSTEP_MAX_STATES]; | ||||
| 	int num_states; | ||||
| }; | ||||
| 
 | ||||
| void speedstep_gen_pstates(struct sst_table *); | ||||
| 
 | ||||
| #define SPEEDSTEP_MAX_POWER_YONAH	31000 | ||||
| #define SPEEDSTEP_MIN_POWER_YONAH	13100 | ||||
| #define SPEEDSTEP_MAX_POWER_MEROM	35000 | ||||
| #define SPEEDSTEP_MIN_POWER_MEROM	25000 | ||||
| #define SPEEDSTEP_SLFM_POWER_MEROM	12000 | ||||
| #define SPEEDSTEP_MAX_POWER_PENRYN	35000 | ||||
| #define SPEEDSTEP_MIN_POWER_PENRYN	15000 | ||||
| #define SPEEDSTEP_SLFM_POWER_PENRYN	12000 | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,31 @@ | |||
| /*
 | ||||
|  * From coreboot file of the same name | ||||
|  * | ||||
|  * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. | ||||
|  * | ||||
|  * SPDX-License-Identifier:	GPL-2.0 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _ASM_TURBO_H | ||||
| #define _ASM_TURBO_H | ||||
| 
 | ||||
| #define CPUID_LEAF_PM		6 | ||||
| #define PM_CAP_TURBO_MODE	(1 << 1) | ||||
| 
 | ||||
| #define MSR_IA32_MISC_ENABLES	0x1a0 | ||||
| #define H_MISC_DISABLE_TURBO	(1 << 6) | ||||
| 
 | ||||
| enum { | ||||
| 	TURBO_UNKNOWN, | ||||
| 	TURBO_UNAVAILABLE, | ||||
| 	TURBO_DISABLED, | ||||
| 	TURBO_ENABLED, | ||||
| }; | ||||
| 
 | ||||
| /* Return current turbo state */ | ||||
| int turbo_get_state(void); | ||||
| 
 | ||||
| /* Enable turbo */ | ||||
| void turbo_enable(void); | ||||
| 
 | ||||
| #endif | ||||
		Loading…
	
		Reference in New Issue