blob: 0cb75a02df54134d201e9f94f2445feabeca487f [file] [log] [blame]
Sumit Garg0f18bc42018-06-15 15:20:53 +05301/*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Sumit Garg0f18bc42018-06-15 15:20:53 +05307#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008#include <string.h>
9
Sumit Garg0f18bc42018-06-15 15:20:53 +053010#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011
12#include <arch_helpers.h>
13#include <common/debug.h>
Sumit Garg0f18bc42018-06-15 15:20:53 +053014#include <sq_common.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015
Sumit Garg0f18bc42018-06-15 15:20:53 +053016#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
31static void scpi_secure_message_start(void)
32{
33 mhu_secure_message_start(SCPI_MHU_SLOT_ID);
34}
35
36static 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
48static 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
73static void scpi_secure_message_end(void)
74{
75 mhu_secure_message_end(SCPI_MHU_SLOT_ID);
76}
77
78int 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
116void 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
149uint32_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}
Ard Biesheuvel6fc122f2018-06-15 15:25:42 +0530174
175uint32_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}