You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next' of git://github.com/kernelslacker/cpufreq
* 'next' of git://github.com/kernelslacker/cpufreq: [CPUFREQ] db8500: support all frequencies [CPUFREQ] db8500: remove unneeded for loop iteration over freq_table [CPUFREQ] ARM Exynos4210 PM/Suspend compatibility with different bootloaders [CPUFREQ] ARM: ux500: send cpufreq notification for all cpus [CPUFREQ] e_powersaver: Allow user to lower maximum voltage [CPUFREQ] e_powersaver: Check BIOS limit for CPU frequency [CPUFREQ] e_powersaver: Additional checks [CPUFREQ] exynos4210: Show list of available frequencies
This commit is contained in:
@@ -18,24 +18,29 @@
|
|||||||
static struct cpufreq_frequency_table freq_table[] = {
|
static struct cpufreq_frequency_table freq_table[] = {
|
||||||
[0] = {
|
[0] = {
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.frequency = 300000,
|
.frequency = 200000,
|
||||||
},
|
},
|
||||||
[1] = {
|
[1] = {
|
||||||
.index = 1,
|
.index = 1,
|
||||||
.frequency = 600000,
|
.frequency = 300000,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
/* Used for MAX_OPP, if available */
|
|
||||||
.index = 2,
|
.index = 2,
|
||||||
.frequency = CPUFREQ_TABLE_END,
|
.frequency = 600000,
|
||||||
},
|
},
|
||||||
[3] = {
|
[3] = {
|
||||||
|
/* Used for MAX_OPP, if available */
|
||||||
.index = 3,
|
.index = 3,
|
||||||
.frequency = CPUFREQ_TABLE_END,
|
.frequency = CPUFREQ_TABLE_END,
|
||||||
},
|
},
|
||||||
|
[4] = {
|
||||||
|
.index = 4,
|
||||||
|
.frequency = CPUFREQ_TABLE_END,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum arm_opp idx2opp[] = {
|
static enum arm_opp idx2opp[] = {
|
||||||
|
ARM_EXTCLK,
|
||||||
ARM_50_OPP,
|
ARM_50_OPP,
|
||||||
ARM_100_OPP,
|
ARM_100_OPP,
|
||||||
ARM_MAX_OPP
|
ARM_MAX_OPP
|
||||||
@@ -72,13 +77,13 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
|
|||||||
|
|
||||||
freqs.old = policy->cur;
|
freqs.old = policy->cur;
|
||||||
freqs.new = freq_table[idx].frequency;
|
freqs.new = freq_table[idx].frequency;
|
||||||
freqs.cpu = policy->cpu;
|
|
||||||
|
|
||||||
if (freqs.old == freqs.new)
|
if (freqs.old == freqs.new)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* pre-change notification */
|
/* pre-change notification */
|
||||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
for_each_cpu(freqs.cpu, policy->cpus)
|
||||||
|
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||||
|
|
||||||
/* request the PRCM unit for opp change */
|
/* request the PRCM unit for opp change */
|
||||||
if (prcmu_set_arm_opp(idx2opp[idx])) {
|
if (prcmu_set_arm_opp(idx2opp[idx])) {
|
||||||
@@ -87,7 +92,8 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* post change notification */
|
/* post change notification */
|
||||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
for_each_cpu(freqs.cpu, policy->cpus)
|
||||||
|
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -104,16 +110,18 @@ static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
|
|||||||
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
|
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int i;
|
|
||||||
|
|
||||||
BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
|
BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
|
||||||
|
|
||||||
if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
|
if (!prcmu_is_u8400()) {
|
||||||
freq_table[0].frequency = 400000;
|
freq_table[1].frequency = 400000;
|
||||||
freq_table[1].frequency = 800000;
|
freq_table[2].frequency = 800000;
|
||||||
if (prcmu_has_arm_maxopp())
|
if (prcmu_has_arm_maxopp())
|
||||||
freq_table[2].frequency = 1000000;
|
freq_table[3].frequency = 1000000;
|
||||||
}
|
}
|
||||||
|
pr_info("db8500-cpufreq : Available frequencies:\n");
|
||||||
|
while (freq_table[i].frequency != CPUFREQ_TABLE_END)
|
||||||
|
pr_info(" %d Mhz\n", freq_table[i++].frequency/1000);
|
||||||
|
|
||||||
/* get policy fields based on the table */
|
/* get policy fields based on the table */
|
||||||
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||||
@@ -127,10 +135,6 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
|
|||||||
policy->min = policy->cpuinfo.min_freq;
|
policy->min = policy->cpuinfo.min_freq;
|
||||||
policy->max = policy->cpuinfo.max_freq;
|
policy->max = policy->cpuinfo.max_freq;
|
||||||
policy->cur = db8500_cpufreq_getspeed(policy->cpu);
|
policy->cur = db8500_cpufreq_getspeed(policy->cpu);
|
||||||
|
|
||||||
for (i = 0; freq_table[i].frequency != policy->cur; i++)
|
|
||||||
;
|
|
||||||
|
|
||||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+124
-11
@@ -19,6 +19,11 @@
|
|||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
#include <asm/tsc.h>
|
#include <asm/tsc.h>
|
||||||
|
|
||||||
|
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <acpi/processor.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define EPS_BRAND_C7M 0
|
#define EPS_BRAND_C7M 0
|
||||||
#define EPS_BRAND_C7 1
|
#define EPS_BRAND_C7 1
|
||||||
#define EPS_BRAND_EDEN 2
|
#define EPS_BRAND_EDEN 2
|
||||||
@@ -27,11 +32,59 @@
|
|||||||
|
|
||||||
struct eps_cpu_data {
|
struct eps_cpu_data {
|
||||||
u32 fsb;
|
u32 fsb;
|
||||||
|
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
|
||||||
|
u32 bios_limit;
|
||||||
|
#endif
|
||||||
struct cpufreq_frequency_table freq_table[];
|
struct cpufreq_frequency_table freq_table[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct eps_cpu_data *eps_cpu[NR_CPUS];
|
static struct eps_cpu_data *eps_cpu[NR_CPUS];
|
||||||
|
|
||||||
|
/* Module parameters */
|
||||||
|
static int freq_failsafe_off;
|
||||||
|
static int voltage_failsafe_off;
|
||||||
|
static int set_max_voltage;
|
||||||
|
|
||||||
|
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
|
||||||
|
static int ignore_acpi_limit;
|
||||||
|
|
||||||
|
static struct acpi_processor_performance *eps_acpi_cpu_perf;
|
||||||
|
|
||||||
|
/* Minimum necessary to get acpi_processor_get_bios_limit() working */
|
||||||
|
static int eps_acpi_init(void)
|
||||||
|
{
|
||||||
|
eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!eps_acpi_cpu_perf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!zalloc_cpumask_var(&eps_acpi_cpu_perf->shared_cpu_map,
|
||||||
|
GFP_KERNEL)) {
|
||||||
|
kfree(eps_acpi_cpu_perf);
|
||||||
|
eps_acpi_cpu_perf = NULL;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acpi_processor_register_performance(eps_acpi_cpu_perf, 0)) {
|
||||||
|
free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
|
||||||
|
kfree(eps_acpi_cpu_perf);
|
||||||
|
eps_acpi_cpu_perf = NULL;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eps_acpi_exit(struct cpufreq_policy *policy)
|
||||||
|
{
|
||||||
|
if (eps_acpi_cpu_perf) {
|
||||||
|
acpi_processor_unregister_performance(eps_acpi_cpu_perf, 0);
|
||||||
|
free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
|
||||||
|
kfree(eps_acpi_cpu_perf);
|
||||||
|
eps_acpi_cpu_perf = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static unsigned int eps_get(unsigned int cpu)
|
static unsigned int eps_get(unsigned int cpu)
|
||||||
{
|
{
|
||||||
@@ -164,6 +217,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
|
|||||||
int k, step, voltage;
|
int k, step, voltage;
|
||||||
int ret;
|
int ret;
|
||||||
int states;
|
int states;
|
||||||
|
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
|
||||||
|
unsigned int limit;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (policy->cpu != 0)
|
if (policy->cpu != 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -244,11 +300,62 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (current_voltage > 0x1f || max_voltage > 0x1f)
|
if (current_voltage > 0x1f || max_voltage > 0x1f)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (max_voltage < min_voltage)
|
if (max_voltage < min_voltage
|
||||||
|
|| current_voltage < min_voltage
|
||||||
|
|| current_voltage > max_voltage)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Check for systems using underclocked CPU */
|
||||||
|
if (!freq_failsafe_off && max_multiplier != current_multiplier) {
|
||||||
|
printk(KERN_INFO "eps: Your processor is running at different "
|
||||||
|
"frequency then its maximum. Aborting.\n");
|
||||||
|
printk(KERN_INFO "eps: You can use freq_failsafe_off option "
|
||||||
|
"to disable this check.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (!voltage_failsafe_off && max_voltage != current_voltage) {
|
||||||
|
printk(KERN_INFO "eps: Your processor is running at different "
|
||||||
|
"voltage then its maximum. Aborting.\n");
|
||||||
|
printk(KERN_INFO "eps: You can use voltage_failsafe_off "
|
||||||
|
"option to disable this check.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calc FSB speed */
|
/* Calc FSB speed */
|
||||||
fsb = cpu_khz / current_multiplier;
|
fsb = cpu_khz / current_multiplier;
|
||||||
|
|
||||||
|
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
|
||||||
|
/* Check for ACPI processor speed limit */
|
||||||
|
if (!ignore_acpi_limit && !eps_acpi_init()) {
|
||||||
|
if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) {
|
||||||
|
printk(KERN_INFO "eps: ACPI limit %u.%uGHz\n",
|
||||||
|
limit/1000000,
|
||||||
|
(limit%1000000)/10000);
|
||||||
|
eps_acpi_exit(policy);
|
||||||
|
/* Check if max_multiplier is in BIOS limits */
|
||||||
|
if (limit && max_multiplier * fsb > limit) {
|
||||||
|
printk(KERN_INFO "eps: Aborting.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Allow user to set lower maximum voltage then that reported
|
||||||
|
* by processor */
|
||||||
|
if (brand == EPS_BRAND_C7M && set_max_voltage) {
|
||||||
|
u32 v;
|
||||||
|
|
||||||
|
/* Change mV to something hardware can use */
|
||||||
|
v = (set_max_voltage - 700) / 16;
|
||||||
|
/* Check if voltage is within limits */
|
||||||
|
if (v >= min_voltage && v <= max_voltage) {
|
||||||
|
printk(KERN_INFO "eps: Setting %dmV as maximum.\n",
|
||||||
|
v * 16 + 700);
|
||||||
|
max_voltage = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Calc number of p-states supported */
|
/* Calc number of p-states supported */
|
||||||
if (brand == EPS_BRAND_C7M)
|
if (brand == EPS_BRAND_C7M)
|
||||||
states = max_multiplier - min_multiplier + 1;
|
states = max_multiplier - min_multiplier + 1;
|
||||||
@@ -265,6 +372,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
|
|||||||
|
|
||||||
/* Copy basic values */
|
/* Copy basic values */
|
||||||
centaur->fsb = fsb;
|
centaur->fsb = fsb;
|
||||||
|
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
|
||||||
|
centaur->bios_limit = limit;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Fill frequency and MSR value table */
|
/* Fill frequency and MSR value table */
|
||||||
f_table = ¢aur->freq_table[0];
|
f_table = ¢aur->freq_table[0];
|
||||||
@@ -303,17 +413,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
|
|||||||
static int eps_cpu_exit(struct cpufreq_policy *policy)
|
static int eps_cpu_exit(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
unsigned int cpu = policy->cpu;
|
unsigned int cpu = policy->cpu;
|
||||||
struct eps_cpu_data *centaur;
|
|
||||||
u32 lo, hi;
|
|
||||||
|
|
||||||
if (eps_cpu[cpu] == NULL)
|
|
||||||
return -ENODEV;
|
|
||||||
centaur = eps_cpu[cpu];
|
|
||||||
|
|
||||||
/* Get max frequency */
|
|
||||||
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
|
|
||||||
/* Set max frequency */
|
|
||||||
eps_set_state(centaur, cpu, hi & 0xffff);
|
|
||||||
/* Bye */
|
/* Bye */
|
||||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||||
kfree(eps_cpu[cpu]);
|
kfree(eps_cpu[cpu]);
|
||||||
@@ -359,6 +459,19 @@ static void __exit eps_exit(void)
|
|||||||
cpufreq_unregister_driver(&eps_driver);
|
cpufreq_unregister_driver(&eps_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allow user to overclock his machine or to change frequency to higher after
|
||||||
|
* unloading module */
|
||||||
|
module_param(freq_failsafe_off, int, 0644);
|
||||||
|
MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check");
|
||||||
|
module_param(voltage_failsafe_off, int, 0644);
|
||||||
|
MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check");
|
||||||
|
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
|
||||||
|
module_param(ignore_acpi_limit, int, 0644);
|
||||||
|
MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit");
|
||||||
|
#endif
|
||||||
|
module_param(set_max_voltage, int, 0644);
|
||||||
|
MODULE_PARM_DESC(set_max_voltage, "Set maximum CPU voltage (mV) C7-M only");
|
||||||
|
|
||||||
MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>");
|
MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>");
|
||||||
MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
|
MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/cpufreq.h>
|
#include <linux/cpufreq.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
|
||||||
#include <mach/map.h>
|
#include <mach/map.h>
|
||||||
#include <mach/regs-clock.h>
|
#include <mach/regs-clock.h>
|
||||||
@@ -36,6 +38,10 @@ static struct regulator *int_regulator;
|
|||||||
static struct cpufreq_freqs freqs;
|
static struct cpufreq_freqs freqs;
|
||||||
static unsigned int memtype;
|
static unsigned int memtype;
|
||||||
|
|
||||||
|
static unsigned int locking_frequency;
|
||||||
|
static bool frequency_locked;
|
||||||
|
static DEFINE_MUTEX(cpufreq_lock);
|
||||||
|
|
||||||
enum exynos4_memory_type {
|
enum exynos4_memory_type {
|
||||||
DDR2 = 4,
|
DDR2 = 4,
|
||||||
LPDDR2,
|
LPDDR2,
|
||||||
@@ -405,22 +411,32 @@ static int exynos4_target(struct cpufreq_policy *policy,
|
|||||||
{
|
{
|
||||||
unsigned int index, old_index;
|
unsigned int index, old_index;
|
||||||
unsigned int arm_volt, int_volt;
|
unsigned int arm_volt, int_volt;
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
freqs.old = exynos4_getspeed(policy->cpu);
|
freqs.old = exynos4_getspeed(policy->cpu);
|
||||||
|
|
||||||
|
mutex_lock(&cpufreq_lock);
|
||||||
|
|
||||||
|
if (frequency_locked && target_freq != locking_frequency) {
|
||||||
|
err = -EAGAIN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
|
if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
|
||||||
freqs.old, relation, &old_index))
|
freqs.old, relation, &old_index))
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
|
||||||
if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
|
if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
|
||||||
target_freq, relation, &index))
|
target_freq, relation, &index))
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
|
||||||
freqs.new = exynos4_freq_table[index].frequency;
|
freqs.new = exynos4_freq_table[index].frequency;
|
||||||
freqs.cpu = policy->cpu;
|
freqs.cpu = policy->cpu;
|
||||||
|
|
||||||
if (freqs.new == freqs.old)
|
if (freqs.new == freqs.old)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
/* get the voltage value */
|
/* get the voltage value */
|
||||||
arm_volt = exynos4_volt_table[index].arm_volt;
|
arm_volt = exynos4_volt_table[index].arm_volt;
|
||||||
@@ -447,10 +463,16 @@ static int exynos4_target(struct cpufreq_policy *policy,
|
|||||||
|
|
||||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||||
|
|
||||||
return 0;
|
out:
|
||||||
|
mutex_unlock(&cpufreq_lock);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
/*
|
||||||
|
* These suspend/resume are used as syscore_ops, it is already too
|
||||||
|
* late to set regulator voltages at this stage.
|
||||||
|
*/
|
||||||
static int exynos4_cpufreq_suspend(struct cpufreq_policy *policy)
|
static int exynos4_cpufreq_suspend(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -462,8 +484,82 @@ static int exynos4_cpufreq_resume(struct cpufreq_policy *policy)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* exynos4_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
|
||||||
|
* context
|
||||||
|
* @notifier
|
||||||
|
* @pm_event
|
||||||
|
* @v
|
||||||
|
*
|
||||||
|
* While frequency_locked == true, target() ignores every frequency but
|
||||||
|
* locking_frequency. The locking_frequency value is the initial frequency,
|
||||||
|
* which is set by the bootloader. In order to eliminate possible
|
||||||
|
* inconsistency in clock values, we save and restore frequencies during
|
||||||
|
* suspend and resume and block CPUFREQ activities. Note that the standard
|
||||||
|
* suspend/resume cannot be used as they are too deep (syscore_ops) for
|
||||||
|
* regulator actions.
|
||||||
|
*/
|
||||||
|
static int exynos4_cpufreq_pm_notifier(struct notifier_block *notifier,
|
||||||
|
unsigned long pm_event, void *v)
|
||||||
|
{
|
||||||
|
struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
|
||||||
|
static unsigned int saved_frequency;
|
||||||
|
unsigned int temp;
|
||||||
|
|
||||||
|
mutex_lock(&cpufreq_lock);
|
||||||
|
switch (pm_event) {
|
||||||
|
case PM_SUSPEND_PREPARE:
|
||||||
|
if (frequency_locked)
|
||||||
|
goto out;
|
||||||
|
frequency_locked = true;
|
||||||
|
|
||||||
|
if (locking_frequency) {
|
||||||
|
saved_frequency = exynos4_getspeed(0);
|
||||||
|
|
||||||
|
mutex_unlock(&cpufreq_lock);
|
||||||
|
exynos4_target(policy, locking_frequency,
|
||||||
|
CPUFREQ_RELATION_H);
|
||||||
|
mutex_lock(&cpufreq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PM_POST_SUSPEND:
|
||||||
|
|
||||||
|
if (saved_frequency) {
|
||||||
|
/*
|
||||||
|
* While frequency_locked, only locking_frequency
|
||||||
|
* is valid for target(). In order to use
|
||||||
|
* saved_frequency while keeping frequency_locked,
|
||||||
|
* we temporarly overwrite locking_frequency.
|
||||||
|
*/
|
||||||
|
temp = locking_frequency;
|
||||||
|
locking_frequency = saved_frequency;
|
||||||
|
|
||||||
|
mutex_unlock(&cpufreq_lock);
|
||||||
|
exynos4_target(policy, locking_frequency,
|
||||||
|
CPUFREQ_RELATION_H);
|
||||||
|
mutex_lock(&cpufreq_lock);
|
||||||
|
|
||||||
|
locking_frequency = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
frequency_locked = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
mutex_unlock(&cpufreq_lock);
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block exynos4_cpufreq_nb = {
|
||||||
|
.notifier_call = exynos4_cpufreq_pm_notifier,
|
||||||
|
};
|
||||||
|
|
||||||
static int exynos4_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
static int exynos4_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
policy->cur = policy->min = policy->max = exynos4_getspeed(policy->cpu);
|
policy->cur = policy->min = policy->max = exynos4_getspeed(policy->cpu);
|
||||||
|
|
||||||
cpufreq_frequency_table_get_attr(exynos4_freq_table, policy->cpu);
|
cpufreq_frequency_table_get_attr(exynos4_freq_table, policy->cpu);
|
||||||
@@ -479,16 +575,35 @@ static int exynos4_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|||||||
*/
|
*/
|
||||||
cpumask_setall(policy->cpus);
|
cpumask_setall(policy->cpus);
|
||||||
|
|
||||||
return cpufreq_frequency_table_cpuinfo(policy, exynos4_freq_table);
|
ret = cpufreq_frequency_table_cpuinfo(policy, exynos4_freq_table);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
cpufreq_frequency_table_get_attr(exynos4_freq_table, policy->cpu);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int exynos4_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||||
|
{
|
||||||
|
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct freq_attr *exynos4_cpufreq_attr[] = {
|
||||||
|
&cpufreq_freq_attr_scaling_available_freqs,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static struct cpufreq_driver exynos4_driver = {
|
static struct cpufreq_driver exynos4_driver = {
|
||||||
.flags = CPUFREQ_STICKY,
|
.flags = CPUFREQ_STICKY,
|
||||||
.verify = exynos4_verify_speed,
|
.verify = exynos4_verify_speed,
|
||||||
.target = exynos4_target,
|
.target = exynos4_target,
|
||||||
.get = exynos4_getspeed,
|
.get = exynos4_getspeed,
|
||||||
.init = exynos4_cpufreq_cpu_init,
|
.init = exynos4_cpufreq_cpu_init,
|
||||||
|
.exit = exynos4_cpufreq_cpu_exit,
|
||||||
.name = "exynos4_cpufreq",
|
.name = "exynos4_cpufreq",
|
||||||
|
.attr = exynos4_cpufreq_attr,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.suspend = exynos4_cpufreq_suspend,
|
.suspend = exynos4_cpufreq_suspend,
|
||||||
.resume = exynos4_cpufreq_resume,
|
.resume = exynos4_cpufreq_resume,
|
||||||
@@ -501,6 +616,8 @@ static int __init exynos4_cpufreq_init(void)
|
|||||||
if (IS_ERR(cpu_clk))
|
if (IS_ERR(cpu_clk))
|
||||||
return PTR_ERR(cpu_clk);
|
return PTR_ERR(cpu_clk);
|
||||||
|
|
||||||
|
locking_frequency = exynos4_getspeed(0);
|
||||||
|
|
||||||
moutcore = clk_get(NULL, "moutcore");
|
moutcore = clk_get(NULL, "moutcore");
|
||||||
if (IS_ERR(moutcore))
|
if (IS_ERR(moutcore))
|
||||||
goto out;
|
goto out;
|
||||||
@@ -540,6 +657,8 @@ static int __init exynos4_cpufreq_init(void)
|
|||||||
printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype);
|
printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register_pm_notifier(&exynos4_cpufreq_nb);
|
||||||
|
|
||||||
return cpufreq_register_driver(&exynos4_driver);
|
return cpufreq_register_driver(&exynos4_driver);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
Reference in New Issue
Block a user