blob: 796fba1de46151edeb2a5fff82aa83b889a7f819 [file] [log] [blame]
Jeff Ohlsteine14411d2010-11-30 13:06:36 -08001/*
2 * Copyright (C) 2002 ARM Ltd.
3 * All Rights Reserved
Syed Rameez Mustafa3971c142013-01-09 19:04:53 -08004 * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Jeff Ohlsteine14411d2010-11-30 13:06:36 -08005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -080011#include <linux/init.h>
Joel King274621c2011-12-05 06:18:20 -080012#include <linux/kernel.h>
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080013#include <linux/init.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070014#include <linux/cpumask.h>
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080015#include <linux/delay.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070016#include <linux/interrupt.h>
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080017#include <linux/io.h>
Stepan Moskovchenko6b1d5df2012-08-11 22:33:20 -070018#include <linux/regulator/krait-regulator.h>
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080019
20#include <asm/hardware/gic.h>
21#include <asm/cacheflush.h>
Jeff Ohlstein41ff4452011-04-07 17:41:09 -070022#include <asm/cputype.h>
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080023#include <asm/mach-types.h>
Will Deaconeb504392012-01-20 12:01:12 +010024#include <asm/smp_plat.h>
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include <mach/hardware.h>
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080028#include <mach/msm_iomap.h>
29
Matt Wagantall7cca4642012-02-01 16:43:24 -080030#include "pm.h"
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -080031#include "platsmp.h"
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080032#include "scm-boot.h"
Stepan Moskovchenko9bbe5852012-01-09 13:28:28 -080033#include "spm.h"
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080034
35#define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0
36#define SCSS_CPU1CORE_RESET 0xD80
37#define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64
Steve Mucklef132c6c2012-06-06 18:30:57 -070038
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080039/*
40 * control for which core is the next to come out of the secondary
41 * boot "holding pen".
42 */
43volatile int pen_release = -1;
44
Stephen Boydf5e90822012-08-08 13:36:15 -070045/*
46 * Write pen_release in a way that is guaranteed to be visible to all
47 * observers, irrespective of whether they're taking part in coherency
48 * or not. This is necessary for the hotplug code to work reliably.
49 */
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -080050void __cpuinit write_pen_release(int val)
Stephen Boydf5e90822012-08-08 13:36:15 -070051{
52 pen_release = val;
53 smp_wmb();
54 __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
55 outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
56}
57
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080058static DEFINE_SPINLOCK(boot_lock);
59
60void __cpuinit platform_secondary_init(unsigned int cpu)
61{
Steve Mucklef132c6c2012-06-06 18:30:57 -070062 WARN_ON(msm_platform_secondary_init(cpu));
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080063
64 /*
65 * if any interrupts are already enabled for the primary
66 * core (e.g. timer irq), then they will not have been enabled
67 * for us: do so
68 */
69 gic_secondary_init(0);
70
71 /*
Stephen Boydf5e90822012-08-08 13:36:15 -070072 * let the primary processor know we're out of the
73 * pen, then head off into the C entry point
74 */
75 write_pen_release(-1);
76
77 /*
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080078 * Synchronise with the boot thread.
79 */
80 spin_lock(&boot_lock);
81 spin_unlock(&boot_lock);
82}
83
Syed Rameez Mustafa8386d532013-01-18 17:41:17 -080084static int __cpuinit release_secondary_sim(unsigned long base, unsigned int cpu)
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -080085{
86 void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
87 if (!base_ptr)
88 return -ENODEV;
89
90 writel_relaxed(0x800, base_ptr+0x04);
91 writel_relaxed(0x3FFF, base_ptr+0x14);
92
93 mb();
94 iounmap(base_ptr);
95 return 0;
96}
97
Stepan Moskovchenko964e1032012-01-06 18:16:10 -080098static int __cpuinit scorpion_release_secondary(void)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080099{
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800100 void *base_ptr = ioremap_nocache(0x00902000, SZ_4K*2);
101 if (!base_ptr)
102 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103
Steve Mucklef132c6c2012-06-06 18:30:57 -0700104 writel_relaxed(0, base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800105 dmb();
Steve Mucklef132c6c2012-06-06 18:30:57 -0700106 writel_relaxed(0, base_ptr + SCSS_CPU1CORE_RESET);
107 writel_relaxed(3, base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP);
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800108 mb();
109 iounmap(base_ptr);
110
111 return 0;
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800112}
113
Syed Rameez Mustafa8386d532013-01-18 17:41:17 -0800114static int __cpuinit msm8960_release_secondary(unsigned long base,
115 unsigned int cpu)
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800116{
Sathish Ambley576a6972012-03-20 12:38:45 -0700117 void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800118 if (!base_ptr)
119 return -ENODEV;
120
Stepan Moskovchenko9bbe5852012-01-09 13:28:28 -0800121 msm_spm_turn_on_cpu_rail(cpu);
122
Stepan Moskovchenko986b5152012-12-11 18:33:07 -0800123 writel_relaxed(0x109, base_ptr+0x04);
124 writel_relaxed(0x101, base_ptr+0x04);
125 mb();
126 ndelay(300);
127
128 writel_relaxed(0x121, base_ptr+0x04);
Stepan Moskovchenko121f75f2012-08-16 21:10:13 -0700129 mb();
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800130 udelay(2);
131
Stepan Moskovchenko986b5152012-12-11 18:33:07 -0800132 writel_relaxed(0x120, base_ptr+0x04);
Stepan Moskovchenko121f75f2012-08-16 21:10:13 -0700133 mb();
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800134 udelay(2);
135
Stepan Moskovchenko986b5152012-12-11 18:33:07 -0800136 writel_relaxed(0x100, base_ptr+0x04);
Stepan Moskovchenko121f75f2012-08-16 21:10:13 -0700137 mb();
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800138 udelay(100);
139
Stepan Moskovchenko986b5152012-12-11 18:33:07 -0800140 writel_relaxed(0x180, base_ptr+0x04);
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800141 mb();
142 iounmap(base_ptr);
143 return 0;
144}
145
Syed Rameez Mustafa8386d532013-01-18 17:41:17 -0800146static int __cpuinit msm8974_release_secondary(unsigned long base,
147 unsigned int cpu)
Stepan Moskovchenko25173722012-08-09 13:43:02 -0700148{
149 void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
Abhijeet Dharmapurikardd167852013-02-14 16:46:48 -0800150
Stepan Moskovchenko25173722012-08-09 13:43:02 -0700151 if (!base_ptr)
152 return -ENODEV;
153
Abhijeet Dharmapurikardd167852013-02-14 16:46:48 -0800154 secondary_cpu_hs_init(base_ptr, cpu);
Stepan Moskovchenko6b1d5df2012-08-11 22:33:20 -0700155
Stepan Moskovchenko25173722012-08-09 13:43:02 -0700156 writel_relaxed(0x021, base_ptr+0x04);
157 mb();
158 udelay(2);
159
160 writel_relaxed(0x020, base_ptr+0x04);
161 mb();
162 udelay(2);
163
164 writel_relaxed(0x000, base_ptr+0x04);
165 mb();
166
167 writel_relaxed(0x080, base_ptr+0x04);
168 mb();
169 iounmap(base_ptr);
170 return 0;
171}
172
Syed Rameez Mustafa975329c2013-01-18 18:42:12 -0800173static int __cpuinit arm_release_secondary(unsigned long base, unsigned int cpu)
174{
175 void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
176 if (!base_ptr)
177 return -ENODEV;
178
179 writel_relaxed(0x00000033, base_ptr+0x04);
180 mb();
181
182 writel_relaxed(0x10000001, base_ptr+0x14);
183 mb();
184 udelay(2);
185
186 writel_relaxed(0x00000031, base_ptr+0x04);
187 mb();
188
189 writel_relaxed(0x00000039, base_ptr+0x04);
190 mb();
191 udelay(2);
192
193 writel_relaxed(0x00020038, base_ptr+0x04);
194 mb();
195 udelay(2);
196
197
198 writel_relaxed(0x00020008, base_ptr+0x04);
199 mb();
200
201 writel_relaxed(0x00020088, base_ptr+0x04);
202 mb();
203
204 iounmap(base_ptr);
205 return 0;
206}
207
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800208static int __cpuinit release_from_pen(unsigned int cpu)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800209{
210 unsigned long timeout;
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 /* Set preset_lpj to avoid subsequent lpj recalculations */
213 preset_lpj = loops_per_jiffy;
214
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800215 /*
216 * set synchronisation state between this boot processor
217 * and the secondary one
218 */
219 spin_lock(&boot_lock);
220
221 /*
222 * The secondary processor is waiting to be released from
223 * the holding pen - release it, then wait for it to flag
224 * that it has been released by resetting pen_release.
225 *
226 * Note that "pen_release" is the hardware CPU ID, whereas
227 * "cpu" is Linux's internal ID.
228 */
Stephen Boydf5e90822012-08-08 13:36:15 -0700229 write_pen_release(cpu_logical_map(cpu));
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800230
231 /*
232 * Send the secondary CPU a soft interrupt, thereby causing
233 * the boot monitor to read the system wide flags register,
234 * and branch to the address found there.
235 */
Russell King0f7b3322011-04-03 13:01:30 +0100236 gic_raise_softirq(cpumask_of(cpu), 1);
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800237
238 timeout = jiffies + (1 * HZ);
239 while (time_before(jiffies, timeout)) {
240 smp_rmb();
241 if (pen_release == -1)
242 break;
243
244 udelay(10);
245 }
246
247 /*
248 * now the secondary core is starting up let it run its
249 * calibrations, then wait for it to finish
250 */
251 spin_unlock(&boot_lock);
252
253 return pen_release != -1 ? -ENOSYS : 0;
254}
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800255
256DEFINE_PER_CPU(int, cold_boot_done);
257
258int __cpuinit scorpion_boot_secondary(unsigned int cpu,
259 struct task_struct *idle)
260{
261 pr_debug("Starting secondary CPU %d\n", cpu);
262
263 if (per_cpu(cold_boot_done, cpu) == false) {
264 scorpion_release_secondary();
265 per_cpu(cold_boot_done, cpu) = true;
266 }
267 return release_from_pen(cpu);
268}
269
270int __cpuinit msm8960_boot_secondary(unsigned int cpu, struct task_struct *idle)
271{
272 pr_debug("Starting secondary CPU %d\n", cpu);
273
274 if (per_cpu(cold_boot_done, cpu) == false) {
275 msm8960_release_secondary(0x02088000, cpu);
276 per_cpu(cold_boot_done, cpu) = true;
277 }
278 return release_from_pen(cpu);
279}
280
281int __cpuinit msm8974_boot_secondary(unsigned int cpu, struct task_struct *idle)
282{
283 pr_debug("Starting secondary CPU %d\n", cpu);
284
285 if (per_cpu(cold_boot_done, cpu) == false) {
Stepan Moskovchenko82f0eab2013-04-02 19:52:28 -0700286 if (of_board_is_sim())
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800287 release_secondary_sim(0xf9088000, cpu);
Stepan Moskovchenko82f0eab2013-04-02 19:52:28 -0700288 else if (!of_board_is_rumi())
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800289 msm8974_release_secondary(0xf9088000, cpu);
290
291 per_cpu(cold_boot_done, cpu) = true;
292 }
293 return release_from_pen(cpu);
294}
295
296int __cpuinit arm_boot_secondary(unsigned int cpu, struct task_struct *idle)
297{
298 pr_debug("Starting secondary CPU %d\n", cpu);
299
300 if (per_cpu(cold_boot_done, cpu) == false) {
Stepan Moskovchenko82f0eab2013-04-02 19:52:28 -0700301 if (of_board_is_sim())
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800302 release_secondary_sim(0xf9088000, cpu);
Stepan Moskovchenko82f0eab2013-04-02 19:52:28 -0700303 else if (!of_board_is_rumi())
Syed Rameez Mustafa975329c2013-01-18 18:42:12 -0800304 arm_release_secondary(0xf9088000, cpu);
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800305
306 per_cpu(cold_boot_done, cpu) = true;
307 }
308 return release_from_pen(cpu);
309}
310
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800311/*
312 * Initialise the CPU possible map early - this describes the CPUs
Steve Mucklef132c6c2012-06-06 18:30:57 -0700313 * which may be present or become present in the system.
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800314 */
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800315static void __init msm_smp_init_cpus(void)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800316{
Jeff Ohlstein41ff4452011-04-07 17:41:09 -0700317 unsigned int i, ncores = get_core_count();
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800318
Russell Kinga06f9162011-10-20 22:04:18 +0100319 if (ncores > nr_cpu_ids) {
320 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
321 ncores, nr_cpu_ids);
322 ncores = nr_cpu_ids;
323 }
324
Jeff Ohlstein41ff4452011-04-07 17:41:09 -0700325 for (i = 0; i < ncores; i++)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800326 set_cpu_possible(i, true);
Russell King0f7b3322011-04-03 13:01:30 +0100327
Steve Mucklef132c6c2012-06-06 18:30:57 -0700328 set_smp_cross_call(gic_raise_softirq);
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800329}
330
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800331static void __init arm_smp_init_cpus(void)
332{
333 unsigned int i, ncores;
334
335 ncores = (__raw_readl(MSM_APCS_GCC_BASE + 0x30)) & 0xF;
336
337 if (ncores > nr_cpu_ids) {
338 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
339 ncores, nr_cpu_ids);
340 ncores = nr_cpu_ids;
341 }
342
343 for (i = 0; i < ncores; i++)
344 set_cpu_possible(i, true);
345
346 set_smp_cross_call(gic_raise_softirq);
347}
348
Stephen Boyd8699b372012-08-08 15:22:04 -0700349static int cold_boot_flags[] __initdata = {
350 0,
351 SCM_FLAG_COLDBOOT_CPU1,
352 SCM_FLAG_COLDBOOT_CPU2,
353 SCM_FLAG_COLDBOOT_CPU3,
354};
355
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800356static void __init msm_platform_smp_prepare_cpus(unsigned int max_cpus)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800357{
Stephen Boyd8699b372012-08-08 15:22:04 -0700358 int cpu, map;
359 unsigned int flags = 0;
360
361 for_each_present_cpu(cpu) {
362 map = cpu_logical_map(cpu);
363 if (map > ARRAY_SIZE(cold_boot_flags)) {
364 set_cpu_present(cpu, false);
365 __WARN();
366 continue;
367 }
368 flags |= cold_boot_flags[map];
369 }
370
371 if (scm_set_boot_addr(virt_to_phys(msm_secondary_startup), flags))
372 pr_warn("Failed to set CPU boot address\n");
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800373}
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800374
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800375struct smp_operations arm_smp_ops __initdata = {
376 .smp_init_cpus = arm_smp_init_cpus,
Syed Rameez Mustafa41504582013-01-25 20:28:16 -0800377 .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800378 .smp_secondary_init = platform_secondary_init,
379 .smp_boot_secondary = arm_boot_secondary,
380 .cpu_kill = platform_cpu_kill,
381 .cpu_die = platform_cpu_die,
382 .cpu_disable = platform_cpu_disable
383};
384
385struct smp_operations msm8974_smp_ops __initdata = {
386 .smp_init_cpus = msm_smp_init_cpus,
387 .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
388 .smp_secondary_init = platform_secondary_init,
389 .smp_boot_secondary = msm8974_boot_secondary,
390 .cpu_kill = platform_cpu_kill,
391 .cpu_die = platform_cpu_die,
392 .cpu_disable = platform_cpu_disable
393};
394
395struct smp_operations msm8960_smp_ops __initdata = {
396 .smp_init_cpus = msm_smp_init_cpus,
397 .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
398 .smp_secondary_init = platform_secondary_init,
399 .smp_boot_secondary = msm8960_boot_secondary,
400 .cpu_kill = platform_cpu_kill,
401 .cpu_die = platform_cpu_die,
402 .cpu_disable = platform_cpu_disable
403};
404
405struct smp_operations scorpion_smp_ops __initdata = {
406 .smp_init_cpus = msm_smp_init_cpus,
407 .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
408 .smp_secondary_init = platform_secondary_init,
409 .smp_boot_secondary = scorpion_boot_secondary,
410 .cpu_kill = platform_cpu_kill,
411 .cpu_die = platform_cpu_die,
412 .cpu_disable = platform_cpu_disable
413};