18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/mach-tegra/sleep.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2011, NVIDIA Corporation. 68c2ecf20Sopenharmony_ci * Copyright (c) 2011, Google, Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Colin Cross <ccross@android.com> 98c2ecf20Sopenharmony_ci * Gary King <gking@nvidia.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/linkage.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/assembler.h> 158c2ecf20Sopenharmony_ci#include <asm/cache.h> 168c2ecf20Sopenharmony_ci#include <asm/cp15.h> 178c2ecf20Sopenharmony_ci#include <asm/hardware/cache-l2x0.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "iomap.h" 208c2ecf20Sopenharmony_ci#include "sleep.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define CLK_RESET_CCLK_BURST 0x20 238c2ecf20Sopenharmony_ci#define CLK_RESET_CCLK_DIVIDER 0x24 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * tegra_disable_clean_inv_dcache 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * disable, clean & invalidate the D-cache 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Corrupted registers: r1-r3, r6, r8, r9-r11 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ciENTRY(tegra_disable_clean_inv_dcache) 348c2ecf20Sopenharmony_ci stmfd sp!, {r0, r4-r5, r7, r9-r11, lr} 358c2ecf20Sopenharmony_ci dmb @ ensure ordering 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci /* Disable the D-cache */ 388c2ecf20Sopenharmony_ci mrc p15, 0, r2, c1, c0, 0 398c2ecf20Sopenharmony_ci tst r2, #CR_C @ see tegra_sleep_cpu() 408c2ecf20Sopenharmony_ci bic r2, r2, #CR_C 418c2ecf20Sopenharmony_ci mcrne p15, 0, r2, c1, c0, 0 428c2ecf20Sopenharmony_ci isb 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* Flush the D-cache */ 458c2ecf20Sopenharmony_ci cmp r0, #TEGRA_FLUSH_CACHE_ALL 468c2ecf20Sopenharmony_ci blne v7_flush_dcache_louis 478c2ecf20Sopenharmony_ci bleq v7_flush_dcache_all 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Trun off coherency */ 508c2ecf20Sopenharmony_ci exit_smp r4, r5 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci ldmfd sp!, {r0, r4-r5, r7, r9-r11, pc} 538c2ecf20Sopenharmony_ciENDPROC(tegra_disable_clean_inv_dcache) 548c2ecf20Sopenharmony_ci#endif 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * tegra_init_l2_for_a15 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * set up the correct L2 cache data RAM latency 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ciENTRY(tegra_init_l2_for_a15) 638c2ecf20Sopenharmony_ci mrc p15, 0, r0, c0, c0, 5 648c2ecf20Sopenharmony_ci ubfx r0, r0, #8, #4 658c2ecf20Sopenharmony_ci tst r0, #1 @ only need for cluster 0 668c2ecf20Sopenharmony_ci bne _exit_init_l2_a15 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci mrc p15, 0x1, r0, c9, c0, 2 698c2ecf20Sopenharmony_ci and r0, r0, #7 708c2ecf20Sopenharmony_ci cmp r0, #2 718c2ecf20Sopenharmony_ci bicne r0, r0, #7 728c2ecf20Sopenharmony_ci orrne r0, r0, #2 738c2ecf20Sopenharmony_ci mcrne p15, 0x1, r0, c9, c0, 2 748c2ecf20Sopenharmony_ci_exit_init_l2_a15: 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ret lr 778c2ecf20Sopenharmony_ciENDPROC(tegra_init_l2_for_a15) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * tegra_sleep_cpu_finish(unsigned long v2p) 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * enters suspend in LP2 by turning off the mmu and jumping to 838c2ecf20Sopenharmony_ci * tegra?_tear_down_cpu 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ciENTRY(tegra_sleep_cpu_finish) 868c2ecf20Sopenharmony_ci mov r4, r0 878c2ecf20Sopenharmony_ci /* Flush and disable the L1 data cache */ 888c2ecf20Sopenharmony_ci mov r0, #TEGRA_FLUSH_CACHE_ALL 898c2ecf20Sopenharmony_ci bl tegra_disable_clean_inv_dcache 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci mov r0, r4 928c2ecf20Sopenharmony_ci mov32 r6, tegra_tear_down_cpu 938c2ecf20Sopenharmony_ci ldr r1, [r6] 948c2ecf20Sopenharmony_ci add r1, r1, r0 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci mov32 r3, tegra_shut_off_mmu 978c2ecf20Sopenharmony_ci add r3, r3, r0 988c2ecf20Sopenharmony_ci mov r0, r1 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci ret r3 1018c2ecf20Sopenharmony_ciENDPROC(tegra_sleep_cpu_finish) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * tegra_shut_off_mmu 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * r0 = physical address to jump to with mmu off 1078c2ecf20Sopenharmony_ci * 1088c2ecf20Sopenharmony_ci * called with VA=PA mapping 1098c2ecf20Sopenharmony_ci * turns off MMU, icache, dcache and branch prediction 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci .align L1_CACHE_SHIFT 1128c2ecf20Sopenharmony_ci .pushsection .idmap.text, "ax" 1138c2ecf20Sopenharmony_ciENTRY(tegra_shut_off_mmu) 1148c2ecf20Sopenharmony_ci mrc p15, 0, r3, c1, c0, 0 1158c2ecf20Sopenharmony_ci movw r2, #CR_I | CR_Z | CR_C | CR_M 1168c2ecf20Sopenharmony_ci bic r3, r3, r2 1178c2ecf20Sopenharmony_ci dsb 1188c2ecf20Sopenharmony_ci mcr p15, 0, r3, c1, c0, 0 1198c2ecf20Sopenharmony_ci isb 1208c2ecf20Sopenharmony_ci#ifdef CONFIG_CACHE_L2X0 1218c2ecf20Sopenharmony_ci /* Disable L2 cache */ 1228c2ecf20Sopenharmony_ci check_cpu_part_num 0xc09, r9, r10 1238c2ecf20Sopenharmony_ci retne r0 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci mov32 r2, TEGRA_ARM_PERIF_BASE + 0x3000 1268c2ecf20Sopenharmony_ci ldr r3, [r2, #L2X0_CTRL] 1278c2ecf20Sopenharmony_ci tst r3, #L2X0_CTRL_EN @ see tegra_sleep_cpu() 1288c2ecf20Sopenharmony_ci mov r3, #0 1298c2ecf20Sopenharmony_ci strne r3, [r2, #L2X0_CTRL] 1308c2ecf20Sopenharmony_ci#endif 1318c2ecf20Sopenharmony_ci ret r0 1328c2ecf20Sopenharmony_ciENDPROC(tegra_shut_off_mmu) 1338c2ecf20Sopenharmony_ci .popsection 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * tegra_switch_cpu_to_pllp 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * In LP2 the normal cpu clock pllx will be turned off. Switch the CPU to pllp 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ciENTRY(tegra_switch_cpu_to_pllp) 1418c2ecf20Sopenharmony_ci /* in LP2 idle (SDRAM active), set the CPU burst policy to PLLP */ 1428c2ecf20Sopenharmony_ci mov32 r5, TEGRA_CLK_RESET_BASE 1438c2ecf20Sopenharmony_ci mov r0, #(2 << 28) @ burst policy = run mode 1448c2ecf20Sopenharmony_ci orr r0, r0, #(4 << 4) @ use PLLP in run mode burst 1458c2ecf20Sopenharmony_ci str r0, [r5, #CLK_RESET_CCLK_BURST] 1468c2ecf20Sopenharmony_ci mov r0, #0 1478c2ecf20Sopenharmony_ci str r0, [r5, #CLK_RESET_CCLK_DIVIDER] 1488c2ecf20Sopenharmony_ci ret lr 1498c2ecf20Sopenharmony_ciENDPROC(tegra_switch_cpu_to_pllp) 1508c2ecf20Sopenharmony_ci#endif 151