blob: 9421b2d176a34804aaf2bf85dc25b147205103af [file] [log] [blame]
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright 2017 NXP
*
* Peng Fan <peng.fan@nxp.com>
*/
#include <arm32_macros_cortex_a9.S>
#include <arm32_macros.S>
#include <arm.h>
#include <asm.S>
#include <generated/asm-defines.h>
#include <keep.h>
#include <kernel/asan.h>
#include <kernel/unwind.h>
#include <platform_config.h>
.section .text
/*
* int sm_pm_cpu_suspend(uint32_t arg, int (*fn)(uint32_t))
* @arg will be passed to fn as argument
* return value: 0 - cpu resumed from suspended state.
* -1 - cpu not suspended.
*/
FUNC sm_pm_cpu_suspend, :
UNWIND( .fnstart)
UNWIND( .cantunwind)
push {r4 - r12, lr}
mov r5, sp
sub sp, sp, #SM_PM_CTX_SIZE
push {r0, r1}
mov r1, r5
add r0, sp, #8
blx sm_pm_cpu_suspend_save
adr lr, aborted
/* Jump to arch specific suspend */
pop {r0, pc}
aborted:
/* cpu not suspended */
add sp, sp, #SM_PM_CTX_SIZE
/* Return -1 to the caller */
mov r0, #(-1)
suspend_return:
pop {r4 - r12, pc}
UNWIND( .fnend)
END_FUNC sm_pm_cpu_suspend
FUNC sm_pm_cpu_do_suspend, :
UNWIND( .fnstart)
UNWIND( .cantunwind)
push {r4 - r11}
read_midr r4
ubfx r5, r4, #4, #12
ldr r4, =CORTEX_A7_PART_NUM
cmp r5, r4
beq a7_suspend
ldr r4, =CORTEX_A9_PART_NUM
cmp r5, r4
beq a9_suspend
/* cpu not supported */
b .
/* A9 needs PCR/DIAG */
a9_suspend:
read_pcr r4
read_diag r5
stmia r0!, {r4 - r5}
a7_suspend:
read_fcseidr r4
read_tpidruro r5
stmia r0!, {r4 - r5}
read_dacr r4
#ifdef CFG_WITH_LPAE
#error "Not supported"
#else
read_ttbr0 r5
read_ttbr1 r6
read_ttbcr r7
#endif
read_sctlr r8
read_actlr r9
read_cpacr r10
read_mvbar r11
stmia r0!, {r4 - r11}
read_prrr r4
read_nmrr r5
read_vbar r6
read_nsacr r7
stmia r0, {r4 - r7}
pop {r4 - r11}
bx lr
UNWIND( .fnend)
END_FUNC sm_pm_cpu_do_suspend
FUNC sm_pm_cpu_resume, :
UNWIND( .fnstart)
UNWIND( .cantunwind)
cpsid aif
/* Call into the runtime address of __get_core_pos */
adr r0, _core_pos
ldr r1, [r0]
add r0, r0, r1
blx r0
/*
* At this point, MMU is not enabled now.
* 1. Get the runtime physical address of _suspend_sp
* 2. Get the offset from _suspend_sp to &thread_core_local
* 3. Get the runtime physical address of thread_core_local
* Since moving towards non-linear mapping,
* `ldr r0, =thread_core_local` is not used here.
*/
adr r4, _suspend_sp
ldr r5, [r4]
add r4, r4, r5
mov_imm r1, THREAD_CORE_LOCAL_SIZE
mla r0, r0, r1, r4
ldr r0, [r0, #THREAD_CORE_LOCAL_SM_PM_CTX_PHYS]
/* Need to use r0!, because sm_pm_cpu_do_resume needs it */
ldmia r0!, {sp, pc}
UNWIND( .fnend)
END_FUNC sm_pm_cpu_resume
/*
* The following will be located in text section whose attribute is
* marked as readonly, but we only need to read here
* _suspend_sp stores the offset between thread_core_local to _suspend_sp.
* _core_pos stores the offset between __get_core_pos to _core_pos.
*/
.align 2
.extern thread_core_local
_suspend_sp:
.long thread_core_local - .
.extern __get_core_pos
_core_pos:
.long __get_core_pos - .
/*
* void sm_pm_cpu_do_resume(paddr suspend_regs) __noreturn;
* Restore the registers stored when sm_pm_cpu_do_suspend
* r0 points to the physical base address of the suspend_regs
* field of struct sm_pm_ctx.
*/
FUNC sm_pm_cpu_do_resume, :
UNWIND( .fnstart)
UNWIND( .cantunwind)
read_midr r4
ubfx r5, r4, #4, #12
ldr r4, =CORTEX_A7_PART_NUM
cmp r5, r4
beq a7_resume
/*
* A9 needs PCR/DIAG
*/
ldmia r0!, {r4 - r5}
write_pcr r4
write_diag r5
a7_resume:
/* v7 resume */
mov ip, #0
/* Invalidate icache to PoU */
write_iciallu
/* set reserved context */
write_contextidr ip
ldmia r0!, {r4 - r5}
write_fcseidr r4
write_tpidruro r5
ldmia r0!, {r4 - r11}
/* Invalidate entire TLB */
write_tlbiall
write_dacr r4
#ifdef CFG_WITH_LPAE
#error "Not supported -"
#else
write_ttbr0 r5
write_ttbr1 r6
write_ttbcr r7
#endif
ldmia r0, {r4 - r7}
write_prrr r4
write_nmrr r5
write_vbar r6
write_nsacr r7
write_actlr r9
write_cpacr r10
write_mvbar r11
write_bpiall
isb
dsb
/* MMU will be enabled here */
write_sctlr r8
isb
mov r0, #0
b suspend_return
UNWIND( .fnend)
END_FUNC sm_pm_cpu_do_resume