blob: 416356bf2a786e6a13d497ccff509d609de5d003 [file] [log] [blame]
Dan Handley9df48042015-03-19 18:58:55 +00001/*
Samuel Holland0806cd22018-10-21 12:44:24 -05002 * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
Dan Handley9df48042015-03-19 18:58:55 +00003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Dan Handley9df48042015-03-19 18:58:55 +00005 */
6
Sandrine Bailleux04b66d82015-03-18 14:52:53 +00007#include <assert.h>
Sandrine Bailleux04b66d82015-03-18 14:52:53 +00008#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
10#include <arch_helpers.h>
11#include <common/debug.h>
Antonio Nino Diaz1b0c6f12019-01-23 21:08:43 +000012#include <drivers/arm/css/css_mhu.h>
Antonio Nino Diazae9654d2019-01-25 14:23:49 +000013#include <drivers/arm/css/css_scpi.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000014#include <lib/utils.h>
15#include <plat/common/platform.h>
Antonio Nino Diaza320ecd2019-01-15 14:19:50 +000016#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000017
Vikram Kanigiri72084192016-02-08 16:29:30 +000018#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)
Dan Handley9df48042015-03-19 18:58:55 +000021
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +010022/* Header and payload addresses for commands from AP to SCP */
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000023#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)))
Dan Handley9df48042015-03-19 18:58:55 +000027
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +010028/* 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
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000034/* ID of the MHU slot used for the SCPI protocol */
35#define SCPI_MHU_SLOT_ID 0
Dan Handley9df48042015-03-19 18:58:55 +000036
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000037static void scpi_secure_message_start(void)
Dan Handley9df48042015-03-19 18:58:55 +000038{
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000039 mhu_secure_message_start(SCPI_MHU_SLOT_ID);
Dan Handley9df48042015-03-19 18:58:55 +000040}
41
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000042static void scpi_secure_message_send(size_t payload_size)
Dan Handley9df48042015-03-19 18:58:55 +000043{
Soby Mathew200fffd2016-10-21 11:34:59 +010044 /*
45 * Ensure that any write to the SCPI payload area is seen by SCP before
Juan Castillo2e86cb12016-01-13 15:01:09 +000046 * we write to the MHU register. If these 2 writes were reordered by
Soby Mathew200fffd2016-10-21 11:34:59 +010047 * the CPU then SCP would read stale payload data
48 */
Juan Castillo2e86cb12016-01-13 15:01:09 +000049 dmbst();
Dan Handley9df48042015-03-19 18:58:55 +000050
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000051 mhu_secure_message_send(SCPI_MHU_SLOT_ID);
Dan Handley9df48042015-03-19 18:58:55 +000052}
53
Samuel Holland0806cd22018-10-21 12:44:24 -050054static int scpi_secure_message_receive(scpi_cmd_t *cmd)
Dan Handley9df48042015-03-19 18:58:55 +000055{
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000056 uint32_t mhu_status;
Dan Handley9df48042015-03-19 18:58:55 +000057
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000058 assert(cmd != NULL);
Dan Handley9df48042015-03-19 18:58:55 +000059
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000060 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);
Samuel Holland0806cd22018-10-21 12:44:24 -050066 return -1;
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000067 }
Dan Handley9df48042015-03-19 18:58:55 +000068
Soby Mathew200fffd2016-10-21 11:34:59 +010069 /*
70 * Ensure that any read to the SCPI payload area is done after reading
Juan Castillo2e86cb12016-01-13 15:01:09 +000071 * the MHU register. If these 2 reads were reordered then the CPU would
Soby Mathew200fffd2016-10-21 11:34:59 +010072 * read invalid payload data
73 */
Juan Castillo2e86cb12016-01-13 15:01:09 +000074 dmbld();
Dan Handley9df48042015-03-19 18:58:55 +000075
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000076 memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
Samuel Holland0806cd22018-10-21 12:44:24 -050077
78 return 0;
Dan Handley9df48042015-03-19 18:58:55 +000079}
80
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000081static void scpi_secure_message_end(void)
Dan Handley9df48042015-03-19 18:58:55 +000082{
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000083 mhu_secure_message_end(SCPI_MHU_SLOT_ID);
Dan Handley9df48042015-03-19 18:58:55 +000084}
85
86int scpi_wait_ready(void)
87{
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000088 scpi_cmd_t scpi_cmd;
Samuel Holland0806cd22018-10-21 12:44:24 -050089 int rc;
Sandrine Bailleux04b66d82015-03-18 14:52:53 +000090
91 VERBOSE("Waiting for SCP_READY command...\n");
92
Dan Handley9df48042015-03-19 18:58:55 +000093 /* Get a message from the SCP */
94 scpi_secure_message_start();
Samuel Holland0806cd22018-10-21 12:44:24 -050095 rc = scpi_secure_message_receive(&scpi_cmd);
Dan Handley9df48042015-03-19 18:58:55 +000096 scpi_secure_message_end();
97
Samuel Holland0806cd22018-10-21 12:44:24 -050098 /* If no message was received, don't send a response */
99 if (rc != 0)
100 return rc;
101
Dan Handley9df48042015-03-19 18:58:55 +0000102 /* We are expecting 'SCP Ready', produce correct error if it's not */
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000103 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 }
Dan Handley9df48042015-03-19 18:58:55 +0000113
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000114 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();
Dan Handley9df48042015-03-19 18:58:55 +0000125
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000126 return status == SCP_OK ? 0 : -1;
Dan Handley9df48042015-03-19 18:58:55 +0000127}
128
Soby Mathew200fffd2016-10-21 11:34:59 +0100129void 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)
Dan Handley9df48042015-03-19 18:58:55 +0000132{
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000133 scpi_cmd_t *cmd;
134 uint32_t state = 0;
135 uint32_t *payload_addr;
136
Summer Qin93c812f2017-02-28 16:46:17 +0000137#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
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000145 state |= mpidr & 0x0f; /* CPU ID */
Dan Handley9df48042015-03-19 18:58:55 +0000146 state |= (mpidr & 0xf00) >> 4; /* Cluster ID */
Summer Qin93c812f2017-02-28 16:46:17 +0000147#endif /* ARM_PLAT_MT */
148
Dan Handley9df48042015-03-19 18:58:55 +0000149 state |= cpu_state << 8;
150 state |= cluster_state << 12;
151 state |= css_state << 16;
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000152
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
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100170 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
Antonio Nino Diaz56b68ad2019-02-28 13:35:21 +0000179 * via supplied non-NULL pointer arguments.
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100180 *
181 * Returns 0 on success, or -1 on errors.
182 */
183int 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 */
jagadeesh ujja64fa64b2017-05-11 16:32:18 +0530194#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
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100202 cpu = mpidr & MPIDR_AFFLVL_MASK;
203 cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
jagadeesh ujja64fa64b2017-05-11 16:32:18 +0530204#endif /* ARM_PLAT_MT */
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100205 if (cpu >= 8 || cluster >= 0xf)
206 return -1;
207
208 scpi_secure_message_start();
209
210 /* Populate request headers */
Douglas Raillarda8954fc2017-01-26 15:54:44 +0000211 zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd));
212 cmd = SCPI_CMD_HEADER_AP_TO_SCP;
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100213 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);
Samuel Holland0806cd22018-10-21 12:44:24 -0500219 if (scpi_secure_message_receive(&response) != 0)
220 goto exit;
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100221
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
Antonio Nino Diaz56b68ad2019-02-28 13:35:21 +0000234 /* Update power state via pointers */
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100235 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
241exit:
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000242 scpi_secure_message_end();
Jeenu Viswambharanb1f68092016-08-04 12:44:52 +0100243 return rc;
Dan Handley9df48042015-03-19 18:58:55 +0000244}
245
246uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
247{
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000248 scpi_cmd_t *cmd;
249 uint8_t *payload_addr;
250 scpi_cmd_t response;
251
252 scpi_secure_message_start();
Dan Handley9df48042015-03-19 18:58:55 +0000253
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000254 /* 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
Samuel Holland0806cd22018-10-21 12:44:24 -0500265 /* If no response is received, fill in an error status */
266 if (scpi_secure_message_receive(&response) != 0)
267 response.status = SCP_E_TIMEOUT;
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000268
Dan Handley9df48042015-03-19 18:58:55 +0000269 scpi_secure_message_end();
Sandrine Bailleux04b66d82015-03-18 14:52:53 +0000270
271 return response.status;
Dan Handley9df48042015-03-19 18:58:55 +0000272}