aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhangfei Gao <zhangfei.gao@linaro.org>2013-01-22 13:12:23 +0800
committerGuodong Xu <guodong.xu@linaro.org>2013-02-21 16:12:23 +0800
commit727ff80179f73fea39b998fba8d8c81f8daa8898 (patch)
tree662f8f0b7ccb581ee31e4a0c11e9b0dbbd3485ef
parentcd338d3a9f47ce77b101a7f755c606fc2e3ec0e1 (diff)
ARM: hs: support smp
uboot requirement: CPUn: enable gic cpu interface; 1: wfi; check regn; /* notes: CPUn check own specific regn */ if (reg == 0) goto 1; else disable gic cpu interface set pc regn Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org> Tested-by: Zhang Mingjun <zhang.mingjun@linaro.org> Tested-by: Li Xin <li.xin@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/system.txt28
-rw-r--r--arch/arm/mach-hs/Kconfig1
-rw-r--r--arch/arm/mach-hs/Makefile1
-rw-r--r--arch/arm/mach-hs/hs-dt.c30
-rw-r--r--arch/arm/mach-hs/platsmp.c78
5 files changed, 138 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/system.txt b/Documentation/devicetree/bindings/arm/hisilicon/system.txt
new file mode 100644
index 00000000000..9c707e86b3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/system.txt
@@ -0,0 +1,28 @@
+Hisilicon system requirement
+
+Required properties:
+- compatible : "hisilicon,sysctrl"
+- reg : Address and size of sysctrl.
+- smp_reg : offset in sysctrl for notifying slave cpu booting
+ cpu 1, reg;
+ cpu 2, reg + 0x4;
+ cpu 3, reg + 0x8;
+ If reg value is not zero, cpun exit wfi and go
+- reset_reg : offset in sysctrl for system reset
+
+Example:
+ hi3716:
+ sysctrl@f8000000 {
+ compatible = "hisilicon,sysctrl";
+ reg = <0xf8000000 0x1000>;
+ smp_reg = <0xc0>;
+ reboot_reg = <0x4>;
+ };
+
+ hi3620:
+ sysctrl@fc802000 {
+ compatible = "hisilicon,sysctrl";
+ reg = <0xfc802000 0x1000>;
+ smp_reg = <0x31c>;
+ reboot_reg = <0x4>;
+ };
diff --git a/arch/arm/mach-hs/Kconfig b/arch/arm/mach-hs/Kconfig
index 6fbc2e3ed56..04a76a3fafe 100644
--- a/arch/arm/mach-hs/Kconfig
+++ b/arch/arm/mach-hs/Kconfig
@@ -6,6 +6,7 @@ config ARCH_HS
select PINCTRL_SINGLE
select SERIAL_AMBA_PL011
select SERIAL_AMBA_PL011_CONSOLE
+ select HAVE_SMP
help
Support for Hislicon Hi36xx/Hi37xx processor family
diff --git a/arch/arm/mach-hs/Makefile b/arch/arm/mach-hs/Makefile
index d79ecb55a2c..56bd1be58d2 100644
--- a/arch/arm/mach-hs/Makefile
+++ b/arch/arm/mach-hs/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_MACH_HS_DT) += hs-dt.o
+obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-hs/hs-dt.c b/arch/arm/mach-hs/hs-dt.c
index 9b79071fdb9..a644ea68ec6 100644
--- a/arch/arm/mach-hs/hs-dt.c
+++ b/arch/arm/mach-hs/hs-dt.c
@@ -15,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/smp.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/cache-l2x0.h>
@@ -23,6 +24,32 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
+#include <asm/smp_plat.h>
+#include <asm/proc-fns.h>
+
+static void __iomem *hs_sctrl_base;
+static int hs_smp_reg;
+static int hs_reset_reg;
+
+static void __init hs_map_io(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+ hs_sctrl_base = of_iomap(np, 0);
+ of_property_read_u32(np, "smp_reg", &hs_smp_reg);
+ of_property_read_u32(np, "reset_reg", &hs_reset_reg);
+}
+
+void hs_set_cpu_jump(int cpu, void *jump_addr)
+{
+ int offset = hs_smp_reg;
+
+ cpu = cpu_logical_map(cpu);
+ if (cpu > 0)
+ offset += 0x04 * (cpu - 1);
+ writel(virt_to_phys(jump_addr), hs_sctrl_base + offset);
+}
static struct of_device_id hs_timer_match[] __initdata = {
{ .compatible = "arm,sp804", },
@@ -83,6 +110,7 @@ static void __init hs_irq_init(void)
int ret;
u32 data[2];
+ hs_map_io();
of_irq_init(hs_irq_match);
node = of_find_matching_node(NULL, hs_l2cache_match);
@@ -110,8 +138,10 @@ static const char *hs_compat[] __initdata = {
NULL,
};
+extern struct smp_operations hs_smp_ops;
DT_MACHINE_START(HS_DT, "Hisilicon Hi36xx/Hi37xx (Flattened Device Tree)")
/* Maintainer: Haojian Zhuang <haojian.zhuang@linaro.org> */
+ .smp = smp_ops(hs_smp_ops),
.map_io = debug_ll_io_init,
.init_irq = hs_irq_init,
.timer = &hs_timer,
diff --git a/arch/arm/mach-hs/platsmp.c b/arch/arm/mach-hs/platsmp.c
new file mode 100644
index 00000000000..5eb4b2bcb10
--- /dev/null
+++ b/arch/arm/mach-hs/platsmp.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012-2013 Linaro Ltd.
+ * Based on platsmp.c, Copyright (C) 2002 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#include <asm/smp_scu.h>
+#include <asm/hardware/gic.h>
+#include <asm/proc-fns.h>
+
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+static void __init hs_smp_init_cpus(void)
+{
+ set_smp_cross_call(gic_raise_softirq);
+}
+
+static void __init hs_smp_prepare_cpus(unsigned int max_cpus)
+{
+ unsigned long base;
+ void __iomem *hs_scu_base_addr;
+
+ asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
+
+ hs_scu_base_addr = ioremap(base, SZ_4K);
+
+ if (hs_scu_base_addr)
+ scu_enable(hs_scu_base_addr);
+}
+
+static void __cpuinit hs_secondary_init(unsigned int cpu)
+{
+ gic_secondary_init(0);
+}
+
+static int __cpuinit hs_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ extern void secondary_startup(void);
+ extern void hs_set_cpu_jump(int cpu, void *jump_addr);
+
+ hs_set_cpu_jump(cpu, secondary_startup);
+ gic_raise_softirq(cpumask_of(cpu), 0);
+ return 0;
+}
+
+static void hs_cpu_die(unsigned int cpu)
+{
+ cpu_do_idle();
+
+ /* We should have never returned from idle */
+ panic("cpu %d unexpectedly exit from shutdown\n", cpu);
+}
+
+struct smp_operations hs_smp_ops __initdata = {
+ .smp_init_cpus = hs_smp_init_cpus,
+ .smp_prepare_cpus = hs_smp_prepare_cpus,
+ .smp_secondary_init = hs_secondary_init,
+ .smp_boot_secondary = hs_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = hs_cpu_die,
+#endif
+};