Merge tag 'net-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / arch / arm / mach-qcom / platsmp.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  Copyright (C) 2002 ARM Ltd.
4  *  All Rights Reserved
5  *  Copyright (c) 2010, Code Aurora Forum. All rights reserved.
6  *  Copyright (c) 2014 The Linux Foundation. All rights reserved.
7  */
8
9 #include <linux/init.h>
10 #include <linux/errno.h>
11 #include <linux/delay.h>
12 #include <linux/device.h>
13 #include <linux/of.h>
14 #include <linux/of_address.h>
15 #include <linux/smp.h>
16 #include <linux/io.h>
17 #include <linux/qcom_scm.h>
18
19 #include <asm/smp_plat.h>
20
21
22 #define VDD_SC1_ARRAY_CLAMP_GFS_CTL     0x35a0
23 #define SCSS_CPU1CORE_RESET             0x2d80
24 #define SCSS_DBG_STATUS_CORE_PWRDUP     0x2e64
25
26 #define APCS_CPU_PWR_CTL        0x04
27 #define PLL_CLAMP               BIT(8)
28 #define CORE_PWRD_UP            BIT(7)
29 #define COREPOR_RST             BIT(5)
30 #define CORE_RST                BIT(4)
31 #define L2DT_SLP                BIT(3)
32 #define CLAMP                   BIT(0)
33
34 #define APC_PWR_GATE_CTL        0x14
35 #define BHS_CNT_SHIFT           24
36 #define LDO_PWR_DWN_SHIFT       16
37 #define LDO_BYP_SHIFT           8
38 #define BHS_SEG_SHIFT           1
39 #define BHS_EN                  BIT(0)
40
41 #define APCS_SAW2_VCTL          0x14
42 #define APCS_SAW2_2_VCTL        0x1c
43
44 extern void secondary_startup_arm(void);
45
46 #ifdef CONFIG_HOTPLUG_CPU
47 static void qcom_cpu_die(unsigned int cpu)
48 {
49         wfi();
50 }
51 #endif
52
53 static int scss_release_secondary(unsigned int cpu)
54 {
55         struct device_node *node;
56         void __iomem *base;
57
58         node = of_find_compatible_node(NULL, NULL, "qcom,gcc-msm8660");
59         if (!node) {
60                 pr_err("%s: can't find node\n", __func__);
61                 return -ENXIO;
62         }
63
64         base = of_iomap(node, 0);
65         of_node_put(node);
66         if (!base)
67                 return -ENOMEM;
68
69         writel_relaxed(0, base + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
70         writel_relaxed(0, base + SCSS_CPU1CORE_RESET);
71         writel_relaxed(3, base + SCSS_DBG_STATUS_CORE_PWRDUP);
72         mb();
73         iounmap(base);
74
75         return 0;
76 }
77
78 static int kpssv1_release_secondary(unsigned int cpu)
79 {
80         int ret = 0;
81         void __iomem *reg, *saw_reg;
82         struct device_node *cpu_node, *acc_node, *saw_node;
83         u32 val;
84
85         cpu_node = of_get_cpu_node(cpu, NULL);
86         if (!cpu_node)
87                 return -ENODEV;
88
89         acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
90         if (!acc_node) {
91                 ret = -ENODEV;
92                 goto out_acc;
93         }
94
95         saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
96         if (!saw_node) {
97                 ret = -ENODEV;
98                 goto out_saw;
99         }
100
101         reg = of_iomap(acc_node, 0);
102         if (!reg) {
103                 ret = -ENOMEM;
104                 goto out_acc_map;
105         }
106
107         saw_reg = of_iomap(saw_node, 0);
108         if (!saw_reg) {
109                 ret = -ENOMEM;
110                 goto out_saw_map;
111         }
112
113         /* Turn on CPU rail */
114         writel_relaxed(0xA4, saw_reg + APCS_SAW2_VCTL);
115         mb();
116         udelay(512);
117
118         /* Krait bring-up sequence */
119         val = PLL_CLAMP | L2DT_SLP | CLAMP;
120         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
121         val &= ~L2DT_SLP;
122         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
123         mb();
124         ndelay(300);
125
126         val |= COREPOR_RST;
127         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
128         mb();
129         udelay(2);
130
131         val &= ~CLAMP;
132         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
133         mb();
134         udelay(2);
135
136         val &= ~COREPOR_RST;
137         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
138         mb();
139         udelay(100);
140
141         val |= CORE_PWRD_UP;
142         writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
143         mb();
144
145         iounmap(saw_reg);
146 out_saw_map:
147         iounmap(reg);
148 out_acc_map:
149         of_node_put(saw_node);
150 out_saw:
151         of_node_put(acc_node);
152 out_acc:
153         of_node_put(cpu_node);
154         return ret;
155 }
156
157 static int kpssv2_release_secondary(unsigned int cpu)
158 {
159         void __iomem *reg;
160         struct device_node *cpu_node, *l2_node, *acc_node, *saw_node;
161         void __iomem *l2_saw_base;
162         unsigned reg_val;
163         int ret;
164
165         cpu_node = of_get_cpu_node(cpu, NULL);
166         if (!cpu_node)
167                 return -ENODEV;
168
169         acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
170         if (!acc_node) {
171                 ret = -ENODEV;
172                 goto out_acc;
173         }
174
175         l2_node = of_parse_phandle(cpu_node, "next-level-cache", 0);
176         if (!l2_node) {
177                 ret = -ENODEV;
178                 goto out_l2;
179         }
180
181         saw_node = of_parse_phandle(l2_node, "qcom,saw", 0);
182         if (!saw_node) {
183                 ret = -ENODEV;
184                 goto out_saw;
185         }
186
187         reg = of_iomap(acc_node, 0);
188         if (!reg) {
189                 ret = -ENOMEM;
190                 goto out_map;
191         }
192
193         l2_saw_base = of_iomap(saw_node, 0);
194         if (!l2_saw_base) {
195                 ret = -ENOMEM;
196                 goto out_saw_map;
197         }
198
199         /* Turn on the BHS, turn off LDO Bypass and power down LDO */
200         reg_val = (64 << BHS_CNT_SHIFT) | (0x3f << LDO_PWR_DWN_SHIFT) | BHS_EN;
201         writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
202         mb();
203         /* wait for the BHS to settle */
204         udelay(1);
205
206         /* Turn on BHS segments */
207         reg_val |= 0x3f << BHS_SEG_SHIFT;
208         writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
209         mb();
210          /* wait for the BHS to settle */
211         udelay(1);
212
213         /* Finally turn on the bypass so that BHS supplies power */
214         reg_val |= 0x3f << LDO_BYP_SHIFT;
215         writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
216
217         /* enable max phases */
218         writel_relaxed(0x10003, l2_saw_base + APCS_SAW2_2_VCTL);
219         mb();
220         udelay(50);
221
222         reg_val = COREPOR_RST | CLAMP;
223         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
224         mb();
225         udelay(2);
226
227         reg_val &= ~CLAMP;
228         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
229         mb();
230         udelay(2);
231
232         reg_val &= ~COREPOR_RST;
233         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
234         mb();
235
236         reg_val |= CORE_PWRD_UP;
237         writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
238         mb();
239
240         ret = 0;
241
242         iounmap(l2_saw_base);
243 out_saw_map:
244         iounmap(reg);
245 out_map:
246         of_node_put(saw_node);
247 out_saw:
248         of_node_put(l2_node);
249 out_l2:
250         of_node_put(acc_node);
251 out_acc:
252         of_node_put(cpu_node);
253
254         return ret;
255 }
256
257 static DEFINE_PER_CPU(int, cold_boot_done);
258
259 static int qcom_boot_secondary(unsigned int cpu, int (*func)(unsigned int))
260 {
261         int ret = 0;
262
263         if (!per_cpu(cold_boot_done, cpu)) {
264                 ret = func(cpu);
265                 if (!ret)
266                         per_cpu(cold_boot_done, cpu) = true;
267         }
268
269         /*
270          * Send the secondary CPU a soft interrupt, thereby causing
271          * the boot monitor to read the system wide flags register,
272          * and branch to the address found there.
273          */
274         arch_send_wakeup_ipi_mask(cpumask_of(cpu));
275
276         return ret;
277 }
278
279 static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle)
280 {
281         return qcom_boot_secondary(cpu, scss_release_secondary);
282 }
283
284 static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle)
285 {
286         return qcom_boot_secondary(cpu, kpssv1_release_secondary);
287 }
288
289 static int kpssv2_boot_secondary(unsigned int cpu, struct task_struct *idle)
290 {
291         return qcom_boot_secondary(cpu, kpssv2_release_secondary);
292 }
293
294 static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
295 {
296         int cpu;
297
298         if (qcom_scm_set_cold_boot_addr(secondary_startup_arm,
299                                         cpu_present_mask)) {
300                 for_each_present_cpu(cpu) {
301                         if (cpu == smp_processor_id())
302                                 continue;
303                         set_cpu_present(cpu, false);
304                 }
305                 pr_warn("Failed to set CPU boot address, disabling SMP\n");
306         }
307 }
308
309 static const struct smp_operations smp_msm8660_ops __initconst = {
310         .smp_prepare_cpus       = qcom_smp_prepare_cpus,
311         .smp_boot_secondary     = msm8660_boot_secondary,
312 #ifdef CONFIG_HOTPLUG_CPU
313         .cpu_die                = qcom_cpu_die,
314 #endif
315 };
316 CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops);
317
318 static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
319         .smp_prepare_cpus       = qcom_smp_prepare_cpus,
320         .smp_boot_secondary     = kpssv1_boot_secondary,
321 #ifdef CONFIG_HOTPLUG_CPU
322         .cpu_die                = qcom_cpu_die,
323 #endif
324 };
325 CPU_METHOD_OF_DECLARE(qcom_smp_kpssv1, "qcom,kpss-acc-v1", &qcom_smp_kpssv1_ops);
326
327 static const struct smp_operations qcom_smp_kpssv2_ops __initconst = {
328         .smp_prepare_cpus       = qcom_smp_prepare_cpus,
329         .smp_boot_secondary     = kpssv2_boot_secondary,
330 #ifdef CONFIG_HOTPLUG_CPU
331         .cpu_die                = qcom_cpu_die,
332 #endif
333 };
334 CPU_METHOD_OF_DECLARE(qcom_smp_kpssv2, "qcom,kpss-acc-v2", &qcom_smp_kpssv2_ops);