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