diff --git a/drivers/arm/css/scpi/css_scpi.c b/drivers/arm/css/scpi/css_scpi.c new file mode 100644 index 0000000..4b73265 --- /dev/null +++ b/drivers/arm/css/scpi/css_scpi.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SCPI_SHARED_MEM_SCP_TO_AP PLAT_CSS_SCP_COM_SHARED_MEM_BASE +#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 + +static void scpi_secure_message_start(void) +{ + mhu_secure_message_start(SCPI_MHU_SLOT_ID); +} + +static void scpi_secure_message_send(size_t payload_size) +{ + /* + * Ensure that any write to the SCPI payload area is seen by SCP before + * we write to the MHU register. If these 2 writes were reordered by + * the CPU then SCP would read stale payload data + */ + dmbst(); + + mhu_secure_message_send(SCPI_MHU_SLOT_ID); +} + +static void scpi_secure_message_receive(scpi_cmd_t *cmd) +{ + uint32_t mhu_status; + + assert(cmd != NULL); + + mhu_status = mhu_secure_message_wait(); + + /* Expect an SCPI message, reject any other protocol */ + if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { + ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", + mhu_status); + panic(); + } + + /* + * Ensure that any read to the SCPI payload area is done after reading + * the MHU register. If these 2 reads were reordered then the CPU would + * read invalid payload data + */ + dmbld(); + + memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd)); +} + +static void scpi_secure_message_end(void) +{ + mhu_secure_message_end(SCPI_MHU_SLOT_ID); +} + +int scpi_wait_ready(void) +{ + scpi_cmd_t scpi_cmd; + + VERBOSE("Waiting for SCP_READY command...\n"); + + /* Get a message from the SCP */ + scpi_secure_message_start(); + scpi_secure_message_receive(&scpi_cmd); + scpi_secure_message_end(); + + /* We are expecting 'SCP Ready', produce correct error if it's not */ + scpi_status_t status = SCP_OK; + if (scpi_cmd.id != SCPI_CMD_SCP_READY) { + ERROR("Unexpected SCP command: expected command #%u, got command #%u\n", + SCPI_CMD_SCP_READY, scpi_cmd.id); + status = SCP_E_SUPPORT; + } else if (scpi_cmd.size != 0) { + ERROR("SCP_READY command has incorrect size: expected 0, got %u\n", + scpi_cmd.size); + status = SCP_E_SIZE; + } + + VERBOSE("Sending response for SCP_READY command\n"); + + /* + * Send our response back to SCP. + * We are using the same SCPI header, just update the status field. + */ + scpi_cmd.status = status; + scpi_secure_message_start(); + memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd)); + scpi_secure_message_send(0); + scpi_secure_message_end(); + + return status == SCP_OK ? 0 : -1; +} + +void scpi_set_css_power_state(unsigned int mpidr, + scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, + scpi_power_state_t css_state) +{ + scpi_cmd_t *cmd; + uint32_t state = 0; + uint32_t *payload_addr; + +#if ARM_PLAT_MT + /* + * The current SCPI driver only caters for single-threaded platforms. + * Hence we ignore the thread ID (which is always 0) for such platforms. + */ + state |= (mpidr >> MPIDR_AFF1_SHIFT) & 0x0f; /* CPU ID */ + state |= ((mpidr >> MPIDR_AFF2_SHIFT) & 0x0f) << 4; /* Cluster ID */ +#else + state |= mpidr & 0x0f; /* CPU ID */ + state |= (mpidr & 0xf00) >> 4; /* Cluster ID */ +#endif /* ARM_PLAT_MT */ + + state |= cpu_state << 8; + state |= cluster_state << 12; + state |= css_state << 16; + + scpi_secure_message_start(); + + /* Populate the command header */ + cmd = SCPI_CMD_HEADER_AP_TO_SCP; + cmd->id = SCPI_CMD_SET_CSS_POWER_STATE; + cmd->set = SCPI_SET_NORMAL; + cmd->sender = 0; + cmd->size = sizeof(state); + /* Populate the command payload */ + payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; + *payload_addr = state; + scpi_secure_message_send(sizeof(state)); + /* + * SCP does not reply to this command in order to avoid MHU interrupts + * from the sender, which could interfere with its power state request. + */ + + 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 + */ +#if ARM_PLAT_MT + /* + * The current SCPI driver only caters for single-threaded platforms. + * Hence we ignore the thread ID (which is always 0) for such platforms. + */ + cpu = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + cluster = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; +#else + cpu = mpidr & MPIDR_AFFLVL_MASK; + cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; +#endif /* ARM_PLAT_MT */ + if (cpu >= 8 || cluster >= 0xf) + return -1; + + scpi_secure_message_start(); + + /* Populate request headers */ + zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd)); + cmd = SCPI_CMD_HEADER_AP_TO_SCP; + 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; + uint8_t *payload_addr; + scpi_cmd_t response; + + scpi_secure_message_start(); + + /* Populate the command header */ + cmd = SCPI_CMD_HEADER_AP_TO_SCP; + cmd->id = SCPI_CMD_SYS_POWER_STATE; + cmd->set = 0; + cmd->sender = 0; + cmd->size = sizeof(*payload_addr); + /* Populate the command payload */ + payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; + *payload_addr = system_state & 0xff; + scpi_secure_message_send(sizeof(*payload_addr)); + + scpi_secure_message_receive(&response); + + scpi_secure_message_end(); + + return response.status; +} diff --git a/include/drivers/arm/css/css_scpi.h b/include/drivers/arm/css/css_scpi.h new file mode 100644 index 0000000..68fc60a --- /dev/null +++ b/include/drivers/arm/css/css_scpi.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CSS_SCPI_H +#define CSS_SCPI_H + +#include +#include + +/* + * An SCPI command consists of a header and a payload. + * The following structure describes the header. It is 64-bit long. + */ +typedef struct { + /* Command ID */ + uint32_t id : 7; + /* Set ID. Identifies whether this is a standard or extended command. */ + uint32_t set : 1; + /* Sender ID to match a reply. The value is sender specific. */ + uint32_t sender : 8; + /* Size of the payload in bytes (0 - 511) */ + uint32_t size : 9; + uint32_t reserved : 7; + /* + * Status indicating the success of a command. + * See the enum below. + */ + uint32_t status; +} scpi_cmd_t; + +typedef enum { + SCPI_SET_NORMAL = 0, /* Normal SCPI commands */ + SCPI_SET_EXTENDED /* Extended SCPI commands */ +} scpi_set_t; + +enum { + SCP_OK = 0, /* Success */ + SCP_E_PARAM, /* Invalid parameter(s) */ + SCP_E_ALIGN, /* Invalid alignment */ + SCP_E_SIZE, /* Invalid size */ + SCP_E_HANDLER, /* Invalid handler or callback */ + SCP_E_ACCESS, /* Invalid access or permission denied */ + SCP_E_RANGE, /* Value out of range */ + SCP_E_TIMEOUT, /* Time out has ocurred */ + SCP_E_NOMEM, /* Invalid memory area or pointer */ + SCP_E_PWRSTATE, /* Invalid power state */ + SCP_E_SUPPORT, /* Feature not supported or disabled */ + SCPI_E_DEVICE, /* Device error */ + SCPI_E_BUSY, /* Device is busy */ +}; + +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, + scpi_power_off = 3, +} scpi_power_state_t; + +typedef enum { + scpi_system_shutdown = 0, + scpi_system_reboot = 1, + scpi_system_reset = 2 +} scpi_system_state_t; + +int scpi_wait_ready(void); +void scpi_set_css_power_state(unsigned int 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); + +#endif /* CSS_SCPI_H */ diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk index 55303f1..36da732 100644 --- a/plat/arm/css/common/css_common.mk +++ b/plat/arm/css/common/css_common.mk @@ -27,8 +27,8 @@ ifeq (${CSS_USE_SCMI_SDS_DRIVER},0) BL31_SOURCES += drivers/arm/css/mhu/css_mhu.c \ - plat/arm/css/drivers/scp/css_pm_scpi.c \ - plat/arm/css/drivers/scpi/css_scpi.c + drivers/arm/css/scpi/css_scpi.c \ + plat/arm/css/drivers/scp/css_pm_scpi.c else BL31_SOURCES += drivers/arm/css/mhu/css_mhu_doorbell.c \ drivers/arm/css/scmi/scmi_ap_core_proto.c \ @@ -55,13 +55,13 @@ BL2_SOURCES += plat/arm/css/drivers/scp/css_sds.c \ plat/arm/css/drivers/sds/sds.c else - BL2U_SOURCES += drivers/arm/css/mhu/css_mhu.c \ - plat/arm/css/drivers/scp/css_bom_bootloader.c \ - plat/arm/css/drivers/scpi/css_scpi.c + BL2U_SOURCES += drivers/arm/css/mhu/css_mhu.c \ + drivers/arm/css/scpi/css_scpi.c \ + plat/arm/css/drivers/scp/css_bom_bootloader.c - BL2_SOURCES += drivers/arm/css/mhu/css_mhu.c \ - plat/arm/css/drivers/scp/css_bom_bootloader.c \ - plat/arm/css/drivers/scpi/css_scpi.c + BL2_SOURCES += drivers/arm/css/mhu/css_mhu.c \ + drivers/arm/css/scpi/css_scpi.c \ + plat/arm/css/drivers/scp/css_bom_bootloader.c # Enable option to detect whether the SCP ROM firmware in use predates version # 1.7.0 and therefore, is incompatible. CSS_DETECT_PRE_1_7_0_SCP := 1 diff --git a/plat/arm/css/common/sp_min/css_sp_min.mk b/plat/arm/css/common/sp_min/css_sp_min.mk index 53daf1b..a7c61be 100644 --- a/plat/arm/css/common/sp_min/css_sp_min.mk +++ b/plat/arm/css/common/sp_min/css_sp_min.mk @@ -10,8 +10,8 @@ ifeq (${CSS_USE_SCMI_SDS_DRIVER},0) BL32_SOURCES += drivers/arm/css/mhu/css_mhu.c \ - plat/arm/css/drivers/scp/css_pm_scpi.c \ - plat/arm/css/drivers/scpi/css_scpi.c + drivers/arm/css/scpi/css_scpi.c \ + plat/arm/css/drivers/scp/css_pm_scpi.c else BL32_SOURCES += drivers/arm/css/mhu/css_mhu_doorbell.c \ drivers/arm/css/scmi/scmi_common.c \ diff --git a/plat/arm/css/drivers/scp/css_bom_bootloader.c b/plat/arm/css/drivers/scp/css_bom_bootloader.c index 5fe268d..40880da 100644 --- a/plat/arm/css/drivers/scp/css_bom_bootloader.c +++ b/plat/arm/css/drivers/scp/css_bom_bootloader.c @@ -10,10 +10,10 @@ #include #include #include +#include #include #include -#include "../scpi/css_scpi.h" #include "css_scp.h" /* ID of the MHU slot used for the BOM protocol */ diff --git a/plat/arm/css/drivers/scp/css_pm_scpi.c b/plat/arm/css/drivers/scp/css_pm_scpi.c index 04c5f9b..7e22816 100644 --- a/plat/arm/css/drivers/scp/css_pm_scpi.c +++ b/plat/arm/css/drivers/scp/css_pm_scpi.c @@ -8,10 +8,10 @@ #include #include +#include #include #include -#include "../scpi/css_scpi.h" #include "css_scp.h" /* diff --git a/plat/arm/css/drivers/scpi/css_scpi.c b/plat/arm/css/drivers/scpi/css_scpi.c deleted file mode 100644 index 4965c66..0000000 --- a/plat/arm/css/drivers/scpi/css_scpi.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "css_scpi.h" - -#define SCPI_SHARED_MEM_SCP_TO_AP PLAT_CSS_SCP_COM_SHARED_MEM_BASE -#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 - -static void scpi_secure_message_start(void) -{ - mhu_secure_message_start(SCPI_MHU_SLOT_ID); -} - -static void scpi_secure_message_send(size_t payload_size) -{ - /* - * Ensure that any write to the SCPI payload area is seen by SCP before - * we write to the MHU register. If these 2 writes were reordered by - * the CPU then SCP would read stale payload data - */ - dmbst(); - - mhu_secure_message_send(SCPI_MHU_SLOT_ID); -} - -static void scpi_secure_message_receive(scpi_cmd_t *cmd) -{ - uint32_t mhu_status; - - assert(cmd != NULL); - - mhu_status = mhu_secure_message_wait(); - - /* Expect an SCPI message, reject any other protocol */ - if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { - ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", - mhu_status); - panic(); - } - - /* - * Ensure that any read to the SCPI payload area is done after reading - * the MHU register. If these 2 reads were reordered then the CPU would - * read invalid payload data - */ - dmbld(); - - memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd)); -} - -static void scpi_secure_message_end(void) -{ - mhu_secure_message_end(SCPI_MHU_SLOT_ID); -} - -int scpi_wait_ready(void) -{ - scpi_cmd_t scpi_cmd; - - VERBOSE("Waiting for SCP_READY command...\n"); - - /* Get a message from the SCP */ - scpi_secure_message_start(); - scpi_secure_message_receive(&scpi_cmd); - scpi_secure_message_end(); - - /* We are expecting 'SCP Ready', produce correct error if it's not */ - scpi_status_t status = SCP_OK; - if (scpi_cmd.id != SCPI_CMD_SCP_READY) { - ERROR("Unexpected SCP command: expected command #%u, got command #%u\n", - SCPI_CMD_SCP_READY, scpi_cmd.id); - status = SCP_E_SUPPORT; - } else if (scpi_cmd.size != 0) { - ERROR("SCP_READY command has incorrect size: expected 0, got %u\n", - scpi_cmd.size); - status = SCP_E_SIZE; - } - - VERBOSE("Sending response for SCP_READY command\n"); - - /* - * Send our response back to SCP. - * We are using the same SCPI header, just update the status field. - */ - scpi_cmd.status = status; - scpi_secure_message_start(); - memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd)); - scpi_secure_message_send(0); - scpi_secure_message_end(); - - return status == SCP_OK ? 0 : -1; -} - -void scpi_set_css_power_state(unsigned int mpidr, - scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, - scpi_power_state_t css_state) -{ - scpi_cmd_t *cmd; - uint32_t state = 0; - uint32_t *payload_addr; - -#if ARM_PLAT_MT - /* - * The current SCPI driver only caters for single-threaded platforms. - * Hence we ignore the thread ID (which is always 0) for such platforms. - */ - state |= (mpidr >> MPIDR_AFF1_SHIFT) & 0x0f; /* CPU ID */ - state |= ((mpidr >> MPIDR_AFF2_SHIFT) & 0x0f) << 4; /* Cluster ID */ -#else - state |= mpidr & 0x0f; /* CPU ID */ - state |= (mpidr & 0xf00) >> 4; /* Cluster ID */ -#endif /* ARM_PLAT_MT */ - - state |= cpu_state << 8; - state |= cluster_state << 12; - state |= css_state << 16; - - scpi_secure_message_start(); - - /* Populate the command header */ - cmd = SCPI_CMD_HEADER_AP_TO_SCP; - cmd->id = SCPI_CMD_SET_CSS_POWER_STATE; - cmd->set = SCPI_SET_NORMAL; - cmd->sender = 0; - cmd->size = sizeof(state); - /* Populate the command payload */ - payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; - *payload_addr = state; - scpi_secure_message_send(sizeof(state)); - /* - * SCP does not reply to this command in order to avoid MHU interrupts - * from the sender, which could interfere with its power state request. - */ - - 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 - */ -#if ARM_PLAT_MT - /* - * The current SCPI driver only caters for single-threaded platforms. - * Hence we ignore the thread ID (which is always 0) for such platforms. - */ - cpu = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; - cluster = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; -#else - cpu = mpidr & MPIDR_AFFLVL_MASK; - cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; -#endif /* ARM_PLAT_MT */ - if (cpu >= 8 || cluster >= 0xf) - return -1; - - scpi_secure_message_start(); - - /* Populate request headers */ - zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd)); - cmd = SCPI_CMD_HEADER_AP_TO_SCP; - 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; - uint8_t *payload_addr; - scpi_cmd_t response; - - scpi_secure_message_start(); - - /* Populate the command header */ - cmd = SCPI_CMD_HEADER_AP_TO_SCP; - cmd->id = SCPI_CMD_SYS_POWER_STATE; - cmd->set = 0; - cmd->sender = 0; - cmd->size = sizeof(*payload_addr); - /* Populate the command payload */ - payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; - *payload_addr = system_state & 0xff; - scpi_secure_message_send(sizeof(*payload_addr)); - - scpi_secure_message_receive(&response); - - scpi_secure_message_end(); - - return response.status; -} diff --git a/plat/arm/css/drivers/scpi/css_scpi.h b/plat/arm/css/drivers/scpi/css_scpi.h deleted file mode 100644 index 68fc60a..0000000 --- a/plat/arm/css/drivers/scpi/css_scpi.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef CSS_SCPI_H -#define CSS_SCPI_H - -#include -#include - -/* - * An SCPI command consists of a header and a payload. - * The following structure describes the header. It is 64-bit long. - */ -typedef struct { - /* Command ID */ - uint32_t id : 7; - /* Set ID. Identifies whether this is a standard or extended command. */ - uint32_t set : 1; - /* Sender ID to match a reply. The value is sender specific. */ - uint32_t sender : 8; - /* Size of the payload in bytes (0 - 511) */ - uint32_t size : 9; - uint32_t reserved : 7; - /* - * Status indicating the success of a command. - * See the enum below. - */ - uint32_t status; -} scpi_cmd_t; - -typedef enum { - SCPI_SET_NORMAL = 0, /* Normal SCPI commands */ - SCPI_SET_EXTENDED /* Extended SCPI commands */ -} scpi_set_t; - -enum { - SCP_OK = 0, /* Success */ - SCP_E_PARAM, /* Invalid parameter(s) */ - SCP_E_ALIGN, /* Invalid alignment */ - SCP_E_SIZE, /* Invalid size */ - SCP_E_HANDLER, /* Invalid handler or callback */ - SCP_E_ACCESS, /* Invalid access or permission denied */ - SCP_E_RANGE, /* Value out of range */ - SCP_E_TIMEOUT, /* Time out has ocurred */ - SCP_E_NOMEM, /* Invalid memory area or pointer */ - SCP_E_PWRSTATE, /* Invalid power state */ - SCP_E_SUPPORT, /* Feature not supported or disabled */ - SCPI_E_DEVICE, /* Device error */ - SCPI_E_BUSY, /* Device is busy */ -}; - -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, - scpi_power_off = 3, -} scpi_power_state_t; - -typedef enum { - scpi_system_shutdown = 0, - scpi_system_reboot = 1, - scpi_system_reset = 2 -} scpi_system_state_t; - -int scpi_wait_ready(void); -void scpi_set_css_power_state(unsigned int 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); - -#endif /* CSS_SCPI_H */