Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

authored by

Graf Yang and committed by
Mike Frysinger
6f546bc3 820b127d

+70 -34
+3
arch/blackfin/include/asm/dpmc.h
··· 125 125 126 126 #define VRPAIR(vlev, freq) (((vlev) << 16) | ((freq) >> 16)) 127 127 128 + #ifdef CONFIG_CPU_FREQ 129 + #define CPUFREQ_CPU 0 130 + #endif 128 131 struct bfin_dpmc_platform_data { 129 132 const unsigned int *tuple_tab; 130 133 unsigned short tabsize;
+1 -1
arch/blackfin/include/asm/smp.h
··· 34 34 void smp_icache_flush_range_others(unsigned long start, 35 35 unsigned long end); 36 36 #ifdef CONFIG_HOTPLUG_CPU 37 - void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2); 37 + void coreb_die(void); 38 38 void cpu_die(void); 39 39 void platform_cpu_die(void); 40 40 int __cpu_disable(void);
+9 -12
arch/blackfin/mach-bf561/hotplug.c
··· 5 5 * Licensed under the GPL-2 or later. 6 6 */ 7 7 8 + #include <linux/smp.h> 8 9 #include <asm/blackfin.h> 9 - #include <asm/irq.h> 10 - #include <asm/smp.h> 11 - 12 - #define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1)) 10 + #include <mach/pll.h> 13 11 14 12 int hotplug_coreb; 15 13 16 14 void platform_cpu_die(void) 17 15 { 18 - unsigned long iwr[2] = {0, 0}; 19 - unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32; 20 - unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32); 21 - 16 + unsigned long iwr; 22 17 hotplug_coreb = 1; 23 - 24 - iwr[bank] = bit; 25 18 26 19 /* disable core timer */ 27 20 bfin_write_TCNTL(0); 28 21 29 - /* clear ipi interrupt IRQ_SUPPLE_0 */ 22 + /* clear ipi interrupt IRQ_SUPPLE_0 of CoreB */ 30 23 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1))); 31 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 }
+9 -17
arch/blackfin/mach-bf561/secondary.S
··· 162 162 ENDPROC(_coreb_trampoline_start) 163 163 ENTRY(_coreb_trampoline_end) 164 164 165 + #ifdef CONFIG_HOTPLUG_CPU 165 166 .section ".text" 166 - ENTRY(_set_sicb_iwr) 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) 167 + ENTRY(_coreb_die) 178 168 sp.l = lo(INITIAL_STACK); 179 169 sp.h = hi(INITIAL_STACK); 180 170 fp = sp; 181 171 usp = sp; 182 - 183 - call _set_sicb_iwr; 184 172 185 173 CLI R2; 186 174 SSYNC; ··· 176 188 STI R2; 177 189 178 190 R0 = IWR_DISABLE_ALL; 179 - R1 = IWR_DISABLE_ALL; 180 - call _set_sicb_iwr; 191 + P0.H = hi(SYSMMR_BASE); 192 + P0.L = lo(SYSMMR_BASE); 193 + [P0 + (SICB_IWR0 - SYSMMR_BASE)] = R0; 194 + [P0 + (SICB_IWR1 - SYSMMR_BASE)] = R0; 195 + SSYNC; 181 196 182 197 p0.h = hi(COREB_L1_CODE_START); 183 198 p0.l = lo(COREB_L1_CODE_START); 184 199 jump (p0); 185 - ENDPROC(_coreb_sleep) 200 + ENDPROC(_coreb_die) 201 + #endif 186 202 187 203 __INIT 188 204 ENTRY(_coreb_start)
-2
arch/blackfin/mach-common/cpufreq.c
··· 16 16 #include <asm/time.h> 17 17 #include <asm/dpmc.h> 18 18 19 - #define CPUFREQ_CPU 0 20 - 21 19 /* this is the table of CCLK frequencies, in Hz */ 22 20 /* .index is the entry in the auxillary dpm_state_table[] */ 23 21 static struct cpufreq_frequency_table bfin_freq_table[] = {
+48 -2
arch/blackfin/mach-common/dpmc.c
··· 61 61 } 62 62 63 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 103 static int 65 104 vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) 66 105 { 67 106 struct cpufreq_freqs *freq = data; 68 107 108 + if (freq->cpu != CPUFREQ_CPU) 109 + return 0; 110 + 69 111 if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) { 112 + bfin_idle_cpu(); 70 113 bfin_set_vlev(bfin_get_vlev(freq->new)); 71 114 udelay(pdata->vr_settling_time); /* Wait until Volatge settled */ 72 - 73 - } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) 115 + bfin_wakeup_cpu(); 116 + } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) { 117 + bfin_idle_cpu(); 74 118 bfin_set_vlev(bfin_get_vlev(freq->new)); 119 + bfin_wakeup_cpu(); 120 + } 75 121 76 122 return 0; 77 123 }