diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt | 11 | ||||
-rw-r--r-- | arch/arm/mach-hisi/Kconfig | 13 | ||||
-rw-r--r-- | arch/arm/mach-hisi/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-hisi/core.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-hisi/headsmp.S | 16 | ||||
-rw-r--r-- | arch/arm/mach-hisi/hisilicon.c | 12 | ||||
-rw-r--r-- | arch/arm/mach-hisi/hotplug.c | 58 | ||||
-rw-r--r-- | arch/arm/mach-hisi/platsmp.c | 50 |
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 | ----------------------------------------------------------------------- | ||
35 | Hisilicon CPU controller | ||
36 | |||
37 | Required properties: | ||
38 | - compatible : "hisilicon,cpuctrl" | ||
39 | - reg : Register address and size | ||
40 | |||
41 | The clock registers and power registers of secondary cores are defined | ||
42 | in CPU controller, especially in HIX5HD2 SoC. | ||
43 | |||
44 | ----------------------------------------------------------------------- | ||
34 | PCTRL: Peripheral misc control register | 45 | PCTRL: Peripheral misc control register |
35 | 46 | ||
36 | Required Properties: | 47 | Required 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 | |||
10 | menu "Hisilicon platform type" | 10 | menu "Hisilicon platform type" |
11 | 11 | ||
12 | config ARCH_HI3xxx | 12 | config 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 | ||
22 | config 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 | ||
22 | endmenu | 31 | endmenu |
23 | 32 | ||
24 | endif | 33 | endif |
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 | ||
5 | obj-y += hisilicon.o | 5 | obj-y += hisilicon.o |
6 | obj-$(CONFIG_SMP) += platsmp.o hotplug.o | 6 | obj-$(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); | |||
12 | extern int hi3xxx_cpu_kill(unsigned int cpu); | 12 | extern int hi3xxx_cpu_kill(unsigned int cpu); |
13 | extern void hi3xxx_set_cpu(int cpu, bool enable); | 13 | extern void hi3xxx_set_cpu(int cpu, bool enable); |
14 | 14 | ||
15 | extern void hix5hd2_secondary_startup(void); | ||
16 | extern struct smp_operations hix5hd2_smp_ops; | ||
17 | extern void hix5hd2_set_cpu(int cpu, bool enable); | ||
18 | extern 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 | |||
14 | ENTRY(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, |
90 | MACHINE_END | 90 | MACHINE_END |
91 | |||
92 | static const char *hix5hd2_compat[] __initconst = { | ||
93 | "hisilicon,hix5hd2", | ||
94 | NULL, | ||
95 | }; | ||
96 | |||
97 | DT_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, | ||
102 | MACHINE_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 | |||
60 | enum { | 68 | enum { |
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 | ||
168 | static 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 | |||
180 | void 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 | |||
160 | static inline void cpu_enter_lowpower(void) | 212 | static 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 | |||
255 | void 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 | |||
20 | static void __iomem *ctrl_base; | 22 | static void __iomem *ctrl_base; |
21 | 23 | ||
22 | void hi3xxx_set_cpu_jump(int cpu, void *jump_addr) | 24 | void 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 | ||
38 | static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus) | 40 | static 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 | |||
57 | static 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 | |||
99 | static void __init hix5hd2_smp_prepare_cpus(unsigned int max_cpus) | ||
100 | { | ||
101 | hisi_enable_scu_a9(); | ||
102 | } | ||
103 | |||
104 | void 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 | |||
115 | static 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 | |||
127 | struct 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 | }; | ||