Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | /* SPDX-License-Identifier: GPL-2.0-only */ /* * OMAP44xx sleep code. * * Copyright (C) 2011 Texas Instruments, Inc. * Santosh Shilimkar <santosh.shilimkar@ti.com> */ #include <linux/linkage.h> #include <asm/assembler.h> #include <asm/smp_scu.h> #include <asm/memory.h> #include <asm/hardware/cache-l2x0.h> #include "omap-secure.h" #include "common.h" #include "omap44xx.h" #include "omap4-sar-layout.h" .arch armv7-a #if defined(CONFIG_SMP) && defined(CONFIG_PM) .arch_extension sec .macro DO_SMC dsb smc #0 dsb .endm #ifdef CONFIG_ARCH_OMAP4 /* * ============================= * == CPU suspend finisher == * ============================= * * void omap4_finish_suspend(unsigned long cpu_state) * * This function code saves the CPU context and performs the CPU * power down sequence. Calling WFI effectively changes the CPU * power domains states to the desired target power state. * * @cpu_state : contains context save state (r0) * 0 - No context lost * 1 - CPUx L1 and logic lost: MPUSS CSWR * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR * 3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF * @return: This function never returns for CPU OFF and DORMANT power states. * Post WFI, CPU transitions to DORMANT or OFF power state and on wake-up * from this follows a full CPU reset path via ROM code to CPU restore code. * The restore function pointer is stored at CPUx_WAKEUP_NS_PA_ADDR_OFFSET. * It returns to the caller for CPU INACTIVE and ON power states or in case * CPU failed to transition to targeted OFF/DORMANT state. * * omap4_finish_suspend() calls v7_flush_dcache_all() which doesn't save * stack frame and it expects the caller to take care of it. Hence the entire * stack frame is saved to avoid possible stack corruption. */ ENTRY(omap4_finish_suspend) stmfd sp!, {r4-r12, lr} cmp r0, #0x0 beq do_WFI @ No lowpower state, jump to WFI /* * Flush all data from the L1 data cache before disabling * SCTLR.C bit. */ bl omap4_get_sar_ram_base ldr r9, [r0, #OMAP_TYPE_OFFSET] cmp r9, #0x1 @ Check for HS device bne skip_secure_l1_clean mov r0, #SCU_PM_NORMAL mov r1, #0xFF @ clean seucre L1 stmfd r13!, {r4-r12, r14} ldr r12, =OMAP4_MON_SCU_PWR_INDEX DO_SMC ldmfd r13!, {r4-r12, r14} skip_secure_l1_clean: bl v7_flush_dcache_all /* * Clear the SCTLR.C bit to prevent further data cache * allocation. Clearing SCTLR.C would make all the data accesses * strongly ordered and would not hit the cache. */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #(1 << 2) @ Disable the C bit mcr p15, 0, r0, c1, c0, 0 isb bl v7_invalidate_l1 /* * Switch the CPU from Symmetric Multiprocessing (SMP) mode * to AsymmetricMultiprocessing (AMP) mode by programming * the SCU power status to DORMANT or OFF mode. * This enables the CPU to be taken out of coherency by * preventing the CPU from receiving cache, TLB, or BTB * maintenance operations broadcast by other CPUs in the cluster. */ bl omap4_get_sar_ram_base mov r8, r0 ldr r9, [r8, #OMAP_TYPE_OFFSET] cmp r9, #0x1 @ Check for HS device bne scu_gp_set mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR ands r0, r0, #0x0f ldreq r0, [r8, #SCU_OFFSET0] ldrne r0, [r8, #SCU_OFFSET1] mov r1, #0x00 stmfd r13!, {r4-r12, r14} ldr r12, =OMAP4_MON_SCU_PWR_INDEX DO_SMC ldmfd r13!, {r4-r12, r14} b skip_scu_gp_set scu_gp_set: mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR ands r0, r0, #0x0f ldreq r1, [r8, #SCU_OFFSET0] ldrne r1, [r8, #SCU_OFFSET1] bl omap4_get_scu_base bl scu_power_mode skip_scu_gp_set: mrc p15, 0, r0, c1, c1, 2 @ Read NSACR data tst r0, #(1 << 18) mrcne p15, 0, r0, c1, c0, 1 bicne r0, r0, #(1 << 6) @ Disable SMP bit mcrne p15, 0, r0, c1, c0, 1 isb dsb #ifdef CONFIG_CACHE_L2X0 /* * Clean and invalidate the L2 cache. * Common cache-l2x0.c functions can't be used here since it * uses spinlocks. We are out of coherency here with data cache * disabled. The spinlock implementation uses exclusive load/store * instruction which can fail without data cache being enabled. * OMAP4 hardware doesn't support exclusive monitor which can * overcome exclusive access issue. Because of this, CPU can * lead to deadlock. */ bl omap4_get_sar_ram_base mov r8, r0 mrc p15, 0, r5, c0, c0, 5 @ Read MPIDR ands r5, r5, #0x0f ldreq r0, [r8, #L2X0_SAVE_OFFSET0] @ Retrieve L2 state from SAR ldrne r0, [r8, #L2X0_SAVE_OFFSET1] @ memory. cmp r0, #3 bne do_WFI #ifdef CONFIG_PL310_ERRATA_727915 mov r0, #0x03 mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX DO_SMC #endif bl omap4_get_l2cache_base mov r2, r0 ldr r0, =0xffff str r0, [r2, #L2X0_CLEAN_INV_WAY] wait: ldr r0, [r2, #L2X0_CLEAN_INV_WAY] ldr r1, =0xffff ands r0, r0, r1 bne wait #ifdef CONFIG_PL310_ERRATA_727915 mov r0, #0x00 mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX DO_SMC #endif l2x_sync: bl omap4_get_l2cache_base mov r2, r0 mov r0, #0x0 str r0, [r2, #L2X0_CACHE_SYNC] sync: ldr r0, [r2, #L2X0_CACHE_SYNC] ands r0, r0, #0x1 bne sync #endif do_WFI: bl omap_do_wfi /* * CPU is here when it failed to enter OFF/DORMANT or * no low power state was attempted. */ mrc p15, 0, r0, c1, c0, 0 tst r0, #(1 << 2) @ Check C bit enabled? orreq r0, r0, #(1 << 2) @ Enable the C bit mcreq p15, 0, r0, c1, c0, 0 isb /* * Ensure the CPU power state is set to NORMAL in * SCU power state so that CPU is back in coherency. * In non-coherent mode CPU can lock-up and lead to * system deadlock. */ mrc p15, 0, r0, c1, c0, 1 tst r0, #(1 << 6) @ Check SMP bit enabled? orreq r0, r0, #(1 << 6) mcreq p15, 0, r0, c1, c0, 1 isb bl omap4_get_sar_ram_base mov r8, r0 ldr r9, [r8, #OMAP_TYPE_OFFSET] cmp r9, #0x1 @ Check for HS device bne scu_gp_clear mov r0, #SCU_PM_NORMAL mov r1, #0x00 stmfd r13!, {r4-r12, r14} ldr r12, =OMAP4_MON_SCU_PWR_INDEX DO_SMC ldmfd r13!, {r4-r12, r14} b skip_scu_gp_clear scu_gp_clear: bl omap4_get_scu_base mov r1, #SCU_PM_NORMAL bl scu_power_mode skip_scu_gp_clear: isb dsb ldmfd sp!, {r4-r12, pc} ENDPROC(omap4_finish_suspend) /* * ============================ * == CPU resume entry point == * ============================ * * void omap4_cpu_resume(void) * * ROM code jumps to this function while waking up from CPU * OFF or DORMANT state. Physical address of the function is * stored in the SAR RAM while entering to OFF or DORMANT mode. * The restore function pointer is stored at CPUx_WAKEUP_NS_PA_ADDR_OFFSET. */ ENTRY(omap4_cpu_resume) /* * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device. * OMAP44XX EMU/HS devices - CPU0 SMP bit access is enabled in PPA * init and for CPU1, a secure PPA API provided. CPU0 must be ON * while executing NS_SMP API on CPU1 and PPA version must be 1.4.0+. * OMAP443X GP devices- SMP bit isn't accessible. * OMAP446X GP devices - SMP bit access is enabled on both CPUs. */ ldr r8, =OMAP44XX_SAR_RAM_BASE ldr r9, [r8, #OMAP_TYPE_OFFSET] cmp r9, #0x1 @ Skip if GP device bne skip_ns_smp_enable mrc p15, 0, r0, c0, c0, 5 ands r0, r0, #0x0f beq skip_ns_smp_enable ppa_actrl_retry: mov r0, #OMAP4_PPA_CPU_ACTRL_SMP_INDEX adr r1, ppa_zero_params_offset ldr r3, [r1] add r3, r3, r1 @ Pointer to ppa_zero_params mov r1, #0x0 @ Process ID mov r2, #0x4 @ Flag mov r6, #0xff mov r12, #0x00 @ Secure Service ID DO_SMC cmp r0, #0x0 @ API returns 0 on success. beq enable_smp_bit b ppa_actrl_retry enable_smp_bit: mrc p15, 0, r0, c1, c0, 1 tst r0, #(1 << 6) @ Check SMP bit enabled? orreq r0, r0, #(1 << 6) mcreq p15, 0, r0, c1, c0, 1 isb skip_ns_smp_enable: #ifdef CONFIG_CACHE_L2X0 /* * Restore the L2 AUXCTRL and enable the L2 cache. * OMAP4_MON_L2X0_AUXCTRL_INDEX = Program the L2X0 AUXCTRL * OMAP4_MON_L2X0_CTRL_INDEX = Enable the L2 using L2X0 CTRL * register r0 contains value to be programmed. * L2 cache is already invalidate by ROM code as part * of MPUSS OFF wakeup path. */ ldr r2, =OMAP44XX_L2CACHE_BASE ldr r0, [r2, #L2X0_CTRL] and r0, #0x0f cmp r0, #1 beq skip_l2en @ Skip if already enabled ldr r3, =OMAP44XX_SAR_RAM_BASE ldr r1, [r3, #OMAP_TYPE_OFFSET] cmp r1, #0x1 @ Check for HS device bne set_gp_por ldr r0, =OMAP4_PPA_L2_POR_INDEX ldr r1, =OMAP44XX_SAR_RAM_BASE ldr r4, [r1, #L2X0_PREFETCH_CTRL_OFFSET] adr r1, ppa_por_params_offset ldr r3, [r1] add r3, r3, r1 @ Pointer to ppa_por_params str r4, [r3, #0x04] mov r1, #0x0 @ Process ID mov r2, #0x4 @ Flag mov r6, #0xff mov r12, #0x00 @ Secure Service ID DO_SMC b set_aux_ctrl set_gp_por: ldr r1, =OMAP44XX_SAR_RAM_BASE ldr r0, [r1, #L2X0_PREFETCH_CTRL_OFFSET] ldr r12, =OMAP4_MON_L2X0_PREFETCH_INDEX @ Setup L2 PREFETCH DO_SMC set_aux_ctrl: ldr r1, =OMAP44XX_SAR_RAM_BASE ldr r0, [r1, #L2X0_AUXCTRL_OFFSET] ldr r12, =OMAP4_MON_L2X0_AUXCTRL_INDEX @ Setup L2 AUXCTRL DO_SMC mov r0, #0x1 ldr r12, =OMAP4_MON_L2X0_CTRL_INDEX @ Enable L2 cache DO_SMC skip_l2en: #endif b cpu_resume @ Jump to generic resume ppa_por_params_offset: .long ppa_por_params - . ENDPROC(omap4_cpu_resume) #endif /* CONFIG_ARCH_OMAP4 */ #endif /* defined(CONFIG_SMP) && defined(CONFIG_PM) */ ENTRY(omap_do_wfi) stmfd sp!, {lr} #ifdef CONFIG_OMAP_INTERCONNECT_BARRIER /* Drain interconnect write buffers. */ bl omap_interconnect_sync #endif /* * Execute an ISB instruction to ensure that all of the * CP15 register changes have been committed. */ isb /* * Execute a barrier instruction to ensure that all cache, * TLB and branch predictor maintenance operations issued * by any CPU in the cluster have completed. */ dsb dmb /* * Execute a WFI instruction and wait until the * STANDBYWFI output is asserted to indicate that the * CPU is in idle and low power state. CPU can specualatively * prefetch the instructions so add NOPs after WFI. Sixteen * NOPs as per Cortex-A9 pipeline. */ wfi @ Wait For Interrupt nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop ldmfd sp!, {pc} ppa_zero_params_offset: .long ppa_zero_params - . ENDPROC(omap_do_wfi) .data .align 2 ppa_zero_params: .word 0 ppa_por_params: .word 1, 0 |