From 28d3d614b57730bdf364e49259d3c42599d26145 Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Wed, 3 Aug 2016 15:54:50 +0100 Subject: [PATCH] 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 --- docs/firmware-design.md | 2 +- docs/porting-guide.md | 14 ++++++++++++++ include/lib/psci/psci.h | 16 ++++++++++++++++ lib/psci/psci_main.c | 31 +++++++++++++++++++++++++++++++ lib/psci/psci_private.h | 1 + lib/psci/psci_setup.c | 2 ++ 6 files changed, 65 insertions(+), 1 deletion(-) diff --git a/docs/firmware-design.md b/docs/firmware-design.md index 68cad2e3b..90ce4b1bf 100644 --- a/docs/firmware-design.md +++ b/docs/firmware-design.md @@ -716,7 +716,7 @@ required support. |`PSCI_FEATURES` | Yes | | |`CPU_FREEZE` | No | | |`CPU_DEFAULT_SUSPEND` | No | | -|`CPU_HW_STATE` | No | | +|`NODE_HW_STATE` | Yes* | | |`SYSTEM_SUSPEND` | Yes* | | |`PSCI_SET_SUSPEND_MODE`| No | | |`PSCI_STAT_RESIDENCY` | Yes* | | diff --git a/docs/porting-guide.md b/docs/porting-guide.md index 8dad4a051..195c9374d 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -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 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) ---------------------------------------------- BL31 implements an Interrupt Management Framework (IMF) to manage interrupts diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h index a583fef7e..02cbbf355 100644 --- a/include/lib/psci/psci.h +++ b/include/lib/psci/psci.h @@ -78,6 +78,8 @@ #define PSCI_SYSTEM_OFF 0x84000008 #define PSCI_SYSTEM_RESET 0x84000009 #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_AARCH64 0xc400000E #define PSCI_STAT_RESIDENCY_AARCH32 0x84000010 @@ -199,6 +201,17 @@ typedef enum { AFF_STATE_ON_PENDING = 2 } 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. */ @@ -293,6 +306,7 @@ typedef struct plat_psci_ops { int (*translate_power_state_by_mpidr)(u_register_t mpidr, unsigned int power_state, psci_power_state_t *output_state); + int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level); } plat_psci_ops_t; /******************************************************************************* @@ -330,6 +344,8 @@ int psci_affinity_info(u_register_t target_affinity, int psci_migrate(u_register_t target_cpu); int psci_migrate_info_type(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); void __dead2 psci_power_down_wfi(void); void psci_arch_setup(void); diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c index 3ad3dd40e..23bd106ca 100644 --- a/lib/psci/psci_main.c +++ b/lib/psci/psci_main.c @@ -295,6 +295,31 @@ long psci_migrate_info_up_cpu(void) 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) { unsigned int local_caps = psci_caps; @@ -378,6 +403,9 @@ u_register_t psci_smc_handler(uint32_t smc_fid, case PSCI_MIG_INFO_UP_CPU_AARCH32: return psci_migrate_info_up_cpu(); + case PSCI_NODE_HW_STATE_AARCH32: + return psci_node_hw_state(x1, x2); + case PSCI_SYSTEM_SUSPEND_AARCH32: return psci_system_suspend(x1, x2); @@ -422,6 +450,9 @@ u_register_t psci_smc_handler(uint32_t smc_fid, case PSCI_MIG_INFO_UP_CPU_AARCH64: return psci_migrate_info_up_cpu(); + case PSCI_NODE_HW_STATE_AARCH64: + return psci_node_hw_state(x1, x2); + case PSCI_SYSTEM_SUSPEND_AARCH64: return psci_system_suspend(x1, x2); diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h index b795c8e03..781b3b526 100644 --- a/lib/psci/psci_private.h +++ b/lib/psci/psci_private.h @@ -68,6 +68,7 @@ define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \ define_psci_cap(PSCI_MIG_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_STAT_RESIDENCY_AARCH64) | \ define_psci_cap(PSCI_STAT_COUNT_AARCH64)) diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c index 20d06352c..1ac1f23db 100644 --- a/lib/psci/psci_setup.c +++ b/lib/psci/psci_setup.c @@ -256,6 +256,8 @@ int psci_setup(uintptr_t mailbox_ep) psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF); if (psci_plat_pm_ops->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 psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);