* [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(<9611uxc->ocm_lock); connected = lt9611uxc->hdmi_connected; + if (!connected) + lt9611uxc->edid_read = false; mutex_unlock(<9611uxc->ocm_lock); drm_bridge_hpd_notify(<9611uxc->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(<9611uxc->ocm_lock); > connected = lt9611uxc->hdmi_connected; > + if (!connected) > + lt9611uxc->edid_read = false; > mutex_unlock(<9611uxc->ocm_lock); > > drm_bridge_hpd_notify(<9611uxc->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(<9611uxc->ocm_lock); > > connected = lt9611uxc->hdmi_connected; > > + if (!connected) > > + lt9611uxc->edid_read = false; > > mutex_unlock(<9611uxc->ocm_lock); > > > > drm_bridge_hpd_notify(<9611uxc->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.