aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt11
-rw-r--r--arch/arm/mach-hisi/Kconfig13
-rw-r--r--arch/arm/mach-hisi/Makefile2
-rw-r--r--arch/arm/mach-hisi/core.h5
-rw-r--r--arch/arm/mach-hisi/headsmp.S16
-rw-r--r--arch/arm/mach-hisi/hisilicon.c12
-rw-r--r--arch/arm/mach-hisi/hotplug.c58
-rw-r--r--arch/arm/mach-hisi/platsmp.c50
8 files changed, 161 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index df0a452b8526..934f00025cc4 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -31,6 +31,17 @@ Example:
31 reboot-offset = <0x4>; 31 reboot-offset = <0x4>;
32 }; 32 };
33 33
34-----------------------------------------------------------------------
35Hisilicon CPU controller
36
37Required properties:
38- compatible : "hisilicon,cpuctrl"
39- reg : Register address and size
40
41The clock registers and power registers of secondary cores are defined
42in CPU controller, especially in HIX5HD2 SoC.
43
44-----------------------------------------------------------------------
34PCTRL: Peripheral misc control register 45PCTRL: Peripheral misc control register
35 46
36Required Properties: 47Required Properties:
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
index da16efd3c927..90fdbb4ae00a 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -10,15 +10,24 @@ if ARCH_HISI
10menu "Hisilicon platform type" 10menu "Hisilicon platform type"
11 11
12config ARCH_HI3xxx 12config ARCH_HI3xxx
13 bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7 13 bool "Hisilicon Hi36xx family" if ARCH_MULTI_V7
14 select CACHE_L2X0 14 select CACHE_L2X0
15 select HAVE_ARM_SCU if SMP 15 select HAVE_ARM_SCU if SMP
16 select HAVE_ARM_TWD if SMP 16 select HAVE_ARM_TWD if SMP
17 select PINCTRL 17 select PINCTRL
18 select PINCTRL_SINGLE 18 select PINCTRL_SINGLE
19 help 19 help
20 Support for Hisilicon Hi36xx/Hi37xx processor family 20 Support for Hisilicon Hi36xx SoC family
21 21
22config ARCH_HIX5HD2
23 bool "Hisilicon X5HD2 family" if ARCH_MULTI_V7
24 select CACHE_L2X0
25 select HAVE_ARM_SCU if SMP
26 select HAVE_ARM_TWD if SMP
27 select PINCTRL
28 select PINCTRL_SINGLE
29 help
30 Support for Hisilicon HIX5HD2 SoC family
22endmenu 31endmenu
23 32
24endif 33endif
diff --git a/arch/arm/mach-hisi/Makefile b/arch/arm/mach-hisi/Makefile
index 2ae1b59267c2..ee2506b9cde3 100644
--- a/arch/arm/mach-hisi/Makefile
+++ b/arch/arm/mach-hisi/Makefile
@@ -3,4 +3,4 @@
3# 3#
4 4
5obj-y += hisilicon.o 5obj-y += hisilicon.o
6obj-$(CONFIG_SMP) += platsmp.o hotplug.o 6obj-$(CONFIG_SMP) += platsmp.o hotplug.o headsmp.o
diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h
index af23ec204538..88b1f487d065 100644
--- a/arch/arm/mach-hisi/core.h
+++ b/arch/arm/mach-hisi/core.h
@@ -12,4 +12,9 @@ extern void hi3xxx_cpu_die(unsigned int cpu);
12extern int hi3xxx_cpu_kill(unsigned int cpu); 12extern int hi3xxx_cpu_kill(unsigned int cpu);
13extern void hi3xxx_set_cpu(int cpu, bool enable); 13extern void hi3xxx_set_cpu(int cpu, bool enable);
14 14
15extern void hix5hd2_secondary_startup(void);
16extern struct smp_operations hix5hd2_smp_ops;
17extern void hix5hd2_set_cpu(int cpu, bool enable);
18extern void hix5hd2_cpu_die(unsigned int cpu);
19
15#endif 20#endif
diff --git a/arch/arm/mach-hisi/headsmp.S b/arch/arm/mach-hisi/headsmp.S
new file mode 100644
index 000000000000..278889c00b77
--- /dev/null
+++ b/arch/arm/mach-hisi/headsmp.S
@@ -0,0 +1,16 @@
1/*
2 * Copyright (c) 2014 Hisilicon Limited.
3 * Copyright (c) 2014 Linaro Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#include <linux/linkage.h>
10#include <linux/init.h>
11
12 __CPUINIT
13
14ENTRY(hix5hd2_secondary_startup)
15 bl v7_invalidate_l1
16 b secondary_startup
diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c
index 741faf3e7100..2bfbe3f1392d 100644
--- a/arch/arm/mach-hisi/hisilicon.c
+++ b/arch/arm/mach-hisi/hisilicon.c
@@ -88,3 +88,15 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)")
88 .smp = smp_ops(hi3xxx_smp_ops), 88 .smp = smp_ops(hi3xxx_smp_ops),
89 .restart = hi3xxx_restart, 89 .restart = hi3xxx_restart,
90MACHINE_END 90MACHINE_END
91
92static const char *hix5hd2_compat[] __initconst = {
93 "hisilicon,hix5hd2",
94 NULL,
95};
96
97DT_MACHINE_START(HIX5HD2_DT, "Hisilicon HIX5HD2 (Flattened Device Tree)")
98 .dt_compat = hix5hd2_compat,
99 .init_late = hi3xxx_init_late,
100 .smp = smp_ops(hix5hd2_smp_ops),
101 .restart = hi3xxx_restart,
102MACHINE_END
diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c
index abd441b0c604..84e6919f68c7 100644
--- a/arch/arm/mach-hisi/hotplug.c
+++ b/arch/arm/mach-hisi/hotplug.c
@@ -57,6 +57,14 @@
57#define CPU0_NEON_SRST_REQ_EN (1 << 4) 57#define CPU0_NEON_SRST_REQ_EN (1 << 4)
58#define CPU0_SRST_REQ_EN (1 << 0) 58#define CPU0_SRST_REQ_EN (1 << 0)
59 59
60#define HIX5HD2_PERI_CRG20 0x50
61#define CRG20_CPU1_RESET (1 << 17)
62
63#define HIX5HD2_PERI_PMC0 0x1000
64#define PMC0_CPU1_WAIT_MTCOMS_ACK (1 << 8)
65#define PMC0_CPU1_PMC_ENABLE (1 << 7)
66#define PMC0_CPU1_POWERDOWN (1 << 3)
67
60enum { 68enum {
61 HI3620_CTRL, 69 HI3620_CTRL,
62 ERROR_CTRL, 70 ERROR_CTRL,
@@ -157,6 +165,50 @@ void hi3xxx_set_cpu(int cpu, bool enable)
157 set_cpu_hi3620(cpu, enable); 165 set_cpu_hi3620(cpu, enable);
158} 166}
159 167
168static bool hix5hd2_hotplug_init(void)
169{
170 struct device_node *np;
171
172 np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl");
173 if (np) {
174 ctrl_base = of_iomap(np, 0);
175 return true;
176 }
177 return false;
178}
179
180void hix5hd2_set_cpu(int cpu, bool enable)
181{
182 u32 val = 0;
183
184 if (!ctrl_base)
185 if (!hix5hd2_hotplug_init())
186 BUG();
187
188 if (enable) {
189 /* power on cpu1 */
190 val = readl_relaxed(ctrl_base + HIX5HD2_PERI_PMC0);
191 val &= ~(PMC0_CPU1_WAIT_MTCOMS_ACK | PMC0_CPU1_POWERDOWN);
192 val |= PMC0_CPU1_PMC_ENABLE;
193 writel_relaxed(val, ctrl_base + HIX5HD2_PERI_PMC0);
194 /* unreset */
195 val = readl_relaxed(ctrl_base + HIX5HD2_PERI_CRG20);
196 val &= ~CRG20_CPU1_RESET;
197 writel_relaxed(val, ctrl_base + HIX5HD2_PERI_CRG20);
198 } else {
199 /* power down cpu1 */
200 val = readl_relaxed(ctrl_base + HIX5HD2_PERI_PMC0);
201 val |= PMC0_CPU1_PMC_ENABLE | PMC0_CPU1_POWERDOWN;
202 val &= ~PMC0_CPU1_WAIT_MTCOMS_ACK;
203 writel_relaxed(val, ctrl_base + HIX5HD2_PERI_PMC0);
204
205 /* reset */
206 val = readl_relaxed(ctrl_base + HIX5HD2_PERI_CRG20);
207 val |= CRG20_CPU1_RESET;
208 writel_relaxed(val, ctrl_base + HIX5HD2_PERI_CRG20);
209 }
210}
211
160static inline void cpu_enter_lowpower(void) 212static inline void cpu_enter_lowpower(void)
161{ 213{
162 unsigned int v; 214 unsigned int v;
@@ -199,4 +251,10 @@ int hi3xxx_cpu_kill(unsigned int cpu)
199 hi3xxx_set_cpu(cpu, false); 251 hi3xxx_set_cpu(cpu, false);
200 return 1; 252 return 1;
201} 253}
254
255void hix5hd2_cpu_die(unsigned int cpu)
256{
257 flush_cache_all();
258 hix5hd2_set_cpu(cpu, false);
259}
202#endif 260#endif
diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c
index 471f1ee3be2b..ecf7058d5c15 100644
--- a/arch/arm/mach-hisi/platsmp.c
+++ b/arch/arm/mach-hisi/platsmp.c
@@ -17,6 +17,8 @@
17 17
18#include "core.h" 18#include "core.h"
19 19
20#define HIX5HD2_BOOT_ADDRESS 0xffff0000
21
20static void __iomem *ctrl_base; 22static void __iomem *ctrl_base;
21 23
22void hi3xxx_set_cpu_jump(int cpu, void *jump_addr) 24void hi3xxx_set_cpu_jump(int cpu, void *jump_addr)
@@ -35,11 +37,9 @@ int hi3xxx_get_cpu_jump(int cpu)
35 return readl_relaxed(ctrl_base + ((cpu - 1) << 2)); 37 return readl_relaxed(ctrl_base + ((cpu - 1) << 2));
36} 38}
37 39
38static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus) 40static void __init hisi_enable_scu_a9(void)
39{ 41{
40 struct device_node *np = NULL;
41 unsigned long base = 0; 42 unsigned long base = 0;
42 u32 offset = 0;
43 void __iomem *scu_base = NULL; 43 void __iomem *scu_base = NULL;
44 44
45 if (scu_a9_has_base()) { 45 if (scu_a9_has_base()) {
@@ -52,6 +52,14 @@ static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus)
52 scu_enable(scu_base); 52 scu_enable(scu_base);
53 iounmap(scu_base); 53 iounmap(scu_base);
54 } 54 }
55}
56
57static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus)
58{
59 struct device_node *np = NULL;
60 u32 offset = 0;
61
62 hisi_enable_scu_a9();
55 if (!ctrl_base) { 63 if (!ctrl_base) {
56 np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); 64 np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
57 if (!np) { 65 if (!np) {
@@ -87,3 +95,39 @@ struct smp_operations hi3xxx_smp_ops __initdata = {
87 .cpu_kill = hi3xxx_cpu_kill, 95 .cpu_kill = hi3xxx_cpu_kill,
88#endif 96#endif
89}; 97};
98
99static void __init hix5hd2_smp_prepare_cpus(unsigned int max_cpus)
100{
101 hisi_enable_scu_a9();
102}
103
104void hix5hd2_set_scu_boot_addr(phys_addr_t start_addr, phys_addr_t jump_addr)
105{
106 void __iomem *virt;
107
108 virt = ioremap(start_addr, PAGE_SIZE);
109
110 writel_relaxed(0xe51ff004, virt); /* ldr pc, [rc, #-4] */
111 writel_relaxed(jump_addr, virt + 4); /* pc jump phy address */
112 iounmap(virt);
113}
114
115static int hix5hd2_boot_secondary(unsigned int cpu, struct task_struct *idle)
116{
117 phys_addr_t jumpaddr;
118
119 jumpaddr = virt_to_phys(hix5hd2_secondary_startup);
120 hix5hd2_set_scu_boot_addr(HIX5HD2_BOOT_ADDRESS, jumpaddr);
121 hix5hd2_set_cpu(cpu, true);
122 arch_send_wakeup_ipi_mask(cpumask_of(cpu));
123 return 0;
124}
125
126
127struct smp_operations hix5hd2_smp_ops __initdata = {
128 .smp_prepare_cpus = hix5hd2_smp_prepare_cpus,
129 .smp_boot_secondary = hix5hd2_boot_secondary,
130#ifdef CONFIG_HOTPLUG_CPU
131 .cpu_die = hix5hd2_cpu_die,
132#endif
133};