summaryrefslogtreecommitdiff
path: root/drivers/firmware
diff options
context:
space:
mode:
authorAKASHI Takahiro <[email protected]>2023-10-11 19:06:54 +0900
committerTom Rini <[email protected]>2023-10-13 16:59:23 -0400
commitc6230cd8427c906baa52dbff5b95027ef58e6048 (patch)
tree3a1ca7d9de802439e9d702ebdad90066f0f8a173 /drivers/firmware
parentab9fbac81670478feccd439a5d84a67bd14d581d (diff)
scmi: refactor the code to hide a channel from devices
The commit 85dc58289238 ("firmware: scmi: prepare uclass to pass channel reference") added an explicit parameter, channel, but it seems to make the code complex. Hiding this parameter will allow for adding a generic (protocol-agnostic) helper function, i.e. for PROTOCOL_VERSION, in a later patch. Signed-off-by: AKASHI Takahiro <[email protected]> Reviewed-by: Simon Glass <[email protected]> Reviewed-by: Etienne Carriere <[email protected]>
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c105
1 files changed, 79 insertions, 26 deletions
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 02de692d66f..ec58ccd2bc5 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
+#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <dm/device_compat.h>
@@ -110,18 +111,23 @@ static int scmi_bind_protocols(struct udevice *dev)
return ret;
}
-static struct udevice *find_scmi_transport_device(struct udevice *dev)
+static struct udevice *find_scmi_protocol_device(struct udevice *dev)
{
- struct udevice *parent = dev;
+ struct udevice *parent = NULL, *protocol;
- do {
- parent = dev_get_parent(parent);
- } while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT);
+ for (protocol = dev; protocol; protocol = parent) {
+ parent = dev_get_parent(protocol);
+ if (!parent ||
+ device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
+ break;
+ }
- if (!parent)
+ if (!parent) {
dev_err(dev, "Invalid SCMI device, agent not found\n");
+ return NULL;
+ }
- return parent;
+ return protocol;
}
static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
@@ -129,43 +135,90 @@ static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
return (const struct scmi_agent_ops *)dev->driver->ops;
}
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
+/**
+ * scmi_of_get_channel() - Get SCMI channel handle
+ *
+ * @dev: SCMI agent device
+ * @channel: Output reference to the SCMI channel upon success
+ *
+ * On return, @channel will be set.
+ * Return 0 on success and a negative errno on failure
+ */
+static int scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
{
- struct udevice *parent;
+ const struct scmi_agent_ops *ops;
- parent = find_scmi_transport_device(dev);
- if (!parent)
+ ops = transport_dev_ops(dev);
+ if (ops->of_get_channel)
+ return ops->of_get_channel(dev, channel);
+ else
+ return -EPROTONOSUPPORT;
+}
+
+int devm_scmi_of_get_channel(struct udevice *dev)
+{
+ struct udevice *protocol;
+ struct scmi_agent_proto_priv *priv;
+ int ret;
+
+ protocol = find_scmi_protocol_device(dev);
+ if (!protocol)
return -ENODEV;
- if (transport_dev_ops(parent)->of_get_channel)
- return transport_dev_ops(parent)->of_get_channel(parent, channel);
+ priv = dev_get_parent_priv(protocol);
+ ret = scmi_of_get_channel(protocol->parent, &priv->channel);
+ if (ret == -EPROTONOSUPPORT) {
+ /* Drivers without a get_channel operator don't need a channel ref */
+ priv->channel = NULL;
- /* Drivers without a get_channel operator don't need a channel ref */
- *channel = NULL;
+ return 0;
+ }
- return 0;
+ return ret;
}
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
- struct scmi_msg *msg)
+/**
+ * scmi_process_msg() - Send and process an SCMI message
+ *
+ * Send a message to an SCMI server.
+ * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
+ *
+ * @dev: SCMI agent device
+ * @channel: Communication channel for the device
+ * @msg: Message structure reference
+ *
+ * On return, scmi_msg::out_msg_sz stores the response payload size.
+ * Return: 0 on success and a negative errno on failure
+ */
+static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
+ struct scmi_msg *msg)
{
const struct scmi_agent_ops *ops;
- struct udevice *parent;
- parent = find_scmi_transport_device(dev);
- if (!parent)
- return -ENODEV;
+ ops = transport_dev_ops(dev);
+ if (ops->process_msg)
+ return ops->process_msg(dev, channel, msg);
+ else
+ return -EPROTONOSUPPORT;
+}
- ops = transport_dev_ops(parent);
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct udevice *protocol;
+ struct scmi_agent_proto_priv *priv;
- if (ops->process_msg)
- return ops->process_msg(parent, channel, msg);
+ protocol = find_scmi_protocol_device(dev);
+ if (!protocol)
+ return -ENODEV;
+
+ priv = dev_get_parent_priv(protocol);
- return -EPROTONOSUPPORT;
+ return scmi_process_msg(protocol->parent, priv->channel, msg);
}
UCLASS_DRIVER(scmi_agent) = {
.id = UCLASS_SCMI_AGENT,
.name = "scmi_agent",
.post_bind = scmi_bind_protocols,
+ .per_child_auto = sizeof(struct scmi_agent_proto_priv),
};