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