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