blob: 716bbf97d5c99bb6db19c1037fd6505770af3b3f [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
Etienne Carriere09665cb2022-02-21 09:22:39 +010089static struct sandbox_scmi_service sandbox_scmi_service_state;
Etienne Carriere02fd1262020-09-09 18:44:00 +020090
91struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
92{
93 return &sandbox_scmi_service_state;
94}
95
96static void debug_print_agent_state(struct udevice *dev, char *str)
97{
98 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
99
Etienne Carriere09665cb2022-02-21 09:22:39 +0100100 dev_dbg(dev, "Dump sandbox_scmi_agent: %s\n", str);
101 dev_dbg(dev, " scmi_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200102 agent->clk_count,
103 agent->clk_count ? agent->clk[0].enabled : -1,
104 agent->clk_count ? agent->clk[0].rate : -1,
105 agent->clk_count > 1 ? agent->clk[1].enabled : -1,
106 agent->clk_count > 1 ? agent->clk[1].rate : -1,
107 agent->clk_count > 2 ? agent->clk[2].enabled : -1,
108 agent->clk_count > 2 ? agent->clk[2].rate : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100109 dev_dbg(dev, " scmi_reset (%zu): %d, %d, ...\n",
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200110 agent->reset_count,
111 agent->reset_count ? agent->reset[0].asserted : -1,
112 agent->reset_count > 1 ? agent->reset[1].asserted : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +0100113 dev_dbg(dev, " scmi_voltd (%zu): %u/%d, %u/%d, ...\n",
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100114 agent->voltd_count,
115 agent->voltd_count ? agent->voltd[0].enabled : -1,
116 agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
117 agent->voltd_count ? agent->voltd[1].enabled : -1,
118 agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200119};
120
Etienne Carriere09665cb2022-02-21 09:22:39 +0100121static struct sandbox_scmi_clk *get_scmi_clk_state(uint clock_id)
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200122{
Etienne Carrierebf1f1322022-02-21 09:22:41 +0100123 if (clock_id < ARRAY_SIZE(scmi_clk))
124 return scmi_clk + clock_id;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200125
126 return NULL;
127}
128
Etienne Carriere09665cb2022-02-21 09:22:39 +0100129static struct sandbox_scmi_reset *get_scmi_reset_state(uint reset_id)
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200130{
131 size_t n;
132
Etienne Carriere09665cb2022-02-21 09:22:39 +0100133 for (n = 0; n < ARRAY_SIZE(scmi_reset); n++)
134 if (scmi_reset[n].id == reset_id)
135 return scmi_reset + n;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200136
137 return NULL;
138}
139
Etienne Carriere09665cb2022-02-21 09:22:39 +0100140static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100141{
142 size_t n;
143
Etienne Carriere09665cb2022-02-21 09:22:39 +0100144 for (n = 0; n < ARRAY_SIZE(scmi_voltd); n++)
145 if (scmi_voltd[n].id == domain_id)
146 return scmi_voltd + n;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100147
148 return NULL;
149}
150
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200151/*
152 * Sandbox SCMI agent ops
153 */
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900154
155/* Base Protocol */
156
157/**
158 * sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
159 * @dev: SCMI device
160 * @msg: SCMI message
161 *
162 * Implement SCMI_BASE_PROTOCOL_VERSION command.
163 */
164static int sandbox_scmi_base_protocol_version(struct udevice *dev,
165 struct scmi_msg *msg)
166{
167 struct scmi_protocol_version_out *out = NULL;
168
169 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
170 return -EINVAL;
171
172 out = (struct scmi_protocol_version_out *)msg->out_msg;
173 out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION;
174 out->status = SCMI_SUCCESS;
175
176 return 0;
177}
178
179/**
180 * sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
181 * @dev: SCMI device
182 * @msg: SCMI message
183 *
184 * Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
185 */
186static int sandbox_scmi_base_protocol_attrs(struct udevice *dev,
187 struct scmi_msg *msg)
188{
189 struct scmi_protocol_attrs_out *out = NULL;
190
191 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
192 return -EINVAL;
193
194 out = (struct scmi_protocol_attrs_out *)msg->out_msg;
195 out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS;
196 out->status = SCMI_SUCCESS;
197
198 return 0;
199}
200
201/**
202 * sandbox_scmi_base_message_attrs - implement
203 * SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
204 * @dev: SCMI device
205 * @msg: SCMI message
206 *
207 * Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
208 */
209static int sandbox_scmi_base_message_attrs(struct udevice *dev,
210 struct scmi_msg *msg)
211{
212 u32 message_id;
213 struct scmi_protocol_msg_attrs_out *out = NULL;
214
215 if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
216 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
217 return -EINVAL;
218
219 message_id = *(u32 *)msg->in_msg;
220 out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg;
221
222 if (message_id >= SCMI_PROTOCOL_VERSION &&
223 message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION &&
224 message_id != SCMI_BASE_NOTIFY_ERRORS) {
225 out->attributes = 0;
226 out->status = SCMI_SUCCESS;
227 } else {
228 out->status = SCMI_NOT_FOUND;
229 }
230
231 return 0;
232}
233
234/**
235 * sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
236 * @dev: SCMI device
237 * @msg: SCMI message
238 *
239 * Implement SCMI_BASE_DISCOVER_VENDOR command
240 */
241static int sandbox_scmi_base_discover_vendor(struct udevice *dev,
242 struct scmi_msg *msg)
243{
244 struct scmi_base_discover_vendor_out *out = NULL;
245
246 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
247 return -EINVAL;
248
249 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
250 strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR);
251 out->status = SCMI_SUCCESS;
252
253 return 0;
254}
255
256/**
257 * sandbox_scmi_base_discover_sub_vendor - implement
258 * SCMI_BASE_DISCOVER_SUB_VENDOR
259 * @dev: SCMI device
260 * @msg: SCMI message
261 *
262 * Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
263 */
264static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev,
265 struct scmi_msg *msg)
266{
267 struct scmi_base_discover_vendor_out *out = NULL;
268
269 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
270 return -EINVAL;
271
272 out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
273 strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR);
274 out->status = SCMI_SUCCESS;
275
276 return 0;
277}
278
279/**
280 * sandbox_scmi_base_discover_impl_version - implement
281 * SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
282 * @dev: SCMI device
283 * @msg: SCMI message
284 *
285 * Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
286 */
287static int sandbox_scmi_base_discover_impl_version(struct udevice *dev,
288 struct scmi_msg *msg)
289{
290 struct scmi_base_discover_impl_version_out *out = NULL;
291
292 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
293 return -EINVAL;
294
295 out = (struct scmi_base_discover_impl_version_out *)msg->out_msg;
296 out->impl_version = SANDBOX_SCMI_IMPL_VERSION;
297 out->status = SCMI_SUCCESS;
298
299 return 0;
300}
301
302/**
303 * sandbox_scmi_base_discover_list_protocols - implement
304 * SCMI_BASE_DISCOVER_LIST_PROTOCOLS
305 * @dev: SCMI device
306 * @msg: SCMI message
307 *
308 * Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
309 */
310static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev,
311 struct scmi_msg *msg)
312{
313 struct scmi_base_discover_list_protocols_out *out = NULL;
314
315 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
316 return -EINVAL;
317
318 out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg;
319 memcpy(out->protocols, protocols, sizeof(protocols));
320 out->num_protocols = NUM_PROTOCOLS;
321 out->status = SCMI_SUCCESS;
322
323 return 0;
324}
325
326/**
327 * sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
328 * @dev: SCMI device
329 * @msg: SCMI message
330 *
331 * Implement SCMI_BASE_DISCOVER_AGENT command
332 */
333static int sandbox_scmi_base_discover_agent(struct udevice *dev,
334 struct scmi_msg *msg)
335{
336 u32 agent_id;
337 struct scmi_base_discover_agent_out *out = NULL;
338
339 if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) ||
340 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
341 return -EINVAL;
342
343 agent_id = *(u32 *)msg->in_msg;
344 out = (struct scmi_base_discover_agent_out *)msg->out_msg;
345 out->status = SCMI_SUCCESS;
346 if (agent_id == 0xffffffff || agent_id == 1) {
347 out->agent_id = 1;
348 strcpy(out->name, SANDBOX_SCMI_AGENT_NAME);
349 } else if (!agent_id) {
350 out->agent_id = agent_id;
351 strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME);
352 } else {
353 out->status = SCMI_NOT_FOUND;
354 }
355
356 return 0;
357}
358
359/**
360 * sandbox_scmi_base_set_device_permissions - implement
361 * SCMI_BASE_SET_DEVICE_PERMISSIONS
362 * @dev: SCMI device
363 * @msg: SCMI message
364 *
365 * Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
366 */
367static int sandbox_scmi_base_set_device_permissions(struct udevice *dev,
368 struct scmi_msg *msg)
369{
370 struct scmi_base_set_device_permissions_in *in = NULL;
371 u32 *status;
372
373 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
374 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
375 return -EINVAL;
376
377 in = (struct scmi_base_set_device_permissions_in *)msg->in_msg;
378 status = (u32 *)msg->out_msg;
379
380 if (in->agent_id != 1 || in->device_id != 0)
381 *status = SCMI_NOT_FOUND;
382 else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
383 *status = SCMI_INVALID_PARAMETERS;
384 else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
385 *status = SCMI_SUCCESS;
386 else
387 /* unset not allowed */
388 *status = SCMI_DENIED;
389
390 return 0;
391}
392
393/**
394 * sandbox_scmi_base_set_protocol_permissions - implement
395 * SCMI_BASE_SET_PROTOCOL_PERMISSIONS
396 * @dev: SCMI device
397 * @msg: SCMI message
398 *
399 * Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
400 */
401static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev,
402 struct scmi_msg *msg)
403{
404 struct scmi_base_set_protocol_permissions_in *in = NULL;
405 u32 *status;
406 int i;
407
408 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
409 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
410 return -EINVAL;
411
412 in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg;
413 status = (u32 *)msg->out_msg;
414
415 for (i = 0; i < ARRAY_SIZE(protocols); i++)
416 if (protocols[i] == in->command_id)
417 break;
418 if (in->agent_id != 1 || in->device_id != 0 ||
419 i == ARRAY_SIZE(protocols))
420 *status = SCMI_NOT_FOUND;
421 else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
422 *status = SCMI_INVALID_PARAMETERS;
423 else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
424 *status = SCMI_SUCCESS;
425 else
426 /* unset not allowed */
427 *status = SCMI_DENIED;
428
429 return 0;
430}
431
432/**
433 * sandbox_scmi_base_reset_agent_configuration - implement
434 * SCMI_BASE_RESET_AGENT_CONFIGURATION
435 * @dev: SCMI device
436 * @msg: SCMI message
437 *
438 * Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
439 */
440static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
441 struct scmi_msg *msg)
442{
443 struct scmi_base_reset_agent_configuration_in *in = NULL;
444 u32 *status;
445
446 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
447 !msg->out_msg || msg->out_msg_sz < sizeof(*status))
448 return -EINVAL;
449
450 in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg;
451 status = (u32 *)msg->out_msg;
452
453 if (in->agent_id != 1)
454 *status = SCMI_NOT_FOUND;
455 else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS)
456 *status = SCMI_INVALID_PARAMETERS;
457 else
458 *status = SCMI_DENIED;
459
460 return 0;
461}
462
463/* Clock Protocol */
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200464
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100465static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
466 struct scmi_msg *msg)
467{
468 struct scmi_clk_protocol_attr_out *out = NULL;
469
470 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
471 return -EINVAL;
472
473 out = (struct scmi_clk_protocol_attr_out *)msg->out_msg;
474 out->attributes = ARRAY_SIZE(scmi_clk);
475 out->status = SCMI_SUCCESS;
476
477 return 0;
478}
479
480static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
481{
482 struct scmi_clk_attribute_in *in = NULL;
483 struct scmi_clk_attribute_out *out = NULL;
484 struct sandbox_scmi_clk *clk_state = NULL;
485 int ret;
486
487 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
488 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
489 return -EINVAL;
490
491 in = (struct scmi_clk_attribute_in *)msg->in_msg;
492 out = (struct scmi_clk_attribute_out *)msg->out_msg;
493
494 clk_state = get_scmi_clk_state(in->clock_id);
495 if (!clk_state) {
496 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
497
498 out->status = SCMI_NOT_FOUND;
499 } else {
500 memset(out, 0, sizeof(*out));
501
502 if (clk_state->enabled)
503 out->attributes = 1;
504
505 ret = snprintf(out->clock_name, sizeof(out->clock_name),
506 "clk%u", in->clock_id);
507 assert(ret > 0 && ret < sizeof(out->clock_name));
508
509 out->status = SCMI_SUCCESS;
510 }
511
512 return 0;
513}
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200514static int sandbox_scmi_clock_rate_set(struct udevice *dev,
515 struct scmi_msg *msg)
516{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200517 struct scmi_clk_rate_set_in *in = NULL;
518 struct scmi_clk_rate_set_out *out = NULL;
519 struct sandbox_scmi_clk *clk_state = NULL;
520
521 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
522 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
523 return -EINVAL;
524
525 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
526 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
527
Etienne Carriere09665cb2022-02-21 09:22:39 +0100528 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200529 if (!clk_state) {
530 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
531
532 out->status = SCMI_NOT_FOUND;
533 } else {
534 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
535
536 clk_state->rate = (ulong)rate;
537
538 out->status = SCMI_SUCCESS;
539 }
540
541 return 0;
542}
543
544static int sandbox_scmi_clock_rate_get(struct udevice *dev,
545 struct scmi_msg *msg)
546{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200547 struct scmi_clk_rate_get_in *in = NULL;
548 struct scmi_clk_rate_get_out *out = NULL;
549 struct sandbox_scmi_clk *clk_state = NULL;
550
551 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
552 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
553 return -EINVAL;
554
555 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
556 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
557
Etienne Carriere09665cb2022-02-21 09:22:39 +0100558 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200559 if (!clk_state) {
560 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
561
562 out->status = SCMI_NOT_FOUND;
563 } else {
564 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
565 out->rate_lsb = (u32)clk_state->rate;
566
567 out->status = SCMI_SUCCESS;
568 }
569
570 return 0;
571}
572
573static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
574{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200575 struct scmi_clk_state_in *in = NULL;
576 struct scmi_clk_state_out *out = NULL;
577 struct sandbox_scmi_clk *clk_state = NULL;
578
579 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
580 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
581 return -EINVAL;
582
583 in = (struct scmi_clk_state_in *)msg->in_msg;
584 out = (struct scmi_clk_state_out *)msg->out_msg;
585
Etienne Carriere09665cb2022-02-21 09:22:39 +0100586 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200587 if (!clk_state) {
588 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
589
590 out->status = SCMI_NOT_FOUND;
591 } else if (in->attributes > 1) {
592 out->status = SCMI_PROTOCOL_ERROR;
593 } else {
594 clk_state->enabled = in->attributes;
595
596 out->status = SCMI_SUCCESS;
597 }
598
599 return 0;
600}
601
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200602static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
603{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200604 struct scmi_rd_attr_in *in = NULL;
605 struct scmi_rd_attr_out *out = NULL;
606 struct sandbox_scmi_reset *reset_state = NULL;
607
608 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
609 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
610 return -EINVAL;
611
612 in = (struct scmi_rd_attr_in *)msg->in_msg;
613 out = (struct scmi_rd_attr_out *)msg->out_msg;
614
Etienne Carriere09665cb2022-02-21 09:22:39 +0100615 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200616 if (!reset_state) {
617 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
618
619 out->status = SCMI_NOT_FOUND;
620 } else {
621 memset(out, 0, sizeof(*out));
622 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
623
624 out->status = SCMI_SUCCESS;
625 }
626
627 return 0;
628}
629
630static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
631{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200632 struct scmi_rd_reset_in *in = NULL;
633 struct scmi_rd_reset_out *out = NULL;
634 struct sandbox_scmi_reset *reset_state = NULL;
635
636 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
637 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
638 return -EINVAL;
639
640 in = (struct scmi_rd_reset_in *)msg->in_msg;
641 out = (struct scmi_rd_reset_out *)msg->out_msg;
642
Etienne Carriere09665cb2022-02-21 09:22:39 +0100643 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200644 if (!reset_state) {
645 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
646
647 out->status = SCMI_NOT_FOUND;
648 } else if (in->reset_state > 1) {
649 dev_err(dev, "Invalid reset domain input attribute value\n");
650
651 out->status = SCMI_INVALID_PARAMETERS;
652 } else {
653 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
654 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
655 out->status = SCMI_NOT_SUPPORTED;
656 } else {
657 /* Ends deasserted whatever current state */
658 reset_state->asserted = false;
659 out->status = SCMI_SUCCESS;
660 }
661 } else {
662 reset_state->asserted = in->flags &
663 SCMI_RD_RESET_FLAG_ASSERT;
664
665 out->status = SCMI_SUCCESS;
666 }
667 }
668
669 return 0;
670}
671
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100672static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
673{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100674 struct scmi_voltd_attr_in *in = NULL;
675 struct scmi_voltd_attr_out *out = NULL;
676 struct sandbox_scmi_voltd *voltd_state = NULL;
677
678 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
679 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
680 return -EINVAL;
681
682 in = (struct scmi_voltd_attr_in *)msg->in_msg;
683 out = (struct scmi_voltd_attr_out *)msg->out_msg;
684
Etienne Carriere09665cb2022-02-21 09:22:39 +0100685 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100686 if (!voltd_state) {
687 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
688
689 out->status = SCMI_NOT_FOUND;
690 } else {
691 memset(out, 0, sizeof(*out));
692 snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
693
694 out->status = SCMI_SUCCESS;
695 }
696
697 return 0;
698}
699
700static int sandbox_scmi_voltd_config_set(struct udevice *dev,
701 struct scmi_msg *msg)
702{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100703 struct scmi_voltd_config_set_in *in = NULL;
704 struct scmi_voltd_config_set_out *out = NULL;
705 struct sandbox_scmi_voltd *voltd_state = NULL;
706
707 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
708 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
709 return -EINVAL;
710
711 in = (struct scmi_voltd_config_set_in *)msg->in_msg;
712 out = (struct scmi_voltd_config_set_out *)msg->out_msg;
713
Etienne Carriere09665cb2022-02-21 09:22:39 +0100714 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100715 if (!voltd_state) {
716 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
717
718 out->status = SCMI_NOT_FOUND;
719 } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
720 dev_err(dev, "Invalid config value 0x%x\n", in->config);
721
722 out->status = SCMI_INVALID_PARAMETERS;
723 } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
724 in->config != SCMI_VOLTD_CONFIG_OFF) {
725 dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
726
727 out->status = SCMI_INVALID_PARAMETERS;
728 } else {
729 voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
730 out->status = SCMI_SUCCESS;
731 }
732
733 return 0;
734}
735
736static int sandbox_scmi_voltd_config_get(struct udevice *dev,
737 struct scmi_msg *msg)
738{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100739 struct scmi_voltd_config_get_in *in = NULL;
740 struct scmi_voltd_config_get_out *out = NULL;
741 struct sandbox_scmi_voltd *voltd_state = NULL;
742
743 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
744 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
745 return -EINVAL;
746
747 in = (struct scmi_voltd_config_get_in *)msg->in_msg;
748 out = (struct scmi_voltd_config_get_out *)msg->out_msg;
749
Etienne Carriere09665cb2022-02-21 09:22:39 +0100750 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100751 if (!voltd_state) {
752 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
753
754 out->status = SCMI_NOT_FOUND;
755 } else {
756 if (voltd_state->enabled)
757 out->config = SCMI_VOLTD_CONFIG_ON;
758 else
759 out->config = SCMI_VOLTD_CONFIG_OFF;
760
761 out->status = SCMI_SUCCESS;
762 }
763
764 return 0;
765}
766
767static int sandbox_scmi_voltd_level_set(struct udevice *dev,
768 struct scmi_msg *msg)
769{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100770 struct scmi_voltd_level_set_in *in = NULL;
771 struct scmi_voltd_level_set_out *out = NULL;
772 struct sandbox_scmi_voltd *voltd_state = NULL;
773
774 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
775 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
776 return -EINVAL;
777
778 in = (struct scmi_voltd_level_set_in *)msg->in_msg;
779 out = (struct scmi_voltd_level_set_out *)msg->out_msg;
780
Etienne Carriere09665cb2022-02-21 09:22:39 +0100781 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100782 if (!voltd_state) {
783 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
784
785 out->status = SCMI_NOT_FOUND;
786 } else {
787 voltd_state->voltage_uv = in->voltage_level;
788 out->status = SCMI_SUCCESS;
789 }
790
791 return 0;
792}
793
794static int sandbox_scmi_voltd_level_get(struct udevice *dev,
795 struct scmi_msg *msg)
796{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100797 struct scmi_voltd_level_get_in *in = NULL;
798 struct scmi_voltd_level_get_out *out = NULL;
799 struct sandbox_scmi_voltd *voltd_state = NULL;
800
801 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
802 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
803 return -EINVAL;
804
805 in = (struct scmi_voltd_level_get_in *)msg->in_msg;
806 out = (struct scmi_voltd_level_get_out *)msg->out_msg;
807
Etienne Carriere09665cb2022-02-21 09:22:39 +0100808 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100809 if (!voltd_state) {
810 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
811
812 out->status = SCMI_NOT_FOUND;
813 } else {
814 out->voltage_level = voltd_state->voltage_uv;
815 out->status = SCMI_SUCCESS;
816 }
817
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900818 return 0;
819}
820
821/**
822 * sandbox_scmi_of_get_channel - assigne a channel
823 * @dev: SCMI agent device
824 * @protocol: SCMI protocol device
825 * @channel: Pointer to channel info
826 *
827 * Assign a channel for the protocol, @protocol, in @channel,
828 * based on a device tree's property.
829 *
830 * Return: 0 on success, error code on failure
831 */
832static int sandbox_scmi_of_get_channel(struct udevice *dev,
833 struct udevice *protocol,
834 struct scmi_channel **channel)
835{
836 struct sandbox_channel *agent_chan = dev_get_plat(dev);
837 struct sandbox_channel *chan;
838 u32 channel_id;
839
840 if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
841 /* Uses agent channel */
842 *channel = container_of(agent_chan, struct scmi_channel, ref);
843
844 return 0;
845 }
846
847 /* Setup a dedicated channel */
848 chan = calloc(1, sizeof(*chan));
849 if (!chan)
850 return -ENOMEM;
851
852 chan->channel_id = channel_id;
853
854 *channel = container_of(chan, struct scmi_channel, ref);
855
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100856 return 0;
857}
858
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900859/**
860 * sandbox_scmi_of_to_plat - assigne a channel to agent
861 * @dev: SCMI agent device
862 *
863 * Assign a channel for the agent, @protocol.
864 *
865 * Return: always 0
866 */
867static int sandbox_scmi_of_to_plat(struct udevice *dev)
868{
869 struct sandbox_channel *chan = dev_get_plat(dev);
870
871 /* The channel for agent is always 0 */
872 chan->channel_id = 0;
873
874 return 0;
875}
876
877unsigned int sandbox_scmi_channel_id(struct udevice *dev)
878{
879 struct scmi_agent_proto_priv *priv;
880 struct sandbox_channel *chan;
881
882 priv = dev_get_parent_priv(dev);
883 chan = (struct sandbox_channel *)&priv->channel->ref;
884
885 return chan->channel_id;
886}
887
Etienne Carriere02fd1262020-09-09 18:44:00 +0200888static int sandbox_scmi_test_process_msg(struct udevice *dev,
Etienne Carriere05440292022-05-31 18:09:19 +0200889 struct scmi_channel *channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +0200890 struct scmi_msg *msg)
891{
892 switch (msg->protocol_id) {
AKASHI Takahiro4b9839a2023-10-11 19:07:02 +0900893 case SCMI_PROTOCOL_ID_BASE:
894 switch (msg->message_id) {
895 case SCMI_PROTOCOL_VERSION:
896 return sandbox_scmi_base_protocol_version(dev, msg);
897 case SCMI_PROTOCOL_ATTRIBUTES:
898 return sandbox_scmi_base_protocol_attrs(dev, msg);
899 case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
900 return sandbox_scmi_base_message_attrs(dev, msg);
901 case SCMI_BASE_DISCOVER_VENDOR:
902 return sandbox_scmi_base_discover_vendor(dev, msg);
903 case SCMI_BASE_DISCOVER_SUB_VENDOR:
904 return sandbox_scmi_base_discover_sub_vendor(dev, msg);
905 case SCMI_BASE_DISCOVER_IMPL_VERSION:
906 return sandbox_scmi_base_discover_impl_version(dev, msg);
907 case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
908 return sandbox_scmi_base_discover_list_protocols(dev, msg);
909 case SCMI_BASE_DISCOVER_AGENT:
910 return sandbox_scmi_base_discover_agent(dev, msg);
911 case SCMI_BASE_NOTIFY_ERRORS:
912 break;
913 case SCMI_BASE_SET_DEVICE_PERMISSIONS:
914 return sandbox_scmi_base_set_device_permissions(dev, msg);
915 case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
916 return sandbox_scmi_base_set_protocol_permissions(dev, msg);
917 case SCMI_BASE_RESET_AGENT_CONFIGURATION:
918 return sandbox_scmi_base_reset_agent_configuration(dev, msg);
919 default:
920 break;
921 }
922 break;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200923 case SCMI_PROTOCOL_ID_CLOCK:
924 switch (msg->message_id) {
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100925 case SCMI_PROTOCOL_ATTRIBUTES:
926 return sandbox_scmi_clock_protocol_attribs(dev, msg);
927 case SCMI_CLOCK_ATTRIBUTES:
928 return sandbox_scmi_clock_attribs(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200929 case SCMI_CLOCK_RATE_SET:
930 return sandbox_scmi_clock_rate_set(dev, msg);
931 case SCMI_CLOCK_RATE_GET:
932 return sandbox_scmi_clock_rate_get(dev, msg);
933 case SCMI_CLOCK_CONFIG_SET:
934 return sandbox_scmi_clock_gate(dev, msg);
935 default:
936 break;
937 }
938 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200939 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
940 switch (msg->message_id) {
941 case SCMI_RESET_DOMAIN_ATTRIBUTES:
942 return sandbox_scmi_rd_attribs(dev, msg);
943 case SCMI_RESET_DOMAIN_RESET:
944 return sandbox_scmi_rd_reset(dev, msg);
945 default:
946 break;
947 }
948 break;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100949 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
950 switch (msg->message_id) {
951 case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
952 return sandbox_scmi_voltd_attribs(dev, msg);
953 case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
954 return sandbox_scmi_voltd_config_set(dev, msg);
955 case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
956 return sandbox_scmi_voltd_config_get(dev, msg);
957 case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
958 return sandbox_scmi_voltd_level_set(dev, msg);
959 case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
960 return sandbox_scmi_voltd_level_get(dev, msg);
961 default:
962 break;
963 }
964 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200965 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
966 case SCMI_PROTOCOL_ID_SYSTEM:
967 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200968 case SCMI_PROTOCOL_ID_SENSOR:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200969 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
970 return 0;
971 default:
972 break;
973 }
974
975 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
976 __func__, dev->name, msg->protocol_id, msg->message_id);
977
978 if (msg->out_msg_sz < sizeof(u32))
979 return -EINVAL;
980
981 /* Intentionnaly report unhandled IDs through the SCMI return code */
982 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
983 return 0;
984}
985
986static int sandbox_scmi_test_remove(struct udevice *dev)
987{
988 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
989
Etienne Carriere09665cb2022-02-21 09:22:39 +0100990 if (agent != sandbox_scmi_service_ctx()->agent)
991 return -EINVAL;
992
Etienne Carriere02fd1262020-09-09 18:44:00 +0200993 debug_print_agent_state(dev, "removed");
994
995 /* We only need to dereference the agent in the context */
Etienne Carriere09665cb2022-02-21 09:22:39 +0100996 sandbox_scmi_service_ctx()->agent = NULL;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200997
998 return 0;
999}
1000
1001static int sandbox_scmi_test_probe(struct udevice *dev)
1002{
Etienne Carriere02fd1262020-09-09 18:44:00 +02001003 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +02001004
Etienne Carriere09665cb2022-02-21 09:22:39 +01001005 if (sandbox_scmi_service_ctx()->agent)
1006 return -EINVAL;
Etienne Carriere02fd1262020-09-09 18:44:00 +02001007
Etienne Carriere09665cb2022-02-21 09:22:39 +01001008 *agent = (struct sandbox_scmi_agent){
1009 .clk = scmi_clk,
1010 .clk_count = ARRAY_SIZE(scmi_clk),
1011 .reset = scmi_reset,
1012 .reset_count = ARRAY_SIZE(scmi_reset),
1013 .voltd = scmi_voltd,
1014 .voltd_count = ARRAY_SIZE(scmi_voltd),
1015 };
Etienne Carriere02fd1262020-09-09 18:44:00 +02001016
1017 debug_print_agent_state(dev, "probed");
1018
1019 /* Save reference for tests purpose */
Etienne Carriere09665cb2022-02-21 09:22:39 +01001020 sandbox_scmi_service_ctx()->agent = agent;
Etienne Carriere02fd1262020-09-09 18:44:00 +02001021
1022 return 0;
1023};
1024
1025static const struct udevice_id sandbox_scmi_test_ids[] = {
1026 { .compatible = "sandbox,scmi-agent" },
1027 { }
1028};
1029
1030struct scmi_agent_ops sandbox_scmi_test_ops = {
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001031 .of_get_channel = sandbox_scmi_of_get_channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001032 .process_msg = sandbox_scmi_test_process_msg,
1033};
1034
1035U_BOOT_DRIVER(sandbox_scmi_agent) = {
1036 .name = "sandbox-scmi_agent",
1037 .id = UCLASS_SCMI_AGENT,
1038 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001039 .priv_auto = sizeof(struct sandbox_scmi_agent),
AKASHI Takahiro6221bf72023-10-11 19:06:56 +09001040 .plat_auto = sizeof(struct sandbox_channel),
1041 .of_to_plat = sandbox_scmi_of_to_plat,
Etienne Carriere02fd1262020-09-09 18:44:00 +02001042 .probe = sandbox_scmi_test_probe,
1043 .remove = sandbox_scmi_test_remove,
1044 .ops = &sandbox_scmi_test_ops,
1045};