]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
ARM: tegra20: Store CPU "resettable" status in IRAM
authorDmitry Osipenko <digetx@gmail.com>
Thu, 15 Jan 2015 10:58:57 +0000 (13:58 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Jul 2015 16:45:40 +0000 (09:45 -0700)
commit 4d48edb3c3e1234d6b3fcdfb9ac24d7c6de449cb upstream.

Commit 7232398abc6a ("ARM: tegra: Convert PMC to a driver") changed tegra_resume()
location storing from late to early and, as a result, broke suspend on Tegra20.
PMC scratch register 41 is used by tegra LP1 resume code for retrieving stored
physical memory address of common resume function and in the same time used by
tegra20_cpu_shutdown() (shared by Tegra20 cpuidle driver and platform SMP code),
which is storing CPU1 "resettable" status. It implies strict order of scratch
register usage, otherwise resume function address is lost on Tegra20 after
disabling non-boot CPU's on suspend. Fix it by storing "resettable" status in
IRAM instead of PMC scratch register.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Fixes: 7232398abc6a (ARM: tegra: Convert PMC to a driver)
Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm/mach-tegra/cpuidle-tegra20.c
arch/arm/mach-tegra/reset-handler.S
arch/arm/mach-tegra/reset.h
arch/arm/mach-tegra/sleep-tegra20.S
arch/arm/mach-tegra/sleep.h

index 4f25a7c7ca0fed7b74c8aab8b0f4281021f9e175..a351eff089f33321cdf9d7bf620c1867095ab1fd 100644 (file)
@@ -35,6 +35,7 @@
 #include "iomap.h"
 #include "irq.h"
 #include "pm.h"
+#include "reset.h"
 #include "sleep.h"
 
 #ifdef CONFIG_PM_SLEEP
@@ -71,15 +72,13 @@ static struct cpuidle_driver tegra_idle_driver = {
 
 #ifdef CONFIG_PM_SLEEP
 #ifdef CONFIG_SMP
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-
 static int tegra20_reset_sleeping_cpu_1(void)
 {
        int ret = 0;
 
        tegra_pen_lock();
 
-       if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE)
+       if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE)
                tegra20_cpu_shutdown(1);
        else
                ret = -EINVAL;
index 71be4af5e975bec078508d1ea920568edf11b289..e3070fdab80b8b7481c0527e2d649ae7d664dc58 100644 (file)
@@ -169,10 +169,10 @@ after_errata:
        cmp     r6, #TEGRA20
        bne     1f
        /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
-       mov32   r5, TEGRA_PMC_BASE
-       mov     r0, #0
+       mov32   r5, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
+       mov     r0, #CPU_NOT_RESETTABLE
        cmp     r10, #0
-       strne   r0, [r5, #PMC_SCRATCH41]
+       strneb  r0, [r5, #__tegra20_cpu1_resettable_status_offset]
 1:
 #endif
 
@@ -281,6 +281,10 @@ __tegra_cpu_reset_handler_data:
        .rept   TEGRA_RESET_DATA_SIZE
        .long   0
        .endr
+       .globl  __tegra20_cpu1_resettable_status_offset
+       .equ    __tegra20_cpu1_resettable_status_offset, \
+                                       . - __tegra_cpu_reset_handler_start
+       .byte   0
        .align L1_CACHE_SHIFT
 
 ENTRY(__tegra_cpu_reset_handler_end)
index 76a93434c6ee07b8b2357761c7a18c1335e6039e..29c3dec0126a4105f97fd5f321017869880ad95c 100644 (file)
@@ -35,6 +35,7 @@ extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];
 
 void __tegra_cpu_reset_handler_start(void);
 void __tegra_cpu_reset_handler(void);
+void __tegra20_cpu1_resettable_status_offset(void);
 void __tegra_cpu_reset_handler_end(void);
 void tegra_secondary_startup(void);
 
@@ -47,6 +48,9 @@ void tegra_secondary_startup(void);
        (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
        ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
         (u32)__tegra_cpu_reset_handler_start)))
+#define tegra20_cpu1_resettable_status \
+       (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
+        (u32)__tegra20_cpu1_resettable_status_offset))
 #endif
 
 #define tegra_cpu_reset_handler_offset \
index be4bc5f853f5c370ed345bf135d1092b9e94e883..e6b684e14322cef21e44d1b660e4c6e8d0c7ec43 100644 (file)
@@ -97,9 +97,10 @@ ENDPROC(tegra20_hotplug_shutdown)
 ENTRY(tegra20_cpu_shutdown)
        cmp     r0, #0
        reteq   lr                      @ must not be called for CPU 0
-       mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+       mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
+       ldr     r2, =__tegra20_cpu1_resettable_status_offset
        mov     r12, #CPU_RESETTABLE
-       str     r12, [r1]
+       strb    r12, [r1, r2]
 
        cpu_to_halt_reg r1, r0
        ldr     r3, =TEGRA_FLOW_CTRL_VIRT
@@ -182,38 +183,41 @@ ENDPROC(tegra_pen_unlock)
 /*
  * tegra20_cpu_clear_resettable(void)
  *
- * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when
+ * Called to clear the "resettable soon" flag in IRAM variable when
  * it is expected that the secondary CPU will be idle soon.
  */
 ENTRY(tegra20_cpu_clear_resettable)
-       mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+       mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
+       ldr     r2, =__tegra20_cpu1_resettable_status_offset
        mov     r12, #CPU_NOT_RESETTABLE
-       str     r12, [r1]
+       strb    r12, [r1, r2]
        ret     lr
 ENDPROC(tegra20_cpu_clear_resettable)
 
 /*
  * tegra20_cpu_set_resettable_soon(void)
  *
- * Called to set the "resettable soon" flag in PMC_SCRATCH41 when
+ * Called to set the "resettable soon" flag in IRAM variable when
  * it is expected that the secondary CPU will be idle soon.
  */
 ENTRY(tegra20_cpu_set_resettable_soon)
-       mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+       mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
+       ldr     r2, =__tegra20_cpu1_resettable_status_offset
        mov     r12, #CPU_RESETTABLE_SOON
-       str     r12, [r1]
+       strb    r12, [r1, r2]
        ret     lr
 ENDPROC(tegra20_cpu_set_resettable_soon)
 
 /*
  * tegra20_cpu_is_resettable_soon(void)
  *
- * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been
+ * Returns true if the "resettable soon" flag in IRAM variable has been
  * set because it is expected that the secondary CPU will be idle soon.
  */
 ENTRY(tegra20_cpu_is_resettable_soon)
-       mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
-       ldr     r12, [r1]
+       mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
+       ldr     r2, =__tegra20_cpu1_resettable_status_offset
+       ldrb    r12, [r1, r2]
        cmp     r12, #CPU_RESETTABLE_SOON
        moveq   r0, #1
        movne   r0, #0
@@ -256,9 +260,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
        mov     r0, #TEGRA_FLUSH_CACHE_LOUIS
        bl      tegra_disable_clean_inv_dcache
 
-       mov32   r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
+       mov32   r0, TEGRA_IRAM_RESET_BASE_VIRT
+       ldr     r4, =__tegra20_cpu1_resettable_status_offset
        mov     r3, #CPU_RESETTABLE
-       str     r3, [r0]
+       strb    r3, [r0, r4]
 
        bl      tegra_cpu_do_idle
 
@@ -274,10 +279,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
 
        bl      tegra_pen_lock
 
-       mov32   r3, TEGRA_PMC_VIRT
-       add     r0, r3, #PMC_SCRATCH41
+       mov32   r0, TEGRA_IRAM_RESET_BASE_VIRT
+       ldr     r4, =__tegra20_cpu1_resettable_status_offset
        mov     r3, #CPU_NOT_RESETTABLE
-       str     r3, [r0]
+       strb    r3, [r0, r4]
 
        bl      tegra_pen_unlock
 
index 92d46ec1361abba6f8beb6130d753ea634c8933a..0d59360d891da8e244c81241f1cf39c96235919c 100644 (file)
@@ -18,6 +18,7 @@
 #define __MACH_TEGRA_SLEEP_H
 
 #include "iomap.h"
+#include "irammap.h"
 
 #define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
                                        + IO_CPU_VIRT)
@@ -29,6 +30,9 @@
                                        + IO_APB_VIRT)
 #define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
 
+#define TEGRA_IRAM_RESET_BASE_VIRT (IO_IRAM_VIRT + \
+                               TEGRA_IRAM_RESET_HANDLER_OFFSET)
+
 /* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
 #define PMC_SCRATCH37  0x130
 #define PMC_SCRATCH38  0x134