]>
Commit | Line | Data |
---|---|---|
65ebcc11 SK |
1 | /* |
2 | * arch/arm/mach-sti/platsmp.c | |
3 | * | |
4 | * Copyright (C) 2013 STMicroelectronics (R&D) Limited. | |
5 | * http://www.st.com | |
6 | * | |
7 | * Cloned from linux/arch/arm/mach-vexpress/platsmp.c | |
8 | * | |
9 | * Copyright (C) 2002 ARM Ltd. | |
10 | * All Rights Reserved | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License version 2 as | |
14 | * published by the Free Software Foundation. | |
15 | */ | |
16 | #include <linux/init.h> | |
17 | #include <linux/errno.h> | |
18 | #include <linux/delay.h> | |
19 | #include <linux/smp.h> | |
20 | #include <linux/io.h> | |
21 | #include <linux/of.h> | |
22 | #include <linux/of_address.h> | |
94a8cfce | 23 | #include <linux/memblock.h> |
65ebcc11 SK |
24 | |
25 | #include <asm/cacheflush.h> | |
26 | #include <asm/smp_plat.h> | |
27 | #include <asm/smp_scu.h> | |
28 | ||
29 | #include "smp.h" | |
30 | ||
8bd26e3a | 31 | static void write_pen_release(int val) |
65ebcc11 SK |
32 | { |
33 | pen_release = val; | |
34 | smp_wmb(); | |
f45913fd | 35 | sync_cache_w(&pen_release); |
65ebcc11 SK |
36 | } |
37 | ||
38 | static DEFINE_SPINLOCK(boot_lock); | |
39 | ||
7e4588e8 | 40 | static void sti_secondary_init(unsigned int cpu) |
65ebcc11 | 41 | { |
65ebcc11 SK |
42 | /* |
43 | * let the primary processor know we're out of the | |
44 | * pen, then head off into the C entry point | |
45 | */ | |
46 | write_pen_release(-1); | |
47 | ||
48 | /* | |
49 | * Synchronise with the boot thread. | |
50 | */ | |
51 | spin_lock(&boot_lock); | |
52 | spin_unlock(&boot_lock); | |
53 | } | |
54 | ||
7e4588e8 | 55 | static int sti_boot_secondary(unsigned int cpu, struct task_struct *idle) |
65ebcc11 SK |
56 | { |
57 | unsigned long timeout; | |
58 | ||
59 | /* | |
60 | * set synchronisation state between this boot processor | |
61 | * and the secondary one | |
62 | */ | |
63 | spin_lock(&boot_lock); | |
64 | ||
65 | /* | |
66 | * The secondary processor is waiting to be released from | |
67 | * the holding pen - release it, then wait for it to flag | |
68 | * that it has been released by resetting pen_release. | |
69 | * | |
70 | * Note that "pen_release" is the hardware CPU ID, whereas | |
71 | * "cpu" is Linux's internal ID. | |
72 | */ | |
73 | write_pen_release(cpu_logical_map(cpu)); | |
74 | ||
75 | /* | |
76 | * Send the secondary CPU a soft interrupt, thereby causing | |
77 | * it to jump to the secondary entrypoint. | |
78 | */ | |
79 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | |
80 | ||
81 | timeout = jiffies + (1 * HZ); | |
82 | while (time_before(jiffies, timeout)) { | |
83 | smp_rmb(); | |
84 | if (pen_release == -1) | |
85 | break; | |
86 | ||
87 | udelay(10); | |
88 | } | |
89 | ||
90 | /* | |
91 | * now the secondary core is starting up let it run its | |
92 | * calibrations, then wait for it to finish | |
93 | */ | |
94 | spin_unlock(&boot_lock); | |
95 | ||
96 | return pen_release != -1 ? -ENOSYS : 0; | |
97 | } | |
98 | ||
7e4588e8 | 99 | static void __init sti_smp_prepare_cpus(unsigned int max_cpus) |
65ebcc11 | 100 | { |
94a8cfce PG |
101 | struct device_node *np; |
102 | void __iomem *scu_base; | |
103 | u32 __iomem *cpu_strt_ptr; | |
104 | u32 release_phys; | |
105 | int cpu; | |
64fc2a94 | 106 | unsigned long entry_pa = __pa_symbol(sti_secondary_startup); |
94a8cfce PG |
107 | |
108 | np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); | |
109 | ||
65ebcc11 SK |
110 | if (np) { |
111 | scu_base = of_iomap(np, 0); | |
112 | scu_enable(scu_base); | |
113 | of_node_put(np); | |
114 | } | |
94a8cfce PG |
115 | |
116 | if (max_cpus <= 1) | |
117 | return; | |
118 | ||
119 | for_each_possible_cpu(cpu) { | |
120 | ||
121 | np = of_get_cpu_node(cpu, NULL); | |
122 | ||
123 | if (!np) | |
124 | continue; | |
125 | ||
126 | if (of_property_read_u32(np, "cpu-release-addr", | |
127 | &release_phys)) { | |
128 | pr_err("CPU %d: missing or invalid cpu-release-addr " | |
129 | "property\n", cpu); | |
130 | continue; | |
131 | } | |
132 | ||
133 | /* | |
134 | * holding pen is usually configured in SBC DMEM but can also be | |
135 | * in RAM. | |
136 | */ | |
137 | ||
138 | if (!memblock_is_memory(release_phys)) | |
139 | cpu_strt_ptr = | |
140 | ioremap(release_phys, sizeof(release_phys)); | |
141 | else | |
142 | cpu_strt_ptr = | |
143 | (u32 __iomem *)phys_to_virt(release_phys); | |
144 | ||
145 | __raw_writel(entry_pa, cpu_strt_ptr); | |
146 | ||
147 | /* | |
148 | * wmb so that data is actually written | |
149 | * before cache flush is done | |
150 | */ | |
151 | smp_wmb(); | |
152 | sync_cache_w(cpu_strt_ptr); | |
153 | ||
154 | if (!memblock_is_memory(release_phys)) | |
155 | iounmap(cpu_strt_ptr); | |
156 | } | |
65ebcc11 SK |
157 | } |
158 | ||
75305275 | 159 | const struct smp_operations sti_smp_ops __initconst = { |
65ebcc11 SK |
160 | .smp_prepare_cpus = sti_smp_prepare_cpus, |
161 | .smp_secondary_init = sti_secondary_init, | |
162 | .smp_boot_secondary = sti_boot_secondary, | |
163 | }; |