diff options
Diffstat (limited to 'arch/arm/mach-exynos/platsmp.c')
-rw-r--r-- | arch/arm/mach-exynos/platsmp.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 95e04bd5813f..a0e8ff7758a4 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/cacheflush.h> | 24 | #include <asm/cacheflush.h> |
25 | #include <asm/smp_plat.h> | 25 | #include <asm/smp_plat.h> |
26 | #include <asm/smp_scu.h> | 26 | #include <asm/smp_scu.h> |
27 | #include <asm/firmware.h> | ||
27 | 28 | ||
28 | #include <mach/hardware.h> | 29 | #include <mach/hardware.h> |
29 | #include <mach/regs-clock.h> | 30 | #include <mach/regs-clock.h> |
@@ -137,10 +138,21 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct | |||
137 | 138 | ||
138 | timeout = jiffies + (1 * HZ); | 139 | timeout = jiffies + (1 * HZ); |
139 | while (time_before(jiffies, timeout)) { | 140 | while (time_before(jiffies, timeout)) { |
141 | unsigned long boot_addr; | ||
142 | |||
140 | smp_rmb(); | 143 | smp_rmb(); |
141 | 144 | ||
142 | __raw_writel(virt_to_phys(exynos4_secondary_startup), | 145 | boot_addr = virt_to_phys(exynos4_secondary_startup); |
143 | cpu_boot_reg(phys_cpu)); | 146 | |
147 | /* | ||
148 | * Try to set boot address using firmware first | ||
149 | * and fall back to boot register if it fails. | ||
150 | */ | ||
151 | if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr)) | ||
152 | __raw_writel(boot_addr, cpu_boot_reg(phys_cpu)); | ||
153 | |||
154 | call_firmware_op(cpu_boot, phys_cpu); | ||
155 | |||
144 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | 156 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); |
145 | 157 | ||
146 | if (pen_release == -1) | 158 | if (pen_release == -1) |
@@ -196,10 +208,20 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) | |||
196 | * system-wide flags register. The boot monitor waits | 208 | * system-wide flags register. The boot monitor waits |
197 | * until it receives a soft interrupt, and then the | 209 | * until it receives a soft interrupt, and then the |
198 | * secondary CPU branches to this address. | 210 | * secondary CPU branches to this address. |
211 | * | ||
212 | * Try using firmware operation first and fall back to | ||
213 | * boot register if it fails. | ||
199 | */ | 214 | */ |
200 | for (i = 1; i < max_cpus; ++i) | 215 | for (i = 1; i < max_cpus; ++i) { |
201 | __raw_writel(virt_to_phys(exynos4_secondary_startup), | 216 | unsigned long phys_cpu; |
202 | cpu_boot_reg(cpu_logical_map(i))); | 217 | unsigned long boot_addr; |
218 | |||
219 | phys_cpu = cpu_logical_map(i); | ||
220 | boot_addr = virt_to_phys(exynos4_secondary_startup); | ||
221 | |||
222 | if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr)) | ||
223 | __raw_writel(boot_addr, cpu_boot_reg(phys_cpu)); | ||
224 | } | ||
203 | } | 225 | } |
204 | 226 | ||
205 | struct smp_operations exynos_smp_ops __initdata = { | 227 | struct smp_operations exynos_smp_ops __initdata = { |