2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2014-07-17 10:30:07 +01:00
/*
* ARM64 CPU idle arch support
*
* Copyright ( C ) 2014 ARM Ltd .
* Author : Lorenzo Pieralisi < lorenzo . pieralisi @ arm . com >
*/
2016-07-19 18:52:58 +01:00
# include <linux/acpi.h>
# include <linux/cpuidle.h>
# include <linux/cpu_pm.h>
2014-07-17 10:30:07 +01:00
# include <linux/of.h>
# include <linux/of_device.h>
2019-08-09 12:03:11 +01:00
# include <linux/psci.h>
2014-07-17 10:30:07 +01:00
# include <asm/cpuidle.h>
# include <asm/cpu_ops.h>
2016-07-19 18:52:55 +01:00
int arm_cpuidle_init ( unsigned int cpu )
2014-07-17 10:30:07 +01:00
{
2020-03-19 10:01:44 +11:00
const struct cpu_operations * ops = get_cpu_ops ( cpu ) ;
2014-07-17 10:30:07 +01:00
int ret = - EOPNOTSUPP ;
2020-03-19 10:01:44 +11:00
if ( ops & & ops - > cpu_suspend & & ops - > cpu_init_idle )
ret = ops - > cpu_init_idle ( cpu ) ;
2014-07-17 10:30:07 +01:00
return ret ;
}
2015-01-26 18:33:44 +00:00
/**
2017-02-17 15:25:08 +01:00
* arm_cpuidle_suspend ( ) - function to enter a low - power idle state
2021-05-06 13:54:22 +08:00
* @ index : argument to pass to CPU suspend operations
2015-01-26 18:33:44 +00:00
*
* Return : 0 on success , - EOPNOTSUPP if CPU suspend hook not initialized , CPU
* operations back - end error code otherwise .
*/
2015-06-18 15:41:32 +01:00
int arm_cpuidle_suspend ( int index )
2015-01-26 18:33:44 +00:00
{
int cpu = smp_processor_id ( ) ;
2020-03-19 10:01:44 +11:00
const struct cpu_operations * ops = get_cpu_ops ( cpu ) ;
2015-01-26 18:33:44 +00:00
2020-03-19 10:01:44 +11:00
return ops - > cpu_suspend ( index ) ;
2015-01-26 18:33:44 +00:00
}
2016-07-19 18:52:58 +01:00
# ifdef CONFIG_ACPI
# include <acpi/processor.h>
2017-11-15 10:11:50 -07:00
# define ARM64_LPI_IS_RETENTION_STATE(arch_flags) (!(arch_flags))
2019-08-09 12:03:12 +01:00
static int psci_acpi_cpu_init_idle ( unsigned int cpu )
{
int i , count ;
struct acpi_lpi_state * lpi ;
struct acpi_processor * pr = per_cpu ( processors , cpu ) ;
/*
* If the PSCI cpu_suspend function hook has not been initialized
* idle states must not be enabled , so bail out
*/
if ( ! psci_ops . cpu_suspend )
return - EOPNOTSUPP ;
if ( unlikely ( ! pr | | ! pr - > flags . has_lpi ) )
return - EINVAL ;
count = pr - > power . count - 1 ;
if ( count < = 0 )
return - ENODEV ;
for ( i = 0 ; i < count ; i + + ) {
u32 state ;
lpi = & pr - > power . lpi_states [ i + 1 ] ;
/*
* Only bits [ 31 : 0 ] represent a PSCI power_state while
* bits [ 63 : 32 ] must be 0x0 as per ARM ACPI FFH Specification
*/
state = lpi - > address ;
if ( ! psci_power_state_is_valid ( state ) ) {
pr_warn ( " Invalid PSCI power state %#x \n " , state ) ;
return - EINVAL ;
}
}
return 0 ;
}
2016-07-19 18:52:58 +01:00
int acpi_processor_ffh_lpi_probe ( unsigned int cpu )
{
2019-08-09 12:03:12 +01:00
return psci_acpi_cpu_init_idle ( cpu ) ;
2016-07-19 18:52:58 +01:00
}
int acpi_processor_ffh_lpi_enter ( struct acpi_lpi_state * lpi )
{
2019-08-09 12:03:12 +01:00
u32 state = lpi - > address ;
2017-11-15 10:11:50 -07:00
if ( ARM64_LPI_IS_RETENTION_STATE ( lpi - > arch_flags ) )
2019-08-09 12:03:12 +01:00
return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM ( psci_cpu_suspend_enter ,
lpi - > index , state ) ;
2017-11-15 10:11:50 -07:00
else
2019-08-09 12:03:12 +01:00
return CPU_PM_CPU_IDLE_ENTER_PARAM ( psci_cpu_suspend_enter ,
lpi - > index , state ) ;
2016-07-19 18:52:58 +01:00
}
# endif