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