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