@@ -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;
}
@@ -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",
@@ -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.
*/
@@ -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 */
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(-)