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