Thread (1 message) 1 message, 1 author, 2013-11-12

[PATCH v11 5/6] ARM: hi3xxx: add smp support

From: haojian.zhuang@linaro.org (Haojian Zhuang)
Date: 2013-11-12 08:49:42
Also in: linux-devicetree

On 7 November 2013 18:30, Dinh Nguyen [off-list ref] wrote:
On 11/7/13 2:41 AM, Haojian Zhuang wrote:
quoted
From: Zhangfei Gao <zhangfei.gao@linaro.org>

Enable SMP support on hi3xxx platform

Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Tested-by: Zhang Mingjun <redacted>
Tested-by: Li Xin <redacted>
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
 .../bindings/arm/hisilicon/hisilicon.txt           | 30 ++++++--
 arch/arm/boot/dts/hi3620.dtsi                      | 38 ++++++++++
 arch/arm/mach-hi3xxx/Kconfig                       |  3 +
 arch/arm/mach-hi3xxx/Makefile                      |  1 +
 arch/arm/mach-hi3xxx/core.h                        | 11 +++
 arch/arm/mach-hi3xxx/hi3xxx.c                      | 34 +++++++++
 arch/arm/mach-hi3xxx/platsmp.c                     | 84 ++++++++++++++++++++++
 7 files changed, 197 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/mach-hi3xxx/core.h
 create mode 100644 arch/arm/mach-hi3xxx/platsmp.c
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 3be60c8..8c7a465 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -1,10 +1,32 @@
 Hisilicon Platforms Device Tree Bindings
 ----------------------------------------------------

-Hi3716 Development Board
-Required root node properties:
-     - compatible = "hisilicon,hi3716-dkb";
-
 Hi4511 Board
 Required root node properties:
      - compatible = "hisilicon,hi3620-hi4511";
+
+Hisilicon system controller
+
+Required properties:
+- compatible : "hisilicon,sysctrl"
+- reg : Register address and size
+
+Optional properties:
+- smp-offset : 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
+- resume-offset : offset in sysctrl for notifying cpu0 when resume
+- reboot-offset : offset in sysctrl for system reboot
+
+Example:
+
+     /* for Hi3620 */
+     sysctrl: system-controller at fc802000 {
+             compatible = "hisilicon,sysctrl";
+             reg = <0xfc802000 0x1000>;
+             smp-offset = <0x31c>;
+             resume-offset = <0x308>;
+             reboot-offset = <0x4>;
+     };
diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi
index b9d8679..e311937 100644
--- a/arch/arm/boot/dts/hi3620.dtsi
+++ b/arch/arm/boot/dts/hi3620.dtsi
@@ -39,6 +39,27 @@
                      reg = <0x0>;
                      next-level-cache = <&L2>;
              };
+
+             cpu at 1 {
+                     compatible = "arm,cortex-a9";
+                     device_type = "cpu";
+                     reg = <1>;
+                     next-level-cache = <&L2>;
+             };
+
+             cpu at 2 {
+                     compatible = "arm,cortex-a9";
+                     device_type = "cpu";
+                     reg = <2>;
+                     next-level-cache = <&L2>;
+             };
+
+             cpu at 3 {
+                     compatible = "arm,cortex-a9";
+                     device_type = "cpu";
+                     reg = <3>;
+                     next-level-cache = <&L2>;
+             };
      };

      amba {
@@ -65,6 +86,17 @@
                      reg = <0x1000 0x1000>, <0x100 0x100>;
              };

+             sysctrl: system-controller at 802000 {
+                     compatible = "hisilicon,sysctrl";
+                     reg = <0x802000 0x1000>;
+                     #address-cells = <1>;
+                     #size-cells = <0>;
+
+                     smp-offset = <0x31c>;
+                     resume-offset = <0x308>;
+                     reboot-offset = <0x4>;
+             };
+
              dual_timer0: dual_timer at 800000 {
                      compatible = "arm,sp804", "arm,primecell";
                      reg = <0x800000 0x1000>;
@@ -115,6 +147,12 @@
                      status = "disabled";
              };

+             timer5: timer at 600 {
+                     compatible = "arm,cortex-a9-twd-timer";
+                     reg = <0x600 0x20>;
+                     interrupts = <1 13 0xf01>;
+             };
Do you have a clocks node for this timer?
As I mentioned in the 0th patch, clock binding are totally removed
in this patch. And clock driver will be append in another patch set.
quoted
+
              uart0: uart at b00000 {
                      compatible = "arm,pl011", "arm,primecell";
                      reg = <0xb00000 0x1000>;
diff --git a/arch/arm/mach-hi3xxx/Kconfig b/arch/arm/mach-hi3xxx/Kconfig
index 68bd26c..d0f298a 100644
--- a/arch/arm/mach-hi3xxx/Kconfig
+++ b/arch/arm/mach-hi3xxx/Kconfig
@@ -6,6 +6,9 @@ config ARCH_HI3xxx
      select CACHE_L2X0
      select CLKSRC_OF
      select GENERIC_CLOCKEVENTS
+     select HAVE_ARM_SCU
+     select HAVE_ARM_TWD
Need "if SMP" to avoid a build failure for a non-smp kernel.
ARCH_HI3xxx always need SMP configuration. HAVE_SMP is already
required. So it's impossible to build a non-smp kernel with this kernel
configuration.
Dinh
quoted
+     select HAVE_SMP
      select PINCTRL
      select PINCTRL_SINGLE
      help
diff --git a/arch/arm/mach-hi3xxx/Makefile b/arch/arm/mach-hi3xxx/Makefile
index d68ebb3..7a869a7 100644
--- a/arch/arm/mach-hi3xxx/Makefile
+++ b/arch/arm/mach-hi3xxx/Makefile
@@ -3,3 +3,4 @@
 #

 obj-y        += hi3xxx.o
+obj-$(CONFIG_SMP)            += platsmp.o
diff --git a/arch/arm/mach-hi3xxx/core.h b/arch/arm/mach-hi3xxx/core.h
new file mode 100644
index 0000000..226f020
--- /dev/null
+++ b/arch/arm/mach-hi3xxx/core.h
@@ -0,0 +1,11 @@
+#ifndef __HISILICON_CORE_H
+#define __HISILICON_CORE_H
+
+#include <linux/reboot.h>
+
+extern void hi3xxx_set_cpu_jump(int cpu, void *jump_addr);
+extern int hi3xxx_get_cpu_jump(int cpu);
+extern void secondary_startup(void);
+extern struct smp_operations hi3xxx_smp_ops;
+
+#endif
diff --git a/arch/arm/mach-hi3xxx/hi3xxx.c b/arch/arm/mach-hi3xxx/hi3xxx.c
index 925af13..80990b3 100644
--- a/arch/arm/mach-hi3xxx/hi3xxx.c
+++ b/arch/arm/mach-hi3xxx/hi3xxx.c
@@ -14,11 +14,16 @@
 #include <linux/clk-provider.h>
 #include <linux/clocksource.h>
 #include <linux/irqchip.h>
+#include <linux/of_address.h>
 #include <linux/of_platform.h>

+#include <asm/proc-fns.h>
+
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>

+#include "core.h"
+
 /*
  * This table is only for optimization. Since ioremap() could always share
  * the same mapping if it's defined as static IO mapping.
@@ -29,6 +34,7 @@
  */
 static struct map_desc hi3620_io_desc[] __initdata = {
      {
+             /* sysctrl */
What's this comment for?
quoted
              .pfn            = __phys_to_pfn(0xfc802000),
              .virtual        = 0xfe802000,
              .length         = 0x1000,
@@ -48,6 +54,32 @@ static void __init hi3xxx_timer_init(void)
      clocksource_of_init();
 }

+static void hi3xxx_restart(enum reboot_mode mode, const char *cmd)
+{
+     struct device_node *np;
+     void __iomem *base;
+     int offset;
+
+     np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+     if (!np) {
+             pr_err("failed to find hisilicon,sysctrl node\n");
+             return;
+     }
+     base = of_iomap(np, 0);
+     if (!base) {
+             pr_err("failed to map address in hisilicon,sysctrl node\n");
+             return;
+     }
+     if (of_property_read_u32(np, "reboot-offset", &offset) < 0) {
+             pr_err("failed to find reboot-offset property\n");
+             return;
+     }
+     writel_relaxed(0xdeadbeef, base + offset);
+
+     while (1)
+             cpu_do_idle();
+}
+
 static const char *hi3xxx_compat[] __initdata = {
      "hisilicon,hi3620-hi4511",
      NULL,
@@ -57,4 +89,6 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)")
      .map_io         = hi3620_map_io,
      .init_time      = hi3xxx_timer_init,
      .dt_compat      = hi3xxx_compat,
+     .smp            = smp_ops(hi3xxx_smp_ops),
+     .restart        = hi3xxx_restart,
 MACHINE_END
diff --git a/arch/arm/mach-hi3xxx/platsmp.c b/arch/arm/mach-hi3xxx/platsmp.c
new file mode 100644
index 0000000..a4d04c0
--- /dev/null
+++ b/arch/arm/mach-hi3xxx/platsmp.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ * 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.
+ */
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+#include "core.h"
+
+static void __iomem *ctrl_base = NULL;
+
+void hi3xxx_set_cpu_jump(int cpu, void *jump_addr)
+{
+     cpu = cpu_logical_map(cpu);
+     if (!cpu || !ctrl_base)
+             return;
+     writel_relaxed(virt_to_phys(jump_addr), ctrl_base + ((cpu - 1) << 2));
+}
+
+int hi3xxx_get_cpu_jump(int cpu)
+{
+     cpu = cpu_logical_map(cpu);
+     if (!cpu || !ctrl_base)
+             return 0;
+     return readl_relaxed(ctrl_base + ((cpu - 1 ) << 2));
+}
+
+static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus)
+{
+     struct device_node *np = NULL;
+     unsigned long base = 0;
+     u32 offset = 0;
+     void __iomem *scu_base = NULL;
+
+     if (scu_a9_has_base()) {
+             base = scu_a9_get_base();
+             scu_base = ioremap(base, SZ_4K);
+             if (!scu_base) {
+                     pr_err("ioremap(scu_base) failed\n");
+                     return;
+             }
+             scu_enable(scu_base);
+             iounmap(scu_base);
+     }
+     if (!ctrl_base) {
+             np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+             if (!np) {
+                     pr_err("failed to find hisilicon,sysctrl node\n");
+                     return;
+             }
+             ctrl_base = of_iomap(np, 0);
+             if (!ctrl_base) {
+                     pr_err("failed to map address\n");
+                     return;
+             }
+             if (of_property_read_u32(np, "smp-offset", &offset) < 0) {
+                     pr_err("failed to find smp-offset property\n");
+                     return;
+             }
+             ctrl_base += offset;
+     }
+}
+
+static int hi3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+     hi3xxx_set_cpu_jump(cpu, secondary_startup);
+     arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+     return 0;
+}
+
+struct smp_operations hi3xxx_smp_ops __initdata = {
+     .smp_prepare_cpus       = hi3xxx_smp_prepare_cpus,
+     .smp_boot_secondary     = hi3xxx_boot_secondary,
+};
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help