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