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