U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
To: Tom Rini <trini@konsulko.com>,
	Kamil Lulko <kamil.lulko@gmail.com>,
	Patrice Chotard <patrice.chotard@foss.st.com>,
	Dillon Min <dillon.minfei@gmail.com>,
	Patrick Delaunay <patrick.delaunay@foss.st.com>,
	Anatolij Gustschin <ag.dev.uboot@gmail.com>,
	Simon Glass <sjg@chromium.org>,
	Sumit Garg <sumit.garg@kernel.org>,
	Philippe Cornu <philippe.cornu@foss.st.com>,
	Yannick Fertre <yannick.fertre@foss.st.com>
Cc: <u-boot@lists.denx.de>, <uboot-stm32@st-md-mailman.stormreply.com>
Subject: [PATCH v3 5/7] video: stm32: ltdc: properly search the first available panel
Date: Thu, 4 Sep 2025 14:53:09 +0200	[thread overview]
Message-ID: <20250904-master-v3-5-b42847884974@foss.st.com> (raw)
In-Reply-To: <20250904-master-v3-0-b42847884974@foss.st.com>

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 <yannick.fertre@foss.st.com>
Signed-off-by: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
---
 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) {

-- 
2.25.1


  parent reply	other threads:[~2025-09-04 12:53 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-04 12:53 [PATCH v3 0/7] Add display support for STM32MP25 Raphael Gallais-Pou
2025-09-04 12:53 ` [PATCH v3 1/7] ofnode: support panel-timings in ofnode_decode_display_timing Raphael Gallais-Pou
2025-10-30  7:35   ` Yannick FERTRE
2025-11-01  9:03   ` Simon Glass
2025-11-02  1:09     ` [Uboot-stm32] " Raphaël Gallais-Pou
2025-11-02 19:53       ` Simon Glass
2025-11-03 14:17         ` Tom Rini
2025-11-04 14:01           ` Raphael Gallais-Pou
2025-11-04 16:21             ` Tom Rini
2025-11-14 16:48               ` Patrice CHOTARD
2025-11-04 16:31           ` Simon Glass
2025-11-04 16:55             ` Tom Rini
2025-11-07 12:23               ` Simon Glass
2025-09-04 12:53 ` [PATCH v3 2/7] video: simple_panel: add support for "panel-lvds" display Raphael Gallais-Pou
2025-10-30  7:41   ` Yannick FERTRE
2025-11-14 16:48   ` Patrice CHOTARD
2025-09-04 12:53 ` [PATCH v3 3/7] video: stm32: STM32 driver support for LVDS Raphael Gallais-Pou
2025-10-30  7:42   ` Yannick FERTRE
2025-11-14 16:48     ` Patrice CHOTARD
2025-09-04 12:53 ` [PATCH v3 4/7] video: stm32: ltdc: support new hardware version for STM32MP25 SoC Raphael Gallais-Pou
2025-09-12 16:41   ` Patrice CHOTARD
2025-09-15 13:05     ` Raphael Gallais-Pou
2025-09-17 15:10       ` Patrice CHOTARD
2025-10-30  7:43   ` Yannick FERTRE
2025-11-14 16:49     ` Patrice CHOTARD
2025-09-04 12:53 ` Raphael Gallais-Pou [this message]
2025-09-12 16:45   ` [PATCH v3 5/7] video: stm32: ltdc: properly search the first available panel Patrice CHOTARD
2025-10-30  7:43   ` Yannick FERTRE
2025-11-14 16:49     ` Patrice CHOTARD
2025-09-04 12:53 ` [PATCH v3 6/7] ARM: dts: stm32: use LTDC and LVDS nodes before relocation in stm32mp25-u-boot Raphael Gallais-Pou
2025-09-12 16:45   ` Patrice CHOTARD
2025-10-30  7:43   ` Yannick FERTRE
2025-11-14 16:49     ` Patrice CHOTARD
2025-11-14 16:54       ` Patrice CHOTARD
2025-11-14 17:30         ` [Uboot-stm32] " Patrice CHOTARD
2025-09-04 12:53 ` [PATCH v3 7/7] configs: stm32mp25: enable LVDS display support Raphael Gallais-Pou
2025-09-12 16:46   ` Patrice CHOTARD
2025-10-30  7:44   ` Yannick FERTRE
2025-11-14 16:48   ` Patrice CHOTARD

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250904-master-v3-5-b42847884974@foss.st.com \
    --to=raphael.gallais-pou@foss.st.com \
    --cc=ag.dev.uboot@gmail.com \
    --cc=dillon.minfei@gmail.com \
    --cc=kamil.lulko@gmail.com \
    --cc=patrice.chotard@foss.st.com \
    --cc=patrick.delaunay@foss.st.com \
    --cc=philippe.cornu@foss.st.com \
    --cc=sjg@chromium.org \
    --cc=sumit.garg@kernel.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=uboot-stm32@st-md-mailman.stormreply.com \
    --cc=yannick.fertre@foss.st.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox