diff options
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/exynos-cpufreq.c | 62 | ||||
-rw-r--r-- | drivers/cpufreq/exynos4210-cpufreq.c | 61 |
2 files changed, 113 insertions, 10 deletions
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index b243a7ee01f..1ff48a4526b 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -17,6 +17,8 @@ #include <linux/regulator/consumer.h> #include <linux/cpufreq.h> #include <linux/suspend.h> +#include <linux/notifier.h> +#include <linux/reboot.h> #include <mach/cpufreq.h> @@ -46,7 +48,7 @@ static int exynos_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - unsigned int index, old_index; + unsigned int index, old_index = 0, i; unsigned int arm_volt, safe_arm_volt = 0; int ret = 0; struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; @@ -62,10 +64,11 @@ static int exynos_target(struct cpufreq_policy *policy, goto out; } - if (cpufreq_frequency_table_target(policy, freq_table, - freqs.old, relation, &old_index)) { - ret = -EINVAL; - goto out; + for (i = 0; (freq_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if (freqs.old == freq_table[i].frequency) { + old_index = i; + break; + } } if (cpufreq_frequency_table_target(policy, freq_table, @@ -204,8 +207,35 @@ static struct notifier_block exynos_cpufreq_nb = { .notifier_call = exynos_cpufreq_pm_notifier, }; +static int exynos_cpufreq_reboot_notifier(struct notifier_block *this, + unsigned long code, void *_cmd) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */ + mutex_lock(&cpufreq_lock); + + if (frequency_locked) + goto out; + frequency_locked = true; + + if (locking_frequency) { + mutex_unlock(&cpufreq_lock); + exynos_target(policy, locking_frequency, CPUFREQ_RELATION_H); + mutex_lock(&cpufreq_lock); + } + +out: + mutex_unlock(&cpufreq_lock); + return NOTIFY_DONE; +} + +static struct notifier_block exynos_cpufreq_reboot_nb = { + .notifier_call = exynos_cpufreq_reboot_notifier, +}; + static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) { + int ret; + policy->cur = policy->min = policy->max = exynos_getspeed(policy->cpu); cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu); @@ -228,16 +258,35 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) cpumask_setall(policy->cpus); } - return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table); + ret = cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table); + if (ret) + return ret; + + cpufreq_frequency_table_get_attr(exynos_info->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 exynos_driver = { .flags = CPUFREQ_STICKY, .verify = exynos_verify_speed, .target = exynos_target, .get = exynos_getspeed, .init = exynos_cpufreq_cpu_init, + .exit = exynos4_cpufreq_cpu_exit, .name = "exynos_cpufreq", + .attr = exynos4_cpufreq_attr, #ifdef CONFIG_PM .suspend = exynos_cpufreq_suspend, .resume = exynos_cpufreq_resume, @@ -276,6 +325,7 @@ static int __init exynos_cpufreq_init(void) } register_pm_notifier(&exynos_cpufreq_nb); + register_reboot_notifier(&exynos_cpufreq_reboot_nb); if (cpufreq_register_driver(&exynos_driver)) { pr_err("%s: failed to register cpufreq driver\n", __func__); diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c index fb148fa2767..e67453a6489 100644 --- a/drivers/cpufreq/exynos4210-cpufreq.c +++ b/drivers/cpufreq/exynos4210-cpufreq.c @@ -20,6 +20,13 @@ #include <mach/regs-clock.h> #include <mach/cpufreq.h> +#define SUPPORT_1400MHZ (1 << 31) +#define SUPPORT_1200MHZ (1 << 30) +#define SUPPORT_1000MHZ (1 << 29) + +#define SUPPORT_FREQ_SHIFT 29 +#define SUPPORT_FREQ_MASK 7 + #define CPUFREQ_LEVEL_END L5 static int max_support_idx = L0; @@ -35,10 +42,7 @@ struct cpufreq_clkdiv { unsigned int clkdiv; }; -static unsigned int exynos4210_volt_table[CPUFREQ_LEVEL_END] = { - 1250000, 1150000, 1050000, 975000, 950000, -}; - +static unsigned int exynos4210_volt_table[CPUFREQ_LEVEL_END]; static struct cpufreq_clkdiv exynos4210_clkdiv_table[CPUFREQ_LEVEL_END]; @@ -51,6 +55,28 @@ static struct cpufreq_frequency_table exynos4210_freq_table[] = { {0, CPUFREQ_TABLE_END}, }; +/* + * ASV group voltage table + */ +static const unsigned int asv_voltage[CPUFREQ_LEVEL_END][8] = { + /* + * SS, A1, A2, B1, B2, C1, C2, D + * @1200 : + * @1000 : + * @800 : ASV_VOLTAGE_TABLE + * @500 : + * @200 : + */ + { 1350000, 1350000, 1300000, 1275000, 1250000, 1225000, 1200000, + 1175000 }, + { 1300000, 1250000, 1200000, 1175000, 1150000, 1125000, 1100000, + 1075000 }, + { 1200000, 1150000, 1100000, 1075000, 1050000, 1025000, 1000000, + 975000 }, + { 1100000, 1050000, 1000000, 975000, 975000, 950000, 925000, 925000 }, + { 1050000, 1000000, 975000, 950000, 950000, 925000, 925000, 925000 }, +}; + static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = { /* * Clock divider value for following @@ -229,6 +255,31 @@ static void exynos4210_set_frequency(unsigned int old_index, } } +static void __init set_volt_table(void) +{ + unsigned int tmp, i, asv_group = 0; + + tmp = exynos_result_of_asv; + + switch (tmp & (SUPPORT_FREQ_MASK << SUPPORT_FREQ_SHIFT)) { + case SUPPORT_1200MHZ: + asv_group = (tmp & 0xF); + break; + case SUPPORT_1400MHZ: + case SUPPORT_1000MHZ: + default: + /* Not supported and assign typical ASV group */ + asv_group = 2; + break; + } + + printk(KERN_INFO "DVFS: VDD_ARM Voltage table set with %d Group\n", + asv_group); + + for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++) + exynos4210_volt_table[i] = asv_voltage[i][asv_group]; +} + int exynos4210_cpufreq_init(struct exynos_dvfs_info *info) { int i; @@ -275,6 +326,8 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info) exynos4210_clkdiv_table[i].clkdiv = tmp; } + set_volt_table(); + info->mpll_freq_khz = rate; info->pm_lock_idx = L2; info->pll_safe_idx = L2; |