diff options
author | Graf Yang <graf.yang@analog.com> | 2010-01-28 10:46:55 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2011-03-18 04:01:03 -0400 |
commit | 6f546bc3ac9eedbf770bf3bcbc45ce2ea32c94ad (patch) | |
tree | 7089509d165a19156c3be21950f96160fb1f06a1 /arch/blackfin/mach-common/dpmc.c | |
parent | 820b127dae869cbbd2133f066e8b8f32a90d46e5 (diff) | |
download | op-kernel-dev-6f546bc3ac9eedbf770bf3bcbc45ce2ea32c94ad.zip op-kernel-dev-6f546bc3ac9eedbf770bf3bcbc45ce2ea32c94ad.tar.gz |
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.c | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c index 02c7efd..382099f 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; } |