summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/cpuidle-t2.c34
-rw-r--r--arch/arm/mach-tegra/headsmp.S8
-rw-r--r--arch/arm/mach-tegra/pm.c6
-rw-r--r--arch/arm/mach-tegra/sleep-t2.S29
-rw-r--r--arch/arm/mach-tegra/sleep.h1
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);