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.

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

Signed-off-by: Ravi Agola <[email protected]>
Signed-off-by: Vishnu Saini <[email protected]>
---
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 | 74 +++++++++++++++++++++++++-----
 1 file changed, 63 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c 
b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
index 11aab07d88df..6c13d93996b1 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"
 
@@ -170,6 +170,9 @@ static void lt9611uxc_hpd_work(struct work_struct *work)
        connected = lt9611uxc->hdmi_connected;
        mutex_unlock(&lt9611uxc->ocm_lock);
 
+       if (!connected)
+               lt9611uxc->edid_read = false;
+
        drm_bridge_hpd_notify(&lt9611uxc->bridge,
                              connected ?
                              connector_status_connected :
@@ -384,10 +387,35 @@ static int lt9611uxc_wait_for_edid(struct lt9611uxc 
*lt9611uxc)
                        msecs_to_jiffies(500));
 }
 
+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;
+       const u8 edid_header[8] = { 0x00, 0xFF, 0xFF, 0xFF,
+                                   0xFF, 0xFF, 0xFF, 0x00 };
 
        if (len > EDID_BLOCK_SIZE)
                return -EINVAL;
@@ -395,20 +423,44 @@ 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);
+                       if ((block == 0 && header_matched) ||
+                           (block == 2 && !header_matched))
+                               break;
+
+               } while (retry_cnt-- > 0);
+       } 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: 4c26e162947f91aa78ba57dd4fddd38fc80e7d60
change-id: 20260517-lt9611usc_edid34_misc_next-b02592de0b25

Best regards,
-- 
Vishnu Saini <[email protected]>

Reply via email to