blob: eb567dd900d7ae220238a0ea3787d9bf7be1be2e [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 Takahiro6221bf72023-10-11 19:06:56 +090046/**
47 * struct sandbox_channel - Description of sandbox transport
48 * @channel_id: Channel identifier
49 *
50 * Dummy channel. This will be used to test if a protocol-specific
51 * channel is properly used.
52 * Id 0 means a channel for the sandbox agent.
53 */
54struct sandbox_channel {
55 unsigned int channel_id;
56};
57
58/**
59 * struct scmi_channel - Channel instance referenced in SCMI drivers
60 * @ref: Reference to local channel instance
61 **/
62struct scmi_channel {
63 struct sandbox_channel ref;
64};
65
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +090066static u8 protocols[] = {
67 SCMI_PROTOCOL_ID_CLOCK,
68 SCMI_PROTOCOL_ID_RESET_DOMAIN,
69 SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
70};
71
72#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
73
Etienne Carriere09665cb2022-02-21 09:22:39 +010074static struct sandbox_scmi_clk scmi_clk[] = {
Etienne Carrierebf1f1322022-02-21 09:22:41 +010075 { .rate = 333 },
76 { .rate = 200 },
77 { .rate = 1000 },
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020078};
79
Etienne Carriere09665cb2022-02-21 09:22:39 +010080static struct sandbox_scmi_reset scmi_reset[] = {
Etienne Carriere8b9b6892020-09-09 18:44:07 +020081 { .id = 3 },
82};
83
Etienne Carriere09665cb2022-02-21 09:22:39 +010084static struct sandbox_scmi_voltd scmi_voltd[] = {
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010085 { .id = 0, .voltage_uv = 3300000 },
86 { .id = 1, .voltage_uv = 1800000 },
87};
88
AKASHI Takahirodae00462023-10-11 19:07:03 +090089struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
Etienne Carriere02fd1262020-09-09 18:44:00 +020090{
AKASHI Takahirodae00462023-10-11 19:07:03 +090091 return dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +020092}
93
94static void debug_print_agent_state(struct udevice *dev, char *str)
95{
96 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
97
Etienne Carriere09665cb2022-02-21 09:22:39 +010098 dev_dbg(dev, "Dump sandbox_scmi_agent: %s\n", str);
99 dev_dbg(dev, " scmi_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200100 agent->clk_count,
101 agent->clk_count ? agent->clk[0].enabled : -1,
102 agent->clk_count ? agent->clk[0].rate : -1,
103 agent->clk_count > 1 ? agent->clk[1].enabled : -1,
104 agent->clk_count > 1 ? agent->clk[1].rate : -1,
105 agent->clk_count > 2 ? agent->clk[2].enabled : -1,
106 agent->clk_count > 2 ? agent->clk[2].rate : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100107 dev_dbg(dev, " scmi_reset (%zu): %d, %d, ...\n",
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200108 agent->reset_count,
109 agent->reset_count ? agent->reset[0].asserted : -1,
110 agent->reset_count > 1 ? agent->reset[1].asserted : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100111 dev_dbg(dev, " scmi_voltd (%zu): %u/%d, %u/%d, ...\n",
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100112 agent->voltd_count,
113 agent->voltd_count ? agent->voltd[0].enabled : -1,
114 agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
115 agent->voltd_count ? agent->voltd[1].enabled : -1,
116 agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200117};
118
Etienne Carriere09665cb2022-02-21 09:22:39 +0100119static struct sandbox_scmi_clk *get_scmi_clk_state(uint clock_id)
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200120{
Etienne Carrierebf1f1322022-02-21 09:22:41 +0100121 if (clock_id < ARRAY_SIZE(scmi_clk))
122 return scmi_clk + clock_id;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200123
124 return NULL;
125}
126
Etienne Carriere09665cb2022-02-21 09:22:39 +0100127static struct sandbox_scmi_reset *get_scmi_reset_state(uint reset_id)
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200128{
129 size_t n;
130
Etienne Carriere09665cb2022-02-21 09:22:39 +0100131 for (n = 0; n < ARRAY_SIZE(scmi_reset); n++)
132 if (scmi_reset[n].id == reset_id)
133 return scmi_reset + n;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200134
135 return NULL;
136}
137
Etienne Carriere09665cb2022-02-21 09:22:39 +0100138static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100139{
140 size_t n;
141
Etienne Carriere09665cb2022-02-21 09:22:39 +0100142 for (n = 0; n < ARRAY_SIZE(scmi_voltd); n++)
143 if (scmi_voltd[n].id == domain_id)
144 return scmi_voltd + n;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100145
146 return NULL;
147}
148
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200149/*
150 * Sandbox SCMI agent ops
151 */
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900152
153/* Base Protocol */
154
155/**
156 * sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
157 * @dev: SCMI device
158 * @msg: SCMI message
159 *
160 * Implement SCMI_BASE_PROTOCOL_VERSION command.
161 */
162static int sandbox_scmi_base_protocol_version(struct udevice *dev,
163 struct scmi_msg *msg)
164{
165 struct scmi_protocol_version_out *out = NULL;
166
167 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
168 return -EINVAL;
169
170 out = (struct scmi_protocol_version_out *)msg->out_msg;
171 out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION;
172 out->status = SCMI_SUCCESS;
173
174 return 0;
175}
176
177/**
178 * sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
179 * @dev: SCMI device
180 * @msg: SCMI message
181 *
182 * Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
183 */
184static int sandbox_scmi_base_protocol_attrs(struct udevice *dev,
185 struct scmi_msg *msg)
186{
187 struct scmi_protocol_attrs_out *out = NULL;
188
189 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
190 return -EINVAL;
191
192 out = (struct scmi_protocol_attrs_out *)msg->out_msg;
193 out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS;
194 out->status = SCMI_SUCCESS;
195
196 return 0;
197}
198
199/**
200 * sandbox_scmi_base_message_attrs - implement
201 * SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
202 * @dev: SCMI device
203 * @msg: SCMI message
204 *
205 * Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
206 */
207static int sandbox_scmi_base_message_attrs(struct udevice *dev,
208 struct scmi_msg *msg)
209{
210 u32 message_id;
211 struct scmi_protocol_msg_attrs_out *out = NULL;
212
213 if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
214 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
215 return -EINVAL;
216
217 message_id = *(u32 *)msg->in_msg;
218 out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg;
219
220 if (message_id >= SCMI_PROTOCOL_VERSION &&
221 message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION &&
222 message_id != SCMI_BASE_NOTIFY_ERRORS) {
223 out->attributes = 0;
224 out->status = SCMI_SUCCESS;
225 } else {
226 out->status = SCMI_NOT_FOUND;
227 }
228
229 return 0;
230}
231
232/**
233 * sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
234 * @dev: SCMI device
235 * @msg: SCMI message
236 *
237 * Implement SCMI_BASE_DISCOVER_VENDOR command
238 */
239static int sandbox_scmi_base_discover_vendor(struct udevice *dev,
240 struct scmi_msg *msg)
241{
242 struct scmi_base_discover_vendor_out *out = NULL;
243
244 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
245 return -EINVAL;
246
247 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
248 strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR);
249 out->status = SCMI_SUCCESS;
250
251 return 0;
252}
253
254/**
255 * sandbox_scmi_base_discover_sub_vendor - implement
256 * SCMI_BASE_DISCOVER_SUB_VENDOR
257 * @dev: SCMI device
258 * @msg: SCMI message
259 *
260 * Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
261 */
262static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev,
263 struct scmi_msg *msg)
264{
265 struct scmi_base_discover_vendor_out *out = NULL;
266
267 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
268 return -EINVAL;
269
270 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
271 strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR);
272 out->status = SCMI_SUCCESS;
273
274 return 0;
275}
276
277/**
278 * sandbox_scmi_base_discover_impl_version - implement
279 * SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
280 * @dev: SCMI device
281 * @msg: SCMI message
282 *
283 * Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
284 */
285static int sandbox_scmi_base_discover_impl_version(struct udevice *dev,
286 struct scmi_msg *msg)
287{
288 struct scmi_base_discover_impl_version_out *out = NULL;
289
290 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
291 return -EINVAL;
292
293 out = (struct scmi_base_discover_impl_version_out *)msg->out_msg;
294 out->impl_version = SANDBOX_SCMI_IMPL_VERSION;
295 out->status = SCMI_SUCCESS;
296
297 return 0;
298}
299
300/**
301 * sandbox_scmi_base_discover_list_protocols - implement
302 * SCMI_BASE_DISCOVER_LIST_PROTOCOLS
303 * @dev: SCMI device
304 * @msg: SCMI message
305 *
306 * Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
307 */
308static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev,
309 struct scmi_msg *msg)
310{
311 struct scmi_base_discover_list_protocols_out *out = NULL;
312
313 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
314 return -EINVAL;
315
316 out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg;
317 memcpy(out->protocols, protocols, sizeof(protocols));
318 out->num_protocols = NUM_PROTOCOLS;
319 out->status = SCMI_SUCCESS;
320
321 return 0;
322}
323
324/**
325 * sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
326 * @dev: SCMI device
327 * @msg: SCMI message
328 *
329 * Implement SCMI_BASE_DISCOVER_AGENT command
330 */
331static int sandbox_scmi_base_discover_agent(struct udevice *dev,
332 struct scmi_msg *msg)
333{
334 u32 agent_id;
335 struct scmi_base_discover_agent_out *out = NULL;
336
337 if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) ||
338 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
339 return -EINVAL;
340
341 agent_id = *(u32 *)msg->in_msg;
342 out = (struct scmi_base_discover_agent_out *)msg->out_msg;
343 out->status = SCMI_SUCCESS;
344 if (agent_id == 0xffffffff || agent_id == 1) {
345 out->agent_id = 1;
346 strcpy(out->name, SANDBOX_SCMI_AGENT_NAME);
347 } else if (!agent_id) {
348 out->agent_id = agent_id;
349 strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME);
350 } else {
351 out->status = SCMI_NOT_FOUND;
352 }
353
354 return 0;
355}
356
357/**
358 * sandbox_scmi_base_set_device_permissions - implement
359 * SCMI_BASE_SET_DEVICE_PERMISSIONS
360 * @dev: SCMI device
361 * @msg: SCMI message
362 *
363 * Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
364 */
365static int sandbox_scmi_base_set_device_permissions(struct udevice *dev,
366 struct scmi_msg *msg)
367{
368 struct scmi_base_set_device_permissions_in *in = NULL;
369 u32 *status;
370
371 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
372 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
373 return -EINVAL;
374
375 in = (struct scmi_base_set_device_permissions_in *)msg->in_msg;
376 status = (u32 *)msg->out_msg;
377
378 if (in->agent_id != 1 || in->device_id != 0)
379 *status = SCMI_NOT_FOUND;
380 else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
381 *status = SCMI_INVALID_PARAMETERS;
382 else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
383 *status = SCMI_SUCCESS;
384 else
385 /* unset not allowed */
386 *status = SCMI_DENIED;
387
388 return 0;
389}
390
391/**
392 * sandbox_scmi_base_set_protocol_permissions - implement
393 * SCMI_BASE_SET_PROTOCOL_PERMISSIONS
394 * @dev: SCMI device
395 * @msg: SCMI message
396 *
397 * Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
398 */
399static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev,
400 struct scmi_msg *msg)
401{
402 struct scmi_base_set_protocol_permissions_in *in = NULL;
403 u32 *status;
404 int i;
405
406 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
407 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
408 return -EINVAL;
409
410 in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg;
411 status = (u32 *)msg->out_msg;
412
413 for (i = 0; i < ARRAY_SIZE(protocols); i++)
414 if (protocols[i] == in->command_id)
415 break;
416 if (in->agent_id != 1 || in->device_id != 0 ||
417 i == ARRAY_SIZE(protocols))
418 *status = SCMI_NOT_FOUND;
419 else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
420 *status = SCMI_INVALID_PARAMETERS;
421 else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
422 *status = SCMI_SUCCESS;
423 else
424 /* unset not allowed */
425 *status = SCMI_DENIED;
426
427 return 0;
428}
429
430/**
431 * sandbox_scmi_base_reset_agent_configuration - implement
432 * SCMI_BASE_RESET_AGENT_CONFIGURATION
433 * @dev: SCMI device
434 * @msg: SCMI message
435 *
436 * Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
437 */
438static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
439 struct scmi_msg *msg)
440{
441 struct scmi_base_reset_agent_configuration_in *in = NULL;
442 u32 *status;
443
444 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
445 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
446 return -EINVAL;
447
448 in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg;
449 status = (u32 *)msg->out_msg;
450
451 if (in->agent_id != 1)
452 *status = SCMI_NOT_FOUND;
453 else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS)
454 *status = SCMI_INVALID_PARAMETERS;
455 else
456 *status = SCMI_DENIED;
457
458 return 0;
459}
460
461/* Clock Protocol */
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200462
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100463static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
464 struct scmi_msg *msg)
465{
466 struct scmi_clk_protocol_attr_out *out = NULL;
467
468 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
469 return -EINVAL;
470
471 out = (struct scmi_clk_protocol_attr_out *)msg->out_msg;
472 out->attributes = ARRAY_SIZE(scmi_clk);
473 out->status = SCMI_SUCCESS;
474
475 return 0;
476}
477
478static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
479{
480 struct scmi_clk_attribute_in *in = NULL;
481 struct scmi_clk_attribute_out *out = NULL;
482 struct sandbox_scmi_clk *clk_state = NULL;
483 int ret;
484
485 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
486 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
487 return -EINVAL;
488
489 in = (struct scmi_clk_attribute_in *)msg->in_msg;
490 out = (struct scmi_clk_attribute_out *)msg->out_msg;
491
492 clk_state = get_scmi_clk_state(in->clock_id);
493 if (!clk_state) {
494 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
495
496 out->status = SCMI_NOT_FOUND;
497 } else {
498 memset(out, 0, sizeof(*out));
499
500 if (clk_state->enabled)
501 out->attributes = 1;
502
503 ret = snprintf(out->clock_name, sizeof(out->clock_name),
504 "clk%u", in->clock_id);
505 assert(ret > 0 && ret < sizeof(out->clock_name));
506
507 out->status = SCMI_SUCCESS;
508 }
509
510 return 0;
511}
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200512static int sandbox_scmi_clock_rate_set(struct udevice *dev,
513 struct scmi_msg *msg)
514{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200515 struct scmi_clk_rate_set_in *in = NULL;
516 struct scmi_clk_rate_set_out *out = NULL;
517 struct sandbox_scmi_clk *clk_state = NULL;
518
519 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
520 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
521 return -EINVAL;
522
523 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
524 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
525
Etienne Carriere09665cb2022-02-21 09:22:39 +0100526 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200527 if (!clk_state) {
528 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
529
530 out->status = SCMI_NOT_FOUND;
531 } else {
532 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
533
534 clk_state->rate = (ulong)rate;
535
536 out->status = SCMI_SUCCESS;
537 }
538
539 return 0;
540}
541
542static int sandbox_scmi_clock_rate_get(struct udevice *dev,
543 struct scmi_msg *msg)
544{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200545 struct scmi_clk_rate_get_in *in = NULL;
546 struct scmi_clk_rate_get_out *out = NULL;
547 struct sandbox_scmi_clk *clk_state = NULL;
548
549 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
550 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
551 return -EINVAL;
552
553 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
554 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
555
Etienne Carriere09665cb2022-02-21 09:22:39 +0100556 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200557 if (!clk_state) {
558 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
559
560 out->status = SCMI_NOT_FOUND;
561 } else {
562 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
563 out->rate_lsb = (u32)clk_state->rate;
564
565 out->status = SCMI_SUCCESS;
566 }
567
568 return 0;
569}
570
571static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
572{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200573 struct scmi_clk_state_in *in = NULL;
574 struct scmi_clk_state_out *out = NULL;
575 struct sandbox_scmi_clk *clk_state = NULL;
576
577 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
578 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
579 return -EINVAL;
580
581 in = (struct scmi_clk_state_in *)msg->in_msg;
582 out = (struct scmi_clk_state_out *)msg->out_msg;
583
Etienne Carriere09665cb2022-02-21 09:22:39 +0100584 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200585 if (!clk_state) {
586 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
587
588 out->status = SCMI_NOT_FOUND;
589 } else if (in->attributes > 1) {
590 out->status = SCMI_PROTOCOL_ERROR;
591 } else {
592 clk_state->enabled = in->attributes;
593
594 out->status = SCMI_SUCCESS;
595 }
596
597 return 0;
598}
599
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200600static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
601{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200602 struct scmi_rd_attr_in *in = NULL;
603 struct scmi_rd_attr_out *out = NULL;
604 struct sandbox_scmi_reset *reset_state = NULL;
605
606 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
607 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
608 return -EINVAL;
609
610 in = (struct scmi_rd_attr_in *)msg->in_msg;
611 out = (struct scmi_rd_attr_out *)msg->out_msg;
612
Etienne Carriere09665cb2022-02-21 09:22:39 +0100613 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200614 if (!reset_state) {
615 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
616
617 out->status = SCMI_NOT_FOUND;
618 } else {
619 memset(out, 0, sizeof(*out));
620 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
621
622 out->status = SCMI_SUCCESS;
623 }
624
625 return 0;
626}
627
628static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
629{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200630 struct scmi_rd_reset_in *in = NULL;
631 struct scmi_rd_reset_out *out = NULL;
632 struct sandbox_scmi_reset *reset_state = NULL;
633
634 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
635 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
636 return -EINVAL;
637
638 in = (struct scmi_rd_reset_in *)msg->in_msg;
639 out = (struct scmi_rd_reset_out *)msg->out_msg;
640
Etienne Carriere09665cb2022-02-21 09:22:39 +0100641 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200642 if (!reset_state) {
643 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
644
645 out->status = SCMI_NOT_FOUND;
646 } else if (in->reset_state > 1) {
647 dev_err(dev, "Invalid reset domain input attribute value\n");
648
649 out->status = SCMI_INVALID_PARAMETERS;
650 } else {
651 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
652 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
653 out->status = SCMI_NOT_SUPPORTED;
654 } else {
655 /* Ends deasserted whatever current state */
656 reset_state->asserted = false;
657 out->status = SCMI_SUCCESS;
658 }
659 } else {
660 reset_state->asserted = in->flags &
661 SCMI_RD_RESET_FLAG_ASSERT;
662
663 out->status = SCMI_SUCCESS;
664 }
665 }
666
667 return 0;
668}
669
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100670static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
671{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100672 struct scmi_voltd_attr_in *in = NULL;
673 struct scmi_voltd_attr_out *out = NULL;
674 struct sandbox_scmi_voltd *voltd_state = NULL;
675
676 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
677 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
678 return -EINVAL;
679
680 in = (struct scmi_voltd_attr_in *)msg->in_msg;
681 out = (struct scmi_voltd_attr_out *)msg->out_msg;
682
Etienne Carriere09665cb2022-02-21 09:22:39 +0100683 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100684 if (!voltd_state) {
685 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
686
687 out->status = SCMI_NOT_FOUND;
688 } else {
689 memset(out, 0, sizeof(*out));
690 snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
691
692 out->status = SCMI_SUCCESS;
693 }
694
695 return 0;
696}
697
698static int sandbox_scmi_voltd_config_set(struct udevice *dev,
699 struct scmi_msg *msg)
700{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100701 struct scmi_voltd_config_set_in *in = NULL;
702 struct scmi_voltd_config_set_out *out = NULL;
703 struct sandbox_scmi_voltd *voltd_state = NULL;
704
705 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
706 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
707 return -EINVAL;
708
709 in = (struct scmi_voltd_config_set_in *)msg->in_msg;
710 out = (struct scmi_voltd_config_set_out *)msg->out_msg;
711
Etienne Carriere09665cb2022-02-21 09:22:39 +0100712 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100713 if (!voltd_state) {
714 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
715
716 out->status = SCMI_NOT_FOUND;
717 } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
718 dev_err(dev, "Invalid config value 0x%x\n", in->config);
719
720 out->status = SCMI_INVALID_PARAMETERS;
721 } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
722 in->config != SCMI_VOLTD_CONFIG_OFF) {
723 dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
724
725 out->status = SCMI_INVALID_PARAMETERS;
726 } else {
727 voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
728 out->status = SCMI_SUCCESS;
729 }
730
731 return 0;
732}
733
734static int sandbox_scmi_voltd_config_get(struct udevice *dev,
735 struct scmi_msg *msg)
736{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100737 struct scmi_voltd_config_get_in *in = NULL;
738 struct scmi_voltd_config_get_out *out = NULL;
739 struct sandbox_scmi_voltd *voltd_state = NULL;
740
741 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
742 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
743 return -EINVAL;
744
745 in = (struct scmi_voltd_config_get_in *)msg->in_msg;
746 out = (struct scmi_voltd_config_get_out *)msg->out_msg;
747
Etienne Carriere09665cb2022-02-21 09:22:39 +0100748 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100749 if (!voltd_state) {
750 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
751
752 out->status = SCMI_NOT_FOUND;
753 } else {
754 if (voltd_state->enabled)
755 out->config = SCMI_VOLTD_CONFIG_ON;
756 else
757 out->config = SCMI_VOLTD_CONFIG_OFF;
758
759 out->status = SCMI_SUCCESS;
760 }
761
762 return 0;
763}
764
765static int sandbox_scmi_voltd_level_set(struct udevice *dev,
766 struct scmi_msg *msg)
767{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100768 struct scmi_voltd_level_set_in *in = NULL;
769 struct scmi_voltd_level_set_out *out = NULL;
770 struct sandbox_scmi_voltd *voltd_state = NULL;
771
772 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
773 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
774 return -EINVAL;
775
776 in = (struct scmi_voltd_level_set_in *)msg->in_msg;
777 out = (struct scmi_voltd_level_set_out *)msg->out_msg;
778
Etienne Carriere09665cb2022-02-21 09:22:39 +0100779 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100780 if (!voltd_state) {
781 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
782
783 out->status = SCMI_NOT_FOUND;
784 } else {
785 voltd_state->voltage_uv = in->voltage_level;
786 out->status = SCMI_SUCCESS;
787 }
788
789 return 0;
790}
791
792static int sandbox_scmi_voltd_level_get(struct udevice *dev,
793 struct scmi_msg *msg)
794{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100795 struct scmi_voltd_level_get_in *in = NULL;
796 struct scmi_voltd_level_get_out *out = NULL;
797 struct sandbox_scmi_voltd *voltd_state = NULL;
798
799 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
800 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
801 return -EINVAL;
802
803 in = (struct scmi_voltd_level_get_in *)msg->in_msg;
804 out = (struct scmi_voltd_level_get_out *)msg->out_msg;
805
Etienne Carriere09665cb2022-02-21 09:22:39 +0100806 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100807 if (!voltd_state) {
808 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
809
810 out->status = SCMI_NOT_FOUND;
811 } else {
812 out->voltage_level = voltd_state->voltage_uv;
813 out->status = SCMI_SUCCESS;
814 }
815
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900816 return 0;
817}
818
819/**
820 * sandbox_scmi_of_get_channel - assigne a channel
821 * @dev: SCMI agent device
822 * @protocol: SCMI protocol device
823 * @channel: Pointer to channel info
824 *
825 * Assign a channel for the protocol, @protocol, in @channel,
826 * based on a device tree's property.
827 *
828 * Return: 0 on success, error code on failure
829 */
830static int sandbox_scmi_of_get_channel(struct udevice *dev,
831 struct udevice *protocol,
832 struct scmi_channel **channel)
833{
834 struct sandbox_channel *agent_chan = dev_get_plat(dev);
835 struct sandbox_channel *chan;
836 u32 channel_id;
837
838 if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
839 /* Uses agent channel */
840 *channel = container_of(agent_chan, struct scmi_channel, ref);
841
842 return 0;
843 }
844
845 /* Setup a dedicated channel */
846 chan = calloc(1, sizeof(*chan));
847 if (!chan)
848 return -ENOMEM;
849
850 chan->channel_id = channel_id;
851
852 *channel = container_of(chan, struct scmi_channel, ref);
853
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100854 return 0;
855}
856
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900857/**
858 * sandbox_scmi_of_to_plat - assigne a channel to agent
859 * @dev: SCMI agent device
860 *
861 * Assign a channel for the agent, @protocol.
862 *
863 * Return: always 0
864 */
865static int sandbox_scmi_of_to_plat(struct udevice *dev)
866{
867 struct sandbox_channel *chan = dev_get_plat(dev);
868
869 /* The channel for agent is always 0 */
870 chan->channel_id = 0;
871
872 return 0;
873}
874
875unsigned int sandbox_scmi_channel_id(struct udevice *dev)
876{
877 struct scmi_agent_proto_priv *priv;
878 struct sandbox_channel *chan;
879
880 priv = dev_get_parent_priv(dev);
881 chan = (struct sandbox_channel *)&priv->channel->ref;
882
883 return chan->channel_id;
884}
885
Etienne Carriere02fd1262020-09-09 18:44:00 +0200886static int sandbox_scmi_test_process_msg(struct udevice *dev,
Etienne Carriere05440292022-05-31 18:09:19 +0200887 struct scmi_channel *channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +0200888 struct scmi_msg *msg)
889{
890 switch (msg->protocol_id) {
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900891 case SCMI_PROTOCOL_ID_BASE:
892 switch (msg->message_id) {
893 case SCMI_PROTOCOL_VERSION:
894 return sandbox_scmi_base_protocol_version(dev, msg);
895 case SCMI_PROTOCOL_ATTRIBUTES:
896 return sandbox_scmi_base_protocol_attrs(dev, msg);
897 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
898 return sandbox_scmi_base_message_attrs(dev, msg);
899 case SCMI_BASE_DISCOVER_VENDOR:
900 return sandbox_scmi_base_discover_vendor(dev, msg);
901 case SCMI_BASE_DISCOVER_SUB_VENDOR:
902 return sandbox_scmi_base_discover_sub_vendor(dev, msg);
903 case SCMI_BASE_DISCOVER_IMPL_VERSION:
904 return sandbox_scmi_base_discover_impl_version(dev, msg);
905 case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
906 return sandbox_scmi_base_discover_list_protocols(dev, msg);
907 case SCMI_BASE_DISCOVER_AGENT:
908 return sandbox_scmi_base_discover_agent(dev, msg);
909 case SCMI_BASE_NOTIFY_ERRORS:
910 break;
911 case SCMI_BASE_SET_DEVICE_PERMISSIONS:
912 return sandbox_scmi_base_set_device_permissions(dev, msg);
913 case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
914 return sandbox_scmi_base_set_protocol_permissions(dev, msg);
915 case SCMI_BASE_RESET_AGENT_CONFIGURATION:
916 return sandbox_scmi_base_reset_agent_configuration(dev, msg);
917 default:
918 break;
919 }
920 break;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200921 case SCMI_PROTOCOL_ID_CLOCK:
922 switch (msg->message_id) {
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100923 case SCMI_PROTOCOL_ATTRIBUTES:
924 return sandbox_scmi_clock_protocol_attribs(dev, msg);
925 case SCMI_CLOCK_ATTRIBUTES:
926 return sandbox_scmi_clock_attribs(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200927 case SCMI_CLOCK_RATE_SET:
928 return sandbox_scmi_clock_rate_set(dev, msg);
929 case SCMI_CLOCK_RATE_GET:
930 return sandbox_scmi_clock_rate_get(dev, msg);
931 case SCMI_CLOCK_CONFIG_SET:
932 return sandbox_scmi_clock_gate(dev, msg);
933 default:
934 break;
935 }
936 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200937 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
938 switch (msg->message_id) {
939 case SCMI_RESET_DOMAIN_ATTRIBUTES:
940 return sandbox_scmi_rd_attribs(dev, msg);
941 case SCMI_RESET_DOMAIN_RESET:
942 return sandbox_scmi_rd_reset(dev, msg);
943 default:
944 break;
945 }
946 break;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100947 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
948 switch (msg->message_id) {
949 case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
950 return sandbox_scmi_voltd_attribs(dev, msg);
951 case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
952 return sandbox_scmi_voltd_config_set(dev, msg);
953 case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
954 return sandbox_scmi_voltd_config_get(dev, msg);
955 case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
956 return sandbox_scmi_voltd_level_set(dev, msg);
957 case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
958 return sandbox_scmi_voltd_level_get(dev, msg);
959 default:
960 break;
961 }
962 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200963 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
964 case SCMI_PROTOCOL_ID_SYSTEM:
965 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200966 case SCMI_PROTOCOL_ID_SENSOR:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200967 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
968 return 0;
969 default:
970 break;
971 }
972
973 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
974 __func__, dev->name, msg->protocol_id, msg->message_id);
975
976 if (msg->out_msg_sz < sizeof(u32))
977 return -EINVAL;
978
979 /* Intentionnaly report unhandled IDs through the SCMI return code */
980 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
981 return 0;
982}
983
984static int sandbox_scmi_test_remove(struct udevice *dev)
985{
Etienne Carriere02fd1262020-09-09 18:44:00 +0200986 debug_print_agent_state(dev, "removed");
987
Etienne Carriere02fd1262020-09-09 18:44:00 +0200988 return 0;
989}
990
991static int sandbox_scmi_test_probe(struct udevice *dev)
992{
Etienne Carriere02fd1262020-09-09 18:44:00 +0200993 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200994
Etienne Carriere09665cb2022-02-21 09:22:39 +0100995 *agent = (struct sandbox_scmi_agent){
996 .clk = scmi_clk,
997 .clk_count = ARRAY_SIZE(scmi_clk),
998 .reset = scmi_reset,
999 .reset_count = ARRAY_SIZE(scmi_reset),
1000 .voltd = scmi_voltd,
1001 .voltd_count = ARRAY_SIZE(scmi_voltd),
1002 };
Etienne Carriere02fd1262020-09-09 18:44:00 +02001003
1004 debug_print_agent_state(dev, "probed");
1005
Etienne Carriere02fd1262020-09-09 18:44:00 +02001006 return 0;
1007};
1008
1009static const struct udevice_id sandbox_scmi_test_ids[] = {
1010 { .compatible = "sandbox,scmi-agent" },
1011 { }
1012};
1013
1014struct scmi_agent_ops sandbox_scmi_test_ops = {
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001015 .of_get_channel = sandbox_scmi_of_get_channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001016 .process_msg = sandbox_scmi_test_process_msg,
1017};
1018
1019U_BOOT_DRIVER(sandbox_scmi_agent) = {
1020 .name = "sandbox-scmi_agent",
1021 .id = UCLASS_SCMI_AGENT,
1022 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001023 .priv_auto = sizeof(struct sandbox_scmi_agent),
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001024 .plat_auto = sizeof(struct sandbox_channel),
1025 .of_to_plat = sandbox_scmi_of_to_plat,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001026 .probe = sandbox_scmi_test_probe,
1027 .remove = sandbox_scmi_test_remove,
1028 .ops = &sandbox_scmi_test_ops,
1029};