mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-23 15:11:16 +00:00
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
6 changed files with 70 additions and 34 deletions
|
@ -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];
|
||||||
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 @@
|
||||||
* 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)
|
||||||
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 @@
|
||||||
#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 @@ err_out:
|
||||||
}
|
}
|
||||||
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue