1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * (C) Copyright 2017 Rockchip Electronics Co., Ltd. 3*4882a593Smuzhiyun * 4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+ 5*4882a593Smuzhiyun */ 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun#include <asm/arm32_macros.S> 8*4882a593Smuzhiyun#include <asm/macro.h> 9*4882a593Smuzhiyun#include <asm-offsets.h> 10*4882a593Smuzhiyun#include <asm/psci.h> 11*4882a593Smuzhiyun#include <config.h> 12*4882a593Smuzhiyun#include <linux/linkage.h> 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun .globl cpu_suspend 15*4882a593Smuzhiyun .globl cpu_do_suspend 16*4882a593Smuzhiyun .globl cpu_suspend_save 17*4882a593Smuzhiyun .globl cpu_resume 18*4882a593Smuzhiyun .globl cpu_do_resume 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun/* 21*4882a593Smuzhiyun * int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) 22*4882a593Smuzhiyun * @arg will be passed to fn as argument 23*4882a593Smuzhiyun * return value: 0 - cpu resumed from suspended state. 24*4882a593Smuzhiyun * -1 - cpu not suspended. 25*4882a593Smuzhiyun */ 26*4882a593SmuzhiyunENTRY(cpu_suspend) 27*4882a593Smuzhiyun push {r4 - r12, lr} 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun mov r5, sp 30*4882a593Smuzhiyun sub sp, sp, #PM_CTX_SIZE 31*4882a593Smuzhiyun push {r0, r1} 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun /* r9 is gd, save it to __suspend_gd !!! */ 34*4882a593Smuzhiyun adr r4, __suspend_gd 35*4882a593Smuzhiyun str r9, [r4] 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun mov r1, r5 38*4882a593Smuzhiyun add r0, sp, #8 39*4882a593Smuzhiyun blx cpu_suspend_save 40*4882a593Smuzhiyun 41*4882a593Smuzhiyun adr lr, aborted 42*4882a593Smuzhiyun /* Jump to arch specific suspend */ 43*4882a593Smuzhiyun pop {r0, pc} 44*4882a593Smuzhiyun 45*4882a593Smuzhiyunaborted: 46*4882a593Smuzhiyun /* cpu not suspended */ 47*4882a593Smuzhiyun add sp, sp, #PM_CTX_SIZE 48*4882a593Smuzhiyun /* Return -1 to the caller */ 49*4882a593Smuzhiyun mov r0, #(-1) 50*4882a593Smuzhiyun 51*4882a593Smuzhiyunsuspend_return: 52*4882a593Smuzhiyun pop {r4 - r12, pc} 53*4882a593SmuzhiyunENDPROC(cpu_suspend) 54*4882a593Smuzhiyun 55*4882a593SmuzhiyunENTRY(cpu_do_suspend) 56*4882a593Smuzhiyun push {r4 - r11} 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun read_midr r4 59*4882a593Smuzhiyun ubfx r5, r4, #4, #12 60*4882a593Smuzhiyun 61*4882a593Smuzhiyun ldr r4, CORTEX_A7_PART_NUM 62*4882a593Smuzhiyun cmp r5, r4 63*4882a593Smuzhiyun beq a7_suspend 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun ldr r4, CORTEX_A9_PART_NUM 66*4882a593Smuzhiyun cmp r5, r4 67*4882a593Smuzhiyun beq a9_suspend 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun b other_suspend 70*4882a593Smuzhiyun 71*4882a593Smuzhiyun /* A9 needs PCR/DIAG */ 72*4882a593Smuzhiyuna9_suspend: 73*4882a593Smuzhiyun read_pcr r4 74*4882a593Smuzhiyun read_diag r5 75*4882a593Smuzhiyun stmia r0!, {r4 - r5} 76*4882a593Smuzhiyun 77*4882a593Smuzhiyuna7_suspend: 78*4882a593Smuzhiyun read_fcseidr r4 79*4882a593Smuzhiyun read_tpidruro r5 80*4882a593Smuzhiyun stmia r0!, {r4 - r5} 81*4882a593Smuzhiyun 82*4882a593Smuzhiyunother_suspend: 83*4882a593Smuzhiyun read_dacr r4 84*4882a593Smuzhiyun read_ttbr0 r5 85*4882a593Smuzhiyun read_ttbr1 r6 86*4882a593Smuzhiyun read_ttbcr r7 87*4882a593Smuzhiyun read_sctlr r8 88*4882a593Smuzhiyun read_actlr r9 89*4882a593Smuzhiyun read_cpacr r10 90*4882a593Smuzhiyun stmia r0!, {r4 - r10} 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun read_prrr r4 93*4882a593Smuzhiyun read_nmrr r5 94*4882a593Smuzhiyun read_vbar r6 95*4882a593Smuzhiyun mrs r7, CPSR 96*4882a593Smuzhiyun stmia r0, {r4 - r7} 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun pop {r4 - r11} 99*4882a593Smuzhiyun bx lr 100*4882a593SmuzhiyunENDPROC(cpu_do_suspend) 101*4882a593Smuzhiyun 102*4882a593SmuzhiyunENTRY(cpu_resume) 103*4882a593Smuzhiyun /* Disable interrupt */ 104*4882a593Smuzhiyun cpsid aif 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun /* Load gd !! */ 107*4882a593Smuzhiyun adr r1, __suspend_gd 108*4882a593Smuzhiyun ldr r2, [r1] 109*4882a593Smuzhiyun 110*4882a593Smuzhiyun /* Get pm_ctx */ 111*4882a593Smuzhiyun add r2, r2, #PM_CTX_PHYS 112*4882a593Smuzhiyun ldr r0, [r2] 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun /* Need to use r0!, because cpu_do_resume needs it */ 115*4882a593Smuzhiyun ldmia r0!, {sp, pc} 116*4882a593SmuzhiyunENDPROC(cpu_resume) 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun/* 119*4882a593Smuzhiyun * void sm_do_cpu_do_resume(paddr suspend_regs) __noreturn; 120*4882a593Smuzhiyun * Restore the registers stored when cpu_do_suspend 121*4882a593Smuzhiyun * r0 points to the physical base address of the suspend_regs 122*4882a593Smuzhiyun * field of struct pm_ctx. 123*4882a593Smuzhiyun */ 124*4882a593SmuzhiyunENTRY(cpu_do_resume) 125*4882a593Smuzhiyun read_midr r4 126*4882a593Smuzhiyun ubfx r5, r4, #4, #12 127*4882a593Smuzhiyun 128*4882a593Smuzhiyun ldr r4, CORTEX_A9_PART_NUM 129*4882a593Smuzhiyun cmp r5, r4 130*4882a593Smuzhiyun beq a9_resume 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun ldr r4, CORTEX_A7_PART_NUM 133*4882a593Smuzhiyun cmp r5, r4 134*4882a593Smuzhiyun beq a7_resume 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun /* v7 resume */ 137*4882a593Smuzhiyun mov ip, #0 138*4882a593Smuzhiyun /* Invalidate icache to PoU */ 139*4882a593Smuzhiyun write_iciallu 140*4882a593Smuzhiyun /* set reserved context */ 141*4882a593Smuzhiyun write_contextidr ip 142*4882a593Smuzhiyun b other_resume 143*4882a593Smuzhiyun 144*4882a593Smuzhiyuna9_resume: 145*4882a593Smuzhiyun /* 146*4882a593Smuzhiyun * A9 needs PCR/DIAG 147*4882a593Smuzhiyun */ 148*4882a593Smuzhiyun ldmia r0!, {r4 - r5} 149*4882a593Smuzhiyun write_pcr r4 150*4882a593Smuzhiyun write_diag r5 151*4882a593Smuzhiyun 152*4882a593Smuzhiyuna7_resume: 153*4882a593Smuzhiyun /* v7 resume */ 154*4882a593Smuzhiyun mov ip, #0 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun /* Invalidate icache to PoU */ 157*4882a593Smuzhiyun write_iciallu 158*4882a593Smuzhiyun /* set reserved context */ 159*4882a593Smuzhiyun write_contextidr ip 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun ldmia r0!, {r4 - r5} 162*4882a593Smuzhiyun write_fcseidr r4 163*4882a593Smuzhiyun write_tpidruro r5 164*4882a593Smuzhiyun 165*4882a593Smuzhiyunother_resume: 166*4882a593Smuzhiyun ldmia r0!, {r4 - r10} 167*4882a593Smuzhiyun /* Invalidate entire TLB */ 168*4882a593Smuzhiyun write_tlbiall 169*4882a593Smuzhiyun write_dacr r4 170*4882a593Smuzhiyun write_ttbr0 r5 171*4882a593Smuzhiyun write_ttbr1 r6 172*4882a593Smuzhiyun write_ttbcr r7 173*4882a593Smuzhiyun 174*4882a593Smuzhiyun ldmia r0, {r4 - r7} 175*4882a593Smuzhiyun write_prrr r4 176*4882a593Smuzhiyun write_nmrr r5 177*4882a593Smuzhiyun write_vbar r6 178*4882a593Smuzhiyun 179*4882a593Smuzhiyun write_actlr r9 180*4882a593Smuzhiyun write_cpacr r10 181*4882a593Smuzhiyun write_bpiall 182*4882a593Smuzhiyun isb 183*4882a593Smuzhiyun dsb 184*4882a593Smuzhiyun 185*4882a593Smuzhiyun /* MMU will be enabled here */ 186*4882a593Smuzhiyun write_sctlr r8 187*4882a593Smuzhiyun isb 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun /* Restore interrupt */ 190*4882a593Smuzhiyun msr CPSR_c, r7 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun mov r0, #0 193*4882a593Smuzhiyun b suspend_return 194*4882a593SmuzhiyunENDPROC(cpu_do_resume) 195*4882a593Smuzhiyun 196*4882a593Smuzhiyun.align 4 197*4882a593Smuzhiyun__suspend_gd: 198*4882a593Smuzhiyun .word 0x0 199*4882a593SmuzhiyunCORTEX_A7_PART_NUM: 200*4882a593Smuzhiyun .word 0xC07 201*4882a593SmuzhiyunCORTEX_A9_PART_NUM: 202*4882a593Smuzhiyun .word 0xC09 203