Skip to content

Commit

Permalink
ARM: hi3xxx: add smp support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kevin Hilman committed Dec 18, 2013
1 parent 524b7df commit a9434e9
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 3 deletions.
26 changes: 26 additions & 0 deletions Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
};
38 changes: 38 additions & 0 deletions arch/arm/boot/dts/hi3620.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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>;
Expand Down Expand Up @@ -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>;
Expand Down
4 changes: 4 additions & 0 deletions arch/arm/mach-hi3xxx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions arch/arm/mach-hi3xxx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
#

obj-y += hi3xxx.o
obj-$(CONFIG_SMP) += platsmp.o
11 changes: 11 additions & 0 deletions arch/arm/mach-hi3xxx/core.h
Original file line number Diff line number Diff line change
@@ -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
43 changes: 40 additions & 3 deletions arch/arm/mach-hi3xxx/hi3xxx.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
5/*
/*
* (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine
*
* Copyright (c) 2012-2013 Hisilicon Ltd.
Expand All @@ -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.
Expand All @@ -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,
},
Expand All @@ -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,
Expand All @@ -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
84 changes: 84 additions & 0 deletions arch/arm/mach-hi3xxx/platsmp.c
Original file line number Diff line number Diff line change
@@ -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,
};

0 comments on commit a9434e9

Please sign in to comment.