]> Pileus Git - ~andy/linux/blobdiff - arch/arm/mach-exynos/platsmp.c
Merge tag 'firmware-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[~andy/linux] / arch / arm / mach-exynos / platsmp.c
index 60f7c5be057d3c2440f7613b4ccdecd897753249..a0e8ff7758a4c055e16323364167cfeb8fcfe2ab 100644 (file)
 #include <linux/jiffies.h>
 #include <linux/smp.h>
 #include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
 
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_scu.h>
+#include <asm/firmware.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-clock.h>
@@ -75,13 +75,6 @@ static DEFINE_SPINLOCK(boot_lock);
 
 static void __cpuinit exynos_secondary_init(unsigned int cpu)
 {
-       /*
-        * if any interrupts are already enabled for the primary
-        * core (e.g. timer irq), then they will not have been enabled
-        * for us: do so
-        */
-       gic_secondary_init(0);
-
        /*
         * let the primary processor know we're out of the
         * pen, then head off into the C entry point
@@ -145,10 +138,21 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct
 
        timeout = jiffies + (1 * HZ);
        while (time_before(jiffies, timeout)) {
+               unsigned long boot_addr;
+
                smp_rmb();
 
-               __raw_writel(virt_to_phys(exynos4_secondary_startup),
-                                                       cpu_boot_reg(phys_cpu));
+               boot_addr = virt_to_phys(exynos4_secondary_startup);
+
+               /*
+                * Try to set boot address using firmware first
+                * and fall back to boot register if it fails.
+                */
+               if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr))
+                       __raw_writel(boot_addr, cpu_boot_reg(phys_cpu));
+
+               call_firmware_op(cpu_boot, phys_cpu);
+
                arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 
                if (pen_release == -1)
@@ -204,10 +208,20 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
         * system-wide flags register. The boot monitor waits
         * until it receives a soft interrupt, and then the
         * secondary CPU branches to this address.
+        *
+        * Try using firmware operation first and fall back to
+        * boot register if it fails.
         */
-       for (i = 1; i < max_cpus; ++i)
-               __raw_writel(virt_to_phys(exynos4_secondary_startup),
-                                       cpu_boot_reg(cpu_logical_map(i)));
+       for (i = 1; i < max_cpus; ++i) {
+               unsigned long phys_cpu;
+               unsigned long boot_addr;
+
+               phys_cpu = cpu_logical_map(i);
+               boot_addr = virt_to_phys(exynos4_secondary_startup);
+
+               if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr))
+                       __raw_writel(boot_addr, cpu_boot_reg(phys_cpu));
+       }
 }
 
 struct smp_operations exynos_smp_ops __initdata = {