aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2010-12-14 02:57:11 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-12-14 04:15:47 -0500
commit72f4d57923d2aa651db060a71a6f6211654c119e (patch)
tree11c20ab3f639c842b9b8d0ff46e03025780fe4b7 /arch/arm
parent4d7ec69576ca4427478405190bd32e560f06fe99 (diff)
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>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-shmobile/Makefile1
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h5
-rw-r--r--arch/arm/mach-shmobile/platsmp.c14
-rw-r--r--arch/arm/mach-shmobile/smp-sh73a0.c97
4 files changed, 116 insertions, 1 deletions
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index d4346ddd9121..995f39bde909 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o
15smp-y := platsmp.o headsmp.o 15smp-y := platsmp.o headsmp.o
16smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o 16smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
17smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o 17smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o
18smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
18 19
19# Pinmux setup 20# Pinmux setup
20pfc-y := 21pfc-y :=
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 32822f7556ea..b8f1f62bce97 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -38,4 +38,9 @@ extern void sh73a0_pinmux_init(void);
38extern struct clk sh73a0_extal1_clk; 38extern struct clk sh73a0_extal1_clk;
39extern struct clk sh73a0_extal2_clk; 39extern struct clk sh73a0_extal2_clk;
40 40
41extern unsigned int sh73a0_get_core_count(void);
42extern void sh73a0_secondary_init(unsigned int cpu);
43extern int sh73a0_boot_secondary(unsigned int cpu);
44extern void sh73a0_smp_prepare_cpus(void);
45
41#endif /* __ARCH_MACH_COMMON_H */ 46#endif /* __ARCH_MACH_COMMON_H */
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index b41f5d0650e4..3c2c0f49073e 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -16,25 +16,37 @@
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
20static unsigned int __init shmobile_smp_get_core_count(void) 22static 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
25static void __init shmobile_smp_prepare_cpus(void) 30static 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
31void __cpuinit platform_secondary_init(unsigned int cpu) 37void __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
36int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 45int __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
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
new file mode 100644
index 000000000000..4e71fd416cd5
--- /dev/null
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -0,0 +1,97 @@
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
36static void __iomem *scu_base_addr(void)
37{
38 return (void __iomem *)0xf0000000;
39}
40
41static DEFINE_SPINLOCK(scu_lock);
42static unsigned long tmp;
43
44static 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
58unsigned 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
65void __cpuinit sh73a0_secondary_init(unsigned int cpu)
66{
67 gic_cpu_init(0, __io(0xf0000100));
68}
69
70int __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
83void __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}