ARM: hi3xxx: add smp support
Enable SMP support on hi3xxx platform Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org> Tested-by: Zhang Mingjun <zhang.mingjun@linaro.org> Tested-by: Li Xin <li.xin@linaro.org> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> [khilman: fix checkpatch errors] Signed-off-by: Kevin Hilman <khilman@linaro.org>
This commit is contained in:
parent
524b7df9fd
commit
a9434e96d9
|
@ -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 @@
|
||||||
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 @@
|
||||||
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 @@
|
||||||
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
|
||||||
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 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-y += hi3xxx.o
|
obj-y += hi3xxx.o
|
||||||
|
obj-$(CONFIG_SMP) += platsmp.o
|
||||||
|
|
|
@ -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
|
|
@ -1,4 +1,4 @@
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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)")
|
||||||
.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
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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,
|
||||||
|
};
|
Loading…
Reference in New Issue