blob: cc9011c7312f0e53878aebb9d127d9d449464243 [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 <common.h>
9#include <dm.h>
10#include <malloc.h>
11#include <scmi_agent.h>
12#include <scmi_agent-uclass.h>
13#include <scmi_protocols.h>
14#include <asm/io.h>
15#include <asm/scmi_test.h>
16#include <dm/device_compat.h>
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090017#include <linux/bitfield.h>
18#include <linux/kernel.h>
Etienne Carriere02fd1262020-09-09 18:44:00 +020019
20/*
21 * The sandbox SCMI agent driver simulates to some extend a SCMI message
22 * processing. It simulates few of the SCMI services for some of the
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020023 * SCMI protocols embedded in U-Boot. Currently:
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090024 * - SCMI base protocol
Etienne Carriere09665cb2022-02-21 09:22:39 +010025 * - SCMI clock protocol emulates an agent exposing 2 clocks
26 * - SCMI reset protocol emulates an agent exposing a reset controller
27 * - SCMI voltage domain protocol emulates an agent exposing 2 regulators
Etienne Carriere02fd1262020-09-09 18:44:00 +020028 *
Etienne Carriere09665cb2022-02-21 09:22:39 +010029 * As per DT bindings, the device node name shall be scmi.
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020030 *
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010031 * All clocks and regulators are default disabled and reset controller down.
Etienne Carriere02fd1262020-09-09 18:44:00 +020032 *
Etienne Carriere09665cb2022-02-21 09:22:39 +010033 * This driver exports sandbox_scmi_service_ctx() for the test sequence to
Etienne Carriere02fd1262020-09-09 18:44:00 +020034 * get the state of the simulated services (clock state, rate, ...) and
35 * check back-end device state reflects the request send through the
Etienne Carriere8b9b6892020-09-09 18:44:07 +020036 * various uclass devices, as clocks and reset controllers.
Etienne Carriere02fd1262020-09-09 18:44:00 +020037 */
38
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090039#define SANDBOX_SCMI_BASE_PROTOCOL_VERSION SCMI_BASE_PROTOCOL_VERSION
40#define SANDBOX_SCMI_VENDOR "U-Boot"
41#define SANDBOX_SCMI_SUB_VENDOR "Sandbox"
42#define SANDBOX_SCMI_IMPL_VERSION 0x1
43#define SANDBOX_SCMI_AGENT_NAME "OSPM"
44#define SANDBOX_SCMI_PLATFORM_NAME "platform"
45
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +090046#define SANDBOX_SCMI_PWD_PROTOCOL_VERSION SCMI_PWD_PROTOCOL_VERSION
47
AKASHI Takahiro6221bf72023-10-11 19:06:56 +090048/**
49 * struct sandbox_channel - Description of sandbox transport
50 * @channel_id: Channel identifier
51 *
52 * Dummy channel. This will be used to test if a protocol-specific
53 * channel is properly used.
54 * Id 0 means a channel for the sandbox agent.
55 */
56struct sandbox_channel {
57 unsigned int channel_id;
58};
59
60/**
61 * struct scmi_channel - Channel instance referenced in SCMI drivers
62 * @ref: Reference to local channel instance
63 **/
64struct scmi_channel {
65 struct sandbox_channel ref;
66};
67
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090068static u8 protocols[] = {
AKASHI Takahiro59171ff2023-11-14 11:14:25 +090069 CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN, (SCMI_PROTOCOL_ID_POWER_DOMAIN,))
70 CONFIG_IS_ENABLED(CLK_SCMI, (SCMI_PROTOCOL_ID_CLOCK,))
71 CONFIG_IS_ENABLED(RESET_SCMI, (SCMI_PROTOCOL_ID_RESET_DOMAIN,))
72 CONFIG_IS_ENABLED(DM_REGULATOR_SCMI, (SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,))
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090073};
74
75#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
76
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +090077static struct sandbox_scmi_pwd scmi_pwdom[] = {
78 { .id = 0 },
79 { .id = 1 },
80 { .id = 2 },
81};
82
Etienne Carriere09665cb2022-02-21 09:22:39 +010083static struct sandbox_scmi_clk scmi_clk[] = {
Etienne Carrierebf1f1322022-02-21 09:22:41 +010084 { .rate = 333 },
85 { .rate = 200 },
86 { .rate = 1000 },
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020087};
88
Etienne Carriere09665cb2022-02-21 09:22:39 +010089static struct sandbox_scmi_reset scmi_reset[] = {
Etienne Carriere8b9b6892020-09-09 18:44:07 +020090 { .id = 3 },
91};
92
Etienne Carriere09665cb2022-02-21 09:22:39 +010093static struct sandbox_scmi_voltd scmi_voltd[] = {
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010094 { .id = 0, .voltage_uv = 3300000 },
95 { .id = 1, .voltage_uv = 1800000 },
96};
97
AKASHI Takahirodae00462023-10-11 19:07:03 +090098struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
Etienne Carriere02fd1262020-09-09 18:44:00 +020099{
AKASHI Takahirodae00462023-10-11 19:07:03 +0900100 return dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200101}
102
103static void debug_print_agent_state(struct udevice *dev, char *str)
104{
105 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
106
Etienne Carriere09665cb2022-02-21 09:22:39 +0100107 dev_dbg(dev, "Dump sandbox_scmi_agent: %s\n", str);
108 dev_dbg(dev, " scmi_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200109 agent->clk_count,
110 agent->clk_count ? agent->clk[0].enabled : -1,
111 agent->clk_count ? agent->clk[0].rate : -1,
112 agent->clk_count > 1 ? agent->clk[1].enabled : -1,
113 agent->clk_count > 1 ? agent->clk[1].rate : -1,
114 agent->clk_count > 2 ? agent->clk[2].enabled : -1,
115 agent->clk_count > 2 ? agent->clk[2].rate : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100116 dev_dbg(dev, " scmi_reset (%zu): %d, %d, ...\n",
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200117 agent->reset_count,
118 agent->reset_count ? agent->reset[0].asserted : -1,
119 agent->reset_count > 1 ? agent->reset[1].asserted : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100120 dev_dbg(dev, " scmi_voltd (%zu): %u/%d, %u/%d, ...\n",
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100121 agent->voltd_count,
122 agent->voltd_count ? agent->voltd[0].enabled : -1,
123 agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
124 agent->voltd_count ? agent->voltd[1].enabled : -1,
125 agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200126};
127
Etienne Carriere09665cb2022-02-21 09:22:39 +0100128static struct sandbox_scmi_clk *get_scmi_clk_state(uint clock_id)
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200129{
Etienne Carrierebf1f1322022-02-21 09:22:41 +0100130 if (clock_id < ARRAY_SIZE(scmi_clk))
131 return scmi_clk + clock_id;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200132
133 return NULL;
134}
135
Etienne Carriere09665cb2022-02-21 09:22:39 +0100136static struct sandbox_scmi_reset *get_scmi_reset_state(uint reset_id)
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200137{
138 size_t n;
139
Etienne Carriere09665cb2022-02-21 09:22:39 +0100140 for (n = 0; n < ARRAY_SIZE(scmi_reset); n++)
141 if (scmi_reset[n].id == reset_id)
142 return scmi_reset + n;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200143
144 return NULL;
145}
146
Etienne Carriere09665cb2022-02-21 09:22:39 +0100147static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100148{
149 size_t n;
150
Etienne Carriere09665cb2022-02-21 09:22:39 +0100151 for (n = 0; n < ARRAY_SIZE(scmi_voltd); n++)
152 if (scmi_voltd[n].id == domain_id)
153 return scmi_voltd + n;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100154
155 return NULL;
156}
157
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200158/*
159 * Sandbox SCMI agent ops
160 */
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900161
162/* Base Protocol */
163
164/**
165 * sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
166 * @dev: SCMI device
167 * @msg: SCMI message
168 *
169 * Implement SCMI_BASE_PROTOCOL_VERSION command.
170 */
171static int sandbox_scmi_base_protocol_version(struct udevice *dev,
172 struct scmi_msg *msg)
173{
174 struct scmi_protocol_version_out *out = NULL;
175
176 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
177 return -EINVAL;
178
179 out = (struct scmi_protocol_version_out *)msg->out_msg;
180 out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION;
181 out->status = SCMI_SUCCESS;
182
183 return 0;
184}
185
186/**
187 * sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
188 * @dev: SCMI device
189 * @msg: SCMI message
190 *
191 * Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
192 */
193static int sandbox_scmi_base_protocol_attrs(struct udevice *dev,
194 struct scmi_msg *msg)
195{
196 struct scmi_protocol_attrs_out *out = NULL;
197
198 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
199 return -EINVAL;
200
201 out = (struct scmi_protocol_attrs_out *)msg->out_msg;
202 out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS;
203 out->status = SCMI_SUCCESS;
204
205 return 0;
206}
207
208/**
209 * sandbox_scmi_base_message_attrs - implement
210 * SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
211 * @dev: SCMI device
212 * @msg: SCMI message
213 *
214 * Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
215 */
216static int sandbox_scmi_base_message_attrs(struct udevice *dev,
217 struct scmi_msg *msg)
218{
219 u32 message_id;
220 struct scmi_protocol_msg_attrs_out *out = NULL;
221
222 if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
223 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
224 return -EINVAL;
225
226 message_id = *(u32 *)msg->in_msg;
227 out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg;
228
229 if (message_id >= SCMI_PROTOCOL_VERSION &&
230 message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION &&
231 message_id != SCMI_BASE_NOTIFY_ERRORS) {
232 out->attributes = 0;
233 out->status = SCMI_SUCCESS;
234 } else {
235 out->status = SCMI_NOT_FOUND;
236 }
237
238 return 0;
239}
240
241/**
242 * sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
243 * @dev: SCMI device
244 * @msg: SCMI message
245 *
246 * Implement SCMI_BASE_DISCOVER_VENDOR command
247 */
248static int sandbox_scmi_base_discover_vendor(struct udevice *dev,
249 struct scmi_msg *msg)
250{
251 struct scmi_base_discover_vendor_out *out = NULL;
252
253 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
254 return -EINVAL;
255
256 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
257 strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR);
258 out->status = SCMI_SUCCESS;
259
260 return 0;
261}
262
263/**
264 * sandbox_scmi_base_discover_sub_vendor - implement
265 * SCMI_BASE_DISCOVER_SUB_VENDOR
266 * @dev: SCMI device
267 * @msg: SCMI message
268 *
269 * Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
270 */
271static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev,
272 struct scmi_msg *msg)
273{
274 struct scmi_base_discover_vendor_out *out = NULL;
275
276 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
277 return -EINVAL;
278
279 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
280 strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR);
281 out->status = SCMI_SUCCESS;
282
283 return 0;
284}
285
286/**
287 * sandbox_scmi_base_discover_impl_version - implement
288 * SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
289 * @dev: SCMI device
290 * @msg: SCMI message
291 *
292 * Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
293 */
294static int sandbox_scmi_base_discover_impl_version(struct udevice *dev,
295 struct scmi_msg *msg)
296{
297 struct scmi_base_discover_impl_version_out *out = NULL;
298
299 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
300 return -EINVAL;
301
302 out = (struct scmi_base_discover_impl_version_out *)msg->out_msg;
303 out->impl_version = SANDBOX_SCMI_IMPL_VERSION;
304 out->status = SCMI_SUCCESS;
305
306 return 0;
307}
308
309/**
310 * sandbox_scmi_base_discover_list_protocols - implement
311 * SCMI_BASE_DISCOVER_LIST_PROTOCOLS
312 * @dev: SCMI device
313 * @msg: SCMI message
314 *
315 * Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
316 */
317static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev,
318 struct scmi_msg *msg)
319{
320 struct scmi_base_discover_list_protocols_out *out = NULL;
321
322 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
323 return -EINVAL;
324
325 out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg;
326 memcpy(out->protocols, protocols, sizeof(protocols));
327 out->num_protocols = NUM_PROTOCOLS;
328 out->status = SCMI_SUCCESS;
329
330 return 0;
331}
332
333/**
334 * sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
335 * @dev: SCMI device
336 * @msg: SCMI message
337 *
338 * Implement SCMI_BASE_DISCOVER_AGENT command
339 */
340static int sandbox_scmi_base_discover_agent(struct udevice *dev,
341 struct scmi_msg *msg)
342{
343 u32 agent_id;
344 struct scmi_base_discover_agent_out *out = NULL;
345
346 if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) ||
347 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
348 return -EINVAL;
349
350 agent_id = *(u32 *)msg->in_msg;
351 out = (struct scmi_base_discover_agent_out *)msg->out_msg;
352 out->status = SCMI_SUCCESS;
353 if (agent_id == 0xffffffff || agent_id == 1) {
354 out->agent_id = 1;
355 strcpy(out->name, SANDBOX_SCMI_AGENT_NAME);
356 } else if (!agent_id) {
357 out->agent_id = agent_id;
358 strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME);
359 } else {
360 out->status = SCMI_NOT_FOUND;
361 }
362
363 return 0;
364}
365
366/**
367 * sandbox_scmi_base_set_device_permissions - implement
368 * SCMI_BASE_SET_DEVICE_PERMISSIONS
369 * @dev: SCMI device
370 * @msg: SCMI message
371 *
372 * Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
373 */
374static int sandbox_scmi_base_set_device_permissions(struct udevice *dev,
375 struct scmi_msg *msg)
376{
377 struct scmi_base_set_device_permissions_in *in = NULL;
378 u32 *status;
379
380 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
381 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
382 return -EINVAL;
383
384 in = (struct scmi_base_set_device_permissions_in *)msg->in_msg;
385 status = (u32 *)msg->out_msg;
386
387 if (in->agent_id != 1 || in->device_id != 0)
388 *status = SCMI_NOT_FOUND;
389 else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
390 *status = SCMI_INVALID_PARAMETERS;
391 else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
392 *status = SCMI_SUCCESS;
393 else
394 /* unset not allowed */
395 *status = SCMI_DENIED;
396
397 return 0;
398}
399
400/**
401 * sandbox_scmi_base_set_protocol_permissions - implement
402 * SCMI_BASE_SET_PROTOCOL_PERMISSIONS
403 * @dev: SCMI device
404 * @msg: SCMI message
405 *
406 * Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
407 */
408static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev,
409 struct scmi_msg *msg)
410{
411 struct scmi_base_set_protocol_permissions_in *in = NULL;
412 u32 *status;
413 int i;
414
415 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
416 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
417 return -EINVAL;
418
419 in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg;
420 status = (u32 *)msg->out_msg;
421
422 for (i = 0; i < ARRAY_SIZE(protocols); i++)
423 if (protocols[i] == in->command_id)
424 break;
425 if (in->agent_id != 1 || in->device_id != 0 ||
426 i == ARRAY_SIZE(protocols))
427 *status = SCMI_NOT_FOUND;
428 else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
429 *status = SCMI_INVALID_PARAMETERS;
430 else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
431 *status = SCMI_SUCCESS;
432 else
433 /* unset not allowed */
434 *status = SCMI_DENIED;
435
436 return 0;
437}
438
439/**
440 * sandbox_scmi_base_reset_agent_configuration - implement
441 * SCMI_BASE_RESET_AGENT_CONFIGURATION
442 * @dev: SCMI device
443 * @msg: SCMI message
444 *
445 * Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
446 */
447static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
448 struct scmi_msg *msg)
449{
450 struct scmi_base_reset_agent_configuration_in *in = NULL;
451 u32 *status;
452
453 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
454 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
455 return -EINVAL;
456
457 in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg;
458 status = (u32 *)msg->out_msg;
459
460 if (in->agent_id != 1)
461 *status = SCMI_NOT_FOUND;
462 else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS)
463 *status = SCMI_INVALID_PARAMETERS;
464 else
465 *status = SCMI_DENIED;
466
467 return 0;
468}
469
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900470/* Power Domain Management Protocol */
471
472/**
473 * sandbox_scmi_pwd_protocol_version - implement SCMI_PROTOCOL_VERSION
474 * @dev: SCMI device
475 * @msg: SCMI message
476 *
477 * Implement SCMI_PROTOCOL_VERSION command.
478 *
479 * Return: 0 on success, error code on failure
480 */
481static int sandbox_scmi_pwd_protocol_version(struct udevice *dev,
482 struct scmi_msg *msg)
483{
484 struct scmi_protocol_version_out *out = NULL;
485
486 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
487 return -EINVAL;
488
489 out = (struct scmi_protocol_version_out *)msg->out_msg;
490 out->version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION;
491 out->status = SCMI_SUCCESS;
492
493 return 0;
494}
495
496/**
497 * sandbox_scmi_pwd_protocol_attribs - implement SCMI_PWD_PROTOCOL_ATTRS
498 * @dev: SCMI device
499 * @msg: SCMI message
500 *
501 * Implement SCMI_PWD_PROTOCOL_ATTRS command.
502 *
503 * Return: 0 on success, error code on failure
504 */
505static int sandbox_scmi_pwd_protocol_attribs(struct udevice *dev,
506 struct scmi_msg *msg)
507{
508 struct scmi_pwd_protocol_attrs_out *out;
509
510 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
511 return -EINVAL;
512
513 out = (struct scmi_pwd_protocol_attrs_out *)msg->out_msg;
514
515 out->attributes = ARRAY_SIZE(scmi_pwdom);
516 out->stats_addr_low = 0;
517 out->stats_addr_high = 0;
518 out->stats_len = 0;
519 out->status = SCMI_SUCCESS;
520
521 return 0;
522}
523
524/**
525 * sandbox_scmi_pwd_protocol_msg_attribs - implement
526 SCMI_PWD_PROTOCOL_MESSAGE_ATTRS
527 * @dev: SCMI device
528 * @msg: SCMI message
529 *
530 * Implement SCMI_PWD_PROTOCOL_MESSAGE_ATTRS command.
531 *
532 * Return: 0 on success, error code on failure
533 */
534static int sandbox_scmi_pwd_protocol_msg_attribs(struct udevice *dev,
535 struct scmi_msg *msg)
536{
537 u32 message_id;
538 struct scmi_pwd_protocol_msg_attrs_out *out;
539
540 if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
541 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
542 return -EINVAL;
543
544 message_id = *(u32 *)msg->in_msg;
545
546 out = (struct scmi_pwd_protocol_msg_attrs_out *)msg->out_msg;
547 if (message_id <= SCMI_PWD_STATE_GET ||
548 message_id == SCMI_PWD_NAME_GET) {
549 out->attributes = 0;
550 out->status = SCMI_SUCCESS;
551 } else {
552 out->status = SCMI_NOT_FOUND;
553 }
554
555 return 0;
556}
557
558/**
559 * sandbox_scmi_pwd_attribs - implement SCMI_PWD_ATTRS
560 * @dev: SCMI device
561 * @msg: SCMI message
562 *
563 * Implement SCMI_PWD_ATTRS command.
564 *
565 * Return: 0 on success, error code on failure
566 */
567static int sandbox_scmi_pwd_attribs(struct udevice *dev, struct scmi_msg *msg)
568{
569 u32 domain_id;
570 struct scmi_pwd_attrs_out *out;
571
572 if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
573 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
574 return -EINVAL;
575
576 domain_id = *(u32 *)msg->in_msg;
577 out = (struct scmi_pwd_attrs_out *)msg->out_msg;
578
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900579 if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900580 out->status = SCMI_NOT_FOUND;
581
582 return 0;
583 }
584
585 out->attributes =
586 SCMI_PWD_ATTR_PSTATE_SYNC | SCMI_PWD_ATTR_EXTENDED_NAME;
587 /* just 15-char + NULL */
588 snprintf(out->name, SCMI_PWD_NAME_LENGTH_MAX, "power-domain--%d",
589 domain_id);
590 out->status = SCMI_SUCCESS;
591
592 return 0;
593}
594
595/**
596 * sandbox_scmi_pwd_state_set - implement SCMI_PWD_STATE_SET
597 * @dev: SCMI device
598 * @msg: SCMI message
599 *
600 * Implement SCMI_PWD_STATE_SET command.
601 *
602 * Return: 0 on success, error code on failure
603 */
604static int sandbox_scmi_pwd_state_set(struct udevice *dev, struct scmi_msg *msg)
605{
606 struct scmi_pwd_state_set_in *in;
607 s32 *status;
608
609 if (!msg->in_msg || msg->in_msg_sz < sizeof(in) ||
610 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
611 return -EINVAL;
612
613 in = (struct scmi_pwd_state_set_in *)msg->in_msg;
614 status = (s32 *)msg->out_msg;
615
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900616 if (in->domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900617 *status = SCMI_NOT_FOUND;
618
619 return 0;
620 }
621
622 if ((in->flags & SCMI_PWD_SET_FLAGS_ASYNC) ||
623 (in->pstate != SCMI_PWD_PSTATE_TYPE_LOST && in->pstate)) {
624 *status = SCMI_INVALID_PARAMETERS;
625
626 return 0;
627 }
628
629 scmi_pwdom[in->domain_id].pstate = in->pstate;
630 *status = SCMI_SUCCESS;
631
632 return 0;
633}
634
635/**
636 * sandbox_scmi_pwd_state_get - implement SCMI_PWD_STATE_GET
637 * @dev: SCMI device
638 * @msg: SCMI message
639 *
640 * Implement SCMI_PWD_STATE_GET command.
641 *
642 * Return: 0 on success, error code on failure
643 */
644static int sandbox_scmi_pwd_state_get(struct udevice *dev, struct scmi_msg *msg)
645{
646 u32 domain_id;
647 struct scmi_pwd_state_get_out *out;
648
649 if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
650 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
651 return -EINVAL;
652
653 domain_id = *(u32 *)msg->in_msg;
654 out = (struct scmi_pwd_state_get_out *)msg->out_msg;
655
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900656 if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900657 out->status = SCMI_NOT_FOUND;
658
659 return 0;
660 }
661
662 out->pstate = scmi_pwdom[domain_id].pstate;
663 out->status = SCMI_SUCCESS;
664
665 return 0;
666}
667
668/**
669 * sandbox_scmi_pwd_name_get - implement SCMI_PWD_NAME_GET
670 * @dev: SCMI device
671 * @msg: SCMI message
672 *
673 * Implement SCMI_PWD_NAME_GET command.
674 *
675 * Return: 0 on success, error code on failure
676 */
677static int sandbox_scmi_pwd_name_get(struct udevice *dev, struct scmi_msg *msg)
678{
679 u32 domain_id;
680 struct scmi_pwd_name_get_out *out;
681
682 if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
683 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
684 return -EINVAL;
685
686 domain_id = *(u32 *)msg->in_msg;
687 out = (struct scmi_pwd_name_get_out *)msg->out_msg;
688
AKASHI Takahiro224b2ff2023-11-07 09:05:47 +0900689 if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +0900690 out->status = SCMI_NOT_FOUND;
691
692 return 0;
693 }
694
695 snprintf(out->extended_name, SCMI_PWD_EXTENDED_NAME_MAX,
696 "power-domain--%d-extended", domain_id);
697 out->status = SCMI_SUCCESS;
698
699 return 0;
700}
701
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900702/* Clock Protocol */
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200703
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100704static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
705 struct scmi_msg *msg)
706{
707 struct scmi_clk_protocol_attr_out *out = NULL;
708
709 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
710 return -EINVAL;
711
712 out = (struct scmi_clk_protocol_attr_out *)msg->out_msg;
713 out->attributes = ARRAY_SIZE(scmi_clk);
714 out->status = SCMI_SUCCESS;
715
716 return 0;
717}
718
719static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
720{
721 struct scmi_clk_attribute_in *in = NULL;
722 struct scmi_clk_attribute_out *out = NULL;
723 struct sandbox_scmi_clk *clk_state = NULL;
724 int ret;
725
726 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
727 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
728 return -EINVAL;
729
730 in = (struct scmi_clk_attribute_in *)msg->in_msg;
731 out = (struct scmi_clk_attribute_out *)msg->out_msg;
732
733 clk_state = get_scmi_clk_state(in->clock_id);
734 if (!clk_state) {
735 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
736
737 out->status = SCMI_NOT_FOUND;
738 } else {
739 memset(out, 0, sizeof(*out));
740
741 if (clk_state->enabled)
742 out->attributes = 1;
743
744 ret = snprintf(out->clock_name, sizeof(out->clock_name),
745 "clk%u", in->clock_id);
746 assert(ret > 0 && ret < sizeof(out->clock_name));
747
748 out->status = SCMI_SUCCESS;
749 }
750
751 return 0;
752}
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200753static int sandbox_scmi_clock_rate_set(struct udevice *dev,
754 struct scmi_msg *msg)
755{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200756 struct scmi_clk_rate_set_in *in = NULL;
757 struct scmi_clk_rate_set_out *out = NULL;
758 struct sandbox_scmi_clk *clk_state = NULL;
759
760 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
761 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
762 return -EINVAL;
763
764 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
765 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
766
Etienne Carriere09665cb2022-02-21 09:22:39 +0100767 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200768 if (!clk_state) {
769 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
770
771 out->status = SCMI_NOT_FOUND;
772 } else {
773 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
774
775 clk_state->rate = (ulong)rate;
776
777 out->status = SCMI_SUCCESS;
778 }
779
780 return 0;
781}
782
783static int sandbox_scmi_clock_rate_get(struct udevice *dev,
784 struct scmi_msg *msg)
785{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200786 struct scmi_clk_rate_get_in *in = NULL;
787 struct scmi_clk_rate_get_out *out = NULL;
788 struct sandbox_scmi_clk *clk_state = NULL;
789
790 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
791 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
792 return -EINVAL;
793
794 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
795 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
796
Etienne Carriere09665cb2022-02-21 09:22:39 +0100797 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200798 if (!clk_state) {
799 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
800
801 out->status = SCMI_NOT_FOUND;
802 } else {
803 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
804 out->rate_lsb = (u32)clk_state->rate;
805
806 out->status = SCMI_SUCCESS;
807 }
808
809 return 0;
810}
811
812static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
813{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200814 struct scmi_clk_state_in *in = NULL;
815 struct scmi_clk_state_out *out = NULL;
816 struct sandbox_scmi_clk *clk_state = NULL;
817
818 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
819 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
820 return -EINVAL;
821
822 in = (struct scmi_clk_state_in *)msg->in_msg;
823 out = (struct scmi_clk_state_out *)msg->out_msg;
824
Etienne Carriere09665cb2022-02-21 09:22:39 +0100825 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200826 if (!clk_state) {
827 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
828
829 out->status = SCMI_NOT_FOUND;
830 } else if (in->attributes > 1) {
831 out->status = SCMI_PROTOCOL_ERROR;
832 } else {
833 clk_state->enabled = in->attributes;
834
835 out->status = SCMI_SUCCESS;
836 }
837
838 return 0;
839}
840
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200841static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
842{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200843 struct scmi_rd_attr_in *in = NULL;
844 struct scmi_rd_attr_out *out = NULL;
845 struct sandbox_scmi_reset *reset_state = NULL;
846
847 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
848 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
849 return -EINVAL;
850
851 in = (struct scmi_rd_attr_in *)msg->in_msg;
852 out = (struct scmi_rd_attr_out *)msg->out_msg;
853
Etienne Carriere09665cb2022-02-21 09:22:39 +0100854 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200855 if (!reset_state) {
856 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
857
858 out->status = SCMI_NOT_FOUND;
859 } else {
860 memset(out, 0, sizeof(*out));
861 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
862
863 out->status = SCMI_SUCCESS;
864 }
865
866 return 0;
867}
868
869static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
870{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200871 struct scmi_rd_reset_in *in = NULL;
872 struct scmi_rd_reset_out *out = NULL;
873 struct sandbox_scmi_reset *reset_state = NULL;
874
875 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
876 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
877 return -EINVAL;
878
879 in = (struct scmi_rd_reset_in *)msg->in_msg;
880 out = (struct scmi_rd_reset_out *)msg->out_msg;
881
Etienne Carriere09665cb2022-02-21 09:22:39 +0100882 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200883 if (!reset_state) {
884 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
885
886 out->status = SCMI_NOT_FOUND;
887 } else if (in->reset_state > 1) {
888 dev_err(dev, "Invalid reset domain input attribute value\n");
889
890 out->status = SCMI_INVALID_PARAMETERS;
891 } else {
892 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
893 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
894 out->status = SCMI_NOT_SUPPORTED;
895 } else {
896 /* Ends deasserted whatever current state */
897 reset_state->asserted = false;
898 out->status = SCMI_SUCCESS;
899 }
900 } else {
901 reset_state->asserted = in->flags &
902 SCMI_RD_RESET_FLAG_ASSERT;
903
904 out->status = SCMI_SUCCESS;
905 }
906 }
907
908 return 0;
909}
910
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100911static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
912{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100913 struct scmi_voltd_attr_in *in = NULL;
914 struct scmi_voltd_attr_out *out = NULL;
915 struct sandbox_scmi_voltd *voltd_state = NULL;
916
917 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
918 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
919 return -EINVAL;
920
921 in = (struct scmi_voltd_attr_in *)msg->in_msg;
922 out = (struct scmi_voltd_attr_out *)msg->out_msg;
923
Etienne Carriere09665cb2022-02-21 09:22:39 +0100924 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100925 if (!voltd_state) {
926 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
927
928 out->status = SCMI_NOT_FOUND;
929 } else {
930 memset(out, 0, sizeof(*out));
931 snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
932
933 out->status = SCMI_SUCCESS;
934 }
935
936 return 0;
937}
938
939static int sandbox_scmi_voltd_config_set(struct udevice *dev,
940 struct scmi_msg *msg)
941{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100942 struct scmi_voltd_config_set_in *in = NULL;
943 struct scmi_voltd_config_set_out *out = NULL;
944 struct sandbox_scmi_voltd *voltd_state = NULL;
945
946 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
947 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
948 return -EINVAL;
949
950 in = (struct scmi_voltd_config_set_in *)msg->in_msg;
951 out = (struct scmi_voltd_config_set_out *)msg->out_msg;
952
Etienne Carriere09665cb2022-02-21 09:22:39 +0100953 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100954 if (!voltd_state) {
955 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
956
957 out->status = SCMI_NOT_FOUND;
958 } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
959 dev_err(dev, "Invalid config value 0x%x\n", in->config);
960
961 out->status = SCMI_INVALID_PARAMETERS;
962 } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
963 in->config != SCMI_VOLTD_CONFIG_OFF) {
964 dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
965
966 out->status = SCMI_INVALID_PARAMETERS;
967 } else {
968 voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
969 out->status = SCMI_SUCCESS;
970 }
971
972 return 0;
973}
974
975static int sandbox_scmi_voltd_config_get(struct udevice *dev,
976 struct scmi_msg *msg)
977{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100978 struct scmi_voltd_config_get_in *in = NULL;
979 struct scmi_voltd_config_get_out *out = NULL;
980 struct sandbox_scmi_voltd *voltd_state = NULL;
981
982 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
983 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
984 return -EINVAL;
985
986 in = (struct scmi_voltd_config_get_in *)msg->in_msg;
987 out = (struct scmi_voltd_config_get_out *)msg->out_msg;
988
Etienne Carriere09665cb2022-02-21 09:22:39 +0100989 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100990 if (!voltd_state) {
991 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
992
993 out->status = SCMI_NOT_FOUND;
994 } else {
995 if (voltd_state->enabled)
996 out->config = SCMI_VOLTD_CONFIG_ON;
997 else
998 out->config = SCMI_VOLTD_CONFIG_OFF;
999
1000 out->status = SCMI_SUCCESS;
1001 }
1002
1003 return 0;
1004}
1005
1006static int sandbox_scmi_voltd_level_set(struct udevice *dev,
1007 struct scmi_msg *msg)
1008{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001009 struct scmi_voltd_level_set_in *in = NULL;
1010 struct scmi_voltd_level_set_out *out = NULL;
1011 struct sandbox_scmi_voltd *voltd_state = NULL;
1012
1013 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
1014 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
1015 return -EINVAL;
1016
1017 in = (struct scmi_voltd_level_set_in *)msg->in_msg;
1018 out = (struct scmi_voltd_level_set_out *)msg->out_msg;
1019
Etienne Carriere09665cb2022-02-21 09:22:39 +01001020 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001021 if (!voltd_state) {
1022 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1023
1024 out->status = SCMI_NOT_FOUND;
1025 } else {
1026 voltd_state->voltage_uv = in->voltage_level;
1027 out->status = SCMI_SUCCESS;
1028 }
1029
1030 return 0;
1031}
1032
1033static int sandbox_scmi_voltd_level_get(struct udevice *dev,
1034 struct scmi_msg *msg)
1035{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001036 struct scmi_voltd_level_get_in *in = NULL;
1037 struct scmi_voltd_level_get_out *out = NULL;
1038 struct sandbox_scmi_voltd *voltd_state = NULL;
1039
1040 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
1041 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
1042 return -EINVAL;
1043
1044 in = (struct scmi_voltd_level_get_in *)msg->in_msg;
1045 out = (struct scmi_voltd_level_get_out *)msg->out_msg;
1046
Etienne Carriere09665cb2022-02-21 09:22:39 +01001047 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001048 if (!voltd_state) {
1049 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
1050
1051 out->status = SCMI_NOT_FOUND;
1052 } else {
1053 out->voltage_level = voltd_state->voltage_uv;
1054 out->status = SCMI_SUCCESS;
1055 }
1056
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001057 return 0;
1058}
1059
1060/**
1061 * sandbox_scmi_of_get_channel - assigne a channel
1062 * @dev: SCMI agent device
1063 * @protocol: SCMI protocol device
1064 * @channel: Pointer to channel info
1065 *
1066 * Assign a channel for the protocol, @protocol, in @channel,
1067 * based on a device tree's property.
1068 *
1069 * Return: 0 on success, error code on failure
1070 */
1071static int sandbox_scmi_of_get_channel(struct udevice *dev,
1072 struct udevice *protocol,
1073 struct scmi_channel **channel)
1074{
1075 struct sandbox_channel *agent_chan = dev_get_plat(dev);
1076 struct sandbox_channel *chan;
1077 u32 channel_id;
1078
1079 if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
1080 /* Uses agent channel */
1081 *channel = container_of(agent_chan, struct scmi_channel, ref);
1082
1083 return 0;
1084 }
1085
1086 /* Setup a dedicated channel */
1087 chan = calloc(1, sizeof(*chan));
1088 if (!chan)
1089 return -ENOMEM;
1090
1091 chan->channel_id = channel_id;
1092
1093 *channel = container_of(chan, struct scmi_channel, ref);
1094
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001095 return 0;
1096}
1097
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001098/**
1099 * sandbox_scmi_of_to_plat - assigne a channel to agent
1100 * @dev: SCMI agent device
1101 *
1102 * Assign a channel for the agent, @protocol.
1103 *
1104 * Return: always 0
1105 */
1106static int sandbox_scmi_of_to_plat(struct udevice *dev)
1107{
1108 struct sandbox_channel *chan = dev_get_plat(dev);
1109
1110 /* The channel for agent is always 0 */
1111 chan->channel_id = 0;
1112
1113 return 0;
1114}
1115
1116unsigned int sandbox_scmi_channel_id(struct udevice *dev)
1117{
1118 struct scmi_agent_proto_priv *priv;
1119 struct sandbox_channel *chan;
1120
1121 priv = dev_get_parent_priv(dev);
1122 chan = (struct sandbox_channel *)&priv->channel->ref;
1123
1124 return chan->channel_id;
1125}
1126
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001127static int sandbox_proto_not_supported(struct scmi_msg *msg)
1128{
1129 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
1130
1131 return 0;
1132}
1133
Etienne Carriere02fd1262020-09-09 18:44:00 +02001134static int sandbox_scmi_test_process_msg(struct udevice *dev,
Etienne Carriere05440292022-05-31 18:09:19 +02001135 struct scmi_channel *channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001136 struct scmi_msg *msg)
1137{
1138 switch (msg->protocol_id) {
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +09001139 case SCMI_PROTOCOL_ID_BASE:
1140 switch (msg->message_id) {
1141 case SCMI_PROTOCOL_VERSION:
1142 return sandbox_scmi_base_protocol_version(dev, msg);
1143 case SCMI_PROTOCOL_ATTRIBUTES:
1144 return sandbox_scmi_base_protocol_attrs(dev, msg);
1145 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
1146 return sandbox_scmi_base_message_attrs(dev, msg);
1147 case SCMI_BASE_DISCOVER_VENDOR:
1148 return sandbox_scmi_base_discover_vendor(dev, msg);
1149 case SCMI_BASE_DISCOVER_SUB_VENDOR:
1150 return sandbox_scmi_base_discover_sub_vendor(dev, msg);
1151 case SCMI_BASE_DISCOVER_IMPL_VERSION:
1152 return sandbox_scmi_base_discover_impl_version(dev, msg);
1153 case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
1154 return sandbox_scmi_base_discover_list_protocols(dev, msg);
1155 case SCMI_BASE_DISCOVER_AGENT:
1156 return sandbox_scmi_base_discover_agent(dev, msg);
1157 case SCMI_BASE_NOTIFY_ERRORS:
1158 break;
1159 case SCMI_BASE_SET_DEVICE_PERMISSIONS:
1160 return sandbox_scmi_base_set_device_permissions(dev, msg);
1161 case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
1162 return sandbox_scmi_base_set_protocol_permissions(dev, msg);
1163 case SCMI_BASE_RESET_AGENT_CONFIGURATION:
1164 return sandbox_scmi_base_reset_agent_configuration(dev, msg);
1165 default:
1166 break;
1167 }
1168 break;
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001169 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001170 if (!CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN))
1171 return sandbox_proto_not_supported(msg);
1172
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001173 switch (msg->message_id) {
1174 case SCMI_PROTOCOL_VERSION:
1175 return sandbox_scmi_pwd_protocol_version(dev, msg);
1176 case SCMI_PROTOCOL_ATTRIBUTES:
1177 return sandbox_scmi_pwd_protocol_attribs(dev, msg);
1178 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
1179 return sandbox_scmi_pwd_protocol_msg_attribs(dev, msg);
1180 case SCMI_PWD_ATTRIBUTES:
1181 return sandbox_scmi_pwd_attribs(dev, msg);
1182 case SCMI_PWD_STATE_SET:
1183 return sandbox_scmi_pwd_state_set(dev, msg);
1184 case SCMI_PWD_STATE_GET:
1185 return sandbox_scmi_pwd_state_get(dev, msg);
1186 case SCMI_PWD_NAME_GET:
1187 return sandbox_scmi_pwd_name_get(dev, msg);
1188 default:
1189 break;
1190 }
1191 break;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001192 case SCMI_PROTOCOL_ID_CLOCK:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001193 if (!CONFIG_IS_ENABLED(CLK_SCMI))
1194 return sandbox_proto_not_supported(msg);
1195
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001196 switch (msg->message_id) {
Etienne Carriere4c4ec902022-02-21 09:22:42 +01001197 case SCMI_PROTOCOL_ATTRIBUTES:
1198 return sandbox_scmi_clock_protocol_attribs(dev, msg);
1199 case SCMI_CLOCK_ATTRIBUTES:
1200 return sandbox_scmi_clock_attribs(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +02001201 case SCMI_CLOCK_RATE_SET:
1202 return sandbox_scmi_clock_rate_set(dev, msg);
1203 case SCMI_CLOCK_RATE_GET:
1204 return sandbox_scmi_clock_rate_get(dev, msg);
1205 case SCMI_CLOCK_CONFIG_SET:
1206 return sandbox_scmi_clock_gate(dev, msg);
1207 default:
1208 break;
1209 }
1210 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +02001211 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001212 if (!CONFIG_IS_ENABLED(RESET_SCMI))
1213 return sandbox_proto_not_supported(msg);
1214
Etienne Carriere8b9b6892020-09-09 18:44:07 +02001215 switch (msg->message_id) {
1216 case SCMI_RESET_DOMAIN_ATTRIBUTES:
1217 return sandbox_scmi_rd_attribs(dev, msg);
1218 case SCMI_RESET_DOMAIN_RESET:
1219 return sandbox_scmi_rd_reset(dev, msg);
1220 default:
1221 break;
1222 }
1223 break;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001224 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001225 if (!CONFIG_IS_ENABLED(DM_REGULATOR_SCMI))
1226 return sandbox_proto_not_supported(msg);
1227
Etienne Carriereb8f15cd2021-03-08 22:38:07 +01001228 switch (msg->message_id) {
1229 case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
1230 return sandbox_scmi_voltd_attribs(dev, msg);
1231 case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
1232 return sandbox_scmi_voltd_config_set(dev, msg);
1233 case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
1234 return sandbox_scmi_voltd_config_get(dev, msg);
1235 case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
1236 return sandbox_scmi_voltd_level_set(dev, msg);
1237 case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
1238 return sandbox_scmi_voltd_level_get(dev, msg);
1239 default:
1240 break;
1241 }
1242 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +02001243 case SCMI_PROTOCOL_ID_SYSTEM:
1244 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +02001245 case SCMI_PROTOCOL_ID_SENSOR:
AKASHI Takahiro59171ff2023-11-14 11:14:25 +09001246 return sandbox_proto_not_supported(msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +02001247 default:
1248 break;
1249 }
1250
1251 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
1252 __func__, dev->name, msg->protocol_id, msg->message_id);
1253
1254 if (msg->out_msg_sz < sizeof(u32))
1255 return -EINVAL;
1256
1257 /* Intentionnaly report unhandled IDs through the SCMI return code */
1258 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
1259 return 0;
1260}
1261
1262static int sandbox_scmi_test_remove(struct udevice *dev)
1263{
Etienne Carriere02fd1262020-09-09 18:44:00 +02001264 debug_print_agent_state(dev, "removed");
1265
Etienne Carriere02fd1262020-09-09 18:44:00 +02001266 return 0;
1267}
1268
1269static int sandbox_scmi_test_probe(struct udevice *dev)
1270{
Etienne Carriere02fd1262020-09-09 18:44:00 +02001271 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +02001272
Etienne Carriere09665cb2022-02-21 09:22:39 +01001273 *agent = (struct sandbox_scmi_agent){
AKASHI Takahiro535a7bd2023-10-16 14:39:45 +09001274 .pwdom_version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION,
1275 .pwdom = scmi_pwdom,
1276 .pwdom_count = ARRAY_SIZE(scmi_pwdom),
Etienne Carriere09665cb2022-02-21 09:22:39 +01001277 .clk = scmi_clk,
1278 .clk_count = ARRAY_SIZE(scmi_clk),
1279 .reset = scmi_reset,
1280 .reset_count = ARRAY_SIZE(scmi_reset),
1281 .voltd = scmi_voltd,
1282 .voltd_count = ARRAY_SIZE(scmi_voltd),
1283 };
Etienne Carriere02fd1262020-09-09 18:44:00 +02001284
1285 debug_print_agent_state(dev, "probed");
1286
Etienne Carriere02fd1262020-09-09 18:44:00 +02001287 return 0;
1288};
1289
1290static const struct udevice_id sandbox_scmi_test_ids[] = {
1291 { .compatible = "sandbox,scmi-agent" },
1292 { }
1293};
1294
1295struct scmi_agent_ops sandbox_scmi_test_ops = {
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001296 .of_get_channel = sandbox_scmi_of_get_channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001297 .process_msg = sandbox_scmi_test_process_msg,
1298};
1299
1300U_BOOT_DRIVER(sandbox_scmi_agent) = {
1301 .name = "sandbox-scmi_agent",
1302 .id = UCLASS_SCMI_AGENT,
1303 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001304 .priv_auto = sizeof(struct sandbox_scmi_agent),
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001305 .plat_auto = sizeof(struct sandbox_channel),
1306 .of_to_plat = sandbox_scmi_of_to_plat,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001307 .probe = sandbox_scmi_test_probe,
1308 .remove = sandbox_scmi_test_remove,
1309 .ops = &sandbox_scmi_test_ops,
1310};