Permalink
Browse files

mach-s5pv310: cpufreq smooth scaling

When a cpufreq governor policy requires to switch from a very low
frequency to a very high frequency, the low lever driver may jump to a
frequency lower than the target value requested by the higher layers,
according to the configuration of the cpufreq step up sequence.

For example, with the 2-step selection (CONFIG_FREQ_STEP_UP_L2_L0=y) a
change from L3 to L0 (500MHz to 1200MHz) would jump to 800MHz, instead
of the requested 1200MHz.

To satisfy the requirements of the higher cpufreq layers introduce a
smooth scaling mechanism that allows to switch to the target frequency
incrementally in multiple steps.

So, if it's not possible to switch to the target frequency in a single
step, schedule an additional frequency step later in the future (after
0.5sec by default) using a delayed workqueue.

The additional step is performed by the low-level driver and it's
totally transparent for the higher layers.

Signed-off-by: Andrea Righi <andrea@betterlinux.com>
  • Loading branch information...
1 parent 9d9903d commit 888555febc22e72515d124477bee0a1c515289a1 @arighi arighi committed with Oct 1, 2011
Showing with 32 additions and 1 deletion.
  1. +32 −1 arch/arm/mach-s5pv310/cpufreq.c
@@ -1157,12 +1157,36 @@ void s5pv310_set_frequency(unsigned int old_index, unsigned int new_index)
}
}
+unsigned int target_freq_smooth;
+
+static void do_smooth_freq(struct work_struct *work)
+{
+ unsigned int target_freq;
+
+ mutex_lock(&set_cpu_freq_change);
+ target_freq = target_freq_smooth;
+ mutex_unlock(&set_cpu_freq_change);
+
+ if (likely(target_freq)) {
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+ int ret;
+
+ printk(KERN_INFO "%s: cpu%d: freq set to %u\n",
+ __func__, policy->cpu, target_freq_smooth);
+ ret = cpufreq_driver_target(policy,
+ target_freq_smooth, CPUFREQ_RELATION_H);
+ WARN_ON(ret < 0);
+ }
+}
+
+static DECLARE_DELAYED_WORK(smooth_freq_work, do_smooth_freq);
+
static int s5pv310_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
int ret = 0;
- unsigned int index, old_index;
+ unsigned int index, old_index, target_index;
unsigned int arm_volt;
#ifndef CONFIG_S5PV310_BUSFREQ
unsigned int int_volt;
@@ -1222,6 +1246,8 @@ static int s5pv310_target(struct cpufreq_policy *policy,
if ((index < g_cpufreq_limit_level) && check_gov)
index = g_cpufreq_limit_level;
+ target_index = index;
+
if (s5pv310_max_armclk == ARMCLOCK_1200MHZ) {
#ifdef CONFIG_FREQ_STEP_UP_L2_L0
/* change L2 -> L0 */
@@ -1252,6 +1278,11 @@ static int s5pv310_target(struct cpufreq_policy *policy,
freqs.new = s5pv310_freq_table[index].frequency;
freqs.cpu = policy->cpu;
+ if (index != target_index) {
+ target_freq_smooth = target_freq;
+ schedule_delayed_work_on(0, &smooth_freq_work, HZ >> 1);
+ }
+
/* If the new frequency is same with previous frequency, skip */
if (freqs.new == freqs.old)
goto bus_freq;

0 comments on commit 888555f

Please sign in to comment.