
Hi Miquel,
On Tue, 10 Sept 2024 at 04:13, Miquel Raynal miquel.raynal@bootlin.com wrote:
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@bootlin.com
drivers/core/uclass.c | 62 +++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass.h | 21 +++++++++++++++ 2 files changed, 83 insertions(+)
This is fine, but please add a test when changing driver model.
Perhaps it is in another patch? I don't seem to have the series so I wonder if I have been unsubscribed again...
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index e46d5717aa6..5803fd51986 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -572,6 +572,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;
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 -EINVAL;
}
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 456eef7f2f3..1194174ca9b 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.43.0
Regards, SImon