xref: /rk3399_rockchip-uboot/drivers/firmware/scmi/scmi_agent-uclass.c (revision 3cdb50e61826b9de0e070cec703df08a030e5624)
11afcdfc6SEtienne Carriere // SPDX-License-Identifier: GPL-2.0+
21afcdfc6SEtienne Carriere /*
31afcdfc6SEtienne Carriere  * Copyright (C) 2020 Linaro Limited.
41afcdfc6SEtienne Carriere  */
51afcdfc6SEtienne Carriere 
61afcdfc6SEtienne Carriere #include <common.h>
71afcdfc6SEtienne Carriere #include <dm.h>
81afcdfc6SEtienne Carriere #include <errno.h>
91afcdfc6SEtienne Carriere #include <scmi_agent-uclass.h>
101afcdfc6SEtienne Carriere #include <scmi_protocols.h>
111afcdfc6SEtienne Carriere 
121afcdfc6SEtienne Carriere #include <dm/device-internal.h>
131afcdfc6SEtienne Carriere #include <linux/compat.h>
141afcdfc6SEtienne Carriere 
151afcdfc6SEtienne Carriere /**
161afcdfc6SEtienne Carriere  * struct error_code - Helper structure for SCMI error code conversion
171afcdfc6SEtienne Carriere  * @scmi:	SCMI error code
181afcdfc6SEtienne Carriere  * @errno:	Related standard error number
191afcdfc6SEtienne Carriere  */
201afcdfc6SEtienne Carriere struct error_code {
211afcdfc6SEtienne Carriere 	int scmi;
221afcdfc6SEtienne Carriere 	int errno;
231afcdfc6SEtienne Carriere };
241afcdfc6SEtienne Carriere 
251afcdfc6SEtienne Carriere static const struct error_code scmi_linux_errmap[] = {
261afcdfc6SEtienne Carriere 	{ .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
271afcdfc6SEtienne Carriere 	{ .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
281afcdfc6SEtienne Carriere 	{ .scmi = SCMI_DENIED, .errno = -EACCES, },
291afcdfc6SEtienne Carriere 	{ .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
301afcdfc6SEtienne Carriere 	{ .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
311afcdfc6SEtienne Carriere 	{ .scmi = SCMI_BUSY, .errno = -EBUSY, },
321afcdfc6SEtienne Carriere 	{ .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
331afcdfc6SEtienne Carriere 	{ .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
341afcdfc6SEtienne Carriere 	{ .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
351afcdfc6SEtienne Carriere 	{ .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
361afcdfc6SEtienne Carriere };
371afcdfc6SEtienne Carriere 
381afcdfc6SEtienne Carriere int scmi_to_linux_errno(s32 scmi_code)
391afcdfc6SEtienne Carriere {
401afcdfc6SEtienne Carriere 	int n;
411afcdfc6SEtienne Carriere 
421afcdfc6SEtienne Carriere 	if (!scmi_code)
431afcdfc6SEtienne Carriere 		return 0;
441afcdfc6SEtienne Carriere 
451afcdfc6SEtienne Carriere 	for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
461afcdfc6SEtienne Carriere 		if (scmi_code == scmi_linux_errmap[n].scmi)
471afcdfc6SEtienne Carriere 			return scmi_linux_errmap[1].errno;
481afcdfc6SEtienne Carriere 
491afcdfc6SEtienne Carriere 	return -EPROTO;
501afcdfc6SEtienne Carriere }
511afcdfc6SEtienne Carriere 
521afcdfc6SEtienne Carriere /*
531afcdfc6SEtienne Carriere  * SCMI agent devices binds devices of various uclasses depeding on
541afcdfc6SEtienne Carriere  * the FDT description. scmi_bind_protocol() is a generic bind sequence
551afcdfc6SEtienne Carriere  * called by the uclass at bind stage, that is uclass post_bind.
561afcdfc6SEtienne Carriere  */
571afcdfc6SEtienne Carriere static int scmi_bind_protocols(struct udevice *dev)
581afcdfc6SEtienne Carriere {
591afcdfc6SEtienne Carriere 	int ret = 0;
601afcdfc6SEtienne Carriere 	ofnode node;
611afcdfc6SEtienne Carriere 
621afcdfc6SEtienne Carriere 	dev_for_each_subnode(node, dev) {
637c4b6f22SEtienne Carriere 		struct driver *drv = NULL;
641afcdfc6SEtienne Carriere 		u32 protocol_id;
651afcdfc6SEtienne Carriere 
661afcdfc6SEtienne Carriere 		if (!ofnode_is_available(node))
671afcdfc6SEtienne Carriere 			continue;
681afcdfc6SEtienne Carriere 
691afcdfc6SEtienne Carriere 		if (ofnode_read_u32(node, "reg", &protocol_id))
701afcdfc6SEtienne Carriere 			continue;
711afcdfc6SEtienne Carriere 
721afcdfc6SEtienne Carriere 		switch (protocol_id) {
737c4b6f22SEtienne Carriere 		case SCMI_PROTOCOL_ID_CLOCK:
747c4b6f22SEtienne Carriere 			if (IS_ENABLED(CONFIG_CLK_SCMI))
757c4b6f22SEtienne Carriere 				drv = DM_GET_DRIVER(scmi_clock);
767c4b6f22SEtienne Carriere 			break;
77*3cdb50e6SEtienne Carriere 		case SCMI_PROTOCOL_ID_RESET_DOMAIN:
78*3cdb50e6SEtienne Carriere 			if (IS_ENABLED(CONFIG_RESET_SCMI))
79*3cdb50e6SEtienne Carriere 				drv = DM_GET_DRIVER(scmi_reset_domain);
80*3cdb50e6SEtienne Carriere 			break;
811afcdfc6SEtienne Carriere 		default:
827c4b6f22SEtienne Carriere 			break;
837c4b6f22SEtienne Carriere 		}
847c4b6f22SEtienne Carriere 
857c4b6f22SEtienne Carriere 		if (!drv) {
867c4b6f22SEtienne Carriere 			dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
871afcdfc6SEtienne Carriere 				protocol_id);
881afcdfc6SEtienne Carriere 			continue;
891afcdfc6SEtienne Carriere 		}
901afcdfc6SEtienne Carriere 
911afcdfc6SEtienne Carriere 		ret = device_bind_ofnode(dev, drv, ofnode_get_name(node),
921afcdfc6SEtienne Carriere 					 NULL, node, NULL);
931afcdfc6SEtienne Carriere 		if (ret)
941afcdfc6SEtienne Carriere 			break;
951afcdfc6SEtienne Carriere 	}
961afcdfc6SEtienne Carriere 
971afcdfc6SEtienne Carriere 	return ret;
981afcdfc6SEtienne Carriere }
991afcdfc6SEtienne Carriere 
1001afcdfc6SEtienne Carriere static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
1011afcdfc6SEtienne Carriere {
1021afcdfc6SEtienne Carriere 	return (const struct scmi_agent_ops *)dev->driver->ops;
1031afcdfc6SEtienne Carriere }
1041afcdfc6SEtienne Carriere 
1051afcdfc6SEtienne Carriere int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
1061afcdfc6SEtienne Carriere {
1071afcdfc6SEtienne Carriere 	const struct scmi_agent_ops *ops = transport_dev_ops(dev);
1081afcdfc6SEtienne Carriere 
1091afcdfc6SEtienne Carriere 	if (ops->process_msg)
1101afcdfc6SEtienne Carriere 		return ops->process_msg(dev, msg);
1111afcdfc6SEtienne Carriere 
1121afcdfc6SEtienne Carriere 	return -EPROTONOSUPPORT;
1131afcdfc6SEtienne Carriere }
1141afcdfc6SEtienne Carriere 
1151afcdfc6SEtienne Carriere UCLASS_DRIVER(scmi_agent) = {
1161afcdfc6SEtienne Carriere 	.id		= UCLASS_SCMI_AGENT,
1171afcdfc6SEtienne Carriere 	.name		= "scmi_agent",
1181afcdfc6SEtienne Carriere 	.post_bind	= scmi_bind_protocols,
1191afcdfc6SEtienne Carriere };
120