summaryrefslogtreecommitdiff
path: root/drivers/cpufreq/omap-cpufreq.c
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/cpufreq/omap-cpufreq.c
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/cpufreq/omap-cpufreq.c')
-rw-r--r--drivers/cpufreq/omap-cpufreq.c144
1 files changed, 108 insertions, 36 deletions
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index a0acd0b..f31fcfc 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -22,7 +22,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/pm_opp.h>
+#include <linux/opp.h>
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -40,6 +40,13 @@ static struct clk *mpu_clk;
static struct device *mpu_dev;
static struct regulator *mpu_reg;
+static int omap_verify_speed(struct cpufreq_policy *policy)
+{
+ if (!freq_table)
+ return -EINVAL;
+ return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
static unsigned int omap_getspeed(unsigned int cpu)
{
unsigned long rate;
@@ -51,17 +58,42 @@ static unsigned int omap_getspeed(unsigned int cpu)
return rate;
}
-static int omap_target(struct cpufreq_policy *policy, unsigned int index)
+static int omap_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
- int r, ret;
- struct dev_pm_opp *opp;
+ unsigned int i;
+ int r, ret = 0;
+ struct cpufreq_freqs freqs;
+ struct opp *opp;
unsigned long freq, volt = 0, volt_old = 0, tol = 0;
- unsigned int old_freq, new_freq;
- old_freq = omap_getspeed(policy->cpu);
- new_freq = freq_table[index].frequency;
+ if (!freq_table) {
+ dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
+ policy->cpu);
+ return -EINVAL;
+ }
- freq = new_freq * 1000;
+ ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+ relation, &i);
+ if (ret) {
+ dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n",
+ __func__, policy->cpu, target_freq, ret);
+ return ret;
+ }
+ freqs.new = freq_table[i].frequency;
+ if (!freqs.new) {
+ dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__,
+ policy->cpu, target_freq);
+ return -EINVAL;
+ }
+
+ freqs.old = omap_getspeed(policy->cpu);
+
+ if (freqs.old == freqs.new && policy->cur == freqs.new)
+ return ret;
+
+ freq = freqs.new * 1000;
ret = clk_round_rate(mpu_clk, freq);
if (IS_ERR_VALUE(ret)) {
dev_warn(mpu_dev,
@@ -73,103 +105,143 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
if (mpu_reg) {
rcu_read_lock();
- opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
+ opp = opp_find_freq_ceil(mpu_dev, &freq);
if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
- __func__, new_freq);
+ __func__, freqs.new);
return -EINVAL;
}
- volt = dev_pm_opp_get_voltage(opp);
+ volt = opp_get_voltage(opp);
rcu_read_unlock();
tol = volt * OPP_TOLERANCE / 100;
volt_old = regulator_get_voltage(mpu_reg);
}
dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n",
- old_freq / 1000, volt_old ? volt_old / 1000 : -1,
- new_freq / 1000, volt ? volt / 1000 : -1);
+ freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
+ freqs.new / 1000, volt ? volt / 1000 : -1);
+
+ /* notifiers */
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* scaling up? scale voltage before frequency */
- if (mpu_reg && (new_freq > old_freq)) {
+ if (mpu_reg && (freqs.new > freqs.old)) {
r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
if (r < 0) {
dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
__func__);
- return r;
+ freqs.new = freqs.old;
+ goto done;
}
}
- ret = clk_set_rate(mpu_clk, new_freq * 1000);
+ ret = clk_set_rate(mpu_clk, freqs.new * 1000);
/* scaling down? scale voltage after frequency */
- if (mpu_reg && (new_freq < old_freq)) {
+ if (mpu_reg && (freqs.new < freqs.old)) {
r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
if (r < 0) {
dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
__func__);
- clk_set_rate(mpu_clk, old_freq * 1000);
- return r;
+ ret = clk_set_rate(mpu_clk, freqs.old * 1000);
+ freqs.new = freqs.old;
+ goto done;
}
}
+ freqs.new = omap_getspeed(policy->cpu);
+
+done:
+ /* notifiers */
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
return ret;
}
static inline void freq_table_free(void)
{
if (atomic_dec_and_test(&freq_table_users))
- dev_pm_opp_free_cpufreq_table(mpu_dev, &freq_table);
+ opp_free_cpufreq_table(mpu_dev, &freq_table);
}
static int omap_cpu_init(struct cpufreq_policy *policy)
{
- int result;
+ int result = 0;
mpu_clk = clk_get(NULL, "cpufreq_ck");
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
- if (!freq_table) {
- result = dev_pm_opp_init_cpufreq_table(mpu_dev, &freq_table);
- if (result) {
- dev_err(mpu_dev,
- "%s: cpu%d: failed creating freq table[%d]\n",
+ if (policy->cpu >= NR_CPUS) {
+ result = -EINVAL;
+ goto fail_ck;
+ }
+
+ policy->cur = omap_getspeed(policy->cpu);
+
+ if (!freq_table)
+ result = opp_init_cpufreq_table(mpu_dev, &freq_table);
+
+ if (result) {
+ dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n",
__func__, policy->cpu, result);
- goto fail;
- }
+ goto fail_ck;
}
atomic_inc_return(&freq_table_users);
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (result)
+ goto fail_table;
+
+ cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+ policy->cur = omap_getspeed(policy->cpu);
+
+ /*
+ * On OMAP SMP configuartion, both processors share the voltage
+ * and clock. So both CPUs needs to be scaled together and hence
+ * needs software co-ordination. Use cpufreq affected_cpus
+ * interface to handle this scenario. Additional is_smp() check
+ * is to keep SMP_ON_UP build working.
+ */
+ if (is_smp())
+ cpumask_setall(policy->cpus);
+
/* FIXME: what's the actual transition time? */
- result = cpufreq_generic_init(policy, freq_table, 300 * 1000);
- if (!result)
- return 0;
+ policy->cpuinfo.transition_latency = 300 * 1000;
+ return 0;
+
+fail_table:
freq_table_free();
-fail:
+fail_ck:
clk_put(mpu_clk);
return result;
}
static int omap_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
freq_table_free();
clk_put(mpu_clk);
return 0;
}
+static struct freq_attr *omap_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
static struct cpufreq_driver omap_driver = {
.flags = CPUFREQ_STICKY,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = omap_target,
+ .verify = omap_verify_speed,
+ .target = omap_target,
.get = omap_getspeed,
.init = omap_cpu_init,
.exit = omap_cpu_exit,
.name = "omap",
- .attr = cpufreq_generic_attr,
+ .attr = omap_cpufreq_attr,
};
static int omap_cpufreq_probe(struct platform_device *pdev)