SCPI: Add function to query CSS power state
authorJeenu Viswambharan <[email protected]>
Thu, 4 Aug 2016 11:44:52 +0000 (12:44 +0100)
committerJeenu Viswambharan <[email protected]>
Thu, 15 Sep 2016 10:18:48 +0000 (11:18 +0100)
This patch adds the function scpi_get_css_power_state to perform the
'Get CSS Power State' SCP command and handle its response. The function
parses SCP response to obtain power states of requested cluster and CPUs
within.

Change-Id: I3ea26e48dff1a139da73f6c1e0893f21accaf9f0

plat/arm/css/common/css_scpi.c
plat/arm/css/common/css_scpi.h

index 02d573c9fb6d78ff8fc2d4202bb79c63fbbb40cd..90a8939d985266903deb0185b7ff54490a456448 100644 (file)
 #define SCPI_SHARED_MEM_AP_TO_SCP      (PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
                                                                 + 0x100)
 
+/* Header and payload addresses for commands from AP to SCP */
 #define SCPI_CMD_HEADER_AP_TO_SCP              \
        ((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
 #define SCPI_CMD_PAYLOAD_AP_TO_SCP             \
        ((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
 
+/* Header and payload addresses for responses from SCP to AP */
+#define SCPI_RES_HEADER_SCP_TO_AP \
+       ((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP)
+#define SCPI_RES_PAYLOAD_SCP_TO_AP \
+       ((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t)))
+
 /* ID of the MHU slot used for the SCPI protocol */
 #define SCPI_MHU_SLOT_ID               0
 
@@ -163,6 +170,68 @@ void scpi_set_css_power_state(unsigned mpidr, scpi_power_state_t cpu_state,
        scpi_secure_message_end();
 }
 
+/*
+ * Query and obtain CSS power state from SCP.
+ *
+ * In response to the query, SCP returns power states of all CPUs in all
+ * clusters of the system. The returned response is then filtered based on the
+ * supplied MPIDR. Power states of requested cluster and CPUs within are updated
+ * via. supplied non-NULL pointer arguments.
+ *
+ * Returns 0 on success, or -1 on errors.
+ */
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+               unsigned int *cluster_state_p)
+{
+       scpi_cmd_t *cmd;
+       scpi_cmd_t response;
+       int power_state, cpu, cluster, rc = -1;
+
+       /*
+        * Extract CPU and cluster membership of the given MPIDR. SCPI caters
+        * for only up to 0xf clusters, and 8 CPUs per cluster
+        */
+       cpu = mpidr & MPIDR_AFFLVL_MASK;
+       cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+       if (cpu >= 8 || cluster >= 0xf)
+               return -1;
+
+       scpi_secure_message_start();
+
+       /* Populate request headers */
+       cmd = memset(SCPI_CMD_HEADER_AP_TO_SCP, 0, sizeof(*cmd));
+       cmd->id = SCPI_CMD_GET_CSS_POWER_STATE;
+
+       /*
+        * Send message and wait for SCP's response
+        */
+       scpi_secure_message_send(0);
+       scpi_secure_message_receive(&response);
+
+       if (response.status != SCP_OK)
+               goto exit;
+
+       /* Validate SCP response */
+       if (!CHECK_RESPONSE(response, cluster))
+               goto exit;
+
+       /* Extract power states for required cluster */
+       power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster);
+       if (CLUSTER_ID(power_state) != cluster)
+               goto exit;
+
+       /* Update power state via. pointers */
+       if (cluster_state_p)
+               *cluster_state_p = CLUSTER_POWER_STATE(power_state);
+       if (cpu_state_p)
+               *cpu_state_p = CPU_POWER_STATE(power_state);
+       rc = 0;
+
+exit:
+       scpi_secure_message_end();
+       return rc;
+}
+
 uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
 {
        scpi_cmd_t *cmd;
index 4a601f3ef14f5c3d7ce7e24bddc492c1a8d37bf8..1fb55e4ddc8e4f107a2f8148b752ecf16d65cd01 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -81,9 +81,34 @@ typedef uint32_t scpi_status_t;
 typedef enum {
        SCPI_CMD_SCP_READY = 0x01,
        SCPI_CMD_SET_CSS_POWER_STATE = 0x03,
+       SCPI_CMD_GET_CSS_POWER_STATE = 0x04,
        SCPI_CMD_SYS_POWER_STATE = 0x05
 } scpi_command_t;
 
+/*
+ * Macros to parse SCP response to GET_CSS_POWER_STATE command
+ *
+ *   [3:0] : cluster ID
+ *   [7:4] : cluster state: 0 = on; 3 = off; rest are reserved
+ *   [15:8]: on/off state for individual CPUs in the cluster
+ *
+ * Payload is in little-endian
+ */
+#define CLUSTER_ID(_resp)              ((_resp) & 0xf)
+#define CLUSTER_POWER_STATE(_resp)     (((_resp) >> 4) & 0xf)
+
+/* Result is a bit mask of CPU on/off states in the cluster */
+#define CPU_POWER_STATE(_resp)         (((_resp) >> 8) & 0xff)
+
+/*
+ * For GET_CSS_POWER_STATE, SCP returns the power states of every cluster. The
+ * size of response depends on the number of clusters in the system. The
+ * SCP-to-AP payload contains 2 bytes per cluster. Make sure the response is
+ * large enough to contain power states of a given cluster
+ */
+#define CHECK_RESPONSE(_resp, _clus) \
+       (_resp.size >= (((_clus) + 1) * 2))
+
 typedef enum {
        scpi_power_on = 0,
        scpi_power_retention = 1,
@@ -101,6 +126,8 @@ extern void scpi_set_css_power_state(unsigned mpidr,
                                        scpi_power_state_t cpu_state,
                                        scpi_power_state_t cluster_state,
                                        scpi_power_state_t css_state);
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+               unsigned int *cluster_state_p);
 uint32_t scpi_sys_power_state(scpi_system_state_t system_state);