blob: 031882998dfaea9fa7043fffbec213b0d37d524b [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
Etienne Carriere09665cb2022-02-21 09:22:39 +010036static struct sandbox_scmi_clk scmi_clk[] = {
Etienne Carrierebf1f1322022-02-21 09:22:41 +010037 { .rate = 333 },
38 { .rate = 200 },
39 { .rate = 1000 },
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020040};
41
Etienne Carriere09665cb2022-02-21 09:22:39 +010042static struct sandbox_scmi_reset scmi_reset[] = {
Etienne Carriere8b9b6892020-09-09 18:44:07 +020043 { .id = 3 },
44};
45
Etienne Carriere09665cb2022-02-21 09:22:39 +010046static struct sandbox_scmi_voltd scmi_voltd[] = {
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010047 { .id = 0, .voltage_uv = 3300000 },
48 { .id = 1, .voltage_uv = 1800000 },
49};
50
Etienne Carriere09665cb2022-02-21 09:22:39 +010051static struct sandbox_scmi_service sandbox_scmi_service_state;
Etienne Carriere02fd1262020-09-09 18:44:00 +020052
53struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
54{
55 return &sandbox_scmi_service_state;
56}
57
58static void debug_print_agent_state(struct udevice *dev, char *str)
59{
60 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
61
Etienne Carriere09665cb2022-02-21 09:22:39 +010062 dev_dbg(dev, "Dump sandbox_scmi_agent: %s\n", str);
63 dev_dbg(dev, " scmi_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020064 agent->clk_count,
65 agent->clk_count ? agent->clk[0].enabled : -1,
66 agent->clk_count ? agent->clk[0].rate : -1,
67 agent->clk_count > 1 ? agent->clk[1].enabled : -1,
68 agent->clk_count > 1 ? agent->clk[1].rate : -1,
69 agent->clk_count > 2 ? agent->clk[2].enabled : -1,
70 agent->clk_count > 2 ? agent->clk[2].rate : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +010071 dev_dbg(dev, " scmi_reset (%zu): %d, %d, ...\n",
Etienne Carriere8b9b6892020-09-09 18:44:07 +020072 agent->reset_count,
73 agent->reset_count ? agent->reset[0].asserted : -1,
74 agent->reset_count > 1 ? agent->reset[1].asserted : -1);
Etienne Carriere09665cb2022-02-21 09:22:39 +010075 dev_dbg(dev, " scmi_voltd (%zu): %u/%d, %u/%d, ...\n",
Etienne Carriereb8f15cd2021-03-08 22:38:07 +010076 agent->voltd_count,
77 agent->voltd_count ? agent->voltd[0].enabled : -1,
78 agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
79 agent->voltd_count ? agent->voltd[1].enabled : -1,
80 agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
Etienne Carriere02fd1262020-09-09 18:44:00 +020081};
82
Etienne Carriere09665cb2022-02-21 09:22:39 +010083static struct sandbox_scmi_clk *get_scmi_clk_state(uint clock_id)
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020084{
Etienne Carrierebf1f1322022-02-21 09:22:41 +010085 if (clock_id < ARRAY_SIZE(scmi_clk))
86 return scmi_clk + clock_id;
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020087
88 return NULL;
89}
90
Etienne Carriere09665cb2022-02-21 09:22:39 +010091static struct sandbox_scmi_reset *get_scmi_reset_state(uint reset_id)
Etienne Carriere8b9b6892020-09-09 18:44:07 +020092{
93 size_t n;
94
Etienne Carriere09665cb2022-02-21 09:22:39 +010095 for (n = 0; n < ARRAY_SIZE(scmi_reset); n++)
96 if (scmi_reset[n].id == reset_id)
97 return scmi_reset + n;
Etienne Carriere8b9b6892020-09-09 18:44:07 +020098
99 return NULL;
100}
101
Etienne Carriere09665cb2022-02-21 09:22:39 +0100102static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100103{
104 size_t n;
105
Etienne Carriere09665cb2022-02-21 09:22:39 +0100106 for (n = 0; n < ARRAY_SIZE(scmi_voltd); n++)
107 if (scmi_voltd[n].id == domain_id)
108 return scmi_voltd + n;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100109
110 return NULL;
111}
112
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200113/*
114 * Sandbox SCMI agent ops
115 */
116
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100117static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
118 struct scmi_msg *msg)
119{
120 struct scmi_clk_protocol_attr_out *out = NULL;
121
122 if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
123 return -EINVAL;
124
125 out = (struct scmi_clk_protocol_attr_out *)msg->out_msg;
126 out->attributes = ARRAY_SIZE(scmi_clk);
127 out->status = SCMI_SUCCESS;
128
129 return 0;
130}
131
132static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
133{
134 struct scmi_clk_attribute_in *in = NULL;
135 struct scmi_clk_attribute_out *out = NULL;
136 struct sandbox_scmi_clk *clk_state = NULL;
137 int ret;
138
139 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
140 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
141 return -EINVAL;
142
143 in = (struct scmi_clk_attribute_in *)msg->in_msg;
144 out = (struct scmi_clk_attribute_out *)msg->out_msg;
145
146 clk_state = get_scmi_clk_state(in->clock_id);
147 if (!clk_state) {
148 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
149
150 out->status = SCMI_NOT_FOUND;
151 } else {
152 memset(out, 0, sizeof(*out));
153
154 if (clk_state->enabled)
155 out->attributes = 1;
156
157 ret = snprintf(out->clock_name, sizeof(out->clock_name),
158 "clk%u", in->clock_id);
159 assert(ret > 0 && ret < sizeof(out->clock_name));
160
161 out->status = SCMI_SUCCESS;
162 }
163
164 return 0;
165}
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200166static int sandbox_scmi_clock_rate_set(struct udevice *dev,
167 struct scmi_msg *msg)
168{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200169 struct scmi_clk_rate_set_in *in = NULL;
170 struct scmi_clk_rate_set_out *out = NULL;
171 struct sandbox_scmi_clk *clk_state = NULL;
172
173 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
174 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
175 return -EINVAL;
176
177 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
178 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
179
Etienne Carriere09665cb2022-02-21 09:22:39 +0100180 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200181 if (!clk_state) {
182 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
183
184 out->status = SCMI_NOT_FOUND;
185 } else {
186 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
187
188 clk_state->rate = (ulong)rate;
189
190 out->status = SCMI_SUCCESS;
191 }
192
193 return 0;
194}
195
196static int sandbox_scmi_clock_rate_get(struct udevice *dev,
197 struct scmi_msg *msg)
198{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200199 struct scmi_clk_rate_get_in *in = NULL;
200 struct scmi_clk_rate_get_out *out = NULL;
201 struct sandbox_scmi_clk *clk_state = NULL;
202
203 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
204 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
205 return -EINVAL;
206
207 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
208 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
209
Etienne Carriere09665cb2022-02-21 09:22:39 +0100210 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200211 if (!clk_state) {
212 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
213
214 out->status = SCMI_NOT_FOUND;
215 } else {
216 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
217 out->rate_lsb = (u32)clk_state->rate;
218
219 out->status = SCMI_SUCCESS;
220 }
221
222 return 0;
223}
224
225static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
226{
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200227 struct scmi_clk_state_in *in = NULL;
228 struct scmi_clk_state_out *out = NULL;
229 struct sandbox_scmi_clk *clk_state = NULL;
230
231 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
232 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
233 return -EINVAL;
234
235 in = (struct scmi_clk_state_in *)msg->in_msg;
236 out = (struct scmi_clk_state_out *)msg->out_msg;
237
Etienne Carriere09665cb2022-02-21 09:22:39 +0100238 clk_state = get_scmi_clk_state(in->clock_id);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200239 if (!clk_state) {
240 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
241
242 out->status = SCMI_NOT_FOUND;
243 } else if (in->attributes > 1) {
244 out->status = SCMI_PROTOCOL_ERROR;
245 } else {
246 clk_state->enabled = in->attributes;
247
248 out->status = SCMI_SUCCESS;
249 }
250
251 return 0;
252}
253
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200254static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
255{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200256 struct scmi_rd_attr_in *in = NULL;
257 struct scmi_rd_attr_out *out = NULL;
258 struct sandbox_scmi_reset *reset_state = NULL;
259
260 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
261 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
262 return -EINVAL;
263
264 in = (struct scmi_rd_attr_in *)msg->in_msg;
265 out = (struct scmi_rd_attr_out *)msg->out_msg;
266
Etienne Carriere09665cb2022-02-21 09:22:39 +0100267 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200268 if (!reset_state) {
269 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
270
271 out->status = SCMI_NOT_FOUND;
272 } else {
273 memset(out, 0, sizeof(*out));
274 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
275
276 out->status = SCMI_SUCCESS;
277 }
278
279 return 0;
280}
281
282static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
283{
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200284 struct scmi_rd_reset_in *in = NULL;
285 struct scmi_rd_reset_out *out = NULL;
286 struct sandbox_scmi_reset *reset_state = NULL;
287
288 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
289 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
290 return -EINVAL;
291
292 in = (struct scmi_rd_reset_in *)msg->in_msg;
293 out = (struct scmi_rd_reset_out *)msg->out_msg;
294
Etienne Carriere09665cb2022-02-21 09:22:39 +0100295 reset_state = get_scmi_reset_state(in->domain_id);
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200296 if (!reset_state) {
297 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
298
299 out->status = SCMI_NOT_FOUND;
300 } else if (in->reset_state > 1) {
301 dev_err(dev, "Invalid reset domain input attribute value\n");
302
303 out->status = SCMI_INVALID_PARAMETERS;
304 } else {
305 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
306 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
307 out->status = SCMI_NOT_SUPPORTED;
308 } else {
309 /* Ends deasserted whatever current state */
310 reset_state->asserted = false;
311 out->status = SCMI_SUCCESS;
312 }
313 } else {
314 reset_state->asserted = in->flags &
315 SCMI_RD_RESET_FLAG_ASSERT;
316
317 out->status = SCMI_SUCCESS;
318 }
319 }
320
321 return 0;
322}
323
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100324static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
325{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100326 struct scmi_voltd_attr_in *in = NULL;
327 struct scmi_voltd_attr_out *out = NULL;
328 struct sandbox_scmi_voltd *voltd_state = NULL;
329
330 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
331 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
332 return -EINVAL;
333
334 in = (struct scmi_voltd_attr_in *)msg->in_msg;
335 out = (struct scmi_voltd_attr_out *)msg->out_msg;
336
Etienne Carriere09665cb2022-02-21 09:22:39 +0100337 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100338 if (!voltd_state) {
339 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
340
341 out->status = SCMI_NOT_FOUND;
342 } else {
343 memset(out, 0, sizeof(*out));
344 snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
345
346 out->status = SCMI_SUCCESS;
347 }
348
349 return 0;
350}
351
352static int sandbox_scmi_voltd_config_set(struct udevice *dev,
353 struct scmi_msg *msg)
354{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100355 struct scmi_voltd_config_set_in *in = NULL;
356 struct scmi_voltd_config_set_out *out = NULL;
357 struct sandbox_scmi_voltd *voltd_state = NULL;
358
359 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
360 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
361 return -EINVAL;
362
363 in = (struct scmi_voltd_config_set_in *)msg->in_msg;
364 out = (struct scmi_voltd_config_set_out *)msg->out_msg;
365
Etienne Carriere09665cb2022-02-21 09:22:39 +0100366 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100367 if (!voltd_state) {
368 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
369
370 out->status = SCMI_NOT_FOUND;
371 } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
372 dev_err(dev, "Invalid config value 0x%x\n", in->config);
373
374 out->status = SCMI_INVALID_PARAMETERS;
375 } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
376 in->config != SCMI_VOLTD_CONFIG_OFF) {
377 dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
378
379 out->status = SCMI_INVALID_PARAMETERS;
380 } else {
381 voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
382 out->status = SCMI_SUCCESS;
383 }
384
385 return 0;
386}
387
388static int sandbox_scmi_voltd_config_get(struct udevice *dev,
389 struct scmi_msg *msg)
390{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100391 struct scmi_voltd_config_get_in *in = NULL;
392 struct scmi_voltd_config_get_out *out = NULL;
393 struct sandbox_scmi_voltd *voltd_state = NULL;
394
395 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
396 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
397 return -EINVAL;
398
399 in = (struct scmi_voltd_config_get_in *)msg->in_msg;
400 out = (struct scmi_voltd_config_get_out *)msg->out_msg;
401
Etienne Carriere09665cb2022-02-21 09:22:39 +0100402 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100403 if (!voltd_state) {
404 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
405
406 out->status = SCMI_NOT_FOUND;
407 } else {
408 if (voltd_state->enabled)
409 out->config = SCMI_VOLTD_CONFIG_ON;
410 else
411 out->config = SCMI_VOLTD_CONFIG_OFF;
412
413 out->status = SCMI_SUCCESS;
414 }
415
416 return 0;
417}
418
419static int sandbox_scmi_voltd_level_set(struct udevice *dev,
420 struct scmi_msg *msg)
421{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100422 struct scmi_voltd_level_set_in *in = NULL;
423 struct scmi_voltd_level_set_out *out = NULL;
424 struct sandbox_scmi_voltd *voltd_state = NULL;
425
426 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
427 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
428 return -EINVAL;
429
430 in = (struct scmi_voltd_level_set_in *)msg->in_msg;
431 out = (struct scmi_voltd_level_set_out *)msg->out_msg;
432
Etienne Carriere09665cb2022-02-21 09:22:39 +0100433 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100434 if (!voltd_state) {
435 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
436
437 out->status = SCMI_NOT_FOUND;
438 } else {
439 voltd_state->voltage_uv = in->voltage_level;
440 out->status = SCMI_SUCCESS;
441 }
442
443 return 0;
444}
445
446static int sandbox_scmi_voltd_level_get(struct udevice *dev,
447 struct scmi_msg *msg)
448{
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100449 struct scmi_voltd_level_get_in *in = NULL;
450 struct scmi_voltd_level_get_out *out = NULL;
451 struct sandbox_scmi_voltd *voltd_state = NULL;
452
453 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
454 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
455 return -EINVAL;
456
457 in = (struct scmi_voltd_level_get_in *)msg->in_msg;
458 out = (struct scmi_voltd_level_get_out *)msg->out_msg;
459
Etienne Carriere09665cb2022-02-21 09:22:39 +0100460 voltd_state = get_scmi_voltd_state(in->domain_id);
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100461 if (!voltd_state) {
462 dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
463
464 out->status = SCMI_NOT_FOUND;
465 } else {
466 out->voltage_level = voltd_state->voltage_uv;
467 out->status = SCMI_SUCCESS;
468 }
469
470 return 0;
471}
472
Etienne Carriere02fd1262020-09-09 18:44:00 +0200473static int sandbox_scmi_test_process_msg(struct udevice *dev,
Etienne Carriere05440292022-05-31 18:09:19 +0200474 struct scmi_channel *channel,
Etienne Carriere02fd1262020-09-09 18:44:00 +0200475 struct scmi_msg *msg)
476{
477 switch (msg->protocol_id) {
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200478 case SCMI_PROTOCOL_ID_CLOCK:
479 switch (msg->message_id) {
Etienne Carriere4c4ec902022-02-21 09:22:42 +0100480 case SCMI_PROTOCOL_ATTRIBUTES:
481 return sandbox_scmi_clock_protocol_attribs(dev, msg);
482 case SCMI_CLOCK_ATTRIBUTES:
483 return sandbox_scmi_clock_attribs(dev, msg);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200484 case SCMI_CLOCK_RATE_SET:
485 return sandbox_scmi_clock_rate_set(dev, msg);
486 case SCMI_CLOCK_RATE_GET:
487 return sandbox_scmi_clock_rate_get(dev, msg);
488 case SCMI_CLOCK_CONFIG_SET:
489 return sandbox_scmi_clock_gate(dev, msg);
490 default:
491 break;
492 }
493 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200494 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
495 switch (msg->message_id) {
496 case SCMI_RESET_DOMAIN_ATTRIBUTES:
497 return sandbox_scmi_rd_attribs(dev, msg);
498 case SCMI_RESET_DOMAIN_RESET:
499 return sandbox_scmi_rd_reset(dev, msg);
500 default:
501 break;
502 }
503 break;
Etienne Carriereb8f15cd2021-03-08 22:38:07 +0100504 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
505 switch (msg->message_id) {
506 case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
507 return sandbox_scmi_voltd_attribs(dev, msg);
508 case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
509 return sandbox_scmi_voltd_config_set(dev, msg);
510 case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
511 return sandbox_scmi_voltd_config_get(dev, msg);
512 case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
513 return sandbox_scmi_voltd_level_set(dev, msg);
514 case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
515 return sandbox_scmi_voltd_level_get(dev, msg);
516 default:
517 break;
518 }
519 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200520 case SCMI_PROTOCOL_ID_BASE:
521 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
522 case SCMI_PROTOCOL_ID_SYSTEM:
523 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200524 case SCMI_PROTOCOL_ID_SENSOR:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200525 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
526 return 0;
527 default:
528 break;
529 }
530
531 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
532 __func__, dev->name, msg->protocol_id, msg->message_id);
533
534 if (msg->out_msg_sz < sizeof(u32))
535 return -EINVAL;
536
537 /* Intentionnaly report unhandled IDs through the SCMI return code */
538 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
539 return 0;
540}
541
542static int sandbox_scmi_test_remove(struct udevice *dev)
543{
544 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
545
Etienne Carriere09665cb2022-02-21 09:22:39 +0100546 if (agent != sandbox_scmi_service_ctx()->agent)
547 return -EINVAL;
548
Etienne Carriere02fd1262020-09-09 18:44:00 +0200549 debug_print_agent_state(dev, "removed");
550
551 /* We only need to dereference the agent in the context */
Etienne Carriere09665cb2022-02-21 09:22:39 +0100552 sandbox_scmi_service_ctx()->agent = NULL;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200553
554 return 0;
555}
556
557static int sandbox_scmi_test_probe(struct udevice *dev)
558{
Etienne Carriere02fd1262020-09-09 18:44:00 +0200559 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200560
Etienne Carriere09665cb2022-02-21 09:22:39 +0100561 if (sandbox_scmi_service_ctx()->agent)
562 return -EINVAL;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200563
Etienne Carriere09665cb2022-02-21 09:22:39 +0100564 *agent = (struct sandbox_scmi_agent){
565 .clk = scmi_clk,
566 .clk_count = ARRAY_SIZE(scmi_clk),
567 .reset = scmi_reset,
568 .reset_count = ARRAY_SIZE(scmi_reset),
569 .voltd = scmi_voltd,
570 .voltd_count = ARRAY_SIZE(scmi_voltd),
571 };
Etienne Carriere02fd1262020-09-09 18:44:00 +0200572
573 debug_print_agent_state(dev, "probed");
574
575 /* Save reference for tests purpose */
Etienne Carriere09665cb2022-02-21 09:22:39 +0100576 sandbox_scmi_service_ctx()->agent = agent;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200577
578 return 0;
579};
580
581static const struct udevice_id sandbox_scmi_test_ids[] = {
582 { .compatible = "sandbox,scmi-agent" },
583 { }
584};
585
586struct scmi_agent_ops sandbox_scmi_test_ops = {
587 .process_msg = sandbox_scmi_test_process_msg,
588};
589
590U_BOOT_DRIVER(sandbox_scmi_agent) = {
591 .name = "sandbox-scmi_agent",
592 .id = UCLASS_SCMI_AGENT,
593 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700594 .priv_auto = sizeof(struct sandbox_scmi_agent),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200595 .probe = sandbox_scmi_test_probe,
596 .remove = sandbox_scmi_test_remove,
597 .ops = &sandbox_scmi_test_ops,
598};