diff options
| -rw-r--r-- | arch/arm/mach-tegra/pm.c | 49 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/reset-handler.S | 26 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/sleep.S | 14 |
3 files changed, 84 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 1ad5719779b0..abf5f88778f4 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c | |||
| @@ -33,11 +33,13 @@ | |||
| 33 | #include <soc/tegra/pmc.h> | 33 | #include <soc/tegra/pmc.h> |
| 34 | 34 | ||
| 35 | #include <asm/cacheflush.h> | 35 | #include <asm/cacheflush.h> |
| 36 | #include <asm/firmware.h> | ||
| 36 | #include <asm/idmap.h> | 37 | #include <asm/idmap.h> |
| 37 | #include <asm/proc-fns.h> | 38 | #include <asm/proc-fns.h> |
| 38 | #include <asm/smp_plat.h> | 39 | #include <asm/smp_plat.h> |
| 39 | #include <asm/suspend.h> | 40 | #include <asm/suspend.h> |
| 40 | #include <asm/tlbflush.h> | 41 | #include <asm/tlbflush.h> |
| 42 | #include <asm/trusted_foundations.h> | ||
| 41 | 43 | ||
| 42 | #include "iomap.h" | 44 | #include "iomap.h" |
| 43 | #include "pm.h" | 45 | #include "pm.h" |
| @@ -159,6 +161,28 @@ int tegra_cpu_do_idle(void) | |||
| 159 | 161 | ||
| 160 | static int tegra_sleep_cpu(unsigned long v2p) | 162 | static int tegra_sleep_cpu(unsigned long v2p) |
| 161 | { | 163 | { |
| 164 | /* | ||
| 165 | * L2 cache disabling using kernel API only allowed when all | ||
| 166 | * secondary CPU's are offline. Cache have to be disabled with | ||
| 167 | * MMU-on if cache maintenance is done via Trusted Foundations | ||
| 168 | * firmware. Note that CPUIDLE won't ever enter powergate on Tegra30 | ||
| 169 | * if any of secondary CPU's is online and this is the LP2-idle | ||
| 170 | * code-path only for Tegra20/30. | ||
| 171 | */ | ||
| 172 | if (trusted_foundations_registered()) | ||
| 173 | outer_disable(); | ||
| 174 | |||
| 175 | /* | ||
| 176 | * Note that besides of setting up CPU reset vector this firmware | ||
| 177 | * call may also do the following, depending on the FW version: | ||
| 178 | * 1) Disable L2. But this doesn't matter since we already | ||
| 179 | * disabled the L2. | ||
| 180 | * 2) Disable D-cache. This need to be taken into account in | ||
| 181 | * particular by the tegra_disable_clean_inv_dcache() which | ||
| 182 | * shall avoid the re-disable. | ||
| 183 | */ | ||
| 184 | call_firmware_op(prepare_idle, TF_PM_MODE_LP2); | ||
| 185 | |||
| 162 | setup_mm_for_reboot(); | 186 | setup_mm_for_reboot(); |
| 163 | tegra_sleep_cpu_finish(v2p); | 187 | tegra_sleep_cpu_finish(v2p); |
| 164 | 188 | ||
| @@ -197,6 +221,14 @@ void tegra_idle_lp2_last(void) | |||
| 197 | 221 | ||
| 198 | cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); | 222 | cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); |
| 199 | 223 | ||
| 224 | /* | ||
| 225 | * Resume L2 cache if it wasn't re-enabled early during resume, | ||
| 226 | * which is the case for Tegra30 that has to re-enable the cache | ||
| 227 | * via firmware call. In other cases cache is already enabled and | ||
| 228 | * hence re-enabling is a no-op. This is always a no-op on Tegra114+. | ||
| 229 | */ | ||
| 230 | outer_resume(); | ||
| 231 | |||
| 200 | restore_cpu_complex(); | 232 | restore_cpu_complex(); |
| 201 | cpu_cluster_pm_exit(); | 233 | cpu_cluster_pm_exit(); |
| 202 | } | 234 | } |
| @@ -215,6 +247,15 @@ enum tegra_suspend_mode tegra_pm_validate_suspend_mode( | |||
| 215 | 247 | ||
| 216 | static int tegra_sleep_core(unsigned long v2p) | 248 | static int tegra_sleep_core(unsigned long v2p) |
| 217 | { | 249 | { |
| 250 | /* | ||
| 251 | * Cache have to be disabled with MMU-on if cache maintenance is done | ||
| 252 | * via Trusted Foundations firmware. This is a no-op on Tegra114+. | ||
| 253 | */ | ||
| 254 | if (trusted_foundations_registered()) | ||
| 255 | outer_disable(); | ||
| 256 | |||
| 257 | call_firmware_op(prepare_idle, TF_PM_MODE_LP1); | ||
| 258 | |||
| 218 | setup_mm_for_reboot(); | 259 | setup_mm_for_reboot(); |
| 219 | tegra_sleep_core_finish(v2p); | 260 | tegra_sleep_core_finish(v2p); |
| 220 | 261 | ||
| @@ -342,6 +383,14 @@ static int tegra_suspend_enter(suspend_state_t state) | |||
| 342 | 383 | ||
| 343 | cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, tegra_sleep_func); | 384 | cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, tegra_sleep_func); |
| 344 | 385 | ||
| 386 | /* | ||
| 387 | * Resume L2 cache if it wasn't re-enabled early during resume, | ||
| 388 | * which is the case for Tegra30 that has to re-enable the cache | ||
| 389 | * via firmware call. In other cases cache is already enabled and | ||
| 390 | * hence re-enabling is a no-op. | ||
| 391 | */ | ||
| 392 | outer_resume(); | ||
| 393 | |||
| 345 | switch (mode) { | 394 | switch (mode) { |
| 346 | case TEGRA_SUSPEND_LP1: | 395 | case TEGRA_SUSPEND_LP1: |
| 347 | tegra_suspend_exit_lp1(); | 396 | tegra_suspend_exit_lp1(); |
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index 31fb53f9ce13..cd94d7c41fc0 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <soc/tegra/flowctrl.h> | 20 | #include <soc/tegra/flowctrl.h> |
| 21 | #include <soc/tegra/fuse.h> | 21 | #include <soc/tegra/fuse.h> |
| 22 | 22 | ||
| 23 | #include <asm/assembler.h> | ||
| 23 | #include <asm/asm-offsets.h> | 24 | #include <asm/asm-offsets.h> |
| 24 | #include <asm/cache.h> | 25 | #include <asm/cache.h> |
| 25 | 26 | ||
| @@ -76,6 +77,7 @@ ENTRY(tegra_resume) | |||
| 76 | orr r1, r1, #1 | 77 | orr r1, r1, #1 |
| 77 | str r1, [r0] | 78 | str r1, [r0] |
| 78 | #endif | 79 | #endif |
| 80 | bl tegra_resume_trusted_foundations | ||
| 79 | 81 | ||
| 80 | #ifdef CONFIG_CACHE_L2X0 | 82 | #ifdef CONFIG_CACHE_L2X0 |
| 81 | /* L2 cache resume & re-enable */ | 83 | /* L2 cache resume & re-enable */ |
| @@ -88,6 +90,30 @@ end_ca9_scu_l2_resume: | |||
| 88 | 90 | ||
| 89 | b cpu_resume | 91 | b cpu_resume |
| 90 | ENDPROC(tegra_resume) | 92 | ENDPROC(tegra_resume) |
| 93 | |||
| 94 | /* | ||
| 95 | * tegra_resume_trusted_foundations | ||
| 96 | * | ||
| 97 | * Trusted Foundations firmware initialization. | ||
| 98 | * | ||
| 99 | * Doesn't return if firmware presents. | ||
| 100 | * Corrupted registers: r1, r2 | ||
| 101 | */ | ||
| 102 | ENTRY(tegra_resume_trusted_foundations) | ||
| 103 | /* Check whether Trusted Foundations firmware presents. */ | ||
| 104 | mov32 r2, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET | ||
| 105 | ldr r1, =__tegra_cpu_reset_handler_data_offset + \ | ||
| 106 | RESET_DATA(TF_PRESENT) | ||
| 107 | ldr r1, [r2, r1] | ||
| 108 | cmp r1, #0 | ||
| 109 | reteq lr | ||
| 110 | |||
| 111 | .arch_extension sec | ||
| 112 | /* First call after suspend wakes firmware. No arguments required. */ | ||
| 113 | smc #0 | ||
| 114 | |||
| 115 | b cpu_resume | ||
| 116 | ENDPROC(tegra_resume_trusted_foundations) | ||
| 91 | #endif | 117 | #endif |
| 92 | 118 | ||
| 93 | .align L1_CACHE_SHIFT | 119 | .align L1_CACHE_SHIFT |
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S index 5e3496753df1..1735ded5a812 100644 --- a/arch/arm/mach-tegra/sleep.S +++ b/arch/arm/mach-tegra/sleep.S | |||
| @@ -49,8 +49,9 @@ ENTRY(tegra_disable_clean_inv_dcache) | |||
| 49 | 49 | ||
| 50 | /* Disable the D-cache */ | 50 | /* Disable the D-cache */ |
| 51 | mrc p15, 0, r2, c1, c0, 0 | 51 | mrc p15, 0, r2, c1, c0, 0 |
| 52 | tst r2, #CR_C @ see tegra_sleep_cpu() | ||
| 52 | bic r2, r2, #CR_C | 53 | bic r2, r2, #CR_C |
| 53 | mcr p15, 0, r2, c1, c0, 0 | 54 | mcrne p15, 0, r2, c1, c0, 0 |
| 54 | isb | 55 | isb |
| 55 | 56 | ||
| 56 | /* Flush the D-cache */ | 57 | /* Flush the D-cache */ |
| @@ -132,10 +133,13 @@ ENTRY(tegra_shut_off_mmu) | |||
| 132 | #ifdef CONFIG_CACHE_L2X0 | 133 | #ifdef CONFIG_CACHE_L2X0 |
| 133 | /* Disable L2 cache */ | 134 | /* Disable L2 cache */ |
| 134 | check_cpu_part_num 0xc09, r9, r10 | 135 | check_cpu_part_num 0xc09, r9, r10 |
| 135 | movweq r2, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000) | 136 | retne r0 |
| 136 | movteq r2, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000) | 137 | |
| 137 | moveq r3, #0 | 138 | mov32 r2, TEGRA_ARM_PERIF_BASE + 0x3000 |
| 138 | streq r3, [r2, #L2X0_CTRL] | 139 | ldr r3, [r2, #L2X0_CTRL] |
| 140 | tst r3, #L2X0_CTRL_EN @ see tegra_sleep_cpu() | ||
| 141 | mov r3, #0 | ||
| 142 | strne r3, [r2, #L2X0_CTRL] | ||
| 139 | #endif | 143 | #endif |
| 140 | ret r0 | 144 | ret r0 |
| 141 | ENDPROC(tegra_shut_off_mmu) | 145 | ENDPROC(tegra_shut_off_mmu) |
