On 11/7/13 2:41 AM, Haojian Zhuang wrote: > From: Zhangfei Gao <zhangfei.gao@xxxxxxxxxx> > > Enable SMP support on hi3xxx platform > > Signed-off-by: Zhangfei Gao <zhangfei.gao@xxxxxxxxxx> > Tested-by: Zhang Mingjun <zhang.mingjun@xxxxxxxxxx> > Tested-by: Li Xin <li.xin@xxxxxxxxxx> > Signed-off-by: Haojian Zhuang <haojian.zhuang@xxxxxxxxxx> > --- > .../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@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@1 { > + compatible = "arm,cortex-a9"; > + device_type = "cpu"; > + reg = <1>; > + next-level-cache = <&L2>; > + }; > + > + cpu@2 { > + compatible = "arm,cortex-a9"; > + device_type = "cpu"; > + reg = <2>; > + next-level-cache = <&L2>; > + }; > + > + cpu@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@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@800000 { > compatible = "arm,sp804", "arm,primecell"; > reg = <0x800000 0x1000>; > @@ -115,6 +147,12 @@ > status = "disabled"; > }; > > + timer5: timer@600 { > + compatible = "arm,cortex-a9-twd-timer"; > + reg = <0x600 0x20>; > + interrupts = <1 13 0xf01>; > + }; Do you have a clocks node for this timer? > + > uart0: uart@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. Dinh > + 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? > .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, > +}; -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html