On Tue, Sep 22, 2026 at 11:55:01AM +0300, Jani Nikula wrote:
> On Tue, 22 Sep 2026, [email protected] wrote:
> > From: Ravi Agola <[email protected]>
> >
> > 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 <[email protected]>
> > Signed-off-by: Vishnu Saini <[email protected]>
> > ---
> > 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-7ec2bba6f...@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-24ce3f577...@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-5e2fd8c63...@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

Reply via email to