blob: ec69aea03de4127cfa3cdce6ae018de1268ff909 [file] [log] [blame]
/*
* Copyright 2018-2021 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <asm_macros.S>
#include <assert_macros.S>
#include <lib/psci/psci.h>
#include <bl31_data.h>
#include <plat_psci.h>
#define RESET_RETRY_CNT 800
#define PSCI_ABORT_CNT 100
#if (SOC_CORE_RELEASE)
.global _psci_cpu_on
/*
* int _psci_cpu_on(u_register_t core_mask)
* x0 = target cpu core mask
*
* Called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*
*/
func _psci_cpu_on
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x6, x0
/* x0 = core mask (lsb)
* x6 = core mask (lsb)
*/
/* check if core disabled */
bl _soc_ck_disabled /* 0-2 */
cbnz w0, psci_disabled
/* check core data area to see if core cannot be turned on
* read the core state
*/
mov x0, x6
bl _getCoreState /* 0-5 */
mov x9, x0
/* x6 = core mask (lsb)
* x9 = core state (from data area)
*/
cmp x9, #CORE_DISABLED
mov x0, #PSCI_E_DISABLED
b.eq cpu_on_done
cmp x9, #CORE_PENDING
mov x0, #PSCI_E_ON_PENDING
b.eq cpu_on_done
cmp x9, #CORE_RELEASED
mov x0, #PSCI_E_ALREADY_ON
b.eq cpu_on_done
8:
/* x6 = core mask (lsb)
* x9 = core state (from data area)
*/
cmp x9, #CORE_WFE
b.eq core_in_wfe
cmp x9, #CORE_IN_RESET
b.eq core_in_reset
cmp x9, #CORE_OFF
b.eq core_is_off
cmp x9, #CORE_OFF_PENDING
/* if state == CORE_OFF_PENDING, set abort */
mov x0, x6
mov x1, #ABORT_FLAG_DATA
mov x2, #CORE_ABORT_OP
bl _setCoreData /* 0-3, [13-15] */
ldr x3, =PSCI_ABORT_CNT
7:
/* watch for abort to take effect */
mov x0, x6
bl _getCoreState /* 0-5 */
cmp x0, #CORE_OFF
b.eq core_is_off
cmp x0, #CORE_PENDING
mov x0, #PSCI_E_SUCCESS
b.eq cpu_on_done
/* loop til finished */
sub x3, x3, #1
cbnz x3, 7b
/* if we didn't see either CORE_OFF or CORE_PENDING, then this
* core is in CORE_OFF_PENDING - exit with success, as the core will
* respond to the abort request
*/
mov x0, #PSCI_E_SUCCESS
b cpu_on_done
/* this is where we start up a core out of reset */
core_in_reset:
/* see if the soc-specific module supports this op */
ldr x7, =SOC_CORE_RELEASE
cbnz x7, 3f
mov x0, #PSCI_E_NOT_SUPPORTED
b cpu_on_done
/* x6 = core mask (lsb) */
3:
/* set core state in data area */
mov x0, x6
mov x1, #CORE_PENDING
bl _setCoreState /* 0-3, [13-15] */
/* release the core from reset */
mov x0, x6
bl _soc_core_release /* 0-3 */
mov x0, #PSCI_E_SUCCESS
b cpu_on_done
/* Start up the core that has been powered-down via CPU_OFF
*/
core_is_off:
/* see if the soc-specific module supports this op
*/
ldr x7, =SOC_CORE_RESTART
cbnz x7, 2f
mov x0, #PSCI_E_NOT_SUPPORTED
b cpu_on_done
/* x6 = core mask (lsb) */
2:
/* set core state in data area */
mov x0, x6
mov x1, #CORE_WAKEUP
bl _setCoreState /* 0-3, [13-15] */
/* put the core back into service */
mov x0, x6
#if (SOC_CORE_RESTART)
bl _soc_core_restart /* 0-5 */
#endif
mov x0, #PSCI_E_SUCCESS
b cpu_on_done
/* this is where we release a core that is being held in wfe */
core_in_wfe:
/* x6 = core mask (lsb) */
/* set core state in data area */
mov x0, x6
mov x1, #CORE_PENDING
bl _setCoreState /* 0-3, [13-15] */
dsb sy
isb
/* put the core back into service */
sev
sev
isb
mov x0, #PSCI_E_SUCCESS
cpu_on_done:
/* restore the aarch32/64 non-volatile registers */
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_cpu_on
#endif
#if (SOC_CORE_OFF)
.global _psci_cpu_prep_off
.global _psci_cpu_off_wfi
/*
* void _psci_cpu_prep_off(u_register_t core_mask)
* this function performs the SoC-specific programming prior
* to shutting the core down
* x0 = core_mask
*
* called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_cpu_prep_off
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x10, x0 /* x10 = core_mask */
/* the core does not return from cpu_off, so no need
* to save/restore non-volatile registers
*/
/* mask interrupts by setting DAIF[7:4] to 'b1111 */
msr DAIFSet, #0xF
/* read cpuectlr and save current value */
mrs x4, CPUECTLR_EL1
mov x1, #CPUECTLR_DATA
mov x2, x4
mov x0, x10
bl _setCoreData
/* remove the core from coherency */
bic x4, x4, #CPUECTLR_SMPEN_MASK
msr CPUECTLR_EL1, x4
/* save scr_el3 */
mov x0, x10
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* x4 = scr_el3 */
/* secure SGI (FIQ) taken to EL3, set SCR_EL3[FIQ] */
orr x4, x4, #SCR_FIQ_MASK
msr scr_el3, x4
/* x10 = core_mask */
/* prep the core for shutdown */
mov x0, x10
bl _soc_core_prep_off
/* restore the aarch32/64 non-volatile registers */
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_cpu_prep_off
/*
* void _psci_cpu_off_wfi(u_register_t core_mask, u_register_t resume_addr)
* - this function shuts down the core
* - this function does not return!!
*/
func _psci_cpu_off_wfi
/* save the wakeup address */
mov x29, x1
/* x0 = core_mask */
/* shutdown the core */
bl _soc_core_entr_off
/* branch to resume execution */
br x29
endfunc _psci_cpu_off_wfi
#endif
#if (SOC_CORE_RESTART)
.global _psci_wakeup
/*
* void _psci_wakeup(u_register_t core_mask)
* this function performs the SoC-specific programming
* after a core wakes up from OFF
* x0 = core mask
*
* called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_wakeup
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x4, x0 /* x4 = core mask */
/* restore scr_el3 */
mov x0, x4
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
/* x4 = core mask */
/* restore CPUECTLR */
mov x0, x4
mov x1, #CPUECTLR_DATA
bl _getCoreData
orr x0, x0, #CPUECTLR_SMPEN_MASK
msr CPUECTLR_EL1, x0
/* x4 = core mask */
/* start the core back up */
mov x0, x4
bl _soc_core_exit_off
/* restore the aarch32/64 non-volatile registers
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_wakeup
#endif
#if (SOC_SYSTEM_RESET)
.global _psci_system_reset
func _psci_system_reset
/* system reset is mandatory
* system reset is soc-specific
* Note: under no circumstances do we return from this call
*/
bl _soc_sys_reset
endfunc _psci_system_reset
#endif
#if (SOC_SYSTEM_OFF)
.global _psci_system_off
func _psci_system_off
/* system off is mandatory
* system off is soc-specific
* Note: under no circumstances do we return from this call */
b _soc_sys_off
endfunc _psci_system_off
#endif
#if (SOC_CORE_STANDBY)
.global _psci_core_entr_stdby
.global _psci_core_prep_stdby
.global _psci_core_exit_stdby
/*
* void _psci_core_entr_stdby(u_register_t core_mask) - this
* is the fast-path for simple core standby
*/
func _psci_core_entr_stdby
stp x4, x5, [sp, #-16]!
stp x6, x30, [sp, #-16]!
mov x5, x0 /* x5 = core mask */
/* save scr_el3 */
mov x0, x5
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* x4 = SCR_EL3
* x5 = core mask
*/
/* allow interrupts @ EL3 */
orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
msr SCR_EL3, x4
/* x5 = core mask */
/* put the core into standby */
mov x0, x5
bl _soc_core_entr_stdby
/* restore scr_el3 */
mov x0, x5
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
ldp x6, x30, [sp], #16
ldp x4, x5, [sp], #16
isb
ret
endfunc _psci_core_entr_stdby
/*
* void _psci_core_prep_stdby(u_register_t core_mask) - this
* sets up the core to enter standby state thru the normal path
*/
func _psci_core_prep_stdby
stp x4, x5, [sp, #-16]!
stp x6, x30, [sp, #-16]!
mov x5, x0
/* x5 = core mask */
/* save scr_el3 */
mov x0, x5
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* allow interrupts @ EL3 */
orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
msr SCR_EL3, x4
/* x5 = core mask */
/* call for any SoC-specific programming */
mov x0, x5
bl _soc_core_prep_stdby
ldp x6, x30, [sp], #16
ldp x4, x5, [sp], #16
isb
ret
endfunc _psci_core_prep_stdby
/*
* void _psci_core_exit_stdby(u_register_t core_mask) - this
* exits the core from standby state thru the normal path
*/
func _psci_core_exit_stdby
stp x4, x5, [sp, #-16]!
stp x6, x30, [sp, #-16]!
mov x5, x0
/* x5 = core mask */
/* restore scr_el3 */
mov x0, x5
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
/* x5 = core mask */
/* perform any SoC-specific programming after standby state */
mov x0, x5
bl _soc_core_exit_stdby
ldp x6, x30, [sp], #16
ldp x4, x5, [sp], #16
isb
ret
endfunc _psci_core_exit_stdby
#endif
#if (SOC_CORE_PWR_DWN)
.global _psci_core_prep_pwrdn
.global _psci_cpu_pwrdn_wfi
.global _psci_core_exit_pwrdn
/*
* void _psci_core_prep_pwrdn_(u_register_t core_mask)
* this function prepares the core for power-down
* x0 = core mask
*
* called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_core_prep_pwrdn
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x6, x0
/* x6 = core mask */
/* mask interrupts by setting DAIF[7:4] to 'b1111 */
msr DAIFSet, #0xF
/* save scr_el3 */
mov x0, x6
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* allow interrupts @ EL3 */
orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
msr SCR_EL3, x4
/* save cpuectlr */
mov x0, x6
mov x1, #CPUECTLR_DATA
mrs x2, CPUECTLR_EL1
bl _setCoreData
/* x6 = core mask */
/* SoC-specific programming for power-down */
mov x0, x6
bl _soc_core_prep_pwrdn
/* restore the aarch32/64 non-volatile registers
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_core_prep_pwrdn
/*
* void _psci_cpu_pwrdn_wfi(u_register_t core_mask, u_register_t resume_addr)
* this function powers down the core
*/
func _psci_cpu_pwrdn_wfi
/* save the wakeup address */
mov x29, x1
/* x0 = core mask */
/* shutdown the core */
bl _soc_core_entr_pwrdn
/* branch to resume execution */
br x29
endfunc _psci_cpu_pwrdn_wfi
/*
* void _psci_core_exit_pwrdn_(u_register_t core_mask)
* this function cleans up after a core power-down
* x0 = core mask
*
* called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_core_exit_pwrdn
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x5, x0 /* x5 = core mask */
/* restore scr_el3 */
mov x0, x5
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
/* x5 = core mask */
/* restore cpuectlr */
mov x0, x5
mov x1, #CPUECTLR_DATA
bl _getCoreData
/* make sure smp is set */
orr x0, x0, #CPUECTLR_SMPEN_MASK
msr CPUECTLR_EL1, x0
/* x5 = core mask */
/* SoC-specific cleanup */
mov x0, x5
bl _soc_core_exit_pwrdn
/* restore the aarch32/64 non-volatile registers
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_core_exit_pwrdn
#endif
#if (SOC_CLUSTER_STANDBY)
.global _psci_clstr_prep_stdby
.global _psci_clstr_exit_stdby
/*
* void _psci_clstr_prep_stdby(u_register_t core_mask) - this
* sets up the clstr to enter standby state thru the normal path
*/
func _psci_clstr_prep_stdby
stp x4, x5, [sp, #-16]!
stp x6, x30, [sp, #-16]!
mov x5, x0
/* x5 = core mask */
/* save scr_el3 */
mov x0, x5
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* allow interrupts @ EL3 */
orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
msr SCR_EL3, x4
/* x5 = core mask */
/* call for any SoC-specific programming */
mov x0, x5
bl _soc_clstr_prep_stdby
ldp x6, x30, [sp], #16
ldp x4, x5, [sp], #16
isb
ret
endfunc _psci_clstr_prep_stdby
/*
* void _psci_clstr_exit_stdby(u_register_t core_mask) - this
* exits the clstr from standby state thru the normal path
*/
func _psci_clstr_exit_stdby
stp x4, x5, [sp, #-16]!
stp x6, x30, [sp, #-16]!
mov x5, x0 /* x5 = core mask */
/* restore scr_el3 */
mov x0, x5
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
/* x5 = core mask */
/* perform any SoC-specific programming after standby state */
mov x0, x5
bl _soc_clstr_exit_stdby
ldp x6, x30, [sp], #16
ldp x4, x5, [sp], #16
isb
ret
endfunc _psci_clstr_exit_stdby
#endif
#if (SOC_CLUSTER_PWR_DWN)
.global _psci_clstr_prep_pwrdn
.global _psci_clstr_exit_pwrdn
/*
* void _psci_clstr_prep_pwrdn_(u_register_t core_mask)
* this function prepares the cluster+core for power-down
* x0 = core mask
*
* called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_clstr_prep_pwrdn
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x6, x0 /* x6 = core mask */
/* mask interrupts by setting DAIF[7:4] to 'b1111 */
msr DAIFSet, #0xF
/* save scr_el3 */
mov x0, x6
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* allow interrupts @ EL3 */
orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
msr SCR_EL3, x4
/* save cpuectlr */
mov x0, x6
mov x1, #CPUECTLR_DATA
mrs x2, CPUECTLR_EL1
mov x4, x2
bl _setCoreData
/* remove core from coherency */
bic x4, x4, #CPUECTLR_SMPEN_MASK
msr CPUECTLR_EL1, x4
/* x6 = core mask */
/* SoC-specific programming for power-down */
mov x0, x6
bl _soc_clstr_prep_pwrdn
/* restore the aarch32/64 non-volatile registers
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_clstr_prep_pwrdn
/*
* void _psci_clstr_exit_pwrdn_(u_register_t core_mask)
* this function cleans up after a cluster power-down
* x0 = core mask
*
* called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_clstr_exit_pwrdn
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x4, x0 /* x4 = core mask */
/* restore scr_el3 */
mov x0, x4
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
/* x4 = core mask */
/* restore cpuectlr */
mov x0, x4
mov x1, #CPUECTLR_DATA
bl _getCoreData
/* make sure smp is set */
orr x0, x0, #CPUECTLR_SMPEN_MASK
msr CPUECTLR_EL1, x0
/* x4 = core mask */
/* SoC-specific cleanup */
mov x0, x4
bl _soc_clstr_exit_pwrdn
/* restore the aarch32/64 non-volatile registers
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_clstr_exit_pwrdn
#endif
#if (SOC_SYSTEM_STANDBY)
.global _psci_sys_prep_stdby
.global _psci_sys_exit_stdby
/*
* void _psci_sys_prep_stdby(u_register_t core_mask) - this
* sets up the system to enter standby state thru the normal path
*/
func _psci_sys_prep_stdby
stp x4, x5, [sp, #-16]!
stp x6, x30, [sp, #-16]!
mov x5, x0 /* x5 = core mask */
/* save scr_el3 */
mov x0, x5
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* allow interrupts @ EL3 */
orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
msr SCR_EL3, x4
/* x5 = core mask */
/* call for any SoC-specific programming */
mov x0, x5
bl _soc_sys_prep_stdby
ldp x6, x30, [sp], #16
ldp x4, x5, [sp], #16
isb
ret
endfunc _psci_sys_prep_stdby
/*
* void _psci_sys_exit_stdby(u_register_t core_mask) - this
* exits the system from standby state thru the normal path
*/
func _psci_sys_exit_stdby
stp x4, x5, [sp, #-16]!
stp x6, x30, [sp, #-16]!
mov x5, x0
/* x5 = core mask */
/* restore scr_el3 */
mov x0, x5
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
/* x5 = core mask */
/* perform any SoC-specific programming after standby state */
mov x0, x5
bl _soc_sys_exit_stdby
ldp x6, x30, [sp], #16
ldp x4, x5, [sp], #16
isb
ret
endfunc _psci_sys_exit_stdby
#endif
#if (SOC_SYSTEM_PWR_DWN)
.global _psci_sys_prep_pwrdn
.global _psci_sys_pwrdn_wfi
.global _psci_sys_exit_pwrdn
/*
* void _psci_sys_prep_pwrdn_(u_register_t core_mask)
* this function prepares the system+core for power-down
* x0 = core mask
*
* called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_sys_prep_pwrdn
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x6, x0 /* x6 = core mask */
/* mask interrupts by setting DAIF[7:4] to 'b1111 */
msr DAIFSet, #0xF
/* save scr_el3 */
mov x0, x6
mrs x4, SCR_EL3
mov x2, x4
mov x1, #SCR_EL3_DATA
bl _setCoreData
/* allow interrupts @ EL3 */
orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
msr SCR_EL3, x4
/* save cpuectlr */
mov x0, x6
mov x1, #CPUECTLR_DATA
mrs x2, CPUECTLR_EL1
mov x4, x2
bl _setCoreData
/* remove core from coherency */
bic x4, x4, #CPUECTLR_SMPEN_MASK
msr CPUECTLR_EL1, x4
/* x6 = core mask */
/* SoC-specific programming for power-down */
mov x0, x6
bl _soc_sys_prep_pwrdn
/* restore the aarch32/64 non-volatile registers
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_sys_prep_pwrdn
/*
* void _psci_sys_pwrdn_wfi(u_register_t core_mask, u_register_t resume_addr)
* this function powers down the system
*/
func _psci_sys_pwrdn_wfi
/* save the wakeup address */
mov x29, x1
/* x0 = core mask */
/* shutdown the system */
bl _soc_sys_pwrdn_wfi
/* branch to resume execution */
br x29
endfunc _psci_sys_pwrdn_wfi
/*
* void _psci_sys_exit_pwrdn_(u_register_t core_mask)
* this function cleans up after a system power-down
* x0 = core mask
*
* Called from C, so save the non-volatile regs
* save these as pairs of registers to maintain the
* required 16-byte alignment on the stack
*/
func _psci_sys_exit_pwrdn
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
mov x4, x0 /* x4 = core mask */
/* restore scr_el3 */
mov x0, x4
mov x1, #SCR_EL3_DATA
bl _getCoreData
/* x0 = saved scr_el3 */
msr SCR_EL3, x0
/* x4 = core mask */
/* restore cpuectlr */
mov x0, x4
mov x1, #CPUECTLR_DATA
bl _getCoreData
/* make sure smp is set */
orr x0, x0, #CPUECTLR_SMPEN_MASK
msr CPUECTLR_EL1, x0
/* x4 = core mask */
/* SoC-specific cleanup */
mov x0, x4
bl _soc_sys_exit_pwrdn
/* restore the aarch32/64 non-volatile registers
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
b psci_completed
endfunc _psci_sys_exit_pwrdn
#endif
/* psci std returns */
func psci_disabled
ldr w0, =PSCI_E_DISABLED
b psci_completed
endfunc psci_disabled
func psci_not_present
ldr w0, =PSCI_E_NOT_PRESENT
b psci_completed
endfunc psci_not_present
func psci_on_pending
ldr w0, =PSCI_E_ON_PENDING
b psci_completed
endfunc psci_on_pending
func psci_already_on
ldr w0, =PSCI_E_ALREADY_ON
b psci_completed
endfunc psci_already_on
func psci_failure
ldr w0, =PSCI_E_INTERN_FAIL
b psci_completed
endfunc psci_failure
func psci_unimplemented
ldr w0, =PSCI_E_NOT_SUPPORTED
b psci_completed
endfunc psci_unimplemented
func psci_denied
ldr w0, =PSCI_E_DENIED
b psci_completed
endfunc psci_denied
func psci_invalid
ldr w0, =PSCI_E_INVALID_PARAMS
b psci_completed
endfunc psci_invalid
func psci_success
mov x0, #PSCI_E_SUCCESS
endfunc psci_success
func psci_completed
/* x0 = status code */
ret
endfunc psci_completed