Home | History | Annotate | Download | only in scpi
      1 /*
      2  * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch_helpers.h>
      8 #include <assert.h>
      9 #include <css_def.h>
     10 #include <debug.h>
     11 #include <platform.h>
     12 #include <string.h>
     13 #include <utils.h>
     14 #include "css_mhu.h"
     15 #include "css_scpi.h"
     16 
     17 #define SCPI_SHARED_MEM_SCP_TO_AP	PLAT_CSS_SCP_COM_SHARED_MEM_BASE
     18 #define SCPI_SHARED_MEM_AP_TO_SCP	(PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
     19 								 + 0x100)
     20 
     21 /* Header and payload addresses for commands from AP to SCP */
     22 #define SCPI_CMD_HEADER_AP_TO_SCP		\
     23 	((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
     24 #define SCPI_CMD_PAYLOAD_AP_TO_SCP		\
     25 	((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
     26 
     27 /* Header and payload addresses for responses from SCP to AP */
     28 #define SCPI_RES_HEADER_SCP_TO_AP \
     29 	((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP)
     30 #define SCPI_RES_PAYLOAD_SCP_TO_AP \
     31 	((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t)))
     32 
     33 /* ID of the MHU slot used for the SCPI protocol */
     34 #define SCPI_MHU_SLOT_ID		0
     35 
     36 static void scpi_secure_message_start(void)
     37 {
     38 	mhu_secure_message_start(SCPI_MHU_SLOT_ID);
     39 }
     40 
     41 static void scpi_secure_message_send(size_t payload_size)
     42 {
     43 	/*
     44 	 * Ensure that any write to the SCPI payload area is seen by SCP before
     45 	 * we write to the MHU register. If these 2 writes were reordered by
     46 	 * the CPU then SCP would read stale payload data
     47 	 */
     48 	dmbst();
     49 
     50 	mhu_secure_message_send(SCPI_MHU_SLOT_ID);
     51 }
     52 
     53 static void scpi_secure_message_receive(scpi_cmd_t *cmd)
     54 {
     55 	uint32_t mhu_status;
     56 
     57 	assert(cmd != NULL);
     58 
     59 	mhu_status = mhu_secure_message_wait();
     60 
     61 	/* Expect an SCPI message, reject any other protocol */
     62 	if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
     63 		ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
     64 			mhu_status);
     65 		panic();
     66 	}
     67 
     68 	/*
     69 	 * Ensure that any read to the SCPI payload area is done after reading
     70 	 * the MHU register. If these 2 reads were reordered then the CPU would
     71 	 * read invalid payload data
     72 	 */
     73 	dmbld();
     74 
     75 	memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
     76 }
     77 
     78 static void scpi_secure_message_end(void)
     79 {
     80 	mhu_secure_message_end(SCPI_MHU_SLOT_ID);
     81 }
     82 
     83 int scpi_wait_ready(void)
     84 {
     85 	scpi_cmd_t scpi_cmd;
     86 
     87 	VERBOSE("Waiting for SCP_READY command...\n");
     88 
     89 	/* Get a message from the SCP */
     90 	scpi_secure_message_start();
     91 	scpi_secure_message_receive(&scpi_cmd);
     92 	scpi_secure_message_end();
     93 
     94 	/* We are expecting 'SCP Ready', produce correct error if it's not */
     95 	scpi_status_t status = SCP_OK;
     96 	if (scpi_cmd.id != SCPI_CMD_SCP_READY) {
     97 		ERROR("Unexpected SCP command: expected command #%u, got command #%u\n",
     98 		      SCPI_CMD_SCP_READY, scpi_cmd.id);
     99 		status = SCP_E_SUPPORT;
    100 	} else if (scpi_cmd.size != 0) {
    101 		ERROR("SCP_READY command has incorrect size: expected 0, got %u\n",
    102 		      scpi_cmd.size);
    103 		status = SCP_E_SIZE;
    104 	}
    105 
    106 	VERBOSE("Sending response for SCP_READY command\n");
    107 
    108 	/*
    109 	 * Send our response back to SCP.
    110 	 * We are using the same SCPI header, just update the status field.
    111 	 */
    112 	scpi_cmd.status = status;
    113 	scpi_secure_message_start();
    114 	memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd));
    115 	scpi_secure_message_send(0);
    116 	scpi_secure_message_end();
    117 
    118 	return status == SCP_OK ? 0 : -1;
    119 }
    120 
    121 void scpi_set_css_power_state(unsigned int mpidr,
    122 		scpi_power_state_t cpu_state, scpi_power_state_t cluster_state,
    123 		scpi_power_state_t css_state)
    124 {
    125 	scpi_cmd_t *cmd;
    126 	uint32_t state = 0;
    127 	uint32_t *payload_addr;
    128 
    129 #if ARM_PLAT_MT
    130 	/*
    131 	 * The current SCPI driver only caters for single-threaded platforms.
    132 	 * Hence we ignore the thread ID (which is always 0) for such platforms.
    133 	 */
    134 	state |= (mpidr >> MPIDR_AFF1_SHIFT) & 0x0f;	/* CPU ID */
    135 	state |= ((mpidr >> MPIDR_AFF2_SHIFT) & 0x0f) << 4;	/* Cluster ID */
    136 #else
    137 	state |= mpidr & 0x0f;	/* CPU ID */
    138 	state |= (mpidr & 0xf00) >> 4;	/* Cluster ID */
    139 #endif /* ARM_PLAT_MT */
    140 
    141 	state |= cpu_state << 8;
    142 	state |= cluster_state << 12;
    143 	state |= css_state << 16;
    144 
    145 	scpi_secure_message_start();
    146 
    147 	/* Populate the command header */
    148 	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
    149 	cmd->id = SCPI_CMD_SET_CSS_POWER_STATE;
    150 	cmd->set = SCPI_SET_NORMAL;
    151 	cmd->sender = 0;
    152 	cmd->size = sizeof(state);
    153 	/* Populate the command payload */
    154 	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
    155 	*payload_addr = state;
    156 	scpi_secure_message_send(sizeof(state));
    157 	/*
    158 	 * SCP does not reply to this command in order to avoid MHU interrupts
    159 	 * from the sender, which could interfere with its power state request.
    160 	 */
    161 
    162 	scpi_secure_message_end();
    163 }
    164 
    165 /*
    166  * Query and obtain CSS power state from SCP.
    167  *
    168  * In response to the query, SCP returns power states of all CPUs in all
    169  * clusters of the system. The returned response is then filtered based on the
    170  * supplied MPIDR. Power states of requested cluster and CPUs within are updated
    171  * via. supplied non-NULL pointer arguments.
    172  *
    173  * Returns 0 on success, or -1 on errors.
    174  */
    175 int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
    176 		unsigned int *cluster_state_p)
    177 {
    178 	scpi_cmd_t *cmd;
    179 	scpi_cmd_t response;
    180 	int power_state, cpu, cluster, rc = -1;
    181 
    182 	/*
    183 	 * Extract CPU and cluster membership of the given MPIDR. SCPI caters
    184 	 * for only up to 0xf clusters, and 8 CPUs per cluster
    185 	 */
    186 #if ARM_PLAT_MT
    187 	/*
    188 	 * The current SCPI driver only caters for single-threaded platforms.
    189 	 * Hence we ignore the thread ID (which is always 0) for such platforms.
    190 	 */
    191 	cpu = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
    192 	cluster = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
    193 #else
    194 	cpu = mpidr & MPIDR_AFFLVL_MASK;
    195 	cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
    196 #endif  /* ARM_PLAT_MT */
    197 	if (cpu >= 8 || cluster >= 0xf)
    198 		return -1;
    199 
    200 	scpi_secure_message_start();
    201 
    202 	/* Populate request headers */
    203 	zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd));
    204 	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
    205 	cmd->id = SCPI_CMD_GET_CSS_POWER_STATE;
    206 
    207 	/*
    208 	 * Send message and wait for SCP's response
    209 	 */
    210 	scpi_secure_message_send(0);
    211 	scpi_secure_message_receive(&response);
    212 
    213 	if (response.status != SCP_OK)
    214 		goto exit;
    215 
    216 	/* Validate SCP response */
    217 	if (!CHECK_RESPONSE(response, cluster))
    218 		goto exit;
    219 
    220 	/* Extract power states for required cluster */
    221 	power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster);
    222 	if (CLUSTER_ID(power_state) != cluster)
    223 		goto exit;
    224 
    225 	/* Update power state via. pointers */
    226 	if (cluster_state_p)
    227 		*cluster_state_p = CLUSTER_POWER_STATE(power_state);
    228 	if (cpu_state_p)
    229 		*cpu_state_p = CPU_POWER_STATE(power_state);
    230 	rc = 0;
    231 
    232 exit:
    233 	scpi_secure_message_end();
    234 	return rc;
    235 }
    236 
    237 uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
    238 {
    239 	scpi_cmd_t *cmd;
    240 	uint8_t *payload_addr;
    241 	scpi_cmd_t response;
    242 
    243 	scpi_secure_message_start();
    244 
    245 	/* Populate the command header */
    246 	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
    247 	cmd->id = SCPI_CMD_SYS_POWER_STATE;
    248 	cmd->set = 0;
    249 	cmd->sender = 0;
    250 	cmd->size = sizeof(*payload_addr);
    251 	/* Populate the command payload */
    252 	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
    253 	*payload_addr = system_state & 0xff;
    254 	scpi_secure_message_send(sizeof(*payload_addr));
    255 
    256 	scpi_secure_message_receive(&response);
    257 
    258 	scpi_secure_message_end();
    259 
    260 	return response.status;
    261 }
    262