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