diff options
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t2.c | 34 | ||||
-rw-r--r-- | arch/arm/mach-tegra/headsmp.S | 8 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep-t2.S | 29 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep.h | 1 |
5 files changed, 61 insertions, 17 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t2.c b/arch/arm/mach-tegra/cpuidle-t2.c index 034c8bbce1a8..14fde6f7c4ab 100644 --- a/arch/arm/mach-tegra/cpuidle-t2.c +++ b/arch/arm/mach-tegra/cpuidle-t2.c @@ -71,6 +71,9 @@ static inline unsigned int time_to_bin(unsigned int time) #ifdef CONFIG_SMP +#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4C +#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 + static void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE); static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); static s64 tegra_cpu1_wake_by_time = LLONG_MAX; @@ -79,6 +82,7 @@ static int tegra2_reset_sleeping_cpu(int cpu) { int ret = 0; + BUG_ON(cpu == 0); BUG_ON(cpu == smp_processor_id()); tegra_pen_lock(); @@ -96,38 +100,51 @@ static void tegra2_wake_reset_cpu(int cpu) { u32 reg; + BUG_ON(cpu == 0); + BUG_ON(cpu == smp_processor_id()); + + tegra_pen_lock(); + + tegra2_cpu_clear_resettable(); + /* enable cpu clock on cpu */ reg = readl(clk_rst + 0x4c); - writel(reg & ~(1 << (8 + cpu)), clk_rst + 0x4c); + writel(reg & ~(1 << (8 + cpu)), + clk_rst + CLK_RST_CONTROLLER_CLK_CPU_CMPLX); /* take the CPU out of reset */ reg = 0x1111 << cpu; - writel(reg, clk_rst + 0x344); + writel(reg, clk_rst + + CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); /* unhalt the cpu */ flowctrl_writel(0, FLOW_CTRL_HALT_CPU(1)); + + tegra_pen_unlock(); } static int tegra2_reset_other_cpus(int cpu) { int i; - int abort = -1; + int ret = 0; + + BUG_ON(cpu != 0); for_each_online_cpu(i) { if (i != cpu) { if (tegra2_reset_sleeping_cpu(i)) { - abort = i; + ret = -EBUSY; break; } } } - if (abort >= 0) { + if (ret) { for_each_online_cpu(i) { - if (i != cpu && i < abort) + if (i != cpu) tegra2_wake_reset_cpu(i); } - return -EINVAL; + return ret; } return 0; @@ -249,6 +266,7 @@ static void tegra2_idle_lp2_cpu_1(struct cpuidle_device *dev, /* * Not enough time left to enter LP2 */ + tegra2_cpu_clear_resettable(); tegra_cpu_wfi(); return; } @@ -263,6 +281,8 @@ static void tegra2_idle_lp2_cpu_1(struct cpuidle_device *dev, tegra2_sleep_wfi(PLAT_PHYS_OFFSET - PAGE_OFFSET); + tegra2_cpu_clear_resettable(); + tegra_cpu1_wake_by_time = LLONG_MAX; tegra_twd_resume(&twd_context); diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index caf38171f03e..ec6d24169697 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -184,6 +184,14 @@ ENTRY(__tegra_cpu_reset_handler) bleq __die @ CPU not present (to OS) #endif +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + /* If CPU1, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ + mov32 r6, TEGRA_PMC_BASE + mov r0, #0 + cmp r10, #0 + strne r0, [r6, #PMC_SCRATCH41] +#endif + #ifdef CONFIG_PM_SLEEP /* Waking up from LP1? */ ldr r8, [r12, #RESET_DATA(MASK_LP1)] diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index d24b60586cf4..77e9d6ffeba8 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -470,7 +470,8 @@ void tegra_clear_cpu_in_lp2(int cpu) can't use used directly by cpumask_clear_cpu() because it uses LDREX/STREX which requires the addressed location to be inner cacheable and sharable which IRAM isn't. */ - *iram_cpu_lp2_mask = tegra_in_lp2; + writel(tegra_in_lp2.bits[0], iram_cpu_lp2_mask); + dsb(); spin_unlock(&tegra_lp2_lock); } @@ -487,7 +488,8 @@ bool tegra_set_cpu_in_lp2(int cpu) can't use used directly by cpumask_set_cpu() because it uses LDREX/STREX which requires the addressed location to be inner cacheable and sharable which IRAM isn't. */ - *iram_cpu_lp2_mask = tegra_in_lp2; + writel(tegra_in_lp2.bits[0], iram_cpu_lp2_mask); + dsb(); if ((cpu == 0) && cpumask_equal(&tegra_in_lp2, cpu_online_mask)) last_cpu = true; diff --git a/arch/arm/mach-tegra/sleep-t2.S b/arch/arm/mach-tegra/sleep-t2.S index 3144368c23f0..e4bf9223e635 100644 --- a/arch/arm/mach-tegra/sleep-t2.S +++ b/arch/arm/mach-tegra/sleep-t2.S @@ -107,8 +107,7 @@ ENTRY(tegra2_cpu_reset) cmp r0, #0 moveq pc, lr @ must not be called for CPU 0 - mov32 r3, TEGRA_PMC_VIRT - add r1, r3, #PMC_SCRATCH41 + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 mov r12, #CPU_RESETTABLE str r12, [r1] @@ -134,14 +133,26 @@ ENDPROC(tegra2_cpu_reset) #ifdef CONFIG_PM_SLEEP /* + * tegra2_cpu_clear_resettable(void) + * + * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when + * it is expected that the secondary CPU will be idle soon. + */ +ENTRY(tegra2_cpu_clear_resettable) + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r12, #CPU_NOT_RESETTABLE + str r12, [r1] + mov pc, lr +ENDPROC(tegra2_cpu_clear_resettable) + +/* * tegra2_cpu_set_resettable_soon(void) * * Called to set the "resettable soon" flag in PMC_SCRATCH41 when * it is expected that the secondary CPU will be idle soon. */ ENTRY(tegra2_cpu_set_resettable_soon) - mov32 r3, TEGRA_PMC_VIRT - add r1, r3, #PMC_SCRATCH41 + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 mov r12, #CPU_RESETTABLE_SOON str r12, [r1] mov pc, lr @@ -154,8 +165,7 @@ ENDPROC(tegra2_cpu_set_resettable_soon) * set because it is expected that the secondary CPU will be idle soon. */ ENTRY(tegra2_cpu_is_resettable_soon) - mov32 r3, TEGRA_PMC_VIRT - add r1, r3, #PMC_SCRATCH41 + mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 ldr r12, [r1] cmp r12, #CPU_RESETTABLE_SOON moveq r0, #1 @@ -189,13 +199,16 @@ ENTRY(tegra2_sleep_wfi) b tegra_cpu_save mov r11, r2 - mov32 r3, TEGRA_PMC_VIRT - add r0, r3, #PMC_SCRATCH41 + mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41 mov r3, #CPU_RESETTABLE str r3, [r0] bl tegra_cpu_wfi + mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41 + mov r3, #CPU_NOT_RESETTABLE + str r3, [r0] + /* * cpu may be reset while in wfi, which will return through * tegra_resume to tegra_cpu_resume_phys to tegra_cpu_resume diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h index fcc6503d7e64..8f9926fe7172 100644 --- a/arch/arm/mach-tegra/sleep.h +++ b/arch/arm/mach-tegra/sleep.h @@ -206,6 +206,7 @@ extern void tegra2_iram_end; int tegra2_cpu_is_resettable_soon(void); void tegra2_cpu_reset(int cpu); void tegra2_cpu_set_resettable_soon(void); +void tegra2_cpu_clear_resettable(void); void tegra2_sleep_core(unsigned long v2p); void tegra2_hotplug_shutdown(void); void tegra2_sleep_wfi(unsigned long v2p); |