1 /*
2  * Copyright (c) 2018, 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 <platform_def.h>
11 
12 #include <arch_helpers.h>
13 #include <common/debug.h>
14 #include <sq_common.h>
15 
16 #include "sq_mhu.h"
17 #include "sq_scpi.h"
18 
19 #define SCPI_SHARED_MEM_SCP_TO_AP	PLAT_SQ_SCP_COM_SHARED_MEM_BASE
20 #define SCPI_SHARED_MEM_AP_TO_SCP	(PLAT_SQ_SCP_COM_SHARED_MEM_BASE \
21 								 + 0x100)
22 
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 /* ID of the MHU slot used for the SCPI protocol */
29 #define SCPI_MHU_SLOT_ID		0
30 
scpi_secure_message_start(void)31 static void scpi_secure_message_start(void)
32 {
33 	mhu_secure_message_start(SCPI_MHU_SLOT_ID);
34 }
35 
scpi_secure_message_send(size_t payload_size)36 static void scpi_secure_message_send(size_t payload_size)
37 {
38 	/*
39 	 * Ensure that any write to the SCPI payload area is seen by SCP before
40 	 * we write to the MHU register. If these 2 writes were reordered by
41 	 * the CPU then SCP would read stale payload data
42 	 */
43 	dmbst();
44 
45 	mhu_secure_message_send(SCPI_MHU_SLOT_ID);
46 }
47 
scpi_secure_message_receive(scpi_cmd_t * cmd)48 static void scpi_secure_message_receive(scpi_cmd_t *cmd)
49 {
50 	uint32_t mhu_status;
51 
52 	assert(cmd != NULL);
53 
54 	mhu_status = mhu_secure_message_wait();
55 
56 	/* Expect an SCPI message, reject any other protocol */
57 	if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
58 		ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
59 			mhu_status);
60 		panic();
61 	}
62 
63 	/*
64 	 * Ensure that any read to the SCPI payload area is done after reading
65 	 * the MHU register. If these 2 reads were reordered then the CPU would
66 	 * read invalid payload data
67 	 */
68 	dmbld();
69 
70 	memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
71 }
72 
scpi_secure_message_end(void)73 static void scpi_secure_message_end(void)
74 {
75 	mhu_secure_message_end(SCPI_MHU_SLOT_ID);
76 }
77 
scpi_wait_ready(void)78 int scpi_wait_ready(void)
79 {
80 	scpi_cmd_t scpi_cmd;
81 	scpi_status_t status = SCP_OK;
82 
83 	VERBOSE("Waiting for SCP_READY command...\n");
84 
85 	/* Get a message from the SCP */
86 	scpi_secure_message_start();
87 	scpi_secure_message_receive(&scpi_cmd);
88 	scpi_secure_message_end();
89 
90 	/* We are expecting 'SCP Ready', produce correct error if it's not */
91 	if (scpi_cmd.id != SCPI_CMD_SCP_READY) {
92 		ERROR("Unexpected SCP command: expected command #%u,"
93 		      "got command #%u\n", SCPI_CMD_SCP_READY, scpi_cmd.id);
94 		status = SCP_E_SUPPORT;
95 	} else if (scpi_cmd.size != 0) {
96 		ERROR("SCP_READY command has incorrect size: expected 0,"
97 		      "got %u\n", scpi_cmd.size);
98 		status = SCP_E_SIZE;
99 	}
100 
101 	VERBOSE("Sending response for SCP_READY command\n");
102 
103 	/*
104 	 * Send our response back to SCP.
105 	 * We are using the same SCPI header, just update the status field.
106 	 */
107 	scpi_cmd.status = status;
108 	scpi_secure_message_start();
109 	memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd));
110 	scpi_secure_message_send(0);
111 	scpi_secure_message_end();
112 
113 	return status == SCP_OK ? 0 : -1;
114 }
115 
scpi_set_sq_power_state(unsigned int mpidr,scpi_power_state_t cpu_state,scpi_power_state_t cluster_state,scpi_power_state_t sq_state)116 void scpi_set_sq_power_state(unsigned int mpidr, scpi_power_state_t cpu_state,
117 		scpi_power_state_t cluster_state, scpi_power_state_t sq_state)
118 {
119 	scpi_cmd_t *cmd;
120 	uint32_t state = 0;
121 	uint32_t *payload_addr;
122 
123 	state |= mpidr & 0x0f;	/* CPU ID */
124 	state |= (mpidr & 0xf00) >> 4;	/* Cluster ID */
125 	state |= cpu_state << 8;
126 	state |= cluster_state << 12;
127 	state |= sq_state << 16;
128 
129 	scpi_secure_message_start();
130 
131 	/* Populate the command header */
132 	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
133 	cmd->id = SCPI_CMD_SET_POWER_STATE;
134 	cmd->set = SCPI_SET_NORMAL;
135 	cmd->sender = 0;
136 	cmd->size = sizeof(state);
137 	/* Populate the command payload */
138 	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
139 	*payload_addr = state;
140 	scpi_secure_message_send(sizeof(state));
141 
142 	/*
143 	 * SCP does not reply to this command in order to avoid MHU interrupts
144 	 * from the sender, which could interfere with its power state request.
145 	 */
146 	scpi_secure_message_end();
147 }
148 
scpi_sys_power_state(scpi_system_state_t system_state)149 uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
150 {
151 	scpi_cmd_t *cmd;
152 	uint8_t *payload_addr;
153 	scpi_cmd_t response;
154 
155 	scpi_secure_message_start();
156 
157 	/* Populate the command header */
158 	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
159 	cmd->id = SCPI_CMD_SYS_POWER_STATE;
160 	cmd->set = 0;
161 	cmd->sender = 0;
162 	cmd->size = sizeof(*payload_addr);
163 	/* Populate the command payload */
164 	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
165 	*payload_addr = system_state & 0xff;
166 	scpi_secure_message_send(sizeof(*payload_addr));
167 
168 	scpi_secure_message_receive(&response);
169 
170 	scpi_secure_message_end();
171 
172 	return response.status;
173 }
174 
scpi_get_draminfo(struct draminfo * info)175 uint32_t scpi_get_draminfo(struct draminfo *info)
176 {
177 	scpi_cmd_t *cmd;
178 	struct {
179 		scpi_cmd_t	cmd;
180 		struct draminfo	info;
181 	} response;
182 	uint32_t mhu_status;
183 
184 	scpi_secure_message_start();
185 
186 	/* Populate the command header */
187 	cmd		= SCPI_CMD_HEADER_AP_TO_SCP;
188 	cmd->id		= SCPI_CMD_GET_DRAMINFO;
189 	cmd->set	= SCPI_SET_EXTENDED;
190 	cmd->sender	= 0;
191 	cmd->size	= 0;
192 
193 	scpi_secure_message_send(0);
194 
195 	mhu_status = mhu_secure_message_wait();
196 
197 	/* Expect an SCPI message, reject any other protocol */
198 	if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
199 		ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
200 			mhu_status);
201 		panic();
202 	}
203 
204 	/*
205 	 * Ensure that any read to the SCPI payload area is done after reading
206 	 * the MHU register. If these 2 reads were reordered then the CPU would
207 	 * read invalid payload data
208 	 */
209 	dmbld();
210 
211 	memcpy(&response, (void *)SCPI_SHARED_MEM_SCP_TO_AP, sizeof(response));
212 
213 	scpi_secure_message_end();
214 
215 	if (response.cmd.status == SCP_OK)
216 		*info = response.info;
217 
218 	return response.cmd.status;
219 }
220