[PATCH v11 5/6] ARM: hi3xxx: add smp support
Dinh Nguyen
dinh.linux at gmail.com
Thu Nov 7 05:30:34 EST 2013
On 11/7/13 2:41 AM, Haojian Zhuang wrote:
> From: Zhangfei Gao <zhangfei.gao at linaro.org>
>
> Enable SMP support on hi3xxx platform
>
> Signed-off-by: Zhangfei Gao <zhangfei.gao at linaro.org>
> Tested-by: Zhang Mingjun <zhang.mingjun at linaro.org>
> Tested-by: Li Xin <li.xin at linaro.org>
> Signed-off-by: Haojian Zhuang <haojian.zhuang at 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?
> +
> 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.
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,
> +};
More information about the linux-arm-kernel
mailing list