提交 6f546bc3 编写于 作者: G Graf Yang 提交者: Mike Frysinger

Blackfin: SMP: implement cpu_freq support

Re-use some of the existing cpu hotplugging code in the process.
Signed-off-by: NGraf Yang <graf.yang@analog.com>
Signed-off-by: NMike Frysinger <vapier@gentoo.org>
上级 820b127d
...@@ -125,6 +125,9 @@ void unset_dram_srfs(void); ...@@ -125,6 +125,9 @@ void unset_dram_srfs(void);
#define VRPAIR(vlev, freq) (((vlev) << 16) | ((freq) >> 16)) #define VRPAIR(vlev, freq) (((vlev) << 16) | ((freq) >> 16))
#ifdef CONFIG_CPU_FREQ
#define CPUFREQ_CPU 0
#endif
struct bfin_dpmc_platform_data { struct bfin_dpmc_platform_data {
const unsigned int *tuple_tab; const unsigned int *tuple_tab;
unsigned short tabsize; unsigned short tabsize;
......
...@@ -34,7 +34,7 @@ extern unsigned long dcache_invld_count[NR_CPUS]; ...@@ -34,7 +34,7 @@ extern unsigned long dcache_invld_count[NR_CPUS];
void smp_icache_flush_range_others(unsigned long start, void smp_icache_flush_range_others(unsigned long start,
unsigned long end); unsigned long end);
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2); void coreb_die(void);
void cpu_die(void); void cpu_die(void);
void platform_cpu_die(void); void platform_cpu_die(void);
int __cpu_disable(void); int __cpu_disable(void);
......
...@@ -5,30 +5,27 @@ ...@@ -5,30 +5,27 @@
* Licensed under the GPL-2 or later. * Licensed under the GPL-2 or later.
*/ */
#include <linux/smp.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/irq.h> #include <mach/pll.h>
#include <asm/smp.h>
#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
int hotplug_coreb; int hotplug_coreb;
void platform_cpu_die(void) void platform_cpu_die(void)
{ {
unsigned long iwr[2] = {0, 0}; unsigned long iwr;
unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32;
unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32);
hotplug_coreb = 1; hotplug_coreb = 1;
iwr[bank] = bit;
/* disable core timer */ /* disable core timer */
bfin_write_TCNTL(0); bfin_write_TCNTL(0);
/* clear ipi interrupt IRQ_SUPPLE_0 */ /* clear ipi interrupt IRQ_SUPPLE_0 of CoreB */
bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1))); bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1)));
SSYNC(); SSYNC();
coreb_sleep(iwr[0], iwr[1], 0); /* set CoreB wakeup by ipi0, iwr will be discarded */
bfin_iwr_set_sup0(&iwr, &iwr, &iwr);
SSYNC();
coreb_die();
} }
...@@ -162,39 +162,31 @@ ENTRY(_coreb_trampoline_start) ...@@ -162,39 +162,31 @@ ENTRY(_coreb_trampoline_start)
ENDPROC(_coreb_trampoline_start) ENDPROC(_coreb_trampoline_start)
ENTRY(_coreb_trampoline_end) ENTRY(_coreb_trampoline_end)
#ifdef CONFIG_HOTPLUG_CPU
.section ".text" .section ".text"
ENTRY(_set_sicb_iwr) ENTRY(_coreb_die)
P0.H = hi(SICB_IWR0);
P0.L = lo(SICB_IWR0);
P1.H = hi(SICB_IWR1);
P1.L = lo(SICB_IWR1);
[P0] = R0;
[P1] = R1;
SSYNC;
RTS;
ENDPROC(_set_sicb_iwr)
ENTRY(_coreb_sleep)
sp.l = lo(INITIAL_STACK); sp.l = lo(INITIAL_STACK);
sp.h = hi(INITIAL_STACK); sp.h = hi(INITIAL_STACK);
fp = sp; fp = sp;
usp = sp; usp = sp;
call _set_sicb_iwr;
CLI R2; CLI R2;
SSYNC; SSYNC;
IDLE; IDLE;
STI R2; STI R2;
R0 = IWR_DISABLE_ALL; R0 = IWR_DISABLE_ALL;
R1 = IWR_DISABLE_ALL; P0.H = hi(SYSMMR_BASE);
call _set_sicb_iwr; P0.L = lo(SYSMMR_BASE);
[P0 + (SICB_IWR0 - SYSMMR_BASE)] = R0;
[P0 + (SICB_IWR1 - SYSMMR_BASE)] = R0;
SSYNC;
p0.h = hi(COREB_L1_CODE_START); p0.h = hi(COREB_L1_CODE_START);
p0.l = lo(COREB_L1_CODE_START); p0.l = lo(COREB_L1_CODE_START);
jump (p0); jump (p0);
ENDPROC(_coreb_sleep) ENDPROC(_coreb_die)
#endif
__INIT __INIT
ENTRY(_coreb_start) ENTRY(_coreb_start)
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
#include <asm/time.h> #include <asm/time.h>
#include <asm/dpmc.h> #include <asm/dpmc.h>
#define CPUFREQ_CPU 0
/* this is the table of CCLK frequencies, in Hz */ /* this is the table of CCLK frequencies, in Hz */
/* .index is the entry in the auxillary dpm_state_table[] */ /* .index is the entry in the auxillary dpm_state_table[] */
static struct cpufreq_frequency_table bfin_freq_table[] = { static struct cpufreq_frequency_table bfin_freq_table[] = {
......
...@@ -61,17 +61,63 @@ static unsigned int bfin_get_vlev(unsigned int freq) ...@@ -61,17 +61,63 @@ static unsigned int bfin_get_vlev(unsigned int freq)
} }
#ifdef CONFIG_CPU_FREQ #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 static int
vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
{ {
struct cpufreq_freqs *freq = data; struct cpufreq_freqs *freq = data;
if (freq->cpu != CPUFREQ_CPU)
return 0;
if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) { if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) {
bfin_idle_cpu();
bfin_set_vlev(bfin_get_vlev(freq->new)); bfin_set_vlev(bfin_get_vlev(freq->new));
udelay(pdata->vr_settling_time); /* Wait until Volatge settled */ udelay(pdata->vr_settling_time); /* Wait until Volatge settled */
bfin_wakeup_cpu();
} else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) {
bfin_idle_cpu();
bfin_set_vlev(bfin_get_vlev(freq->new)); bfin_set_vlev(bfin_get_vlev(freq->new));
bfin_wakeup_cpu();
}
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册