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