[PATCH v2 02/13] dm: core: Add a helper to retrieve devices through graph endpoints
Miquel Raynal
miquel.raynal at bootlin.com
Thu Dec 5 14:54:08 CET 2024
There are already several helpers to find a udevice based on its
position in a device tree, like getting a child or a node pointed by a
phandle, but there was no support for graph endpoints, which are very
common in display pipelines.
Add a new helper, named uclass_get_device_by_endpoint() which enters the
child graph reprensentation, looks for a specific port, then follows the
remote endpoint, and finally retrieves the first parent of the given
uclass_id.
This is a very handy and straightforward way to get a bridge or a panel
handle.
Signed-off-by: Miquel Raynal <miquel.raynal at bootlin.com>
---
drivers/core/uclass.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
include/dm/uclass.h | 21 +++++++++++++++++
2 files changed, 83 insertions(+)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index f846a35d6b2537bab56bca158cedfb134b37f477..c9c5debbe7cd9ec44f95dc80d3199ee11521e997 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -582,6 +582,68 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
ret = uclass_find_device_by_phandle(id, parent, name, &dev);
return uclass_get_device_tail(dev, ret, devp);
}
+
+int uclass_get_device_by_endpoint(enum uclass_id class_id, struct udevice *dev,
+ u32 ep_idx, struct udevice **devp)
+{
+ ofnode port = ofnode_null(), ep, remote_ep;
+ struct udevice *target = NULL;
+ u32 remote_phandle;
+ int ret;
+
+ if (!ep_idx)
+ port = dev_read_subnode(dev, "port");
+
+ if (!ofnode_valid(port)) {
+ char port_name[32];
+
+ port = dev_read_subnode(dev, "ports");
+ if (!ofnode_valid(port)) {
+ debug("%s: no 'port'/'ports' subnode\n",
+ dev_read_name(dev));
+ return -EINVAL;
+ }
+
+ snprintf(port_name, sizeof(port_name), "port@%x", ep_idx);
+ port = ofnode_find_subnode(port, port_name);
+ if (!ofnode_valid(port)) {
+ debug("%s: no 'port@%x' subnode\n",
+ dev_read_name(dev), ep_idx);
+ return -EINVAL;
+ }
+ }
+
+ ep = ofnode_find_subnode(port, "endpoint");
+ if (!ofnode_valid(ep)) {
+ debug("%s: no 'endpoint' in %s subnode\n",
+ ofnode_get_name(port), dev_read_name(dev));
+ return -EINVAL;
+ }
+
+ ret = ofnode_read_u32(ep, "remote-endpoint", &remote_phandle);
+ if (ret)
+ return ret;
+
+ remote_ep = ofnode_get_by_phandle(remote_phandle);
+ if (!ofnode_valid(remote_ep))
+ return -EINVAL;
+
+ while (ofnode_valid(remote_ep)) {
+ remote_ep = ofnode_get_parent(remote_ep);
+ debug("trying subnode: %s\n", ofnode_get_name(remote_ep));
+ if (!ofnode_valid(remote_ep)) {
+ debug("%s: no more remote devices\n",
+ ofnode_get_name(remote_ep));
+ return -ENODEV;
+ }
+
+ ret = uclass_find_device_by_ofnode(class_id, remote_ep, &target);
+ if (!ret)
+ break;
+ };
+
+ return uclass_get_device_tail(target, ret, devp);
+}
#endif
/*
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index c279304092352200d5297ad2d17f527173ec506b..6b76a9a588e70f487c2ce5398526d98b4547e2a7 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -333,6 +333,27 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
struct udevice **devp);
+/**
+ * uclass_get_device_by_endpoint() - Get a uclass device for a remote endpoint
+ *
+ * This searches through the parents of the specified remote endpoint
+ * for the first device matching the uclass. Said otherwise, this helper
+ * goes through the graph (endpoint) representation and searches for
+ * matching devices. Endpoints can be subnodes of the "port" node or
+ * subnodes of ports identified with a reg property, themselves in a
+ * "ports" container.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @class_id: uclass ID to look up
+ * @dev: Device to start from
+ * @ep_idx: Index of the endpoint to follow, 0 if there is none.
+ * @target: Returns pointer to the first device matching the expected uclass.
+ * Return: 0 if OK, -ve on error
+ */
+int uclass_get_device_by_endpoint(enum uclass_id class_id, struct udevice *dev,
+ u32 ep_idx, struct udevice **target);
+
/**
* uclass_first_device() - Get the first device in a uclass
*
--
2.47.0
More information about the U-Boot
mailing list