diff options
Diffstat (limited to 'arch/arm/mach-exynos/platsmp.c')
| -rw-r--r-- | arch/arm/mach-exynos/platsmp.c | 40 | 
1 files changed, 27 insertions, 13 deletions
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 60f7c5be057..a0e8ff7758a 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -20,11 +20,11 @@  #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> @@ -76,13 +76,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 = {  |