Commit 28d3d614 authored by Jeenu Viswambharan's avatar Jeenu Viswambharan
Browse files

PSCI: Add support for PSCI NODE_HW_STATE API

This patch adds support for NODE_HW_STATE PSCI API by introducing a new
PSCI platform hook (get_node_hw_state). The implementation validates
supplied arguments, and then invokes this platform-defined hook and
returns its result to the caller. PSCI capabilities are updated
accordingly.

Also updates porting and firmware design guides.

Change-Id: I808e55bdf0c157002a7c104b875779fe50a68a30
parent 77b05323
...@@ -716,7 +716,7 @@ required support. ...@@ -716,7 +716,7 @@ required support.
|`PSCI_FEATURES` | Yes | | |`PSCI_FEATURES` | Yes | |
|`CPU_FREEZE` | No | | |`CPU_FREEZE` | No | |
|`CPU_DEFAULT_SUSPEND` | No | | |`CPU_DEFAULT_SUSPEND` | No | |
|`CPU_HW_STATE` | No | | |`NODE_HW_STATE` | Yes* | |
|`SYSTEM_SUSPEND` | Yes* | | |`SYSTEM_SUSPEND` | Yes* | |
|`PSCI_SET_SUSPEND_MODE`| No | | |`PSCI_SET_SUSPEND_MODE`| No | |
|`PSCI_STAT_RESIDENCY` | Yes* | | |`PSCI_STAT_RESIDENCY` | Yes* | |
......
...@@ -1832,6 +1832,20 @@ This function can also be used in case the platform wants to support local ...@@ -1832,6 +1832,20 @@ This function can also be used in case the platform wants to support local
power state encoding for `power_state` parameter of PSCI_STAT_COUNT/RESIDENCY power state encoding for `power_state` parameter of PSCI_STAT_COUNT/RESIDENCY
APIs as described in Section 5.18 of [PSCI]. APIs as described in Section 5.18 of [PSCI].
#### plat_psci_ops.get_node_hw_state()
This is an optional function. If implemented this function is intended to return
the power state of a node (identified by the first parameter, the `MPIDR`) in
the power domain topology (identified by the second parameter, `power_level`),
as retrieved from a power controller or equivalent component on the platform.
Upon successful completion, the implementation must map and return the final
status among `HW_ON`, `HW_OFF` or `HW_STANDBY`. Upon encountering failures, it
must return either `PSCI_E_INVALID_PARAMS` or `PSCI_E_NOT_SUPPORTED` as
appropriate.
Implementations are not expected to handle `power_levels` greater than
`PLAT_MAX_PWR_LVL`.
3.6 Interrupt Management framework (in BL31) 3.6 Interrupt Management framework (in BL31)
---------------------------------------------- ----------------------------------------------
BL31 implements an Interrupt Management Framework (IMF) to manage interrupts BL31 implements an Interrupt Management Framework (IMF) to manage interrupts
......
...@@ -78,6 +78,8 @@ ...@@ -78,6 +78,8 @@
#define PSCI_SYSTEM_OFF 0x84000008 #define PSCI_SYSTEM_OFF 0x84000008
#define PSCI_SYSTEM_RESET 0x84000009 #define PSCI_SYSTEM_RESET 0x84000009
#define PSCI_FEATURES 0x8400000A #define PSCI_FEATURES 0x8400000A
#define PSCI_NODE_HW_STATE_AARCH32 0x8400000d
#define PSCI_NODE_HW_STATE_AARCH64 0xc400000d
#define PSCI_SYSTEM_SUSPEND_AARCH32 0x8400000E #define PSCI_SYSTEM_SUSPEND_AARCH32 0x8400000E
#define PSCI_SYSTEM_SUSPEND_AARCH64 0xc400000E #define PSCI_SYSTEM_SUSPEND_AARCH64 0xc400000E
#define PSCI_STAT_RESIDENCY_AARCH32 0x84000010 #define PSCI_STAT_RESIDENCY_AARCH32 0x84000010
...@@ -199,6 +201,17 @@ typedef enum { ...@@ -199,6 +201,17 @@ typedef enum {
AFF_STATE_ON_PENDING = 2 AFF_STATE_ON_PENDING = 2
} aff_info_state_t; } aff_info_state_t;
/*
* These are the power states reported by PSCI_NODE_HW_STATE API for the
* specified CPU. The definitions of these states can be found in Section 5.15.3
* of PSCI specification (ARM DEN 0022C).
*/
typedef enum {
HW_ON = 0,
HW_OFF = 1,
HW_STANDBY = 2
} node_hw_state_t;
/* /*
* Macro to represent invalid affinity level within PSCI. * Macro to represent invalid affinity level within PSCI.
*/ */
...@@ -293,6 +306,7 @@ typedef struct plat_psci_ops { ...@@ -293,6 +306,7 @@ typedef struct plat_psci_ops {
int (*translate_power_state_by_mpidr)(u_register_t mpidr, int (*translate_power_state_by_mpidr)(u_register_t mpidr,
unsigned int power_state, unsigned int power_state,
psci_power_state_t *output_state); psci_power_state_t *output_state);
int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
} plat_psci_ops_t; } plat_psci_ops_t;
/******************************************************************************* /*******************************************************************************
...@@ -330,6 +344,8 @@ int psci_affinity_info(u_register_t target_affinity, ...@@ -330,6 +344,8 @@ int psci_affinity_info(u_register_t target_affinity,
int psci_migrate(u_register_t target_cpu); int psci_migrate(u_register_t target_cpu);
int psci_migrate_info_type(void); int psci_migrate_info_type(void);
long psci_migrate_info_up_cpu(void); long psci_migrate_info_up_cpu(void);
int psci_node_hw_state(u_register_t target_cpu,
unsigned int power_level);
int psci_features(unsigned int psci_fid); int psci_features(unsigned int psci_fid);
void __dead2 psci_power_down_wfi(void); void __dead2 psci_power_down_wfi(void);
void psci_arch_setup(void); void psci_arch_setup(void);
......
...@@ -295,6 +295,31 @@ long psci_migrate_info_up_cpu(void) ...@@ -295,6 +295,31 @@ long psci_migrate_info_up_cpu(void)
return resident_cpu_mpidr; return resident_cpu_mpidr;
} }
int psci_node_hw_state(u_register_t target_cpu,
unsigned int power_level)
{
int rc;
/* Validate target_cpu */
rc = psci_validate_mpidr(target_cpu);
if (rc != PSCI_E_SUCCESS)
return PSCI_E_INVALID_PARAMS;
/* Validate power_level against PLAT_MAX_PWR_LVL */
if (power_level > PLAT_MAX_PWR_LVL)
return PSCI_E_INVALID_PARAMS;
/*
* Dispatch this call to platform to query power controller, and pass on
* to the caller what it returns
*/
assert(psci_plat_pm_ops->get_node_hw_state);
rc = psci_plat_pm_ops->get_node_hw_state(target_cpu, power_level);
assert((rc >= HW_ON && rc <= HW_STANDBY) || rc == PSCI_E_NOT_SUPPORTED
|| rc == PSCI_E_INVALID_PARAMS);
return rc;
}
int psci_features(unsigned int psci_fid) int psci_features(unsigned int psci_fid)
{ {
unsigned int local_caps = psci_caps; unsigned int local_caps = psci_caps;
...@@ -378,6 +403,9 @@ u_register_t psci_smc_handler(uint32_t smc_fid, ...@@ -378,6 +403,9 @@ u_register_t psci_smc_handler(uint32_t smc_fid,
case PSCI_MIG_INFO_UP_CPU_AARCH32: case PSCI_MIG_INFO_UP_CPU_AARCH32:
return psci_migrate_info_up_cpu(); return psci_migrate_info_up_cpu();
case PSCI_NODE_HW_STATE_AARCH32:
return psci_node_hw_state(x1, x2);
case PSCI_SYSTEM_SUSPEND_AARCH32: case PSCI_SYSTEM_SUSPEND_AARCH32:
return psci_system_suspend(x1, x2); return psci_system_suspend(x1, x2);
...@@ -422,6 +450,9 @@ u_register_t psci_smc_handler(uint32_t smc_fid, ...@@ -422,6 +450,9 @@ u_register_t psci_smc_handler(uint32_t smc_fid,
case PSCI_MIG_INFO_UP_CPU_AARCH64: case PSCI_MIG_INFO_UP_CPU_AARCH64:
return psci_migrate_info_up_cpu(); return psci_migrate_info_up_cpu();
case PSCI_NODE_HW_STATE_AARCH64:
return psci_node_hw_state(x1, x2);
case PSCI_SYSTEM_SUSPEND_AARCH64: case PSCI_SYSTEM_SUSPEND_AARCH64:
return psci_system_suspend(x1, x2); return psci_system_suspend(x1, x2);
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \ define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \
define_psci_cap(PSCI_MIG_AARCH64) | \ define_psci_cap(PSCI_MIG_AARCH64) | \
define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) | \ define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) | \
define_psci_cap(PSCI_NODE_HW_STATE_AARCH64) | \
define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) | \ define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) | \
define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) | \ define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) | \
define_psci_cap(PSCI_STAT_COUNT_AARCH64)) define_psci_cap(PSCI_STAT_COUNT_AARCH64))
......
...@@ -256,6 +256,8 @@ int psci_setup(uintptr_t mailbox_ep) ...@@ -256,6 +256,8 @@ int psci_setup(uintptr_t mailbox_ep)
psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF); psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF);
if (psci_plat_pm_ops->system_reset) if (psci_plat_pm_ops->system_reset)
psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET); psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
if (psci_plat_pm_ops->get_node_hw_state)
psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
#if ENABLE_PSCI_STAT #if ENABLE_PSCI_STAT
psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64); psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment