Commit 72f4d57923d2aa651db060a71a6f6211654c119e

Authored by Magnus Damm
Committed by Paul Mundt
1 parent 4d7ec69576

ARM: mach-shmobile: sh73a0 SMP support

Add SMP support for ag5evm and the sh73a0 processor.

Onlining and offlining works well, but at this point
offlined processor cores are not put into sleep mode.

There is no spinlock for syncing the secondary core
with the first one in this implementation. The code
instead relies on the cpu_online() check in __cpu_up().

Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

Showing 4 changed files with 116 additions and 1 deletions Inline Diff

arch/arm/mach-shmobile/Makefile
1 # 1 #
2 # Makefile for the linux kernel. 2 # Makefile for the linux kernel.
3 # 3 #
4 4
5 # Common objects 5 # Common objects
6 obj-y := timer.o console.o clock.o pm_runtime.o 6 obj-y := timer.o console.o clock.o pm_runtime.o
7 7
8 # CPU objects 8 # CPU objects
9 obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o 9 obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o
10 obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7377.o intc-sh7377.o 10 obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7377.o intc-sh7377.o
11 obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o 11 obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o
12 obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o 12 obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o
13 13
14 # SMP objects 14 # SMP objects
15 smp-y := platsmp.o headsmp.o 15 smp-y := platsmp.o headsmp.o
16 smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o 16 smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
17 smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o 17 smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o
18 smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
18 19
19 # Pinmux setup 20 # Pinmux setup
20 pfc-y := 21 pfc-y :=
21 pfc-$(CONFIG_ARCH_SH7367) += pfc-sh7367.o 22 pfc-$(CONFIG_ARCH_SH7367) += pfc-sh7367.o
22 pfc-$(CONFIG_ARCH_SH7377) += pfc-sh7377.o 23 pfc-$(CONFIG_ARCH_SH7377) += pfc-sh7377.o
23 pfc-$(CONFIG_ARCH_SH7372) += pfc-sh7372.o 24 pfc-$(CONFIG_ARCH_SH7372) += pfc-sh7372.o
24 pfc-$(CONFIG_ARCH_SH73A0) += pfc-sh73a0.o 25 pfc-$(CONFIG_ARCH_SH73A0) += pfc-sh73a0.o
25 26
26 # Board objects 27 # Board objects
27 obj-$(CONFIG_MACH_G3EVM) += board-g3evm.o 28 obj-$(CONFIG_MACH_G3EVM) += board-g3evm.o
28 obj-$(CONFIG_MACH_G4EVM) += board-g4evm.o 29 obj-$(CONFIG_MACH_G4EVM) += board-g4evm.o
29 obj-$(CONFIG_MACH_AP4EVB) += board-ap4evb.o 30 obj-$(CONFIG_MACH_AP4EVB) += board-ap4evb.o
30 obj-$(CONFIG_MACH_AG5EVM) += board-ag5evm.o 31 obj-$(CONFIG_MACH_AG5EVM) += board-ag5evm.o
31 obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o 32 obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o
32 33
33 # Framework support 34 # Framework support
34 obj-$(CONFIG_SMP) += $(smp-y) 35 obj-$(CONFIG_SMP) += $(smp-y)
35 obj-$(CONFIG_GENERIC_GPIO) += $(pfc-y) 36 obj-$(CONFIG_GENERIC_GPIO) += $(pfc-y)
36 37
arch/arm/mach-shmobile/include/mach/common.h
1 #ifndef __ARCH_MACH_COMMON_H 1 #ifndef __ARCH_MACH_COMMON_H
2 #define __ARCH_MACH_COMMON_H 2 #define __ARCH_MACH_COMMON_H
3 3
4 extern struct sys_timer shmobile_timer; 4 extern struct sys_timer shmobile_timer;
5 extern void shmobile_setup_console(void); 5 extern void shmobile_setup_console(void);
6 extern void shmobile_secondary_vector(void); 6 extern void shmobile_secondary_vector(void);
7 struct clk; 7 struct clk;
8 extern int clk_init(void); 8 extern int clk_init(void);
9 9
10 extern void sh7367_init_irq(void); 10 extern void sh7367_init_irq(void);
11 extern void sh7367_add_early_devices(void); 11 extern void sh7367_add_early_devices(void);
12 extern void sh7367_add_standard_devices(void); 12 extern void sh7367_add_standard_devices(void);
13 extern void sh7367_clock_init(void); 13 extern void sh7367_clock_init(void);
14 extern void sh7367_pinmux_init(void); 14 extern void sh7367_pinmux_init(void);
15 extern struct clk sh7367_extalb1_clk; 15 extern struct clk sh7367_extalb1_clk;
16 extern struct clk sh7367_extal2_clk; 16 extern struct clk sh7367_extal2_clk;
17 17
18 extern void sh7377_init_irq(void); 18 extern void sh7377_init_irq(void);
19 extern void sh7377_add_early_devices(void); 19 extern void sh7377_add_early_devices(void);
20 extern void sh7377_add_standard_devices(void); 20 extern void sh7377_add_standard_devices(void);
21 extern void sh7377_clock_init(void); 21 extern void sh7377_clock_init(void);
22 extern void sh7377_pinmux_init(void); 22 extern void sh7377_pinmux_init(void);
23 extern struct clk sh7377_extalc1_clk; 23 extern struct clk sh7377_extalc1_clk;
24 extern struct clk sh7377_extal2_clk; 24 extern struct clk sh7377_extal2_clk;
25 25
26 extern void sh7372_init_irq(void); 26 extern void sh7372_init_irq(void);
27 extern void sh7372_add_early_devices(void); 27 extern void sh7372_add_early_devices(void);
28 extern void sh7372_add_standard_devices(void); 28 extern void sh7372_add_standard_devices(void);
29 extern void sh7372_clock_init(void); 29 extern void sh7372_clock_init(void);
30 extern void sh7372_pinmux_init(void); 30 extern void sh7372_pinmux_init(void);
31 extern struct clk sh7372_extal1_clk; 31 extern struct clk sh7372_extal1_clk;
32 extern struct clk sh7372_extal2_clk; 32 extern struct clk sh7372_extal2_clk;
33 33
34 extern void sh73a0_add_early_devices(void); 34 extern void sh73a0_add_early_devices(void);
35 extern void sh73a0_add_standard_devices(void); 35 extern void sh73a0_add_standard_devices(void);
36 extern void sh73a0_clock_init(void); 36 extern void sh73a0_clock_init(void);
37 extern void sh73a0_pinmux_init(void); 37 extern void sh73a0_pinmux_init(void);
38 extern struct clk sh73a0_extal1_clk; 38 extern struct clk sh73a0_extal1_clk;
39 extern struct clk sh73a0_extal2_clk; 39 extern struct clk sh73a0_extal2_clk;
40 40
41 extern unsigned int sh73a0_get_core_count(void);
42 extern void sh73a0_secondary_init(unsigned int cpu);
43 extern int sh73a0_boot_secondary(unsigned int cpu);
44 extern void sh73a0_smp_prepare_cpus(void);
45
41 #endif /* __ARCH_MACH_COMMON_H */ 46 #endif /* __ARCH_MACH_COMMON_H */
42 47
arch/arm/mach-shmobile/platsmp.c
1 /* 1 /*
2 * SMP support for R-Mobile / SH-Mobile 2 * SMP support for R-Mobile / SH-Mobile
3 * 3 *
4 * Copyright (C) 2010 Magnus Damm 4 * Copyright (C) 2010 Magnus Damm
5 * 5 *
6 * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved 6 * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11 */ 11 */
12 #include <linux/init.h> 12 #include <linux/init.h>
13 #include <linux/errno.h> 13 #include <linux/errno.h>
14 #include <linux/delay.h> 14 #include <linux/delay.h>
15 #include <linux/device.h> 15 #include <linux/device.h>
16 #include <linux/smp.h> 16 #include <linux/smp.h>
17 #include <linux/io.h> 17 #include <linux/io.h>
18 #include <asm/localtimer.h> 18 #include <asm/localtimer.h>
19 #include <asm/mach-types.h>
20 #include <mach/common.h>
19 21
20 static unsigned int __init shmobile_smp_get_core_count(void) 22 static unsigned int __init shmobile_smp_get_core_count(void)
21 { 23 {
24 if (machine_is_ag5evm())
25 return sh73a0_get_core_count();
26
22 return 1; 27 return 1;
23 } 28 }
24 29
25 static void __init shmobile_smp_prepare_cpus(void) 30 static void __init shmobile_smp_prepare_cpus(void)
26 { 31 {
27 /* do nothing for now */ 32 if (machine_is_ag5evm())
33 sh73a0_smp_prepare_cpus();
28 } 34 }
29 35
30 36
31 void __cpuinit platform_secondary_init(unsigned int cpu) 37 void __cpuinit platform_secondary_init(unsigned int cpu)
32 { 38 {
33 trace_hardirqs_off(); 39 trace_hardirqs_off();
40
41 if (machine_is_ag5evm())
42 sh73a0_secondary_init(cpu);
34 } 43 }
35 44
36 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 45 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
37 { 46 {
47 if (machine_is_ag5evm())
48 return sh73a0_boot_secondary(cpu);
49
38 return -ENOSYS; 50 return -ENOSYS;
39 } 51 }
40 52
41 void __init smp_init_cpus(void) 53 void __init smp_init_cpus(void)
42 { 54 {
43 unsigned int ncores = shmobile_smp_get_core_count(); 55 unsigned int ncores = shmobile_smp_get_core_count();
44 unsigned int i; 56 unsigned int i;
45 57
46 for (i = 0; i < ncores; i++) 58 for (i = 0; i < ncores; i++)
47 set_cpu_possible(i, true); 59 set_cpu_possible(i, true);
48 } 60 }
49 61
50 void __init smp_prepare_cpus(unsigned int max_cpus) 62 void __init smp_prepare_cpus(unsigned int max_cpus)
51 { 63 {
52 unsigned int ncores = shmobile_smp_get_core_count(); 64 unsigned int ncores = shmobile_smp_get_core_count();
53 unsigned int cpu = smp_processor_id(); 65 unsigned int cpu = smp_processor_id();
54 int i; 66 int i;
55 67
56 smp_store_cpu_info(cpu); 68 smp_store_cpu_info(cpu);
57 69
58 if (max_cpus > ncores) 70 if (max_cpus > ncores)
59 max_cpus = ncores; 71 max_cpus = ncores;
60 72
61 for (i = 0; i < max_cpus; i++) 73 for (i = 0; i < max_cpus; i++)
62 set_cpu_present(i, true); 74 set_cpu_present(i, true);
63 75
64 if (max_cpus > 1) { 76 if (max_cpus > 1) {
65 shmobile_smp_prepare_cpus(); 77 shmobile_smp_prepare_cpus();
66 78
67 /* 79 /*
68 * Enable the local timer or broadcast device for the 80 * Enable the local timer or broadcast device for the
69 * boot CPU, but only if we have more than one CPU. 81 * boot CPU, but only if we have more than one CPU.
70 */ 82 */
71 percpu_timer_setup(); 83 percpu_timer_setup();
72 } 84 }
73 } 85 }
74 86
arch/arm/mach-shmobile/smp-sh73a0.c
File was created 1 /*
2 * SMP support for R-Mobile / SH-Mobile - sh73a0 portion
3 *
4 * Copyright (C) 2010 Magnus Damm
5 * Copyright (C) 2010 Takashi Yoshii
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 #include <linux/kernel.h>
21 #include <linux/init.h>
22 #include <linux/smp.h>
23 #include <linux/spinlock.h>
24 #include <linux/io.h>
25 #include <mach/common.h>
26 #include <asm/smp_scu.h>
27 #include <asm/smp_twd.h>
28 #include <asm/hardware/gic.h>
29
30 #define WUPCR 0xe6151010
31 #define SRESCR 0xe6151018
32 #define PSTR 0xe6151040
33 #define SBAR 0xe6180020
34 #define APARMBAREA 0xe6f10020
35
36 static void __iomem *scu_base_addr(void)
37 {
38 return (void __iomem *)0xf0000000;
39 }
40
41 static DEFINE_SPINLOCK(scu_lock);
42 static unsigned long tmp;
43
44 static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
45 {
46 void __iomem *scu_base = scu_base_addr();
47
48 spin_lock(&scu_lock);
49 tmp = __raw_readl(scu_base + 8);
50 tmp &= ~clr;
51 tmp |= set;
52 spin_unlock(&scu_lock);
53
54 /* disable cache coherency after releasing the lock */
55 __raw_writel(tmp, scu_base + 8);
56 }
57
58 unsigned int __init sh73a0_get_core_count(void)
59 {
60 void __iomem *scu_base = scu_base_addr();
61
62 return scu_get_core_count(scu_base);
63 }
64
65 void __cpuinit sh73a0_secondary_init(unsigned int cpu)
66 {
67 gic_cpu_init(0, __io(0xf0000100));
68 }
69
70 int __cpuinit sh73a0_boot_secondary(unsigned int cpu)
71 {
72 /* enable cache coherency */
73 modify_scu_cpu_psr(0, 3 << (cpu * 8));
74
75 if (((__raw_readw(__io(PSTR)) >> (4 * cpu)) & 3) == 3)
76 __raw_writel(1 << cpu, __io(WUPCR)); /* wake up */
77 else
78 __raw_writel(1 << cpu, __io(SRESCR)); /* reset */
79
80 return 0;
81 }
82
83 void __init sh73a0_smp_prepare_cpus(void)
84 {
85 #ifdef CONFIG_HAVE_ARM_TWD
86 twd_base = (void __iomem *)0xf0000600;
87 #endif
88
89 scu_enable(scu_base_addr());
90
91 /* Map the reset vector (in headsmp.S) */
92 __raw_writel(0, __io(APARMBAREA)); /* 4k */
93 __raw_writel(__pa(shmobile_secondary_vector), __io(SBAR));
94
95 /* enable cache coherency on CPU0 */
96 modify_scu_cpu_psr(0, 3 << (0 * 8));
97 }
98