source "arch/arm/mach-gemini/Kconfig"
-source "arch/arm/mach-hi3xxx/Kconfig"
-
source "arch/arm/mach-highbank/Kconfig"
+source "arch/arm/mach-hisi/Kconfig"
+
source "arch/arm/mach-integrator/Kconfig"
source "arch/arm/mach-iop32x/Kconfig"
machine-$(CONFIG_ARCH_EP93XX) += ep93xx
machine-$(CONFIG_ARCH_EXYNOS) += exynos
machine-$(CONFIG_ARCH_GEMINI) += gemini
-machine-$(CONFIG_ARCH_HI3xxx) += hi3xxx
machine-$(CONFIG_ARCH_HIGHBANK) += highbank
+machine-$(CONFIG_ARCH_HI3xxx) += hisi
machine-$(CONFIG_ARCH_INTEGRATOR) += integrator
machine-$(CONFIG_ARCH_IOP13XX) += iop13xx
machine-$(CONFIG_ARCH_IOP32X) += iop32x
+++ /dev/null
-config ARCH_HI3xxx
- bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7
- select ARM_AMBA
- select ARM_GIC
- select ARM_TIMER_SP804
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select CACHE_L2X0
- select CLKSRC_OF
- select GENERIC_CLOCKEVENTS
- select HAVE_ARM_SCU
- select HAVE_ARM_TWD
- select HAVE_SMP
- select PINCTRL
- select PINCTRL_SINGLE
- select SMP
- help
- Support for Hisilicon Hi36xx/Hi37xx processor family
+++ /dev/null
-#
-# Makefile for Hisilicon Hi36xx/Hi37xx processors line
-#
-
-obj-y += hi3xxx.o
-obj-$(CONFIG_SMP) += platsmp.o
-obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+++ /dev/null
-#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;
-
-extern void hi3xxx_cpu_die(unsigned int cpu);
-extern int hi3xxx_cpu_kill(unsigned int cpu);
-extern void hi3xxx_set_cpu(int cpu, bool enable);
-
-#endif
+++ /dev/null
-/*
- * (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine
- *
- * Copyright (c) 2012-2013 Hisilicon Ltd.
- * Copyright (c) 2012-2013 Linaro Ltd.
- *
- * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#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"
-
-#define HI3620_SYSCTRL_PHYS_BASE 0xfc802000
-#define HI3620_SYSCTRL_VIRT_BASE 0xfe802000
-
-/*
- * This table is only for optimization. Since ioremap() could always share
- * the same mapping if it's defined as static IO mapping.
- *
- * Without this table, system could also work. The cost is some virtual address
- * spaces wasted since ioremap() may be called multi times for the same
- * IO space.
- */
-static struct map_desc hi3620_io_desc[] __initdata = {
- {
- /* sysctrl */
- .pfn = __phys_to_pfn(HI3620_SYSCTRL_PHYS_BASE),
- .virtual = HI3620_SYSCTRL_VIRT_BASE,
- .length = 0x1000,
- .type = MT_DEVICE,
- },
-};
-
-static void __init hi3620_map_io(void)
-{
- debug_ll_io_init();
- iotable_init(hi3620_io_desc, ARRAY_SIZE(hi3620_io_desc));
-}
-
-static void __init hi3xxx_timer_init(void)
-{
- of_clk_init(NULL);
- 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[] __initconst = {
- "hisilicon,hi3620-hi4511",
- NULL,
-};
-
-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
+++ /dev/null
-/*
- * Copyright (c) 2013 Linaro Ltd.
- * Copyright (c) 2013 Hisilicon Limited.
- *
- * 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/cpu.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <asm/cacheflush.h>
-#include <asm/smp_plat.h>
-#include "core.h"
-
-/* Sysctrl registers in Hi3620 SoC */
-#define SCISOEN 0xc0
-#define SCISODIS 0xc4
-#define SCPERPWREN 0xd0
-#define SCPERPWRDIS 0xd4
-#define SCCPUCOREEN 0xf4
-#define SCCPUCOREDIS 0xf8
-#define SCPERCTRL0 0x200
-#define SCCPURSTEN 0x410
-#define SCCPURSTDIS 0x414
-
-/*
- * bit definition in SCISOEN/SCPERPWREN/...
- *
- * CPU2_ISO_CTRL (1 << 5)
- * CPU3_ISO_CTRL (1 << 6)
- * ...
- */
-#define CPU2_ISO_CTRL (1 << 5)
-
-/*
- * bit definition in SCPERCTRL0
- *
- * CPU0_WFI_MASK_CFG (1 << 28)
- * CPU1_WFI_MASK_CFG (1 << 29)
- * ...
- */
-#define CPU0_WFI_MASK_CFG (1 << 28)
-
-/*
- * bit definition in SCCPURSTEN/...
- *
- * CPU0_SRST_REQ_EN (1 << 0)
- * CPU1_SRST_REQ_EN (1 << 1)
- * ...
- */
-#define CPU0_HPM_SRST_REQ_EN (1 << 22)
-#define CPU0_DBG_SRST_REQ_EN (1 << 12)
-#define CPU0_NEON_SRST_REQ_EN (1 << 4)
-#define CPU0_SRST_REQ_EN (1 << 0)
-
-enum {
- HI3620_CTRL,
- ERROR_CTRL,
-};
-
-static void __iomem *ctrl_base;
-static int id;
-
-static void set_cpu_hi3620(int cpu, bool enable)
-{
- u32 val = 0;
-
- if (enable) {
- /* MTCMOS set */
- if ((cpu == 2) || (cpu == 3))
- writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
- ctrl_base + SCPERPWREN);
- udelay(100);
-
- /* Enable core */
- writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREEN);
-
- /* unreset */
- val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
- | CPU0_SRST_REQ_EN;
- writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
- /* reset */
- val |= CPU0_HPM_SRST_REQ_EN;
- writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
-
- /* ISO disable */
- if ((cpu == 2) || (cpu == 3))
- writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
- ctrl_base + SCISODIS);
- udelay(1);
-
- /* WFI Mask */
- val = readl_relaxed(ctrl_base + SCPERCTRL0);
- val &= ~(CPU0_WFI_MASK_CFG << cpu);
- writel_relaxed(val, ctrl_base + SCPERCTRL0);
-
- /* Unreset */
- val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
- | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
- writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
- } else {
- /* wfi mask */
- val = readl_relaxed(ctrl_base + SCPERCTRL0);
- val |= (CPU0_WFI_MASK_CFG << cpu);
- writel_relaxed(val, ctrl_base + SCPERCTRL0);
-
- /* disable core*/
- writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREDIS);
-
- if ((cpu == 2) || (cpu == 3)) {
- /* iso enable */
- writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
- ctrl_base + SCISOEN);
- udelay(1);
- }
-
- /* reset */
- val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
- | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
- writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
-
- if ((cpu == 2) || (cpu == 3)) {
- /* MTCMOS unset */
- writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
- ctrl_base + SCPERPWRDIS);
- udelay(100);
- }
- }
-}
-
-static int hi3xxx_hotplug_init(void)
-{
- struct device_node *node;
-
- node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
- if (node) {
- ctrl_base = of_iomap(node, 0);
- id = HI3620_CTRL;
- return 0;
- }
- id = ERROR_CTRL;
- return -ENOENT;
-}
-
-void hi3xxx_set_cpu(int cpu, bool enable)
-{
- if (!ctrl_base) {
- if (hi3xxx_hotplug_init() < 0)
- return;
- }
-
- if (id == HI3620_CTRL)
- set_cpu_hi3620(cpu, enable);
-}
-
-static inline void cpu_enter_lowpower(void)
-{
- unsigned int v;
-
- flush_cache_all();
-
- /*
- * Turn off coherency and L1 D-cache
- */
- asm volatile(
- " mrc p15, 0, %0, c1, c0, 1\n"
- " bic %0, %0, #0x40\n"
- " mcr p15, 0, %0, c1, c0, 1\n"
- " mrc p15, 0, %0, c1, c0, 0\n"
- " bic %0, %0, #0x04\n"
- " mcr p15, 0, %0, c1, c0, 0\n"
- : "=&r" (v)
- : "r" (0)
- : "cc");
-}
-
-void hi3xxx_cpu_die(unsigned int cpu)
-{
- cpu_enter_lowpower();
- hi3xxx_set_cpu_jump(cpu, phys_to_virt(0));
- cpu_do_idle();
-
- /* We should have never returned from idle */
- panic("cpu %d unexpectedly exit from shutdown\n", cpu);
-}
-
-int hi3xxx_cpu_kill(unsigned int cpu)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(50);
-
- while (hi3xxx_get_cpu_jump(cpu))
- if (time_after(jiffies, timeout))
- return 0;
- hi3xxx_set_cpu(cpu, false);
- return 1;
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Linaro Ltd.
- * Copyright (c) 2013 Hisilicon Limited.
- * Based on arch/arm/mach-vexpress/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;
-
-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(cpu, true);
- 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,
-#ifdef CONFIG_HOTPLUG_CPU
- .cpu_die = hi3xxx_cpu_die,
- .cpu_kill = hi3xxx_cpu_kill,
-#endif
-};
--- /dev/null
+config ARCH_HI3xxx
+ bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7
+ select ARM_AMBA
+ select ARM_GIC
+ select ARM_TIMER_SP804
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select CACHE_L2X0
+ select CLKSRC_OF
+ select GENERIC_CLOCKEVENTS
+ select HAVE_ARM_SCU
+ select HAVE_ARM_TWD
+ select HAVE_SMP
+ select PINCTRL
+ select PINCTRL_SINGLE
+ select SMP
+ help
+ Support for Hisilicon Hi36xx/Hi37xx processor family
--- /dev/null
+#
+# Makefile for Hisilicon processors family
+#
+
+obj-y += hisilicon.o
+obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
--- /dev/null
+#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;
+
+extern void hi3xxx_cpu_die(unsigned int cpu);
+extern int hi3xxx_cpu_kill(unsigned int cpu);
+extern void hi3xxx_set_cpu(int cpu, bool enable);
+
+#endif
--- /dev/null
+/*
+ * (Hisilicon's SoC based) flattened device tree enabled machine
+ *
+ * Copyright (c) 2012-2013 Hisilicon Ltd.
+ * Copyright (c) 2012-2013 Linaro Ltd.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#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"
+
+#define HI3620_SYSCTRL_PHYS_BASE 0xfc802000
+#define HI3620_SYSCTRL_VIRT_BASE 0xfe802000
+
+/*
+ * This table is only for optimization. Since ioremap() could always share
+ * the same mapping if it's defined as static IO mapping.
+ *
+ * Without this table, system could also work. The cost is some virtual address
+ * spaces wasted since ioremap() may be called multi times for the same
+ * IO space.
+ */
+static struct map_desc hi3620_io_desc[] __initdata = {
+ {
+ /* sysctrl */
+ .pfn = __phys_to_pfn(HI3620_SYSCTRL_PHYS_BASE),
+ .virtual = HI3620_SYSCTRL_VIRT_BASE,
+ .length = 0x1000,
+ .type = MT_DEVICE,
+ },
+};
+
+static void __init hi3620_map_io(void)
+{
+ debug_ll_io_init();
+ iotable_init(hi3620_io_desc, ARRAY_SIZE(hi3620_io_desc));
+}
+
+static void __init hi3xxx_timer_init(void)
+{
+ of_clk_init(NULL);
+ 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[] __initconst = {
+ "hisilicon,hi3620-hi4511",
+ NULL,
+};
+
+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
--- /dev/null
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * 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/cpu.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include "core.h"
+
+/* Sysctrl registers in Hi3620 SoC */
+#define SCISOEN 0xc0
+#define SCISODIS 0xc4
+#define SCPERPWREN 0xd0
+#define SCPERPWRDIS 0xd4
+#define SCCPUCOREEN 0xf4
+#define SCCPUCOREDIS 0xf8
+#define SCPERCTRL0 0x200
+#define SCCPURSTEN 0x410
+#define SCCPURSTDIS 0x414
+
+/*
+ * bit definition in SCISOEN/SCPERPWREN/...
+ *
+ * CPU2_ISO_CTRL (1 << 5)
+ * CPU3_ISO_CTRL (1 << 6)
+ * ...
+ */
+#define CPU2_ISO_CTRL (1 << 5)
+
+/*
+ * bit definition in SCPERCTRL0
+ *
+ * CPU0_WFI_MASK_CFG (1 << 28)
+ * CPU1_WFI_MASK_CFG (1 << 29)
+ * ...
+ */
+#define CPU0_WFI_MASK_CFG (1 << 28)
+
+/*
+ * bit definition in SCCPURSTEN/...
+ *
+ * CPU0_SRST_REQ_EN (1 << 0)
+ * CPU1_SRST_REQ_EN (1 << 1)
+ * ...
+ */
+#define CPU0_HPM_SRST_REQ_EN (1 << 22)
+#define CPU0_DBG_SRST_REQ_EN (1 << 12)
+#define CPU0_NEON_SRST_REQ_EN (1 << 4)
+#define CPU0_SRST_REQ_EN (1 << 0)
+
+enum {
+ HI3620_CTRL,
+ ERROR_CTRL,
+};
+
+static void __iomem *ctrl_base;
+static int id;
+
+static void set_cpu_hi3620(int cpu, bool enable)
+{
+ u32 val = 0;
+
+ if (enable) {
+ /* MTCMOS set */
+ if ((cpu == 2) || (cpu == 3))
+ writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
+ ctrl_base + SCPERPWREN);
+ udelay(100);
+
+ /* Enable core */
+ writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREEN);
+
+ /* unreset */
+ val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
+ | CPU0_SRST_REQ_EN;
+ writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
+ /* reset */
+ val |= CPU0_HPM_SRST_REQ_EN;
+ writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
+
+ /* ISO disable */
+ if ((cpu == 2) || (cpu == 3))
+ writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
+ ctrl_base + SCISODIS);
+ udelay(1);
+
+ /* WFI Mask */
+ val = readl_relaxed(ctrl_base + SCPERCTRL0);
+ val &= ~(CPU0_WFI_MASK_CFG << cpu);
+ writel_relaxed(val, ctrl_base + SCPERCTRL0);
+
+ /* Unreset */
+ val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
+ | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
+ writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
+ } else {
+ /* wfi mask */
+ val = readl_relaxed(ctrl_base + SCPERCTRL0);
+ val |= (CPU0_WFI_MASK_CFG << cpu);
+ writel_relaxed(val, ctrl_base + SCPERCTRL0);
+
+ /* disable core*/
+ writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREDIS);
+
+ if ((cpu == 2) || (cpu == 3)) {
+ /* iso enable */
+ writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
+ ctrl_base + SCISOEN);
+ udelay(1);
+ }
+
+ /* reset */
+ val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
+ | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
+ writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
+
+ if ((cpu == 2) || (cpu == 3)) {
+ /* MTCMOS unset */
+ writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
+ ctrl_base + SCPERPWRDIS);
+ udelay(100);
+ }
+ }
+}
+
+static int hi3xxx_hotplug_init(void)
+{
+ struct device_node *node;
+
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+ if (node) {
+ ctrl_base = of_iomap(node, 0);
+ id = HI3620_CTRL;
+ return 0;
+ }
+ id = ERROR_CTRL;
+ return -ENOENT;
+}
+
+void hi3xxx_set_cpu(int cpu, bool enable)
+{
+ if (!ctrl_base) {
+ if (hi3xxx_hotplug_init() < 0)
+ return;
+ }
+
+ if (id == HI3620_CTRL)
+ set_cpu_hi3620(cpu, enable);
+}
+
+static inline void cpu_enter_lowpower(void)
+{
+ unsigned int v;
+
+ flush_cache_all();
+
+ /*
+ * Turn off coherency and L1 D-cache
+ */
+ asm volatile(
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, #0x40\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ " mrc p15, 0, %0, c1, c0, 0\n"
+ " bic %0, %0, #0x04\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ : "=&r" (v)
+ : "r" (0)
+ : "cc");
+}
+
+void hi3xxx_cpu_die(unsigned int cpu)
+{
+ cpu_enter_lowpower();
+ hi3xxx_set_cpu_jump(cpu, phys_to_virt(0));
+ cpu_do_idle();
+
+ /* We should have never returned from idle */
+ panic("cpu %d unexpectedly exit from shutdown\n", cpu);
+}
+
+int hi3xxx_cpu_kill(unsigned int cpu)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(50);
+
+ while (hi3xxx_get_cpu_jump(cpu))
+ if (time_after(jiffies, timeout))
+ return 0;
+ hi3xxx_set_cpu(cpu, false);
+ return 1;
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ * Based on arch/arm/mach-vexpress/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;
+
+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(cpu, true);
+ 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,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = hi3xxx_cpu_die,
+ .cpu_kill = hi3xxx_cpu_kill,
+#endif
+};