All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks
@ 2026-09-22  3:50 vishnu.saini
  2026-09-22  4:02 ` sashiko-bot
  2026-09-22  8:55 ` Jani Nikula
  0 siblings, 2 replies; 4+ messages in thread
From: vishnu.saini @ 2026-09-22  3:50 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: dri-devel, linux-kernel, venkata.valluru, Jessica Zhang,
	Ravi Agola, Vishnu Saini

From: Ravi Agola <raviagol@qti.qualcomm.com>

The LT9611UXC bridge can fetch only 2 EDID blocks at a time, which
previously limited EDID reading to 2 blocks and prevented support
for displays exposing more than 2 EDID blocks.

Add driver support to fetch up to 4 EDID blocks by re-triggering
EDID access after the first 2 blocks are read. For block 0 and 2,
set the EDID ready flag in 0xb028 so the bridge can expose the
corresponding EDID blocks, then retry the read until the expected
EDID is fetched.

Reset the edid_read flag on HPD disconnect so that the next
connect event triggers a fresh EDID fetch.

Increase EDID wait time from 500ms to 1000ms, On Qualcomm rb3gen2
platform sometimes edid read interrupt is coming 600-650 ms after
HPD interrupt resulting in edid read failure.

Signed-off-by: Ravi Agola <raviagol@qti.qualcomm.com>
Signed-off-by: Vishnu Saini <vishnu.saini@oss.qualcomm.com>
---
Changes in v4:
- Rebased onto latest drm-misc-next.
- No functional changes; replied inline to the two Sashiko-bot
  review comments on v3
- Link to v3: https://lore.kernel.org/r/20260722-lt9611usc_edid34_misc_next-v3-1-7ec2bba6ff8e@oss.qualcomm.com

Changes in v3:
- moved edid_read state change inside mutex lock     [sashiko-bot]
- returned -ETIMEOUT when retry_cnt is exhausted without a match.    [Sashiko-bot]
- Increased edid wait timeout from 500ms to 1000ms as edid interrupt is sometimes taking around 650ms time
- Link to v2: https://lore.kernel.org/r/20260624-lt9611usc_edid34_misc_next-v2-1-24ce3f5770b8@oss.qualcomm.com

Changes in v2:
- Removed memcpy and doing edid fetch everytime. Required an update in firmware as well for edid block0 reset.
- Verified patch with existing firmware V5.0.21, patch is not causing any regression if V5.0.21 firmware is used.
- Firmware V5.0.22 is required with this patch to support edid fetch on more than 2 edid block monitors.
- Link to v1: https://lore.kernel.org/r/20260517-lt9611usc_edid34_misc_next-v1-1-5e2fd8c6399b@oss.qualcomm.com
---
 drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 80 +++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
index b3bb7f2cebb3..a74077a65f62 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
@@ -28,7 +28,7 @@
 #include <drm/display/drm_hdmi_audio_helper.h>
 
 #define EDID_BLOCK_SIZE	128
-#define EDID_NUM_BLOCKS	2
+#define EDID_NUM_BLOCKS	4
 
 #define FW_FILE "lt9611uxc_fw.bin"
 
@@ -167,6 +167,8 @@ static void lt9611uxc_hpd_work(struct work_struct *work)
 
 	mutex_lock(&lt9611uxc->ocm_lock);
 	connected = lt9611uxc->hdmi_connected;
+	if (!connected)
+		lt9611uxc->edid_read = false;
 	mutex_unlock(&lt9611uxc->ocm_lock);
 
 	drm_bridge_hpd_notify(&lt9611uxc->bridge,
@@ -380,13 +382,39 @@ lt9611uxc_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connect
 static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc)
 {
 	return wait_event_interruptible_timeout(lt9611uxc->wq, lt9611uxc->edid_read,
-			msecs_to_jiffies(500));
+			msecs_to_jiffies(1000));
+}
+
+static int lt9611uxc_read_edid_block(struct lt9611uxc *lt9611uxc, unsigned int block,
+				     u8 *buf,  size_t len)
+{
+	int ret;
+
+	lt9611uxc_lock(lt9611uxc);
+
+	regmap_write(lt9611uxc->regmap, 0xb00a, (block % 2) * EDID_BLOCK_SIZE);
+
+	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
+	if (ret) {
+		dev_err(lt9611uxc->dev, "edid block %d read failed: %d\n", block, ret);
+		lt9611uxc_unlock(lt9611uxc);
+		return -EINVAL;
+	}
+	lt9611uxc_unlock(lt9611uxc);
+
+	return ret;
 }
 
 static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
 {
 	struct lt9611uxc *lt9611uxc = data;
-	int ret;
+	int ret = 0;
+	int retry_cnt = 10;
+	unsigned int edid_ready_flag = 0;
+	bool header_matched;
+	bool edid_valid = false;
+	const u8 edid_header[8] = { 0x00, 0xFF, 0xFF, 0xFF,
+				    0xFF, 0xFF, 0xFF, 0x00 };
 
 	if (len > EDID_BLOCK_SIZE)
 		return -EINVAL;
@@ -394,20 +422,48 @@ static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, siz
 	if (block >= EDID_NUM_BLOCKS)
 		return -EINVAL;
 
-	lt9611uxc_lock(lt9611uxc);
+	if (block == 0 || block == 2) {
 
-	regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
+		lt9611uxc_lock(lt9611uxc);
 
-	regmap_write(lt9611uxc->regmap, 0xb00a, block * EDID_BLOCK_SIZE);
+		edid_ready_flag = (block == 0) ? BIT(0) : BIT(1);
 
-	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
-	if (ret)
-		dev_err(lt9611uxc->dev, "edid read failed: %d\n", ret);
+		/*
+		 * Set the EDID ready flag so that lt9611uxc can fetch correct EDID block
+		 */
+		regmap_write(lt9611uxc->regmap, 0xb028, edid_ready_flag);
 
-	lt9611uxc_unlock(lt9611uxc);
+		lt9611uxc_unlock(lt9611uxc);
 
-	return 0;
-};
+		do {
+			msleep(100);
+			ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
+			if (ret)
+				break;
+			/*
+			 * Compare first 8 bytes of EDID header for block 0 and block 2
+			 * to confirm EDID read successfully
+			 */
+			header_matched = (memcmp(edid_header, buf, 8) == 0);
+			edid_valid = (block == 0 && header_matched) ||
+				     (block == 2 && !header_matched);
+			if (edid_valid)
+				break;
+
+		} while (retry_cnt-- > 0);
+
+		if (!ret && !edid_valid)
+			ret = -ETIMEDOUT;
+	} else {
+		ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
+
+		lt9611uxc_lock(lt9611uxc);
+		regmap_write(lt9611uxc->regmap, 0xb028, 0x00);
+		lt9611uxc_unlock(lt9611uxc);
+	}
+
+	return ret;
+}
 
 static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *bridge,
 							 struct drm_connector *connector)

---
base-commit: 8ef59ee794076e2b58cff357b12de2ba5d441271
change-id: 20260517-lt9611usc_edid34_misc_next-b02592de0b25

Best regards,
-- 
Vishnu Saini <vishnu.saini@oss.qualcomm.com>


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks
  2026-09-22  3:50 [PATCH v4] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks vishnu.saini
@ 2026-09-22  4:02 ` sashiko-bot
  2026-09-22  8:55 ` Jani Nikula
  1 sibling, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-09-22  4:02 UTC (permalink / raw)
  To: vishnu.saini; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] drm/bridge: lt9611uxc: race condition in EDID SRAM polling causes torn reads
- [Medium] drm/bridge: lt9611uxc: strict EDID header check breaks repairable displays
--

commit 6559cd85aa7ae1a652dd056a93747b35998d927d
Author: Ravi Agola <raviagol@qti.qualcomm.com>

drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks

This commit adds support for fetching up to 4 EDID blocks in the LT9611UXC
bridge driver by re-triggering access for blocks beyond the first two. It
introduces a polling mechanism for blocks 0 and 2, checking for a valid EDID
header match to verify read success. It also increases the EDID wait time to
handle slower platform interrupts.

> diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> index b3bb7f2cebb3b..a74077a65f62b 100644
> --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
[ ... ]
> @@ -394,20 +422,48 @@ static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, siz
>  	if (block >= EDID_NUM_BLOCKS)
>  		return -EINVAL;
>  
> -	lt9611uxc_lock(lt9611uxc);
> +	if (block == 0 || block == 2) {
>  
> -	regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
> +		lt9611uxc_lock(lt9611uxc);
>  
> -	regmap_write(lt9611uxc->regmap, 0xb00a, block * EDID_BLOCK_SIZE);
> +		edid_ready_flag = (block == 0) ? BIT(0) : BIT(1);
>  
> -	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
> -	if (ret)
> -		dev_err(lt9611uxc->dev, "edid read failed: %d\n", ret);
> +		/*
> +		 * Set the EDID ready flag so that lt9611uxc can fetch correct EDID block
> +		 */
> +		regmap_write(lt9611uxc->regmap, 0xb028, edid_ready_flag);
>  
> -	lt9611uxc_unlock(lt9611uxc);
> +		lt9611uxc_unlock(lt9611uxc);
>  
> -	return 0;
> -};
> +		do {
> +			msleep(100);
> +			ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
> +			if (ret)
> +				break;
> +			/*
> +			 * Compare first 8 bytes of EDID header for block 0 and block 2
> +			 * to confirm EDID read successfully
> +			 */
> +			header_matched = (memcmp(edid_header, buf, 8) == 0);
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

[Severity: Medium]
Will this strict exact match check inadvertently drop blocks with repairable
header corruptions?

If the display provides a corrupted header that the DRM core is natively
designed to fix via edid_header_fix(), it seems this strict memcmp will never
match and the polling loop will exhaust its retries, returning -ETIMEDOUT.
Does this break initialization for displays with non-compliant but repairable
EDID headers?

> +			edid_valid = (block == 0 && header_matched) ||
> +				     (block == 2 && !header_matched);
> +			if (edid_valid)
> +				break;
                                ^^^^^

[Severity: High]
Does this condition break the wait loop too early, ignoring that the rest of
the block is still being written by the MCU?

When the DRM core requests block 2, the bridge driver writes to 0xb028 to
trigger the MCU fetch, and then polls the SRAM. The SRAM initially contains
block 0 (which has a valid header). As soon as the MCU overwrites the first
byte of SRAM with block 2 data, the !header_matched condition evaluates to
true.

Could this cause the driver to immediately stop polling and read the rest of
the block, which might still contain stale data from block 0?

> +
> +		} while (retry_cnt-- > 0);
> +
> +		if (!ret && !edid_valid)
> +			ret = -ETIMEDOUT;
> +	} else {
> +		ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

[Severity: High]
Blocks 1 and 3 are read immediately here without any synchronization. Does
this guarantee reading torn data if the firmware is still fetching them over
I2C?

> +
> +		lt9611uxc_lock(lt9611uxc);
> +		regmap_write(lt9611uxc->regmap, 0xb028, 0x00);
> +		lt9611uxc_unlock(lt9611uxc);
> +	}
> +
> +	return ret;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260922-lt9611usc_edid34_misc_next-v4-1-47d5315821fe@oss.qualcomm.com?part=1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks
  2026-09-22  3:50 [PATCH v4] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks vishnu.saini
  2026-09-22  4:02 ` sashiko-bot
@ 2026-09-22  8:55 ` Jani Nikula
  2026-09-24 19:33   ` Vishnu Saini
  1 sibling, 1 reply; 4+ messages in thread
From: Jani Nikula @ 2026-09-22  8:55 UTC (permalink / raw)
  To: vishnu.saini, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter
  Cc: dri-devel, linux-kernel, venkata.valluru, Jessica Zhang,
	Ravi Agola, Vishnu Saini

On Tue, 22 Sep 2026, vishnu.saini@oss.qualcomm.com wrote:
> From: Ravi Agola <raviagol@qti.qualcomm.com>
>
> The LT9611UXC bridge can fetch only 2 EDID blocks at a time, which
> previously limited EDID reading to 2 blocks and prevented support
> for displays exposing more than 2 EDID blocks.
>
> Add driver support to fetch up to 4 EDID blocks by re-triggering
> EDID access after the first 2 blocks are read. For block 0 and 2,
> set the EDID ready flag in 0xb028 so the bridge can expose the
> corresponding EDID blocks, then retry the read until the expected
> EDID is fetched.
>
> Reset the edid_read flag on HPD disconnect so that the next
> connect event triggers a fresh EDID fetch.
>
> Increase EDID wait time from 500ms to 1000ms, On Qualcomm rb3gen2
> platform sometimes edid read interrupt is coming 600-650 ms after
> HPD interrupt resulting in edid read failure.
>
> Signed-off-by: Ravi Agola <raviagol@qti.qualcomm.com>
> Signed-off-by: Vishnu Saini <vishnu.saini@oss.qualcomm.com>
> ---
> Changes in v4:
> - Rebased onto latest drm-misc-next.
> - No functional changes; replied inline to the two Sashiko-bot
>   review comments on v3
> - Link to v3: https://lore.kernel.org/r/20260722-lt9611usc_edid34_misc_next-v3-1-7ec2bba6ff8e@oss.qualcomm.com
>
> Changes in v3:
> - moved edid_read state change inside mutex lock     [sashiko-bot]
> - returned -ETIMEOUT when retry_cnt is exhausted without a match.    [Sashiko-bot]
> - Increased edid wait timeout from 500ms to 1000ms as edid interrupt is sometimes taking around 650ms time
> - Link to v2: https://lore.kernel.org/r/20260624-lt9611usc_edid34_misc_next-v2-1-24ce3f5770b8@oss.qualcomm.com
>
> Changes in v2:
> - Removed memcpy and doing edid fetch everytime. Required an update in firmware as well for edid block0 reset.
> - Verified patch with existing firmware V5.0.21, patch is not causing any regression if V5.0.21 firmware is used.
> - Firmware V5.0.22 is required with this patch to support edid fetch on more than 2 edid block monitors.
> - Link to v1: https://lore.kernel.org/r/20260517-lt9611usc_edid34_misc_next-v1-1-5e2fd8c6399b@oss.qualcomm.com
> ---
>  drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 80 +++++++++++++++++++++++++-----
>  1 file changed, 68 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> index b3bb7f2cebb3..a74077a65f62 100644
> --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> @@ -28,7 +28,7 @@
>  #include <drm/display/drm_hdmi_audio_helper.h>
>  
>  #define EDID_BLOCK_SIZE	128
> -#define EDID_NUM_BLOCKS	2
> +#define EDID_NUM_BLOCKS	4
>  
>  #define FW_FILE "lt9611uxc_fw.bin"
>  
> @@ -167,6 +167,8 @@ static void lt9611uxc_hpd_work(struct work_struct *work)
>  
>  	mutex_lock(&lt9611uxc->ocm_lock);
>  	connected = lt9611uxc->hdmi_connected;
> +	if (!connected)
> +		lt9611uxc->edid_read = false;
>  	mutex_unlock(&lt9611uxc->ocm_lock);
>  
>  	drm_bridge_hpd_notify(&lt9611uxc->bridge,
> @@ -380,13 +382,39 @@ lt9611uxc_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connect
>  static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc)
>  {
>  	return wait_event_interruptible_timeout(lt9611uxc->wq, lt9611uxc->edid_read,
> -			msecs_to_jiffies(500));
> +			msecs_to_jiffies(1000));
> +}
> +
> +static int lt9611uxc_read_edid_block(struct lt9611uxc *lt9611uxc, unsigned int block,
> +				     u8 *buf,  size_t len)
> +{
> +	int ret;
> +
> +	lt9611uxc_lock(lt9611uxc);
> +
> +	regmap_write(lt9611uxc->regmap, 0xb00a, (block % 2) * EDID_BLOCK_SIZE);
> +
> +	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
> +	if (ret) {
> +		dev_err(lt9611uxc->dev, "edid block %d read failed: %d\n", block, ret);
> +		lt9611uxc_unlock(lt9611uxc);
> +		return -EINVAL;
> +	}
> +	lt9611uxc_unlock(lt9611uxc);
> +
> +	return ret;
>  }
>  
>  static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
>  {
>  	struct lt9611uxc *lt9611uxc = data;
> -	int ret;
> +	int ret = 0;
> +	int retry_cnt = 10;
> +	unsigned int edid_ready_flag = 0;
> +	bool header_matched;
> +	bool edid_valid = false;
> +	const u8 edid_header[8] = { 0x00, 0xFF, 0xFF, 0xFF,
> +				    0xFF, 0xFF, 0xFF, 0x00 };
>  
>  	if (len > EDID_BLOCK_SIZE)
>  		return -EINVAL;
> @@ -394,20 +422,48 @@ static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, siz
>  	if (block >= EDID_NUM_BLOCKS)
>  		return -EINVAL;
>  
> -	lt9611uxc_lock(lt9611uxc);
> +	if (block == 0 || block == 2) {
>  
> -	regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
> +		lt9611uxc_lock(lt9611uxc);
>  
> -	regmap_write(lt9611uxc->regmap, 0xb00a, block * EDID_BLOCK_SIZE);
> +		edid_ready_flag = (block == 0) ? BIT(0) : BIT(1);
>  
> -	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
> -	if (ret)
> -		dev_err(lt9611uxc->dev, "edid read failed: %d\n", ret);
> +		/*
> +		 * Set the EDID ready flag so that lt9611uxc can fetch correct EDID block
> +		 */
> +		regmap_write(lt9611uxc->regmap, 0xb028, edid_ready_flag);
>  
> -	lt9611uxc_unlock(lt9611uxc);
> +		lt9611uxc_unlock(lt9611uxc);
>  
> -	return 0;
> -};
> +		do {
> +			msleep(100);
> +			ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
> +			if (ret)
> +				break;
> +			/*
> +			 * Compare first 8 bytes of EDID header for block 0 and block 2
> +			 * to confirm EDID read successfully
> +			 */
> +			header_matched = (memcmp(edid_header, buf, 8) == 0);
> +			edid_valid = (block == 0 && header_matched) ||
> +				     (block == 2 && !header_matched);
> +			if (edid_valid)
> +				break;
> +
> +		} while (retry_cnt-- > 0);

What's the purpose of the above dance? Why do you have to try ten times,
and what's with the header matching? None of this is explained in the
commit message.

BR,
Jani.


> +
> +		if (!ret && !edid_valid)
> +			ret = -ETIMEDOUT;
> +	} else {
> +		ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
> +
> +		lt9611uxc_lock(lt9611uxc);
> +		regmap_write(lt9611uxc->regmap, 0xb028, 0x00);
> +		lt9611uxc_unlock(lt9611uxc);
> +	}
> +
> +	return ret;
> +}
>  
>  static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *bridge,
>  							 struct drm_connector *connector)
>
> ---
> base-commit: 8ef59ee794076e2b58cff357b12de2ba5d441271
> change-id: 20260517-lt9611usc_edid34_misc_next-b02592de0b25
>
> Best regards,

-- 
Jani Nikula, Intel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks
  2026-09-22  8:55 ` Jani Nikula
@ 2026-09-24 19:33   ` Vishnu Saini
  0 siblings, 0 replies; 4+ messages in thread
From: Vishnu Saini @ 2026-09-24 19:33 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	dri-devel, linux-kernel, venkata.valluru, Jessica Zhang,
	Ravi Agola

On Tue, Sep 22, 2026 at 11:55:01AM +0300, Jani Nikula wrote:
> On Tue, 22 Sep 2026, vishnu.saini@oss.qualcomm.com wrote:
> > From: Ravi Agola <raviagol@qti.qualcomm.com>
> >
> > The LT9611UXC bridge can fetch only 2 EDID blocks at a time, which
> > previously limited EDID reading to 2 blocks and prevented support
> > for displays exposing more than 2 EDID blocks.
> >
> > Add driver support to fetch up to 4 EDID blocks by re-triggering
> > EDID access after the first 2 blocks are read. For block 0 and 2,
> > set the EDID ready flag in 0xb028 so the bridge can expose the
> > corresponding EDID blocks, then retry the read until the expected
> > EDID is fetched.
> >
> > Reset the edid_read flag on HPD disconnect so that the next
> > connect event triggers a fresh EDID fetch.
> >
> > Increase EDID wait time from 500ms to 1000ms, On Qualcomm rb3gen2
> > platform sometimes edid read interrupt is coming 600-650 ms after
> > HPD interrupt resulting in edid read failure.
> >
> > Signed-off-by: Ravi Agola <raviagol@qti.qualcomm.com>
> > Signed-off-by: Vishnu Saini <vishnu.saini@oss.qualcomm.com>
> > ---
> > Changes in v4:
> > - Rebased onto latest drm-misc-next.
> > - No functional changes; replied inline to the two Sashiko-bot
> >   review comments on v3
> > - Link to v3: https://lore.kernel.org/r/20260722-lt9611usc_edid34_misc_next-v3-1-7ec2bba6ff8e@oss.qualcomm.com
> >
> > Changes in v3:
> > - moved edid_read state change inside mutex lock     [sashiko-bot]
> > - returned -ETIMEOUT when retry_cnt is exhausted without a match.    [Sashiko-bot]
> > - Increased edid wait timeout from 500ms to 1000ms as edid interrupt is sometimes taking around 650ms time
> > - Link to v2: https://lore.kernel.org/r/20260624-lt9611usc_edid34_misc_next-v2-1-24ce3f5770b8@oss.qualcomm.com
> >
> > Changes in v2:
> > - Removed memcpy and doing edid fetch everytime. Required an update in firmware as well for edid block0 reset.
> > - Verified patch with existing firmware V5.0.21, patch is not causing any regression if V5.0.21 firmware is used.
> > - Firmware V5.0.22 is required with this patch to support edid fetch on more than 2 edid block monitors.
> > - Link to v1: https://lore.kernel.org/r/20260517-lt9611usc_edid34_misc_next-v1-1-5e2fd8c6399b@oss.qualcomm.com
> > ---
> >  drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 80 +++++++++++++++++++++++++-----
> >  1 file changed, 68 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> > index b3bb7f2cebb3..a74077a65f62 100644
> > --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> > +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
> > @@ -28,7 +28,7 @@
> >  #include <drm/display/drm_hdmi_audio_helper.h>
> >  
> >  #define EDID_BLOCK_SIZE	128
> > -#define EDID_NUM_BLOCKS	2
> > +#define EDID_NUM_BLOCKS	4
> >  
> >  #define FW_FILE "lt9611uxc_fw.bin"
> >  
> > @@ -167,6 +167,8 @@ static void lt9611uxc_hpd_work(struct work_struct *work)
> >  
> >  	mutex_lock(&lt9611uxc->ocm_lock);
> >  	connected = lt9611uxc->hdmi_connected;
> > +	if (!connected)
> > +		lt9611uxc->edid_read = false;
> >  	mutex_unlock(&lt9611uxc->ocm_lock);
> >  
> >  	drm_bridge_hpd_notify(&lt9611uxc->bridge,
> > @@ -380,13 +382,39 @@ lt9611uxc_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connect
> >  static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc)
> >  {
> >  	return wait_event_interruptible_timeout(lt9611uxc->wq, lt9611uxc->edid_read,
> > -			msecs_to_jiffies(500));
> > +			msecs_to_jiffies(1000));
> > +}
> > +
> > +static int lt9611uxc_read_edid_block(struct lt9611uxc *lt9611uxc, unsigned int block,
> > +				     u8 *buf,  size_t len)
> > +{
> > +	int ret;
> > +
> > +	lt9611uxc_lock(lt9611uxc);
> > +
> > +	regmap_write(lt9611uxc->regmap, 0xb00a, (block % 2) * EDID_BLOCK_SIZE);
> > +
> > +	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
> > +	if (ret) {
> > +		dev_err(lt9611uxc->dev, "edid block %d read failed: %d\n", block, ret);
> > +		lt9611uxc_unlock(lt9611uxc);
> > +		return -EINVAL;
> > +	}
> > +	lt9611uxc_unlock(lt9611uxc);
> > +
> > +	return ret;
> >  }
> >  
> >  static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
> >  {
> >  	struct lt9611uxc *lt9611uxc = data;
> > -	int ret;
> > +	int ret = 0;
> > +	int retry_cnt = 10;
> > +	unsigned int edid_ready_flag = 0;
> > +	bool header_matched;
> > +	bool edid_valid = false;
> > +	const u8 edid_header[8] = { 0x00, 0xFF, 0xFF, 0xFF,
> > +				    0xFF, 0xFF, 0xFF, 0x00 };
> >  
> >  	if (len > EDID_BLOCK_SIZE)
> >  		return -EINVAL;
> > @@ -394,20 +422,48 @@ static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, siz
> >  	if (block >= EDID_NUM_BLOCKS)
> >  		return -EINVAL;
> >  
> > -	lt9611uxc_lock(lt9611uxc);
> > +	if (block == 0 || block == 2) {
> >  
> > -	regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
> > +		lt9611uxc_lock(lt9611uxc);
> >  
> > -	regmap_write(lt9611uxc->regmap, 0xb00a, block * EDID_BLOCK_SIZE);
> > +		edid_ready_flag = (block == 0) ? BIT(0) : BIT(1);
> >  
> > -	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
> > -	if (ret)
> > -		dev_err(lt9611uxc->dev, "edid read failed: %d\n", ret);
> > +		/*
> > +		 * Set the EDID ready flag so that lt9611uxc can fetch correct EDID block
> > +		 */
> > +		regmap_write(lt9611uxc->regmap, 0xb028, edid_ready_flag);
> >  
> > -	lt9611uxc_unlock(lt9611uxc);
> > +		lt9611uxc_unlock(lt9611uxc);
> >  
> > -	return 0;
> > -};
> > +		do {
> > +			msleep(100);
> > +			ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
> > +			if (ret)
> > +				break;
> > +			/*
> > +			 * Compare first 8 bytes of EDID header for block 0 and block 2
> > +			 * to confirm EDID read successfully
> > +			 */
> > +			header_matched = (memcmp(edid_header, buf, 8) == 0);
> > +			edid_valid = (block == 0 && header_matched) ||
> > +				     (block == 2 && !header_matched);
> > +			if (edid_valid)
> > +				break;
> > +
> > +		} while (retry_cnt-- > 0);
> 
> What's the purpose of the above dance? Why do you have to try ten times,
> and what's with the header matching? None of this is explained in the
> commit message.

Fair, sorry for the missing explanation. The bridge only buffers 2
EDID blocks at a time at a fixed offset (block % 2). Writing 0xb028
re-triggers an asynchronous fetch of a fresh pair of blocks from the
sink, and the bridge has no "fetch done" status to wait on, so we
poll the buffer instead: 10 retries at 100ms apart, i.e. up to 1s,
which covers the fetch latency we've observed on this bridge (same
ballpark as the 600-650ms EDID-interrupt delay mentioned in the
commit message).

The header check is how we detect the new pair actually landed rather
than stale data from the previous fetch: block 0 always starts with
the fixed EDID header magic, so we accept it once that magic appears;
block 2 (an extension block) never carries that magic, so we accept it
once the previous block 0's leftover header is gone.

This will allow EDID fetch for more than 2 block monitors like Dell Curved Monitor (Model - U4021QW)

I will improve the commit msg in next revision.
> BR,
> Jani.
> 
> 
> > +
> > +		if (!ret && !edid_valid)
> > +			ret = -ETIMEDOUT;
> > +	} else {
> > +		ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
> > +
> > +		lt9611uxc_lock(lt9611uxc);
> > +		regmap_write(lt9611uxc->regmap, 0xb028, 0x00);
> > +		lt9611uxc_unlock(lt9611uxc);
> > +	}
> > +
> > +	return ret;
> > +}
> >  
> >  static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *bridge,
> >  							 struct drm_connector *connector)
> >
> > ---
> > base-commit: 8ef59ee794076e2b58cff357b12de2ba5d441271
> > change-id: 20260517-lt9611usc_edid34_misc_next-b02592de0b25
> >
> > Best regards,
> 
> -- 
> Jani Nikula, Intel

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-24 19:33 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-22  3:50 [PATCH v4] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks vishnu.saini
2026-09-22  4:02 ` sashiko-bot
2026-09-22  8:55 ` Jani Nikula
2026-09-24 19:33   ` Vishnu Saini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.