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
|
||||
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>;
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
uart0: uart@b00000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0xb00000 0x1000>;
|
||||
|
|
|
@ -7,7 +7,11 @@ config ARCH_HI3xxx
|
|||
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
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
#
|
||||
|
||||
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
|
||||
*
|
||||
* Copyright (c) 2012-2013 Hisilicon Ltd.
|
||||
|
@ -14,11 +14,19 @@
|
|||
#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.
|
||||
|
@ -29,8 +37,9 @@
|
|||
*/
|
||||
static struct map_desc hi3620_io_desc[] __initdata = {
|
||||
{
|
||||
.pfn = __phys_to_pfn(0xfc802000),
|
||||
.virtual = 0xfe802000,
|
||||
/* sysctrl */
|
||||
.pfn = __phys_to_pfn(HI3620_SYSCTRL_PHYS_BASE),
|
||||
.virtual = HI3620_SYSCTRL_VIRT_BASE,
|
||||
.length = 0x1000,
|
||||
.type = MT_DEVICE,
|
||||
},
|
||||
|
@ -48,6 +57,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[] __initconst = {
|
||||
"hisilicon,hi3620-hi4511",
|
||||
NULL,
|
||||
|
@ -57,4 +92,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
|
||||
|
|
|
@ -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