@@ -33,6 +33,8 @@
#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
#include <plat/omap-pm.h>
#include <plat/opp.h>
+#include <plat/resource.h>
+#include "../mach-omap2/pm.h"
#endif
#define VERY_HI_RATE 900000000
@@ -48,6 +50,7 @@ static struct cpufreq_frequency_table *freq_table;
#endif
static struct clk *mpu_clk;
+static struct device l3_dev;
/* TODO: Add support for SDRAM timing changes */
@@ -87,6 +90,10 @@ static int omap_target(struct cpufreq_policy *policy,
#ifdef CONFIG_ARCH_OMAP1
struct cpufreq_freqs freqs;
#endif
+#ifdef CONFIG_ARCH_OMAP3
+ struct omap_opp *opp;
+ unsigned long freq;
+#endif
int ret = 0;
/* Ensure desired rate is within allowed range. Some govenors
@@ -111,15 +118,66 @@ static int omap_target(struct cpufreq_policy *policy,
ret = clk_set_rate(mpu_clk, freqs.new * 1000);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
- if (mpu_opps) {
- unsigned long freq = target_freq * 1000;
- if (!IS_ERR(opp_find_freq_ceil(mpu_opps, &freq)))
- omap_pm_cpu_set_freq(freq);
+ freq = target_freq * 1000;
+ opp = find_opp_by_freq(OPP_MPU, freq, OPP_EQ | OPP_ENABLED);
+ if (!opp) {
+ if (relation == CPUFREQ_RELATION_H)
+ opp = find_opp_by_freq(OPP_MPU, freq,
+ OPP_H | OPP_ENABLED);
+ else if (relation == CPUFREQ_RELATION_L)
+ opp = find_opp_by_freq(OPP_MPU, freq,
+ OPP_L | OPP_ENABLED);
}
+
+ if (opp)
+ omap_pm_cpu_set_freq(opp_to_freq(opp));
+ else
+ ret = -EPERM;
#endif
return ret;
}
+static int l3_cpufreq_notifier(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct cpufreq_freqs *freq = data;
+ struct omap_opp *mpu_target_opp;
+ unsigned long l3_target_freq;
+
+ switch (val) {
+ case CPUFREQ_PRECHANGE:
+ mpu_target_opp = find_opp_by_freq(OPP_MPU, freq->new * 1000,
+ OPP_EQ | OPP_ENABLED);
+ l3_target_freq = get_l3_target_freq(mpu_target_opp);
+ if (resource_get_level("l3_freq") != l3_target_freq)
+ resource_request("l3_freq", &l3_dev, l3_target_freq);
+ break;
+
+ case CPUFREQ_POSTCHANGE:
+ break;
+
+ case CPUFREQ_RESUMECHANGE:
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct notifier_block l3_cpufreq_notifier_block = {
+ .notifier_call = l3_cpufreq_notifier
+};
+
+static void __init l3_cpufreq_init(void)
+{
+ if (cpufreq_register_notifier(&l3_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER))
+ pr_err("omap-cpufreq: L3 cpufreq registration failed\n");
+ return;
+}
+
static int __init omap_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
@@ -131,12 +189,10 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
- policy->cur = policy->min = policy->max = omap_getspeed(0);
-
if (!cpu_is_omap34xx())
clk_init_cpufreq_table(&freq_table);
else
- opp_init_cpufreq_table(mpu_opps, &freq_table);
+ opp_init_cpufreq_table(&freq_table);
if (freq_table) {
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
@@ -151,10 +207,11 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
- policy->cur = omap_getspeed(0);
+ policy->cur = omap_getspeed(smp_processor_id());
/* FIXME: what's the actual transition time? */
policy->cpuinfo.transition_latency = 300 * 1000;
+ l3_cpufreq_init();
return 0;
}