aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorGraf Yang <graf.yang@analog.com>2010-01-28 05:46:55 -0500
committerMike Frysinger <vapier@gentoo.org>2011-03-18 04:01:03 -0400
commit6f546bc3ac9eedbf770bf3bcbc45ce2ea32c94ad (patch)
tree7089509d165a19156c3be21950f96160fb1f06a1 /arch/blackfin
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')
-rw-r--r--arch/blackfin/include/asm/dpmc.h3
-rw-r--r--arch/blackfin/include/asm/smp.h2
-rw-r--r--arch/blackfin/mach-bf561/hotplug.c21
-rw-r--r--arch/blackfin/mach-bf561/secondary.S26
-rw-r--r--arch/blackfin/mach-common/cpufreq.c2
-rw-r--r--arch/blackfin/mach-common/dpmc.c50
6 files changed, 70 insertions, 34 deletions
diff --git a/arch/blackfin/include/asm/dpmc.h b/arch/blackfin/include/asm/dpmc.h
index 3047120cfcff..edf2a2ad5183 100644
--- a/arch/blackfin/include/asm/dpmc.h
+++ b/arch/blackfin/include/asm/dpmc.h
@@ -125,6 +125,9 @@ void unset_dram_srfs(void);
125 125
126#define VRPAIR(vlev, freq) (((vlev) << 16) | ((freq) >> 16)) 126#define VRPAIR(vlev, freq) (((vlev) << 16) | ((freq) >> 16))
127 127
128#ifdef CONFIG_CPU_FREQ
129#define CPUFREQ_CPU 0
130#endif
128struct bfin_dpmc_platform_data { 131struct bfin_dpmc_platform_data {
129 const unsigned int *tuple_tab; 132 const unsigned int *tuple_tab;
130 unsigned short tabsize; 133 unsigned short tabsize;
diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h
index f5b537967116..9dd487375247 100644
--- a/arch/blackfin/include/asm/smp.h
+++ b/arch/blackfin/include/asm/smp.h
@@ -34,7 +34,7 @@ extern unsigned long dcache_invld_count[NR_CPUS];
34void smp_icache_flush_range_others(unsigned long start, 34void smp_icache_flush_range_others(unsigned long start,
35 unsigned long end); 35 unsigned long end);
36#ifdef CONFIG_HOTPLUG_CPU 36#ifdef CONFIG_HOTPLUG_CPU
37void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2); 37void coreb_die(void);
38void cpu_die(void); 38void cpu_die(void);
39void platform_cpu_die(void); 39void platform_cpu_die(void);
40int __cpu_disable(void); 40int __cpu_disable(void);
diff --git a/arch/blackfin/mach-bf561/hotplug.c b/arch/blackfin/mach-bf561/hotplug.c
index 4cd3b28cd046..42fc085629c7 100644
--- a/arch/blackfin/mach-bf561/hotplug.c
+++ b/arch/blackfin/mach-bf561/hotplug.c
@@ -5,30 +5,27 @@
5 * Licensed under the GPL-2 or later. 5 * Licensed under the GPL-2 or later.
6 */ 6 */
7 7
8#include <linux/smp.h>
8#include <asm/blackfin.h> 9#include <asm/blackfin.h>
9#include <asm/irq.h> 10#include <mach/pll.h>
10#include <asm/smp.h>
11
12#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
13 11
14int hotplug_coreb; 12int hotplug_coreb;
15 13
16void platform_cpu_die(void) 14void platform_cpu_die(void)
17{ 15{
18 unsigned long iwr[2] = {0, 0}; 16 unsigned long iwr;
19 unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32;
20 unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32);
21
22 hotplug_coreb = 1; 17 hotplug_coreb = 1;
23 18
24 iwr[bank] = bit;
25
26 /* disable core timer */ 19 /* disable core timer */
27 bfin_write_TCNTL(0); 20 bfin_write_TCNTL(0);
28 21
29 /* clear ipi interrupt IRQ_SUPPLE_0 */ 22 /* clear ipi interrupt IRQ_SUPPLE_0 of CoreB */
30 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1))); 23 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1)));
31 SSYNC(); 24 SSYNC();
32 25
33 coreb_sleep(iwr[0], iwr[1], 0); 26 /* set CoreB wakeup by ipi0, iwr will be discarded */
27 bfin_iwr_set_sup0(&iwr, &iwr, &iwr);
28 SSYNC();
29
30 coreb_die();
34} 31}
diff --git a/arch/blackfin/mach-bf561/secondary.S b/arch/blackfin/mach-bf561/secondary.S
index ef9acf21eb8e..148e50764555 100644
--- a/arch/blackfin/mach-bf561/secondary.S
+++ b/arch/blackfin/mach-bf561/secondary.S
@@ -162,39 +162,31 @@ ENTRY(_coreb_trampoline_start)
162ENDPROC(_coreb_trampoline_start) 162ENDPROC(_coreb_trampoline_start)
163ENTRY(_coreb_trampoline_end) 163ENTRY(_coreb_trampoline_end)
164 164
165#ifdef CONFIG_HOTPLUG_CPU
165.section ".text" 166.section ".text"
166ENTRY(_set_sicb_iwr) 167ENTRY(_coreb_die)
167 P0.H = hi(SICB_IWR0);
168 P0.L = lo(SICB_IWR0);
169 P1.H = hi(SICB_IWR1);
170 P1.L = lo(SICB_IWR1);
171 [P0] = R0;
172 [P1] = R1;
173 SSYNC;
174 RTS;
175ENDPROC(_set_sicb_iwr)
176
177ENTRY(_coreb_sleep)
178 sp.l = lo(INITIAL_STACK); 168 sp.l = lo(INITIAL_STACK);
179 sp.h = hi(INITIAL_STACK); 169 sp.h = hi(INITIAL_STACK);
180 fp = sp; 170 fp = sp;
181 usp = sp; 171 usp = sp;
182 172
183 call _set_sicb_iwr;
184
185 CLI R2; 173 CLI R2;
186 SSYNC; 174 SSYNC;
187 IDLE; 175 IDLE;
188 STI R2; 176 STI R2;
189 177
190 R0 = IWR_DISABLE_ALL; 178 R0 = IWR_DISABLE_ALL;
191 R1 = IWR_DISABLE_ALL; 179 P0.H = hi(SYSMMR_BASE);
192 call _set_sicb_iwr; 180 P0.L = lo(SYSMMR_BASE);
181 [P0 + (SICB_IWR0 - SYSMMR_BASE)] = R0;
182 [P0 + (SICB_IWR1 - SYSMMR_BASE)] = R0;
183 SSYNC;
193 184
194 p0.h = hi(COREB_L1_CODE_START); 185 p0.h = hi(COREB_L1_CODE_START);
195 p0.l = lo(COREB_L1_CODE_START); 186 p0.l = lo(COREB_L1_CODE_START);
196 jump (p0); 187 jump (p0);
197ENDPROC(_coreb_sleep) 188ENDPROC(_coreb_die)
189#endif
198 190
199__INIT 191__INIT
200ENTRY(_coreb_start) 192ENTRY(_coreb_start)
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c
index f4cf11d362e1..c33fb61b5082 100644
--- a/arch/blackfin/mach-common/cpufreq.c
+++ b/arch/blackfin/mach-common/cpufreq.c
@@ -16,8 +16,6 @@
16#include <asm/time.h> 16#include <asm/time.h>
17#include <asm/dpmc.h> 17#include <asm/dpmc.h>
18 18
19#define CPUFREQ_CPU 0
20
21/* this is the table of CCLK frequencies, in Hz */ 19/* this is the table of CCLK frequencies, in Hz */
22/* .index is the entry in the auxillary dpm_state_table[] */ 20/* .index is the entry in the auxillary dpm_state_table[] */
23static struct cpufreq_frequency_table bfin_freq_table[] = { 21static struct cpufreq_frequency_table bfin_freq_table[] = {
diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c
index 02c7efd1bcf4..382099fd5561 100644
--- a/arch/blackfin/mach-common/dpmc.c
+++ b/arch/blackfin/mach-common/dpmc.c
@@ -61,17 +61,63 @@ err_out:
61} 61}
62 62
63#ifdef CONFIG_CPU_FREQ 63#ifdef CONFIG_CPU_FREQ
64# ifdef CONFIG_SMP
65static void bfin_idle_this_cpu(void *info)
66{
67 unsigned long flags = 0;
68 unsigned long iwr0, iwr1, iwr2;
69 unsigned int cpu = smp_processor_id();
70
71 local_irq_save_hw(flags);
72 bfin_iwr_set_sup0(&iwr0, &iwr1, &iwr2);
73
74 platform_clear_ipi(cpu, IRQ_SUPPLE_0);
75 SSYNC();
76 asm("IDLE;");
77 bfin_iwr_restore(iwr0, iwr1, iwr2);
78
79 local_irq_restore_hw(flags);
80}
81
82static void bfin_idle_cpu(void)
83{
84 smp_call_function(bfin_idle_this_cpu, NULL, 0);
85}
86
87static void bfin_wakeup_cpu(void)
88{
89 unsigned int cpu;
90 unsigned int this_cpu = smp_processor_id();
91 cpumask_t mask = cpu_online_map;
92
93 cpu_clear(this_cpu, mask);
94 for_each_cpu_mask(cpu, mask)
95 platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
96}
97
98# else
99static void bfin_idle_cpu(void) {}
100static void bfin_wakeup_cpu(void) {}
101# endif
102
64static int 103static int
65vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) 104vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
66{ 105{
67 struct cpufreq_freqs *freq = data; 106 struct cpufreq_freqs *freq = data;
68 107
108 if (freq->cpu != CPUFREQ_CPU)
109 return 0;
110
69 if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) { 111 if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) {
112 bfin_idle_cpu();
70 bfin_set_vlev(bfin_get_vlev(freq->new)); 113 bfin_set_vlev(bfin_get_vlev(freq->new));
71 udelay(pdata->vr_settling_time); /* Wait until Volatge settled */ 114 udelay(pdata->vr_settling_time); /* Wait until Volatge settled */
72 115 bfin_wakeup_cpu();
73 } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) 116 } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) {
117 bfin_idle_cpu();
74 bfin_set_vlev(bfin_get_vlev(freq->new)); 118 bfin_set_vlev(bfin_get_vlev(freq->new));
119 bfin_wakeup_cpu();
120 }
75 121
76 return 0; 122 return 0;
77} 123}