diff options
Diffstat (limited to 'arch/arm/mach-exynos/platsmp.c')
| -rw-r--r-- | arch/arm/mach-exynos/platsmp.c | 75 | 
1 files changed, 48 insertions, 27 deletions
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 58b43e6f926..50b9aad5e27 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -20,19 +20,15 @@  #include <linux/jiffies.h>  #include <linux/smp.h>  #include <linux/io.h> +#include <linux/of_address.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> -#include <mach/regs-pmu.h> - -#include <plat/cpu.h> -  #include "common.h" +#include "regs-pmu.h"  extern void exynos4_secondary_startup(void); @@ -40,7 +36,7 @@ static inline void __iomem *cpu_boot_reg_base(void)  {  	if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1)  		return S5P_INFORM5; -	return S5P_VA_SYSRAM; +	return sysram_base_addr;  }  static inline void __iomem *cpu_boot_reg(int cpu) @@ -48,9 +44,11 @@ static inline void __iomem *cpu_boot_reg(int cpu)  	void __iomem *boot_reg;  	boot_reg = cpu_boot_reg_base(); +	if (!boot_reg) +		return ERR_PTR(-ENODEV);  	if (soc_is_exynos4412())  		boot_reg += 4*cpu; -	else if (soc_is_exynos5420()) +	else if (soc_is_exynos5420() || soc_is_exynos5800())  		boot_reg += 4;  	return boot_reg;  } @@ -64,8 +62,7 @@ static void write_pen_release(int val)  {  	pen_release = val;  	smp_wmb(); -	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); -	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +	sync_cache_w(&pen_release);  }  static void __iomem *scu_base_addr(void) @@ -93,7 +90,9 @@ static void exynos_secondary_init(unsigned int cpu)  static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)  {  	unsigned long timeout; -	unsigned long phys_cpu = cpu_logical_map(cpu); +	u32 mpidr = cpu_logical_map(cpu); +	u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); +	int ret = -ENOSYS;  	/*  	 * Set synchronisation state between this boot processor @@ -106,20 +105,18 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)  	 * the holding pen - release it, then wait for it to flag  	 * that it has been released by resetting pen_release.  	 * -	 * Note that "pen_release" is the hardware CPU ID, whereas +	 * Note that "pen_release" is the hardware CPU core ID, whereas  	 * "cpu" is Linux's internal ID.  	 */ -	write_pen_release(phys_cpu); - -	if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) { -		__raw_writel(S5P_CORE_LOCAL_PWR_EN, -			     S5P_ARM_CORE1_CONFIGURATION); +	write_pen_release(core_id); +	if (!exynos_cpu_power_state(core_id)) { +		exynos_cpu_power_up(core_id);  		timeout = 10;  		/* wait max 10 ms until cpu1 is on */ -		while ((__raw_readl(S5P_ARM_CORE1_STATUS) -			& S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) { +		while (exynos_cpu_power_state(core_id) +		       != S5P_CORE_LOCAL_PWR_EN) {  			if (timeout-- == 0)  				break; @@ -150,10 +147,20 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)  		 * 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)); +		ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); +		if (ret && ret != -ENOSYS) +			goto fail; +		if (ret == -ENOSYS) { +			void __iomem *boot_reg = cpu_boot_reg(core_id); + +			if (IS_ERR(boot_reg)) { +				ret = PTR_ERR(boot_reg); +				goto fail; +			} +			__raw_writel(boot_addr, cpu_boot_reg(core_id)); +		} -		call_firmware_op(cpu_boot, phys_cpu); +		call_firmware_op(cpu_boot, core_id);  		arch_send_wakeup_ipi_mask(cpumask_of(cpu)); @@ -167,9 +174,10 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)  	 * now the secondary core is starting up let it run its  	 * calibrations, then wait for it to finish  	 */ +fail:  	spin_unlock(&boot_lock); -	return pen_release != -1 ? -ENOSYS : 0; +	return pen_release != -1 ? ret : 0;  }  /* @@ -206,6 +214,8 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)  {  	int i; +	exynos_sysram_init(); +  	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9)  		scu_enable(scu_base_addr()); @@ -219,14 +229,25 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)  	 * boot register if it fails.  	 */  	for (i = 1; i < max_cpus; ++i) { -		unsigned long phys_cpu;  		unsigned long boot_addr; +		u32 mpidr; +		u32 core_id; +		int ret; -		phys_cpu = cpu_logical_map(i); +		mpidr = cpu_logical_map(i); +		core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);  		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)); +		ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); +		if (ret && ret != -ENOSYS) +			break; +		if (ret == -ENOSYS) { +			void __iomem *boot_reg = cpu_boot_reg(core_id); + +			if (IS_ERR(boot_reg)) +				break; +			__raw_writel(boot_addr, cpu_boot_reg(core_id)); +		}  	}  }  | 
