aboutsummaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c62
-rw-r--r--drivers/cpufreq/exynos4210-cpufreq.c61
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;