forked from Minki/linux
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>
This commit is contained in:
parent
820b127dae
commit
6f546bc3ac
@ -125,6 +125,9 @@ void unset_dram_srfs(void);
|
||||
|
||||
#define VRPAIR(vlev, freq) (((vlev) << 16) | ((freq) >> 16))
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
#define CPUFREQ_CPU 0
|
||||
#endif
|
||||
struct bfin_dpmc_platform_data {
|
||||
const unsigned int *tuple_tab;
|
||||
unsigned short tabsize;
|
||||
|
@ -34,7 +34,7 @@ extern unsigned long dcache_invld_count[NR_CPUS];
|
||||
void smp_icache_flush_range_others(unsigned long start,
|
||||
unsigned long end);
|
||||
#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 platform_cpu_die(void);
|
||||
int __cpu_disable(void);
|
||||
|
@ -5,30 +5,27 @@
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/smp.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/smp.h>
|
||||
|
||||
#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
|
||||
#include <mach/pll.h>
|
||||
|
||||
int hotplug_coreb;
|
||||
|
||||
void platform_cpu_die(void)
|
||||
{
|
||||
unsigned long iwr[2] = {0, 0};
|
||||
unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32;
|
||||
unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32);
|
||||
|
||||
unsigned long iwr;
|
||||
hotplug_coreb = 1;
|
||||
|
||||
iwr[bank] = bit;
|
||||
|
||||
/* disable core timer */
|
||||
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)));
|
||||
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)
|
||||
ENDPROC(_coreb_trampoline_start)
|
||||
ENTRY(_coreb_trampoline_end)
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.section ".text"
|
||||
ENTRY(_set_sicb_iwr)
|
||||
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)
|
||||
ENTRY(_coreb_die)
|
||||
sp.l = lo(INITIAL_STACK);
|
||||
sp.h = hi(INITIAL_STACK);
|
||||
fp = sp;
|
||||
usp = sp;
|
||||
|
||||
call _set_sicb_iwr;
|
||||
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
IDLE;
|
||||
STI R2;
|
||||
|
||||
R0 = IWR_DISABLE_ALL;
|
||||
R1 = IWR_DISABLE_ALL;
|
||||
call _set_sicb_iwr;
|
||||
P0.H = hi(SYSMMR_BASE);
|
||||
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.l = lo(COREB_L1_CODE_START);
|
||||
jump (p0);
|
||||
ENDPROC(_coreb_sleep)
|
||||
ENDPROC(_coreb_die)
|
||||
#endif
|
||||
|
||||
__INIT
|
||||
ENTRY(_coreb_start)
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include <asm/time.h>
|
||||
#include <asm/dpmc.h>
|
||||
|
||||
#define CPUFREQ_CPU 0
|
||||
|
||||
/* this is the table of CCLK frequencies, in Hz */
|
||||
/* .index is the entry in the auxillary dpm_state_table[] */
|
||||
static struct cpufreq_frequency_table bfin_freq_table[] = {
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user