blob: 74a87832dcb14d63550e450f4bea2632844199e9 [file] [log] [blame]
Etienne Carriere02fd1262020-09-09 18:44:00 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020, Linaro Limited
4 */
5
Patrick Delaunay5dd84d42021-02-24 11:19:44 +01006#define LOG_CATEGORY UCLASS_SCMI_AGENT
7
Etienne Carriere02fd1262020-09-09 18:44:00 +02008#include <dm.h>
9#include <malloc.h>
10#include <scmi_agent.h>
11#include <scmi_agent-uclass.h>
12#include <scmi_protocols.h>
13#include <asm/io.h>
14#include <asm/scmi_test.h>
15#include <dm/device_compat.h>
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090016#include <linux/bitfield.h>
17#include <linux/kernel.h>
Etienne Carriere02fd1262020-09-09 18:44:00 +020018
19/*
20 * The sandbox SCMI agent driver simulates to some extend a SCMI message
21 * processing. It simulates few of the SCMI services for some of the
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020022 * SCMI protocols embedded in U-Boot. Currently:
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090023 * - SCMI base protocol
Etienne Carriere09665cb2022-02-21 09:22:39 +010024 * - SCMI clock protocol emulates an agent exposing 2 clocks
25 * - SCMI reset protocol emulates an agent exposing a reset controller
26 * - SCMI voltage domain protocol emulates an agent exposing 2 regulators
Etienne Carriere02fd1262020-09-09 18:44:00 +020027 *
Etienne Carriere09665cb2022-02-21 09:22:39 +010028 * As per DT bindings, the device node name shall be scmi.
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020029 *
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010030 * All clocks and regulators are default disabled and reset controller down.
Etienne Carriere02fd1262020-09-09 18:44:00 +020031 *
Etienne Carriere09665cb2022-02-21 09:22:39 +010032 * This driver exports sandbox_scmi_service_ctx() for the test sequence to
Etienne Carriere02fd1262020-09-09 18:44:00 +020033 * get the state of the simulated services (clock state, rate, ...) and
34 * check back-end device state reflects the request send through the
Etienne Carriere8b9b6892020-09-09 18:44:07 +020035 * various uclass devices, as clocks and reset controllers.
Etienne Carriere02fd1262020-09-09 18:44:00 +020036 */
37
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090038#define SANDBOX_SCMI_BASE_PROTOCOL_VERSION SCMI_BASE_PROTOCOL_VERSION
39#define SANDBOX_SCMI_VENDOR "U-Boot"
40#define SANDBOX_SCMI_SUB_VENDOR "Sandbox"
41#define SANDBOX_SCMI_IMPL_VERSION 0x1
42#define SANDBOX_SCMI_AGENT_NAME "OSPM"
43#define SANDBOX_SCMI_PLATFORM_NAME "platform"
44
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +090045#define SANDBOX_SCMI_PWD_PROTOCOL_VERSION SCMI_PWD_PROTOCOL_VERSION
46
AKASHI Takahiro6221bf72023-10-11 19:06:56 +090047/**
48 * struct sandbox_channel - Description of sandbox transport
49 * @channel_id: Channel identifier
50 *
51 * Dummy channel. This will be used to test if a protocol-specific
52 * channel is properly used.
53 * Id 0 means a channel for the sandbox agent.
54 */
55struct sandbox_channel {
56 unsigned int channel_id;
57};
58
59/**
60 * struct scmi_channel - Channel instance referenced in SCMI drivers
61 * @ref: Reference to local channel instance
62 **/
63struct scmi_channel {
64 struct sandbox_channel ref;
65};
66
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090067static u8 protocols[] = {
AKASHI Takahiro59171ff2023-11-14 11:14:25 +090068 CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN, (SCMI_PROTOCOL_ID_POWER_DOMAIN,))
69 CONFIG_IS_ENABLED(CLK_SCMI, (SCMI_PROTOCOL_ID_CLOCK,))
70 CONFIG_IS_ENABLED(RESET_SCMI, (SCMI_PROTOCOL_ID_RESET_DOMAIN,))
71 CONFIG_IS_ENABLED(DM_REGULATOR_SCMI, (SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,))
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090072};
73
74#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
75
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +090076static struct sandbox_scmi_pwd scmi_pwdom[] = {
77 { .id = 0 },
78 { .id = 1 },
79 { .id = 2 },
80};
81
Etienne Carriere09665cb2022-02-21 09:22:39 +010082static struct sandbox_scmi_clk scmi_clk[] = {
Alice Guo6e2a7e72025-04-28 18:37:32 +080083 { .rate = 333, .perm = 0xE0000000 },
84 { .rate = 200, .perm = 0xE0000000 },
85 { .rate = 1000, .perm = 0xE0000000 },
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020086};
87
Etienne Carriere09665cb2022-02-21 09:22:39 +010088static struct sandbox_scmi_reset scmi_reset[] = {
Etienne Carriere8b9b6892020-09-09 18:44:07 +020089 { .id = 3 },
90};
91
Etienne Carriere09665cb2022-02-21 09:22:39 +010092static struct sandbox_scmi_voltd scmi_voltd[] = {
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010093 { .id = 0, .voltage_uv = 3300000 },
94 { .id = 1, .voltage_uv = 1800000 },
95};
96
AKASHI Takahirodae00462023-10-11 19:07:03 +090097struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
Etienne Carriere02fd1262020-09-09 18:44:00 +020098{
AKASHI Takahirodae00462023-10-11 19:07:03 +090099 return dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200100}
101
102static void debug_print_agent_state(struct udevice *dev, char *str)
103{
104 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
105
Etienne Carriere09665cb2022-02-21 09:22:39 +0100106 dev_dbg(dev, "Dump sandbox_scmi_agent: %s\n", str);
107 dev_dbg(dev, " scmi_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200108 agent->clk_count,
109 agent->clk_count ? agent->clk[0].enabled : -1,
110 agent->clk_count ? agent->clk[0].rate : -1,
111 agent->clk_count > 1 ? agent->clk[1].enabled : -1,
112 agent->clk_count > 1 ? agent->clk[1].rate : -1,
113 agent->clk_count > 2 ? agent->clk[2].enabled : -1,
114 agent->clk_count > 2 ? agent->clk[2].rate : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100115 dev_dbg(dev, " scmi_reset (%zu): %d, %d, ...\n",
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200116 agent->reset_count,
117 agent->reset_count ? agent->reset[0].asserted : -1,
118 agent->reset_count > 1 ? agent->reset[1].asserted : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100119 dev_dbg(dev, " scmi_voltd (%zu): %u/%d, %u/%d, ...\n",
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100120 agent->voltd_count,
121 agent->voltd_count ? agent->voltd[0].enabled : -1,
122 agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
123 agent->voltd_count ? agent->voltd[1].enabled : -1,
124 agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200125};
126
Etienne Carriere09665cb2022-02-21 09:22:39 +0100127static struct sandbox_scmi_clk *get_scmi_clk_state(uint clock_id)
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200128{
Etienne Carrierebf1f1322022-02-21 09:22:41 +0100129 if (clock_id < ARRAY_SIZE(scmi_clk))
130 return scmi_clk + clock_id;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200131
132 return NULL;
133}
134
Etienne Carriere09665cb2022-02-21 09:22:39 +0100135static struct sandbox_scmi_reset *get_scmi_reset_state(uint reset_id)
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200136{
137 size_t n;
138
Etienne Carriere09665cb2022-02-21 09:22:39 +0100139 for (n = 0; n < ARRAY_SIZE(scmi_reset); n++)
140 if (scmi_reset[n].id == reset_id)
141 return scmi_reset + n;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200142
143 return NULL;
144}
145
Etienne Carriere09665cb2022-02-21 09:22:39 +0100146static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100147{
148 size_t n;
149
Etienne Carriere09665cb2022-02-21 09:22:39 +0100150 for (n = 0; n < ARRAY_SIZE(scmi_voltd); n++)
151 if (scmi_voltd[n].id == domain_id)
152 return scmi_voltd + n;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100153
154 return NULL;
155}
156
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200157/*
158 * Sandbox SCMI agent ops
159 */
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900160
161/* Base Protocol */
162
163/**
164 * sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
165 * @dev: SCMI device
166 * @msg: SCMI message
167 *
168 * Implement SCMI_BASE_PROTOCOL_VERSION command.
169 */
170static int sandbox_scmi_base_protocol_version(struct udevice *dev,
171 struct scmi_msg *msg)
172{
173 struct scmi_protocol_version_out *out = NULL;
174
175 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
176 return -EINVAL;
177
178 out = (struct scmi_protocol_version_out *)msg->out_msg;
179 out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION;
180 out->status = SCMI_SUCCESS;
181
182 return 0;
183}
184
185/**
186 * sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
187 * @dev: SCMI device
188 * @msg: SCMI message
189 *
190 * Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
191 */
192static int sandbox_scmi_base_protocol_attrs(struct udevice *dev,
193 struct scmi_msg *msg)
194{
195 struct scmi_protocol_attrs_out *out = NULL;
196
197 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
198 return -EINVAL;
199
200 out = (struct scmi_protocol_attrs_out *)msg->out_msg;
201 out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS;
202 out->status = SCMI_SUCCESS;
203
204 return 0;
205}
206
207/**
208 * sandbox_scmi_base_message_attrs - implement
209 * SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
210 * @dev: SCMI device
211 * @msg: SCMI message
212 *
213 * Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
214 */
215static int sandbox_scmi_base_message_attrs(struct udevice *dev,
216 struct scmi_msg *msg)
217{
218 u32 message_id;
219 struct scmi_protocol_msg_attrs_out *out = NULL;
220
221 if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
222 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
223 return -EINVAL;
224
225 message_id = *(u32 *)msg->in_msg;
226 out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg;
227
228 if (message_id >= SCMI_PROTOCOL_VERSION &&
229 message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION &&
230 message_id != SCMI_BASE_NOTIFY_ERRORS) {
231 out->attributes = 0;
232 out->status = SCMI_SUCCESS;
233 } else {
234 out->status = SCMI_NOT_FOUND;
235 }
236
237 return 0;
238}
239
240/**
241 * sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
242 * @dev: SCMI device
243 * @msg: SCMI message
244 *
245 * Implement SCMI_BASE_DISCOVER_VENDOR command
246 */
247static int sandbox_scmi_base_discover_vendor(struct udevice *dev,
248 struct scmi_msg *msg)
249{
250 struct scmi_base_discover_vendor_out *out = NULL;
251
252 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
253 return -EINVAL;
254
255 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
256 strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR);
257 out->status = SCMI_SUCCESS;
258
259 return 0;
260}
261
262/**
263 * sandbox_scmi_base_discover_sub_vendor - implement
264 * SCMI_BASE_DISCOVER_SUB_VENDOR
265 * @dev: SCMI device
266 * @msg: SCMI message
267 *
268 * Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
269 */
270static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev,
271 struct scmi_msg *msg)
272{
273 struct scmi_base_discover_vendor_out *out = NULL;
274
275 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
276 return -EINVAL;
277
278 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
279 strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR);
280 out->status = SCMI_SUCCESS;
281
282 return 0;
283}
284
285/**
286 * sandbox_scmi_base_discover_impl_version - implement
287 * SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
288 * @dev: SCMI device
289 * @msg: SCMI message
290 *
291 * Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
292 */
293static int sandbox_scmi_base_discover_impl_version(struct udevice *dev,
294 struct scmi_msg *msg)
295{
296 struct scmi_base_discover_impl_version_out *out = NULL;
297
298 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
299 return -EINVAL;
300
301 out = (struct scmi_base_discover_impl_version_out *)msg->out_msg;
302 out->impl_version = SANDBOX_SCMI_IMPL_VERSION;
303 out->status = SCMI_SUCCESS;
304
305 return 0;
306}
307
308/**
309 * sandbox_scmi_base_discover_list_protocols - implement
310 * SCMI_BASE_DISCOVER_LIST_PROTOCOLS
311 * @dev: SCMI device
312 * @msg: SCMI message
313 *
314 * Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
315 */
316static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev,
317 struct scmi_msg *msg)
318{
319 struct scmi_base_discover_list_protocols_out *out = NULL;
320
321 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
322 return -EINVAL;
323
324 out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg;
325 memcpy(out->protocols, protocols, sizeof(protocols));
326 out->num_protocols = NUM_PROTOCOLS;
327 out->status = SCMI_SUCCESS;
328
329 return 0;
330}
331
332/**
333 * sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
334 * @dev: SCMI device
335 * @msg: SCMI message
336 *
337 * Implement SCMI_BASE_DISCOVER_AGENT command
338 */
339static int sandbox_scmi_base_discover_agent(struct udevice *dev,
340 struct scmi_msg *msg)
341{
342 u32 agent_id;
343 struct scmi_base_discover_agent_out *out = NULL;
344
345 if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) ||
346 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
347 return -EINVAL;
348
349 agent_id = *(u32 *)msg->in_msg;
350 out = (struct scmi_base_discover_agent_out *)msg->out_msg;
351 out->status = SCMI_SUCCESS;
352 if (agent_id == 0xffffffff || agent_id == 1) {
353 out->agent_id = 1;
354 strcpy(out->name, SANDBOX_SCMI_AGENT_NAME);
355 } else if (!agent_id) {
356 out->agent_id = agent_id;
357 strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME);
358 } else {
359 out->status = SCMI_NOT_FOUND;
360 }
361
362 return 0;
363}
364
365/**
366 * sandbox_scmi_base_set_device_permissions - implement
367 * SCMI_BASE_SET_DEVICE_PERMISSIONS
368 * @dev: SCMI device
369 * @msg: SCMI message
370 *
371 * Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
372 */
373static int sandbox_scmi_base_set_device_permissions(struct udevice *dev,
374 struct scmi_msg *msg)
375{
376 struct scmi_base_set_device_permissions_in *in = NULL;
377 u32 *status;
378
379 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
380 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
381 return -EINVAL;
382
383 in = (struct scmi_base_set_device_permissions_in *)msg->in_msg;
384 status = (u32 *)msg->out_msg;
385
386 if (in->agent_id != 1 || in->device_id != 0)
387 *status = SCMI_NOT_FOUND;
388 else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
389 *status = SCMI_INVALID_PARAMETERS;
390 else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
391 *status = SCMI_SUCCESS;
392 else
393 /* unset not allowed */
394 *status = SCMI_DENIED;
395
396 return 0;
397}
398
399/**
400 * sandbox_scmi_base_set_protocol_permissions - implement
401 * SCMI_BASE_SET_PROTOCOL_PERMISSIONS
402 * @dev: SCMI device
403 * @msg: SCMI message
404 *
405 * Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
406 */
407static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev,
408 struct scmi_msg *msg)
409{
410 struct scmi_base_set_protocol_permissions_in *in = NULL;
411 u32 *status;
412 int i;
413
414 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
415 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
416 return -EINVAL;
417
418 in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg;
419 status = (u32 *)msg->out_msg;
420
421 for (i = 0; i < ARRAY_SIZE(protocols); i++)
422 if (protocols[i] == in->command_id)
423 break;
424 if (in->agent_id != 1 || in->device_id != 0 ||
425 i == ARRAY_SIZE(protocols))
426 *status = SCMI_NOT_FOUND;
427 else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
428 *status = SCMI_INVALID_PARAMETERS;
429 else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
430 *status = SCMI_SUCCESS;
431 else
432 /* unset not allowed */
433 *status = SCMI_DENIED;
434
435 return 0;
436}
437
438/**
439 * sandbox_scmi_base_reset_agent_configuration - implement
440 * SCMI_BASE_RESET_AGENT_CONFIGURATION
441 * @dev: SCMI device
442 * @msg: SCMI message
443 *
444 * Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
445 */
446static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
447 struct scmi_msg *msg)
448{
449 struct scmi_base_reset_agent_configuration_in *in = NULL;
450 u32 *status;
451
452 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
453 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
454 return -EINVAL;
455
456 in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg;
457 status = (u32 *)msg->out_msg;
458
459 if (in->agent_id != 1)
460 *status = SCMI_NOT_FOUND;
461 else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS)
462 *status = SCMI_INVALID_PARAMETERS;
463 else
464 *status = SCMI_DENIED;
465
466 return 0;
467}
468
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900469/* Power Domain Management Protocol */
470
471/**
472 * sandbox_scmi_pwd_protocol_version - implement SCMI_PROTOCOL_VERSION
473 * @dev: SCMI device
474 * @msg: SCMI message
475 *
476 * Implement SCMI_PROTOCOL_VERSION command.
477 *
478 * Return: 0 on success, error code on failure
479 */
480static int sandbox_scmi_pwd_protocol_version(struct udevice *dev,
481 struct scmi_msg *msg)
482{
483 struct scmi_protocol_version_out *out = NULL;
484
485 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
486 return -EINVAL;
487
488 out = (struct scmi_protocol_version_out *)msg->out_msg;
489 out->version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION;
490 out->status = SCMI_SUCCESS;
491
492 return 0;
493}
494
495/**
496 * sandbox_scmi_pwd_protocol_attribs - implement SCMI_PWD_PROTOCOL_ATTRS
497 * @dev: SCMI device
498 * @msg: SCMI message
499 *
500 * Implement SCMI_PWD_PROTOCOL_ATTRS command.
501 *
502 * Return: 0 on success, error code on failure
503 */
504static int sandbox_scmi_pwd_protocol_attribs(struct udevice *dev,
505 struct scmi_msg *msg)
506{
507 struct scmi_pwd_protocol_attrs_out *out;
508
509 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
510 return -EINVAL;
511
512 out = (struct scmi_pwd_protocol_attrs_out *)msg->out_msg;
513
514 out->attributes = ARRAY_SIZE(scmi_pwdom);
515 out->stats_addr_low = 0;
516 out->stats_addr_high = 0;
517 out->stats_len = 0;
518 out->status = SCMI_SUCCESS;
519
520 return 0;
521}
522
523/**
524 * sandbox_scmi_pwd_protocol_msg_attribs - implement
525 SCMI_PWD_PROTOCOL_MESSAGE_ATTRS
526 * @dev: SCMI device
527 * @msg: SCMI message
528 *
529 * Implement SCMI_PWD_PROTOCOL_MESSAGE_ATTRS command.
530 *
531 * Return: 0 on success, error code on failure
532 */
533static int sandbox_scmi_pwd_protocol_msg_attribs(struct udevice *dev,
534 struct scmi_msg *msg)
535{
536 u32 message_id;
537 struct scmi_pwd_protocol_msg_attrs_out *out;
538
539 if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
540 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
541 return -EINVAL;
542
543 message_id = *(u32 *)msg->in_msg;
544
545 out = (struct scmi_pwd_protocol_msg_attrs_out *)msg->out_msg;
546 if (message_id <= SCMI_PWD_STATE_GET ||
547 message_id == SCMI_PWD_NAME_GET) {
548 out->attributes = 0;
549 out->status = SCMI_SUCCESS;
550 } else {
551 out->status = SCMI_NOT_FOUND;
552 }
553
554 return 0;
555}
556
557/**
558 * sandbox_scmi_pwd_attribs - implement SCMI_PWD_ATTRS
559 * @dev: SCMI device
560 * @msg: SCMI message
561 *
562 * Implement SCMI_PWD_ATTRS command.
563 *
564 * Return: 0 on success, error code on failure
565 */
566static int sandbox_scmi_pwd_attribs(struct udevice *dev, struct scmi_msg *msg)
567{
568 u32 domain_id;
569 struct scmi_pwd_attrs_out *out;
570
571 if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
572 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
573 return -EINVAL;
574
575 domain_id = *(u32 *)msg->in_msg;
576 out = (struct scmi_pwd_attrs_out *)msg->out_msg;
577
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900578 if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900579 out->status = SCMI_NOT_FOUND;
580
581 return 0;
582 }
583
584 out->attributes =
585 SCMI_PWD_ATTR_PSTATE_SYNC | SCMI_PWD_ATTR_EXTENDED_NAME;
586 /* just 15-char + NULL */
587 snprintf(out->name, SCMI_PWD_NAME_LENGTH_MAX, "power-domain--%d",
588 domain_id);
589 out->status = SCMI_SUCCESS;
590
591 return 0;
592}
593
594/**
595 * sandbox_scmi_pwd_state_set - implement SCMI_PWD_STATE_SET
596 * @dev: SCMI device
597 * @msg: SCMI message
598 *
599 * Implement SCMI_PWD_STATE_SET command.
600 *
601 * Return: 0 on success, error code on failure
602 */
603static int sandbox_scmi_pwd_state_set(struct udevice *dev, struct scmi_msg *msg)
604{
605 struct scmi_pwd_state_set_in *in;
606 s32 *status;
607
608 if (!msg->in_msg || msg->in_msg_sz < sizeof(in) ||
609 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
610 return -EINVAL;
611
612 in = (struct scmi_pwd_state_set_in *)msg->in_msg;
613 status = (s32 *)msg->out_msg;
614
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900615 if (in->domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900616 *status = SCMI_NOT_FOUND;
617
618 return 0;
619 }
620
621 if ((in->flags & SCMI_PWD_SET_FLAGS_ASYNC) ||
622 (in->pstate != SCMI_PWD_PSTATE_TYPE_LOST && in->pstate)) {
623 *status = SCMI_INVALID_PARAMETERS;
624
625 return 0;
626 }
627
628 scmi_pwdom[in->domain_id].pstate = in->pstate;
629 *status = SCMI_SUCCESS;
630
631 return 0;
632}
633
634/**
635 * sandbox_scmi_pwd_state_get - implement SCMI_PWD_STATE_GET
636 * @dev: SCMI device
637 * @msg: SCMI message
638 *
639 * Implement SCMI_PWD_STATE_GET command.
640 *
641 * Return: 0 on success, error code on failure
642 */
643static int sandbox_scmi_pwd_state_get(struct udevice *dev, struct scmi_msg *msg)
644{
645 u32 domain_id;
646 struct scmi_pwd_state_get_out *out;
647
648 if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
649 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
650 return -EINVAL;
651
652 domain_id = *(u32 *)msg->in_msg;
653 out = (struct scmi_pwd_state_get_out *)msg->out_msg;
654
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900655 if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900656 out->status = SCMI_NOT_FOUND;
657
658 return 0;
659 }
660
661 out->pstate = scmi_pwdom[domain_id].pstate;
662 out->status = SCMI_SUCCESS;
663
664 return 0;
665}
666
667/**
668 * sandbox_scmi_pwd_name_get - implement SCMI_PWD_NAME_GET
669 * @dev: SCMI device
670 * @msg: SCMI message
671 *
672 * Implement SCMI_PWD_NAME_GET command.
673 *
674 * Return: 0 on success, error code on failure
675 */
676static int sandbox_scmi_pwd_name_get(struct udevice *dev, struct scmi_msg *msg)
677{
678 u32 domain_id;
679 struct scmi_pwd_name_get_out *out;
680
681 if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
682 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
683 return -EINVAL;
684
685 domain_id = *(u32 *)msg->in_msg;
686 out = (struct scmi_pwd_name_get_out *)msg->out_msg;
687
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900688 if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900689 out->status = SCMI_NOT_FOUND;
690
691 return 0;
692 }
693
694 snprintf(out->extended_name, SCMI_PWD_EXTENDED_NAME_MAX,
695 "power-domain--%d-extended", domain_id);
696 out->status = SCMI_SUCCESS;
697
698 return 0;
699}
700
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900701/* Clock Protocol */
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200702
Alice Guo6e2a7e72025-04-28 18:37:32 +0800703static int sandbox_scmi_clock_protocol_version(struct udevice *dev,
704 struct scmi_msg *msg)
705{
706 struct scmi_protocol_version_out *out = NULL;
707
708 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
709 return -EINVAL;
710
711 out = (struct scmi_protocol_version_out *)msg->out_msg;
712 out->version = 0x30000;
713 out->status = SCMI_SUCCESS;
714
715 return 0;
716}
717
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100718static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
719 struct scmi_msg *msg)
720{
721 struct scmi_clk_protocol_attr_out *out = NULL;
722
723 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
724 return -EINVAL;
725
726 out = (struct scmi_clk_protocol_attr_out *)msg->out_msg;
727 out->attributes = ARRAY_SIZE(scmi_clk);
728 out->status = SCMI_SUCCESS;
729
730 return 0;
731}
732
733static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
734{
735 struct scmi_clk_attribute_in *in = NULL;
736 struct scmi_clk_attribute_out *out = NULL;
737 struct sandbox_scmi_clk *clk_state = NULL;
738 int ret;
739
740 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
741 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
742 return -EINVAL;
743
744 in = (struct scmi_clk_attribute_in *)msg->in_msg;
745 out = (struct scmi_clk_attribute_out *)msg->out_msg;
746
747 clk_state = get_scmi_clk_state(in->clock_id);
748 if (!clk_state) {
749 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
750
751 out->status = SCMI_NOT_FOUND;
752 } else {
753 memset(out, 0, sizeof(*out));
754
755 if (clk_state->enabled)
756 out->attributes = 1;
757
Alice Guo6e2a7e72025-04-28 18:37:32 +0800758 /* Restricted clock */
759 out->attributes |= BIT(1);
760
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100761 ret = snprintf(out->clock_name, sizeof(out->clock_name),
762 "clk%u", in->clock_id);
763 assert(ret > 0 && ret < sizeof(out->clock_name));
764
765 out->status = SCMI_SUCCESS;
766 }
767
768 return 0;
769}
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200770static int sandbox_scmi_clock_rate_set(struct udevice *dev,
771 struct scmi_msg *msg)
772{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200773 struct scmi_clk_rate_set_in *in = NULL;
774 struct scmi_clk_rate_set_out *out = NULL;
775 struct sandbox_scmi_clk *clk_state = NULL;
776
777 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
778 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
779 return -EINVAL;
780
781 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
782 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
783
Etienne Carriere09665cb2022-02-21 09:22:39 +0100784 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200785 if (!clk_state) {
786 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
787
788 out->status = SCMI_NOT_FOUND;
789 } else {
790 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
791
792 clk_state->rate = (ulong)rate;
793
794 out->status = SCMI_SUCCESS;
795 }
796
797 return 0;
798}
799
800static int sandbox_scmi_clock_rate_get(struct udevice *dev,
801 struct scmi_msg *msg)
802{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200803 struct scmi_clk_rate_get_in *in = NULL;
804 struct scmi_clk_rate_get_out *out = NULL;
805 struct sandbox_scmi_clk *clk_state = NULL;
806
807 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
808 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
809 return -EINVAL;
810
811 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
812 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
813
Etienne Carriere09665cb2022-02-21 09:22:39 +0100814 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200815 if (!clk_state) {
816 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
817
818 out->status = SCMI_NOT_FOUND;
819 } else {
820 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
821 out->rate_lsb = (u32)clk_state->rate;
822
823 out->status = SCMI_SUCCESS;
824 }
825
826 return 0;
827}
828
829static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
830{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200831 struct scmi_clk_state_in *in = NULL;
832 struct scmi_clk_state_out *out = NULL;
833 struct sandbox_scmi_clk *clk_state = NULL;
834
835 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
836 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
837 return -EINVAL;
838
839 in = (struct scmi_clk_state_in *)msg->in_msg;
840 out = (struct scmi_clk_state_out *)msg->out_msg;
841
Etienne Carriere09665cb2022-02-21 09:22:39 +0100842 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200843 if (!clk_state) {
844 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
845
846 out->status = SCMI_NOT_FOUND;
847 } else if (in->attributes > 1) {
848 out->status = SCMI_PROTOCOL_ERROR;
849 } else {
850 clk_state->enabled = in->attributes;
851
852 out->status = SCMI_SUCCESS;
853 }
854
855 return 0;
856}
857
Alice Guo6e2a7e72025-04-28 18:37:32 +0800858static int sandbox_scmi_clock_permissions_get(struct udevice *dev,
859 struct scmi_msg *msg)
860{
861 struct scmi_clk_get_permissions_in *in = NULL;
862 struct scmi_clk_get_permissions_out *out = NULL;
863 struct sandbox_scmi_clk *clk_state = NULL;
864
865 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
866 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
867 return -EINVAL;
868
869 in = (struct scmi_clk_get_permissions_in *)msg->in_msg;
870 out = (struct scmi_clk_get_permissions_out *)msg->out_msg;
871
872 clk_state = get_scmi_clk_state(in->clock_id);
873 if (!clk_state) {
874 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
875
876 out->status = SCMI_NOT_FOUND;
877 } else {
878 out->permissions = clk_state->perm;
879
880 out->status = SCMI_SUCCESS;
881 }
882
883 return 0;
884}
885
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200886static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
887{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200888 struct scmi_rd_attr_in *in = NULL;
889 struct scmi_rd_attr_out *out = NULL;
890 struct sandbox_scmi_reset *reset_state = NULL;
891
892 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
893 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
894 return -EINVAL;
895
896 in = (struct scmi_rd_attr_in *)msg->in_msg;
897 out = (struct scmi_rd_attr_out *)msg->out_msg;
898
Etienne Carriere09665cb2022-02-21 09:22:39 +0100899 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200900 if (!reset_state) {
901 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
902
903 out->status = SCMI_NOT_FOUND;
904 } else {
905 memset(out, 0, sizeof(*out));
906 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
907
908 out->status = SCMI_SUCCESS;
909 }
910
911 return 0;
912}
913
914static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
915{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200916 struct scmi_rd_reset_in *in = NULL;
917 struct scmi_rd_reset_out *out = NULL;
918 struct sandbox_scmi_reset *reset_state = NULL;
919
920 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
921 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
922 return -EINVAL;
923
924 in = (struct scmi_rd_reset_in *)msg->in_msg;
925 out = (struct scmi_rd_reset_out *)msg->out_msg;
926
Etienne Carriere09665cb2022-02-21 09:22:39 +0100927 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200928 if (!reset_state) {
929 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
930
931 out->status = SCMI_NOT_FOUND;
932 } else if (in->reset_state > 1) {
933 dev_err(dev, "Invalid reset domain input attribute value\n");
934
935 out->status = SCMI_INVALID_PARAMETERS;
936 } else {
937 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
938 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
939 out->status = SCMI_NOT_SUPPORTED;
940 } else {
941 /* Ends deasserted whatever current state */
942 reset_state->asserted = false;
943 out->status = SCMI_SUCCESS;
944 }
945 } else {
946 reset_state->asserted = in->flags &
947 SCMI_RD_RESET_FLAG_ASSERT;
948
949 out->status = SCMI_SUCCESS;
950 }
951 }
952
953 return 0;
954}
955
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100956static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
957{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100958 struct scmi_voltd_attr_in *in = NULL;
959 struct scmi_voltd_attr_out *out = NULL;
960 struct sandbox_scmi_voltd *voltd_state = NULL;
961
962 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
963 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
964 return -EINVAL;
965
966 in = (struct scmi_voltd_attr_in *)msg->in_msg;
967 out = (struct scmi_voltd_attr_out *)msg->out_msg;
968
Etienne Carriere09665cb2022-02-21 09:22:39 +0100969 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100970 if (!voltd_state) {
971 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
972
973 out->status = SCMI_NOT_FOUND;
974 } else {
975 memset(out, 0, sizeof(*out));
976 snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
977
978 out->status = SCMI_SUCCESS;
979 }
980
981 return 0;
982}
983
984static int sandbox_scmi_voltd_config_set(struct udevice *dev,
985 struct scmi_msg *msg)
986{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100987 struct scmi_voltd_config_set_in *in = NULL;
988 struct scmi_voltd_config_set_out *out = NULL;
989 struct sandbox_scmi_voltd *voltd_state = NULL;
990
991 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
992 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
993 return -EINVAL;
994
995 in = (struct scmi_voltd_config_set_in *)msg->in_msg;
996 out = (struct scmi_voltd_config_set_out *)msg->out_msg;
997
Etienne Carriere09665cb2022-02-21 09:22:39 +0100998 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100999 if (!voltd_state) {
1000 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1001
1002 out->status = SCMI_NOT_FOUND;
1003 } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
1004 dev_err(dev, "Invalid config value 0x%x\n", in->config);
1005
1006 out->status = SCMI_INVALID_PARAMETERS;
1007 } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
1008 in->config != SCMI_VOLTD_CONFIG_OFF) {
1009 dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
1010
1011 out->status = SCMI_INVALID_PARAMETERS;
1012 } else {
1013 voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
1014 out->status = SCMI_SUCCESS;
1015 }
1016
1017 return 0;
1018}
1019
1020static int sandbox_scmi_voltd_config_get(struct udevice *dev,
1021 struct scmi_msg *msg)
1022{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001023 struct scmi_voltd_config_get_in *in = NULL;
1024 struct scmi_voltd_config_get_out *out = NULL;
1025 struct sandbox_scmi_voltd *voltd_state = NULL;
1026
1027 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
1028 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
1029 return -EINVAL;
1030
1031 in = (struct scmi_voltd_config_get_in *)msg->in_msg;
1032 out = (struct scmi_voltd_config_get_out *)msg->out_msg;
1033
Etienne Carriere09665cb2022-02-21 09:22:39 +01001034 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001035 if (!voltd_state) {
1036 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1037
1038 out->status = SCMI_NOT_FOUND;
1039 } else {
1040 if (voltd_state->enabled)
1041 out->config = SCMI_VOLTD_CONFIG_ON;
1042 else
1043 out->config = SCMI_VOLTD_CONFIG_OFF;
1044
1045 out->status = SCMI_SUCCESS;
1046 }
1047
1048 return 0;
1049}
1050
1051static int sandbox_scmi_voltd_level_set(struct udevice *dev,
1052 struct scmi_msg *msg)
1053{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001054 struct scmi_voltd_level_set_in *in = NULL;
1055 struct scmi_voltd_level_set_out *out = NULL;
1056 struct sandbox_scmi_voltd *voltd_state = NULL;
1057
1058 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
1059 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
1060 return -EINVAL;
1061
1062 in = (struct scmi_voltd_level_set_in *)msg->in_msg;
1063 out = (struct scmi_voltd_level_set_out *)msg->out_msg;
1064
Etienne Carriere09665cb2022-02-21 09:22:39 +01001065 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001066 if (!voltd_state) {
1067 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1068
1069 out->status = SCMI_NOT_FOUND;
1070 } else {
1071 voltd_state->voltage_uv = in->voltage_level;
1072 out->status = SCMI_SUCCESS;
1073 }
1074
1075 return 0;
1076}
1077
1078static int sandbox_scmi_voltd_level_get(struct udevice *dev,
1079 struct scmi_msg *msg)
1080{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001081 struct scmi_voltd_level_get_in *in = NULL;
1082 struct scmi_voltd_level_get_out *out = NULL;
1083 struct sandbox_scmi_voltd *voltd_state = NULL;
1084
1085 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
1086 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
1087 return -EINVAL;
1088
1089 in = (struct scmi_voltd_level_get_in *)msg->in_msg;
1090 out = (struct scmi_voltd_level_get_out *)msg->out_msg;
1091
Etienne Carriere09665cb2022-02-21 09:22:39 +01001092 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001093 if (!voltd_state) {
1094 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1095
1096 out->status = SCMI_NOT_FOUND;
1097 } else {
1098 out->voltage_level = voltd_state->voltage_uv;
1099 out->status = SCMI_SUCCESS;
1100 }
1101
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001102 return 0;
1103}
1104
1105/**
1106 * sandbox_scmi_of_get_channel - assigne a channel
1107 * @dev: SCMI agent device
1108 * @protocol: SCMI protocol device
1109 * @channel: Pointer to channel info
1110 *
1111 * Assign a channel for the protocol, @protocol, in @channel,
1112 * based on a device tree's property.
1113 *
1114 * Return: 0 on success, error code on failure
1115 */
1116static int sandbox_scmi_of_get_channel(struct udevice *dev,
1117 struct udevice *protocol,
1118 struct scmi_channel **channel)
1119{
1120 struct sandbox_channel *agent_chan = dev_get_plat(dev);
1121 struct sandbox_channel *chan;
1122 u32 channel_id;
1123
1124 if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
1125 /* Uses agent channel */
1126 *channel = container_of(agent_chan, struct scmi_channel, ref);
1127
1128 return 0;
1129 }
1130
1131 /* Setup a dedicated channel */
1132 chan = calloc(1, sizeof(*chan));
1133 if (!chan)
1134 return -ENOMEM;
1135
1136 chan->channel_id = channel_id;
1137
1138 *channel = container_of(chan, struct scmi_channel, ref);
1139
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001140 return 0;
1141}
1142
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001143/**
1144 * sandbox_scmi_of_to_plat - assigne a channel to agent
1145 * @dev: SCMI agent device
1146 *
1147 * Assign a channel for the agent, @protocol.
1148 *
1149 * Return: always 0
1150 */
1151static int sandbox_scmi_of_to_plat(struct udevice *dev)
1152{
1153 struct sandbox_channel *chan = dev_get_plat(dev);
1154
1155 /* The channel for agent is always 0 */
1156 chan->channel_id = 0;
1157
1158 return 0;
1159}
1160
1161unsigned int sandbox_scmi_channel_id(struct udevice *dev)
1162{
1163 struct scmi_agent_proto_priv *priv;
1164 struct sandbox_channel *chan;
1165
1166 priv = dev_get_parent_priv(dev);
1167 chan = (struct sandbox_channel *)&priv->channel->ref;
1168
1169 return chan->channel_id;
1170}
1171
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001172static int sandbox_proto_not_supported(struct scmi_msg *msg)
1173{
1174 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
1175
1176 return 0;
1177}
1178
Etienne Carriere02fd1262020-09-09 18:44:00 +02001179static int sandbox_scmi_test_process_msg(struct udevice *dev,
Etienne Carriere05440292022-05-31 18:09:19 +02001180 struct scmi_channel *channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001181 struct scmi_msg *msg)
1182{
1183 switch (msg->protocol_id) {
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +09001184 case SCMI_PROTOCOL_ID_BASE:
1185 switch (msg->message_id) {
1186 case SCMI_PROTOCOL_VERSION:
1187 return sandbox_scmi_base_protocol_version(dev, msg);
1188 case SCMI_PROTOCOL_ATTRIBUTES:
1189 return sandbox_scmi_base_protocol_attrs(dev, msg);
1190 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
1191 return sandbox_scmi_base_message_attrs(dev, msg);
1192 case SCMI_BASE_DISCOVER_VENDOR:
1193 return sandbox_scmi_base_discover_vendor(dev, msg);
1194 case SCMI_BASE_DISCOVER_SUB_VENDOR:
1195 return sandbox_scmi_base_discover_sub_vendor(dev, msg);
1196 case SCMI_BASE_DISCOVER_IMPL_VERSION:
1197 return sandbox_scmi_base_discover_impl_version(dev, msg);
1198 case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
1199 return sandbox_scmi_base_discover_list_protocols(dev, msg);
1200 case SCMI_BASE_DISCOVER_AGENT:
1201 return sandbox_scmi_base_discover_agent(dev, msg);
1202 case SCMI_BASE_NOTIFY_ERRORS:
1203 break;
1204 case SCMI_BASE_SET_DEVICE_PERMISSIONS:
1205 return sandbox_scmi_base_set_device_permissions(dev, msg);
1206 case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
1207 return sandbox_scmi_base_set_protocol_permissions(dev, msg);
1208 case SCMI_BASE_RESET_AGENT_CONFIGURATION:
1209 return sandbox_scmi_base_reset_agent_configuration(dev, msg);
1210 default:
1211 break;
1212 }
1213 break;
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001214 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001215 if (!CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN))
1216 return sandbox_proto_not_supported(msg);
1217
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001218 switch (msg->message_id) {
1219 case SCMI_PROTOCOL_VERSION:
1220 return sandbox_scmi_pwd_protocol_version(dev, msg);
1221 case SCMI_PROTOCOL_ATTRIBUTES:
1222 return sandbox_scmi_pwd_protocol_attribs(dev, msg);
1223 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
1224 return sandbox_scmi_pwd_protocol_msg_attribs(dev, msg);
1225 case SCMI_PWD_ATTRIBUTES:
1226 return sandbox_scmi_pwd_attribs(dev, msg);
1227 case SCMI_PWD_STATE_SET:
1228 return sandbox_scmi_pwd_state_set(dev, msg);
1229 case SCMI_PWD_STATE_GET:
1230 return sandbox_scmi_pwd_state_get(dev, msg);
1231 case SCMI_PWD_NAME_GET:
1232 return sandbox_scmi_pwd_name_get(dev, msg);
1233 default:
1234 break;
1235 }
1236 break;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001237 case SCMI_PROTOCOL_ID_CLOCK:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001238 if (!CONFIG_IS_ENABLED(CLK_SCMI))
1239 return sandbox_proto_not_supported(msg);
1240
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001241 switch (msg->message_id) {
Alice Guo6e2a7e72025-04-28 18:37:32 +08001242 case SCMI_PROTOCOL_VERSION:
1243 return sandbox_scmi_clock_protocol_version(dev, msg);
Etienne Carriere4c4ec902022-02-21 09:22:42 +01001244 case SCMI_PROTOCOL_ATTRIBUTES:
1245 return sandbox_scmi_clock_protocol_attribs(dev, msg);
1246 case SCMI_CLOCK_ATTRIBUTES:
1247 return sandbox_scmi_clock_attribs(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001248 case SCMI_CLOCK_RATE_SET:
1249 return sandbox_scmi_clock_rate_set(dev, msg);
1250 case SCMI_CLOCK_RATE_GET:
1251 return sandbox_scmi_clock_rate_get(dev, msg);
1252 case SCMI_CLOCK_CONFIG_SET:
1253 return sandbox_scmi_clock_gate(dev, msg);
Alice Guo6e2a7e72025-04-28 18:37:32 +08001254 case SCMI_CLOCK_GET_PERMISSIONS:
1255 return sandbox_scmi_clock_permissions_get(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001256 default:
1257 break;
1258 }
1259 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +02001260 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001261 if (!CONFIG_IS_ENABLED(RESET_SCMI))
1262 return sandbox_proto_not_supported(msg);
1263
Etienne Carriere8b9b6892020-09-09 18:44:07 +02001264 switch (msg->message_id) {
1265 case SCMI_RESET_DOMAIN_ATTRIBUTES:
1266 return sandbox_scmi_rd_attribs(dev, msg);
1267 case SCMI_RESET_DOMAIN_RESET:
1268 return sandbox_scmi_rd_reset(dev, msg);
1269 default:
1270 break;
1271 }
1272 break;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001273 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001274 if (!CONFIG_IS_ENABLED(DM_REGULATOR_SCMI))
1275 return sandbox_proto_not_supported(msg);
1276
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001277 switch (msg->message_id) {
1278 case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
1279 return sandbox_scmi_voltd_attribs(dev, msg);
1280 case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
1281 return sandbox_scmi_voltd_config_set(dev, msg);
1282 case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
1283 return sandbox_scmi_voltd_config_get(dev, msg);
1284 case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
1285 return sandbox_scmi_voltd_level_set(dev, msg);
1286 case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
1287 return sandbox_scmi_voltd_level_get(dev, msg);
1288 default:
1289 break;
1290 }
1291 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +02001292 case SCMI_PROTOCOL_ID_SYSTEM:
1293 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +02001294 case SCMI_PROTOCOL_ID_SENSOR:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001295 return sandbox_proto_not_supported(msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +02001296 default:
1297 break;
1298 }
1299
1300 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
1301 __func__, dev->name, msg->protocol_id, msg->message_id);
1302
1303 if (msg->out_msg_sz < sizeof(u32))
1304 return -EINVAL;
1305
1306 /* Intentionnaly report unhandled IDs through the SCMI return code */
1307 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
1308 return 0;
1309}
1310
1311static int sandbox_scmi_test_remove(struct udevice *dev)
1312{
Etienne Carriere02fd1262020-09-09 18:44:00 +02001313 debug_print_agent_state(dev, "removed");
1314
Etienne Carriere02fd1262020-09-09 18:44:00 +02001315 return 0;
1316}
1317
1318static int sandbox_scmi_test_probe(struct udevice *dev)
1319{
Etienne Carriere02fd1262020-09-09 18:44:00 +02001320 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +02001321
Etienne Carriere09665cb2022-02-21 09:22:39 +01001322 *agent = (struct sandbox_scmi_agent){
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001323 .pwdom_version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION,
1324 .pwdom = scmi_pwdom,
1325 .pwdom_count = ARRAY_SIZE(scmi_pwdom),
Etienne Carriere09665cb2022-02-21 09:22:39 +01001326 .clk = scmi_clk,
1327 .clk_count = ARRAY_SIZE(scmi_clk),
1328 .reset = scmi_reset,
1329 .reset_count = ARRAY_SIZE(scmi_reset),
1330 .voltd = scmi_voltd,
1331 .voltd_count = ARRAY_SIZE(scmi_voltd),
1332 };
Etienne Carriere02fd1262020-09-09 18:44:00 +02001333
1334 debug_print_agent_state(dev, "probed");
1335
Etienne Carriere02fd1262020-09-09 18:44:00 +02001336 return 0;
1337};
1338
1339static const struct udevice_id sandbox_scmi_test_ids[] = {
1340 { .compatible = "sandbox,scmi-agent" },
1341 { }
1342};
1343
1344struct scmi_agent_ops sandbox_scmi_test_ops = {
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001345 .of_get_channel = sandbox_scmi_of_get_channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001346 .process_msg = sandbox_scmi_test_process_msg,
1347};
1348
1349U_BOOT_DRIVER(sandbox_scmi_agent) = {
1350 .name = "sandbox-scmi_agent",
1351 .id = UCLASS_SCMI_AGENT,
1352 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001353 .priv_auto = sizeof(struct sandbox_scmi_agent),
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001354 .plat_auto = sizeof(struct sandbox_channel),
1355 .of_to_plat = sandbox_scmi_of_to_plat,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001356 .probe = sandbox_scmi_test_probe,
1357 .remove = sandbox_scmi_test_remove,
1358 .ops = &sandbox_scmi_test_ops,
1359};