blob: 97a5dace15f196f20a64537f5f49326bd51f2e6e [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:
22 * - SCMI clock protocol: emulate 2 agents each exposing few clocks
Etienne Carriere8b9b6892020-09-09 18:44:07 +020023 * - SCMI reset protocol: emulate 1 agents each exposing a reset
Etienne Carriere02fd1262020-09-09 18:44:00 +020024 *
Etienne Carriere8b9b6892020-09-09 18:44:07 +020025 * Agent #0 simulates 2 clocks and 1 reset domain.
26 * See IDs in scmi0_clk[]/scmi0_reset[] and "sandbox-scmi-agent@0" in test.dts.
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020027 *
28 * Agent #1 simulates 1 clock.
29 * See IDs in scmi1_clk[] and "sandbox-scmi-agent@1" in test.dts.
30 *
Etienne Carriere8b9b6892020-09-09 18:44:07 +020031 * All clocks are default disabled and reset levels down.
Etienne Carriere02fd1262020-09-09 18:44:00 +020032 *
33 * This Driver exports sandbox_scmi_service_ct() for the test sequence to
34 * 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
39#define SANDBOX_SCMI_AGENT_COUNT 2
40
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020041static struct sandbox_scmi_clk scmi0_clk[] = {
42 { .id = 7, .rate = 1000 },
43 { .id = 3, .rate = 333 },
44};
45
Etienne Carriere8b9b6892020-09-09 18:44:07 +020046static struct sandbox_scmi_reset scmi0_reset[] = {
47 { .id = 3 },
48};
49
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020050static struct sandbox_scmi_clk scmi1_clk[] = {
51 { .id = 1, .rate = 44 },
52};
53
Etienne Carriere02fd1262020-09-09 18:44:00 +020054/* The list saves to simulted end devices references for test purpose */
55struct sandbox_scmi_agent *sandbox_scmi_agent_list[SANDBOX_SCMI_AGENT_COUNT];
56
57static struct sandbox_scmi_service sandbox_scmi_service_state = {
58 .agent = sandbox_scmi_agent_list,
59 .agent_count = SANDBOX_SCMI_AGENT_COUNT,
60};
61
62struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
63{
64 return &sandbox_scmi_service_state;
65}
66
67static void debug_print_agent_state(struct udevice *dev, char *str)
68{
69 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
70
71 dev_dbg(dev, "Dump sandbox_scmi_agent %u: %s\n", agent->idx, str);
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020072 dev_dbg(dev, " scmi%u_clk (%zu): %d/%ld, %d/%ld, %d/%ld, ...\n",
73 agent->idx,
74 agent->clk_count,
75 agent->clk_count ? agent->clk[0].enabled : -1,
76 agent->clk_count ? agent->clk[0].rate : -1,
77 agent->clk_count > 1 ? agent->clk[1].enabled : -1,
78 agent->clk_count > 1 ? agent->clk[1].rate : -1,
79 agent->clk_count > 2 ? agent->clk[2].enabled : -1,
80 agent->clk_count > 2 ? agent->clk[2].rate : -1);
Etienne Carriere8b9b6892020-09-09 18:44:07 +020081 dev_dbg(dev, " scmi%u_reset (%zu): %d, %d, ...\n",
82 agent->idx,
83 agent->reset_count,
84 agent->reset_count ? agent->reset[0].asserted : -1,
85 agent->reset_count > 1 ? agent->reset[1].asserted : -1);
Etienne Carriere02fd1262020-09-09 18:44:00 +020086};
87
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +020088static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id)
89{
90 struct sandbox_scmi_clk *target = NULL;
91 size_t target_count = 0;
92 size_t n;
93
94 switch (agent_id) {
95 case 0:
96 target = scmi0_clk;
97 target_count = ARRAY_SIZE(scmi0_clk);
98 break;
99 case 1:
100 target = scmi1_clk;
101 target_count = ARRAY_SIZE(scmi1_clk);
102 break;
103 default:
104 return NULL;
105 }
106
107 for (n = 0; n < target_count; n++)
108 if (target[n].id == clock_id)
109 return target + n;
110
111 return NULL;
112}
113
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200114static struct sandbox_scmi_reset *get_scmi_reset_state(uint agent_id,
115 uint reset_id)
116{
117 size_t n;
118
119 if (agent_id == 0) {
120 for (n = 0; n < ARRAY_SIZE(scmi0_reset); n++)
121 if (scmi0_reset[n].id == reset_id)
122 return scmi0_reset + n;
123 }
124
125 return NULL;
126}
127
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200128/*
129 * Sandbox SCMI agent ops
130 */
131
132static int sandbox_scmi_clock_rate_set(struct udevice *dev,
133 struct scmi_msg *msg)
134{
135 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
136 struct scmi_clk_rate_set_in *in = NULL;
137 struct scmi_clk_rate_set_out *out = NULL;
138 struct sandbox_scmi_clk *clk_state = NULL;
139
140 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
141 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
142 return -EINVAL;
143
144 in = (struct scmi_clk_rate_set_in *)msg->in_msg;
145 out = (struct scmi_clk_rate_set_out *)msg->out_msg;
146
147 clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
148 if (!clk_state) {
149 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
150
151 out->status = SCMI_NOT_FOUND;
152 } else {
153 u64 rate = ((u64)in->rate_msb << 32) + in->rate_lsb;
154
155 clk_state->rate = (ulong)rate;
156
157 out->status = SCMI_SUCCESS;
158 }
159
160 return 0;
161}
162
163static int sandbox_scmi_clock_rate_get(struct udevice *dev,
164 struct scmi_msg *msg)
165{
166 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
167 struct scmi_clk_rate_get_in *in = NULL;
168 struct scmi_clk_rate_get_out *out = NULL;
169 struct sandbox_scmi_clk *clk_state = NULL;
170
171 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
172 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
173 return -EINVAL;
174
175 in = (struct scmi_clk_rate_get_in *)msg->in_msg;
176 out = (struct scmi_clk_rate_get_out *)msg->out_msg;
177
178 clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
179 if (!clk_state) {
180 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
181
182 out->status = SCMI_NOT_FOUND;
183 } else {
184 out->rate_msb = (u32)((u64)clk_state->rate >> 32);
185 out->rate_lsb = (u32)clk_state->rate;
186
187 out->status = SCMI_SUCCESS;
188 }
189
190 return 0;
191}
192
193static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
194{
195 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
196 struct scmi_clk_state_in *in = NULL;
197 struct scmi_clk_state_out *out = NULL;
198 struct sandbox_scmi_clk *clk_state = NULL;
199
200 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
201 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
202 return -EINVAL;
203
204 in = (struct scmi_clk_state_in *)msg->in_msg;
205 out = (struct scmi_clk_state_out *)msg->out_msg;
206
207 clk_state = get_scmi_clk_state(agent->idx, in->clock_id);
208 if (!clk_state) {
209 dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
210
211 out->status = SCMI_NOT_FOUND;
212 } else if (in->attributes > 1) {
213 out->status = SCMI_PROTOCOL_ERROR;
214 } else {
215 clk_state->enabled = in->attributes;
216
217 out->status = SCMI_SUCCESS;
218 }
219
220 return 0;
221}
222
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200223static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
224{
225 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
226 struct scmi_rd_attr_in *in = NULL;
227 struct scmi_rd_attr_out *out = NULL;
228 struct sandbox_scmi_reset *reset_state = NULL;
229
230 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
231 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
232 return -EINVAL;
233
234 in = (struct scmi_rd_attr_in *)msg->in_msg;
235 out = (struct scmi_rd_attr_out *)msg->out_msg;
236
237 reset_state = get_scmi_reset_state(agent->idx, in->domain_id);
238 if (!reset_state) {
239 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
240
241 out->status = SCMI_NOT_FOUND;
242 } else {
243 memset(out, 0, sizeof(*out));
244 snprintf(out->name, sizeof(out->name), "rd%u", in->domain_id);
245
246 out->status = SCMI_SUCCESS;
247 }
248
249 return 0;
250}
251
252static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
253{
254 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
255 struct scmi_rd_reset_in *in = NULL;
256 struct scmi_rd_reset_out *out = NULL;
257 struct sandbox_scmi_reset *reset_state = NULL;
258
259 if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
260 !msg->out_msg || msg->out_msg_sz < sizeof(*out))
261 return -EINVAL;
262
263 in = (struct scmi_rd_reset_in *)msg->in_msg;
264 out = (struct scmi_rd_reset_out *)msg->out_msg;
265
266 reset_state = get_scmi_reset_state(agent->idx, in->domain_id);
267 if (!reset_state) {
268 dev_err(dev, "Unexpected reset domain ID %u\n", in->domain_id);
269
270 out->status = SCMI_NOT_FOUND;
271 } else if (in->reset_state > 1) {
272 dev_err(dev, "Invalid reset domain input attribute value\n");
273
274 out->status = SCMI_INVALID_PARAMETERS;
275 } else {
276 if (in->flags & SCMI_RD_RESET_FLAG_CYCLE) {
277 if (in->flags & SCMI_RD_RESET_FLAG_ASYNC) {
278 out->status = SCMI_NOT_SUPPORTED;
279 } else {
280 /* Ends deasserted whatever current state */
281 reset_state->asserted = false;
282 out->status = SCMI_SUCCESS;
283 }
284 } else {
285 reset_state->asserted = in->flags &
286 SCMI_RD_RESET_FLAG_ASSERT;
287
288 out->status = SCMI_SUCCESS;
289 }
290 }
291
292 return 0;
293}
294
Etienne Carriere02fd1262020-09-09 18:44:00 +0200295static int sandbox_scmi_test_process_msg(struct udevice *dev,
296 struct scmi_msg *msg)
297{
298 switch (msg->protocol_id) {
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200299 case SCMI_PROTOCOL_ID_CLOCK:
300 switch (msg->message_id) {
301 case SCMI_CLOCK_RATE_SET:
302 return sandbox_scmi_clock_rate_set(dev, msg);
303 case SCMI_CLOCK_RATE_GET:
304 return sandbox_scmi_clock_rate_get(dev, msg);
305 case SCMI_CLOCK_CONFIG_SET:
306 return sandbox_scmi_clock_gate(dev, msg);
307 default:
308 break;
309 }
310 break;
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200311 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
312 switch (msg->message_id) {
313 case SCMI_RESET_DOMAIN_ATTRIBUTES:
314 return sandbox_scmi_rd_attribs(dev, msg);
315 case SCMI_RESET_DOMAIN_RESET:
316 return sandbox_scmi_rd_reset(dev, msg);
317 default:
318 break;
319 }
320 break;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200321 case SCMI_PROTOCOL_ID_BASE:
322 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
323 case SCMI_PROTOCOL_ID_SYSTEM:
324 case SCMI_PROTOCOL_ID_PERF:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200325 case SCMI_PROTOCOL_ID_SENSOR:
Etienne Carriere02fd1262020-09-09 18:44:00 +0200326 *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
327 return 0;
328 default:
329 break;
330 }
331
332 dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n",
333 __func__, dev->name, msg->protocol_id, msg->message_id);
334
335 if (msg->out_msg_sz < sizeof(u32))
336 return -EINVAL;
337
338 /* Intentionnaly report unhandled IDs through the SCMI return code */
339 *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR;
340 return 0;
341}
342
343static int sandbox_scmi_test_remove(struct udevice *dev)
344{
345 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
346
347 debug_print_agent_state(dev, "removed");
348
349 /* We only need to dereference the agent in the context */
350 sandbox_scmi_service_ctx()->agent[agent->idx] = NULL;
351
352 return 0;
353}
354
355static int sandbox_scmi_test_probe(struct udevice *dev)
356{
357 static const char basename[] = "sandbox-scmi-agent@";
358 struct sandbox_scmi_agent *agent = dev_get_priv(dev);
359 const size_t basename_size = sizeof(basename) - 1;
360
361 if (strncmp(basename, dev->name, basename_size))
362 return -ENOENT;
363
364 switch (dev->name[basename_size]) {
365 case '0':
366 *agent = (struct sandbox_scmi_agent){
367 .idx = 0,
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200368 .clk = scmi0_clk,
369 .clk_count = ARRAY_SIZE(scmi0_clk),
Etienne Carriere8b9b6892020-09-09 18:44:07 +0200370 .reset = scmi0_reset,
371 .reset_count = ARRAY_SIZE(scmi0_reset),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200372 };
373 break;
374 case '1':
375 *agent = (struct sandbox_scmi_agent){
376 .idx = 1,
Etienne Carriere2d94c08fa2020-09-09 18:44:05 +0200377 .clk = scmi1_clk,
378 .clk_count = ARRAY_SIZE(scmi1_clk),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200379 };
380 break;
381 default:
382 dev_err(dev, "%s(): Unexpected agent ID %s\n",
383 __func__, dev->name + basename_size);
384 return -ENOENT;
385 }
386
387 debug_print_agent_state(dev, "probed");
388
389 /* Save reference for tests purpose */
390 sandbox_scmi_service_ctx()->agent[agent->idx] = agent;
391
392 return 0;
393};
394
395static const struct udevice_id sandbox_scmi_test_ids[] = {
396 { .compatible = "sandbox,scmi-agent" },
397 { }
398};
399
400struct scmi_agent_ops sandbox_scmi_test_ops = {
401 .process_msg = sandbox_scmi_test_process_msg,
402};
403
404U_BOOT_DRIVER(sandbox_scmi_agent) = {
405 .name = "sandbox-scmi_agent",
406 .id = UCLASS_SCMI_AGENT,
407 .of_match = sandbox_scmi_test_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700408 .priv_auto = sizeof(struct sandbox_scmi_agent),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200409 .probe = sandbox_scmi_test_probe,
410 .remove = sandbox_scmi_test_remove,
411 .ops = &sandbox_scmi_test_ops,
412};