diff options
-rw-r--r-- | arch/arm/mach-exynos4/hotplug.c | 13 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/include/mach/regs-pmu.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/platsmp.c | 30 |
3 files changed, 38 insertions, 6 deletions
diff --git a/arch/arm/mach-exynos4/hotplug.c b/arch/arm/mach-exynos4/hotplug.c index 2b5909e2ccd..7490789784c 100644 --- a/arch/arm/mach-exynos4/hotplug.c +++ b/arch/arm/mach-exynos4/hotplug.c @@ -13,9 +13,12 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/smp.h> +#include <linux/io.h> #include <asm/cacheflush.h> +#include <mach/regs-pmu.h> + extern volatile int pen_release; static inline void cpu_enter_lowpower(void) @@ -58,12 +61,12 @@ static inline void cpu_leave_lowpower(void) static inline void platform_do_lowpower(unsigned int cpu, int *spurious) { - /* - * there is no power-control hardware on this platform, so all - * we can do is put the core into WFI; this is safe as the calling - * code will have already disabled interrupts - */ for (;;) { + + /* make cpu1 to be turned off at next WFI command */ + if (cpu == 1) + __raw_writel(0, S5P_ARM_CORE1_CONFIGURATION); + /* * here's the WFI */ diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h index a9643371f8e..fa49bbb8e7b 100644 --- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h +++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h @@ -158,6 +158,7 @@ #define S5P_PMU_GPS_CONF S5P_PMUREG(0x3CE0) #define S5P_PMU_SATA_PHY_CONTROL_EN 0x1 +#define S5P_CORE_LOCAL_PWR_EN 0x3 #define S5P_INT_LOCAL_PWR_EN 0x7 #define S5P_CHECK_SLEEP 0x00000BAD diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c index a79863cb7f7..a7f312c1289 100644 --- a/arch/arm/mach-exynos4/platsmp.c +++ b/arch/arm/mach-exynos4/platsmp.c @@ -28,9 +28,12 @@ #include <mach/hardware.h> #include <mach/regs-clock.h> +#include <mach/regs-pmu.h> extern void exynos4_secondary_startup(void); +#define CPU1_BOOT_REG S5P_VA_SYSRAM + /* * control for which core is the next to come out of the secondary * boot "holding pen" @@ -125,16 +128,41 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) */ write_pen_release(cpu); + if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) { + __raw_writel(S5P_CORE_LOCAL_PWR_EN, + S5P_ARM_CORE1_CONFIGURATION); + + 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) { + if (timeout-- == 0) + break; + + mdelay(1); + } + + if (timeout == 0) { + printk(KERN_ERR "cpu1 power enable failed"); + spin_unlock(&boot_lock); + return -ETIMEDOUT; + } + } /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ - gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); + + __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), + CPU1_BOOT_REG); + gic_raise_softirq(cpumask_of(cpu), 1); + if (pen_release == -1) break; |