Hi Miquel, On Tue, 10 Sept 2024 at 04:13, Miquel Raynal <miquel.ray...@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.ray...@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