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
scpi_secure_message_start(void)36 static void scpi_secure_message_start(void)
37 {
38 mhu_secure_message_start(SCPI_MHU_SLOT_ID);
39 }
40
scpi_secure_message_send(size_t payload_size)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
scpi_secure_message_receive(scpi_cmd_t * cmd)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
scpi_secure_message_end(void)78 static void scpi_secure_message_end(void)
79 {
80 mhu_secure_message_end(SCPI_MHU_SLOT_ID);
81 }
82
scpi_wait_ready(void)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
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)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 */
scpi_get_css_power_state(unsigned int mpidr,unsigned int * cpu_state_p,unsigned int * cluster_state_p)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
scpi_sys_power_state(scpi_system_state_t system_state)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