diff options
author | Paul Mundt <lethal@linux-sh.org> | 2011-01-06 20:51:35 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-01-06 20:51:35 -0500 |
commit | e9d728f528f9548c8dd013899b23e662fa7b6bca (patch) | |
tree | d88a5df6e5a2b33ebe088ad0223fe54679a59df3 /arch/arm/mach-shmobile | |
parent | 018a3fc7e3824ffcc80ad0160f9782c7d577c0c1 (diff) | |
parent | 6155f77d09b968f591876f368d4843168910449e (diff) |
Merge branch 'rmobile/smp' into rmobile-latest
Conflicts:
arch/arm/Kconfig
arch/arm/mach-shmobile/include/mach/entry-macro-intc.S
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r-- | arch/arm/mach-shmobile/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/headsmp.S | 27 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/hotplug.c | 41 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/common.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/smp.h | 16 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/localtimer.c | 25 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/platsmp.c | 85 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/smp-sh73a0.c | 97 |
8 files changed, 304 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index d16165a7b487..e2507f66f9d5 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile | |||
@@ -11,6 +11,12 @@ 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 intc-sh73a0.o | 12 | obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o |
13 | 13 | ||
14 | # SMP objects | ||
15 | smp-y := platsmp.o headsmp.o | ||
16 | smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o | ||
17 | smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o | ||
18 | smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o | ||
19 | |||
14 | # Pinmux setup | 20 | # Pinmux setup |
15 | pfc-y := | 21 | pfc-y := |
16 | pfc-$(CONFIG_ARCH_SH7367) += pfc-sh7367.o | 22 | pfc-$(CONFIG_ARCH_SH7367) += pfc-sh7367.o |
@@ -32,4 +38,5 @@ obj-$(CONFIG_MACH_AG5EVM) += board-ag5evm.o | |||
32 | obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o | 38 | obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o |
33 | 39 | ||
34 | # Framework support | 40 | # Framework support |
41 | obj-$(CONFIG_SMP) += $(smp-y) | ||
35 | obj-$(CONFIG_GENERIC_GPIO) += $(pfc-y) | 42 | obj-$(CONFIG_GENERIC_GPIO) += $(pfc-y) |
diff --git a/arch/arm/mach-shmobile/headsmp.S b/arch/arm/mach-shmobile/headsmp.S new file mode 100644 index 000000000000..d4cec6b4c7d9 --- /dev/null +++ b/arch/arm/mach-shmobile/headsmp.S | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * SMP support for R-Mobile / SH-Mobile | ||
3 | * | ||
4 | * Copyright (C) 2010 Magnus Damm | ||
5 | * Copyright (C) 2010 Takashi Yoshii | ||
6 | * | ||
7 | * Based on vexpress, Copyright (c) 2003 ARM Limited, All Rights Reserved | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | #include <linux/linkage.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <asm/memory.h> | ||
16 | |||
17 | __INIT | ||
18 | |||
19 | /* | ||
20 | * Reset vector for secondary CPUs. | ||
21 | * This will be mapped at address 0 by SBAR register. | ||
22 | * We need _long_ jump to the physical address. | ||
23 | */ | ||
24 | .align 12 | ||
25 | ENTRY(shmobile_secondary_vector) | ||
26 | ldr pc, 1f | ||
27 | 1: .long secondary_startup - PAGE_OFFSET + PHYS_OFFSET | ||
diff --git a/arch/arm/mach-shmobile/hotplug.c b/arch/arm/mach-shmobile/hotplug.c new file mode 100644 index 000000000000..238a0d97d2d5 --- /dev/null +++ b/arch/arm/mach-shmobile/hotplug.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * SMP support for R-Mobile / SH-Mobile | ||
3 | * | ||
4 | * Copyright (C) 2010 Magnus Damm | ||
5 | * | ||
6 | * Based on realview, Copyright (C) 2002 ARM Ltd, All Rights Reserved | ||
7 | * | ||
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 | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/smp.h> | ||
15 | |||
16 | int platform_cpu_kill(unsigned int cpu) | ||
17 | { | ||
18 | return 1; | ||
19 | } | ||
20 | |||
21 | void platform_cpu_die(unsigned int cpu) | ||
22 | { | ||
23 | while (1) { | ||
24 | /* | ||
25 | * here's the WFI | ||
26 | */ | ||
27 | asm(".word 0xe320f003\n" | ||
28 | : | ||
29 | : | ||
30 | : "memory", "cc"); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | int platform_cpu_disable(unsigned int cpu) | ||
35 | { | ||
36 | /* | ||
37 | * we don't allow CPU 0 to be shutdown (it is still too special | ||
38 | * e.g. clock tick interrupts) | ||
39 | */ | ||
40 | return cpu == 0 ? -EPERM : 0; | ||
41 | } | ||
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 9f46cf5ca75f..013ac0ee8256 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h | |||
@@ -3,6 +3,7 @@ | |||
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 | struct clk; | 7 | struct clk; |
7 | extern int clk_init(void); | 8 | extern int clk_init(void); |
8 | extern void shmobile_handle_irq_intc(struct pt_regs *); | 9 | extern void shmobile_handle_irq_intc(struct pt_regs *); |
@@ -40,4 +41,9 @@ extern void sh73a0_pinmux_init(void); | |||
40 | extern struct clk sh73a0_extal1_clk; | 41 | extern struct clk sh73a0_extal1_clk; |
41 | extern struct clk sh73a0_extal2_clk; | 42 | extern struct clk sh73a0_extal2_clk; |
42 | 43 | ||
44 | extern unsigned int sh73a0_get_core_count(void); | ||
45 | extern void sh73a0_secondary_init(unsigned int cpu); | ||
46 | extern int sh73a0_boot_secondary(unsigned int cpu); | ||
47 | extern void sh73a0_smp_prepare_cpus(void); | ||
48 | |||
43 | #endif /* __ARCH_MACH_COMMON_H */ | 49 | #endif /* __ARCH_MACH_COMMON_H */ |
diff --git a/arch/arm/mach-shmobile/include/mach/smp.h b/arch/arm/mach-shmobile/include/mach/smp.h new file mode 100644 index 000000000000..f4a35ff82c67 --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/smp.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef __MACH_SMP_H | ||
2 | #define __MACH_SMP_H | ||
3 | |||
4 | #include <asm/hardware/gic.h> | ||
5 | #include <asm/smp_mpidr.h> | ||
6 | |||
7 | /* | ||
8 | * We use IRQ1 as the IPI | ||
9 | */ | ||
10 | static inline void smp_cross_call(const struct cpumask *mask) | ||
11 | { | ||
12 | #if defined(CONFIG_ARM_GIC) | ||
13 | gic_raise_softirq(mask, 1); | ||
14 | #endif | ||
15 | } | ||
16 | #endif | ||
diff --git a/arch/arm/mach-shmobile/localtimer.c b/arch/arm/mach-shmobile/localtimer.c new file mode 100644 index 000000000000..2111c28b724e --- /dev/null +++ b/arch/arm/mach-shmobile/localtimer.c | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * SMP support for R-Mobile / SH-Mobile - local timer portion | ||
3 | * | ||
4 | * Copyright (C) 2010 Magnus Damm | ||
5 | * | ||
6 | * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved | ||
7 | * | ||
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 | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/smp.h> | ||
14 | #include <linux/clockchips.h> | ||
15 | #include <asm/smp_twd.h> | ||
16 | #include <asm/localtimer.h> | ||
17 | |||
18 | /* | ||
19 | * Setup the local clock events for a CPU. | ||
20 | */ | ||
21 | void __cpuinit local_timer_setup(struct clock_event_device *evt) | ||
22 | { | ||
23 | evt->irq = 29; | ||
24 | twd_timer_setup(evt); | ||
25 | } | ||
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c new file mode 100644 index 000000000000..3c2c0f49073e --- /dev/null +++ b/arch/arm/mach-shmobile/platsmp.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * SMP support for R-Mobile / SH-Mobile | ||
3 | * | ||
4 | * Copyright (C) 2010 Magnus Damm | ||
5 | * | ||
6 | * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved | ||
7 | * | ||
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 | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <asm/localtimer.h> | ||
19 | #include <asm/mach-types.h> | ||
20 | #include <mach/common.h> | ||
21 | |||
22 | static unsigned int __init shmobile_smp_get_core_count(void) | ||
23 | { | ||
24 | if (machine_is_ag5evm()) | ||
25 | return sh73a0_get_core_count(); | ||
26 | |||
27 | return 1; | ||
28 | } | ||
29 | |||
30 | static void __init shmobile_smp_prepare_cpus(void) | ||
31 | { | ||
32 | if (machine_is_ag5evm()) | ||
33 | sh73a0_smp_prepare_cpus(); | ||
34 | } | ||
35 | |||
36 | |||
37 | void __cpuinit platform_secondary_init(unsigned int cpu) | ||
38 | { | ||
39 | trace_hardirqs_off(); | ||
40 | |||
41 | if (machine_is_ag5evm()) | ||
42 | sh73a0_secondary_init(cpu); | ||
43 | } | ||
44 | |||
45 | int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
46 | { | ||
47 | if (machine_is_ag5evm()) | ||
48 | return sh73a0_boot_secondary(cpu); | ||
49 | |||
50 | return -ENOSYS; | ||
51 | } | ||
52 | |||
53 | void __init smp_init_cpus(void) | ||
54 | { | ||
55 | unsigned int ncores = shmobile_smp_get_core_count(); | ||
56 | unsigned int i; | ||
57 | |||
58 | for (i = 0; i < ncores; i++) | ||
59 | set_cpu_possible(i, true); | ||
60 | } | ||
61 | |||
62 | void __init smp_prepare_cpus(unsigned int max_cpus) | ||
63 | { | ||
64 | unsigned int ncores = shmobile_smp_get_core_count(); | ||
65 | unsigned int cpu = smp_processor_id(); | ||
66 | int i; | ||
67 | |||
68 | smp_store_cpu_info(cpu); | ||
69 | |||
70 | if (max_cpus > ncores) | ||
71 | max_cpus = ncores; | ||
72 | |||
73 | for (i = 0; i < max_cpus; i++) | ||
74 | set_cpu_present(i, true); | ||
75 | |||
76 | if (max_cpus > 1) { | ||
77 | shmobile_smp_prepare_cpus(); | ||
78 | |||
79 | /* | ||
80 | * Enable the local timer or broadcast device for the | ||
81 | * boot CPU, but only if we have more than one CPU. | ||
82 | */ | ||
83 | percpu_timer_setup(); | ||
84 | } | ||
85 | } | ||
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 | |||
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 | } | ||