Merge back earlier 'pm-cpufreq' material.
This commit is contained in:
commit
51c4c4ce1d
|
@ -200,3 +200,27 @@ Description: address and size of the percpu note.
|
||||||
note of cpu#.
|
note of cpu#.
|
||||||
|
|
||||||
crash_notes_size: size of the note of cpu#.
|
crash_notes_size: size of the note of cpu#.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/devices/system/cpu/intel_pstate/max_perf_pct
|
||||||
|
/sys/devices/system/cpu/intel_pstate/min_perf_pct
|
||||||
|
/sys/devices/system/cpu/intel_pstate/no_turbo
|
||||||
|
Date: February 2013
|
||||||
|
Contact: linux-pm@vger.kernel.org
|
||||||
|
Description: Parameters for the Intel P-state driver
|
||||||
|
|
||||||
|
Logic for selecting the current P-state in Intel
|
||||||
|
Sandybridge+ processors. The three knobs control
|
||||||
|
limits for the P-state that will be requested by the
|
||||||
|
driver.
|
||||||
|
|
||||||
|
max_perf_pct: limits the maximum P state that will be requested by
|
||||||
|
the driver stated as a percentage of the available performance.
|
||||||
|
|
||||||
|
min_perf_pct: limits the minimum P state that will be requested by
|
||||||
|
the driver stated as a percentage of the available performance.
|
||||||
|
|
||||||
|
no_turbo: limits the driver to selecting P states below the turbo
|
||||||
|
frequency range.
|
||||||
|
|
||||||
|
More details can be found in Documentation/cpu-freq/intel-pstate.txt
|
||||||
|
|
40
Documentation/cpu-freq/intel-pstate.txt
Normal file
40
Documentation/cpu-freq/intel-pstate.txt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
Intel P-state driver
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
This driver implements a scaling driver with an internal governor for
|
||||||
|
Intel Core processors. The driver follows the same model as the
|
||||||
|
Transmeta scaling driver (longrun.c) and implements the setpolicy()
|
||||||
|
instead of target(). Scaling drivers that implement setpolicy() are
|
||||||
|
assumed to implement internal governors by the cpufreq core. All the
|
||||||
|
logic for selecting the current P state is contained within the
|
||||||
|
driver; no external governor is used by the cpufreq core.
|
||||||
|
|
||||||
|
Intel SandyBridge+ processors are supported.
|
||||||
|
|
||||||
|
New sysfs files for controlling P state selection have been added to
|
||||||
|
/sys/devices/system/cpu/intel_pstate/
|
||||||
|
|
||||||
|
max_perf_pct: limits the maximum P state that will be requested by
|
||||||
|
the driver stated as a percentage of the available performance.
|
||||||
|
|
||||||
|
min_perf_pct: limits the minimum P state that will be requested by
|
||||||
|
the driver stated as a percentage of the available performance.
|
||||||
|
|
||||||
|
no_turbo: limits the driver to selecting P states below the turbo
|
||||||
|
frequency range.
|
||||||
|
|
||||||
|
For contemporary Intel processors, the frequency is controlled by the
|
||||||
|
processor itself and the P-states exposed to software are related to
|
||||||
|
performance levels. The idea that frequency can be set to a single
|
||||||
|
frequency is fiction for Intel Core processors. Even if the scaling
|
||||||
|
driver selects a single P state the actual frequency the processor
|
||||||
|
will run at is selected by the processor itself.
|
||||||
|
|
||||||
|
New debugfs files have also been added to /sys/kernel/debug/pstate_snb/
|
||||||
|
|
||||||
|
deadband
|
||||||
|
d_gain_pct
|
||||||
|
i_gain_pct
|
||||||
|
p_gain_pct
|
||||||
|
sample_rate_ms
|
||||||
|
setpoint
|
|
@ -303,6 +303,11 @@ void __init exynos_cpuidle_init(void)
|
||||||
platform_device_register(&exynos_cpuidle);
|
platform_device_register(&exynos_cpuidle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __init exynos_cpufreq_init(void)
|
||||||
|
{
|
||||||
|
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void __init exynos_init_late(void)
|
void __init exynos_init_late(void)
|
||||||
{
|
{
|
||||||
if (of_machine_is_compatible("samsung,exynos5440"))
|
if (of_machine_is_compatible("samsung,exynos5440"))
|
||||||
|
|
|
@ -22,6 +22,7 @@ void exynos_init_io(void);
|
||||||
void exynos4_restart(enum reboot_mode mode, const char *cmd);
|
void exynos4_restart(enum reboot_mode mode, const char *cmd);
|
||||||
void exynos5_restart(enum reboot_mode mode, const char *cmd);
|
void exynos5_restart(enum reboot_mode mode, const char *cmd);
|
||||||
void exynos_cpuidle_init(void);
|
void exynos_cpuidle_init(void);
|
||||||
|
void exynos_cpufreq_init(void);
|
||||||
void exynos_init_late(void);
|
void exynos_init_late(void);
|
||||||
|
|
||||||
void exynos_firmware_init(void);
|
void exynos_firmware_init(void);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
static void __init exynos4_dt_machine_init(void)
|
static void __init exynos4_dt_machine_init(void)
|
||||||
{
|
{
|
||||||
exynos_cpuidle_init();
|
exynos_cpuidle_init();
|
||||||
|
exynos_cpufreq_init();
|
||||||
|
|
||||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ static void __init exynos5_dt_machine_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
exynos_cpuidle_init();
|
exynos_cpuidle_init();
|
||||||
|
exynos_cpufreq_init();
|
||||||
|
|
||||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,7 +181,8 @@ config CPU_FREQ_GOV_CONSERVATIVE
|
||||||
|
|
||||||
config GENERIC_CPUFREQ_CPU0
|
config GENERIC_CPUFREQ_CPU0
|
||||||
tristate "Generic CPU0 cpufreq driver"
|
tristate "Generic CPU0 cpufreq driver"
|
||||||
depends on HAVE_CLK && REGULATOR && PM_OPP && OF
|
depends on HAVE_CLK && REGULATOR && OF
|
||||||
|
select PM_OPP
|
||||||
help
|
help
|
||||||
This adds a generic cpufreq driver for CPU0 frequency management.
|
This adds a generic cpufreq driver for CPU0 frequency management.
|
||||||
It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
|
It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
config ARM_BIG_LITTLE_CPUFREQ
|
config ARM_BIG_LITTLE_CPUFREQ
|
||||||
tristate "Generic ARM big LITTLE CPUfreq driver"
|
tristate "Generic ARM big LITTLE CPUfreq driver"
|
||||||
depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK
|
depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
|
||||||
|
select PM_OPP
|
||||||
help
|
help
|
||||||
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
|
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
|
||||||
|
|
||||||
|
@ -54,7 +55,8 @@ config ARM_EXYNOS5250_CPUFREQ
|
||||||
config ARM_EXYNOS5440_CPUFREQ
|
config ARM_EXYNOS5440_CPUFREQ
|
||||||
bool "SAMSUNG EXYNOS5440"
|
bool "SAMSUNG EXYNOS5440"
|
||||||
depends on SOC_EXYNOS5440
|
depends on SOC_EXYNOS5440
|
||||||
depends on HAVE_CLK && PM_OPP && OF
|
depends on HAVE_CLK && OF
|
||||||
|
select PM_OPP
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver for Samsung EXYNOS5440
|
This adds the CPUFreq driver for Samsung EXYNOS5440
|
||||||
|
@ -79,11 +81,11 @@ config ARM_HIGHBANK_CPUFREQ
|
||||||
If in doubt, say N.
|
If in doubt, say N.
|
||||||
|
|
||||||
config ARM_IMX6Q_CPUFREQ
|
config ARM_IMX6Q_CPUFREQ
|
||||||
tristate "Freescale i.MX6Q cpufreq support"
|
tristate "Freescale i.MX6 cpufreq support"
|
||||||
depends on SOC_IMX6Q
|
depends on ARCH_MXC
|
||||||
depends on REGULATOR_ANATOP
|
depends on REGULATOR_ANATOP
|
||||||
help
|
help
|
||||||
This adds cpufreq driver support for Freescale i.MX6Q SOC.
|
This adds cpufreq driver support for Freescale i.MX6 series SoCs.
|
||||||
|
|
||||||
If in doubt, say N.
|
If in doubt, say N.
|
||||||
|
|
||||||
|
|
|
@ -488,7 +488,8 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
|
||||||
static struct cpufreq_driver bL_cpufreq_driver = {
|
static struct cpufreq_driver bL_cpufreq_driver = {
|
||||||
.name = "arm-big-little",
|
.name = "arm-big-little",
|
||||||
.flags = CPUFREQ_STICKY |
|
.flags = CPUFREQ_STICKY |
|
||||||
CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
|
CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
|
||||||
|
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = bL_cpufreq_set_target,
|
.target_index = bL_cpufreq_set_target,
|
||||||
.get = bL_cpufreq_get_rate,
|
.get = bL_cpufreq_get_rate,
|
||||||
|
|
|
@ -44,7 +44,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
|
freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
|
||||||
if (freq_Hz < 0)
|
if (freq_Hz <= 0)
|
||||||
freq_Hz = freq_table[index].frequency * 1000;
|
freq_Hz = freq_table[index].frequency * 1000;
|
||||||
|
|
||||||
freq_exact = freq_Hz;
|
freq_exact = freq_Hz;
|
||||||
|
|
|
@ -39,7 +39,7 @@ static struct cpufreq_driver *cpufreq_driver;
|
||||||
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
|
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
|
||||||
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
|
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
|
||||||
static DEFINE_RWLOCK(cpufreq_driver_lock);
|
static DEFINE_RWLOCK(cpufreq_driver_lock);
|
||||||
static DEFINE_MUTEX(cpufreq_governor_lock);
|
DEFINE_MUTEX(cpufreq_governor_lock);
|
||||||
static LIST_HEAD(cpufreq_policy_list);
|
static LIST_HEAD(cpufreq_policy_list);
|
||||||
|
|
||||||
#ifdef CONFIG_HOTPLUG_CPU
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
|
@ -320,6 +320,20 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
|
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
|
||||||
|
|
||||||
|
/* Do post notifications when there are chances that transition has failed */
|
||||||
|
void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
|
||||||
|
struct cpufreq_freqs *freqs, int transition_failed)
|
||||||
|
{
|
||||||
|
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
|
||||||
|
if (!transition_failed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
swap(freqs->old, freqs->new);
|
||||||
|
cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
|
||||||
|
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* SYSFS INTERFACE *
|
* SYSFS INTERFACE *
|
||||||
|
@ -1059,6 +1073,46 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sometimes boot loaders set CPU frequency to a value outside of
|
||||||
|
* frequency table present with cpufreq core. In such cases CPU might be
|
||||||
|
* unstable if it has to run on that frequency for long duration of time
|
||||||
|
* and so its better to set it to a frequency which is specified in
|
||||||
|
* freq-table. This also makes cpufreq stats inconsistent as
|
||||||
|
* cpufreq-stats would fail to register because current frequency of CPU
|
||||||
|
* isn't found in freq-table.
|
||||||
|
*
|
||||||
|
* Because we don't want this change to effect boot process badly, we go
|
||||||
|
* for the next freq which is >= policy->cur ('cur' must be set by now,
|
||||||
|
* otherwise we will end up setting freq to lowest of the table as 'cur'
|
||||||
|
* is initialized to zero).
|
||||||
|
*
|
||||||
|
* We are passing target-freq as "policy->cur - 1" otherwise
|
||||||
|
* __cpufreq_driver_target() would simply fail, as policy->cur will be
|
||||||
|
* equal to target-freq.
|
||||||
|
*/
|
||||||
|
if ((cpufreq_driver->flags & CPUFREQ_NEED_INITIAL_FREQ_CHECK)
|
||||||
|
&& has_target()) {
|
||||||
|
/* Are we running at unknown frequency ? */
|
||||||
|
ret = cpufreq_frequency_table_get_index(policy, policy->cur);
|
||||||
|
if (ret == -EINVAL) {
|
||||||
|
/* Warn user and fix it */
|
||||||
|
pr_warn("%s: CPU%d: Running at unlisted freq: %u KHz\n",
|
||||||
|
__func__, policy->cpu, policy->cur);
|
||||||
|
ret = __cpufreq_driver_target(policy, policy->cur - 1,
|
||||||
|
CPUFREQ_RELATION_L);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reaching here after boot in a few seconds may not
|
||||||
|
* mean that system will remain stable at "unknown"
|
||||||
|
* frequency for longer duration. Hence, a BUG_ON().
|
||||||
|
*/
|
||||||
|
BUG_ON(ret);
|
||||||
|
pr_warn("%s: CPU%d: Unlisted initial frequency changed to: %u KHz\n",
|
||||||
|
__func__, policy->cpu, policy->cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* related cpus should atleast have policy->cpus */
|
/* related cpus should atleast have policy->cpus */
|
||||||
cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
|
cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
|
||||||
|
|
||||||
|
@ -1725,17 +1779,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||||
pr_err("%s: Failed to change cpu frequency: %d\n",
|
pr_err("%s: Failed to change cpu frequency: %d\n",
|
||||||
__func__, retval);
|
__func__, retval);
|
||||||
|
|
||||||
if (notify) {
|
if (notify)
|
||||||
/*
|
cpufreq_notify_post_transition(policy, &freqs, retval);
|
||||||
* Notify with old freq in case we failed to change
|
|
||||||
* frequency
|
|
||||||
*/
|
|
||||||
if (retval)
|
|
||||||
freqs.new = freqs.old;
|
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs,
|
|
||||||
CPUFREQ_POSTCHANGE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -119,8 +119,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
mutex_lock(&cpufreq_governor_lock);
|
||||||
if (!policy->governor_enabled)
|
if (!policy->governor_enabled)
|
||||||
return;
|
goto out_unlock;
|
||||||
|
|
||||||
if (!all_cpus) {
|
if (!all_cpus) {
|
||||||
/*
|
/*
|
||||||
|
@ -135,6 +136,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
|
||||||
for_each_cpu(i, policy->cpus)
|
for_each_cpu(i, policy->cpus)
|
||||||
__gov_queue_work(i, dbs_data, delay);
|
__gov_queue_work(i, dbs_data, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&cpufreq_governor_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gov_queue_work);
|
EXPORT_SYMBOL_GPL(gov_queue_work);
|
||||||
|
|
||||||
|
|
|
@ -257,6 +257,8 @@ static ssize_t show_sampling_rate_min_gov_pol \
|
||||||
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
|
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern struct mutex cpufreq_governor_lock;
|
||||||
|
|
||||||
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
|
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
|
||||||
bool need_load_eval(struct cpu_dbs_common_info *cdbs,
|
bool need_load_eval(struct cpu_dbs_common_info *cdbs,
|
||||||
unsigned int sampling_rate);
|
unsigned int sampling_rate);
|
||||||
|
|
|
@ -126,7 +126,7 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver davinci_driver = {
|
static struct cpufreq_driver davinci_driver = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = davinci_verify_speed,
|
.verify = davinci_verify_speed,
|
||||||
.target_index = davinci_target,
|
.target_index = davinci_target,
|
||||||
.get = davinci_getspeed,
|
.get = davinci_getspeed,
|
||||||
|
|
|
@ -48,7 +48,8 @@ static int dbx500_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver dbx500_cpufreq_driver = {
|
static struct cpufreq_driver dbx500_cpufreq_driver = {
|
||||||
.flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
|
.flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS |
|
||||||
|
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = dbx500_cpufreq_target,
|
.target_index = dbx500_cpufreq_target,
|
||||||
.get = dbx500_cpufreq_getspeed,
|
.get = dbx500_cpufreq_getspeed,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/cpufreq.h>
|
#include <linux/cpufreq.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
#include <plat/cpu.h>
|
#include <plat/cpu.h>
|
||||||
|
|
||||||
|
@ -218,7 +219,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver exynos_driver = {
|
static struct cpufreq_driver exynos_driver = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = exynos_target,
|
.target_index = exynos_target,
|
||||||
.get = exynos_getspeed,
|
.get = exynos_getspeed,
|
||||||
|
@ -232,7 +233,7 @@ static struct cpufreq_driver exynos_driver = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init exynos_cpufreq_init(void)
|
static int exynos_cpufreq_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
@ -281,4 +282,12 @@ err_vdd_arm:
|
||||||
kfree(exynos_info);
|
kfree(exynos_info);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
late_initcall(exynos_cpufreq_init);
|
|
||||||
|
static struct platform_driver exynos_cpufreq_platdrv = {
|
||||||
|
.driver = {
|
||||||
|
.name = "exynos-cpufreq",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = exynos_cpufreq_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(exynos_cpufreq_platdrv);
|
||||||
|
|
|
@ -102,12 +102,12 @@ static void set_clkdiv(unsigned int div_index)
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_apll(unsigned int new_index,
|
static void set_apll(unsigned int index)
|
||||||
unsigned int old_index)
|
|
||||||
{
|
{
|
||||||
unsigned int tmp, pdiv;
|
unsigned int tmp;
|
||||||
|
unsigned int freq = apll_freq_5250[index].freq;
|
||||||
|
|
||||||
/* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
|
/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
|
||||||
clk_set_parent(moutcore, mout_mpll);
|
clk_set_parent(moutcore, mout_mpll);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -116,24 +116,9 @@ static void set_apll(unsigned int new_index,
|
||||||
tmp &= 0x7;
|
tmp &= 0x7;
|
||||||
} while (tmp != 0x2);
|
} while (tmp != 0x2);
|
||||||
|
|
||||||
/* 2. Set APLL Lock time */
|
clk_set_rate(mout_apll, freq * 1000);
|
||||||
pdiv = ((apll_freq_5250[new_index].mps >> 8) & 0x3f);
|
|
||||||
|
|
||||||
__raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
|
/* MUX_CORE_SEL = APLL */
|
||||||
|
|
||||||
/* 3. Change PLL PMS values */
|
|
||||||
tmp = __raw_readl(EXYNOS5_APLL_CON0);
|
|
||||||
tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
|
|
||||||
tmp |= apll_freq_5250[new_index].mps;
|
|
||||||
__raw_writel(tmp, EXYNOS5_APLL_CON0);
|
|
||||||
|
|
||||||
/* 4. wait_lock_time */
|
|
||||||
do {
|
|
||||||
cpu_relax();
|
|
||||||
tmp = __raw_readl(EXYNOS5_APLL_CON0);
|
|
||||||
} while (!(tmp & (0x1 << 29)));
|
|
||||||
|
|
||||||
/* 5. MUX_CORE_SEL = APLL */
|
|
||||||
clk_set_parent(moutcore, mout_apll);
|
clk_set_parent(moutcore, mout_apll);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -141,55 +126,17 @@ static void set_apll(unsigned int new_index,
|
||||||
tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
|
tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
|
||||||
tmp &= (0x7 << 16);
|
tmp &= (0x7 << 16);
|
||||||
} while (tmp != (0x1 << 16));
|
} while (tmp != (0x1 << 16));
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
|
|
||||||
{
|
|
||||||
unsigned int old_pm = apll_freq_5250[old_index].mps >> 8;
|
|
||||||
unsigned int new_pm = apll_freq_5250[new_index].mps >> 8;
|
|
||||||
|
|
||||||
return (old_pm == new_pm) ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos5250_set_frequency(unsigned int old_index,
|
static void exynos5250_set_frequency(unsigned int old_index,
|
||||||
unsigned int new_index)
|
unsigned int new_index)
|
||||||
{
|
{
|
||||||
unsigned int tmp;
|
|
||||||
|
|
||||||
if (old_index > new_index) {
|
if (old_index > new_index) {
|
||||||
if (!exynos5250_pms_change(old_index, new_index)) {
|
set_clkdiv(new_index);
|
||||||
/* 1. Change the system clock divider values */
|
set_apll(new_index);
|
||||||
set_clkdiv(new_index);
|
|
||||||
/* 2. Change just s value in apll m,p,s value */
|
|
||||||
tmp = __raw_readl(EXYNOS5_APLL_CON0);
|
|
||||||
tmp &= ~(0x7 << 0);
|
|
||||||
tmp |= apll_freq_5250[new_index].mps & 0x7;
|
|
||||||
__raw_writel(tmp, EXYNOS5_APLL_CON0);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* Clock Configuration Procedure */
|
|
||||||
/* 1. Change the system clock divider values */
|
|
||||||
set_clkdiv(new_index);
|
|
||||||
/* 2. Change the apll m,p,s value */
|
|
||||||
set_apll(new_index, old_index);
|
|
||||||
}
|
|
||||||
} else if (old_index < new_index) {
|
} else if (old_index < new_index) {
|
||||||
if (!exynos5250_pms_change(old_index, new_index)) {
|
set_apll(new_index);
|
||||||
/* 1. Change just s value in apll m,p,s value */
|
set_clkdiv(new_index);
|
||||||
tmp = __raw_readl(EXYNOS5_APLL_CON0);
|
|
||||||
tmp &= ~(0x7 << 0);
|
|
||||||
tmp |= apll_freq_5250[new_index].mps & 0x7;
|
|
||||||
__raw_writel(tmp, EXYNOS5_APLL_CON0);
|
|
||||||
/* 2. Change the system clock divider values */
|
|
||||||
set_clkdiv(new_index);
|
|
||||||
} else {
|
|
||||||
/* Clock Configuration Procedure */
|
|
||||||
/* 1. Change the apll m,p,s value */
|
|
||||||
set_apll(new_index, old_index);
|
|
||||||
/* 2. Change the system clock divider values */
|
|
||||||
set_clkdiv(new_index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +169,6 @@ int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
|
||||||
info->volt_table = exynos5250_volt_table;
|
info->volt_table = exynos5250_volt_table;
|
||||||
info->freq_table = exynos5250_freq_table;
|
info->freq_table = exynos5250_freq_table;
|
||||||
info->set_freq = exynos5250_set_frequency;
|
info->set_freq = exynos5250_set_frequency;
|
||||||
info->need_apll_change = exynos5250_pms_change;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,8 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver exynos_driver = {
|
static struct cpufreq_driver exynos_driver = {
|
||||||
.flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION,
|
.flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION |
|
||||||
|
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = exynos_target,
|
.target_index = exynos_target,
|
||||||
.get = exynos_getspeed,
|
.get = exynos_getspeed,
|
||||||
|
|
|
@ -178,7 +178,29 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
|
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
|
||||||
|
|
||||||
|
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
||||||
|
unsigned int freq)
|
||||||
|
{
|
||||||
|
struct cpufreq_frequency_table *table;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
table = cpufreq_frequency_get_table(policy->cpu);
|
||||||
|
if (unlikely(!table)) {
|
||||||
|
pr_debug("%s: Unable to find frequency table\n", __func__);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||||
|
if (table[i].frequency == freq)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
|
static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* show_available_freqs - show available frequencies for the specified CPU
|
* show_available_freqs - show available frequencies for the specified CPU
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,9 @@ static struct device *cpu_dev;
|
||||||
static struct cpufreq_frequency_table *freq_table;
|
static struct cpufreq_frequency_table *freq_table;
|
||||||
static unsigned int transition_latency;
|
static unsigned int transition_latency;
|
||||||
|
|
||||||
|
static u32 *imx6_soc_volt;
|
||||||
|
static u32 soc_opp_count;
|
||||||
|
|
||||||
static unsigned int imx6q_get_speed(unsigned int cpu)
|
static unsigned int imx6q_get_speed(unsigned int cpu)
|
||||||
{
|
{
|
||||||
return clk_get_rate(arm_clk) / 1000;
|
return clk_get_rate(arm_clk) / 1000;
|
||||||
|
@ -69,23 +72,22 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||||
|
|
||||||
/* scaling up? scale voltage before frequency */
|
/* scaling up? scale voltage before frequency */
|
||||||
if (new_freq > old_freq) {
|
if (new_freq > old_freq) {
|
||||||
|
ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
|
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(cpu_dev,
|
dev_err(cpu_dev,
|
||||||
"failed to scale vddarm up: %d\n", ret);
|
"failed to scale vddarm up: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Need to increase vddpu and vddsoc for safety
|
|
||||||
* if we are about to run at 1.2 GHz.
|
|
||||||
*/
|
|
||||||
if (new_freq == FREQ_1P2_GHZ / 1000) {
|
|
||||||
regulator_set_voltage_tol(pu_reg,
|
|
||||||
PU_SOC_VOLTAGE_HIGH, 0);
|
|
||||||
regulator_set_voltage_tol(soc_reg,
|
|
||||||
PU_SOC_VOLTAGE_HIGH, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -120,12 +122,15 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||||
"failed to scale vddarm down: %d\n", ret);
|
"failed to scale vddarm down: %d\n", ret);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
|
||||||
if (old_freq == FREQ_1P2_GHZ / 1000) {
|
if (ret) {
|
||||||
regulator_set_voltage_tol(pu_reg,
|
dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret);
|
||||||
PU_SOC_VOLTAGE_NORMAL, 0);
|
ret = 0;
|
||||||
regulator_set_voltage_tol(soc_reg,
|
}
|
||||||
PU_SOC_VOLTAGE_NORMAL, 0);
|
ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
|
||||||
|
if (ret) {
|
||||||
|
dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret);
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +143,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver imx6q_cpufreq_driver = {
|
static struct cpufreq_driver imx6q_cpufreq_driver = {
|
||||||
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = imx6q_set_target,
|
.target_index = imx6q_set_target,
|
||||||
.get = imx6q_get_speed,
|
.get = imx6q_get_speed,
|
||||||
|
@ -153,6 +159,9 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
|
||||||
struct dev_pm_opp *opp;
|
struct dev_pm_opp *opp;
|
||||||
unsigned long min_volt, max_volt;
|
unsigned long min_volt, max_volt;
|
||||||
int num, ret;
|
int num, ret;
|
||||||
|
const struct property *prop;
|
||||||
|
const __be32 *val;
|
||||||
|
u32 nr, i, j;
|
||||||
|
|
||||||
cpu_dev = get_cpu_device(0);
|
cpu_dev = get_cpu_device(0);
|
||||||
if (!cpu_dev) {
|
if (!cpu_dev) {
|
||||||
|
@ -187,12 +196,25 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
|
||||||
goto put_node;
|
goto put_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We expect an OPP table supplied by platform */
|
/*
|
||||||
|
* We expect an OPP table supplied by platform.
|
||||||
|
* Just, incase the platform did not supply the OPP
|
||||||
|
* table, it will try to get it.
|
||||||
|
*/
|
||||||
num = dev_pm_opp_get_opp_count(cpu_dev);
|
num = dev_pm_opp_get_opp_count(cpu_dev);
|
||||||
if (num < 0) {
|
if (num < 0) {
|
||||||
ret = num;
|
ret = of_init_opp_table(cpu_dev);
|
||||||
dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
|
if (ret < 0) {
|
||||||
goto put_node;
|
dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
|
||||||
|
goto put_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = dev_pm_opp_get_opp_count(cpu_dev);
|
||||||
|
if (num < 0) {
|
||||||
|
ret = num;
|
||||||
|
dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
|
||||||
|
goto put_node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
|
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
|
||||||
|
@ -201,9 +223,61 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
|
||||||
goto put_node;
|
goto put_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make imx6_soc_volt array's size same as arm opp number */
|
||||||
|
imx6_soc_volt = devm_kzalloc(cpu_dev, sizeof(*imx6_soc_volt) * num, GFP_KERNEL);
|
||||||
|
if (imx6_soc_volt == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free_freq_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop = of_find_property(np, "fsl,soc-operating-points", NULL);
|
||||||
|
if (!prop || !prop->value)
|
||||||
|
goto soc_opp_out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each OPP is a set of tuples consisting of frequency and
|
||||||
|
* voltage like <freq-kHz vol-uV>.
|
||||||
|
*/
|
||||||
|
nr = prop->length / sizeof(u32);
|
||||||
|
if (nr % 2 || (nr / 2) < num)
|
||||||
|
goto soc_opp_out;
|
||||||
|
|
||||||
|
for (j = 0; j < num; j++) {
|
||||||
|
val = prop->value;
|
||||||
|
for (i = 0; i < nr / 2; i++) {
|
||||||
|
unsigned long freq = be32_to_cpup(val++);
|
||||||
|
unsigned long volt = be32_to_cpup(val++);
|
||||||
|
if (freq_table[j].frequency == freq) {
|
||||||
|
imx6_soc_volt[soc_opp_count++] = volt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
soc_opp_out:
|
||||||
|
/* use fixed soc opp volt if no valid soc opp info found in dtb */
|
||||||
|
if (soc_opp_count != num) {
|
||||||
|
dev_warn(cpu_dev, "can NOT find valid fsl,soc-operating-points property in dtb, use default value!\n");
|
||||||
|
for (j = 0; j < num; j++)
|
||||||
|
imx6_soc_volt[j] = PU_SOC_VOLTAGE_NORMAL;
|
||||||
|
if (freq_table[num - 1].frequency * 1000 == FREQ_1P2_GHZ)
|
||||||
|
imx6_soc_volt[num - 1] = PU_SOC_VOLTAGE_HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
if (of_property_read_u32(np, "clock-latency", &transition_latency))
|
if (of_property_read_u32(np, "clock-latency", &transition_latency))
|
||||||
transition_latency = CPUFREQ_ETERNAL;
|
transition_latency = CPUFREQ_ETERNAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the ramp time for max voltage change in the
|
||||||
|
* VDDSOC and VDDPU regulators.
|
||||||
|
*/
|
||||||
|
ret = regulator_set_voltage_time(soc_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);
|
||||||
|
if (ret > 0)
|
||||||
|
transition_latency += ret * 1000;
|
||||||
|
ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);
|
||||||
|
if (ret > 0)
|
||||||
|
transition_latency += ret * 1000;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OPP is maintained in order of increasing frequency, and
|
* OPP is maintained in order of increasing frequency, and
|
||||||
* freq_table initialised from OPP is therefore sorted in the
|
* freq_table initialised from OPP is therefore sorted in the
|
||||||
|
@ -221,18 +295,6 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
transition_latency += ret * 1000;
|
transition_latency += ret * 1000;
|
||||||
|
|
||||||
/* Count vddpu and vddsoc latency in for 1.2 GHz support */
|
|
||||||
if (freq_table[num].frequency == FREQ_1P2_GHZ / 1000) {
|
|
||||||
ret = regulator_set_voltage_time(pu_reg, PU_SOC_VOLTAGE_NORMAL,
|
|
||||||
PU_SOC_VOLTAGE_HIGH);
|
|
||||||
if (ret > 0)
|
|
||||||
transition_latency += ret * 1000;
|
|
||||||
ret = regulator_set_voltage_time(soc_reg, PU_SOC_VOLTAGE_NORMAL,
|
|
||||||
PU_SOC_VOLTAGE_HIGH);
|
|
||||||
if (ret > 0)
|
|
||||||
transition_latency += ret * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
|
ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(cpu_dev, "failed register driver: %d\n", ret);
|
dev_err(cpu_dev, "failed register driver: %d\n", ret);
|
||||||
|
|
|
@ -190,6 +190,7 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver integrator_driver = {
|
static struct cpufreq_driver integrator_driver = {
|
||||||
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = integrator_verify_policy,
|
.verify = integrator_verify_policy,
|
||||||
.target = integrator_set_target,
|
.target = integrator_set_target,
|
||||||
.get = integrator_get,
|
.get = integrator_get,
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#define SAMPLE_COUNT 3
|
#define SAMPLE_COUNT 3
|
||||||
|
|
||||||
#define BYT_RATIOS 0x66a
|
#define BYT_RATIOS 0x66a
|
||||||
|
#define BYT_VIDS 0x66b
|
||||||
|
|
||||||
#define FRAC_BITS 8
|
#define FRAC_BITS 8
|
||||||
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
|
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
|
||||||
|
@ -64,6 +65,12 @@ struct pstate_data {
|
||||||
int turbo_pstate;
|
int turbo_pstate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vid_data {
|
||||||
|
int32_t min;
|
||||||
|
int32_t max;
|
||||||
|
int32_t ratio;
|
||||||
|
};
|
||||||
|
|
||||||
struct _pid {
|
struct _pid {
|
||||||
int setpoint;
|
int setpoint;
|
||||||
int32_t integral;
|
int32_t integral;
|
||||||
|
@ -82,10 +89,9 @@ struct cpudata {
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
|
|
||||||
struct pstate_data pstate;
|
struct pstate_data pstate;
|
||||||
|
struct vid_data vid;
|
||||||
struct _pid pid;
|
struct _pid pid;
|
||||||
|
|
||||||
int min_pstate_count;
|
|
||||||
|
|
||||||
u64 prev_aperf;
|
u64 prev_aperf;
|
||||||
u64 prev_mperf;
|
u64 prev_mperf;
|
||||||
int sample_ptr;
|
int sample_ptr;
|
||||||
|
@ -106,7 +112,8 @@ struct pstate_funcs {
|
||||||
int (*get_max)(void);
|
int (*get_max)(void);
|
||||||
int (*get_min)(void);
|
int (*get_min)(void);
|
||||||
int (*get_turbo)(void);
|
int (*get_turbo)(void);
|
||||||
void (*set)(int pstate);
|
void (*set)(struct cpudata*, int pstate);
|
||||||
|
void (*get_vid)(struct cpudata *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cpu_defaults {
|
struct cpu_defaults {
|
||||||
|
@ -358,6 +365,42 @@ static int byt_get_max_pstate(void)
|
||||||
return (value >> 16) & 0xFF;
|
return (value >> 16) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void byt_set_pstate(struct cpudata *cpudata, int pstate)
|
||||||
|
{
|
||||||
|
u64 val;
|
||||||
|
int32_t vid_fp;
|
||||||
|
u32 vid;
|
||||||
|
|
||||||
|
val = pstate << 8;
|
||||||
|
if (limits.no_turbo)
|
||||||
|
val |= (u64)1 << 32;
|
||||||
|
|
||||||
|
vid_fp = cpudata->vid.min + mul_fp(
|
||||||
|
int_tofp(pstate - cpudata->pstate.min_pstate),
|
||||||
|
cpudata->vid.ratio);
|
||||||
|
|
||||||
|
vid_fp = clamp_t(int32_t, vid_fp, cpudata->vid.min, cpudata->vid.max);
|
||||||
|
vid = fp_toint(vid_fp);
|
||||||
|
|
||||||
|
val |= vid;
|
||||||
|
|
||||||
|
wrmsrl(MSR_IA32_PERF_CTL, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void byt_get_vid(struct cpudata *cpudata)
|
||||||
|
{
|
||||||
|
u64 value;
|
||||||
|
|
||||||
|
rdmsrl(BYT_VIDS, value);
|
||||||
|
cpudata->vid.min = int_tofp((value >> 8) & 0x7f);
|
||||||
|
cpudata->vid.max = int_tofp((value >> 16) & 0x7f);
|
||||||
|
cpudata->vid.ratio = div_fp(
|
||||||
|
cpudata->vid.max - cpudata->vid.min,
|
||||||
|
int_tofp(cpudata->pstate.max_pstate -
|
||||||
|
cpudata->pstate.min_pstate));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int core_get_min_pstate(void)
|
static int core_get_min_pstate(void)
|
||||||
{
|
{
|
||||||
u64 value;
|
u64 value;
|
||||||
|
@ -384,7 +427,7 @@ static int core_get_turbo_pstate(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void core_set_pstate(int pstate)
|
static void core_set_pstate(struct cpudata *cpudata, int pstate)
|
||||||
{
|
{
|
||||||
u64 val;
|
u64 val;
|
||||||
|
|
||||||
|
@ -425,7 +468,8 @@ static struct cpu_defaults byt_params = {
|
||||||
.get_max = byt_get_max_pstate,
|
.get_max = byt_get_max_pstate,
|
||||||
.get_min = byt_get_min_pstate,
|
.get_min = byt_get_min_pstate,
|
||||||
.get_turbo = byt_get_max_pstate,
|
.get_turbo = byt_get_max_pstate,
|
||||||
.set = core_set_pstate,
|
.set = byt_set_pstate,
|
||||||
|
.get_vid = byt_get_vid,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -462,7 +506,7 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
|
||||||
|
|
||||||
cpu->pstate.current_pstate = pstate;
|
cpu->pstate.current_pstate = pstate;
|
||||||
|
|
||||||
pstate_funcs.set(pstate);
|
pstate_funcs.set(cpu, pstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
|
static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
|
||||||
|
@ -488,6 +532,9 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
|
||||||
cpu->pstate.max_pstate = pstate_funcs.get_max();
|
cpu->pstate.max_pstate = pstate_funcs.get_max();
|
||||||
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
|
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
|
||||||
|
|
||||||
|
if (pstate_funcs.get_vid)
|
||||||
|
pstate_funcs.get_vid(cpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* goto max pstate so we don't slow up boot if we are built-in if we are
|
* goto max pstate so we don't slow up boot if we are built-in if we are
|
||||||
* a module we will take care of it during normal operation
|
* a module we will take care of it during normal operation
|
||||||
|
@ -568,15 +615,6 @@ static void intel_pstate_timer_func(unsigned long __data)
|
||||||
|
|
||||||
intel_pstate_sample(cpu);
|
intel_pstate_sample(cpu);
|
||||||
intel_pstate_adjust_busy_pstate(cpu);
|
intel_pstate_adjust_busy_pstate(cpu);
|
||||||
|
|
||||||
if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) {
|
|
||||||
cpu->min_pstate_count++;
|
|
||||||
if (!(cpu->min_pstate_count % 5)) {
|
|
||||||
intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
cpu->min_pstate_count = 0;
|
|
||||||
|
|
||||||
intel_pstate_set_sample_time(cpu);
|
intel_pstate_set_sample_time(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,6 +820,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
|
||||||
pstate_funcs.get_min = funcs->get_min;
|
pstate_funcs.get_min = funcs->get_min;
|
||||||
pstate_funcs.get_turbo = funcs->get_turbo;
|
pstate_funcs.get_turbo = funcs->get_turbo;
|
||||||
pstate_funcs.set = funcs->set;
|
pstate_funcs.set = funcs->set;
|
||||||
|
pstate_funcs.get_vid = funcs->get_vid;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ACPI)
|
#if IS_ENABLED(CONFIG_ACPI)
|
||||||
|
|
|
@ -97,6 +97,7 @@ static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver kirkwood_cpufreq_driver = {
|
static struct cpufreq_driver kirkwood_cpufreq_driver = {
|
||||||
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.get = kirkwood_cpufreq_get_cpu_frequency,
|
.get = kirkwood_cpufreq_get_cpu_frequency,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = kirkwood_cpufreq_target,
|
.target_index = kirkwood_cpufreq_target,
|
||||||
|
|
|
@ -162,7 +162,7 @@ static int omap_cpu_exit(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver omap_driver = {
|
static struct cpufreq_driver omap_driver = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = omap_target,
|
.target_index = omap_target,
|
||||||
.get = omap_getspeed,
|
.get = omap_getspeed,
|
||||||
|
|
|
@ -213,6 +213,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
|
||||||
cpu, target_freq,
|
cpu, target_freq,
|
||||||
(pcch_virt_addr + pcc_cpu_data->input_offset));
|
(pcch_virt_addr + pcc_cpu_data->input_offset));
|
||||||
|
|
||||||
|
freqs.old = policy->cur;
|
||||||
freqs.new = target_freq;
|
freqs.new = target_freq;
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||||
|
|
||||||
|
@ -228,25 +229,20 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
|
||||||
memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
|
memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
|
||||||
|
|
||||||
status = ioread16(&pcch_hdr->status);
|
status = ioread16(&pcch_hdr->status);
|
||||||
|
iowrite16(0, &pcch_hdr->status);
|
||||||
|
|
||||||
|
cpufreq_notify_post_transition(policy, &freqs, status != CMD_COMPLETE);
|
||||||
|
spin_unlock(&pcc_lock);
|
||||||
|
|
||||||
if (status != CMD_COMPLETE) {
|
if (status != CMD_COMPLETE) {
|
||||||
pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
|
pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
|
||||||
cpu, status);
|
cpu, status);
|
||||||
goto cmd_incomplete;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
iowrite16(0, &pcch_hdr->status);
|
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
|
||||||
pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
|
pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
|
||||||
spin_unlock(&pcc_lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cmd_incomplete:
|
|
||||||
freqs.new = freqs.old;
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
|
||||||
iowrite16(0, &pcch_hdr->status);
|
|
||||||
spin_unlock(&pcc_lock);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcc_get_offset(int cpu)
|
static int pcc_get_offset(int cpu)
|
||||||
|
|
|
@ -26,41 +26,108 @@
|
||||||
static unsigned int busfreq; /* FSB, in 10 kHz */
|
static unsigned int busfreq; /* FSB, in 10 kHz */
|
||||||
static unsigned int max_multiplier;
|
static unsigned int max_multiplier;
|
||||||
|
|
||||||
|
static unsigned int param_busfreq = 0;
|
||||||
|
static unsigned int param_max_multiplier = 0;
|
||||||
|
|
||||||
|
module_param_named(max_multiplier, param_max_multiplier, uint, S_IRUGO);
|
||||||
|
MODULE_PARM_DESC(max_multiplier, "Maximum multiplier (allowed values: 20 30 35 40 45 50 55 60)");
|
||||||
|
|
||||||
|
module_param_named(bus_frequency, param_busfreq, uint, S_IRUGO);
|
||||||
|
MODULE_PARM_DESC(bus_frequency, "Bus frequency in kHz");
|
||||||
|
|
||||||
/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
|
/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
|
||||||
static struct cpufreq_frequency_table clock_ratio[] = {
|
static struct cpufreq_frequency_table clock_ratio[] = {
|
||||||
{45, /* 000 -> 4.5x */ 0},
|
|
||||||
{50, /* 001 -> 5.0x */ 0},
|
|
||||||
{40, /* 010 -> 4.0x */ 0},
|
|
||||||
{55, /* 011 -> 5.5x */ 0},
|
|
||||||
{20, /* 100 -> 2.0x */ 0},
|
|
||||||
{30, /* 101 -> 3.0x */ 0},
|
|
||||||
{60, /* 110 -> 6.0x */ 0},
|
{60, /* 110 -> 6.0x */ 0},
|
||||||
|
{55, /* 011 -> 5.5x */ 0},
|
||||||
|
{50, /* 001 -> 5.0x */ 0},
|
||||||
|
{45, /* 000 -> 4.5x */ 0},
|
||||||
|
{40, /* 010 -> 4.0x */ 0},
|
||||||
{35, /* 111 -> 3.5x */ 0},
|
{35, /* 111 -> 3.5x */ 0},
|
||||||
|
{30, /* 101 -> 3.0x */ 0},
|
||||||
|
{20, /* 100 -> 2.0x */ 0},
|
||||||
{0, CPUFREQ_TABLE_END}
|
{0, CPUFREQ_TABLE_END}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const u8 index_to_register[8] = { 6, 3, 1, 0, 2, 7, 5, 4 };
|
||||||
|
static const u8 register_to_index[8] = { 3, 2, 4, 1, 7, 6, 0, 5 };
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
unsigned freq;
|
||||||
|
unsigned mult;
|
||||||
|
} usual_frequency_table[] = {
|
||||||
|
{ 400000, 40 }, // 100 * 4
|
||||||
|
{ 450000, 45 }, // 100 * 4.5
|
||||||
|
{ 475000, 50 }, // 95 * 5
|
||||||
|
{ 500000, 50 }, // 100 * 5
|
||||||
|
{ 506250, 45 }, // 112.5 * 4.5
|
||||||
|
{ 533500, 55 }, // 97 * 5.5
|
||||||
|
{ 550000, 55 }, // 100 * 5.5
|
||||||
|
{ 562500, 50 }, // 112.5 * 5
|
||||||
|
{ 570000, 60 }, // 95 * 6
|
||||||
|
{ 600000, 60 }, // 100 * 6
|
||||||
|
{ 618750, 55 }, // 112.5 * 5.5
|
||||||
|
{ 660000, 55 }, // 120 * 5.5
|
||||||
|
{ 675000, 60 }, // 112.5 * 6
|
||||||
|
{ 720000, 60 }, // 120 * 6
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FREQ_RANGE 3000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
|
* powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
|
||||||
*
|
*
|
||||||
* Returns the current setting of the frequency multiplier. Core clock
|
* Returns the current setting of the frequency multiplier. Core clock
|
||||||
* speed is frequency of the Front-Side Bus multiplied with this value.
|
* speed is frequency of the Front-Side Bus multiplied with this value.
|
||||||
*/
|
*/
|
||||||
static int powernow_k6_get_cpu_multiplier(void)
|
static int powernow_k6_get_cpu_multiplier(void)
|
||||||
{
|
{
|
||||||
u64 invalue = 0;
|
unsigned long invalue = 0;
|
||||||
u32 msrval;
|
u32 msrval;
|
||||||
|
|
||||||
|
local_irq_disable();
|
||||||
|
|
||||||
msrval = POWERNOW_IOPORT + 0x1;
|
msrval = POWERNOW_IOPORT + 0x1;
|
||||||
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
||||||
invalue = inl(POWERNOW_IOPORT + 0x8);
|
invalue = inl(POWERNOW_IOPORT + 0x8);
|
||||||
msrval = POWERNOW_IOPORT + 0x0;
|
msrval = POWERNOW_IOPORT + 0x0;
|
||||||
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
||||||
|
|
||||||
return clock_ratio[(invalue >> 5)&7].driver_data;
|
local_irq_enable();
|
||||||
|
|
||||||
|
return clock_ratio[register_to_index[(invalue >> 5)&7]].driver_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
|
||||||
|
{
|
||||||
|
unsigned long outvalue, invalue;
|
||||||
|
unsigned long msrval;
|
||||||
|
unsigned long cr0;
|
||||||
|
|
||||||
|
/* we now need to transform best_i to the BVC format, see AMD#23446 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The processor doesn't respond to inquiry cycles while changing the
|
||||||
|
* frequency, so we must disable cache.
|
||||||
|
*/
|
||||||
|
local_irq_disable();
|
||||||
|
cr0 = read_cr0();
|
||||||
|
write_cr0(cr0 | X86_CR0_CD);
|
||||||
|
wbinvd();
|
||||||
|
|
||||||
|
outvalue = (1<<12) | (1<<10) | (1<<9) | (index_to_register[best_i]<<5);
|
||||||
|
|
||||||
|
msrval = POWERNOW_IOPORT + 0x1;
|
||||||
|
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
||||||
|
invalue = inl(POWERNOW_IOPORT + 0x8);
|
||||||
|
invalue = invalue & 0x1f;
|
||||||
|
outvalue = outvalue | invalue;
|
||||||
|
outl(outvalue, (POWERNOW_IOPORT + 0x8));
|
||||||
|
msrval = POWERNOW_IOPORT + 0x0;
|
||||||
|
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
||||||
|
|
||||||
|
write_cr0(cr0);
|
||||||
|
local_irq_enable();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* powernow_k6_target - set the PowerNow! multiplier
|
* powernow_k6_target - set the PowerNow! multiplier
|
||||||
|
@ -71,8 +138,6 @@ static int powernow_k6_get_cpu_multiplier(void)
|
||||||
static int powernow_k6_target(struct cpufreq_policy *policy,
|
static int powernow_k6_target(struct cpufreq_policy *policy,
|
||||||
unsigned int best_i)
|
unsigned int best_i)
|
||||||
{
|
{
|
||||||
unsigned long outvalue = 0, invalue = 0;
|
|
||||||
unsigned long msrval;
|
|
||||||
struct cpufreq_freqs freqs;
|
struct cpufreq_freqs freqs;
|
||||||
|
|
||||||
if (clock_ratio[best_i].driver_data > max_multiplier) {
|
if (clock_ratio[best_i].driver_data > max_multiplier) {
|
||||||
|
@ -85,35 +150,63 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||||
|
|
||||||
/* we now need to transform best_i to the BVC format, see AMD#23446 */
|
powernow_k6_set_cpu_multiplier(best_i);
|
||||||
|
|
||||||
outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
|
|
||||||
|
|
||||||
msrval = POWERNOW_IOPORT + 0x1;
|
|
||||||
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
|
||||||
invalue = inl(POWERNOW_IOPORT + 0x8);
|
|
||||||
invalue = invalue & 0xf;
|
|
||||||
outvalue = outvalue | invalue;
|
|
||||||
outl(outvalue , (POWERNOW_IOPORT + 0x8));
|
|
||||||
msrval = POWERNOW_IOPORT + 0x0;
|
|
||||||
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
unsigned int i, f;
|
unsigned int i, f;
|
||||||
|
unsigned khz;
|
||||||
|
|
||||||
if (policy->cpu != 0)
|
if (policy->cpu != 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* get frequencies */
|
max_multiplier = 0;
|
||||||
max_multiplier = powernow_k6_get_cpu_multiplier();
|
khz = cpu_khz;
|
||||||
busfreq = cpu_khz / max_multiplier;
|
for (i = 0; i < ARRAY_SIZE(usual_frequency_table); i++) {
|
||||||
|
if (khz >= usual_frequency_table[i].freq - FREQ_RANGE &&
|
||||||
|
khz <= usual_frequency_table[i].freq + FREQ_RANGE) {
|
||||||
|
khz = usual_frequency_table[i].freq;
|
||||||
|
max_multiplier = usual_frequency_table[i].mult;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (param_max_multiplier) {
|
||||||
|
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||||
|
if (clock_ratio[i].driver_data == param_max_multiplier) {
|
||||||
|
max_multiplier = param_max_multiplier;
|
||||||
|
goto have_max_multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!max_multiplier) {
|
||||||
|
printk(KERN_WARNING "powernow-k6: unknown frequency %u, cannot determine current multiplier\n", khz);
|
||||||
|
printk(KERN_WARNING "powernow-k6: use module parameters max_multiplier and bus_frequency\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
have_max_multiplier:
|
||||||
|
param_max_multiplier = max_multiplier;
|
||||||
|
|
||||||
|
if (param_busfreq) {
|
||||||
|
if (param_busfreq >= 50000 && param_busfreq <= 150000) {
|
||||||
|
busfreq = param_busfreq / 10;
|
||||||
|
goto have_busfreq;
|
||||||
|
}
|
||||||
|
printk(KERN_ERR "powernow-k6: invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
busfreq = khz / max_multiplier;
|
||||||
|
have_busfreq:
|
||||||
|
param_busfreq = busfreq * 10;
|
||||||
|
|
||||||
/* table init */
|
/* table init */
|
||||||
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
|
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||||
|
@ -125,7 +218,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cpuinfo and default policy values */
|
/* cpuinfo and default policy values */
|
||||||
policy->cpuinfo.transition_latency = 200000;
|
policy->cpuinfo.transition_latency = 500000;
|
||||||
|
|
||||||
return cpufreq_table_validate_and_show(policy, clock_ratio);
|
return cpufreq_table_validate_and_show(policy, clock_ratio);
|
||||||
}
|
}
|
||||||
|
|
|
@ -964,14 +964,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
|
||||||
cpufreq_cpu_put(policy);
|
cpufreq_cpu_put(policy);
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||||
|
|
||||||
res = transition_fid_vid(data, fid, vid);
|
res = transition_fid_vid(data, fid, vid);
|
||||||
if (res)
|
cpufreq_notify_post_transition(policy, &freqs, res);
|
||||||
freqs.new = freqs.old;
|
|
||||||
else
|
|
||||||
freqs.new = find_khz_freq_from_fid(data->currfid);
|
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -423,6 +423,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver pxa_cpufreq_driver = {
|
static struct cpufreq_driver pxa_cpufreq_driver = {
|
||||||
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = pxa_set_target,
|
.target_index = pxa_set_target,
|
||||||
.init = pxa_cpufreq_init,
|
.init = pxa_cpufreq_init,
|
||||||
|
|
|
@ -201,6 +201,7 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver pxa3xx_cpufreq_driver = {
|
static struct cpufreq_driver pxa3xx_cpufreq_driver = {
|
||||||
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = pxa3xx_cpufreq_set,
|
.target_index = pxa3xx_cpufreq_set,
|
||||||
.init = pxa3xx_cpufreq_init,
|
.init = pxa3xx_cpufreq_init,
|
||||||
|
|
|
@ -481,7 +481,7 @@ err_hclk:
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver s3c2416_cpufreq_driver = {
|
static struct cpufreq_driver s3c2416_cpufreq_driver = {
|
||||||
.flags = 0,
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = s3c2416_cpufreq_set_target,
|
.target_index = s3c2416_cpufreq_set_target,
|
||||||
.get = s3c2416_cpufreq_get_speed,
|
.get = s3c2416_cpufreq_get_speed,
|
||||||
|
|
|
@ -22,8 +22,6 @@
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
#include <mach/hardware.h>
|
|
||||||
|
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
#include <asm/mach/map.h>
|
#include <asm/mach/map.h>
|
||||||
|
|
||||||
|
@ -55,7 +53,7 @@ static inline int within_khz(unsigned long a, unsigned long b)
|
||||||
* specified in @cfg. The values are stored in @cfg for later use
|
* specified in @cfg. The values are stored in @cfg for later use
|
||||||
* by the relevant set routine if the request settings can be reached.
|
* by the relevant set routine if the request settings can be reached.
|
||||||
*/
|
*/
|
||||||
int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
|
static int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
|
||||||
{
|
{
|
||||||
unsigned int hdiv, pdiv;
|
unsigned int hdiv, pdiv;
|
||||||
unsigned long hclk, fclk, armclk;
|
unsigned long hclk, fclk, armclk;
|
||||||
|
@ -242,7 +240,7 @@ static int s3c2440_cpufreq_calctable(struct s3c_cpufreq_config *cfg,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct s3c_cpufreq_info s3c2440_cpufreq_info = {
|
static struct s3c_cpufreq_info s3c2440_cpufreq_info = {
|
||||||
.max = {
|
.max = {
|
||||||
.fclk = 400000000,
|
.fclk = 400000000,
|
||||||
.hclk = 133333333,
|
.hclk = 133333333,
|
||||||
|
|
|
@ -448,7 +448,7 @@ static int s3c_cpufreq_resume(struct cpufreq_policy *policy)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct cpufreq_driver s3c24xx_driver = {
|
static struct cpufreq_driver s3c24xx_driver = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.target = s3c_cpufreq_target,
|
.target = s3c_cpufreq_target,
|
||||||
.get = s3c_cpufreq_get,
|
.get = s3c_cpufreq_get,
|
||||||
.init = s3c_cpufreq_init,
|
.init = s3c_cpufreq_init,
|
||||||
|
@ -509,7 +509,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __init s3c_cpufreq_auto_io(void)
|
static int __init s3c_cpufreq_auto_io(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver s3c64xx_cpufreq_driver = {
|
static struct cpufreq_driver s3c64xx_cpufreq_driver = {
|
||||||
.flags = 0,
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = s3c64xx_cpufreq_set_target,
|
.target_index = s3c64xx_cpufreq_set_target,
|
||||||
.get = s3c64xx_cpufreq_get_speed,
|
.get = s3c64xx_cpufreq_get_speed,
|
||||||
|
|
|
@ -560,7 +560,7 @@ static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver s5pv210_driver = {
|
static struct cpufreq_driver s5pv210_driver = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = s5pv210_target,
|
.target_index = s5pv210_target,
|
||||||
.get = s5pv210_getspeed,
|
.get = s5pv210_getspeed,
|
||||||
|
|
|
@ -201,7 +201,7 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver sa1100_driver __refdata = {
|
static struct cpufreq_driver sa1100_driver __refdata = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = sa1100_target,
|
.target_index = sa1100_target,
|
||||||
.get = sa11x0_getspeed,
|
.get = sa11x0_getspeed,
|
||||||
|
|
|
@ -312,7 +312,7 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
|
||||||
/* sa1110_driver needs __refdata because it must remain after init registers
|
/* sa1110_driver needs __refdata because it must remain after init registers
|
||||||
* it with cpufreq_register_driver() */
|
* it with cpufreq_register_driver() */
|
||||||
static struct cpufreq_driver sa1110_driver __refdata = {
|
static struct cpufreq_driver sa1110_driver __refdata = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = sa1110_target,
|
.target_index = sa1110_target,
|
||||||
.get = sa11x0_getspeed,
|
.get = sa11x0_getspeed,
|
||||||
|
|
|
@ -138,7 +138,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
|
||||||
}
|
}
|
||||||
|
|
||||||
newfreq = clk_round_rate(srcclk, newfreq * mult);
|
newfreq = clk_round_rate(srcclk, newfreq * mult);
|
||||||
if (newfreq < 0) {
|
if (newfreq <= 0) {
|
||||||
pr_err("clk_round_rate failed for cpu src clock\n");
|
pr_err("clk_round_rate failed for cpu src clock\n");
|
||||||
return newfreq;
|
return newfreq;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ static int spear_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
|
|
||||||
static struct cpufreq_driver spear_cpufreq_driver = {
|
static struct cpufreq_driver spear_cpufreq_driver = {
|
||||||
.name = "cpufreq-spear",
|
.name = "cpufreq-spear",
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = spear_cpufreq_target,
|
.target_index = spear_cpufreq_target,
|
||||||
.get = spear_cpufreq_get,
|
.get = spear_cpufreq_get,
|
||||||
|
|
|
@ -214,6 +214,7 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_driver tegra_cpufreq_driver = {
|
static struct cpufreq_driver tegra_cpufreq_driver = {
|
||||||
|
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||||
.verify = cpufreq_generic_frequency_table_verify,
|
.verify = cpufreq_generic_frequency_table_verify,
|
||||||
.target_index = tegra_target,
|
.target_index = tegra_target,
|
||||||
.get = tegra_getspeed,
|
.get = tegra_getspeed,
|
||||||
|
|
|
@ -46,20 +46,18 @@ static int ucv2_target(struct cpufreq_policy *policy,
|
||||||
unsigned int target_freq,
|
unsigned int target_freq,
|
||||||
unsigned int relation)
|
unsigned int relation)
|
||||||
{
|
{
|
||||||
unsigned int cur = ucv2_getspeed(0);
|
|
||||||
struct cpufreq_freqs freqs;
|
struct cpufreq_freqs freqs;
|
||||||
struct clk *mclk = clk_get(NULL, "MAIN_CLK");
|
struct clk *mclk = clk_get(NULL, "MAIN_CLK");
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
freqs.old = policy->cur;
|
||||||
|
freqs.new = target_freq;
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||||
|
ret = clk_set_rate(mclk, target_freq * 1000);
|
||||||
|
cpufreq_notify_post_transition(policy, &freqs, ret);
|
||||||
|
|
||||||
if (!clk_set_rate(mclk, target_freq * 1000)) {
|
return ret;
|
||||||
freqs.old = cur;
|
|
||||||
freqs.new = target_freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init ucv2_cpu_init(struct cpufreq_policy *policy)
|
static int __init ucv2_cpu_init(struct cpufreq_policy *policy)
|
||||||
|
|
|
@ -252,6 +252,15 @@ struct cpufreq_driver {
|
||||||
*/
|
*/
|
||||||
#define CPUFREQ_ASYNC_NOTIFICATION (1 << 4)
|
#define CPUFREQ_ASYNC_NOTIFICATION (1 << 4)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set by drivers which want cpufreq core to check if CPU is running at a
|
||||||
|
* frequency present in freq-table exposed by the driver. For these drivers if
|
||||||
|
* CPU is found running at an out of table freq, we will try to set it to a freq
|
||||||
|
* from the table. And if that fails, we will stop further boot process by
|
||||||
|
* issuing a BUG_ON().
|
||||||
|
*/
|
||||||
|
#define CPUFREQ_NEED_INITIAL_FREQ_CHECK (1 << 5)
|
||||||
|
|
||||||
int cpufreq_register_driver(struct cpufreq_driver *driver_data);
|
int cpufreq_register_driver(struct cpufreq_driver *driver_data);
|
||||||
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
|
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
|
||||||
|
|
||||||
|
@ -306,6 +315,8 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
|
||||||
|
|
||||||
void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||||
struct cpufreq_freqs *freqs, unsigned int state);
|
struct cpufreq_freqs *freqs, unsigned int state);
|
||||||
|
void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
|
||||||
|
struct cpufreq_freqs *freqs, int transition_failed);
|
||||||
|
|
||||||
#else /* CONFIG_CPU_FREQ */
|
#else /* CONFIG_CPU_FREQ */
|
||||||
static inline int cpufreq_register_notifier(struct notifier_block *nb,
|
static inline int cpufreq_register_notifier(struct notifier_block *nb,
|
||||||
|
@ -439,6 +450,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
||||||
unsigned int target_freq,
|
unsigned int target_freq,
|
||||||
unsigned int relation,
|
unsigned int relation,
|
||||||
unsigned int *index);
|
unsigned int *index);
|
||||||
|
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
||||||
|
unsigned int freq);
|
||||||
|
|
||||||
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
|
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
|
||||||
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
|
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
|
||||||
|
|
Loading…
Reference in a new issue