diff mbox series

[03/10] firmware: scmi: install base protocol to SCMI agent

Message ID 20230628004841.21774-4-takahiro.akashi@linaro.org
State New
Headers show
Series firmware: scmi: add SCMI base protocol support | expand

Commit Message

AKASHI Takahiro June 28, 2023, 12:48 a.m. UTC
SCMI base protocol is mandatory, and once SCMI node is found in a device
tree, the protocol handle (udevice) is unconditionally installed to
the agent. Then basic information will be retrieved from SCMI server via
the protocol and saved into the agent instance's local storage.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 drivers/firmware/scmi/base.c              |   6 ++
 drivers/firmware/scmi/scmi_agent-uclass.c | 104 ++++++++++++++++++++++
 include/scmi_agent-uclass.h               |  78 +++++++++++++++-
 include/scmi_agent.h                      |  10 +++
 4 files changed, 195 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/drivers/firmware/scmi/base.c b/drivers/firmware/scmi/base.c
index 04018eb6ecf3..224e0ca7a915 100644
--- a/drivers/firmware/scmi/base.c
+++ b/drivers/firmware/scmi/base.c
@@ -484,6 +484,12 @@  static int scmi_base_probe(struct udevice *dev)
 		return ret;
 	}
 
+	ret = scmi_fill_base_info(dev->parent);
+	if (ret) {
+		dev_err(dev, "get information failed\n");
+		return ret;
+	}
+
 	return ret;
 }
 
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 6fd948ae6ddf..ec15580cc947 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -56,6 +56,9 @@  struct udevice *scmi_get_protocol(struct udevice *dev,
 	}
 
 	switch (id) {
+	case SCMI_PROTOCOL_ID_BASE:
+		proto = priv->base_dev;
+		break;
 	case SCMI_PROTOCOL_ID_CLOCK:
 		proto = priv->clock_dev;
 		break;
@@ -100,6 +103,9 @@  static int scmi_add_protocol(struct udevice *dev,
 	}
 
 	switch (proto_id) {
+	case SCMI_PROTOCOL_ID_BASE:
+		priv->base_dev = proto;
+		break;
 	case SCMI_PROTOCOL_ID_CLOCK:
 		priv->clock_dev = proto;
 		break;
@@ -149,6 +155,20 @@  static int scmi_bind_protocols(struct udevice *dev)
 		return -EBUSY;
 	}
 
+	drv = DM_DRIVER_GET(scmi_base_drv);
+	name = "scmi-base.0";
+	ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
+	if (ret) {
+		dev_err(dev, "failed to bind base protocol\n");
+		return ret;
+	}
+	ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
+	if (ret) {
+		dev_err(dev, "failed to add protocol: %s, ret: %d\n",
+			proto->name, ret);
+		return ret;
+	}
+
 	dev_for_each_subnode(node, dev) {
 		u32 protocol_id;
 
@@ -262,6 +282,90 @@  int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
 	return -EPROTONOSUPPORT;
 }
 
+int scmi_fill_base_info(struct udevice *dev)
+{
+	struct scmi_agent_priv *priv;
+	struct udevice *base;
+	const struct scmi_base_ops *ops;
+	int ret;
+
+	priv = dev_get_uclass_plat(dev);
+
+	base = priv->base_dev;
+	if (!base) {
+		dev_err(dev, "Base protocol not found\n");
+		return -EPROTO;
+	}
+
+	ops = dev_get_driver_ops(base);
+	if (!ops) {
+		dev_err(base, "Operations in Base protocol not found\n");
+		return -EPROTO;
+	}
+	ret = (*ops->protocol_version)(base, &priv->version);
+	if (ret) {
+		dev_err(base, "protocol_version() failed (%d)\n", ret);
+		return ret;
+	}
+	/* check for required version */
+	if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
+		dev_err(base, "base protocol version (%d) lower than expected\n",
+			priv->version);
+		return -EPROTO;
+	}
+
+	ret = (*ops->protocol_attrs)(base, &priv->num_agents,
+				     &priv->num_protocols);
+	if (ret) {
+		dev_err(base, "protocol_attrs() failed (%d)\n", ret);
+		return ret;
+	}
+	ret = (*ops->base_discover_vendor)(base, priv->vendor);
+	if (ret) {
+		dev_err(base, "base_discover_vendor() failed (%d)\n", ret);
+		return ret;
+	}
+	ret = (*ops->base_discover_sub_vendor)(base, priv->sub_vendor);
+	if (ret) {
+		if (ret != -EOPNOTSUPP) {
+			dev_err(base, "base_discover_sub_vendor() failed (%d)\n",
+				ret);
+			return ret;
+		}
+		strcpy(priv->sub_vendor, "NA");
+	}
+	ret = (*ops->base_discover_impl_version)(base,
+						 &priv->impl_version);
+	if (ret) {
+		dev_err(base, "base_discover_impl_version() failed (%d)\n",
+			ret);
+		return ret;
+	}
+
+	priv->agent_id = 0xffffffff; /* to avoid false claim */
+	ret = (*ops->base_discover_agent)(base, 0xffffffff,
+					  &priv->agent_id, priv->agent_name);
+	if (ret) {
+		if (ret != -EOPNOTSUPP) {
+			dev_err(base,
+				"base_discover_agent() failed for myself (%d)\n",
+				ret);
+			return ret;
+		}
+		priv->agent_name[0] = '\0';
+	}
+
+	ret = (*ops->base_discover_list_protocols)(base,
+						    &priv->protocols);
+	if (ret != priv->num_protocols) {
+		dev_err(base, "base_discover_list_protocols() failed (%d)\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 UCLASS_DRIVER(scmi_agent) = {
 	.id		= UCLASS_SCMI_AGENT,
 	.name		= "scmi_agent",
diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h
index 6c3d1321b1aa..8ead08b38fb1 100644
--- a/include/scmi_agent-uclass.h
+++ b/include/scmi_agent-uclass.h
@@ -5,22 +5,94 @@ 
 #ifndef _SCMI_AGENT_UCLASS_H
 #define _SCMI_AGENT_UCLASS_H
 
+#include <scmi_protocols.h>
+
 struct udevice;
 struct scmi_msg;
 struct scmi_channel;
 
 /**
  * struct scmi_agent_priv - private data maintained by agent instance
- * @clock_dev:	SCMI clock protocol device
- * @clock_dev:	SCMI reset domain protocol device
- * @clock_dev:	SCMI voltage domain protocol device
+ * @version:		Version
+ * @num_agents:		Number of agents
+ * @num_protocols:	Number of protocols
+ * @impl_version:	Implementation version
+ * @protocols:		Array of protocol IDs
+ * @vendor:		Vendor name
+ * @sub_vendor:		Sub-vendor name
+ * @agent_name:		Agent name
+ * agent_id:		Identifier of agent
+ * @base_dev:		SCMI base protocol device
+ * @clock_dev:		SCMI block protocol device
+ * @clock_dev:		SCMI reset domain protocol device
+ * @clock_dev:		SCMI voltage domain protocol device
  */
 struct scmi_agent_priv {
+	u32 version;
+	u32 num_agents;
+	u32 num_protocols;
+	u32 impl_version;
+	u8 *protocols;
+	u8 vendor[SCMI_BASE_NAME_LENGTH_MAX];
+	u8 sub_vendor[SCMI_BASE_NAME_LENGTH_MAX];
+	u8 agent_name[SCMI_BASE_NAME_LENGTH_MAX];
+	u32 agent_id;
+	struct udevice *base_dev;
 	struct udevice *clock_dev;
 	struct udevice *resetdom_dev;
 	struct udevice *voltagedom_dev;
 };
 
+static inline u32 scmi_version(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->version;
+}
+
+static inline u32 scmi_num_agents(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_agents;
+}
+
+static inline u32 scmi_num_protocols(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_protocols;
+}
+
+static inline u32 scmi_impl_version(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->impl_version;
+}
+
+static inline u8 *scmi_protocols(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->protocols;
+}
+
+static inline u8 *scmi_vendor(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->vendor;
+}
+
+static inline u8 *scmi_sub_vendor(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->sub_vendor;
+}
+
+static inline u8 *scmi_agent_name(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_name;
+}
+
+static inline u32 scmi_agent_id(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id;
+}
+
+static inline struct udevice *scmi_base_dev(struct udevice *dev)
+{
+	return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->base_dev;
+}
+
 /**
  * struct scmi_transport_ops - The functions that a SCMI transport layer must implement.
  */
diff --git a/include/scmi_agent.h b/include/scmi_agent.h
index f77c10f7abfd..07e99f19726e 100644
--- a/include/scmi_agent.h
+++ b/include/scmi_agent.h
@@ -91,4 +91,14 @@  struct udevice *scmi_get_protocol(struct udevice *dev,
  */
 int scmi_to_linux_errno(s32 scmi_errno);
 
+/**
+ * scmi_fill_base_info - fill information about services by SCMI server
+ * @dev:        SCMI device
+ *
+ * Fill basic information about services provided by SCMI server
+ *
+ * Return:      0 on success, error code otherwise
+ */
+int scmi_fill_base_info(struct udevice *dev);
+
 #endif /* SCMI_H */