18a94cd7eSDave Gerlach/* SPDX-License-Identifier: GPL-2.0 */ 28a94cd7eSDave Gerlach/* 38a94cd7eSDave Gerlach * Low level suspend code for AM33XX SoCs 48a94cd7eSDave Gerlach * 58a94cd7eSDave Gerlach * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ 68a94cd7eSDave Gerlach * Dave Gerlach, Vaibhav Bedia 78a94cd7eSDave Gerlach */ 88a94cd7eSDave Gerlach 941d9d44dSDave Gerlach#include <generated/ti-pm-asm-offsets.h> 108a94cd7eSDave Gerlach#include <linux/linkage.h> 1174655749SDave Gerlach#include <linux/platform_data/pm33xx.h> 128a94cd7eSDave Gerlach#include <linux/ti-emif-sram.h> 138a94cd7eSDave Gerlach#include <asm/assembler.h> 148a94cd7eSDave Gerlach#include <asm/memory.h> 158a94cd7eSDave Gerlach 168a94cd7eSDave Gerlach#include "iomap.h" 178a94cd7eSDave Gerlach#include "cm33xx.h" 188a94cd7eSDave Gerlach 198a94cd7eSDave Gerlach#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 0x00030000 208a94cd7eSDave Gerlach#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 0x0003 218a94cd7eSDave Gerlach#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 0x0002 228a94cd7eSDave Gerlach 2374655749SDave Gerlach/* replicated define because linux/bitops.h cannot be included in assembly */ 2474655749SDave Gerlach#define BIT(nr) (1 << (nr)) 2574655749SDave Gerlach 268a94cd7eSDave Gerlach .arm 278a94cd7eSDave Gerlach .align 3 288a94cd7eSDave Gerlach 298a94cd7eSDave GerlachENTRY(am33xx_do_wfi) 308a94cd7eSDave Gerlach stmfd sp!, {r4 - r11, lr} @ save registers on stack 318a94cd7eSDave Gerlach 3274655749SDave Gerlach /* Save wfi_flags arg to data space */ 3374655749SDave Gerlach mov r4, r0 3474655749SDave Gerlach adr r3, am33xx_pm_ro_sram_data 3574655749SDave Gerlach ldr r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET] 3674655749SDave Gerlach str r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET] 3774655749SDave Gerlach 3874655749SDave Gerlach /* Only flush cache is we know we are losing MPU context */ 3974655749SDave Gerlach tst r4, #WFI_FLAG_FLUSH_CACHE 4074655749SDave Gerlach beq cache_skip_flush 4174655749SDave Gerlach 428a94cd7eSDave Gerlach /* 438a94cd7eSDave Gerlach * Flush all data from the L1 and L2 data cache before disabling 448a94cd7eSDave Gerlach * SCTLR.C bit. 458a94cd7eSDave Gerlach */ 468a94cd7eSDave Gerlach ldr r1, kernel_flush 478a94cd7eSDave Gerlach blx r1 488a94cd7eSDave Gerlach 498a94cd7eSDave Gerlach /* 508a94cd7eSDave Gerlach * Clear the SCTLR.C bit to prevent further data cache 518a94cd7eSDave Gerlach * allocation. Clearing SCTLR.C would make all the data accesses 528a94cd7eSDave Gerlach * strongly ordered and would not hit the cache. 538a94cd7eSDave Gerlach */ 548a94cd7eSDave Gerlach mrc p15, 0, r0, c1, c0, 0 558a94cd7eSDave Gerlach bic r0, r0, #(1 << 2) @ Disable the C bit 568a94cd7eSDave Gerlach mcr p15, 0, r0, c1, c0, 0 578a94cd7eSDave Gerlach isb 588a94cd7eSDave Gerlach 598a94cd7eSDave Gerlach /* 608a94cd7eSDave Gerlach * Invalidate L1 and L2 data cache. 618a94cd7eSDave Gerlach */ 628a94cd7eSDave Gerlach ldr r1, kernel_flush 638a94cd7eSDave Gerlach blx r1 648a94cd7eSDave Gerlach 6574655749SDave Gerlach adr r3, am33xx_pm_ro_sram_data 6674655749SDave Gerlach ldr r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET] 6774655749SDave Gerlach ldr r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET] 6874655749SDave Gerlach 6974655749SDave Gerlachcache_skip_flush: 7074655749SDave Gerlach /* Check if we want self refresh */ 7174655749SDave Gerlach tst r4, #WFI_FLAG_SELF_REFRESH 7274655749SDave Gerlach beq emif_skip_enter_sr 7374655749SDave Gerlach 748a94cd7eSDave Gerlach adr r9, am33xx_emif_sram_table 758a94cd7eSDave Gerlach 768a94cd7eSDave Gerlach ldr r3, [r9, #EMIF_PM_ENTER_SR_OFFSET] 778a94cd7eSDave Gerlach blx r3 788a94cd7eSDave Gerlach 7974655749SDave Gerlachemif_skip_enter_sr: 8074655749SDave Gerlach /* Only necessary if PER is losing context */ 8174655749SDave Gerlach tst r4, #WFI_FLAG_SAVE_EMIF 8274655749SDave Gerlach beq emif_skip_save 8374655749SDave Gerlach 848a94cd7eSDave Gerlach ldr r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET] 858a94cd7eSDave Gerlach blx r3 868a94cd7eSDave Gerlach 8774655749SDave Gerlachemif_skip_save: 8874655749SDave Gerlach /* Only can disable EMIF if we have entered self refresh */ 8974655749SDave Gerlach tst r4, #WFI_FLAG_SELF_REFRESH 9074655749SDave Gerlach beq emif_skip_disable 9174655749SDave Gerlach 928a94cd7eSDave Gerlach /* Disable EMIF */ 938a94cd7eSDave Gerlach ldr r1, virt_emif_clkctrl 948a94cd7eSDave Gerlach ldr r2, [r1] 958a94cd7eSDave Gerlach bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 968a94cd7eSDave Gerlach str r2, [r1] 978a94cd7eSDave Gerlach 988a94cd7eSDave Gerlach ldr r1, virt_emif_clkctrl 998a94cd7eSDave Gerlachwait_emif_disable: 1008a94cd7eSDave Gerlach ldr r2, [r1] 1018a94cd7eSDave Gerlach mov r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 1028a94cd7eSDave Gerlach cmp r2, r3 1038a94cd7eSDave Gerlach bne wait_emif_disable 1048a94cd7eSDave Gerlach 10574655749SDave Gerlachemif_skip_disable: 10674655749SDave Gerlach tst r4, #WFI_FLAG_WAKE_M3 10774655749SDave Gerlach beq wkup_m3_skip 10874655749SDave Gerlach 1098a94cd7eSDave Gerlach /* 1108a94cd7eSDave Gerlach * For the MPU WFI to be registered as an interrupt 1118a94cd7eSDave Gerlach * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set 1128a94cd7eSDave Gerlach * to DISABLED 1138a94cd7eSDave Gerlach */ 1148a94cd7eSDave Gerlach ldr r1, virt_mpu_clkctrl 1158a94cd7eSDave Gerlach ldr r2, [r1] 1168a94cd7eSDave Gerlach bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 1178a94cd7eSDave Gerlach str r2, [r1] 1188a94cd7eSDave Gerlach 11974655749SDave Gerlachwkup_m3_skip: 1208a94cd7eSDave Gerlach /* 1218a94cd7eSDave Gerlach * Execute an ISB instruction to ensure that all of the 1228a94cd7eSDave Gerlach * CP15 register changes have been committed. 1238a94cd7eSDave Gerlach */ 1248a94cd7eSDave Gerlach isb 1258a94cd7eSDave Gerlach 1268a94cd7eSDave Gerlach /* 1278a94cd7eSDave Gerlach * Execute a barrier instruction to ensure that all cache, 1288a94cd7eSDave Gerlach * TLB and branch predictor maintenance operations issued 1298a94cd7eSDave Gerlach * have completed. 1308a94cd7eSDave Gerlach */ 1318a94cd7eSDave Gerlach dsb 1328a94cd7eSDave Gerlach dmb 1338a94cd7eSDave Gerlach 1348a94cd7eSDave Gerlach /* 1358a94cd7eSDave Gerlach * Execute a WFI instruction and wait until the 1368a94cd7eSDave Gerlach * STANDBYWFI output is asserted to indicate that the 1378a94cd7eSDave Gerlach * CPU is in idle and low power state. CPU can specualatively 1388a94cd7eSDave Gerlach * prefetch the instructions so add NOPs after WFI. Thirteen 1398a94cd7eSDave Gerlach * NOPs as per Cortex-A8 pipeline. 1408a94cd7eSDave Gerlach */ 1418a94cd7eSDave Gerlach wfi 1428a94cd7eSDave Gerlach 1438a94cd7eSDave Gerlach nop 1448a94cd7eSDave Gerlach nop 1458a94cd7eSDave Gerlach nop 1468a94cd7eSDave Gerlach nop 1478a94cd7eSDave Gerlach nop 1488a94cd7eSDave Gerlach nop 1498a94cd7eSDave Gerlach nop 1508a94cd7eSDave Gerlach nop 1518a94cd7eSDave Gerlach nop 1528a94cd7eSDave Gerlach nop 1538a94cd7eSDave Gerlach nop 1548a94cd7eSDave Gerlach nop 1558a94cd7eSDave Gerlach nop 1568a94cd7eSDave Gerlach 1578a94cd7eSDave Gerlach /* We come here in case of an abort due to a late interrupt */ 1588a94cd7eSDave Gerlach 1598a94cd7eSDave Gerlach /* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */ 1608a94cd7eSDave Gerlach ldr r1, virt_mpu_clkctrl 1618a94cd7eSDave Gerlach mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 1628a94cd7eSDave Gerlach str r2, [r1] 1638a94cd7eSDave Gerlach 1648a94cd7eSDave Gerlach /* Re-enable EMIF */ 1658a94cd7eSDave Gerlach ldr r1, virt_emif_clkctrl 1668a94cd7eSDave Gerlach mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 1678a94cd7eSDave Gerlach str r2, [r1] 1688a94cd7eSDave Gerlachwait_emif_enable: 1698a94cd7eSDave Gerlach ldr r3, [r1] 1708a94cd7eSDave Gerlach cmp r2, r3 1718a94cd7eSDave Gerlach bne wait_emif_enable 1728a94cd7eSDave Gerlach 17374655749SDave Gerlach /* Only necessary if PER is losing context */ 17474655749SDave Gerlach tst r4, #WFI_FLAG_SELF_REFRESH 17574655749SDave Gerlach beq emif_skip_exit_sr_abt 1768a94cd7eSDave Gerlach 17774655749SDave Gerlach adr r9, am33xx_emif_sram_table 1788a94cd7eSDave Gerlach ldr r1, [r9, #EMIF_PM_ABORT_SR_OFFSET] 1798a94cd7eSDave Gerlach blx r1 1808a94cd7eSDave Gerlach 18174655749SDave Gerlachemif_skip_exit_sr_abt: 18274655749SDave Gerlach tst r4, #WFI_FLAG_FLUSH_CACHE 18374655749SDave Gerlach beq cache_skip_restore 18474655749SDave Gerlach 1858a94cd7eSDave Gerlach /* 1868a94cd7eSDave Gerlach * Set SCTLR.C bit to allow data cache allocation 1878a94cd7eSDave Gerlach */ 1888a94cd7eSDave Gerlach mrc p15, 0, r0, c1, c0, 0 1898a94cd7eSDave Gerlach orr r0, r0, #(1 << 2) @ Enable the C bit 1908a94cd7eSDave Gerlach mcr p15, 0, r0, c1, c0, 0 1918a94cd7eSDave Gerlach isb 1928a94cd7eSDave Gerlach 19374655749SDave Gerlachcache_skip_restore: 1948a94cd7eSDave Gerlach /* Let the suspend code know about the abort */ 1958a94cd7eSDave Gerlach mov r0, #1 1968a94cd7eSDave Gerlach ldmfd sp!, {r4 - r11, pc} @ restore regs and return 1978a94cd7eSDave GerlachENDPROC(am33xx_do_wfi) 1988a94cd7eSDave Gerlach 1998a94cd7eSDave Gerlach .align 2008a94cd7eSDave GerlachENTRY(am33xx_resume_offset) 2018a94cd7eSDave Gerlach .word . - am33xx_do_wfi 2028a94cd7eSDave Gerlach 2038a94cd7eSDave GerlachENTRY(am33xx_resume_from_deep_sleep) 2048a94cd7eSDave Gerlach /* Re-enable EMIF */ 2058a94cd7eSDave Gerlach ldr r0, phys_emif_clkctrl 2068a94cd7eSDave Gerlach mov r1, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 2078a94cd7eSDave Gerlach str r1, [r0] 2088a94cd7eSDave Gerlachwait_emif_enable1: 2098a94cd7eSDave Gerlach ldr r2, [r0] 2108a94cd7eSDave Gerlach cmp r1, r2 2118a94cd7eSDave Gerlach bne wait_emif_enable1 2128a94cd7eSDave Gerlach 2138a94cd7eSDave Gerlach adr r9, am33xx_emif_sram_table 2148a94cd7eSDave Gerlach 2158a94cd7eSDave Gerlach ldr r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET] 2168a94cd7eSDave Gerlach blx r1 2178a94cd7eSDave Gerlach 2188a94cd7eSDave Gerlach ldr r1, [r9, #EMIF_PM_EXIT_SR_OFFSET] 2198a94cd7eSDave Gerlach blx r1 2208a94cd7eSDave Gerlach 2218a94cd7eSDave Gerlachresume_to_ddr: 2228a94cd7eSDave Gerlach /* We are back. Branch to the common CPU resume routine */ 2238a94cd7eSDave Gerlach mov r0, #0 2248a94cd7eSDave Gerlach ldr pc, resume_addr 2258a94cd7eSDave GerlachENDPROC(am33xx_resume_from_deep_sleep) 2268a94cd7eSDave Gerlach 2278a94cd7eSDave Gerlach/* 2288a94cd7eSDave Gerlach * Local variables 2298a94cd7eSDave Gerlach */ 2308a94cd7eSDave Gerlach .align 2318a94cd7eSDave Gerlachkernel_flush: 2328a94cd7eSDave Gerlach .word v7_flush_dcache_all 2338a94cd7eSDave Gerlachvirt_mpu_clkctrl: 2348a94cd7eSDave Gerlach .word AM33XX_CM_MPU_MPU_CLKCTRL 2358a94cd7eSDave Gerlachvirt_emif_clkctrl: 2368a94cd7eSDave Gerlach .word AM33XX_CM_PER_EMIF_CLKCTRL 2378a94cd7eSDave Gerlachphys_emif_clkctrl: 2388a94cd7eSDave Gerlach .word (AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \ 2398a94cd7eSDave Gerlach AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET) 2408a94cd7eSDave Gerlach 2418a94cd7eSDave Gerlach.align 3 2428a94cd7eSDave Gerlach/* DDR related defines */ 2438a94cd7eSDave Gerlacham33xx_emif_sram_table: 2448a94cd7eSDave Gerlach .space EMIF_PM_FUNCTIONS_SIZE 2458a94cd7eSDave Gerlach 2468a94cd7eSDave GerlachENTRY(am33xx_pm_sram) 2478a94cd7eSDave Gerlach .word am33xx_do_wfi 2488a94cd7eSDave Gerlach .word am33xx_do_wfi_sz 2498a94cd7eSDave Gerlach .word am33xx_resume_offset 2508a94cd7eSDave Gerlach .word am33xx_emif_sram_table 2518a94cd7eSDave Gerlach .word am33xx_pm_ro_sram_data 2528a94cd7eSDave Gerlach 2538c5a916fSKeerthyresume_addr: 2548c5a916fSKeerthy.word cpu_resume - PAGE_OFFSET + 0x80000000 2558c5a916fSKeerthy 2568a94cd7eSDave Gerlach.align 3 2578a94cd7eSDave GerlachENTRY(am33xx_pm_ro_sram_data) 2588a94cd7eSDave Gerlach .space AMX3_PM_RO_SRAM_DATA_SIZE 2598a94cd7eSDave Gerlach 2608a94cd7eSDave GerlachENTRY(am33xx_do_wfi_sz) 2618a94cd7eSDave Gerlach .word . - am33xx_do_wfi 262