Commit a9434e96 authored by Kevin Hilman's avatar Kevin Hilman

ARM: hi3xxx: add smp support

Enable SMP support on hi3xxx platform
Signed-off-by: default avatarZhangfei Gao <zhangfei.gao@linaro.org>
Tested-by: default avatarZhang Mingjun <zhang.mingjun@linaro.org>
Tested-by: default avatarLi Xin <li.xin@linaro.org>
Signed-off-by: default avatarHaojian Zhuang <haojian.zhuang@linaro.org>
[khilman: fix checkpatch errors]
Signed-off-by: default avatarKevin Hilman <khilman@linaro.org>
parent 524b7df9
...@@ -4,3 +4,29 @@ Hisilicon Platforms Device Tree Bindings ...@@ -4,3 +4,29 @@ Hisilicon Platforms Device Tree Bindings
Hi4511 Board Hi4511 Board
Required root node properties: Required root node properties:
- compatible = "hisilicon,hi3620-hi4511"; - 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>;
};
...@@ -39,6 +39,27 @@ cpu@0 { ...@@ -39,6 +39,27 @@ cpu@0 {
reg = <0x0>; reg = <0x0>;
next-level-cache = <&L2>; 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 { amba {
...@@ -65,6 +86,17 @@ gic: interrupt-controller@1000 { ...@@ -65,6 +86,17 @@ gic: interrupt-controller@1000 {
reg = <0x1000 0x1000>, <0x100 0x100>; 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 { dual_timer0: dual_timer@800000 {
compatible = "arm,sp804", "arm,primecell"; compatible = "arm,sp804", "arm,primecell";
reg = <0x800000 0x1000>; reg = <0x800000 0x1000>;
...@@ -115,6 +147,12 @@ dual_timer4: dual_timer@a03000 { ...@@ -115,6 +147,12 @@ dual_timer4: dual_timer@a03000 {
status = "disabled"; status = "disabled";
}; };
timer5: timer@600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0x600 0x20>;
interrupts = <1 13 0xf01>;
};
uart0: uart@b00000 { uart0: uart@b00000 {
compatible = "arm,pl011", "arm,primecell"; compatible = "arm,pl011", "arm,primecell";
reg = <0xb00000 0x1000>; reg = <0xb00000 0x1000>;
......
...@@ -7,7 +7,11 @@ config ARCH_HI3xxx ...@@ -7,7 +7,11 @@ config ARCH_HI3xxx
select CACHE_L2X0 select CACHE_L2X0
select CLKSRC_OF select CLKSRC_OF
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU
select HAVE_ARM_TWD
select HAVE_SMP
select PINCTRL select PINCTRL
select PINCTRL_SINGLE select PINCTRL_SINGLE
select SMP
help help
Support for Hisilicon Hi36xx/Hi37xx processor family Support for Hisilicon Hi36xx/Hi37xx processor family
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
# #
obj-y += hi3xxx.o obj-y += hi3xxx.o
obj-$(CONFIG_SMP) += platsmp.o
#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
5/* /*
* (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine * (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine
* *
* Copyright (c) 2012-2013 Hisilicon Ltd. * Copyright (c) 2012-2013 Hisilicon Ltd.
...@@ -14,11 +14,19 @@ ...@@ -14,11 +14,19 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <asm/proc-fns.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.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 * This table is only for optimization. Since ioremap() could always share
* the same mapping if it's defined as static IO mapping. * the same mapping if it's defined as static IO mapping.
...@@ -29,8 +37,9 @@ ...@@ -29,8 +37,9 @@
*/ */
static struct map_desc hi3620_io_desc[] __initdata = { static struct map_desc hi3620_io_desc[] __initdata = {
{ {
.pfn = __phys_to_pfn(0xfc802000), /* sysctrl */
.virtual = 0xfe802000, .pfn = __phys_to_pfn(HI3620_SYSCTRL_PHYS_BASE),
.virtual = HI3620_SYSCTRL_VIRT_BASE,
.length = 0x1000, .length = 0x1000,
.type = MT_DEVICE, .type = MT_DEVICE,
}, },
...@@ -48,6 +57,32 @@ static void __init hi3xxx_timer_init(void) ...@@ -48,6 +57,32 @@ static void __init hi3xxx_timer_init(void)
clocksource_of_init(); 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 = { static const char *hi3xxx_compat[] __initconst = {
"hisilicon,hi3620-hi4511", "hisilicon,hi3620-hi4511",
NULL, NULL,
...@@ -57,4 +92,6 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)") ...@@ -57,4 +92,6 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)")
.map_io = hi3620_map_io, .map_io = hi3620_map_io,
.init_time = hi3xxx_timer_init, .init_time = hi3xxx_timer_init,
.dt_compat = hi3xxx_compat, .dt_compat = hi3xxx_compat,
.smp = smp_ops(hi3xxx_smp_ops),
.restart = hi3xxx_restart,
MACHINE_END MACHINE_END
/*
* 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_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,
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment