1 /*
2 * Copyright 2023-2025 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8
9 #include <arch_helpers.h>
10 #include <common/debug.h>
11 #include <drivers/arm/css/scmi.h>
12 #include "scmi_imx9.h"
13 #include <scmi_private.h>
14
15 /*
16 * API to set the SCMI AP core reset address and attributes
17 */
scmi_core_set_reset_addr(void * p,uint64_t reset_addr,uint32_t cpu_id,uint32_t attr)18 int scmi_core_set_reset_addr(void *p, uint64_t reset_addr, uint32_t cpu_id,
19 uint32_t attr)
20 {
21 mailbox_mem_t *mbx_mem;
22 unsigned int token = 0U;
23 int ret;
24 scmi_channel_t *ch = (scmi_channel_t *)p;
25
26 validate_scmi_channel(ch);
27
28 scmi_get_channel(ch);
29
30 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
31 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
32 IMX9_SCMI_CORE_RESET_ADDR_SET_MSG, token);
33 mbx_mem->len = IMX9_SCMI_CORE_RESET_ADDR_SET_MSG_LEN;
34 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
35 SCMI_PAYLOAD_ARG4(mbx_mem->payload, cpu_id, attr,
36 reset_addr & 0xffffffff, reset_addr >> 32);
37
38 scmi_send_sync_command(ch);
39
40 /* Get the return values */
41 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
42 assert(mbx_mem->len == IMX9_SCMI_CORE_RESET_ADDR_SET_RESP_LEN);
43 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
44
45 scmi_put_channel(ch);
46
47 return ret;
48 }
49
scmi_core_start(void * p,uint32_t cpu_id)50 int scmi_core_start(void *p, uint32_t cpu_id)
51 {
52 mailbox_mem_t *mbx_mem;
53 unsigned int token = 0U;
54 int ret;
55 scmi_channel_t *ch = (scmi_channel_t *)p;
56
57 validate_scmi_channel(ch);
58
59 scmi_get_channel(ch);
60
61 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
62 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
63 IMX9_SCMI_CORE_START_MSG, token);
64 mbx_mem->len = IMX9_SCMI_CORE_START_MSG_LEN;
65 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
66 SCMI_PAYLOAD_ARG1(mbx_mem->payload, cpu_id);
67
68 scmi_send_sync_command(ch);
69
70 /* Get the return values */
71 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
72 assert(mbx_mem->len == IMX9_SCMI_CORE_START_RESP_LEN);
73 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
74
75 scmi_put_channel(ch);
76
77 return ret;
78 }
79
scmi_core_stop(void * p,uint32_t cpu_id)80 int scmi_core_stop(void *p, uint32_t cpu_id)
81 {
82 mailbox_mem_t *mbx_mem;
83 unsigned int token = 0U;
84 int ret;
85 scmi_channel_t *ch = (scmi_channel_t *)p;
86
87 validate_scmi_channel(ch);
88
89 scmi_get_channel(ch);
90
91 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
92 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
93 IMX9_SCMI_CORE_STOP_MSG, token);
94 mbx_mem->len = IMX9_SCMI_CORE_STOP_MSG_LEN;
95 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
96 SCMI_PAYLOAD_ARG1(mbx_mem->payload, cpu_id);
97
98 scmi_send_sync_command(ch);
99
100 /* Get the return values */
101 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
102 assert(mbx_mem->len == IMX9_SCMI_CORE_STOP_RESP_LEN);
103 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
104
105 scmi_put_channel(ch);
106
107 return ret;
108 }
109
scmi_core_set_sleep_mode(void * p,uint32_t cpu_id,uint32_t wakeup,uint32_t mode)110 int scmi_core_set_sleep_mode(void *p, uint32_t cpu_id, uint32_t wakeup,
111 uint32_t mode)
112 {
113 mailbox_mem_t *mbx_mem;
114 unsigned int token = 0U;
115 int ret;
116 scmi_channel_t *ch = (scmi_channel_t *)p;
117
118 validate_scmi_channel(ch);
119
120 scmi_get_channel(ch);
121
122 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
123 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
124 IMX9_SCMI_CORE_SETSLEEPMODE_MSG, token);
125 mbx_mem->len = IMX9_SCMI_CORE_SETSLEEPMODE_MSG_LEN;
126 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
127 SCMI_PAYLOAD_ARG3(mbx_mem->payload, cpu_id, wakeup, mode);
128
129 scmi_send_sync_command(ch);
130
131 /* Get the return values */
132 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
133 assert(mbx_mem->len == IMX9_SCMI_CORE_SETSLEEPMODE_RESP_LEN);
134 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
135
136 scmi_put_channel(ch);
137
138 return ret;
139 }
140
scmi_core_Irq_wake_set(void * p,uint32_t cpu_id,uint32_t mask_idx,uint32_t num_mask,uint32_t * mask)141 int scmi_core_Irq_wake_set(void *p, uint32_t cpu_id, uint32_t mask_idx,
142 uint32_t num_mask, uint32_t *mask)
143 {
144 mailbox_mem_t *mbx_mem;
145 unsigned int token = 0U;
146 int ret;
147 scmi_channel_t *ch = (scmi_channel_t *)p;
148
149 validate_scmi_channel(ch);
150
151 scmi_get_channel(ch);
152
153 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
154 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
155 IMX9_SCMI_CORE_SETIRQWAKESET_MSG, token);
156 mbx_mem->len = IMX9_SCMI_CORE_SETIRQWAKESET_MSG_LEN;
157 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
158 SCMI_PAYLOAD_ARG3(mbx_mem->payload, cpu_id, mask_idx, num_mask);
159
160 for (unsigned int i = 0U; i < num_mask; i++) {
161 mbx_mem->payload[3U + i] = mask[i];
162 }
163
164 scmi_send_sync_command(ch);
165
166 /* Get the return values */
167 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
168 assert(mbx_mem->len == IMX9_SCMI_CORE_SETIRQWAKESET_RESP_LEN);
169 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
170
171 scmi_put_channel(ch);
172
173 return ret;
174 }
175
scmi_core_nonIrq_wake_set(void * p,uint32_t cpu_id,uint32_t mask_idx,uint32_t num_mask,uint32_t mask)176 int scmi_core_nonIrq_wake_set(void *p, uint32_t cpu_id, uint32_t mask_idx,
177 uint32_t num_mask, uint32_t mask)
178 {
179 mailbox_mem_t *mbx_mem;
180 unsigned int token = 0U;
181 int ret;
182 scmi_channel_t *ch = (scmi_channel_t *)p;
183
184 validate_scmi_channel(ch);
185 scmi_get_channel(ch);
186
187 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
188 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
189 IMX9_SCMI_CORE_NONIRQWAKESET_MSG, token);
190 mbx_mem->len = IMX9_SCMI_CORE_NONIRQWAKESET_MSG_LEN;
191 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
192 SCMI_PAYLOAD_ARG4(mbx_mem->payload, cpu_id, mask_idx, num_mask, mask);
193
194 scmi_send_sync_command(ch);
195
196 /* Get the return values */
197 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
198 assert(mbx_mem->len == IMX9_SCMI_CORE_NONIRQWAKESET_RESP_LEN);
199 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
200
201 scmi_put_channel(ch);
202
203 return ret;
204 }
205
scmi_core_lpm_mode_set(void * p,uint32_t cpu_id,uint32_t num_configs,struct scmi_lpm_config * cfg)206 int scmi_core_lpm_mode_set(void *p, uint32_t cpu_id,
207 uint32_t num_configs,
208 struct scmi_lpm_config *cfg)
209 {
210 mailbox_mem_t *mbx_mem;
211 unsigned int token = 0U;
212 int ret;
213 scmi_channel_t *ch = (scmi_channel_t *)p;
214
215 validate_scmi_channel(ch);
216
217 scmi_get_channel(ch);
218
219 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
220 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
221 IMX9_SCMI_CORE_LPMMODESET_MSG, token);
222 mbx_mem->len = IMX9_SCMI_CORE_LPMMODESET_MSG_LEN +
223 (num_configs * sizeof(struct scmi_lpm_config));
224 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
225 SCMI_PAYLOAD_ARG2(mbx_mem->payload, cpu_id, num_configs);
226
227 /* The lpm config starts from byte 2 in the payload memory */
228 unsigned int j = 2U;
229
230 for (unsigned int i = 0U; i < num_configs; i++) {
231 mmio_write_32((uintptr_t)&mbx_mem->payload[j++],
232 cfg[i].power_domain);
233 mmio_write_32((uintptr_t)&mbx_mem->payload[j++],
234 cfg[i].lpmsetting);
235 mmio_write_32((uintptr_t)&mbx_mem->payload[j++],
236 cfg[i].retentionmask);
237 }
238 scmi_send_sync_command(ch);
239
240 /* Get the return values */
241 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
242 assert(mbx_mem->len == IMX9_SCMI_CORE_LPMMODESET_RESP_LEN);
243 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
244
245 scmi_put_channel(ch);
246
247 return ret;
248 }
249
scmi_per_lpm_mode_set(void * p,uint32_t cpu_id,uint32_t num_configs,struct scmi_per_lpm_config * cfg)250 int scmi_per_lpm_mode_set(void *p, uint32_t cpu_id, uint32_t num_configs,
251 struct scmi_per_lpm_config *cfg)
252 {
253 mailbox_mem_t *mbx_mem;
254 unsigned int token = 0U;
255 int ret;
256 scmi_channel_t *ch = (scmi_channel_t *)p;
257 struct scmi_per_lpm_config *tmp = cfg;
258
259 validate_scmi_channel(ch);
260
261 scmi_get_channel(ch);
262
263 do {
264 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
265 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
266 IMX9_SCMI_PER_LPMMODESET_MSG, token);
267 mbx_mem->len = IMX9_SCMI_PER_LPMMODESET_MSG_LEN +
268 (num_configs * sizeof(struct scmi_per_lpm_config));
269 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
270 SCMI_PAYLOAD_ARG2(mbx_mem->payload, cpu_id, num_configs);
271
272 /* The lpm config starts from byte 2 in the payload memory */
273 unsigned int j = 2U;
274
275 for (unsigned int i = 0U; i < num_configs; i++) {
276 mmio_write_32((uintptr_t)&mbx_mem->payload[j++],
277 cfg[i].perId);
278 mmio_write_32((uintptr_t)&mbx_mem->payload[j++],
279 cfg[i].lpmSetting);
280 }
281 scmi_send_sync_command(ch);
282
283 /* Get the return values */
284 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
285 assert(mbx_mem->len == IMX9_SCMI_PER_LPMMODESET_RESP_LEN);
286 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
287
288 if (num_configs > MAX_PER_LPI_CONFIGS_PER_CMD) {
289 num_configs -= MAX_PER_LPI_CONFIGS_PER_CMD;
290 tmp += MAX_PER_LPI_CONFIGS_PER_CMD;
291 } else {
292 break;
293 }
294 } while (num_configs);
295
296 scmi_put_channel(ch);
297
298 return ret;
299 }
300
scmi_perf_mode_set(void * p,uint32_t domain_id,uint32_t perf_level)301 int scmi_perf_mode_set(void *p, uint32_t domain_id, uint32_t perf_level)
302 {
303 mailbox_mem_t *mbx_mem;
304 unsigned int token = 0U;
305 int ret;
306 scmi_channel_t *ch = (scmi_channel_t *)p;
307
308 validate_scmi_channel(ch);
309
310 scmi_get_channel(ch);
311
312 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
313 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_PERF_PROTO_ID,
314 IMX9_SCMI_CORE_PERFLEVELSET_MSG, token);
315 mbx_mem->len = IMX9_SCMI_CORE_PERFLEVELSET_MSG_LEN;
316 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
317 SCMI_PAYLOAD_ARG2(mbx_mem->payload, domain_id, perf_level);
318
319 scmi_send_sync_command(ch);
320
321 /* Get the return values */
322 SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
323 assert(mbx_mem->len == IMX9_SCMI_CORE_PERFLEVELSET_RESP_LEN);
324 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
325
326 scmi_put_channel(ch);
327
328 return ret;
329
330 }
331
scmi_core_info_get(void * p,uint32_t cpu_id,uint32_t * runmode,uint32_t * sleepmode,uint64_t * vector)332 int scmi_core_info_get(void *p, uint32_t cpu_id, uint32_t *runmode,
333 uint32_t *sleepmode, uint64_t *vector)
334 {
335 mailbox_mem_t *mbx_mem;
336 unsigned int token = 0U;
337 int ret;
338 scmi_channel_t *ch = (scmi_channel_t *)p;
339 uint32_t lo_addr, hi_addr;
340
341 validate_scmi_channel(ch);
342
343 scmi_get_channel(ch);
344
345 mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
346 mbx_mem->msg_header = SCMI_MSG_CREATE(IMX9_SCMI_CORE_PROTO_ID,
347 IMX9_SCMI_CORE_GETINFO_MSG, token);
348 mbx_mem->len = IMX9_SCMI_CORE_GETINFO_MSG_LEN;
349 mbx_mem->flags = SCMI_FLAG_RESP_POLL;
350 SCMI_PAYLOAD_ARG1(mbx_mem->payload, cpu_id);
351
352 scmi_send_sync_command(ch);
353
354 /* Get the return values */
355 SCMI_PAYLOAD_RET_VAL5(mbx_mem->payload, ret, *runmode, *sleepmode,
356 lo_addr, hi_addr);
357 *vector = lo_addr | (uint64_t)hi_addr << 32;
358 assert(mbx_mem->len == IMX9_SCMI_CORE_START_RESP_LEN);
359 assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
360
361 scmi_put_channel(ch);
362
363 return ret;
364 }
365