@ -4,6 +4,8 @@
* SPDX - License - Identifier : BSD - 3 - Clause
*/
# include <assert.h>
# include <plat_arm.h>
# include <plat_private.h>
# include <pm_common.h>
# include <common/debug.h>
@ -38,6 +40,71 @@ static int versal_pwr_domain_on(u_register_t mpidr)
return PSCI_E_SUCCESS ;
}
/**
* versal_pwr_domain_suspend ( ) - This function sends request to PMC to suspend
* core .
*
* @ target_state Targated state
*/
static void versal_pwr_domain_suspend ( const psci_power_state_t * target_state )
{
unsigned int state ;
unsigned int cpu_id = plat_my_core_pos ( ) ;
const struct pm_proc * proc = pm_get_proc ( cpu_id ) ;
for ( size_t i = 0 ; i < = PLAT_MAX_PWR_LVL ; i + + )
VERBOSE ( " %s: target_state->pwr_domain_state[%lu]=%x \n " ,
__func__ , i , target_state - > pwr_domain_state [ i ] ) ;
plat_versal_gic_cpuif_disable ( ) ;
plat_versal_gic_save ( ) ;
state = target_state - > pwr_domain_state [ 1 ] > PLAT_MAX_RET_STATE ?
PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE ;
/* Send request to PMC to suspend this core */
pm_self_suspend ( proc - > node_id , MAX_LATENCY , state , versal_sec_entry ) ;
/* APU is to be turned off */
if ( target_state - > pwr_domain_state [ 1 ] > PLAT_MAX_RET_STATE ) {
/* disable coherency */
plat_arm_interconnect_exit_coherency ( ) ;
}
}
/**
* versal_pwr_domain_suspend_finish ( ) - This function performs actions to finish
* suspend procedure .
*
* @ target_state Targated state
*/
static void versal_pwr_domain_suspend_finish (
const psci_power_state_t * target_state )
{
unsigned int cpu_id = plat_my_core_pos ( ) ;
const struct pm_proc * proc = pm_get_proc ( cpu_id ) ;
for ( size_t i = 0 ; i < = PLAT_MAX_PWR_LVL ; i + + )
VERBOSE ( " %s: target_state->pwr_domain_state[%lu]=%x \n " ,
__func__ , i , target_state - > pwr_domain_state [ i ] ) ;
/* Clear the APU power control register for this cpu */
pm_client_wakeup ( proc ) ;
/* enable coherency */
plat_arm_interconnect_enter_coherency ( ) ;
/* APU was turned off, so restore GIC context */
if ( target_state - > pwr_domain_state [ 1 ] > PLAT_MAX_RET_STATE ) {
plat_versal_gic_resume ( ) ;
plat_versal_gic_cpuif_enable ( ) ;
} else {
plat_versal_gic_cpuif_enable ( ) ;
plat_versal_gic_pcpu_init ( ) ;
}
}
void versal_pwr_domain_on_finish ( const psci_power_state_t * target_state )
{
/* Enable the gic cpu interface */
@ -47,9 +114,84 @@ void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
plat_versal_gic_cpuif_enable ( ) ;
}
/**
* versal_pwr_domain_off ( ) - This function performs actions to turn off core
*
* @ target_state Targated state
*/
static void versal_pwr_domain_off ( const psci_power_state_t * target_state )
{
unsigned int cpu_id = plat_my_core_pos ( ) ;
const struct pm_proc * proc = pm_get_proc ( cpu_id ) ;
for ( size_t i = 0 ; i < = PLAT_MAX_PWR_LVL ; i + + )
VERBOSE ( " %s: target_state->pwr_domain_state[%lu]=%x \n " ,
__func__ , i , target_state - > pwr_domain_state [ i ] ) ;
/* Prevent interrupts from spuriously waking up this cpu */
plat_versal_gic_cpuif_disable ( ) ;
/*
* Send request to PMC to power down the appropriate APU CPU
* core .
* According to PSCI specification , CPU_off function does not
* have resume address and CPU core can only be woken up
* invoking CPU_on function , during which resume address will
* be set .
*/
pm_self_suspend ( proc - > node_id , MAX_LATENCY , PM_STATE_CPU_IDLE , 0 ) ;
}
/**
* versal_validate_power_state ( ) - This function ensures that the power state
* parameter in request is valid .
*
* @ power_state Power state of core
* @ req_state Requested state
*
* @ return Returns status , either success or reason
*/
static int versal_validate_power_state ( unsigned int power_state ,
psci_power_state_t * req_state )
{
VERBOSE ( " %s: power_state: 0x%x \n " , __func__ , power_state ) ;
int pstate = psci_get_pstate_type ( power_state ) ;
assert ( req_state ) ;
/* Sanity check the requested state */
if ( pstate = = PSTATE_TYPE_STANDBY )
req_state - > pwr_domain_state [ MPIDR_AFFLVL0 ] = PLAT_MAX_RET_STATE ;
else
req_state - > pwr_domain_state [ MPIDR_AFFLVL0 ] = PLAT_MAX_OFF_STATE ;
/* We expect the 'state id' to be zero */
if ( psci_get_pstate_id ( power_state ) )
return PSCI_E_INVALID_PARAMS ;
return PSCI_E_SUCCESS ;
}
/**
* versal_get_sys_suspend_power_state ( ) - Get power state for system suspend
*
* @ req_state Requested state
*/
static void versal_get_sys_suspend_power_state ( psci_power_state_t * req_state )
{
req_state - > pwr_domain_state [ PSCI_CPU_PWR_LVL ] = PLAT_MAX_OFF_STATE ;
req_state - > pwr_domain_state [ 1 ] = PLAT_MAX_OFF_STATE ;
}
static const struct plat_psci_ops versal_nopmc_psci_ops = {
. pwr_domain_on = versal_pwr_domain_on ,
. pwr_domain_off = versal_pwr_domain_off ,
. pwr_domain_on_finish = versal_pwr_domain_on_finish ,
. pwr_domain_suspend = versal_pwr_domain_suspend ,
. pwr_domain_suspend_finish = versal_pwr_domain_suspend_finish ,
. validate_power_state = versal_validate_power_state ,
. get_sys_suspend_power_state = versal_get_sys_suspend_power_state ,
} ;
/*******************************************************************************