Skip to content

Commit

Permalink
mach-s5pv310: cpufreq smooth scaling
Browse files Browse the repository at this point in the history
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
Andrea Righi authored and Entropy512 committed Feb 7, 2012
1 parent 9d9903d commit 888555f
Showing 1 changed file with 32 additions and 1 deletion.
33 changes: 32 additions & 1 deletion arch/arm/mach-s5pv310/cpufreq.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 888555f

Please sign in to comment.