1/* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7#include <asm/macro.h> 8#include <asm-offsets.h> 9#include <asm/psci.h> 10#include <config.h> 11#include <linux/linkage.h> 12 13 .globl cpu_suspend 14 .globl cpu_do_suspend 15 .globl cpu_suspend_save 16 .globl cpu_resume 17 .globl cpu_do_resume 18 19/* 20 * int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) 21 * @arg will be passed to fn as argument 22 * return value: 0 - cpu resumed from suspended state. 23 * -1 - cpu not suspended. 24 */ 25ENTRY(cpu_suspend) 26 /* 27 * Save x8~x30(lr is x30, sp is x29), total (23 + 1 reserved)*8=192 28 */ 29 stp x29, lr, [sp, #-192]! 30 /* Reserve 8-byte after x8, just for offset with 16-byte aligned */ 31 str x8, [sp, #16] 32 stp x9, x10, [sp, #32] 33 stp x11, x12, [sp, #48] 34 stp x13, x14, [sp, #64] 35 stp x15, x16, [sp, #80] 36 stp x17, x18, [sp, #96] 37 stp x19, x20, [sp,#112] 38 stp x21, x22, [sp,#128] 39 stp x23, x24, [sp,#144] 40 stp x25, x26, [sp,#160] 41 stp x27, x28, [sp,#176] 42 43 mov x19, sp 44 mov x20, x0 45 mov x21, x1 46 47 /* Save arch specific suspend fn and arg to stack */ 48 sub sp, sp, #PM_CTX_SIZE 49 stp x0, x1, [sp, #-16]! 50 51 /* x18 is gd, save it to _suspend_gd !! */ 52 adr x0, _suspend_gd 53 str x18, [x0] 54 55 /* x0: pm_ctx; x1: sp where restore x8~x30 from */ 56 add x0, sp, #16 57 mov x1, x19 58 bl cpu_suspend_save 59 60 adr lr, aborted 61 /* Jump to arch specific suspend */ 62 mov x0, x20 63 br x21 64 65 /* Should never reach here, otherwise failed */ 66aborted: 67 /* cpu not suspended */ 68 add sp, sp, #(16 + PM_CTX_SIZE) 69 /* Return -1 to the caller */ 70 mov x0, #(-1) 71 72suspend_return: 73 ldr x8, [sp, #16] 74 ldp x9, x10, [sp, #32] 75 ldp x11, x12, [sp, #48] 76 ldp x13, x14, [sp, #64] 77 ldp x15, x16, [sp, #80] 78 ldp x17, x18, [sp, #96] 79 ldp x19, x20, [sp,#112] 80 ldp x21, x22, [sp,#128] 81 ldp x23, x24, [sp,#144] 82 ldp x25, x26, [sp,#160] 83 ldp x27, x28, [sp,#176] 84 ldp x29, lr, [sp], #192 85 ret 86ENDPROC(cpu_suspend) 87 88ENTRY(cpu_do_suspend) 89 /* 90 * Save temporary x2~x12, total: 11*8=88, maybe you need not so many 91 * registers now, but I save them for future extendion. 92 */ 93 stp x2, x3, [sp, #-88]! 94 stp x4, x5, [sp, #16] 95 stp x6, x7, [sp, #32] 96 stp x8, x9, [sp, #48] 97 stp x10, x11, [sp,#64] 98 str x12, [sp, #80] 99 100 /* 101 * Save core registers. 102 * 103 * Note: If you want to add/sub the register here, 104 * remember update suspend_regs[] of struct pm_ctx. 105 */ 106 mrs x2, vbar_el2 107 mrs x3, cptr_el2 108 mrs x4, ttbr0_el2 109 mrs x5, tcr_el2 110 mrs x6, mair_el2 111 mrs x7, cntvoff_el2 112 mrs x8, sctlr_el2 113 mrs x9, hcr_el2 114 mrs x10, daif 115 116 stp x2, x3, [x0, #0] 117 stp x4, x5, [x0, #16] 118 stp x6, x7, [x0, #32] 119 stp x8, x9, [x0, #48] 120 str x10, [x0, #64] 121 122 /* Restore temporary x2~x12 */ 123 ldp x4, x5, [sp, #16] 124 ldp x6, x7, [sp, #32] 125 ldp x8, x9, [sp, #48] 126 ldp x10, x11, [sp,#64] 127 ldr x12, [sp, #80] 128 ldp x2, x3, [sp], #88 129 ret 130ENDPROC(cpu_do_suspend) 131 132ENTRY(cpu_resume) 133 /* Disable interrupt */ 134 msr daifset, #0x03 135 136 /* Load gd !! */ 137 adr x1, _suspend_gd 138 ldr x2, [x1] 139 140 /* Get pm_ctx */ 141 add x2, x2, #PM_CTX_PHYS 142 ldr x0, [x2] 143 144 /* Need x0=x0-16, because cpu_do_resume needs it */ 145 ldp x1, lr, [x0], #16 146 mov sp, x1 147 ret 148ENDPROC(cpu_resume) 149 150/* 151 * void sm_do_cpu_do_resume(paddr suspend_regs) __noreturn; 152 * Restore the registers stored when cpu_do_suspend 153 * x0 points to the physical base address of the suspend_regs 154 * field of struct pm_ctx. 155 */ 156ENTRY(cpu_do_resume) 157 /* 158 * Invalidate local tlb entries before turning on MMU !!! 159 */ 160 tlbi alle2 161 dsb sy 162 isb 163 164 ldp x2, x3, [x0] 165 ldp x4, x5, [x0, #16] 166 ldp x6, x7, [x0, #32] 167 ldp x8, x9, [x0, #48] 168 ldp x10, x11, [x0, #64] 169 ldr x12, [x0, #80] 170 171 /* Restore core register */ 172 msr vbar_el2, x2 173 msr cptr_el2, x3 174 msr ttbr0_el2, x4 175 msr tcr_el2, x5 176 msr mair_el2, x6 177 msr cntvoff_el2, x7 178 msr hcr_el2, x9 179 180 /* Enable MMU here */ 181 msr sctlr_el2, x8 182 dsb sy 183 isb 184 185 /* resume interrupt */ 186 msr daif, x10 187 188 mov x0, #0 189 b suspend_return 190ENDPROC(cpu_do_resume) 191 192.align 3 193_suspend_gd: 194 .long 0x0 195 196