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 | |
| 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>
| -rw-r--r-- | arch/arm/Kconfig | 2 | ||||
| -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 |
9 files changed, 305 insertions, 1 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7daab42eb54f..e2f801167593 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -1258,7 +1258,7 @@ config SMP | |||
| 1258 | depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \ | 1258 | depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \ |
| 1259 | MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \ | 1259 | MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \ |
| 1260 | ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \ | 1260 | ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \ |
| 1261 | ARCH_MSM_SCORPIONMP | 1261 | ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE |
| 1262 | select USE_GENERIC_SMP_HELPERS | 1262 | select USE_GENERIC_SMP_HELPERS |
| 1263 | select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP | 1263 | select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP |
| 1264 | help | 1264 | help |
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 | } | ||
