On 10/30/25 08:43, Yannick FERTRE wrote: > Hi Raphael, > > Thanks for the patch. > > Acked-by: Yannick Fertre<[email protected]> > > Le 04/09/2025 à 14:53, Raphael Gallais-Pou a écrit : >> Initially there was only one DSI bridge with one panel attached to this >> device. This explained the call to uclass_first_device_err(UCLASS_PANEL, >> ...) which worked fine at the time. >> >> Now that multiple bridges and panels, with different technologies, can >> be plugged onto the board this way to get the panel device is outdated. >> >> The lookup is done is two steps. First we circle through the >> UCLASS_VIDEO_BRIDGE, and once we get one, we search through its >> endpoints until we get a UCLASS_PANEL device available. >> >> Acked-by: Yannick Fertre <[email protected]> >> Signed-off-by: Raphael Gallais-Pou <[email protected]> >> --- >> drivers/video/stm32/stm32_ltdc.c | 136 >> +++++++++++++++++++++++++++++++++++---- >> 1 file changed, 125 insertions(+), 11 deletions(-) >> >> diff --git a/drivers/video/stm32/stm32_ltdc.c >> b/drivers/video/stm32/stm32_ltdc.c >> index >> efe9a00996eca0301d2a2b82074ba9690a967a73..834bfb625d2d34a44bd8edff1c92af6dec344c20 >> 100644 >> --- a/drivers/video/stm32/stm32_ltdc.c >> +++ b/drivers/video/stm32/stm32_ltdc.c >> @@ -17,6 +17,7 @@ >> #include <video_bridge.h> >> #include <asm/io.h> >> #include <dm/device-internal.h> >> +#include <dm/uclass-internal.h> >> #include <dm/device_compat.h> >> #include <linux/bitops.h> >> #include <linux/printk.h> >> @@ -495,6 +496,101 @@ static void stm32_ltdc_set_layer1(struct >> stm32_ltdc_priv *priv, ulong fb_addr) >> setbits_le32(priv->regs + LTDC_L1CR, LXCR_LEN); >> } >> +static int stm32_ltdc_get_remote_device(struct udevice *dev, ofnode >> ep_node, >> + enum uclass_id id, struct udevice **remote_dev) >> +{ >> + u32 remote_phandle; >> + ofnode remote; >> + int ret = 0; >> + >> + ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle); >> + if (ret) { >> + dev_err(dev, "%s(%s): Could not find remote-endpoint property\n", >> + __func__, dev_read_name(dev)); >> + return ret; >> + } >> + >> + remote = ofnode_get_by_phandle(remote_phandle); >> + if (!ofnode_valid(remote)) >> + return -EINVAL; >> + >> + while (ofnode_valid(remote)) { >> + remote = ofnode_get_parent(remote); >> + if (!ofnode_valid(remote)) { >> + dev_dbg(dev, "%s(%s): no uclass_id %d for remote-endpoint\n", >> + __func__, dev_read_name(dev), id); >> + continue; >> + } >> + >> + ret = uclass_find_device_by_ofnode(id, remote, remote_dev); >> + if (*remote_dev && !ret) { >> + ret = uclass_get_device_by_ofnode(id, remote, remote_dev); >> + if (ret) >> + dev_dbg(dev, "%s(%s): failed to get remote device %s\n", >> + __func__, dev_read_name(dev), >> dev_read_name(*remote_dev)); >> + break; >> + } >> + }; >> + >> + return ret; >> +} >> + >> +static int stm32_ltdc_get_panel(struct udevice *dev, struct udevice **panel) >> +{ >> + ofnode ep_node, node, ports; >> + int ret = 0; >> + >> + if (!dev) >> + return -EINVAL; >> + >> + ports = ofnode_find_subnode(dev_ofnode(dev), "ports"); >> + if (!ofnode_valid(ports)) { >> + dev_err(dev, "Remote bridge subnode\n"); >> + return ret; >> + } >> + >> + for (node = ofnode_first_subnode(ports); >> + ofnode_valid(node); >> + node = dev_read_next_subnode(node)) { >> + ep_node = ofnode_first_subnode(node); >> + if (!ofnode_valid(ep_node)) >> + continue; >> + >> + ret = stm32_ltdc_get_remote_device(dev, ep_node, UCLASS_PANEL, >> panel); >> + } >> + >> + /* Sanity check, we can get out of the loop without having a clean >> ofnode */ >> + if (!(*panel)) >> + ret = -EINVAL; >> + else >> + if (!ofnode_valid(dev_ofnode(*panel))) >> + ret = -EINVAL; >> + >> + return ret; >> +} >> + >> +static int stm32_ltdc_display_init(struct udevice *dev, ofnode *ep_node, >> + struct udevice **panel, struct udevice **bridge) >> +{ >> + int ret; >> + >> + if (*panel) >> + return -EINVAL; >> + >> + if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { >> + ret = stm32_ltdc_get_remote_device(dev, *ep_node, >> UCLASS_VIDEO_BRIDGE, bridge); >> + if (ret) >> + return ret; >> + >> + ret = stm32_ltdc_get_panel(*bridge, panel); >> + } else { >> + /* no bridge, search a panel from display controller node */ >> + ret = stm32_ltdc_get_remote_device(dev, *ep_node, UCLASS_PANEL, >> panel); >> + } >> + >> + return ret; >> +} >> + >> #if IS_ENABLED(CONFIG_TARGET_STM32F469_DISCOVERY) >> static int stm32_ltdc_alloc_fb(struct udevice *dev) >> { >> @@ -532,6 +628,7 @@ static int stm32_ltdc_probe(struct udevice *dev) >> struct display_timing timings; >> struct clk pclk, bclk; >> struct reset_ctl rst; >> + ofnode node, port; >> ulong rate; >> int ret; >> @@ -568,7 +665,7 @@ static int stm32_ltdc_probe(struct udevice *dev) >> } >> priv->hw_version = readl(priv->regs + LTDC_IDR); >> - debug("%s: LTDC hardware 0x%x\n", __func__, priv->hw_version); >> + dev_dbg(dev, "%s: LTDC hardware 0x%x\n", __func__, priv->hw_version); >> switch (priv->hw_version) { >> case HWVER_10200: >> @@ -589,13 +686,35 @@ static int stm32_ltdc_probe(struct udevice *dev) >> return -ENODEV; >> } >> - ret = uclass_first_device_err(UCLASS_PANEL, &panel); >> - if (ret) { >> - if (ret != -ENODEV) >> - dev_err(dev, "panel device error %d\n", ret); >> - return ret; >> + /* >> + * Try all the ports until one working. >> + * >> + * This is done in two times. First is checks for the >> + * UCLASS_VIDEO_BRIDGE available, and then for this bridge >> + * it scans for a UCLASS_PANEL. >> + */ >> + >> + port = dev_read_subnode(dev, "port"); >> + if (!ofnode_valid(port)) { >> + dev_err(dev, "%s(%s): 'port' subnode not found\n", >> + __func__, dev_read_name(dev)); >> + return -EINVAL; >> } >> + for (node = ofnode_first_subnode(port); >> + ofnode_valid(node); >> + node = dev_read_next_subnode(node)) { >> + ret = stm32_ltdc_display_init(dev, &node, &panel, &bridge); >> + if (ret) >> + dev_dbg(dev, "Device failed ret=%d\n", ret); >> + else >> + break; >> + } >> + >> + /* Sanity check */ >> + if (ret) >> + return ret; >> + >> ret = panel_get_display_timing(panel, &timings); >> if (ret) { >> ret = ofnode_decode_display_timing(dev_ofnode(panel), >> @@ -624,11 +743,6 @@ static int stm32_ltdc_probe(struct udevice *dev) >> reset_deassert(&rst); >> if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { >> - ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge); >> - if (ret) >> - dev_dbg(dev, >> - "No video bridge, or no backlight on bridge\n"); >> - >> if (bridge) { >> ret = video_bridge_attach(bridge); >> if (ret) { >> Applied to u-boot-stm32/master Thanks Patrice

