blob: 1d41a8a98fc61b113f255e233589fea28d4f2b85 [file] [log] [blame]
AKASHI Takahirod1ce56a2023-10-11 19:07:00 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * SCMI Base protocol as U-Boot device
4 *
5 * Copyright (C) 2023 Linaro Limited
6 * author: AKASHI Takahiro <takahiro.akashi@linaro.org>
7 */
8
9#include <common.h>
10#include <dm.h>
11#include <scmi_agent.h>
12#include <scmi_protocols.h>
13#include <stdlib.h>
14#include <string.h>
15#include <asm/types.h>
16#include <dm/device_compat.h>
17#include <linux/kernel.h>
18
19/**
20 * scmi_generic_protocol_version - get protocol version
21 * @dev: SCMI device
22 * @id: SCMI protocol ID
23 * @version: Pointer to SCMI protocol version
24 *
25 * Obtain the protocol version number in @version.
26 *
27 * Return: 0 on success, error code on failure
28 */
29int scmi_generic_protocol_version(struct udevice *dev,
30 enum scmi_std_protocol id, u32 *version)
31{
32 struct scmi_protocol_version_out out;
33 struct scmi_msg msg = {
34 .protocol_id = id,
35 .message_id = SCMI_PROTOCOL_VERSION,
36 .out_msg = (u8 *)&out,
37 .out_msg_sz = sizeof(out),
38 };
39 int ret;
40
41 ret = devm_scmi_process_msg(dev, &msg);
42 if (ret)
43 return ret;
44 if (out.status)
45 return scmi_to_linux_errno(out.status);
46
47 *version = out.version;
48
49 return 0;
50}
51
52/**
53 * scmi_base_protocol_version_int - get Base protocol version
54 * @dev: SCMI device
55 * @version: Pointer to SCMI protocol version
56 *
57 * Obtain the protocol version number in @version for Base protocol.
58 *
59 * Return: 0 on success, error code on failure
60 */
61static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version)
62{
63 return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE,
64 version);
65}
66
67/**
68 * scmi_protocol_attrs_int - get protocol attributes
69 * @dev: SCMI device
70 * @num_agents: Number of SCMI agents
71 * @num_protocols: Number of SCMI protocols
72 *
73 * Obtain the protocol attributes, the number of agents and the number
74 * of protocols, in @num_agents and @num_protocols respectively, that
75 * the device provides.
76 *
77 * Return: 0 on success, error code on failure
78 */
79static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents,
80 u32 *num_protocols)
81{
82 struct scmi_protocol_attrs_out out;
83 struct scmi_msg msg = {
84 .protocol_id = SCMI_PROTOCOL_ID_BASE,
85 .message_id = SCMI_PROTOCOL_ATTRIBUTES,
86 .out_msg = (u8 *)&out,
87 .out_msg_sz = sizeof(out),
88 };
89 int ret;
90
91 ret = devm_scmi_process_msg(dev, &msg);
92 if (ret)
93 return ret;
94 if (out.status)
95 return scmi_to_linux_errno(out.status);
96
97 *num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes);
98 *num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes);
99
100 return 0;
101}
102
103/**
104 * scmi_protocol_message_attrs_int - get message-specific attributes
105 * @dev: SCMI device
106 * @message_id: SCMI message ID
107 * @attributes: Message-specific attributes
108 *
109 * Obtain the message-specific attributes in @attributes.
110 * This command succeeds if the message is implemented and available.
111 *
112 * Return: 0 on success, error code on failure
113 */
114static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id,
115 u32 *attributes)
116{
117 struct scmi_protocol_msg_attrs_out out;
118 struct scmi_msg msg = {
119 .protocol_id = SCMI_PROTOCOL_ID_BASE,
120 .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES,
121 .in_msg = (u8 *)&message_id,
122 .in_msg_sz = sizeof(message_id),
123 .out_msg = (u8 *)&out,
124 .out_msg_sz = sizeof(out),
125 };
126 int ret;
127
128 ret = devm_scmi_process_msg(dev, &msg);
129 if (ret)
130 return ret;
131 if (out.status)
132 return scmi_to_linux_errno(out.status);
133
134 *attributes = out.attributes;
135
136 return 0;
137}
138
139/**
140 * scmi_base_discover_vendor_int - get vendor name
141 * @dev: SCMI device
142 * @vendor: Pointer to vendor name
143 *
144 * Obtain the vendor's name in @vendor.
145 * It is a caller's responsibility to free @vendor.
146 *
147 * Return: 0 on success, error code on failure
148 */
149static int scmi_base_discover_vendor_int(struct udevice *dev, u8 **vendor)
150{
151 struct scmi_base_discover_vendor_out out;
152 struct scmi_msg msg = {
153 .protocol_id = SCMI_PROTOCOL_ID_BASE,
154 .message_id = SCMI_BASE_DISCOVER_VENDOR,
155 .out_msg = (u8 *)&out,
156 .out_msg_sz = sizeof(out),
157 };
158 int ret;
159
160 if (!vendor)
161 return -EINVAL;
162
163 ret = devm_scmi_process_msg(dev, &msg);
164 if (ret)
165 return ret;
166 if (out.status)
167 return scmi_to_linux_errno(out.status);
168
169 *vendor = strdup(out.vendor_identifier);
170 if (!*vendor)
171 return -ENOMEM;
172
173 return 0;
174}
175
176/**
177 * scmi_base_discover_sub_vendor_int - get sub-vendor name
178 * @dev: SCMI device
179 * @sub_vendor: Pointer to sub-vendor name
180 *
181 * Obtain the sub-vendor's name in @sub_vendor.
182 * It is a caller's responsibility to free @sub_vendor.
183 *
184 * Return: 0 on success, error code on failure
185 */
186static int scmi_base_discover_sub_vendor_int(struct udevice *dev,
187 u8 **sub_vendor)
188{
189 struct scmi_base_discover_vendor_out out;
190 struct scmi_msg msg = {
191 .protocol_id = SCMI_PROTOCOL_ID_BASE,
192 .message_id = SCMI_BASE_DISCOVER_SUB_VENDOR,
193 .out_msg = (u8 *)&out,
194 .out_msg_sz = sizeof(out),
195 };
196 int ret;
197
198 if (!sub_vendor)
199 return -EINVAL;
200
201 ret = devm_scmi_process_msg(dev, &msg);
202 if (ret)
203 return ret;
204 if (out.status)
205 return scmi_to_linux_errno(out.status);
206
207 *sub_vendor = strdup(out.vendor_identifier);
208 if (!*sub_vendor)
209 return -ENOMEM;
210
211 return 0;
212}
213
214/**
215 * scmi_base_discover_impl_version_int - get implementation version
216 * @dev: SCMI device
217 * @impl_version: Pointer to implementation version
218 *
219 * Obtain the implementation version number in @impl_version.
220 *
221 * Return: 0 on success, error code on failure
222 */
223static int scmi_base_discover_impl_version_int(struct udevice *dev,
224 u32 *impl_version)
225{
226 struct scmi_base_discover_impl_version_out out;
227 struct scmi_msg msg = {
228 .protocol_id = SCMI_PROTOCOL_ID_BASE,
229 .message_id = SCMI_BASE_DISCOVER_IMPL_VERSION,
230 .out_msg = (u8 *)&out,
231 .out_msg_sz = sizeof(out),
232 };
233 int ret;
234
235 ret = devm_scmi_process_msg(dev, &msg);
236 if (ret)
237 return ret;
238 if (out.status)
239 return scmi_to_linux_errno(out.status);
240
241 *impl_version = out.impl_version;
242
243 return 0;
244}
245
246/**
247 * scmi_base_discover_list_protocols_int - get list of protocols
248 * @dev: SCMI device
249 * @protocols: Pointer to array of SCMI protocols
250 *
251 * Obtain the list of protocols provided in @protocols.
252 * The number of elements in @protocols always match to the number of
253 * protocols returned by smci_protocol_attrs() when this function succeeds.
254 * It is a caller's responsibility to free @protocols.
255 *
256 * Return: the number of protocols in @protocols on success, error code on
257 * failure
258 */
259static int scmi_base_discover_list_protocols_int(struct udevice *dev,
260 u8 **protocols)
261{
262 struct scmi_base_discover_list_protocols_out out;
263 int cur;
264 struct scmi_msg msg = {
265 .protocol_id = SCMI_PROTOCOL_ID_BASE,
266 .message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS,
267 .in_msg = (u8 *)&cur,
268 .in_msg_sz = sizeof(cur),
269 .out_msg = (u8 *)&out,
270 .out_msg_sz = sizeof(out),
271 };
272 u32 num_agents, num_protocols;
273 u8 *buf;
274 int i, ret;
275
276 ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols);
277 if (ret)
278 return ret;
279
280 buf = calloc(sizeof(u8), num_protocols);
281 if (!buf)
282 return -ENOMEM;
283
284 cur = 0;
285 do {
286 ret = devm_scmi_process_msg(dev, &msg);
287 if (ret)
288 goto err;
289 if (out.status) {
290 ret = scmi_to_linux_errno(out.status);
291 goto err;
292 }
293
294 for (i = 0; i < out.num_protocols; i++, cur++)
295 buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8);
296 } while (cur < num_protocols);
297
298 *protocols = buf;
299
300 return num_protocols;
301err:
302 free(buf);
303
304 return ret;
305}
306
307/**
308 * scmi_base_discover_agent_int - identify agent
309 * @dev: SCMI device
310 * @agent_id: SCMI agent ID
311 * @ret_agent_id: Pointer to SCMI agent ID
312 * @name: Pointer to SCMI agent name
313 *
314 * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
315 * this function returns the caller's agent id in @ret_agent_id.
316 * It is a caller's responsibility to free @name.
317 *
318 * Return: 0 on success, error code on failure
319 */
320static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id,
321 u32 *ret_agent_id, u8 **name)
322{
323 struct scmi_base_discover_agent_out out;
324 struct scmi_msg msg = {
325 .protocol_id = SCMI_PROTOCOL_ID_BASE,
326 .message_id = SCMI_BASE_DISCOVER_AGENT,
327 .in_msg = (u8 *)&agent_id,
328 .in_msg_sz = sizeof(agent_id),
329 .out_msg = (u8 *)&out,
330 .out_msg_sz = sizeof(out),
331 };
332 int ret;
333
334 ret = devm_scmi_process_msg(dev, &msg);
335 if (ret)
336 return ret;
337 if (out.status)
338 return scmi_to_linux_errno(out.status);
339
340 if (ret_agent_id)
341 *ret_agent_id = out.agent_id;
342 if (name) {
343 *name = strdup(out.name);
344 if (!*name)
345 return -ENOMEM;
346 }
347
348 return 0;
349}
350
351/**
352 * scmi_base_set_device_permissions_int - configure access permission to device
353 * @dev: SCMI device
354 * @agent_id: SCMI agent ID
355 * @device_id: ID of device to access
356 * @flags: A set of flags
357 *
358 * Ask for allowing or denying access permission to the device, @device_id.
359 * The meaning of @flags is defined in SCMI specification.
360 *
361 * Return: 0 on success, error code on failure
362 */
363static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id,
364 u32 device_id, u32 flags)
365{
366 struct scmi_base_set_device_permissions_in in = {
367 .agent_id = agent_id,
368 .device_id = device_id,
369 .flags = flags,
370 };
371 s32 status;
372 struct scmi_msg msg = {
373 .protocol_id = SCMI_PROTOCOL_ID_BASE,
374 .message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS,
375 .in_msg = (u8 *)&in,
376 .in_msg_sz = sizeof(in),
377 .out_msg = (u8 *)&status,
378 .out_msg_sz = sizeof(status),
379 };
380 int ret;
381
382 ret = devm_scmi_process_msg(dev, &msg);
383 if (ret)
384 return ret;
385 if (status)
386 return scmi_to_linux_errno(status);
387
388 return 0;
389}
390
391/**
392 * scmi_base_set_protocol_permissions_int - configure access permission to
393 * protocol on device
394 * @dev: SCMI device
395 * @agent_id: SCMI agent ID
396 * @device_id: ID of device to access
397 * @command_id: SCMI command ID
398 * @flags: A set of flags
399 *
400 * Ask for allowing or denying access permission to the protocol, @command_id,
401 * on the device, @device_id.
402 * The meaning of @flags is defined in SCMI specification.
403 *
404 * Return: 0 on success, error code on failure
405 */
406static int scmi_base_set_protocol_permissions_int(struct udevice *dev,
407 u32 agent_id, u32 device_id,
408 u32 command_id, u32 flags)
409{
410 struct scmi_base_set_protocol_permissions_in in = {
411 .agent_id = agent_id,
412 .device_id = device_id,
413 .command_id = command_id,
414 .flags = flags,
415 };
416 s32 status;
417 struct scmi_msg msg = {
418 .protocol_id = SCMI_PROTOCOL_ID_BASE,
419 .message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS,
420 .in_msg = (u8 *)&in,
421 .in_msg_sz = sizeof(in),
422 .out_msg = (u8 *)&status,
423 .out_msg_sz = sizeof(status),
424 };
425 int ret;
426
427 ret = devm_scmi_process_msg(dev, &msg);
428 if (ret)
429 return ret;
430 if (status)
431 return scmi_to_linux_errno(status);
432
433 return 0;
434}
435
436/**
437 * scmi_base_reset_agent_configuration_int - reset resource settings
438 * @dev: SCMI device
439 * @agent_id: SCMI agent ID
440 * @flags: A set of flags
441 *
442 * Reset all the resource settings against @agent_id.
443 * The meaning of @flags is defined in SCMI specification.
444 *
445 * Return: 0 on success, error code on failure
446 */
447static int scmi_base_reset_agent_configuration_int(struct udevice *dev,
448 u32 agent_id, u32 flags)
449{
450 struct scmi_base_reset_agent_configuration_in in = {
451 .agent_id = agent_id,
452 .flags = flags,
453 };
454 s32 status;
455 struct scmi_msg msg = {
456 .protocol_id = SCMI_PROTOCOL_ID_BASE,
457 .message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION,
458 .in_msg = (u8 *)&in,
459 .in_msg_sz = sizeof(in),
460 .out_msg = (u8 *)&status,
461 .out_msg_sz = sizeof(status),
462 };
463 int ret;
464
465 ret = devm_scmi_process_msg(dev, &msg);
466 if (ret)
467 return ret;
468 if (status)
469 return scmi_to_linux_errno(status);
470
471 return 0;
472}
473
474/**
475 * scmi_base_probe - probe base protocol device
476 * @dev: SCMI device
477 *
478 * Probe the device for SCMI base protocol and initialize the private data.
479 *
480 * Return: 0 on success, error code on failure
481 */
482static int scmi_base_probe(struct udevice *dev)
483{
AKASHI Takahiro3413c312023-10-11 19:07:01 +0900484 u32 version;
AKASHI Takahirod1ce56a2023-10-11 19:07:00 +0900485 int ret;
486
487 ret = devm_scmi_of_get_channel(dev);
488 if (ret) {
489 dev_err(dev, "get_channel failed\n");
490 return ret;
491 }
AKASHI Takahiro3413c312023-10-11 19:07:01 +0900492 ret = scmi_base_protocol_version_int(dev, &version);
493 if (ret) {
494 dev_err(dev, "getting protocol version failed\n");
495 return ret;
496 }
497 if (version < SCMI_BASE_PROTOCOL_VERSION)
498 return -EINVAL;
AKASHI Takahirod1ce56a2023-10-11 19:07:00 +0900499
500 return ret;
501}
502
503static struct scmi_base_ops scmi_base_ops = {
504 /* Commands */
505 .protocol_version = scmi_base_protocol_version_int,
506 .protocol_attrs = scmi_protocol_attrs_int,
507 .protocol_message_attrs = scmi_protocol_message_attrs_int,
508 .base_discover_vendor = scmi_base_discover_vendor_int,
509 .base_discover_sub_vendor = scmi_base_discover_sub_vendor_int,
510 .base_discover_impl_version = scmi_base_discover_impl_version_int,
511 .base_discover_list_protocols = scmi_base_discover_list_protocols_int,
512 .base_discover_agent = scmi_base_discover_agent_int,
513 .base_notify_errors = NULL,
514 .base_set_device_permissions = scmi_base_set_device_permissions_int,
515 .base_set_protocol_permissions = scmi_base_set_protocol_permissions_int,
516 .base_reset_agent_configuration =
517 scmi_base_reset_agent_configuration_int,
518};
519
520int scmi_base_protocol_version(struct udevice *dev, u32 *version)
521{
522 const struct scmi_base_ops *ops = device_get_ops(dev);
523
524 if (ops->protocol_version)
525 return (*ops->protocol_version)(dev, version);
526
527 return -EOPNOTSUPP;
528}
529
530int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
531 u32 *num_protocols)
532{
533 const struct scmi_base_ops *ops = device_get_ops(dev);
534
535 if (ops->protocol_attrs)
536 return (*ops->protocol_attrs)(dev, num_agents, num_protocols);
537
538 return -EOPNOTSUPP;
539}
540
541int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
542 u32 *attributes)
543{
544 const struct scmi_base_ops *ops = device_get_ops(dev);
545
546 if (ops->protocol_message_attrs)
547 return (*ops->protocol_message_attrs)(dev, message_id,
548 attributes);
549
550 return -EOPNOTSUPP;
551}
552
553int scmi_base_discover_vendor(struct udevice *dev, u8 **vendor)
554{
555 const struct scmi_base_ops *ops = device_get_ops(dev);
556
557 if (ops->base_discover_vendor)
558 return (*ops->base_discover_vendor)(dev, vendor);
559
560 return -EOPNOTSUPP;
561}
562
563int scmi_base_discover_sub_vendor(struct udevice *dev, u8 **sub_vendor)
564{
565 const struct scmi_base_ops *ops = device_get_ops(dev);
566
567 if (ops->base_discover_sub_vendor)
568 return (*ops->base_discover_sub_vendor)(dev, sub_vendor);
569
570 return -EOPNOTSUPP;
571}
572
573int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version)
574{
575 const struct scmi_base_ops *ops = device_get_ops(dev);
576
577 if (ops->base_discover_impl_version)
578 return (*ops->base_discover_impl_version)(dev, impl_version);
579
580 return -EOPNOTSUPP;
581}
582
583int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols)
584{
585 const struct scmi_base_ops *ops = device_get_ops(dev);
586
587 if (ops->base_discover_list_protocols)
588 return (*ops->base_discover_list_protocols)(dev, protocols);
589
590 return -EOPNOTSUPP;
591}
592
593int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
594 u32 *ret_agent_id, u8 **name)
595{
596 const struct scmi_base_ops *ops = device_get_ops(dev);
597
598 if (ops->base_discover_agent)
599 return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id,
600 name);
601
602 return -EOPNOTSUPP;
603}
604
605int scmi_base_notify_errors(struct udevice *dev, u32 enable)
606{
607 const struct scmi_base_ops *ops = device_get_ops(dev);
608
609 if (ops->base_notify_errors)
610 return (*ops->base_notify_errors)(dev, enable);
611
612 return -EOPNOTSUPP;
613}
614
615int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
616 u32 device_id, u32 flags)
617{
618 const struct scmi_base_ops *ops = device_get_ops(dev);
619
620 if (ops->base_set_device_permissions)
621 return (*ops->base_set_device_permissions)(dev, agent_id,
622 device_id, flags);
623
624 return -EOPNOTSUPP;
625}
626
627int scmi_base_set_protocol_permissions(struct udevice *dev,
628 u32 agent_id, u32 device_id,
629 u32 command_id, u32 flags)
630{
631 const struct scmi_base_ops *ops = device_get_ops(dev);
632
633 if (ops->base_set_protocol_permissions)
634 return (*ops->base_set_protocol_permissions)(dev, agent_id,
635 device_id,
636 command_id,
637 flags);
638
639 return -EOPNOTSUPP;
640}
641
642int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
643 u32 flags)
644{
645 const struct scmi_base_ops *ops = device_get_ops(dev);
646
647 if (ops->base_reset_agent_configuration)
648 return (*ops->base_reset_agent_configuration)(dev, agent_id,
649 flags);
650
651 return -EOPNOTSUPP;
652}
653
654U_BOOT_DRIVER(scmi_base_drv) = {
655 .id = UCLASS_SCMI_BASE,
656 .name = "scmi_base_drv",
657 .ops = &scmi_base_ops,
658 .probe = scmi_base_probe,
659};
660
661UCLASS_DRIVER(scmi_base) = {
662 .id = UCLASS_SCMI_BASE,
663 .name = "scmi_base",
664};