Linux Audio

Check our new training course

Loading...
v6.13.7
  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/firmware/qcom/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 CORE_MEM_CLAMP		BIT(1)
 33#define CLAMP			BIT(0)
 34
 35#define APC_PWR_GATE_CTL	0x14
 36#define BHS_CNT_SHIFT		24
 37#define LDO_PWR_DWN_SHIFT	16
 38#define LDO_BYP_SHIFT		8
 39#define BHS_SEG_SHIFT		1
 40#define BHS_EN			BIT(0)
 41
 42#define APCS_SAW2_VCTL		0x14
 43#define APCS_SAW2_2_VCTL	0x1c
 44
 45extern void secondary_startup_arm(void);
 46
 47#ifdef CONFIG_HOTPLUG_CPU
 48static void qcom_cpu_die(unsigned int cpu)
 49{
 50	wfi();
 51}
 52#endif
 53
 54static int scss_release_secondary(unsigned int cpu)
 55{
 56	struct device_node *node;
 57	void __iomem *base;
 58
 59	node = of_find_compatible_node(NULL, NULL, "qcom,gcc-msm8660");
 60	if (!node) {
 61		pr_err("%s: can't find node\n", __func__);
 62		return -ENXIO;
 63	}
 64
 65	base = of_iomap(node, 0);
 66	of_node_put(node);
 67	if (!base)
 68		return -ENOMEM;
 69
 70	writel_relaxed(0, base + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
 71	writel_relaxed(0, base + SCSS_CPU1CORE_RESET);
 72	writel_relaxed(3, base + SCSS_DBG_STATUS_CORE_PWRDUP);
 73	mb();
 74	iounmap(base);
 75
 76	return 0;
 77}
 78
 79static int cortex_a7_release_secondary(unsigned int cpu)
 80{
 81	int ret = 0;
 82	void __iomem *reg;
 83	struct device_node *cpu_node, *acc_node;
 84	u32 reg_val;
 85
 86	cpu_node = of_get_cpu_node(cpu, NULL);
 87	if (!cpu_node)
 88		return -ENODEV;
 89
 90	acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
 91	if (!acc_node) {
 92		ret = -ENODEV;
 93		goto out_acc;
 94	}
 95
 96	reg = of_iomap(acc_node, 0);
 97	if (!reg) {
 98		ret = -ENOMEM;
 99		goto out_acc_map;
100	}
101
102	/* Put the CPU into reset. */
103	reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP;
104	writel(reg_val, reg + APCS_CPU_PWR_CTL);
105
106	/* Turn on the BHS and set the BHS_CNT to 16 XO clock cycles */
107	writel(BHS_EN | (0x10 << BHS_CNT_SHIFT), reg + APC_PWR_GATE_CTL);
108	/* Wait for the BHS to settle */
109	udelay(2);
110
111	reg_val &= ~CORE_MEM_CLAMP;
112	writel(reg_val, reg + APCS_CPU_PWR_CTL);
113	reg_val |= L2DT_SLP;
114	writel(reg_val, reg + APCS_CPU_PWR_CTL);
115	udelay(2);
116
117	reg_val = (reg_val | BIT(17)) & ~CLAMP;
118	writel(reg_val, reg + APCS_CPU_PWR_CTL);
119	udelay(2);
120
121	/* Release CPU out of reset and bring it to life. */
122	reg_val &= ~(CORE_RST | COREPOR_RST);
123	writel(reg_val, reg + APCS_CPU_PWR_CTL);
124	reg_val |= CORE_PWRD_UP;
125	writel(reg_val, reg + APCS_CPU_PWR_CTL);
126
127	iounmap(reg);
128out_acc_map:
129	of_node_put(acc_node);
130out_acc:
131	of_node_put(cpu_node);
132	return ret;
133}
134
135static int kpssv1_release_secondary(unsigned int cpu)
136{
137	int ret = 0;
138	void __iomem *reg, *saw_reg;
139	struct device_node *cpu_node, *acc_node, *saw_node;
140	u32 val;
141
142	cpu_node = of_get_cpu_node(cpu, NULL);
143	if (!cpu_node)
144		return -ENODEV;
145
146	acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
147	if (!acc_node) {
148		ret = -ENODEV;
149		goto out_acc;
150	}
151
152	saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
153	if (!saw_node) {
154		ret = -ENODEV;
155		goto out_saw;
156	}
157
158	reg = of_iomap(acc_node, 0);
159	if (!reg) {
160		ret = -ENOMEM;
161		goto out_acc_map;
162	}
163
164	saw_reg = of_iomap(saw_node, 0);
165	if (!saw_reg) {
166		ret = -ENOMEM;
167		goto out_saw_map;
168	}
169
170	/* Turn on CPU rail */
171	writel_relaxed(0xA4, saw_reg + APCS_SAW2_VCTL);
172	mb();
173	udelay(512);
174
175	/* Krait bring-up sequence */
176	val = PLL_CLAMP | L2DT_SLP | CLAMP;
177	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
178	val &= ~L2DT_SLP;
179	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
180	mb();
181	ndelay(300);
182
183	val |= COREPOR_RST;
184	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
185	mb();
186	udelay(2);
187
188	val &= ~CLAMP;
189	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
190	mb();
191	udelay(2);
192
193	val &= ~COREPOR_RST;
194	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
195	mb();
196	udelay(100);
197
198	val |= CORE_PWRD_UP;
199	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
200	mb();
201
202	iounmap(saw_reg);
203out_saw_map:
204	iounmap(reg);
205out_acc_map:
206	of_node_put(saw_node);
207out_saw:
208	of_node_put(acc_node);
209out_acc:
210	of_node_put(cpu_node);
211	return ret;
212}
213
214static int kpssv2_release_secondary(unsigned int cpu)
215{
216	void __iomem *reg;
217	struct device_node *cpu_node, *l2_node, *acc_node, *saw_node;
218	void __iomem *l2_saw_base;
219	unsigned reg_val;
220	int ret;
221
222	cpu_node = of_get_cpu_node(cpu, NULL);
223	if (!cpu_node)
224		return -ENODEV;
225
226	acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
227	if (!acc_node) {
228		ret = -ENODEV;
229		goto out_acc;
230	}
231
232	l2_node = of_parse_phandle(cpu_node, "next-level-cache", 0);
233	if (!l2_node) {
234		ret = -ENODEV;
235		goto out_l2;
236	}
237
238	saw_node = of_parse_phandle(l2_node, "qcom,saw", 0);
239	if (!saw_node) {
240		ret = -ENODEV;
241		goto out_saw;
242	}
243
244	reg = of_iomap(acc_node, 0);
245	if (!reg) {
246		ret = -ENOMEM;
247		goto out_map;
248	}
249
250	l2_saw_base = of_iomap(saw_node, 0);
251	if (!l2_saw_base) {
252		ret = -ENOMEM;
253		goto out_saw_map;
254	}
255
256	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
257	reg_val = (64 << BHS_CNT_SHIFT) | (0x3f << LDO_PWR_DWN_SHIFT) | BHS_EN;
258	writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
259	mb();
260	/* wait for the BHS to settle */
261	udelay(1);
262
263	/* Turn on BHS segments */
264	reg_val |= 0x3f << BHS_SEG_SHIFT;
265	writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
266	mb();
267	 /* wait for the BHS to settle */
268	udelay(1);
269
270	/* Finally turn on the bypass so that BHS supplies power */
271	reg_val |= 0x3f << LDO_BYP_SHIFT;
272	writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
273
274	/* enable max phases */
275	writel_relaxed(0x10003, l2_saw_base + APCS_SAW2_2_VCTL);
276	mb();
277	udelay(50);
278
279	reg_val = COREPOR_RST | CLAMP;
280	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
281	mb();
282	udelay(2);
283
284	reg_val &= ~CLAMP;
285	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
286	mb();
287	udelay(2);
288
289	reg_val &= ~COREPOR_RST;
290	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
291	mb();
292
293	reg_val |= CORE_PWRD_UP;
294	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
295	mb();
296
297	ret = 0;
298
299	iounmap(l2_saw_base);
300out_saw_map:
301	iounmap(reg);
302out_map:
303	of_node_put(saw_node);
304out_saw:
305	of_node_put(l2_node);
306out_l2:
307	of_node_put(acc_node);
308out_acc:
309	of_node_put(cpu_node);
310
311	return ret;
312}
313
314static DEFINE_PER_CPU(int, cold_boot_done);
315
316static int qcom_boot_secondary(unsigned int cpu, int (*func)(unsigned int))
317{
318	int ret = 0;
319
320	if (!per_cpu(cold_boot_done, cpu)) {
321		ret = func(cpu);
322		if (!ret)
323			per_cpu(cold_boot_done, cpu) = true;
324	}
325
326	/*
327	 * Send the secondary CPU a soft interrupt, thereby causing
328	 * the boot monitor to read the system wide flags register,
329	 * and branch to the address found there.
330	 */
331	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
332
333	return ret;
334}
335
336static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle)
337{
338	return qcom_boot_secondary(cpu, scss_release_secondary);
339}
340
341static int cortex_a7_boot_secondary(unsigned int cpu, struct task_struct *idle)
342{
343	return qcom_boot_secondary(cpu, cortex_a7_release_secondary);
344}
345
346static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle)
347{
348	return qcom_boot_secondary(cpu, kpssv1_release_secondary);
349}
350
351static int kpssv2_boot_secondary(unsigned int cpu, struct task_struct *idle)
352{
353	return qcom_boot_secondary(cpu, kpssv2_release_secondary);
354}
355
356static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
357{
358	int cpu;
359
360	if (qcom_scm_set_cold_boot_addr(secondary_startup_arm)) {
361		for_each_present_cpu(cpu) {
362			if (cpu == smp_processor_id())
363				continue;
364			set_cpu_present(cpu, false);
365		}
366		pr_warn("Failed to set CPU boot address, disabling SMP\n");
367	}
368}
369
370static const struct smp_operations smp_msm8660_ops __initconst = {
371	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
372	.smp_boot_secondary	= msm8660_boot_secondary,
373#ifdef CONFIG_HOTPLUG_CPU
374	.cpu_die		= qcom_cpu_die,
375#endif
376};
377CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops);
378
379static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
380	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
381	.smp_boot_secondary	= cortex_a7_boot_secondary,
382#ifdef CONFIG_HOTPLUG_CPU
383	.cpu_die		= qcom_cpu_die,
384#endif
385};
386CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
387CPU_METHOD_OF_DECLARE(qcom_smp_msm8909, "qcom,msm8909-smp", &qcom_smp_cortex_a7_ops);
388CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
389
390static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
391	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
392	.smp_boot_secondary	= kpssv1_boot_secondary,
393#ifdef CONFIG_HOTPLUG_CPU
394	.cpu_die		= qcom_cpu_die,
395#endif
396};
397CPU_METHOD_OF_DECLARE(qcom_smp_kpssv1, "qcom,kpss-acc-v1", &qcom_smp_kpssv1_ops);
398
399static const struct smp_operations qcom_smp_kpssv2_ops __initconst = {
400	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
401	.smp_boot_secondary	= kpssv2_boot_secondary,
402#ifdef CONFIG_HOTPLUG_CPU
403	.cpu_die		= qcom_cpu_die,
404#endif
405};
406CPU_METHOD_OF_DECLARE(qcom_smp_kpssv2, "qcom,kpss-acc-v2", &qcom_smp_kpssv2_ops);
v6.8
  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/firmware/qcom/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 CORE_MEM_CLAMP		BIT(1)
 33#define CLAMP			BIT(0)
 34
 35#define APC_PWR_GATE_CTL	0x14
 36#define BHS_CNT_SHIFT		24
 37#define LDO_PWR_DWN_SHIFT	16
 38#define LDO_BYP_SHIFT		8
 39#define BHS_SEG_SHIFT		1
 40#define BHS_EN			BIT(0)
 41
 42#define APCS_SAW2_VCTL		0x14
 43#define APCS_SAW2_2_VCTL	0x1c
 44
 45extern void secondary_startup_arm(void);
 46
 47#ifdef CONFIG_HOTPLUG_CPU
 48static void qcom_cpu_die(unsigned int cpu)
 49{
 50	wfi();
 51}
 52#endif
 53
 54static int scss_release_secondary(unsigned int cpu)
 55{
 56	struct device_node *node;
 57	void __iomem *base;
 58
 59	node = of_find_compatible_node(NULL, NULL, "qcom,gcc-msm8660");
 60	if (!node) {
 61		pr_err("%s: can't find node\n", __func__);
 62		return -ENXIO;
 63	}
 64
 65	base = of_iomap(node, 0);
 66	of_node_put(node);
 67	if (!base)
 68		return -ENOMEM;
 69
 70	writel_relaxed(0, base + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
 71	writel_relaxed(0, base + SCSS_CPU1CORE_RESET);
 72	writel_relaxed(3, base + SCSS_DBG_STATUS_CORE_PWRDUP);
 73	mb();
 74	iounmap(base);
 75
 76	return 0;
 77}
 78
 79static int cortex_a7_release_secondary(unsigned int cpu)
 80{
 81	int ret = 0;
 82	void __iomem *reg;
 83	struct device_node *cpu_node, *acc_node;
 84	u32 reg_val;
 85
 86	cpu_node = of_get_cpu_node(cpu, NULL);
 87	if (!cpu_node)
 88		return -ENODEV;
 89
 90	acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
 91	if (!acc_node) {
 92		ret = -ENODEV;
 93		goto out_acc;
 94	}
 95
 96	reg = of_iomap(acc_node, 0);
 97	if (!reg) {
 98		ret = -ENOMEM;
 99		goto out_acc_map;
100	}
101
102	/* Put the CPU into reset. */
103	reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP;
104	writel(reg_val, reg + APCS_CPU_PWR_CTL);
105
106	/* Turn on the BHS and set the BHS_CNT to 16 XO clock cycles */
107	writel(BHS_EN | (0x10 << BHS_CNT_SHIFT), reg + APC_PWR_GATE_CTL);
108	/* Wait for the BHS to settle */
109	udelay(2);
110
111	reg_val &= ~CORE_MEM_CLAMP;
112	writel(reg_val, reg + APCS_CPU_PWR_CTL);
113	reg_val |= L2DT_SLP;
114	writel(reg_val, reg + APCS_CPU_PWR_CTL);
115	udelay(2);
116
117	reg_val = (reg_val | BIT(17)) & ~CLAMP;
118	writel(reg_val, reg + APCS_CPU_PWR_CTL);
119	udelay(2);
120
121	/* Release CPU out of reset and bring it to life. */
122	reg_val &= ~(CORE_RST | COREPOR_RST);
123	writel(reg_val, reg + APCS_CPU_PWR_CTL);
124	reg_val |= CORE_PWRD_UP;
125	writel(reg_val, reg + APCS_CPU_PWR_CTL);
126
127	iounmap(reg);
128out_acc_map:
129	of_node_put(acc_node);
130out_acc:
131	of_node_put(cpu_node);
132	return ret;
133}
134
135static int kpssv1_release_secondary(unsigned int cpu)
136{
137	int ret = 0;
138	void __iomem *reg, *saw_reg;
139	struct device_node *cpu_node, *acc_node, *saw_node;
140	u32 val;
141
142	cpu_node = of_get_cpu_node(cpu, NULL);
143	if (!cpu_node)
144		return -ENODEV;
145
146	acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
147	if (!acc_node) {
148		ret = -ENODEV;
149		goto out_acc;
150	}
151
152	saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
153	if (!saw_node) {
154		ret = -ENODEV;
155		goto out_saw;
156	}
157
158	reg = of_iomap(acc_node, 0);
159	if (!reg) {
160		ret = -ENOMEM;
161		goto out_acc_map;
162	}
163
164	saw_reg = of_iomap(saw_node, 0);
165	if (!saw_reg) {
166		ret = -ENOMEM;
167		goto out_saw_map;
168	}
169
170	/* Turn on CPU rail */
171	writel_relaxed(0xA4, saw_reg + APCS_SAW2_VCTL);
172	mb();
173	udelay(512);
174
175	/* Krait bring-up sequence */
176	val = PLL_CLAMP | L2DT_SLP | CLAMP;
177	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
178	val &= ~L2DT_SLP;
179	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
180	mb();
181	ndelay(300);
182
183	val |= COREPOR_RST;
184	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
185	mb();
186	udelay(2);
187
188	val &= ~CLAMP;
189	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
190	mb();
191	udelay(2);
192
193	val &= ~COREPOR_RST;
194	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
195	mb();
196	udelay(100);
197
198	val |= CORE_PWRD_UP;
199	writel_relaxed(val, reg + APCS_CPU_PWR_CTL);
200	mb();
201
202	iounmap(saw_reg);
203out_saw_map:
204	iounmap(reg);
205out_acc_map:
206	of_node_put(saw_node);
207out_saw:
208	of_node_put(acc_node);
209out_acc:
210	of_node_put(cpu_node);
211	return ret;
212}
213
214static int kpssv2_release_secondary(unsigned int cpu)
215{
216	void __iomem *reg;
217	struct device_node *cpu_node, *l2_node, *acc_node, *saw_node;
218	void __iomem *l2_saw_base;
219	unsigned reg_val;
220	int ret;
221
222	cpu_node = of_get_cpu_node(cpu, NULL);
223	if (!cpu_node)
224		return -ENODEV;
225
226	acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
227	if (!acc_node) {
228		ret = -ENODEV;
229		goto out_acc;
230	}
231
232	l2_node = of_parse_phandle(cpu_node, "next-level-cache", 0);
233	if (!l2_node) {
234		ret = -ENODEV;
235		goto out_l2;
236	}
237
238	saw_node = of_parse_phandle(l2_node, "qcom,saw", 0);
239	if (!saw_node) {
240		ret = -ENODEV;
241		goto out_saw;
242	}
243
244	reg = of_iomap(acc_node, 0);
245	if (!reg) {
246		ret = -ENOMEM;
247		goto out_map;
248	}
249
250	l2_saw_base = of_iomap(saw_node, 0);
251	if (!l2_saw_base) {
252		ret = -ENOMEM;
253		goto out_saw_map;
254	}
255
256	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
257	reg_val = (64 << BHS_CNT_SHIFT) | (0x3f << LDO_PWR_DWN_SHIFT) | BHS_EN;
258	writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
259	mb();
260	/* wait for the BHS to settle */
261	udelay(1);
262
263	/* Turn on BHS segments */
264	reg_val |= 0x3f << BHS_SEG_SHIFT;
265	writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
266	mb();
267	 /* wait for the BHS to settle */
268	udelay(1);
269
270	/* Finally turn on the bypass so that BHS supplies power */
271	reg_val |= 0x3f << LDO_BYP_SHIFT;
272	writel_relaxed(reg_val, reg + APC_PWR_GATE_CTL);
273
274	/* enable max phases */
275	writel_relaxed(0x10003, l2_saw_base + APCS_SAW2_2_VCTL);
276	mb();
277	udelay(50);
278
279	reg_val = COREPOR_RST | CLAMP;
280	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
281	mb();
282	udelay(2);
283
284	reg_val &= ~CLAMP;
285	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
286	mb();
287	udelay(2);
288
289	reg_val &= ~COREPOR_RST;
290	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
291	mb();
292
293	reg_val |= CORE_PWRD_UP;
294	writel_relaxed(reg_val, reg + APCS_CPU_PWR_CTL);
295	mb();
296
297	ret = 0;
298
299	iounmap(l2_saw_base);
300out_saw_map:
301	iounmap(reg);
302out_map:
303	of_node_put(saw_node);
304out_saw:
305	of_node_put(l2_node);
306out_l2:
307	of_node_put(acc_node);
308out_acc:
309	of_node_put(cpu_node);
310
311	return ret;
312}
313
314static DEFINE_PER_CPU(int, cold_boot_done);
315
316static int qcom_boot_secondary(unsigned int cpu, int (*func)(unsigned int))
317{
318	int ret = 0;
319
320	if (!per_cpu(cold_boot_done, cpu)) {
321		ret = func(cpu);
322		if (!ret)
323			per_cpu(cold_boot_done, cpu) = true;
324	}
325
326	/*
327	 * Send the secondary CPU a soft interrupt, thereby causing
328	 * the boot monitor to read the system wide flags register,
329	 * and branch to the address found there.
330	 */
331	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
332
333	return ret;
334}
335
336static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle)
337{
338	return qcom_boot_secondary(cpu, scss_release_secondary);
339}
340
341static int cortex_a7_boot_secondary(unsigned int cpu, struct task_struct *idle)
342{
343	return qcom_boot_secondary(cpu, cortex_a7_release_secondary);
344}
345
346static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle)
347{
348	return qcom_boot_secondary(cpu, kpssv1_release_secondary);
349}
350
351static int kpssv2_boot_secondary(unsigned int cpu, struct task_struct *idle)
352{
353	return qcom_boot_secondary(cpu, kpssv2_release_secondary);
354}
355
356static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
357{
358	int cpu;
359
360	if (qcom_scm_set_cold_boot_addr(secondary_startup_arm)) {
361		for_each_present_cpu(cpu) {
362			if (cpu == smp_processor_id())
363				continue;
364			set_cpu_present(cpu, false);
365		}
366		pr_warn("Failed to set CPU boot address, disabling SMP\n");
367	}
368}
369
370static const struct smp_operations smp_msm8660_ops __initconst = {
371	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
372	.smp_boot_secondary	= msm8660_boot_secondary,
373#ifdef CONFIG_HOTPLUG_CPU
374	.cpu_die		= qcom_cpu_die,
375#endif
376};
377CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops);
378
379static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
380	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
381	.smp_boot_secondary	= cortex_a7_boot_secondary,
382#ifdef CONFIG_HOTPLUG_CPU
383	.cpu_die		= qcom_cpu_die,
384#endif
385};
386CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
387CPU_METHOD_OF_DECLARE(qcom_smp_msm8909, "qcom,msm8909-smp", &qcom_smp_cortex_a7_ops);
388CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
389
390static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
391	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
392	.smp_boot_secondary	= kpssv1_boot_secondary,
393#ifdef CONFIG_HOTPLUG_CPU
394	.cpu_die		= qcom_cpu_die,
395#endif
396};
397CPU_METHOD_OF_DECLARE(qcom_smp_kpssv1, "qcom,kpss-acc-v1", &qcom_smp_kpssv1_ops);
398
399static const struct smp_operations qcom_smp_kpssv2_ops __initconst = {
400	.smp_prepare_cpus	= qcom_smp_prepare_cpus,
401	.smp_boot_secondary	= kpssv2_boot_secondary,
402#ifdef CONFIG_HOTPLUG_CPU
403	.cpu_die		= qcom_cpu_die,
404#endif
405};
406CPU_METHOD_OF_DECLARE(qcom_smp_kpssv2, "qcom,kpss-acc-v2", &qcom_smp_kpssv2_ops);