/* * Copyright 2017 NXP * * Peng Fan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include .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_do_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