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