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