summaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/Makefile2
-rw-r--r--drivers/core/ofnode_graph.c217
-rw-r--r--drivers/core/root.c17
3 files changed, 230 insertions, 6 deletions
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 <clamor95@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/drivers/core/root.c b/drivers/core/root.c
index 15b8c83fee9..e53381e3b32 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -295,22 +295,29 @@ void *dm_priv_to_rw(void *priv)
* all its children recursively to do the same.
*
* @dev: Device to (maybe) probe
+ * @pre_reloc_only: Probe only devices marked with the DM_FLAG_PRE_RELOC flag
* Return 0 if OK, -ve on error
*/
-static int dm_probe_devices(struct udevice *dev)
+static int dm_probe_devices(struct udevice *dev, bool pre_reloc_only)
{
+ ofnode node = dev_ofnode(dev);
struct udevice *child;
+ int ret;
- if (dev_get_flags(dev) & DM_FLAG_PROBE_AFTER_BIND) {
- int ret;
+ if (pre_reloc_only &&
+ (!ofnode_valid(node) || !ofnode_pre_reloc(node)) &&
+ !(dev->driver->flags & DM_FLAG_PRE_RELOC))
+ goto probe_children;
+ if (dev_get_flags(dev) & DM_FLAG_PROBE_AFTER_BIND) {
ret = device_probe(dev);
if (ret)
return ret;
}
+probe_children:
list_for_each_entry(child, &dev->child_head, sibling_node)
- dm_probe_devices(child);
+ dm_probe_devices(child, pre_reloc_only);
return 0;
}
@@ -319,7 +326,7 @@ int dm_autoprobe(void)
{
int ret;
- ret = dm_probe_devices(gd->dm_root);
+ ret = dm_probe_devices(gd->dm_root, !(gd->flags & GD_FLG_RELOC));
if (ret)
return log_msg_ret("pro", ret);