Add a mostly complete list of ofnode analogs of of_graph
parsing helpers.

Signed-off-by: Svyatoslav Ryhel <clamo...@gmail.com>
---
 drivers/core/Makefile       |   2 +-
 drivers/core/ofnode_graph.c | 217 ++++++++++++++++++++++++++++++++++++
 include/dm/ofnode_graph.h   |  90 +++++++++++++++
 3 files changed, 308 insertions(+), 1 deletion(-)
 create mode 100644 drivers/core/ofnode_graph.c
 create mode 100644 include/dm/ofnode_graph.h

diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 9ea57911f89..657e589c286 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -16,6 +16,6 @@ ifndef CONFIG_DM_DEV_READ_INLINE
 obj-$(CONFIG_OF_CONTROL) += read.o
 endif
 obj-$(CONFIG_$(XPL_)OF_PLATDATA) += read.o
-obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o
+obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o ofnode_graph.o
 
 ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG
diff --git a/drivers/core/ofnode_graph.c b/drivers/core/ofnode_graph.c
new file mode 100644
index 00000000000..90c92af3258
--- /dev/null
+++ b/drivers/core/ofnode_graph.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamo...@gmail.com>
+ */
+
+#define LOG_CATEGORY   LOGC_DT
+
+#include <dm.h>
+#include <log.h>
+#include <dm/ofnode.h>
+#include <linux/err.h>
+
+/**
+ * ofnode_graph_get_endpoint_count() - get the number of endpoints in a device 
ofnode
+ * @parent: ofnode to the device containing ports and endpoints
+ *
+ * Return: count of endpoint of this device ofnode
+ */
+unsigned int ofnode_graph_get_endpoint_count(ofnode parent)
+{
+       ofnode ports, port, endpoint;
+       unsigned int num = 0;
+
+       /* Check if ports node exists */
+       ports = ofnode_find_subnode(parent, "ports");
+       if (ofnode_valid(ports))
+               parent = ports;
+
+       ofnode_for_each_subnode(port, parent) {
+               if (!strncmp(ofnode_get_name(port), "port", 4)) {
+                       /* Port node can only contain endpoints */
+                       ofnode_for_each_subnode(endpoint, port)
+                               num++;
+               }
+       };
+
+       log_debug("%s: detected %d endpoints\n", __func__, num);
+
+       return num++;
+}
+
+/**
+ * ofnode_graph_get_port_count() - get the number of port in a device or ports 
ofnode
+ * @parent: ofnode to the device or ports node
+ *
+ * Return: count of port of this device or ports node
+ */
+unsigned int ofnode_graph_get_port_count(ofnode parent)
+{
+       ofnode ports, port;
+       unsigned int num = 0;
+
+       /* Check if ports node exists */
+       ports = ofnode_find_subnode(parent, "ports");
+       if (ofnode_valid(ports))
+               parent = ports;
+
+       ofnode_for_each_subnode(port, parent)
+               if (!strncmp(ofnode_get_name(port), "port", 4))
+                       num++;
+
+       log_debug("%s: detected %d ports\n", __func__, num);
+
+       return num++;
+}
+
+/**
+ * ofnode_graph_get_port_by_id() - get the port matching a given id
+ * @parent: parent ofnode
+ * @id: id of the port
+ *
+ * Return: ofnode in given port.
+ */
+ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id)
+{
+       ofnode ports, port;
+       u32 port_id;
+
+       ports = ofnode_find_subnode(parent, "ports");
+       if (!ofnode_valid(ports))
+               return ofnode_null();
+
+       /* Check ports for node with desired id */
+       ofnode_for_each_subnode(port, ports) {
+               ofnode_read_u32(port, "reg", &port_id);
+               log_debug("%s: detected port %d\n", __func__, port_id);
+               if (port_id == id)
+                       return port;
+       }
+
+       return ofnode_null();
+}
+
+/**
+ * ofnode_graph_get_endpoint_by_regs() - get the endpoint matching a given id
+ * @parent: parent ofnode
+ * @reg_id: id of the port
+ * @id: id for the endpoint
+ *
+ * Return: ofnode in given endpoint or ofnode_null() if not found.
+ * reg and port_reg are ignored when they are -1.
+ */
+ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, int reg_id, int id)
+{
+       ofnode port, endpoint;
+       u32 ep_id;
+
+       /* get the port to work with */
+       if (reg_id < 0)
+               port = ofnode_find_subnode(parent, "port");
+       else
+               port = ofnode_graph_get_port_by_id(parent, reg_id);
+
+       if (!ofnode_valid(port)) {
+               log_debug("%s: port node is not found\n", __func__);
+               return ofnode_null();
+       }
+
+       if (id < 0)
+               return ofnode_find_subnode(port, "endpoint");
+
+       /* Check endpoints for node with desired id */
+       ofnode_for_each_subnode(endpoint, port) {
+               ofnode_read_u32(endpoint, "reg", &ep_id);
+               log_debug("%s: detected endpoint %d\n", __func__, ep_id);
+               if (ep_id == id)
+                       return endpoint;
+       }
+
+       return ofnode_null();
+}
+
+/**
+ * ofnode_graph_get_remote_endpoint() - get remote endpoint node
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: Remote endpoint ofnode linked with local endpoint.
+ */
+ofnode ofnode_graph_get_remote_endpoint(ofnode endpoint)
+{
+       /* Get remote endpoint node. */
+       return ofnode_parse_phandle(endpoint, "remote-endpoint", 0);
+}
+
+/**
+ * ofnode_graph_get_port_parent() - get port's parent node
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: device ofnode associated with endpoint
+ */
+ofnode ofnode_graph_get_port_parent(ofnode endpoint)
+{
+       ofnode port = ofnode_get_parent(endpoint);
+       ofnode parent = ofnode_get_parent(port);
+
+       /* check if we are on top level or in ports node */
+       if (!strcmp(ofnode_get_name(parent), "ports"))
+               parent = ofnode_get_parent(parent);
+
+       return parent;
+}
+
+/**
+ * ofnode_graph_get_remote_port_parent() - get remote port's parent ofnode
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: device ofnode associated with endpoint linked to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_port_parent(ofnode endpoint)
+{
+       ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint);
+       if (!ofnode_valid(remote_endpoint)) {
+               log_debug("%s: remote endpoint is not found\n", __func__);
+               return ofnode_null();
+       }
+
+       return ofnode_graph_get_port_parent(remote_endpoint);
+}
+
+/**
+ * ofnode_graph_get_remote_port() - get remote port ofnode
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: port ofnode associated with remote endpoint node linked
+ * to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_port(ofnode endpoint)
+{
+       ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint);
+       if (!ofnode_valid(remote_endpoint)) {
+               log_debug("%s: remote endpoint is not found\n", __func__);
+               return ofnode_null();
+       }
+
+       return ofnode_get_parent(remote_endpoint);
+}
+
+/**
+ * ofnode_graph_get_remote_node() - get remote parent ofnode for given 
port/endpoint
+ * @parent: parent ofnode containing graph port/endpoint
+ * @port: identifier (value of reg property) of the parent port ofnode
+ * @endpoint: identifier (value of reg property) of the endpoint ofnode
+ *
+ * Return: device ofnode associated with endpoint linked to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_node(ofnode parent, int port, int endpoint)
+{
+       ofnode endpoint_ofnode;
+
+       endpoint_ofnode = ofnode_graph_get_endpoint_by_regs(parent, port, 
endpoint);
+       if (!ofnode_valid(endpoint_ofnode)) {
+               log_debug("%s: endpoint is not found\n", __func__);
+               return ofnode_null();
+       }
+
+       return ofnode_graph_get_remote_port_parent(endpoint_ofnode);
+}
diff --git a/include/dm/ofnode_graph.h b/include/dm/ofnode_graph.h
new file mode 100644
index 00000000000..908c990a3f3
--- /dev/null
+++ b/include/dm/ofnode_graph.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamo...@gmail.com>
+ */
+
+#ifndef _DM_OFNODE_GRAPH_H
+#define _DM_OFNODE_GRAPH_H
+
+#include <dm/of.h>
+
+/**
+ * ofnode_graph_get_endpoint_count() - get the number of endpoints in a device 
ofnode
+ * @parent: ofnode to the device containing ports and endpoints
+ *
+ * Return: count of endpoint of this device ofnode
+ */
+unsigned int ofnode_graph_get_endpoint_count(ofnode parent);
+
+/**
+ * ofnode_graph_get_port_count() - get the number of port in a device or ports 
ofnode
+ * @parent: ofnode to the device or ports node
+ *
+ * Return: count of port of this device or ports node
+ */
+unsigned int ofnode_graph_get_port_count(ofnode parent);
+
+/**
+ * ofnode_graph_get_port_by_id() - get the port matching a given id
+ * @parent: parent ofnode
+ * @id: id of the port
+ *
+ * Return: ofnode in given port.
+ */
+ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id);
+
+/**
+ * ofnode_graph_get_endpoint_by_regs() - get the endpoint matching a given id
+ * @parent: parent ofnode
+ * @reg_id: id of the port
+ * @id: id for the endpoint
+ *
+ * Return: ofnode in given endpoint or NULL if not found.
+ * reg and port_reg are ignored when they are -1.
+ */
+ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, u32 reg_id, u32 id);
+
+/**
+ * ofnode_graph_get_remote_endpoint() - get remote endpoint node
+ * @endoint: ofnode of a local endpoint
+ *
+ * Return: Remote endpoint ofnode linked with local endpoint.
+ */
+ofnode ofnode_graph_get_remote_endpoint(ofnode endpoint);
+
+/**
+ * ofnode_graph_get_port_parent() - get port's parent node
+ * @endpoint: ofnode of a local endpoint
+ *
+ * Return: device ofnode associated with endpoint
+ */
+ofnode ofnode_graph_get_port_parent(ofnode endpoint);
+
+/**
+ * ofnode_graph_get_remote_port_parent() - get remote port's parent ofnode
+ * @endoint: ofnode of a local endpoint
+ *
+ * Return: device ofnode associated with endpoint linked to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_port_parent(ofnode endpoint);
+
+/**
+ * ofnode_graph_get_remote_port() - get remote port ofnode
+ * @endoint: ofnode of a local endpoint
+ *
+ * Return: port ofnode associated with remote endpoint node linked
+ * to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_port(ofnode endpoint);
+
+/**
+ * ofnode_graph_get_remote_node() - get remote parent ofnode for given 
port/endpoint
+ * @parent: parent ofnode containing graph port/endpoint
+ * @port: identifier (value of reg property) of the parent port ofnode
+ * @endpoint: identifier (value of reg property) of the endpoint ofnode
+ *
+ * Return: device ofnode associated with endpoint linked to local endpoint.
+ */
+ofnode ofnode_graph_get_remote_node(ofnode parent, u32 port, u32 endpoint);
+
+#endif
-- 
2.43.0

Reply via email to