diff options
author | Graf Yang <graf.yang@analog.com> | 2010-01-28 05:46:55 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2011-03-18 04:01:03 -0400 |
commit | 6f546bc3ac9eedbf770bf3bcbc45ce2ea32c94ad (patch) | |
tree | 7089509d165a19156c3be21950f96160fb1f06a1 /arch/blackfin | |
parent | 820b127dae869cbbd2133f066e8b8f32a90d46e5 (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.h | 3 | ||||
-rw-r--r-- | arch/blackfin/include/asm/smp.h | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-bf561/hotplug.c | 21 | ||||
-rw-r--r-- | arch/blackfin/mach-bf561/secondary.S | 26 | ||||
-rw-r--r-- | arch/blackfin/mach-common/cpufreq.c | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-common/dpmc.c | 50 |
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 | ||
128 | struct bfin_dpmc_platform_data { | 131 | struct 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]; | |||
34 | void smp_icache_flush_range_others(unsigned long start, | 34 | void 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 |
37 | void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2); | 37 | void coreb_die(void); |
38 | void cpu_die(void); | 38 | void cpu_die(void); |
39 | void platform_cpu_die(void); | 39 | void platform_cpu_die(void); |
40 | int __cpu_disable(void); | 40 | int __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 | ||
14 | int hotplug_coreb; | 12 | int hotplug_coreb; |
15 | 13 | ||
16 | void platform_cpu_die(void) | 14 | void 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) | |||
162 | ENDPROC(_coreb_trampoline_start) | 162 | ENDPROC(_coreb_trampoline_start) |
163 | ENTRY(_coreb_trampoline_end) | 163 | ENTRY(_coreb_trampoline_end) |
164 | 164 | ||
165 | #ifdef CONFIG_HOTPLUG_CPU | ||
165 | .section ".text" | 166 | .section ".text" |
166 | ENTRY(_set_sicb_iwr) | 167 | ENTRY(_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; | ||
175 | ENDPROC(_set_sicb_iwr) | ||
176 | |||
177 | ENTRY(_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); |
197 | ENDPROC(_coreb_sleep) | 188 | ENDPROC(_coreb_die) |
189 | #endif | ||
198 | 190 | ||
199 | __INIT | 191 | __INIT |
200 | ENTRY(_coreb_start) | 192 | ENTRY(_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[] */ |
23 | static struct cpufreq_frequency_table bfin_freq_table[] = { | 21 | static 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 | ||
65 | static 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 | |||
82 | static void bfin_idle_cpu(void) | ||
83 | { | ||
84 | smp_call_function(bfin_idle_this_cpu, NULL, 0); | ||
85 | } | ||
86 | |||
87 | static 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 | ||
99 | static void bfin_idle_cpu(void) {} | ||
100 | static void bfin_wakeup_cpu(void) {} | ||
101 | # endif | ||
102 | |||
64 | static int | 103 | static int |
65 | vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) | 104 | vreg_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 | } |