• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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