blob: 394df043918ffca22aa6d4beaf7f6ea4e7486f7d [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>
17
18/*
19 * The sandbox SCMI agent driver simulates to some extend a SCMI message
20 * processing. It simulates few of the SCMI services for some of the
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020021 * SCMI protocols embedded in U-Boot. Currently:
Etienne Carriere09665cb2022-02-21 09:22:39 +010022 * - SCMI clock protocol emulates an agent exposing 2 clocks
23 * - SCMI reset protocol emulates an agent exposing a reset controller
24 * - SCMI voltage domain protocol emulates an agent exposing 2 regulators
Etienne Carriere02fd1262020-09-09 18:44:00 +020025 *
Etienne Carriere09665cb2022-02-21 09:22:39 +010026 * As per DT bindings, the device node name shall be scmi.
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020027 *
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010028 * All clocks and regulators are default disabled and reset controller down.
Etienne Carriere02fd1262020-09-09 18:44:00 +020029 *
Etienne Carriere09665cb2022-02-21 09:22:39 +010030 * This driver exports sandbox_scmi_service_ctx() for the test sequence to
Etienne Carriere02fd1262020-09-09 18:44:00 +020031 * get the state of the simulated services (clock state, rate, ...) and
32 * check back-end device state reflects the request send through the
Etienne Carriere8b9b6892020-09-09 18:44:07 +020033 * various uclass devices, as clocks and reset controllers.
Etienne Carriere02fd1262020-09-09 18:44:00 +020034 */
35
AKASHI Takahiro6221bf72023-10-11 19:06:56 +090036/**
37 * struct sandbox_channel - Description of sandbox transport
38 * @channel_id: Channel identifier
39 *
40 * Dummy channel. This will be used to test if a protocol-specific
41 * channel is properly used.
42 * Id 0 means a channel for the sandbox agent.
43 */
44struct sandbox_channel {
45 unsigned int channel_id;
46};
47
48/**
49 * struct scmi_channel - Channel instance referenced in SCMI drivers
50 * @ref: Reference to local channel instance
51 **/
52struct scmi_channel {
53 struct sandbox_channel ref;
54};
55
Etienne Carriere09665cb2022-02-21 09:22:39 +010056static struct sandbox_scmi_clk scmi_clk[] = {
Etienne Carrierebf1f1322022-02-21 09:22:41 +010057 { .rate = 333 },
58 { .rate = 200 },
59 { .rate = 1000 },
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020060};
61
Etienne Carriere09665cb2022-02-21 09:22:39 +010062static struct sandbox_scmi_reset scmi_reset[] = {
Etienne Carriere8b9b6892020-09-09 18:44:07 +020063 { .id = 3 },
64};
65
Etienne Carriere09665cb2022-02-21 09:22:39 +010066static struct sandbox_scmi_voltd scmi_voltd[] = {
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010067 { .id = 0, .voltage_uv = 3300000 },
68 { .id = 1, .voltage_uv = 1800000 },
69};
70
Etienne Carriere09665cb2022-02-21 09:22:39 +010071static struct sandbox_scmi_service sandbox_scmi_service_state;
Etienne Carriere02fd1262020-09-09 18:44:00 +020072
73struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
74{
75 return &sandbox_scmi_service_state;
76}
77
78static void debug_print_agent_state(struct udevice *dev, char *str)
79{
80 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
81
Etienne Carriere09665cb2022-02-21 09:22:39 +010082 dev_dbg(dev, "Dump sandbox_scmi_agent: %s\n", str);
83 dev_dbg(dev, " scmi_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020084 agent->clk_count,
85 agent->clk_count ? agent->clk[0].enabled : -1,
86 agent->clk_count ? agent->clk[0].rate : -1,
87 agent->clk_count > 1 ? agent->clk[1].enabled : -1,
88 agent->clk_count > 1 ? agent->clk[1].rate : -1,
89 agent->clk_count > 2 ? agent->clk[2].enabled : -1,
90 agent->clk_count > 2 ? agent->clk[2].rate : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +010091 dev_dbg(dev, " scmi_reset (%zu): %d, %d, ...\n",
Etienne Carriere8b9b6892020-09-09 18:44:07 +020092 agent->reset_count,
93 agent->reset_count ? agent->reset[0].asserted : -1,
94 agent->reset_count > 1 ? agent->reset[1].asserted : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +010095 dev_dbg(dev, " scmi_voltd (%zu): %u/%d, %u/%d, ...\n",
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010096 agent->voltd_count,
97 agent->voltd_count ? agent->voltd[0].enabled : -1,
98 agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
99 agent->voltd_count ? agent->voltd[1].enabled : -1,
100 agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200101};
102
Etienne Carriere09665cb2022-02-21 09:22:39 +0100103static struct sandbox_scmi_clk *get_scmi_clk_state(uint clock_id)
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200104{
Etienne Carrierebf1f1322022-02-21 09:22:41 +0100105 if (clock_id < ARRAY_SIZE(scmi_clk))
106 return scmi_clk + clock_id;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200107
108 return NULL;
109}
110
Etienne Carriere09665cb2022-02-21 09:22:39 +0100111static struct sandbox_scmi_reset *get_scmi_reset_state(uint reset_id)
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200112{
113 size_t n;
114
Etienne Carriere09665cb2022-02-21 09:22:39 +0100115 for (n = 0; n < ARRAY_SIZE(scmi_reset); n++)
116 if (scmi_reset[n].id == reset_id)
117 return scmi_reset + n;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200118
119 return NULL;
120}
121
Etienne Carriere09665cb2022-02-21 09:22:39 +0100122static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100123{
124 size_t n;
125
Etienne Carriere09665cb2022-02-21 09:22:39 +0100126 for (n = 0; n < ARRAY_SIZE(scmi_voltd); n++)
127 if (scmi_voltd[n].id == domain_id)
128 return scmi_voltd + n;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100129
130 return NULL;
131}
132
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200133/*
134 * Sandbox SCMI agent ops
135 */
136
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100137static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
138 struct scmi_msg *msg)
139{
140 struct scmi_clk_protocol_attr_out *out = NULL;
141
142 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
143 return -EINVAL;
144
145 out = (struct scmi_clk_protocol_attr_out *)msg->out_msg;
146 out->attributes = ARRAY_SIZE(scmi_clk);
147 out->status = SCMI_SUCCESS;
148
149 return 0;
150}
151
152static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
153{
154 struct scmi_clk_attribute_in *in = NULL;
155 struct scmi_clk_attribute_out *out = NULL;
156 struct sandbox_scmi_clk *clk_state = NULL;
157 int ret;
158
159 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
160 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
161 return -EINVAL;
162
163 in = (struct scmi_clk_attribute_in *)msg->in_msg;
164 out = (struct scmi_clk_attribute_out *)msg->out_msg;
165
166 clk_state = get_scmi_clk_state(in->clock_id);
167 if (!clk_state) {
168 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
169
170 out->status = SCMI_NOT_FOUND;
171 } else {
172 memset(out, 0, sizeof(*out));
173
174 if (clk_state->enabled)
175 out->attributes = 1;
176
177 ret = snprintf(out->clock_name, sizeof(out->clock_name),
178 "clk%u", in->clock_id);
179 assert(ret > 0 && ret < sizeof(out->clock_name));
180
181 out->status = SCMI_SUCCESS;
182 }
183
184 return 0;
185}
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200186static int sandbox_scmi_clock_rate_set(struct udevice *dev,
187 struct scmi_msg *msg)
188{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200189 struct scmi_clk_rate_set_in *in = NULL;
190 struct scmi_clk_rate_set_out *out = NULL;
191 struct sandbox_scmi_clk *clk_state = NULL;
192
193 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
194 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
195 return -EINVAL;
196
197 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
198 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
199
Etienne Carriere09665cb2022-02-21 09:22:39 +0100200 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200201 if (!clk_state) {
202 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
203
204 out->status = SCMI_NOT_FOUND;
205 } else {
206 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
207
208 clk_state->rate = (ulong)rate;
209
210 out->status = SCMI_SUCCESS;
211 }
212
213 return 0;
214}
215
216static int sandbox_scmi_clock_rate_get(struct udevice *dev,
217 struct scmi_msg *msg)
218{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200219 struct scmi_clk_rate_get_in *in = NULL;
220 struct scmi_clk_rate_get_out *out = NULL;
221 struct sandbox_scmi_clk *clk_state = NULL;
222
223 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
224 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
225 return -EINVAL;
226
227 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
228 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
229
Etienne Carriere09665cb2022-02-21 09:22:39 +0100230 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200231 if (!clk_state) {
232 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
233
234 out->status = SCMI_NOT_FOUND;
235 } else {
236 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
237 out->rate_lsb = (u32)clk_state->rate;
238
239 out->status = SCMI_SUCCESS;
240 }
241
242 return 0;
243}
244
245static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
246{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200247 struct scmi_clk_state_in *in = NULL;
248 struct scmi_clk_state_out *out = NULL;
249 struct sandbox_scmi_clk *clk_state = NULL;
250
251 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
252 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
253 return -EINVAL;
254
255 in = (struct scmi_clk_state_in *)msg->in_msg;
256 out = (struct scmi_clk_state_out *)msg->out_msg;
257
Etienne Carriere09665cb2022-02-21 09:22:39 +0100258 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200259 if (!clk_state) {
260 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
261
262 out->status = SCMI_NOT_FOUND;
263 } else if (in->attributes > 1) {
264 out->status = SCMI_PROTOCOL_ERROR;
265 } else {
266 clk_state->enabled = in->attributes;
267
268 out->status = SCMI_SUCCESS;
269 }
270
271 return 0;
272}
273
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200274static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
275{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200276 struct scmi_rd_attr_in *in = NULL;
277 struct scmi_rd_attr_out *out = NULL;
278 struct sandbox_scmi_reset *reset_state = NULL;
279
280 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
281 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
282 return -EINVAL;
283
284 in = (struct scmi_rd_attr_in *)msg->in_msg;
285 out = (struct scmi_rd_attr_out *)msg->out_msg;
286
Etienne Carriere09665cb2022-02-21 09:22:39 +0100287 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200288 if (!reset_state) {
289 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
290
291 out->status = SCMI_NOT_FOUND;
292 } else {
293 memset(out, 0, sizeof(*out));
294 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
295
296 out->status = SCMI_SUCCESS;
297 }
298
299 return 0;
300}
301
302static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
303{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200304 struct scmi_rd_reset_in *in = NULL;
305 struct scmi_rd_reset_out *out = NULL;
306 struct sandbox_scmi_reset *reset_state = NULL;
307
308 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
309 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
310 return -EINVAL;
311
312 in = (struct scmi_rd_reset_in *)msg->in_msg;
313 out = (struct scmi_rd_reset_out *)msg->out_msg;
314
Etienne Carriere09665cb2022-02-21 09:22:39 +0100315 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200316 if (!reset_state) {
317 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
318
319 out->status = SCMI_NOT_FOUND;
320 } else if (in->reset_state > 1) {
321 dev_err(dev, "Invalid reset domain input attribute value\n");
322
323 out->status = SCMI_INVALID_PARAMETERS;
324 } else {
325 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
326 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
327 out->status = SCMI_NOT_SUPPORTED;
328 } else {
329 /* Ends deasserted whatever current state */
330 reset_state->asserted = false;
331 out->status = SCMI_SUCCESS;
332 }
333 } else {
334 reset_state->asserted = in->flags &
335 SCMI_RD_RESET_FLAG_ASSERT;
336
337 out->status = SCMI_SUCCESS;
338 }
339 }
340
341 return 0;
342}
343
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100344static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
345{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100346 struct scmi_voltd_attr_in *in = NULL;
347 struct scmi_voltd_attr_out *out = NULL;
348 struct sandbox_scmi_voltd *voltd_state = NULL;
349
350 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
351 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
352 return -EINVAL;
353
354 in = (struct scmi_voltd_attr_in *)msg->in_msg;
355 out = (struct scmi_voltd_attr_out *)msg->out_msg;
356
Etienne Carriere09665cb2022-02-21 09:22:39 +0100357 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100358 if (!voltd_state) {
359 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
360
361 out->status = SCMI_NOT_FOUND;
362 } else {
363 memset(out, 0, sizeof(*out));
364 snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
365
366 out->status = SCMI_SUCCESS;
367 }
368
369 return 0;
370}
371
372static int sandbox_scmi_voltd_config_set(struct udevice *dev,
373 struct scmi_msg *msg)
374{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100375 struct scmi_voltd_config_set_in *in = NULL;
376 struct scmi_voltd_config_set_out *out = NULL;
377 struct sandbox_scmi_voltd *voltd_state = NULL;
378
379 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
380 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
381 return -EINVAL;
382
383 in = (struct scmi_voltd_config_set_in *)msg->in_msg;
384 out = (struct scmi_voltd_config_set_out *)msg->out_msg;
385
Etienne Carriere09665cb2022-02-21 09:22:39 +0100386 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100387 if (!voltd_state) {
388 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
389
390 out->status = SCMI_NOT_FOUND;
391 } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
392 dev_err(dev, "Invalid config value 0x%x\n", in->config);
393
394 out->status = SCMI_INVALID_PARAMETERS;
395 } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
396 in->config != SCMI_VOLTD_CONFIG_OFF) {
397 dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
398
399 out->status = SCMI_INVALID_PARAMETERS;
400 } else {
401 voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
402 out->status = SCMI_SUCCESS;
403 }
404
405 return 0;
406}
407
408static int sandbox_scmi_voltd_config_get(struct udevice *dev,
409 struct scmi_msg *msg)
410{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100411 struct scmi_voltd_config_get_in *in = NULL;
412 struct scmi_voltd_config_get_out *out = NULL;
413 struct sandbox_scmi_voltd *voltd_state = NULL;
414
415 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
416 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
417 return -EINVAL;
418
419 in = (struct scmi_voltd_config_get_in *)msg->in_msg;
420 out = (struct scmi_voltd_config_get_out *)msg->out_msg;
421
Etienne Carriere09665cb2022-02-21 09:22:39 +0100422 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100423 if (!voltd_state) {
424 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
425
426 out->status = SCMI_NOT_FOUND;
427 } else {
428 if (voltd_state->enabled)
429 out->config = SCMI_VOLTD_CONFIG_ON;
430 else
431 out->config = SCMI_VOLTD_CONFIG_OFF;
432
433 out->status = SCMI_SUCCESS;
434 }
435
436 return 0;
437}
438
439static int sandbox_scmi_voltd_level_set(struct udevice *dev,
440 struct scmi_msg *msg)
441{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100442 struct scmi_voltd_level_set_in *in = NULL;
443 struct scmi_voltd_level_set_out *out = NULL;
444 struct sandbox_scmi_voltd *voltd_state = NULL;
445
446 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
447 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
448 return -EINVAL;
449
450 in = (struct scmi_voltd_level_set_in *)msg->in_msg;
451 out = (struct scmi_voltd_level_set_out *)msg->out_msg;
452
Etienne Carriere09665cb2022-02-21 09:22:39 +0100453 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100454 if (!voltd_state) {
455 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
456
457 out->status = SCMI_NOT_FOUND;
458 } else {
459 voltd_state->voltage_uv = in->voltage_level;
460 out->status = SCMI_SUCCESS;
461 }
462
463 return 0;
464}
465
466static int sandbox_scmi_voltd_level_get(struct udevice *dev,
467 struct scmi_msg *msg)
468{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100469 struct scmi_voltd_level_get_in *in = NULL;
470 struct scmi_voltd_level_get_out *out = NULL;
471 struct sandbox_scmi_voltd *voltd_state = NULL;
472
473 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
474 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
475 return -EINVAL;
476
477 in = (struct scmi_voltd_level_get_in *)msg->in_msg;
478 out = (struct scmi_voltd_level_get_out *)msg->out_msg;
479
Etienne Carriere09665cb2022-02-21 09:22:39 +0100480 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100481 if (!voltd_state) {
482 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
483
484 out->status = SCMI_NOT_FOUND;
485 } else {
486 out->voltage_level = voltd_state->voltage_uv;
487 out->status = SCMI_SUCCESS;
488 }
489
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900490 return 0;
491}
492
493/**
494 * sandbox_scmi_of_get_channel - assigne a channel
495 * @dev: SCMI agent device
496 * @protocol: SCMI protocol device
497 * @channel: Pointer to channel info
498 *
499 * Assign a channel for the protocol, @protocol, in @channel,
500 * based on a device tree's property.
501 *
502 * Return: 0 on success, error code on failure
503 */
504static int sandbox_scmi_of_get_channel(struct udevice *dev,
505 struct udevice *protocol,
506 struct scmi_channel **channel)
507{
508 struct sandbox_channel *agent_chan = dev_get_plat(dev);
509 struct sandbox_channel *chan;
510 u32 channel_id;
511
512 if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
513 /* Uses agent channel */
514 *channel = container_of(agent_chan, struct scmi_channel, ref);
515
516 return 0;
517 }
518
519 /* Setup a dedicated channel */
520 chan = calloc(1, sizeof(*chan));
521 if (!chan)
522 return -ENOMEM;
523
524 chan->channel_id = channel_id;
525
526 *channel = container_of(chan, struct scmi_channel, ref);
527
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100528 return 0;
529}
530
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900531/**
532 * sandbox_scmi_of_to_plat - assigne a channel to agent
533 * @dev: SCMI agent device
534 *
535 * Assign a channel for the agent, @protocol.
536 *
537 * Return: always 0
538 */
539static int sandbox_scmi_of_to_plat(struct udevice *dev)
540{
541 struct sandbox_channel *chan = dev_get_plat(dev);
542
543 /* The channel for agent is always 0 */
544 chan->channel_id = 0;
545
546 return 0;
547}
548
549unsigned int sandbox_scmi_channel_id(struct udevice *dev)
550{
551 struct scmi_agent_proto_priv *priv;
552 struct sandbox_channel *chan;
553
554 priv = dev_get_parent_priv(dev);
555 chan = (struct sandbox_channel *)&priv->channel->ref;
556
557 return chan->channel_id;
558}
559
Etienne Carriere02fd1262020-09-09 18:44:00 +0200560static int sandbox_scmi_test_process_msg(struct udevice *dev,
Etienne Carriere05440292022-05-31 18:09:19 +0200561 struct scmi_channel *channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +0200562 struct scmi_msg *msg)
563{
564 switch (msg->protocol_id) {
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200565 case SCMI_PROTOCOL_ID_CLOCK:
566 switch (msg->message_id) {
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100567 case SCMI_PROTOCOL_ATTRIBUTES:
568 return sandbox_scmi_clock_protocol_attribs(dev, msg);
569 case SCMI_CLOCK_ATTRIBUTES:
570 return sandbox_scmi_clock_attribs(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200571 case SCMI_CLOCK_RATE_SET:
572 return sandbox_scmi_clock_rate_set(dev, msg);
573 case SCMI_CLOCK_RATE_GET:
574 return sandbox_scmi_clock_rate_get(dev, msg);
575 case SCMI_CLOCK_CONFIG_SET:
576 return sandbox_scmi_clock_gate(dev, msg);
577 default:
578 break;
579 }
580 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200581 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
582 switch (msg->message_id) {
583 case SCMI_RESET_DOMAIN_ATTRIBUTES:
584 return sandbox_scmi_rd_attribs(dev, msg);
585 case SCMI_RESET_DOMAIN_RESET:
586 return sandbox_scmi_rd_reset(dev, msg);
587 default:
588 break;
589 }
590 break;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100591 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
592 switch (msg->message_id) {
593 case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
594 return sandbox_scmi_voltd_attribs(dev, msg);
595 case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
596 return sandbox_scmi_voltd_config_set(dev, msg);
597 case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
598 return sandbox_scmi_voltd_config_get(dev, msg);
599 case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
600 return sandbox_scmi_voltd_level_set(dev, msg);
601 case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
602 return sandbox_scmi_voltd_level_get(dev, msg);
603 default:
604 break;
605 }
606 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200607 case SCMI_PROTOCOL_ID_BASE:
608 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
609 case SCMI_PROTOCOL_ID_SYSTEM:
610 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200611 case SCMI_PROTOCOL_ID_SENSOR:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200612 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
613 return 0;
614 default:
615 break;
616 }
617
618 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
619 __func__, dev->name, msg->protocol_id, msg->message_id);
620
621 if (msg->out_msg_sz < sizeof(u32))
622 return -EINVAL;
623
624 /* Intentionnaly report unhandled IDs through the SCMI return code */
625 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
626 return 0;
627}
628
629static int sandbox_scmi_test_remove(struct udevice *dev)
630{
631 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
632
Etienne Carriere09665cb2022-02-21 09:22:39 +0100633 if (agent != sandbox_scmi_service_ctx()->agent)
634 return -EINVAL;
635
Etienne Carriere02fd1262020-09-09 18:44:00 +0200636 debug_print_agent_state(dev, "removed");
637
638 /* We only need to dereference the agent in the context */
Etienne Carriere09665cb2022-02-21 09:22:39 +0100639 sandbox_scmi_service_ctx()->agent = NULL;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200640
641 return 0;
642}
643
644static int sandbox_scmi_test_probe(struct udevice *dev)
645{
Etienne Carriere02fd1262020-09-09 18:44:00 +0200646 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200647
Etienne Carriere09665cb2022-02-21 09:22:39 +0100648 if (sandbox_scmi_service_ctx()->agent)
649 return -EINVAL;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200650
Etienne Carriere09665cb2022-02-21 09:22:39 +0100651 *agent = (struct sandbox_scmi_agent){
652 .clk = scmi_clk,
653 .clk_count = ARRAY_SIZE(scmi_clk),
654 .reset = scmi_reset,
655 .reset_count = ARRAY_SIZE(scmi_reset),
656 .voltd = scmi_voltd,
657 .voltd_count = ARRAY_SIZE(scmi_voltd),
658 };
Etienne Carriere02fd1262020-09-09 18:44:00 +0200659
660 debug_print_agent_state(dev, "probed");
661
662 /* Save reference for tests purpose */
Etienne Carriere09665cb2022-02-21 09:22:39 +0100663 sandbox_scmi_service_ctx()->agent = agent;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200664
665 return 0;
666};
667
668static const struct udevice_id sandbox_scmi_test_ids[] = {
669 { .compatible = "sandbox,scmi-agent" },
670 { }
671};
672
673struct scmi_agent_ops sandbox_scmi_test_ops = {
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900674 .of_get_channel = sandbox_scmi_of_get_channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +0200675 .process_msg = sandbox_scmi_test_process_msg,
676};
677
678U_BOOT_DRIVER(sandbox_scmi_agent) = {
679 .name = "sandbox-scmi_agent",
680 .id = UCLASS_SCMI_AGENT,
681 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700682 .priv_auto = sizeof(struct sandbox_scmi_agent),
AKASHI Takahiro6221bf72023-10-11 19:06:56 +0900683 .plat_auto = sizeof(struct sandbox_channel),
684 .of_to_plat = sandbox_scmi_of_to_plat,
Etienne Carriere02fd1262020-09-09 18:44:00 +0200685 .probe = sandbox_scmi_test_probe,
686 .remove = sandbox_scmi_test_remove,
687 .ops = &sandbox_scmi_test_ops,
688};