Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: tegra: Add firmware calls required for suspend-resume on Tegra30

In order to suspend-resume CPU with Trusted Foundations firmware being
present on Tegra30, the LP1/LP2 boot vectors and CPU caches need to be
set up using the firmware calls and then suspend code shall avoid
re-disabling parts that were disabled by the firmware.

Tested-by: Robert Yang <decatf@gmail.com>
Tested-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Dmitry Osipenko and committed by
Thierry Reding
78ee399f dae84be5

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