154925552SJoseph Chen/* 254925552SJoseph Chen * (C) Copyright 2017 Rockchip Electronics Co., Ltd. 354925552SJoseph Chen * 454925552SJoseph Chen * SPDX-License-Identifier: GPL-2.0+ 554925552SJoseph Chen */ 654925552SJoseph Chen 754925552SJoseph Chen#include <asm/arm32_macros.S> 854925552SJoseph Chen#include <asm/macro.h> 954925552SJoseph Chen#include <asm-offsets.h> 1054925552SJoseph Chen#include <asm/psci.h> 1154925552SJoseph Chen#include <config.h> 1254925552SJoseph Chen#include <linux/linkage.h> 1354925552SJoseph Chen 1454925552SJoseph Chen .globl cpu_suspend 1554925552SJoseph Chen .globl cpu_do_suspend 1654925552SJoseph Chen .globl cpu_suspend_save 1754925552SJoseph Chen .globl cpu_resume 1854925552SJoseph Chen .globl cpu_do_resume 1954925552SJoseph Chen 2054925552SJoseph Chen/* 2154925552SJoseph Chen * int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) 2254925552SJoseph Chen * @arg will be passed to fn as argument 2354925552SJoseph Chen * return value: 0 - cpu resumed from suspended state. 2454925552SJoseph Chen * -1 - cpu not suspended. 2554925552SJoseph Chen */ 2654925552SJoseph ChenENTRY(cpu_suspend) 2754925552SJoseph Chen push {r4 - r12, lr} 2854925552SJoseph Chen 2954925552SJoseph Chen mov r5, sp 3054925552SJoseph Chen sub sp, sp, #PM_CTX_SIZE 3154925552SJoseph Chen push {r0, r1} 3254925552SJoseph Chen 33abf4f551SJoseph Chen /* r9 is gd, save it to __suspend_gd !!! */ 34abf4f551SJoseph Chen adr r4, __suspend_gd 3554925552SJoseph Chen str r9, [r4] 3654925552SJoseph Chen 3754925552SJoseph Chen mov r1, r5 3854925552SJoseph Chen add r0, sp, #8 3954925552SJoseph Chen blx cpu_suspend_save 4054925552SJoseph Chen 4154925552SJoseph Chen adr lr, aborted 4254925552SJoseph Chen /* Jump to arch specific suspend */ 4354925552SJoseph Chen pop {r0, pc} 4454925552SJoseph Chen 4554925552SJoseph Chenaborted: 4654925552SJoseph Chen /* cpu not suspended */ 4754925552SJoseph Chen add sp, sp, #PM_CTX_SIZE 4854925552SJoseph Chen /* Return -1 to the caller */ 4954925552SJoseph Chen mov r0, #(-1) 5054925552SJoseph Chen 5154925552SJoseph Chensuspend_return: 5254925552SJoseph Chen pop {r4 - r12, pc} 5354925552SJoseph ChenENDPROC(cpu_suspend) 5454925552SJoseph Chen 5554925552SJoseph ChenENTRY(cpu_do_suspend) 5654925552SJoseph Chen push {r4 - r11} 5754925552SJoseph Chen 5854925552SJoseph Chen read_midr r4 5954925552SJoseph Chen ubfx r5, r4, #4, #12 60*a059684bSJoseph Chen 6154925552SJoseph Chen ldr r4, CORTEX_A7_PART_NUM 6254925552SJoseph Chen cmp r5, r4 6354925552SJoseph Chen beq a7_suspend 64*a059684bSJoseph Chen 6554925552SJoseph Chen ldr r4, CORTEX_A9_PART_NUM 6654925552SJoseph Chen cmp r5, r4 6754925552SJoseph Chen beq a9_suspend 6854925552SJoseph Chen 69*a059684bSJoseph Chen b other_suspend 7054925552SJoseph Chen 7154925552SJoseph Chen /* A9 needs PCR/DIAG */ 7254925552SJoseph Chena9_suspend: 7354925552SJoseph Chen read_pcr r4 7454925552SJoseph Chen read_diag r5 7554925552SJoseph Chen stmia r0!, {r4 - r5} 7654925552SJoseph Chen 7754925552SJoseph Chena7_suspend: 7854925552SJoseph Chen read_fcseidr r4 7954925552SJoseph Chen read_tpidruro r5 8054925552SJoseph Chen stmia r0!, {r4 - r5} 8154925552SJoseph Chen 82*a059684bSJoseph Chenother_suspend: 8354925552SJoseph Chen read_dacr r4 8454925552SJoseph Chen read_ttbr0 r5 8554925552SJoseph Chen read_ttbr1 r6 8654925552SJoseph Chen read_ttbcr r7 8754925552SJoseph Chen read_sctlr r8 8854925552SJoseph Chen read_actlr r9 8954925552SJoseph Chen read_cpacr r10 9054925552SJoseph Chen stmia r0!, {r4 - r10} 9154925552SJoseph Chen 9254925552SJoseph Chen read_prrr r4 9354925552SJoseph Chen read_nmrr r5 9454925552SJoseph Chen read_vbar r6 9554925552SJoseph Chen mrs r7, CPSR 9654925552SJoseph Chen stmia r0, {r4 - r7} 9754925552SJoseph Chen 9854925552SJoseph Chen pop {r4 - r11} 9954925552SJoseph Chen bx lr 10054925552SJoseph ChenENDPROC(cpu_do_suspend) 10154925552SJoseph Chen 10254925552SJoseph ChenENTRY(cpu_resume) 10354925552SJoseph Chen /* Disable interrupt */ 10454925552SJoseph Chen cpsid aif 10554925552SJoseph Chen 10654925552SJoseph Chen /* Load gd !! */ 107abf4f551SJoseph Chen adr r1, __suspend_gd 10854925552SJoseph Chen ldr r2, [r1] 10954925552SJoseph Chen 11054925552SJoseph Chen /* Get pm_ctx */ 11154925552SJoseph Chen add r2, r2, #PM_CTX_PHYS 11254925552SJoseph Chen ldr r0, [r2] 11354925552SJoseph Chen 11454925552SJoseph Chen /* Need to use r0!, because cpu_do_resume needs it */ 11554925552SJoseph Chen ldmia r0!, {sp, pc} 11654925552SJoseph ChenENDPROC(cpu_resume) 11754925552SJoseph Chen 11854925552SJoseph Chen/* 11954925552SJoseph Chen * void sm_do_cpu_do_resume(paddr suspend_regs) __noreturn; 12054925552SJoseph Chen * Restore the registers stored when cpu_do_suspend 12154925552SJoseph Chen * r0 points to the physical base address of the suspend_regs 12254925552SJoseph Chen * field of struct pm_ctx. 12354925552SJoseph Chen */ 12454925552SJoseph ChenENTRY(cpu_do_resume) 12554925552SJoseph Chen read_midr r4 12654925552SJoseph Chen ubfx r5, r4, #4, #12 127*a059684bSJoseph Chen 128*a059684bSJoseph Chen ldr r4, CORTEX_A9_PART_NUM 129*a059684bSJoseph Chen cmp r5, r4 130*a059684bSJoseph Chen beq a9_resume 131*a059684bSJoseph Chen 13254925552SJoseph Chen ldr r4, CORTEX_A7_PART_NUM 13354925552SJoseph Chen cmp r5, r4 13454925552SJoseph Chen beq a7_resume 13554925552SJoseph Chen 136*a059684bSJoseph Chen /* v7 resume */ 137*a059684bSJoseph Chen mov ip, #0 138*a059684bSJoseph Chen /* Invalidate icache to PoU */ 139*a059684bSJoseph Chen write_iciallu 140*a059684bSJoseph Chen /* set reserved context */ 141*a059684bSJoseph Chen write_contextidr ip 142*a059684bSJoseph Chen b other_resume 143*a059684bSJoseph Chen 144*a059684bSJoseph Chena9_resume: 14554925552SJoseph Chen /* 14654925552SJoseph Chen * A9 needs PCR/DIAG 14754925552SJoseph Chen */ 14854925552SJoseph Chen ldmia r0!, {r4 - r5} 14954925552SJoseph Chen write_pcr r4 15054925552SJoseph Chen write_diag r5 15154925552SJoseph Chen 15254925552SJoseph Chena7_resume: 15354925552SJoseph Chen /* v7 resume */ 15454925552SJoseph Chen mov ip, #0 15554925552SJoseph Chen 15654925552SJoseph Chen /* Invalidate icache to PoU */ 15754925552SJoseph Chen write_iciallu 15854925552SJoseph Chen /* set reserved context */ 15954925552SJoseph Chen write_contextidr ip 16054925552SJoseph Chen 16154925552SJoseph Chen ldmia r0!, {r4 - r5} 16254925552SJoseph Chen write_fcseidr r4 16354925552SJoseph Chen write_tpidruro r5 16454925552SJoseph Chen 165*a059684bSJoseph Chenother_resume: 16654925552SJoseph Chen ldmia r0!, {r4 - r10} 16754925552SJoseph Chen /* Invalidate entire TLB */ 16854925552SJoseph Chen write_tlbiall 16954925552SJoseph Chen write_dacr r4 17054925552SJoseph Chen write_ttbr0 r5 17154925552SJoseph Chen write_ttbr1 r6 17254925552SJoseph Chen write_ttbcr r7 17354925552SJoseph Chen 17454925552SJoseph Chen ldmia r0, {r4 - r7} 17554925552SJoseph Chen write_prrr r4 17654925552SJoseph Chen write_nmrr r5 17754925552SJoseph Chen write_vbar r6 17854925552SJoseph Chen 17954925552SJoseph Chen write_actlr r9 18054925552SJoseph Chen write_cpacr r10 18154925552SJoseph Chen write_bpiall 18254925552SJoseph Chen isb 18354925552SJoseph Chen dsb 18454925552SJoseph Chen 18554925552SJoseph Chen /* MMU will be enabled here */ 18654925552SJoseph Chen write_sctlr r8 18754925552SJoseph Chen isb 18854925552SJoseph Chen 18954925552SJoseph Chen /* Restore interrupt */ 19054925552SJoseph Chen msr CPSR_c, r7 19154925552SJoseph Chen 19254925552SJoseph Chen mov r0, #0 19354925552SJoseph Chen b suspend_return 19454925552SJoseph ChenENDPROC(cpu_do_resume) 19554925552SJoseph Chen 19654925552SJoseph Chen.align 4 197abf4f551SJoseph Chen__suspend_gd: 19854925552SJoseph Chen .word 0x0 19954925552SJoseph ChenCORTEX_A7_PART_NUM: 20054925552SJoseph Chen .word 0xC07 20154925552SJoseph ChenCORTEX_A9_PART_NUM: 20254925552SJoseph Chen .word 0xC09 203