PSCI: Add support for PSCI NODE_HW_STATE API
authorJeenu Viswambharan <[email protected]>
Wed, 3 Aug 2016 14:54:50 +0000 (15:54 +0100)
committerJeenu Viswambharan <[email protected]>
Thu, 15 Sep 2016 10:17:55 +0000 (11:17 +0100)
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
docs/porting-guide.md
include/lib/psci/psci.h
lib/psci/psci_main.c
lib/psci/psci_private.h
lib/psci/psci_setup.c

index 68cad2e3bfb8ff8a72817543ad02b83e29b46336..90ce4b1bf5b0979b5bb601c74edd0c4f8aec7a6d 100644 (file)
@@ -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*    |                                           |
index 8dad4a0516ce902dabddf4f095966c165fc10ddf..195c9374decd4c2846788fc51cd83f4ee2e66e77 100644 (file)
@@ -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
index a583fef7e680bc5869017a854950071d77a778c4..02cbbf3555ba0379c10fa5dc8de50b5673b9c908 100644 (file)
@@ -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);
index 3ad3dd40ef12132ff7493fc097a970e3e5d814f6..23bd106ca83fc501c90b886a2436f21aca6c6b6c 100644 (file)
@@ -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);
 
index b795c8e037ef6ede91a3c8d51c0dab407429cf83..781b3b5265c946dd0adee33a0a2140998acf5e67 100644 (file)
@@ -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))
index 20d06352c41ba621515ccb6b6723386ddd6162e3..1ac1f23dbc33b3d140c0be57b51a7a8f48014523 100644 (file)
@@ -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);