1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Created by: Nicolas Pitre, October 2012 |
4 | * Copyright: (C) 2012-2013 Linaro Limited |
5 | * |
6 | * Some portions of this file were originally written by Achin Gupta |
7 | * Copyright: (C) 2012 ARM Limited |
8 | */ |
9 | |
10 | #include <linux/delay.h> |
11 | #include <linux/init.h> |
12 | #include <linux/io.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/of_address.h> |
15 | #include <linux/of_irq.h> |
16 | #include <linux/errno.h> |
17 | #include <linux/irqchip/arm-gic.h> |
18 | |
19 | #include <asm/mcpm.h> |
20 | #include <asm/proc-fns.h> |
21 | #include <asm/cacheflush.h> |
22 | #include <asm/cputype.h> |
23 | #include <asm/cp15.h> |
24 | |
25 | #include <linux/arm-cci.h> |
26 | |
27 | #include "spc.h" |
28 | |
29 | /* SCC conf registers */ |
30 | #define RESET_CTRL 0x018 |
31 | #define RESET_A15_NCORERESET(cpu) (1 << (2 + (cpu))) |
32 | #define RESET_A7_NCORERESET(cpu) (1 << (16 + (cpu))) |
33 | |
34 | #define A15_CONF 0x400 |
35 | #define A7_CONF 0x500 |
36 | #define SYS_INFO 0x700 |
37 | #define SPC_BASE 0xb00 |
38 | |
39 | static void __iomem *scc; |
40 | |
41 | #define TC2_CLUSTERS 2 |
42 | #define TC2_MAX_CPUS_PER_CLUSTER 3 |
43 | |
44 | static unsigned int tc2_nr_cpus[TC2_CLUSTERS]; |
45 | |
46 | static int tc2_pm_cpu_powerup(unsigned int cpu, unsigned int cluster) |
47 | { |
48 | pr_debug("%s: cpu %u cluster %u\n" , __func__, cpu, cluster); |
49 | if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) |
50 | return -EINVAL; |
51 | ve_spc_set_resume_addr(cluster, cpu, |
52 | __pa_symbol(mcpm_entry_point)); |
53 | ve_spc_cpu_wakeup_irq(cluster, cpu, set: true); |
54 | return 0; |
55 | } |
56 | |
57 | static int tc2_pm_cluster_powerup(unsigned int cluster) |
58 | { |
59 | pr_debug("%s: cluster %u\n" , __func__, cluster); |
60 | if (cluster >= TC2_CLUSTERS) |
61 | return -EINVAL; |
62 | ve_spc_powerdown(cluster, enable: false); |
63 | return 0; |
64 | } |
65 | |
66 | static void tc2_pm_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) |
67 | { |
68 | pr_debug("%s: cpu %u cluster %u\n" , __func__, cpu, cluster); |
69 | BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); |
70 | ve_spc_cpu_wakeup_irq(cluster, cpu, set: true); |
71 | /* |
72 | * If the CPU is committed to power down, make sure |
73 | * the power controller will be in charge of waking it |
74 | * up upon IRQ, ie IRQ lines are cut from GIC CPU IF |
75 | * to the CPU by disabling the GIC CPU IF to prevent wfi |
76 | * from completing execution behind power controller back |
77 | */ |
78 | gic_cpu_if_down(gic_nr: 0); |
79 | } |
80 | |
81 | static void tc2_pm_cluster_powerdown_prepare(unsigned int cluster) |
82 | { |
83 | pr_debug("%s: cluster %u\n" , __func__, cluster); |
84 | BUG_ON(cluster >= TC2_CLUSTERS); |
85 | ve_spc_powerdown(cluster, enable: true); |
86 | ve_spc_global_wakeup_irq(set: true); |
87 | } |
88 | |
89 | static void tc2_pm_cpu_cache_disable(void) |
90 | { |
91 | v7_exit_coherency_flush(louis); |
92 | } |
93 | |
94 | static void tc2_pm_cluster_cache_disable(void) |
95 | { |
96 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) { |
97 | /* |
98 | * On the Cortex-A15 we need to disable |
99 | * L2 prefetching before flushing the cache. |
100 | */ |
101 | asm volatile( |
102 | "mcr p15, 1, %0, c15, c0, 3 \n\t" |
103 | "isb \n\t" |
104 | "dsb " |
105 | : : "r" (0x400) ); |
106 | } |
107 | |
108 | v7_exit_coherency_flush(all); |
109 | cci_disable_port_by_cpu(mpidr: read_cpuid_mpidr()); |
110 | } |
111 | |
112 | static int tc2_core_in_reset(unsigned int cpu, unsigned int cluster) |
113 | { |
114 | u32 mask = cluster ? |
115 | RESET_A7_NCORERESET(cpu) |
116 | : RESET_A15_NCORERESET(cpu); |
117 | |
118 | return !(readl_relaxed(scc + RESET_CTRL) & mask); |
119 | } |
120 | |
121 | #define POLL_MSEC 10 |
122 | #define TIMEOUT_MSEC 1000 |
123 | |
124 | static int tc2_pm_wait_for_powerdown(unsigned int cpu, unsigned int cluster) |
125 | { |
126 | unsigned tries; |
127 | |
128 | pr_debug("%s: cpu %u cluster %u\n" , __func__, cpu, cluster); |
129 | BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); |
130 | |
131 | for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; ++tries) { |
132 | pr_debug("%s(cpu=%u, cluster=%u): RESET_CTRL = 0x%08X\n" , |
133 | __func__, cpu, cluster, |
134 | readl_relaxed(scc + RESET_CTRL)); |
135 | |
136 | /* |
137 | * We need the CPU to reach WFI, but the power |
138 | * controller may put the cluster in reset and |
139 | * power it off as soon as that happens, before |
140 | * we have a chance to see STANDBYWFI. |
141 | * |
142 | * So we need to check for both conditions: |
143 | */ |
144 | if (tc2_core_in_reset(cpu, cluster) || |
145 | ve_spc_cpu_in_wfi(cpu, cluster)) |
146 | return 0; /* success: the CPU is halted */ |
147 | |
148 | /* Otherwise, wait and retry: */ |
149 | msleep(POLL_MSEC); |
150 | } |
151 | |
152 | return -ETIMEDOUT; /* timeout */ |
153 | } |
154 | |
155 | static void tc2_pm_cpu_suspend_prepare(unsigned int cpu, unsigned int cluster) |
156 | { |
157 | ve_spc_set_resume_addr(cluster, cpu, __pa_symbol(mcpm_entry_point)); |
158 | } |
159 | |
160 | static void tc2_pm_cpu_is_up(unsigned int cpu, unsigned int cluster) |
161 | { |
162 | pr_debug("%s: cpu %u cluster %u\n" , __func__, cpu, cluster); |
163 | BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); |
164 | ve_spc_cpu_wakeup_irq(cluster, cpu, set: false); |
165 | ve_spc_set_resume_addr(cluster, cpu, addr: 0); |
166 | } |
167 | |
168 | static void tc2_pm_cluster_is_up(unsigned int cluster) |
169 | { |
170 | pr_debug("%s: cluster %u\n" , __func__, cluster); |
171 | BUG_ON(cluster >= TC2_CLUSTERS); |
172 | ve_spc_powerdown(cluster, enable: false); |
173 | ve_spc_global_wakeup_irq(set: false); |
174 | } |
175 | |
176 | static const struct mcpm_platform_ops tc2_pm_power_ops = { |
177 | .cpu_powerup = tc2_pm_cpu_powerup, |
178 | .cluster_powerup = tc2_pm_cluster_powerup, |
179 | .cpu_suspend_prepare = tc2_pm_cpu_suspend_prepare, |
180 | .cpu_powerdown_prepare = tc2_pm_cpu_powerdown_prepare, |
181 | .cluster_powerdown_prepare = tc2_pm_cluster_powerdown_prepare, |
182 | .cpu_cache_disable = tc2_pm_cpu_cache_disable, |
183 | .cluster_cache_disable = tc2_pm_cluster_cache_disable, |
184 | .wait_for_powerdown = tc2_pm_wait_for_powerdown, |
185 | .cpu_is_up = tc2_pm_cpu_is_up, |
186 | .cluster_is_up = tc2_pm_cluster_is_up, |
187 | }; |
188 | |
189 | /* |
190 | * Enable cluster-level coherency, in preparation for turning on the MMU. |
191 | */ |
192 | static void __naked tc2_pm_power_up_setup(unsigned int affinity_level) |
193 | { |
194 | asm volatile (" \n" |
195 | " cmp r0, #1 \n" |
196 | " bxne lr \n" |
197 | " b cci_enable_port_for_self " ); |
198 | } |
199 | |
200 | static int __init tc2_pm_init(void) |
201 | { |
202 | unsigned int mpidr, cpu, cluster; |
203 | int ret, irq; |
204 | u32 a15_cluster_id, a7_cluster_id, sys_info; |
205 | struct device_node *np; |
206 | |
207 | /* |
208 | * The power management-related features are hidden behind |
209 | * SCC registers. We need to extract runtime information like |
210 | * cluster ids and number of CPUs really available in clusters. |
211 | */ |
212 | np = of_find_compatible_node(NULL, NULL, |
213 | compat: "arm,vexpress-scc,v2p-ca15_a7" ); |
214 | scc = of_iomap(node: np, index: 0); |
215 | if (!scc) |
216 | return -ENODEV; |
217 | |
218 | a15_cluster_id = readl_relaxed(scc + A15_CONF) & 0xf; |
219 | a7_cluster_id = readl_relaxed(scc + A7_CONF) & 0xf; |
220 | if (a15_cluster_id >= TC2_CLUSTERS || a7_cluster_id >= TC2_CLUSTERS) |
221 | return -EINVAL; |
222 | |
223 | sys_info = readl_relaxed(scc + SYS_INFO); |
224 | tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; |
225 | tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; |
226 | |
227 | irq = irq_of_parse_and_map(node: np, index: 0); |
228 | |
229 | /* |
230 | * A subset of the SCC registers is also used to communicate |
231 | * with the SPC (power controller). We need to be able to |
232 | * drive it very early in the boot process to power up |
233 | * processors, so we initialize the SPC driver here. |
234 | */ |
235 | ret = ve_spc_init(base: scc + SPC_BASE, a15_clusid: a15_cluster_id, irq); |
236 | if (ret) |
237 | return ret; |
238 | |
239 | if (!cci_probed()) |
240 | return -ENODEV; |
241 | |
242 | mpidr = read_cpuid_mpidr(); |
243 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); |
244 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); |
245 | pr_debug("%s: cpu %u cluster %u\n" , __func__, cpu, cluster); |
246 | if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) { |
247 | pr_err("%s: boot CPU is out of bound!\n" , __func__); |
248 | return -EINVAL; |
249 | } |
250 | |
251 | ret = mcpm_platform_register(&tc2_pm_power_ops); |
252 | if (!ret) { |
253 | mcpm_sync_init(tc2_pm_power_up_setup); |
254 | /* test if we can (re)enable the CCI on our own */ |
255 | BUG_ON(mcpm_loopback(tc2_pm_cluster_cache_disable) != 0); |
256 | pr_info("TC2 power management initialized\n" ); |
257 | } |
258 | return ret; |
259 | } |
260 | |
261 | early_initcall(tc2_pm_init); |
262 | |