1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Low level suspend code for AM33XX SoCs 4 * 5 * Copyright (C) 2012-2018 Texas Instruments Incorporated - https://www.ti.com/ 6 * Dave Gerlach, Vaibhav Bedia 7 */ 8 9#include <linux/linkage.h> 10#include <linux/platform_data/pm33xx.h> 11#include <linux/ti-emif-sram.h> 12#include <asm/assembler.h> 13#include <asm/memory.h> 14 15#include "iomap.h" 16#include "cm33xx.h" 17#include "pm-asm-offsets.h" 18 19#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 0x00030000 20#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 0x0003 21#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 0x0002 22 23/* replicated define because linux/bitops.h cannot be included in assembly */ 24#define BIT(nr) (1 << (nr)) 25 26 .arm 27 .arch armv7-a 28 .align 3 29 30ENTRY(am33xx_do_wfi) 31 stmfd sp!, {r4 - r11, lr} @ save registers on stack 32 33 /* Save wfi_flags arg to data space */ 34 mov r4, r0 35 adr r3, am33xx_pm_ro_sram_data 36 ldr r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET] 37 str r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET] 38 39 /* Only flush cache is we know we are losing MPU context */ 40 tst r4, #WFI_FLAG_FLUSH_CACHE 41 beq cache_skip_flush 42 43 /* 44 * Flush all data from the L1 and L2 data cache before disabling 45 * SCTLR.C bit. 46 */ 47 ldr r1, kernel_flush 48 blx r1 49 50 /* 51 * Clear the SCTLR.C bit to prevent further data cache 52 * allocation. Clearing SCTLR.C would make all the data accesses 53 * strongly ordered and would not hit the cache. 54 */ 55 mrc p15, 0, r0, c1, c0, 0 56 bic r0, r0, #(1 << 2) @ Disable the C bit 57 mcr p15, 0, r0, c1, c0, 0 58 isb 59 60 /* 61 * Invalidate L1 and L2 data cache. 62 */ 63 ldr r1, kernel_flush 64 blx r1 65 66 adr r3, am33xx_pm_ro_sram_data 67 ldr r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET] 68 ldr r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET] 69 70cache_skip_flush: 71 /* Check if we want self refresh */ 72 tst r4, #WFI_FLAG_SELF_REFRESH 73 beq emif_skip_enter_sr 74 75 adr r9, am33xx_emif_sram_table 76 77 ldr r3, [r9, #EMIF_PM_ENTER_SR_OFFSET] 78 blx r3 79 80emif_skip_enter_sr: 81 /* Only necessary if PER is losing context */ 82 tst r4, #WFI_FLAG_SAVE_EMIF 83 beq emif_skip_save 84 85 ldr r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET] 86 blx r3 87 88emif_skip_save: 89 /* Only can disable EMIF if we have entered self refresh */ 90 tst r4, #WFI_FLAG_SELF_REFRESH 91 beq emif_skip_disable 92 93 /* Disable EMIF */ 94 ldr r1, virt_emif_clkctrl 95 ldr r2, [r1] 96 bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 97 str r2, [r1] 98 99 ldr r1, virt_emif_clkctrl 100wait_emif_disable: 101 ldr r2, [r1] 102 mov r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 103 cmp r2, r3 104 bne wait_emif_disable 105 106emif_skip_disable: 107 tst r4, #WFI_FLAG_WAKE_M3 108 beq wkup_m3_skip 109 110 /* 111 * For the MPU WFI to be registered as an interrupt 112 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set 113 * to DISABLED 114 */ 115 ldr r1, virt_mpu_clkctrl 116 ldr r2, [r1] 117 bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 118 str r2, [r1] 119 120wkup_m3_skip: 121 /* 122 * Execute an ISB instruction to ensure that all of the 123 * CP15 register changes have been committed. 124 */ 125 isb 126 127 /* 128 * Execute a barrier instruction to ensure that all cache, 129 * TLB and branch predictor maintenance operations issued 130 * have completed. 131 */ 132 dsb 133 dmb 134 135 /* 136 * Execute a WFI instruction and wait until the 137 * STANDBYWFI output is asserted to indicate that the 138 * CPU is in idle and low power state. CPU can specualatively 139 * prefetch the instructions so add NOPs after WFI. Thirteen 140 * NOPs as per Cortex-A8 pipeline. 141 */ 142 wfi 143 144 nop 145 nop 146 nop 147 nop 148 nop 149 nop 150 nop 151 nop 152 nop 153 nop 154 nop 155 nop 156 nop 157 158 /* We come here in case of an abort due to a late interrupt */ 159 160 /* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */ 161 ldr r1, virt_mpu_clkctrl 162 mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 163 str r2, [r1] 164 165 /* Re-enable EMIF */ 166 ldr r1, virt_emif_clkctrl 167 mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 168 str r2, [r1] 169wait_emif_enable: 170 ldr r3, [r1] 171 cmp r2, r3 172 bne wait_emif_enable 173 174 /* Only necessary if PER is losing context */ 175 tst r4, #WFI_FLAG_SELF_REFRESH 176 beq emif_skip_exit_sr_abt 177 178 adr r9, am33xx_emif_sram_table 179 ldr r1, [r9, #EMIF_PM_ABORT_SR_OFFSET] 180 blx r1 181 182emif_skip_exit_sr_abt: 183 tst r4, #WFI_FLAG_FLUSH_CACHE 184 beq cache_skip_restore 185 186 /* 187 * Set SCTLR.C bit to allow data cache allocation 188 */ 189 mrc p15, 0, r0, c1, c0, 0 190 orr r0, r0, #(1 << 2) @ Enable the C bit 191 mcr p15, 0, r0, c1, c0, 0 192 isb 193 194cache_skip_restore: 195 /* Let the suspend code know about the abort */ 196 mov r0, #1 197 ldmfd sp!, {r4 - r11, pc} @ restore regs and return 198ENDPROC(am33xx_do_wfi) 199 200 .align 201ENTRY(am33xx_resume_offset) 202 .word . - am33xx_do_wfi 203 204ENTRY(am33xx_resume_from_deep_sleep) 205 /* Re-enable EMIF */ 206 ldr r0, phys_emif_clkctrl 207 mov r1, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 208 str r1, [r0] 209wait_emif_enable1: 210 ldr r2, [r0] 211 cmp r1, r2 212 bne wait_emif_enable1 213 214 adr r9, am33xx_emif_sram_table 215 216 ldr r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET] 217 blx r1 218 219 ldr r1, [r9, #EMIF_PM_EXIT_SR_OFFSET] 220 blx r1 221 222resume_to_ddr: 223 /* We are back. Branch to the common CPU resume routine */ 224 mov r0, #0 225 ldr pc, resume_addr 226ENDPROC(am33xx_resume_from_deep_sleep) 227 228/* 229 * Local variables 230 */ 231 .align 232kernel_flush: 233 .word v7_flush_dcache_all 234virt_mpu_clkctrl: 235 .word AM33XX_CM_MPU_MPU_CLKCTRL 236virt_emif_clkctrl: 237 .word AM33XX_CM_PER_EMIF_CLKCTRL 238phys_emif_clkctrl: 239 .word (AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \ 240 AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET) 241 242.align 3 243/* DDR related defines */ 244am33xx_emif_sram_table: 245 .space EMIF_PM_FUNCTIONS_SIZE 246 247ENTRY(am33xx_pm_sram) 248 .word am33xx_do_wfi 249 .word am33xx_do_wfi_sz 250 .word am33xx_resume_offset 251 .word am33xx_emif_sram_table 252 .word am33xx_pm_ro_sram_data 253 254resume_addr: 255.word cpu_resume - PAGE_OFFSET + 0x80000000 256 257.align 3 258ENTRY(am33xx_pm_ro_sram_data) 259 .space AMX3_PM_RO_SRAM_DATA_SIZE 260 261ENTRY(am33xx_do_wfi_sz) 262 .word . - am33xx_do_wfi 263