blob: 19be280ec44845369d1f46509978ec9b5b59c60b [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[] = {
Etienne Carrierebf1f1322022-02-21 09:22:41 +010083 { .rate = 333 },
84 { .rate = 200 },
85 { .rate = 1000 },
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
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100703static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
704 struct scmi_msg *msg)
705{
706 struct scmi_clk_protocol_attr_out *out = NULL;
707
708 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
709 return -EINVAL;
710
711 out = (struct scmi_clk_protocol_attr_out *)msg->out_msg;
712 out->attributes = ARRAY_SIZE(scmi_clk);
713 out->status = SCMI_SUCCESS;
714
715 return 0;
716}
717
718static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
719{
720 struct scmi_clk_attribute_in *in = NULL;
721 struct scmi_clk_attribute_out *out = NULL;
722 struct sandbox_scmi_clk *clk_state = NULL;
723 int ret;
724
725 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
726 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
727 return -EINVAL;
728
729 in = (struct scmi_clk_attribute_in *)msg->in_msg;
730 out = (struct scmi_clk_attribute_out *)msg->out_msg;
731
732 clk_state = get_scmi_clk_state(in->clock_id);
733 if (!clk_state) {
734 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
735
736 out->status = SCMI_NOT_FOUND;
737 } else {
738 memset(out, 0, sizeof(*out));
739
740 if (clk_state->enabled)
741 out->attributes = 1;
742
743 ret = snprintf(out->clock_name, sizeof(out->clock_name),
744 "clk%u", in->clock_id);
745 assert(ret > 0 && ret < sizeof(out->clock_name));
746
747 out->status = SCMI_SUCCESS;
748 }
749
750 return 0;
751}
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200752static int sandbox_scmi_clock_rate_set(struct udevice *dev,
753 struct scmi_msg *msg)
754{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200755 struct scmi_clk_rate_set_in *in = NULL;
756 struct scmi_clk_rate_set_out *out = NULL;
757 struct sandbox_scmi_clk *clk_state = NULL;
758
759 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
760 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
761 return -EINVAL;
762
763 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
764 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
765
Etienne Carriere09665cb2022-02-21 09:22:39 +0100766 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200767 if (!clk_state) {
768 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
769
770 out->status = SCMI_NOT_FOUND;
771 } else {
772 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
773
774 clk_state->rate = (ulong)rate;
775
776 out->status = SCMI_SUCCESS;
777 }
778
779 return 0;
780}
781
782static int sandbox_scmi_clock_rate_get(struct udevice *dev,
783 struct scmi_msg *msg)
784{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200785 struct scmi_clk_rate_get_in *in = NULL;
786 struct scmi_clk_rate_get_out *out = NULL;
787 struct sandbox_scmi_clk *clk_state = NULL;
788
789 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
790 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
791 return -EINVAL;
792
793 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
794 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
795
Etienne Carriere09665cb2022-02-21 09:22:39 +0100796 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200797 if (!clk_state) {
798 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
799
800 out->status = SCMI_NOT_FOUND;
801 } else {
802 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
803 out->rate_lsb = (u32)clk_state->rate;
804
805 out->status = SCMI_SUCCESS;
806 }
807
808 return 0;
809}
810
811static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
812{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200813 struct scmi_clk_state_in *in = NULL;
814 struct scmi_clk_state_out *out = NULL;
815 struct sandbox_scmi_clk *clk_state = NULL;
816
817 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
818 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
819 return -EINVAL;
820
821 in = (struct scmi_clk_state_in *)msg->in_msg;
822 out = (struct scmi_clk_state_out *)msg->out_msg;
823
Etienne Carriere09665cb2022-02-21 09:22:39 +0100824 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200825 if (!clk_state) {
826 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
827
828 out->status = SCMI_NOT_FOUND;
829 } else if (in->attributes > 1) {
830 out->status = SCMI_PROTOCOL_ERROR;
831 } else {
832 clk_state->enabled = in->attributes;
833
834 out->status = SCMI_SUCCESS;
835 }
836
837 return 0;
838}
839
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200840static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
841{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200842 struct scmi_rd_attr_in *in = NULL;
843 struct scmi_rd_attr_out *out = NULL;
844 struct sandbox_scmi_reset *reset_state = NULL;
845
846 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
847 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
848 return -EINVAL;
849
850 in = (struct scmi_rd_attr_in *)msg->in_msg;
851 out = (struct scmi_rd_attr_out *)msg->out_msg;
852
Etienne Carriere09665cb2022-02-21 09:22:39 +0100853 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200854 if (!reset_state) {
855 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
856
857 out->status = SCMI_NOT_FOUND;
858 } else {
859 memset(out, 0, sizeof(*out));
860 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
861
862 out->status = SCMI_SUCCESS;
863 }
864
865 return 0;
866}
867
868static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
869{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200870 struct scmi_rd_reset_in *in = NULL;
871 struct scmi_rd_reset_out *out = NULL;
872 struct sandbox_scmi_reset *reset_state = NULL;
873
874 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
875 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
876 return -EINVAL;
877
878 in = (struct scmi_rd_reset_in *)msg->in_msg;
879 out = (struct scmi_rd_reset_out *)msg->out_msg;
880
Etienne Carriere09665cb2022-02-21 09:22:39 +0100881 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200882 if (!reset_state) {
883 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
884
885 out->status = SCMI_NOT_FOUND;
886 } else if (in->reset_state > 1) {
887 dev_err(dev, "Invalid reset domain input attribute value\n");
888
889 out->status = SCMI_INVALID_PARAMETERS;
890 } else {
891 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
892 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
893 out->status = SCMI_NOT_SUPPORTED;
894 } else {
895 /* Ends deasserted whatever current state */
896 reset_state->asserted = false;
897 out->status = SCMI_SUCCESS;
898 }
899 } else {
900 reset_state->asserted = in->flags &
901 SCMI_RD_RESET_FLAG_ASSERT;
902
903 out->status = SCMI_SUCCESS;
904 }
905 }
906
907 return 0;
908}
909
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100910static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
911{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100912 struct scmi_voltd_attr_in *in = NULL;
913 struct scmi_voltd_attr_out *out = NULL;
914 struct sandbox_scmi_voltd *voltd_state = NULL;
915
916 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
917 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
918 return -EINVAL;
919
920 in = (struct scmi_voltd_attr_in *)msg->in_msg;
921 out = (struct scmi_voltd_attr_out *)msg->out_msg;
922
Etienne Carriere09665cb2022-02-21 09:22:39 +0100923 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100924 if (!voltd_state) {
925 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
926
927 out->status = SCMI_NOT_FOUND;
928 } else {
929 memset(out, 0, sizeof(*out));
930 snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
931
932 out->status = SCMI_SUCCESS;
933 }
934
935 return 0;
936}
937
938static int sandbox_scmi_voltd_config_set(struct udevice *dev,
939 struct scmi_msg *msg)
940{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100941 struct scmi_voltd_config_set_in *in = NULL;
942 struct scmi_voltd_config_set_out *out = NULL;
943 struct sandbox_scmi_voltd *voltd_state = NULL;
944
945 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
946 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
947 return -EINVAL;
948
949 in = (struct scmi_voltd_config_set_in *)msg->in_msg;
950 out = (struct scmi_voltd_config_set_out *)msg->out_msg;
951
Etienne Carriere09665cb2022-02-21 09:22:39 +0100952 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100953 if (!voltd_state) {
954 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
955
956 out->status = SCMI_NOT_FOUND;
957 } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
958 dev_err(dev, "Invalid config value 0x%x\n", in->config);
959
960 out->status = SCMI_INVALID_PARAMETERS;
961 } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
962 in->config != SCMI_VOLTD_CONFIG_OFF) {
963 dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
964
965 out->status = SCMI_INVALID_PARAMETERS;
966 } else {
967 voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
968 out->status = SCMI_SUCCESS;
969 }
970
971 return 0;
972}
973
974static int sandbox_scmi_voltd_config_get(struct udevice *dev,
975 struct scmi_msg *msg)
976{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100977 struct scmi_voltd_config_get_in *in = NULL;
978 struct scmi_voltd_config_get_out *out = NULL;
979 struct sandbox_scmi_voltd *voltd_state = NULL;
980
981 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
982 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
983 return -EINVAL;
984
985 in = (struct scmi_voltd_config_get_in *)msg->in_msg;
986 out = (struct scmi_voltd_config_get_out *)msg->out_msg;
987
Etienne Carriere09665cb2022-02-21 09:22:39 +0100988 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100989 if (!voltd_state) {
990 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
991
992 out->status = SCMI_NOT_FOUND;
993 } else {
994 if (voltd_state->enabled)
995 out->config = SCMI_VOLTD_CONFIG_ON;
996 else
997 out->config = SCMI_VOLTD_CONFIG_OFF;
998
999 out->status = SCMI_SUCCESS;
1000 }
1001
1002 return 0;
1003}
1004
1005static int sandbox_scmi_voltd_level_set(struct udevice *dev,
1006 struct scmi_msg *msg)
1007{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001008 struct scmi_voltd_level_set_in *in = NULL;
1009 struct scmi_voltd_level_set_out *out = NULL;
1010 struct sandbox_scmi_voltd *voltd_state = NULL;
1011
1012 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
1013 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
1014 return -EINVAL;
1015
1016 in = (struct scmi_voltd_level_set_in *)msg->in_msg;
1017 out = (struct scmi_voltd_level_set_out *)msg->out_msg;
1018
Etienne Carriere09665cb2022-02-21 09:22:39 +01001019 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001020 if (!voltd_state) {
1021 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1022
1023 out->status = SCMI_NOT_FOUND;
1024 } else {
1025 voltd_state->voltage_uv = in->voltage_level;
1026 out->status = SCMI_SUCCESS;
1027 }
1028
1029 return 0;
1030}
1031
1032static int sandbox_scmi_voltd_level_get(struct udevice *dev,
1033 struct scmi_msg *msg)
1034{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001035 struct scmi_voltd_level_get_in *in = NULL;
1036 struct scmi_voltd_level_get_out *out = NULL;
1037 struct sandbox_scmi_voltd *voltd_state = NULL;
1038
1039 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
1040 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
1041 return -EINVAL;
1042
1043 in = (struct scmi_voltd_level_get_in *)msg->in_msg;
1044 out = (struct scmi_voltd_level_get_out *)msg->out_msg;
1045
Etienne Carriere09665cb2022-02-21 09:22:39 +01001046 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001047 if (!voltd_state) {
1048 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1049
1050 out->status = SCMI_NOT_FOUND;
1051 } else {
1052 out->voltage_level = voltd_state->voltage_uv;
1053 out->status = SCMI_SUCCESS;
1054 }
1055
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001056 return 0;
1057}
1058
1059/**
1060 * sandbox_scmi_of_get_channel - assigne a channel
1061 * @dev: SCMI agent device
1062 * @protocol: SCMI protocol device
1063 * @channel: Pointer to channel info
1064 *
1065 * Assign a channel for the protocol, @protocol, in @channel,
1066 * based on a device tree's property.
1067 *
1068 * Return: 0 on success, error code on failure
1069 */
1070static int sandbox_scmi_of_get_channel(struct udevice *dev,
1071 struct udevice *protocol,
1072 struct scmi_channel **channel)
1073{
1074 struct sandbox_channel *agent_chan = dev_get_plat(dev);
1075 struct sandbox_channel *chan;
1076 u32 channel_id;
1077
1078 if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
1079 /* Uses agent channel */
1080 *channel = container_of(agent_chan, struct scmi_channel, ref);
1081
1082 return 0;
1083 }
1084
1085 /* Setup a dedicated channel */
1086 chan = calloc(1, sizeof(*chan));
1087 if (!chan)
1088 return -ENOMEM;
1089
1090 chan->channel_id = channel_id;
1091
1092 *channel = container_of(chan, struct scmi_channel, ref);
1093
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001094 return 0;
1095}
1096
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001097/**
1098 * sandbox_scmi_of_to_plat - assigne a channel to agent
1099 * @dev: SCMI agent device
1100 *
1101 * Assign a channel for the agent, @protocol.
1102 *
1103 * Return: always 0
1104 */
1105static int sandbox_scmi_of_to_plat(struct udevice *dev)
1106{
1107 struct sandbox_channel *chan = dev_get_plat(dev);
1108
1109 /* The channel for agent is always 0 */
1110 chan->channel_id = 0;
1111
1112 return 0;
1113}
1114
1115unsigned int sandbox_scmi_channel_id(struct udevice *dev)
1116{
1117 struct scmi_agent_proto_priv *priv;
1118 struct sandbox_channel *chan;
1119
1120 priv = dev_get_parent_priv(dev);
1121 chan = (struct sandbox_channel *)&priv->channel->ref;
1122
1123 return chan->channel_id;
1124}
1125
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001126static int sandbox_proto_not_supported(struct scmi_msg *msg)
1127{
1128 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
1129
1130 return 0;
1131}
1132
Etienne Carriere02fd1262020-09-09 18:44:00 +02001133static int sandbox_scmi_test_process_msg(struct udevice *dev,
Etienne Carriere05440292022-05-31 18:09:19 +02001134 struct scmi_channel *channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001135 struct scmi_msg *msg)
1136{
1137 switch (msg->protocol_id) {
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +09001138 case SCMI_PROTOCOL_ID_BASE:
1139 switch (msg->message_id) {
1140 case SCMI_PROTOCOL_VERSION:
1141 return sandbox_scmi_base_protocol_version(dev, msg);
1142 case SCMI_PROTOCOL_ATTRIBUTES:
1143 return sandbox_scmi_base_protocol_attrs(dev, msg);
1144 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
1145 return sandbox_scmi_base_message_attrs(dev, msg);
1146 case SCMI_BASE_DISCOVER_VENDOR:
1147 return sandbox_scmi_base_discover_vendor(dev, msg);
1148 case SCMI_BASE_DISCOVER_SUB_VENDOR:
1149 return sandbox_scmi_base_discover_sub_vendor(dev, msg);
1150 case SCMI_BASE_DISCOVER_IMPL_VERSION:
1151 return sandbox_scmi_base_discover_impl_version(dev, msg);
1152 case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
1153 return sandbox_scmi_base_discover_list_protocols(dev, msg);
1154 case SCMI_BASE_DISCOVER_AGENT:
1155 return sandbox_scmi_base_discover_agent(dev, msg);
1156 case SCMI_BASE_NOTIFY_ERRORS:
1157 break;
1158 case SCMI_BASE_SET_DEVICE_PERMISSIONS:
1159 return sandbox_scmi_base_set_device_permissions(dev, msg);
1160 case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
1161 return sandbox_scmi_base_set_protocol_permissions(dev, msg);
1162 case SCMI_BASE_RESET_AGENT_CONFIGURATION:
1163 return sandbox_scmi_base_reset_agent_configuration(dev, msg);
1164 default:
1165 break;
1166 }
1167 break;
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001168 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001169 if (!CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN))
1170 return sandbox_proto_not_supported(msg);
1171
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001172 switch (msg->message_id) {
1173 case SCMI_PROTOCOL_VERSION:
1174 return sandbox_scmi_pwd_protocol_version(dev, msg);
1175 case SCMI_PROTOCOL_ATTRIBUTES:
1176 return sandbox_scmi_pwd_protocol_attribs(dev, msg);
1177 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
1178 return sandbox_scmi_pwd_protocol_msg_attribs(dev, msg);
1179 case SCMI_PWD_ATTRIBUTES:
1180 return sandbox_scmi_pwd_attribs(dev, msg);
1181 case SCMI_PWD_STATE_SET:
1182 return sandbox_scmi_pwd_state_set(dev, msg);
1183 case SCMI_PWD_STATE_GET:
1184 return sandbox_scmi_pwd_state_get(dev, msg);
1185 case SCMI_PWD_NAME_GET:
1186 return sandbox_scmi_pwd_name_get(dev, msg);
1187 default:
1188 break;
1189 }
1190 break;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001191 case SCMI_PROTOCOL_ID_CLOCK:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001192 if (!CONFIG_IS_ENABLED(CLK_SCMI))
1193 return sandbox_proto_not_supported(msg);
1194
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001195 switch (msg->message_id) {
Etienne Carriere4c4ec902022-02-21 09:22:42 +01001196 case SCMI_PROTOCOL_ATTRIBUTES:
1197 return sandbox_scmi_clock_protocol_attribs(dev, msg);
1198 case SCMI_CLOCK_ATTRIBUTES:
1199 return sandbox_scmi_clock_attribs(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001200 case SCMI_CLOCK_RATE_SET:
1201 return sandbox_scmi_clock_rate_set(dev, msg);
1202 case SCMI_CLOCK_RATE_GET:
1203 return sandbox_scmi_clock_rate_get(dev, msg);
1204 case SCMI_CLOCK_CONFIG_SET:
1205 return sandbox_scmi_clock_gate(dev, msg);
1206 default:
1207 break;
1208 }
1209 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +02001210 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001211 if (!CONFIG_IS_ENABLED(RESET_SCMI))
1212 return sandbox_proto_not_supported(msg);
1213
Etienne Carriere8b9b6892020-09-09 18:44:07 +02001214 switch (msg->message_id) {
1215 case SCMI_RESET_DOMAIN_ATTRIBUTES:
1216 return sandbox_scmi_rd_attribs(dev, msg);
1217 case SCMI_RESET_DOMAIN_RESET:
1218 return sandbox_scmi_rd_reset(dev, msg);
1219 default:
1220 break;
1221 }
1222 break;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001223 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001224 if (!CONFIG_IS_ENABLED(DM_REGULATOR_SCMI))
1225 return sandbox_proto_not_supported(msg);
1226
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001227 switch (msg->message_id) {
1228 case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
1229 return sandbox_scmi_voltd_attribs(dev, msg);
1230 case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
1231 return sandbox_scmi_voltd_config_set(dev, msg);
1232 case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
1233 return sandbox_scmi_voltd_config_get(dev, msg);
1234 case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
1235 return sandbox_scmi_voltd_level_set(dev, msg);
1236 case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
1237 return sandbox_scmi_voltd_level_get(dev, msg);
1238 default:
1239 break;
1240 }
1241 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +02001242 case SCMI_PROTOCOL_ID_SYSTEM:
1243 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +02001244 case SCMI_PROTOCOL_ID_SENSOR:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001245 return sandbox_proto_not_supported(msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +02001246 default:
1247 break;
1248 }
1249
1250 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
1251 __func__, dev->name, msg->protocol_id, msg->message_id);
1252
1253 if (msg->out_msg_sz < sizeof(u32))
1254 return -EINVAL;
1255
1256 /* Intentionnaly report unhandled IDs through the SCMI return code */
1257 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
1258 return 0;
1259}
1260
1261static int sandbox_scmi_test_remove(struct udevice *dev)
1262{
Etienne Carriere02fd1262020-09-09 18:44:00 +02001263 debug_print_agent_state(dev, "removed");
1264
Etienne Carriere02fd1262020-09-09 18:44:00 +02001265 return 0;
1266}
1267
1268static int sandbox_scmi_test_probe(struct udevice *dev)
1269{
Etienne Carriere02fd1262020-09-09 18:44:00 +02001270 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +02001271
Etienne Carriere09665cb2022-02-21 09:22:39 +01001272 *agent = (struct sandbox_scmi_agent){
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001273 .pwdom_version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION,
1274 .pwdom = scmi_pwdom,
1275 .pwdom_count = ARRAY_SIZE(scmi_pwdom),
Etienne Carriere09665cb2022-02-21 09:22:39 +01001276 .clk = scmi_clk,
1277 .clk_count = ARRAY_SIZE(scmi_clk),
1278 .reset = scmi_reset,
1279 .reset_count = ARRAY_SIZE(scmi_reset),
1280 .voltd = scmi_voltd,
1281 .voltd_count = ARRAY_SIZE(scmi_voltd),
1282 };
Etienne Carriere02fd1262020-09-09 18:44:00 +02001283
1284 debug_print_agent_state(dev, "probed");
1285
Etienne Carriere02fd1262020-09-09 18:44:00 +02001286 return 0;
1287};
1288
1289static const struct udevice_id sandbox_scmi_test_ids[] = {
1290 { .compatible = "sandbox,scmi-agent" },
1291 { }
1292};
1293
1294struct scmi_agent_ops sandbox_scmi_test_ops = {
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001295 .of_get_channel = sandbox_scmi_of_get_channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001296 .process_msg = sandbox_scmi_test_process_msg,
1297};
1298
1299U_BOOT_DRIVER(sandbox_scmi_agent) = {
1300 .name = "sandbox-scmi_agent",
1301 .id = UCLASS_SCMI_AGENT,
1302 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001303 .priv_auto = sizeof(struct sandbox_scmi_agent),
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001304 .plat_auto = sizeof(struct sandbox_channel),
1305 .of_to_plat = sandbox_scmi_of_to_plat,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001306 .probe = sandbox_scmi_test_probe,
1307 .remove = sandbox_scmi_test_remove,
1308 .ops = &sandbox_scmi_test_ops,
1309};