diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt | 26 | ||||
-rw-r--r-- | arch/arm/boot/dts/hi3620.dtsi | 38 | ||||
-rw-r--r-- | arch/arm/mach-hi3xxx/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-hi3xxx/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-hi3xxx/core.h | 11 | ||||
-rw-r--r-- | arch/arm/mach-hi3xxx/hi3xxx.c | 43 | ||||
-rw-r--r-- | arch/arm/mach-hi3xxx/platsmp.c | 84 |
7 files changed, 204 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt index 21a73363e019..8c7a4653508d 100644 --- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt | |||
@@ -4,3 +4,29 @@ Hisilicon Platforms Device Tree Bindings | |||
4 | Hi4511 Board | 4 | Hi4511 Board |
5 | Required root node properties: | 5 | Required root node properties: |
6 | - compatible = "hisilicon,hi3620-hi4511"; | 6 | - compatible = "hisilicon,hi3620-hi4511"; |
7 | |||
8 | Hisilicon system controller | ||
9 | |||
10 | Required properties: | ||
11 | - compatible : "hisilicon,sysctrl" | ||
12 | - reg : Register address and size | ||
13 | |||
14 | Optional properties: | ||
15 | - smp-offset : offset in sysctrl for notifying slave cpu booting | ||
16 | cpu 1, reg; | ||
17 | cpu 2, reg + 0x4; | ||
18 | cpu 3, reg + 0x8; | ||
19 | If reg value is not zero, cpun exit wfi and go | ||
20 | - resume-offset : offset in sysctrl for notifying cpu0 when resume | ||
21 | - reboot-offset : offset in sysctrl for system reboot | ||
22 | |||
23 | Example: | ||
24 | |||
25 | /* for Hi3620 */ | ||
26 | sysctrl: system-controller@fc802000 { | ||
27 | compatible = "hisilicon,sysctrl"; | ||
28 | reg = <0xfc802000 0x1000>; | ||
29 | smp-offset = <0x31c>; | ||
30 | resume-offset = <0x308>; | ||
31 | reboot-offset = <0x4>; | ||
32 | }; | ||
diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi index b9d86795ed5a..e311937a1e2c 100644 --- a/arch/arm/boot/dts/hi3620.dtsi +++ b/arch/arm/boot/dts/hi3620.dtsi | |||
@@ -39,6 +39,27 @@ | |||
39 | reg = <0x0>; | 39 | reg = <0x0>; |
40 | next-level-cache = <&L2>; | 40 | next-level-cache = <&L2>; |
41 | }; | 41 | }; |
42 | |||
43 | cpu@1 { | ||
44 | compatible = "arm,cortex-a9"; | ||
45 | device_type = "cpu"; | ||
46 | reg = <1>; | ||
47 | next-level-cache = <&L2>; | ||
48 | }; | ||
49 | |||
50 | cpu@2 { | ||
51 | compatible = "arm,cortex-a9"; | ||
52 | device_type = "cpu"; | ||
53 | reg = <2>; | ||
54 | next-level-cache = <&L2>; | ||
55 | }; | ||
56 | |||
57 | cpu@3 { | ||
58 | compatible = "arm,cortex-a9"; | ||
59 | device_type = "cpu"; | ||
60 | reg = <3>; | ||
61 | next-level-cache = <&L2>; | ||
62 | }; | ||
42 | }; | 63 | }; |
43 | 64 | ||
44 | amba { | 65 | amba { |
@@ -65,6 +86,17 @@ | |||
65 | reg = <0x1000 0x1000>, <0x100 0x100>; | 86 | reg = <0x1000 0x1000>, <0x100 0x100>; |
66 | }; | 87 | }; |
67 | 88 | ||
89 | sysctrl: system-controller@802000 { | ||
90 | compatible = "hisilicon,sysctrl"; | ||
91 | reg = <0x802000 0x1000>; | ||
92 | #address-cells = <1>; | ||
93 | #size-cells = <0>; | ||
94 | |||
95 | smp-offset = <0x31c>; | ||
96 | resume-offset = <0x308>; | ||
97 | reboot-offset = <0x4>; | ||
98 | }; | ||
99 | |||
68 | dual_timer0: dual_timer@800000 { | 100 | dual_timer0: dual_timer@800000 { |
69 | compatible = "arm,sp804", "arm,primecell"; | 101 | compatible = "arm,sp804", "arm,primecell"; |
70 | reg = <0x800000 0x1000>; | 102 | reg = <0x800000 0x1000>; |
@@ -115,6 +147,12 @@ | |||
115 | status = "disabled"; | 147 | status = "disabled"; |
116 | }; | 148 | }; |
117 | 149 | ||
150 | timer5: timer@600 { | ||
151 | compatible = "arm,cortex-a9-twd-timer"; | ||
152 | reg = <0x600 0x20>; | ||
153 | interrupts = <1 13 0xf01>; | ||
154 | }; | ||
155 | |||
118 | uart0: uart@b00000 { | 156 | uart0: uart@b00000 { |
119 | compatible = "arm,pl011", "arm,primecell"; | 157 | compatible = "arm,pl011", "arm,primecell"; |
120 | reg = <0xb00000 0x1000>; | 158 | reg = <0xb00000 0x1000>; |
diff --git a/arch/arm/mach-hi3xxx/Kconfig b/arch/arm/mach-hi3xxx/Kconfig index 8a502d1e9542..018ad67f1b38 100644 --- a/arch/arm/mach-hi3xxx/Kconfig +++ b/arch/arm/mach-hi3xxx/Kconfig | |||
@@ -7,7 +7,11 @@ config ARCH_HI3xxx | |||
7 | select CACHE_L2X0 | 7 | select CACHE_L2X0 |
8 | select CLKSRC_OF | 8 | select CLKSRC_OF |
9 | select GENERIC_CLOCKEVENTS | 9 | select GENERIC_CLOCKEVENTS |
10 | select HAVE_ARM_SCU | ||
11 | select HAVE_ARM_TWD | ||
12 | select HAVE_SMP | ||
10 | select PINCTRL | 13 | select PINCTRL |
11 | select PINCTRL_SINGLE | 14 | select PINCTRL_SINGLE |
15 | select SMP | ||
12 | help | 16 | help |
13 | Support for Hisilicon Hi36xx/Hi37xx processor family | 17 | Support for Hisilicon Hi36xx/Hi37xx processor family |
diff --git a/arch/arm/mach-hi3xxx/Makefile b/arch/arm/mach-hi3xxx/Makefile index d68ebb3d10bb..7a869a7b2a95 100644 --- a/arch/arm/mach-hi3xxx/Makefile +++ b/arch/arm/mach-hi3xxx/Makefile | |||
@@ -3,3 +3,4 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += hi3xxx.o | 5 | obj-y += hi3xxx.o |
6 | obj-$(CONFIG_SMP) += platsmp.o | ||
diff --git a/arch/arm/mach-hi3xxx/core.h b/arch/arm/mach-hi3xxx/core.h new file mode 100644 index 000000000000..226f02050597 --- /dev/null +++ b/arch/arm/mach-hi3xxx/core.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef __HISILICON_CORE_H | ||
2 | #define __HISILICON_CORE_H | ||
3 | |||
4 | #include <linux/reboot.h> | ||
5 | |||
6 | extern void hi3xxx_set_cpu_jump(int cpu, void *jump_addr); | ||
7 | extern int hi3xxx_get_cpu_jump(int cpu); | ||
8 | extern void secondary_startup(void); | ||
9 | extern struct smp_operations hi3xxx_smp_ops; | ||
10 | |||
11 | #endif | ||
diff --git a/arch/arm/mach-hi3xxx/hi3xxx.c b/arch/arm/mach-hi3xxx/hi3xxx.c index fe56daf84b1a..661a912f1527 100644 --- a/arch/arm/mach-hi3xxx/hi3xxx.c +++ b/arch/arm/mach-hi3xxx/hi3xxx.c | |||
@@ -1,4 +1,4 @@ | |||
1 | 5/* | 1 | /* |
2 | * (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine | 2 | * (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine |
3 | * | 3 | * |
4 | * Copyright (c) 2012-2013 Hisilicon Ltd. | 4 | * Copyright (c) 2012-2013 Hisilicon Ltd. |
@@ -14,11 +14,19 @@ | |||
14 | #include <linux/clk-provider.h> | 14 | #include <linux/clk-provider.h> |
15 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
16 | #include <linux/irqchip.h> | 16 | #include <linux/irqchip.h> |
17 | #include <linux/of_address.h> | ||
17 | #include <linux/of_platform.h> | 18 | #include <linux/of_platform.h> |
18 | 19 | ||
20 | #include <asm/proc-fns.h> | ||
21 | |||
19 | #include <asm/mach/arch.h> | 22 | #include <asm/mach/arch.h> |
20 | #include <asm/mach/map.h> | 23 | #include <asm/mach/map.h> |
21 | 24 | ||
25 | #include "core.h" | ||
26 | |||
27 | #define HI3620_SYSCTRL_PHYS_BASE 0xfc802000 | ||
28 | #define HI3620_SYSCTRL_VIRT_BASE 0xfe802000 | ||
29 | |||
22 | /* | 30 | /* |
23 | * This table is only for optimization. Since ioremap() could always share | 31 | * This table is only for optimization. Since ioremap() could always share |
24 | * the same mapping if it's defined as static IO mapping. | 32 | * the same mapping if it's defined as static IO mapping. |
@@ -29,8 +37,9 @@ | |||
29 | */ | 37 | */ |
30 | static struct map_desc hi3620_io_desc[] __initdata = { | 38 | static struct map_desc hi3620_io_desc[] __initdata = { |
31 | { | 39 | { |
32 | .pfn = __phys_to_pfn(0xfc802000), | 40 | /* sysctrl */ |
33 | .virtual = 0xfe802000, | 41 | .pfn = __phys_to_pfn(HI3620_SYSCTRL_PHYS_BASE), |
42 | .virtual = HI3620_SYSCTRL_VIRT_BASE, | ||
34 | .length = 0x1000, | 43 | .length = 0x1000, |
35 | .type = MT_DEVICE, | 44 | .type = MT_DEVICE, |
36 | }, | 45 | }, |
@@ -48,6 +57,32 @@ static void __init hi3xxx_timer_init(void) | |||
48 | clocksource_of_init(); | 57 | clocksource_of_init(); |
49 | } | 58 | } |
50 | 59 | ||
60 | static void hi3xxx_restart(enum reboot_mode mode, const char *cmd) | ||
61 | { | ||
62 | struct device_node *np; | ||
63 | void __iomem *base; | ||
64 | int offset; | ||
65 | |||
66 | np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); | ||
67 | if (!np) { | ||
68 | pr_err("failed to find hisilicon,sysctrl node\n"); | ||
69 | return; | ||
70 | } | ||
71 | base = of_iomap(np, 0); | ||
72 | if (!base) { | ||
73 | pr_err("failed to map address in hisilicon,sysctrl node\n"); | ||
74 | return; | ||
75 | } | ||
76 | if (of_property_read_u32(np, "reboot-offset", &offset) < 0) { | ||
77 | pr_err("failed to find reboot-offset property\n"); | ||
78 | return; | ||
79 | } | ||
80 | writel_relaxed(0xdeadbeef, base + offset); | ||
81 | |||
82 | while (1) | ||
83 | cpu_do_idle(); | ||
84 | } | ||
85 | |||
51 | static const char *hi3xxx_compat[] __initconst = { | 86 | static const char *hi3xxx_compat[] __initconst = { |
52 | "hisilicon,hi3620-hi4511", | 87 | "hisilicon,hi3620-hi4511", |
53 | NULL, | 88 | NULL, |
@@ -57,4 +92,6 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)") | |||
57 | .map_io = hi3620_map_io, | 92 | .map_io = hi3620_map_io, |
58 | .init_time = hi3xxx_timer_init, | 93 | .init_time = hi3xxx_timer_init, |
59 | .dt_compat = hi3xxx_compat, | 94 | .dt_compat = hi3xxx_compat, |
95 | .smp = smp_ops(hi3xxx_smp_ops), | ||
96 | .restart = hi3xxx_restart, | ||
60 | MACHINE_END | 97 | MACHINE_END |
diff --git a/arch/arm/mach-hi3xxx/platsmp.c b/arch/arm/mach-hi3xxx/platsmp.c new file mode 100644 index 000000000000..8ebfbe7c8fae --- /dev/null +++ b/arch/arm/mach-hi3xxx/platsmp.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Linaro Ltd. | ||
3 | * Copyright (c) 2013 Hisilicon Limited. | ||
4 | * Based on arch/arm/mach-vexpress/platsmp.c, Copyright (C) 2002 ARM Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/smp.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/of_address.h> | ||
13 | |||
14 | #include <asm/cacheflush.h> | ||
15 | #include <asm/smp_plat.h> | ||
16 | #include <asm/smp_scu.h> | ||
17 | |||
18 | #include "core.h" | ||
19 | |||
20 | static void __iomem *ctrl_base; | ||
21 | |||
22 | void hi3xxx_set_cpu_jump(int cpu, void *jump_addr) | ||
23 | { | ||
24 | cpu = cpu_logical_map(cpu); | ||
25 | if (!cpu || !ctrl_base) | ||
26 | return; | ||
27 | writel_relaxed(virt_to_phys(jump_addr), ctrl_base + ((cpu - 1) << 2)); | ||
28 | } | ||
29 | |||
30 | int hi3xxx_get_cpu_jump(int cpu) | ||
31 | { | ||
32 | cpu = cpu_logical_map(cpu); | ||
33 | if (!cpu || !ctrl_base) | ||
34 | return 0; | ||
35 | return readl_relaxed(ctrl_base + ((cpu - 1) << 2)); | ||
36 | } | ||
37 | |||
38 | static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus) | ||
39 | { | ||
40 | struct device_node *np = NULL; | ||
41 | unsigned long base = 0; | ||
42 | u32 offset = 0; | ||
43 | void __iomem *scu_base = NULL; | ||
44 | |||
45 | if (scu_a9_has_base()) { | ||
46 | base = scu_a9_get_base(); | ||
47 | scu_base = ioremap(base, SZ_4K); | ||
48 | if (!scu_base) { | ||
49 | pr_err("ioremap(scu_base) failed\n"); | ||
50 | return; | ||
51 | } | ||
52 | scu_enable(scu_base); | ||
53 | iounmap(scu_base); | ||
54 | } | ||
55 | if (!ctrl_base) { | ||
56 | np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); | ||
57 | if (!np) { | ||
58 | pr_err("failed to find hisilicon,sysctrl node\n"); | ||
59 | return; | ||
60 | } | ||
61 | ctrl_base = of_iomap(np, 0); | ||
62 | if (!ctrl_base) { | ||
63 | pr_err("failed to map address\n"); | ||
64 | return; | ||
65 | } | ||
66 | if (of_property_read_u32(np, "smp-offset", &offset) < 0) { | ||
67 | pr_err("failed to find smp-offset property\n"); | ||
68 | return; | ||
69 | } | ||
70 | ctrl_base += offset; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static int hi3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
75 | { | ||
76 | hi3xxx_set_cpu_jump(cpu, secondary_startup); | ||
77 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | struct smp_operations hi3xxx_smp_ops __initdata = { | ||
82 | .smp_prepare_cpus = hi3xxx_smp_prepare_cpus, | ||
83 | .smp_boot_secondary = hi3xxx_boot_secondary, | ||
84 | }; | ||