It encourages users from writing to the FSF without giving an address. Linux also prefers to drop that and their checkpatch.pl (that we imported) looks out for that. This is the result of util/scripts/no-fsf-addresses.sh with no further editing. Change-Id: Ie96faea295fe001911d77dbc51e9a6789558fbd6 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Reviewed-on: http://review.coreboot.org/11888 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
185 lines
6.0 KiB
C
185 lines
6.0 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include <types.h>
|
|
#include <string.h>
|
|
#include <arch/cpu.h>
|
|
#include <cpu/x86/msr.h>
|
|
#include <console/console.h>
|
|
#include <cpu/intel/speedstep.h>
|
|
|
|
/**
|
|
* @brief Gather speedstep limits for current processor
|
|
*
|
|
* At least power limits are processor type specific. Penryn introduced half
|
|
* steps in bus ratios. Don't know about Atom processors.
|
|
*/
|
|
static void speedstep_get_limits(sst_params_t *const params)
|
|
{
|
|
msr_t msr;
|
|
|
|
const uint16_t cpu_id = (cpuid_eax(1) >> 4) & 0xffff;
|
|
const uint32_t state_mask =
|
|
/* Penryn supports non integer (i.e. half) ratios. */
|
|
((cpu_id == 0x1067) ? SPEEDSTEP_RATIO_NONINT : 0)
|
|
| SPEEDSTEP_RATIO_VALUE_MASK | SPEEDSTEP_VID_MASK;
|
|
|
|
/* Initialize params to zero. */
|
|
memset(params, '\0', sizeof(*params));
|
|
|
|
/* Read Super-LFM parameters. */
|
|
if (((rdmsr(MSR_EXTENDED_CONFIG).lo >> 27) & 3) == 3) {/*supported and
|
|
enabled bits */
|
|
msr = rdmsr(MSR_FSB_CLOCK_VCC);
|
|
params->slfm = SPEEDSTEP_STATE_FROM_MSR(msr.lo, state_mask);
|
|
params->slfm.dynfsb = 1;
|
|
params->slfm.is_slfm = 1;
|
|
}
|
|
|
|
/* Read normal minimum parameters. */
|
|
msr = rdmsr(MSR_THERM2_CTL);
|
|
params->min = SPEEDSTEP_STATE_FROM_MSR(msr.lo, state_mask);
|
|
|
|
/* Read normal maximum parameters. */
|
|
/* Newer CPUs provide the normal maximum settings in
|
|
IA32_PLATFORM_ID. The values in IA32_PERF_STS change
|
|
when using turbo mode. */
|
|
msr = rdmsr(IA32_PLATFORM_ID);
|
|
params->max = SPEEDSTEP_STATE_FROM_MSR(msr.lo, state_mask);
|
|
if (cpu_id == 0x006e) {
|
|
/* Looks like Yonah CPUs don't have the frequency ratio in
|
|
IA32_PLATFORM_ID. Use IA32_PERF_STS instead, the reading
|
|
should be reliable as those CPUs don't have turbo mode. */
|
|
msr = rdmsr(IA32_PERF_STS);
|
|
params->max.ratio = (msr.hi & SPEEDSTEP_RATIO_VALUE_MASK)
|
|
>> SPEEDSTEP_RATIO_SHIFT;
|
|
}
|
|
|
|
/* Read turbo parameters. */
|
|
msr = rdmsr(MSR_FSB_CLOCK_VCC);
|
|
if ((msr.hi & (1 << (63 - 32))) &&
|
|
/* supported and */
|
|
!(rdmsr(IA32_MISC_ENABLES).hi & (1 << (38 - 32)))) {
|
|
/* not disabled */
|
|
params->turbo = SPEEDSTEP_STATE_FROM_MSR(msr.hi, state_mask);
|
|
params->turbo.is_turbo = 1;
|
|
}
|
|
|
|
/* Set power limits by processor type. */
|
|
/* Defined values match the normal voltage versions only. But
|
|
they are only a hint for OSPM, so this should not hurt much. */
|
|
switch (cpu_id) {
|
|
case 0x006e:
|
|
/* Yonah */
|
|
params->min.power = SPEEDSTEP_MIN_POWER_YONAH;
|
|
params->max.power = SPEEDSTEP_MAX_POWER_YONAH;
|
|
break;
|
|
case 0x1067:
|
|
/* Penryn */
|
|
params->slfm.power = SPEEDSTEP_SLFM_POWER_PENRYN;
|
|
params->min.power = SPEEDSTEP_MIN_POWER_PENRYN;
|
|
params->max.power = SPEEDSTEP_MAX_POWER_PENRYN;
|
|
params->turbo.power = SPEEDSTEP_MAX_POWER_PENRYN;
|
|
break;
|
|
case 0x006f:
|
|
/* Merom */
|
|
default:
|
|
/* Use Merom values by default (as before). */
|
|
params->slfm.power = SPEEDSTEP_SLFM_POWER_MEROM;
|
|
params->min.power = SPEEDSTEP_MIN_POWER_MEROM;
|
|
params->max.power = SPEEDSTEP_MAX_POWER_MEROM;
|
|
params->turbo.power = SPEEDSTEP_MAX_POWER_MEROM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Generate full p-states table from processor parameters
|
|
*
|
|
* This is generic code and should work at least for Merom and Penryn
|
|
* processors. It is used to generate acpi tables and configure EMTTM.
|
|
*/
|
|
void speedstep_gen_pstates(sst_table_t *const table)
|
|
{
|
|
sst_params_t params;
|
|
/* Gather speedstep limits. */
|
|
speedstep_get_limits(¶ms);
|
|
|
|
|
|
/*\ First, find the number of normal states: \*/
|
|
|
|
/* Calculate with doubled values to work
|
|
around non-integer (.5) bus ratios. */
|
|
const int power_diff2 = (params.max.power - params.min.power) * 2;
|
|
const int vid_diff2 = (params.max.vid - params.min.vid) * 2;
|
|
const int max_ratio2 = SPEEDSTEP_DOUBLE_RATIO(params.max);
|
|
const int min_ratio2 = SPEEDSTEP_DOUBLE_RATIO(params.min);
|
|
const int ratio_diff2 = max_ratio2 - min_ratio2;
|
|
/* Calculate number of normal states (LFM to HFM, min to max). */
|
|
/* Increase step size, until all states fit into the table.
|
|
(Note: First try should always work, if
|
|
SPEEDSTEP_MAX_NORMAL_STATES is set correctly.) */
|
|
int states, step2 = 0;
|
|
do {
|
|
step2 += 2 * 2; /* Must be a multiple of 2 (doubled). */
|
|
states = ratio_diff2 / step2 + 1;
|
|
} while (states > SPEEDSTEP_MAX_NORMAL_STATES);
|
|
if (step2 > 4)
|
|
printk(BIOS_INFO, "Enhanced Speedstep processor with "
|
|
"more than %d possible p-states.\n",
|
|
SPEEDSTEP_MAX_NORMAL_STATES);
|
|
if (states < 2) /* Report at least two normal states. */
|
|
states = 2;
|
|
|
|
|
|
/*\ Now, fill the table: \*/
|
|
|
|
table->num_states = 0;
|
|
|
|
/* Add turbo state if supported. */
|
|
if (params.turbo.is_turbo)
|
|
table->states[table->num_states++] = params.turbo;
|
|
|
|
/* Add HFM first. */
|
|
table->states[table->num_states] = params.max;
|
|
/* Work around HFM and LFM having the same bus ratio. */
|
|
if ((params.max.dynfsb == params.min.dynfsb) &&
|
|
(params.max.nonint == params.min.nonint) &&
|
|
(params.max.ratio == params.min.ratio))
|
|
table->states[table->num_states].vid = params.min.vid;
|
|
++table->num_states;
|
|
--states;
|
|
|
|
/* Now, add all other normal states based on LFM (min). */
|
|
const int power_step = (power_diff2 / states) / 2;
|
|
const int vid_step = (vid_diff2 / states) / 2;
|
|
const int ratio_step = step2 / 2;
|
|
int power = params.min.power + (states - 1) * power_step;
|
|
int vid = params.min.vid + (states - 1) * vid_step;
|
|
int ratio = params.min.ratio + (states - 1) * ratio_step;
|
|
for (; states > 0; --states) {
|
|
table->states[table->num_states++] =
|
|
(sst_state_t){ 0, 0, ratio, vid, 0, 0, power };
|
|
power -= power_step;
|
|
vid -= vid_step;
|
|
ratio -= ratio_step;
|
|
}
|
|
|
|
/* At last, add Super-LFM state if supported. */
|
|
if (params.slfm.is_slfm)
|
|
table->states[table->num_states++] = params.slfm;
|
|
}
|