xref: /OK3568_Linux_fs/kernel/arch/arm/mach-spear/platsmp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * arch/arm/mach-spear13xx/platsmp.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * based upon linux/arch/arm/mach-realview/platsmp.c
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 2012 ST Microelectronics Ltd.
8*4882a593Smuzhiyun  * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/jiffies.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/smp.h>
15*4882a593Smuzhiyun #include <asm/cacheflush.h>
16*4882a593Smuzhiyun #include <asm/smp_scu.h>
17*4882a593Smuzhiyun #include <mach/spear.h>
18*4882a593Smuzhiyun #include "generic.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* XXX spear_pen_release is cargo culted code - DO NOT COPY XXX */
21*4882a593Smuzhiyun volatile int spear_pen_release = -1;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /*
24*4882a593Smuzhiyun  * XXX CARGO CULTED CODE - DO NOT COPY XXX
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * Write spear_pen_release in a way that is guaranteed to be visible to
27*4882a593Smuzhiyun  * all observers, irrespective of whether they're taking part in coherency
28*4882a593Smuzhiyun  * or not.  This is necessary for the hotplug code to work reliably.
29*4882a593Smuzhiyun  */
spear_write_pen_release(int val)30*4882a593Smuzhiyun static void spear_write_pen_release(int val)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	spear_pen_release = val;
33*4882a593Smuzhiyun 	smp_wmb();
34*4882a593Smuzhiyun 	sync_cache_w(&spear_pen_release);
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun static DEFINE_SPINLOCK(boot_lock);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun static void __iomem *scu_base = IOMEM(VA_SCU_BASE);
40*4882a593Smuzhiyun 
spear13xx_secondary_init(unsigned int cpu)41*4882a593Smuzhiyun static void spear13xx_secondary_init(unsigned int cpu)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	/*
44*4882a593Smuzhiyun 	 * let the primary processor know we're out of the
45*4882a593Smuzhiyun 	 * pen, then head off into the C entry point
46*4882a593Smuzhiyun 	 */
47*4882a593Smuzhiyun 	spear_write_pen_release(-1);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	/*
50*4882a593Smuzhiyun 	 * Synchronise with the boot thread.
51*4882a593Smuzhiyun 	 */
52*4882a593Smuzhiyun 	spin_lock(&boot_lock);
53*4882a593Smuzhiyun 	spin_unlock(&boot_lock);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
spear13xx_boot_secondary(unsigned int cpu,struct task_struct * idle)56*4882a593Smuzhiyun static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	unsigned long timeout;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	/*
61*4882a593Smuzhiyun 	 * set synchronisation state between this boot processor
62*4882a593Smuzhiyun 	 * and the secondary one
63*4882a593Smuzhiyun 	 */
64*4882a593Smuzhiyun 	spin_lock(&boot_lock);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/*
67*4882a593Smuzhiyun 	 * The secondary processor is waiting to be released from
68*4882a593Smuzhiyun 	 * the holding pen - release it, then wait for it to flag
69*4882a593Smuzhiyun 	 * that it has been released by resetting spear_pen_release.
70*4882a593Smuzhiyun 	 *
71*4882a593Smuzhiyun 	 * Note that "spear_pen_release" is the hardware CPU ID, whereas
72*4882a593Smuzhiyun 	 * "cpu" is Linux's internal ID.
73*4882a593Smuzhiyun 	 */
74*4882a593Smuzhiyun 	spear_write_pen_release(cpu);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	timeout = jiffies + (1 * HZ);
77*4882a593Smuzhiyun 	while (time_before(jiffies, timeout)) {
78*4882a593Smuzhiyun 		smp_rmb();
79*4882a593Smuzhiyun 		if (spear_pen_release == -1)
80*4882a593Smuzhiyun 			break;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 		udelay(10);
83*4882a593Smuzhiyun 	}
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	/*
86*4882a593Smuzhiyun 	 * now the secondary core is starting up let it run its
87*4882a593Smuzhiyun 	 * calibrations, then wait for it to finish
88*4882a593Smuzhiyun 	 */
89*4882a593Smuzhiyun 	spin_unlock(&boot_lock);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return spear_pen_release != -1 ? -ENOSYS : 0;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun  * Initialise the CPU possible map early - this describes the CPUs
96*4882a593Smuzhiyun  * which may be present or become present in the system.
97*4882a593Smuzhiyun  */
spear13xx_smp_init_cpus(void)98*4882a593Smuzhiyun static void __init spear13xx_smp_init_cpus(void)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	unsigned int i, ncores = scu_get_core_count(scu_base);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (ncores > nr_cpu_ids) {
103*4882a593Smuzhiyun 		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
104*4882a593Smuzhiyun 			ncores, nr_cpu_ids);
105*4882a593Smuzhiyun 		ncores = nr_cpu_ids;
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	for (i = 0; i < ncores; i++)
109*4882a593Smuzhiyun 		set_cpu_possible(i, true);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
spear13xx_smp_prepare_cpus(unsigned int max_cpus)112*4882a593Smuzhiyun static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	scu_enable(scu_base);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	/*
118*4882a593Smuzhiyun 	 * Write the address of secondary startup into the system-wide location
119*4882a593Smuzhiyun 	 * (presently it is in SRAM). The BootMonitor waits until it receives a
120*4882a593Smuzhiyun 	 * soft interrupt, and then the secondary CPU branches to this address.
121*4882a593Smuzhiyun 	 */
122*4882a593Smuzhiyun 	__raw_writel(__pa_symbol(spear13xx_secondary_startup), SYS_LOCATION);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun const struct smp_operations spear13xx_smp_ops __initconst = {
126*4882a593Smuzhiyun        .smp_init_cpus		= spear13xx_smp_init_cpus,
127*4882a593Smuzhiyun        .smp_prepare_cpus	= spear13xx_smp_prepare_cpus,
128*4882a593Smuzhiyun        .smp_secondary_init	= spear13xx_secondary_init,
129*4882a593Smuzhiyun        .smp_boot_secondary	= spear13xx_boot_secondary,
130*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
131*4882a593Smuzhiyun        .cpu_die			= spear13xx_cpu_die,
132*4882a593Smuzhiyun #endif
133*4882a593Smuzhiyun };
134