blob: b03452521faa90434384d167b68f6b874c43df3d [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
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -080038#define BOOT_REMAP_ENABLE 0x01
Steve Mucklef132c6c2012-06-06 18:30:57 -070039
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080040/*
41 * control for which core is the next to come out of the secondary
42 * boot "holding pen".
43 */
44volatile int pen_release = -1;
45
Stephen Boydf5e90822012-08-08 13:36:15 -070046/*
47 * Write pen_release in a way that is guaranteed to be visible to all
48 * observers, irrespective of whether they're taking part in coherency
49 * or not. This is necessary for the hotplug code to work reliably.
50 */
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -080051void __cpuinit write_pen_release(int val)
Stephen Boydf5e90822012-08-08 13:36:15 -070052{
53 pen_release = val;
54 smp_wmb();
55 __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
56 outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
57}
58
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080059static DEFINE_SPINLOCK(boot_lock);
60
61void __cpuinit platform_secondary_init(unsigned int cpu)
62{
Steve Mucklef132c6c2012-06-06 18:30:57 -070063 WARN_ON(msm_platform_secondary_init(cpu));
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080064
65 /*
66 * if any interrupts are already enabled for the primary
67 * core (e.g. timer irq), then they will not have been enabled
68 * for us: do so
69 */
70 gic_secondary_init(0);
71
72 /*
Stephen Boydf5e90822012-08-08 13:36:15 -070073 * let the primary processor know we're out of the
74 * pen, then head off into the C entry point
75 */
76 write_pen_release(-1);
77
78 /*
Jeff Ohlsteine14411d2010-11-30 13:06:36 -080079 * Synchronise with the boot thread.
80 */
81 spin_lock(&boot_lock);
82 spin_unlock(&boot_lock);
83}
84
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -080085static int __cpuinit release_secondary_sim(unsigned long base, int cpu)
86{
87 void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
88 if (!base_ptr)
89 return -ENODEV;
90
91 writel_relaxed(0x800, base_ptr+0x04);
92 writel_relaxed(0x3FFF, base_ptr+0x14);
93
94 mb();
95 iounmap(base_ptr);
96 return 0;
97}
98
Stepan Moskovchenko964e1032012-01-06 18:16:10 -080099static int __cpuinit scorpion_release_secondary(void)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800100{
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800101 void *base_ptr = ioremap_nocache(0x00902000, SZ_4K*2);
102 if (!base_ptr)
103 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104
Steve Mucklef132c6c2012-06-06 18:30:57 -0700105 writel_relaxed(0, base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800106 dmb();
Steve Mucklef132c6c2012-06-06 18:30:57 -0700107 writel_relaxed(0, base_ptr + SCSS_CPU1CORE_RESET);
108 writel_relaxed(3, base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP);
Stepan Moskovchenko964e1032012-01-06 18:16:10 -0800109 mb();
110 iounmap(base_ptr);
111
112 return 0;
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800113}
114
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800115static int __cpuinit msm8960_release_secondary(unsigned long base, 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 Mustafa9de46342012-11-30 11:00:08 -0800146static int __cpuinit msm8974_release_secondary(unsigned long base, int cpu)
Stepan Moskovchenko25173722012-08-09 13:43:02 -0700147{
148 void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
149 if (!base_ptr)
150 return -ENODEV;
151
Stepan Moskovchenko6b1d5df2012-08-11 22:33:20 -0700152 secondary_cpu_hs_init(base_ptr);
153
Stepan Moskovchenko25173722012-08-09 13:43:02 -0700154 writel_relaxed(0x021, base_ptr+0x04);
155 mb();
156 udelay(2);
157
158 writel_relaxed(0x020, base_ptr+0x04);
159 mb();
160 udelay(2);
161
162 writel_relaxed(0x000, base_ptr+0x04);
163 mb();
164
165 writel_relaxed(0x080, base_ptr+0x04);
166 mb();
167 iounmap(base_ptr);
168 return 0;
169}
170
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800171static int __cpuinit release_from_pen(unsigned int cpu)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800172{
173 unsigned long timeout;
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175 /* Set preset_lpj to avoid subsequent lpj recalculations */
176 preset_lpj = loops_per_jiffy;
177
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800178 /*
179 * set synchronisation state between this boot processor
180 * and the secondary one
181 */
182 spin_lock(&boot_lock);
183
184 /*
185 * The secondary processor is waiting to be released from
186 * the holding pen - release it, then wait for it to flag
187 * that it has been released by resetting pen_release.
188 *
189 * Note that "pen_release" is the hardware CPU ID, whereas
190 * "cpu" is Linux's internal ID.
191 */
Stephen Boydf5e90822012-08-08 13:36:15 -0700192 write_pen_release(cpu_logical_map(cpu));
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800193
194 /*
195 * Send the secondary CPU a soft interrupt, thereby causing
196 * the boot monitor to read the system wide flags register,
197 * and branch to the address found there.
198 */
Russell King0f7b3322011-04-03 13:01:30 +0100199 gic_raise_softirq(cpumask_of(cpu), 1);
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800200
201 timeout = jiffies + (1 * HZ);
202 while (time_before(jiffies, timeout)) {
203 smp_rmb();
204 if (pen_release == -1)
205 break;
206
207 udelay(10);
208 }
209
210 /*
211 * now the secondary core is starting up let it run its
212 * calibrations, then wait for it to finish
213 */
214 spin_unlock(&boot_lock);
215
216 return pen_release != -1 ? -ENOSYS : 0;
217}
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800218
219DEFINE_PER_CPU(int, cold_boot_done);
220
221int __cpuinit scorpion_boot_secondary(unsigned int cpu,
222 struct task_struct *idle)
223{
224 pr_debug("Starting secondary CPU %d\n", cpu);
225
226 if (per_cpu(cold_boot_done, cpu) == false) {
227 scorpion_release_secondary();
228 per_cpu(cold_boot_done, cpu) = true;
229 }
230 return release_from_pen(cpu);
231}
232
233int __cpuinit msm8960_boot_secondary(unsigned int cpu, struct task_struct *idle)
234{
235 pr_debug("Starting secondary CPU %d\n", cpu);
236
237 if (per_cpu(cold_boot_done, cpu) == false) {
238 msm8960_release_secondary(0x02088000, cpu);
239 per_cpu(cold_boot_done, cpu) = true;
240 }
241 return release_from_pen(cpu);
242}
243
244int __cpuinit msm8974_boot_secondary(unsigned int cpu, struct task_struct *idle)
245{
246 pr_debug("Starting secondary CPU %d\n", cpu);
247
248 if (per_cpu(cold_boot_done, cpu) == false) {
249 if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
250 release_secondary_sim(0xf9088000, cpu);
251 else if (machine_is_msm8974_rumi())
252 return 0;
253 else
254 msm8974_release_secondary(0xf9088000, cpu);
255
256 per_cpu(cold_boot_done, cpu) = true;
257 }
258 return release_from_pen(cpu);
259}
260
261int __cpuinit arm_boot_secondary(unsigned int cpu, struct task_struct *idle)
262{
263 pr_debug("Starting secondary CPU %d\n", cpu);
264
265 if (per_cpu(cold_boot_done, cpu) == false) {
Syed Rameez Mustafa3971c142013-01-09 19:04:53 -0800266 if (machine_is_msm8226_sim() || machine_is_msm8610_sim())
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800267 release_secondary_sim(0xf9088000, cpu);
268
269 per_cpu(cold_boot_done, cpu) = true;
270 }
271 return release_from_pen(cpu);
272}
273
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800274/*
275 * Initialise the CPU possible map early - this describes the CPUs
Steve Mucklef132c6c2012-06-06 18:30:57 -0700276 * which may be present or become present in the system.
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800277 */
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800278static void __init msm_smp_init_cpus(void)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800279{
Jeff Ohlstein41ff4452011-04-07 17:41:09 -0700280 unsigned int i, ncores = get_core_count();
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800281
Russell Kinga06f9162011-10-20 22:04:18 +0100282 if (ncores > nr_cpu_ids) {
283 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
284 ncores, nr_cpu_ids);
285 ncores = nr_cpu_ids;
286 }
287
Jeff Ohlstein41ff4452011-04-07 17:41:09 -0700288 for (i = 0; i < ncores; i++)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800289 set_cpu_possible(i, true);
Russell King0f7b3322011-04-03 13:01:30 +0100290
Steve Mucklef132c6c2012-06-06 18:30:57 -0700291 set_smp_cross_call(gic_raise_softirq);
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800292}
293
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800294static void __init arm_smp_init_cpus(void)
295{
296 unsigned int i, ncores;
297
298 ncores = (__raw_readl(MSM_APCS_GCC_BASE + 0x30)) & 0xF;
299
300 if (ncores > nr_cpu_ids) {
301 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
302 ncores, nr_cpu_ids);
303 ncores = nr_cpu_ids;
304 }
305
306 for (i = 0; i < ncores; i++)
307 set_cpu_possible(i, true);
308
309 set_smp_cross_call(gic_raise_softirq);
310}
311
Stephen Boyd8699b372012-08-08 15:22:04 -0700312static int cold_boot_flags[] __initdata = {
313 0,
314 SCM_FLAG_COLDBOOT_CPU1,
315 SCM_FLAG_COLDBOOT_CPU2,
316 SCM_FLAG_COLDBOOT_CPU3,
317};
318
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800319static void __init msm_platform_smp_prepare_cpus(unsigned int max_cpus)
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800320{
Stephen Boyd8699b372012-08-08 15:22:04 -0700321 int cpu, map;
322 unsigned int flags = 0;
323
324 for_each_present_cpu(cpu) {
325 map = cpu_logical_map(cpu);
326 if (map > ARRAY_SIZE(cold_boot_flags)) {
327 set_cpu_present(cpu, false);
328 __WARN();
329 continue;
330 }
331 flags |= cold_boot_flags[map];
332 }
333
334 if (scm_set_boot_addr(virt_to_phys(msm_secondary_startup), flags))
335 pr_warn("Failed to set CPU boot address\n");
Jeff Ohlsteine14411d2010-11-30 13:06:36 -0800336}
Syed Rameez Mustafa9de46342012-11-30 11:00:08 -0800337
338static void __init arm_platform_smp_prepare_cpus(unsigned int max_cpus)
339{
340 void *remap_ptr = ioremap_nocache(0xF9010000, SZ_4K);
341 if (!remap_ptr) {
342 pr_err("Failed to ioremap for secondary cores\n");
343 return;
344 }
345
346 /*
347 * Write the address of secondary startup into boot remapper
348 * register and enable boot remapping.
349 */
350 __raw_writel((virt_to_phys(msm_secondary_startup)|BOOT_REMAP_ENABLE),
351 (remap_ptr + 0x4));
352 mb();
353 iounmap(remap_ptr);
354}
355
356struct smp_operations arm_smp_ops __initdata = {
357 .smp_init_cpus = arm_smp_init_cpus,
358 .smp_prepare_cpus = arm_platform_smp_prepare_cpus,
359 .smp_secondary_init = platform_secondary_init,
360 .smp_boot_secondary = arm_boot_secondary,
361 .cpu_kill = platform_cpu_kill,
362 .cpu_die = platform_cpu_die,
363 .cpu_disable = platform_cpu_disable
364};
365
366struct smp_operations msm8974_smp_ops __initdata = {
367 .smp_init_cpus = msm_smp_init_cpus,
368 .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
369 .smp_secondary_init = platform_secondary_init,
370 .smp_boot_secondary = msm8974_boot_secondary,
371 .cpu_kill = platform_cpu_kill,
372 .cpu_die = platform_cpu_die,
373 .cpu_disable = platform_cpu_disable
374};
375
376struct smp_operations msm8960_smp_ops __initdata = {
377 .smp_init_cpus = msm_smp_init_cpus,
378 .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
379 .smp_secondary_init = platform_secondary_init,
380 .smp_boot_secondary = msm8960_boot_secondary,
381 .cpu_kill = platform_cpu_kill,
382 .cpu_die = platform_cpu_die,
383 .cpu_disable = platform_cpu_disable
384};
385
386struct smp_operations scorpion_smp_ops __initdata = {
387 .smp_init_cpus = msm_smp_init_cpus,
388 .smp_prepare_cpus = msm_platform_smp_prepare_cpus,
389 .smp_secondary_init = platform_secondary_init,
390 .smp_boot_secondary = scorpion_boot_secondary,
391 .cpu_kill = platform_cpu_kill,
392 .cpu_die = platform_cpu_die,
393 .cpu_disable = platform_cpu_disable
394};