summaryrefslogtreecommitdiffstats
path: root/arch/blackfin/mach-common/dpmc.c
diff options
context:
space:
mode:
authorGraf Yang <graf.yang@analog.com>2010-01-28 10:46:55 +0000
committerMike Frysinger <vapier@gentoo.org>2011-03-18 04:01:03 -0400
commit6f546bc3ac9eedbf770bf3bcbc45ce2ea32c94ad (patch)
tree7089509d165a19156c3be21950f96160fb1f06a1 /arch/blackfin/mach-common/dpmc.c
parent820b127dae869cbbd2133f066e8b8f32a90d46e5 (diff)
Blackfin: SMP: implement cpu_freq support
Re-use some of the existing cpu hotplugging code in the process. Signed-off-by: Graf Yang <graf.yang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/mach-common/dpmc.c')
-rw-r--r--arch/blackfin/mach-common/dpmc.c50
1 files changed, 48 insertions, 2 deletions
diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c
index 02c7efd1bcf..382099fd556 100644
--- a/arch/blackfin/mach-common/dpmc.c
+++ b/arch/blackfin/mach-common/dpmc.c
@@ -61,17 +61,63 @@ err_out:
}
#ifdef CONFIG_CPU_FREQ
+# ifdef CONFIG_SMP
+static void bfin_idle_this_cpu(void *info)
+{
+ unsigned long flags = 0;
+ unsigned long iwr0, iwr1, iwr2;
+ unsigned int cpu = smp_processor_id();
+
+ local_irq_save_hw(flags);
+ bfin_iwr_set_sup0(&iwr0, &iwr1, &iwr2);
+
+ platform_clear_ipi(cpu, IRQ_SUPPLE_0);
+ SSYNC();
+ asm("IDLE;");
+ bfin_iwr_restore(iwr0, iwr1, iwr2);
+
+ local_irq_restore_hw(flags);
+}
+
+static void bfin_idle_cpu(void)
+{
+ smp_call_function(bfin_idle_this_cpu, NULL, 0);
+}
+
+static void bfin_wakeup_cpu(void)
+{
+ unsigned int cpu;
+ unsigned int this_cpu = smp_processor_id();
+ cpumask_t mask = cpu_online_map;
+
+ cpu_clear(this_cpu, mask);
+ for_each_cpu_mask(cpu, mask)
+ platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
+}
+
+# else
+static void bfin_idle_cpu(void) {}
+static void bfin_wakeup_cpu(void) {}
+# endif
+
static int
vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
{
struct cpufreq_freqs *freq = data;
+ if (freq->cpu != CPUFREQ_CPU)
+ return 0;
+
if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) {
+ bfin_idle_cpu();
bfin_set_vlev(bfin_get_vlev(freq->new));
udelay(pdata->vr_settling_time); /* Wait until Volatge settled */
-
- } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)
+ bfin_wakeup_cpu();
+ } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) {
+ bfin_idle_cpu();
bfin_set_vlev(bfin_get_vlev(freq->new));
+ bfin_wakeup_cpu();
+ }
return 0;
}