| From 0af702823eae60eceedd80cbd4bd0670285a2cca Mon Sep 17 00:00:00 2001 |
| From: Magnus Damm <damm@opensource.se> |
| Date: Wed, 16 May 2012 15:45:25 +0900 |
| Subject: mach-shmobile: Emma Mobile EV2 SMP support V3 |
| |
| This is V3 of Emma Mobile EV2 SMP support. |
| |
| At this point only the most basic form of SMP operation |
| is supported. TWD and CPU Hotplug support is excluded. |
| |
| Tied to both the Emma Mobile EV2 and the KZM9D board |
| due to the need to switch on board in platsmp.c and |
| the newly introduced need for static mappings. |
| |
| The static mappings are needed to allow hardware |
| acces early during boot when SMP is initialized. |
| This early requirement forces us to also map in |
| the SMU registers. |
| |
| Signed-off-by: Magnus Damm <damm@opensource.se> |
| Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> |
| (cherry picked from commit bd5a875d90c878be4d23f54ea565253734ae2377) |
| |
| Conflicts: |
| arch/arm/mach-shmobile/Makefile |
| arch/arm/mach-shmobile/platsmp.c |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| arch/arm/mach-shmobile/Makefile | 1 + |
| arch/arm/mach-shmobile/board-kzm9d.c | 1 + |
| arch/arm/mach-shmobile/clock-emev2.c | 18 +++++ |
| arch/arm/mach-shmobile/include/mach/emev2.h | 7 ++ |
| arch/arm/mach-shmobile/platsmp.c | 17 +++++ |
| arch/arm/mach-shmobile/setup-emev2.c | 24 +++++++ |
| arch/arm/mach-shmobile/smp-emev2.c | 97 +++++++++++++++++++++++++++ |
| 7 files changed, 165 insertions(+) |
| create mode 100644 arch/arm/mach-shmobile/smp-emev2.c |
| |
| diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile |
| index bdd4383..a2c56d5 100644 |
| --- a/arch/arm/mach-shmobile/Makefile |
| +++ b/arch/arm/mach-shmobile/Makefile |
| @@ -18,6 +18,7 @@ smp-y := platsmp.o headsmp.o |
| smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
| smp-$(CONFIG_LOCAL_TIMERS) += localtimer.o |
| smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o |
| +smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o |
| |
| # Pinmux setup |
| pfc-y := |
| diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c |
| index e743f90..42fc479 100644 |
| --- a/arch/arm/mach-shmobile/board-kzm9d.c |
| +++ b/arch/arm/mach-shmobile/board-kzm9d.c |
| @@ -27,6 +27,7 @@ |
| #include <asm/hardware/gic.h> |
| |
| MACHINE_START(KZM9D, "kzm9d") |
| + .map_io = emev2_map_io, |
| .init_early = emev2_add_early_devices, |
| .nr_irqs = NR_IRQS_LEGACY, |
| .init_irq = emev2_init_irq, |
| diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c |
| index 64d4a56..9414383 100644 |
| --- a/arch/arm/mach-shmobile/clock-emev2.c |
| +++ b/arch/arm/mach-shmobile/clock-emev2.c |
| @@ -40,6 +40,7 @@ |
| #define USIB2SCLKDIV 0x65c |
| #define USIB3SCLKDIV 0x660 |
| #define STI_CLKSEL 0x688 |
| +#define SMU_GENERAL_REG0 0x7c0 |
| |
| /* not pretty, but hey */ |
| static void __iomem *smu_base; |
| @@ -50,6 +51,11 @@ static void emev2_smu_write(unsigned long value, int offs) |
| iowrite32(value, smu_base + offs); |
| } |
| |
| +void emev2_set_boot_vector(unsigned long value) |
| +{ |
| + emev2_smu_write(value, SMU_GENERAL_REG0); |
| +} |
| + |
| static struct clk_mapping smu_mapping = { |
| .phys = EMEV2_SMU_BASE, |
| .len = PAGE_SIZE, |
| @@ -196,6 +202,18 @@ static struct clk_lookup lookups[] = { |
| void __init emev2_clock_init(void) |
| { |
| int k, ret = 0; |
| + static int is_setup; |
| + |
| + /* yuck, this is ugly as hell, but the non-smp case of clocks |
| + * code is now designed to rely on ioremap() instead of static |
| + * entity maps. in the case of smp we need access to the SMU |
| + * register earlier than ioremap() is actually working without |
| + * any static maps. to enable SMP in ugly but with dynamic |
| + * mappings we have to call emev2_clock_init() from different |
| + * places depending on UP and SMP... |
| + */ |
| + if (is_setup++) |
| + return; |
| |
| smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE); |
| BUG_ON(!smu_base); |
| diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h |
| index 92646c1..3fc7184 100644 |
| --- a/arch/arm/mach-shmobile/include/mach/emev2.h |
| +++ b/arch/arm/mach-shmobile/include/mach/emev2.h |
| @@ -1,9 +1,16 @@ |
| #ifndef __ASM_EMEV2_H__ |
| #define __ASM_EMEV2_H__ |
| |
| +extern void emev2_map_io(void); |
| extern void emev2_init_irq(void); |
| extern void emev2_add_early_devices(void); |
| extern void emev2_add_standard_devices(void); |
| extern void emev2_clock_init(void); |
| +extern void emev2_set_boot_vector(unsigned long value); |
| +extern unsigned int emev2_get_core_count(void); |
| +extern int emev2_platform_cpu_kill(unsigned int cpu); |
| +extern void emev2_secondary_init(unsigned int cpu); |
| +extern int emev2_boot_secondary(unsigned int cpu); |
| +extern void emev2_smp_prepare_cpus(void); |
| |
| #endif /* __ASM_EMEV2_H__ */ |
| diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c |
| index 1103ce5..9e98f9e 100644 |
| --- a/arch/arm/mach-shmobile/platsmp.c |
| +++ b/arch/arm/mach-shmobile/platsmp.c |
| @@ -20,14 +20,19 @@ |
| #include <asm/localtimer.h> |
| #include <asm/mach-types.h> |
| #include <mach/common.h> |
| +#include <mach/emev2.h> |
| |
| #define is_sh73a0() (machine_is_ag5evm() || machine_is_kzm9g()) |
| +#define is_emev2() machine_is_kzm9d() |
| |
| static unsigned int __init shmobile_smp_get_core_count(void) |
| { |
| if (is_sh73a0()) |
| return sh73a0_get_core_count(); |
| |
| + if (is_emev2()) |
| + return emev2_get_core_count(); |
| + |
| return 1; |
| } |
| |
| @@ -35,10 +40,16 @@ static void __init shmobile_smp_prepare_cpus(void) |
| { |
| if (is_sh73a0()) |
| sh73a0_smp_prepare_cpus(); |
| + |
| + if (is_emev2()) |
| + emev2_smp_prepare_cpus(); |
| } |
| |
| int shmobile_platform_cpu_kill(unsigned int cpu) |
| { |
| + if (is_emev2()) |
| + return emev2_platform_cpu_kill(cpu); |
| + |
| return 1; |
| } |
| |
| @@ -48,6 +59,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu) |
| |
| if (is_sh73a0()) |
| sh73a0_secondary_init(cpu); |
| + |
| + if (is_emev2()) |
| + emev2_secondary_init(cpu); |
| } |
| |
| int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) |
| @@ -55,6 +69,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) |
| if (is_sh73a0()) |
| return sh73a0_boot_secondary(cpu); |
| |
| + if (is_emev2()) |
| + return emev2_boot_secondary(cpu); |
| + |
| return -ENOSYS; |
| } |
| |
| diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c |
| index 9fff623..2a03a78 100644 |
| --- a/arch/arm/mach-shmobile/setup-emev2.c |
| +++ b/arch/arm/mach-shmobile/setup-emev2.c |
| @@ -34,6 +34,30 @@ |
| #include <asm/mach/time.h> |
| #include <asm/hardware/gic.h> |
| |
| +static struct map_desc emev2_io_desc[] __initdata = { |
| +#ifdef CONFIG_SMP |
| + /* 128K entity map for 0xe0100000 (SMU) */ |
| + { |
| + .virtual = 0xe0100000, |
| + .pfn = __phys_to_pfn(0xe0100000), |
| + .length = SZ_128K, |
| + .type = MT_DEVICE |
| + }, |
| + /* 2M mapping for SCU + L2 controller */ |
| + { |
| + .virtual = 0xf0000000, |
| + .pfn = __phys_to_pfn(0x1e000000), |
| + .length = SZ_2M, |
| + .type = MT_DEVICE |
| + }, |
| +#endif |
| +}; |
| + |
| +void __init emev2_map_io(void) |
| +{ |
| + iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc)); |
| +} |
| + |
| /* UART */ |
| static struct resource uart0_resources[] = { |
| [0] = { |
| diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c |
| new file mode 100644 |
| index 0000000..6a35c4a |
| --- /dev/null |
| +++ b/arch/arm/mach-shmobile/smp-emev2.c |
| @@ -0,0 +1,97 @@ |
| +/* |
| + * SMP support for Emma Mobile EV2 |
| + * |
| + * Copyright (C) 2012 Renesas Solutions Corp. |
| + * Copyright (C) 2012 Magnus Damm |
| + * |
| + * This program is free software; you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License as published by |
| + * the Free Software Foundation; version 2 of the License. |
| + * |
| + * This program is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with this program; if not, write to the Free Software |
| + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| + */ |
| +#include <linux/kernel.h> |
| +#include <linux/init.h> |
| +#include <linux/smp.h> |
| +#include <linux/spinlock.h> |
| +#include <linux/io.h> |
| +#include <linux/delay.h> |
| +#include <mach/common.h> |
| +#include <mach/emev2.h> |
| +#include <asm/smp_plat.h> |
| +#include <asm/smp_scu.h> |
| +#include <asm/hardware/gic.h> |
| +#include <asm/cacheflush.h> |
| + |
| +#define EMEV2_SCU_BASE 0x1e000000 |
| + |
| +static DEFINE_SPINLOCK(scu_lock); |
| +static void __iomem *scu_base; |
| + |
| +static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) |
| +{ |
| + unsigned long tmp; |
| + |
| + /* we assume this code is running on a different cpu |
| + * than the one that is changing coherency setting */ |
| + spin_lock(&scu_lock); |
| + tmp = readl(scu_base + 8); |
| + tmp &= ~clr; |
| + tmp |= set; |
| + writel(tmp, scu_base + 8); |
| + spin_unlock(&scu_lock); |
| + |
| +} |
| + |
| +unsigned int __init emev2_get_core_count(void) |
| +{ |
| + if (!scu_base) { |
| + scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE); |
| + emev2_clock_init(); /* need ioremapped SMU */ |
| + } |
| + |
| + WARN_ON_ONCE(!scu_base); |
| + |
| + return scu_base ? scu_get_core_count(scu_base) : 1; |
| +} |
| + |
| +int emev2_platform_cpu_kill(unsigned int cpu) |
| +{ |
| + return 0; /* not supported yet */ |
| +} |
| + |
| +void __cpuinit emev2_secondary_init(unsigned int cpu) |
| +{ |
| + gic_secondary_init(0); |
| +} |
| + |
| +int __cpuinit emev2_boot_secondary(unsigned int cpu) |
| +{ |
| + cpu = cpu_logical_map(cpu); |
| + |
| + /* enable cache coherency */ |
| + modify_scu_cpu_psr(0, 3 << (cpu * 8)); |
| + |
| + /* Tell ROM loader about our vector (in headsmp.S) */ |
| + emev2_set_boot_vector(__pa(shmobile_secondary_vector)); |
| + |
| + gic_raise_softirq(cpumask_of(cpu), 1); |
| + return 0; |
| +} |
| + |
| +void __init emev2_smp_prepare_cpus(void) |
| +{ |
| + int cpu = cpu_logical_map(0); |
| + |
| + scu_enable(scu_base); |
| + |
| + /* enable cache coherency on CPU0 */ |
| + modify_scu_cpu_psr(0, 3 << (cpu * 8)); |
| +} |
| -- |
| 1.7.10.1.362.g242cab3 |
| |