drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 84 ++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 11 deletions(-)
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.
Extend the driver to support up to 4 EDID blocks by re-triggering
EDID access after the first 2 blocks are read. For block 2, clear
the EDID ready flag in 0xb02a so the bridge can expose the remaining
blocks, then retry the read until the expected EDID is returned.
Also cache the full EDID blob in the driver and reuse it until the
next HPD disconnect event, so repeated EDID reads do not re-query
the bridge.
Signed-off-by: Ravi Agola <raviagol@qti.qualcomm.com>
Signed-off-by: Vishnu Saini <vishnu.saini@oss.qualcomm.com>
---
drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 84 ++++++++++++++++++++++++++----
1 file changed, 73 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
index 11aab07d88df..b5a9f62b9fe3 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"
@@ -61,6 +61,8 @@ struct lt9611uxc {
/* can be accessed from different threads, so protect this with ocm_lock */
bool hdmi_connected;
uint8_t fw_version;
+
+ const struct drm_edid *edid_data;
};
#define LT9611_PAGE_CONTROL 0xff
@@ -170,6 +172,12 @@ static void lt9611uxc_hpd_work(struct work_struct *work)
connected = lt9611uxc->hdmi_connected;
mutex_unlock(<9611uxc->ocm_lock);
+ if (!connected) {
+ lt9611uxc->edid_read = false;
+ drm_edid_free(lt9611uxc->edid_data);
+ lt9611uxc->edid_data = NULL;
+ }
+
drm_bridge_hpd_notify(<9611uxc->bridge,
connected ?
connector_status_connected :
@@ -384,10 +392,34 @@ 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;
+ int edid_ext_block;
+ const u8 edid_header[8] = { 0x00, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00 };
if (len > EDID_BLOCK_SIZE)
return -EINVAL;
@@ -395,19 +427,39 @@ 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 == 2) {
+ lt9611uxc_lock(lt9611uxc);
- regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
+ /* Read number of block available in EDID data */
+ ret = regmap_read(lt9611uxc->regmap, 0xb02a, &edid_ext_block);
+ if (ret) {
+ dev_err(lt9611uxc->dev, "edid block read failed: %d\n", ret);
+ lt9611uxc_unlock(lt9611uxc);
+ return ret;
+ }
- regmap_write(lt9611uxc->regmap, 0xb00a, block * EDID_BLOCK_SIZE);
+ /* Reset EDID ready flag so that lt9611uxc can read 2nd and 3rd block */
+ regmap_write(lt9611uxc->regmap, 0xb02a, (edid_ext_block & (~BIT(3))));
- ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
- if (ret)
- dev_err(lt9611uxc->dev, "edid read failed: %d\n", ret);
+ lt9611uxc_unlock(lt9611uxc);
- lt9611uxc_unlock(lt9611uxc);
+ msleep(100);
- return 0;
+ ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
+
+ /*
+ * Compare first 8 bytes of EDID header (0th block) and 2nd block to confirm
+ * that 2nd EDID block data is read successfully by lt9611uxc
+ */
+ while (!ret && 0 == memcmp(&edid_header, &buf, 8) && retry_cnt-- > 0) {
+ msleep(100);
+ ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
+ }
+ } else {
+ ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
+ }
+
+ return ret;
};
static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *bridge,
@@ -425,7 +477,17 @@ static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *brid
return NULL;
}
- return drm_edid_read_custom(connector, lt9611uxc_get_edid_block, lt9611uxc);
+ /* If EDID is read once, provide same EDID data till next HPD event */
+ if (lt9611uxc->edid_data == NULL) {
+ lt9611uxc->edid_data = drm_edid_read_custom(connector, lt9611uxc_get_edid_block,
+ lt9611uxc);
+ }
+
+ /*
+ * Copy the EDID data and return the copied value which will be freed by DRM.
+ * The original EDID data is cached in the driver until the next HPD event.
+ */
+ return drm_edid_dup(lt9611uxc->edid_data);
}
static void lt9611uxc_bridge_hpd_notify(struct drm_bridge *bridge,
---
base-commit: 4c26e162947f91aa78ba57dd4fddd38fc80e7d60
change-id: 20260517-lt9611usc_edid34_misc_next-b02592de0b25
Best regards,
--
Vishnu Saini <vishnu.saini@oss.qualcomm.com>
Hi,
kernel test robot noticed the following build errors:
[auto build test ERROR on 4c26e162947f91aa78ba57dd4fddd38fc80e7d60]
url: https://github.com/intel-lab-lkp/linux/commits/vishnu-saini-oss-qualcomm-com/drm-bridge-lt9611uxc-support-displays-with-up-to-4-EDID-blocks/20260518-021632
base: 4c26e162947f91aa78ba57dd4fddd38fc80e7d60
patch link: https://lore.kernel.org/r/20260517-lt9611usc_edid34_misc_next-v1-1-5e2fd8c6399b%40oss.qualcomm.com
patch subject: [PATCH] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks
config: i386-randconfig-014-20260518 (https://download.01.org/0day-ci/archive/20260518/202605180800.luZQCJZK-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260518/202605180800.luZQCJZK-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605180800.luZQCJZK-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from include/linux/string.h:386,
from include/linux/bitmap.h:13,
from include/linux/cpumask.h:11,
from arch/x86/include/asm/paravirt.h:19,
from arch/x86/include/asm/irqflags.h:100,
from include/linux/irqflags.h:18,
from include/linux/spinlock.h:59,
from include/linux/mmzone.h:8,
from include/linux/gfp.h:7,
from include/linux/firmware.h:8,
from drivers/gpu/drm/bridge/lontium-lt9611uxc.c:7:
In function 'memcmp',
inlined from 'lt9611uxc_get_edid_block' at drivers/gpu/drm/bridge/lontium-lt9611uxc.c:454:23:
>> include/linux/fortify-string.h:719:25: error: call to '__read_overflow2' declared with attribute error: detected read beyond size of object (2nd parameter)
719 | __read_overflow2();
| ^~~~~~~~~~~~~~~~~~
vim +/__read_overflow2 +719 include/linux/fortify-string.h
a28a6e860c6cf23 Francis Laniel 2021-02-25 708
92df138a8d663ce Kees Cook 2022-02-08 709 __FORTIFY_INLINE __diagnose_as(__builtin_memcmp, 1, 2, 3)
281d0c962752fb4 Kees Cook 2022-02-08 710 int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t size)
a28a6e860c6cf23 Francis Laniel 2021-02-25 711 {
21a2c74b0a2a784 Kees Cook 2023-04-07 712 const size_t p_size = __struct_size(p);
21a2c74b0a2a784 Kees Cook 2023-04-07 713 const size_t q_size = __struct_size(q);
a28a6e860c6cf23 Francis Laniel 2021-02-25 714
a28a6e860c6cf23 Francis Laniel 2021-02-25 715 if (__builtin_constant_p(size)) {
fa35198f39571bb Kees Cook 2022-09-19 716 if (__compiletime_lessthan(p_size, size))
a28a6e860c6cf23 Francis Laniel 2021-02-25 717 __read_overflow();
fa35198f39571bb Kees Cook 2022-09-19 718 if (__compiletime_lessthan(q_size, size))
a28a6e860c6cf23 Francis Laniel 2021-02-25 @719 __read_overflow2();
a28a6e860c6cf23 Francis Laniel 2021-02-25 720 }
3d965b33e40d973 Kees Cook 2023-04-07 721 if (p_size < size)
3d965b33e40d973 Kees Cook 2023-04-07 722 fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ, p_size, size, INT_MIN);
3d965b33e40d973 Kees Cook 2023-04-07 723 else if (q_size < size)
3d965b33e40d973 Kees Cook 2023-04-07 724 fortify_panic(FORTIFY_FUNC_memcmp, FORTIFY_READ, q_size, size, INT_MIN);
a28a6e860c6cf23 Francis Laniel 2021-02-25 725 return __underlying_memcmp(p, q, size);
a28a6e860c6cf23 Francis Laniel 2021-02-25 726 }
a28a6e860c6cf23 Francis Laniel 2021-02-25 727
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 4c26e162947f91aa78ba57dd4fddd38fc80e7d60]
url: https://github.com/intel-lab-lkp/linux/commits/vishnu-saini-oss-qualcomm-com/drm-bridge-lt9611uxc-support-displays-with-up-to-4-EDID-blocks/20260518-021632
base: 4c26e162947f91aa78ba57dd4fddd38fc80e7d60
patch link: https://lore.kernel.org/r/20260517-lt9611usc_edid34_misc_next-v1-1-5e2fd8c6399b%40oss.qualcomm.com
patch subject: [PATCH] drm/bridge: lt9611uxc: support displays with up to 4 EDID blocks
config: csky-randconfig-001-20260518 (https://download.01.org/0day-ci/archive/20260518/202605180850.uN2x73KR-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260518/202605180850.uN2x73KR-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605180850.uN2x73KR-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/gpu/drm/bridge/lontium-lt9611uxc.c: In function 'lt9611uxc_get_edid_block':
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:454:37: warning: 'memcmp' specified bound 8 exceeds source size 4 [-Wstringop-overread]
454 | while (!ret && 0 == memcmp(&edid_header, &buf, 8) && retry_cnt-- > 0) {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/gpu/drm/bridge/lontium-lt9611uxc.c:415:53: note: source object allocated here
415 | static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
| ~~~~^~~
vim +/memcmp +454 drivers/gpu/drm/bridge/lontium-lt9611uxc.c
414
415 static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
416 {
417 struct lt9611uxc *lt9611uxc = data;
418 int ret = 0;
419 int retry_cnt = 10;
420 int edid_ext_block;
421 const u8 edid_header[8] = { 0x00, 0xFF, 0xFF, 0xFF,
422 0xFF, 0xFF, 0xFF, 0x00 };
423
424 if (len > EDID_BLOCK_SIZE)
425 return -EINVAL;
426
427 if (block >= EDID_NUM_BLOCKS)
428 return -EINVAL;
429
430 if (block == 2) {
431 lt9611uxc_lock(lt9611uxc);
432
433 /* Read number of block available in EDID data */
434 ret = regmap_read(lt9611uxc->regmap, 0xb02a, &edid_ext_block);
435 if (ret) {
436 dev_err(lt9611uxc->dev, "edid block read failed: %d\n", ret);
437 lt9611uxc_unlock(lt9611uxc);
438 return ret;
439 }
440
441 /* Reset EDID ready flag so that lt9611uxc can read 2nd and 3rd block */
442 regmap_write(lt9611uxc->regmap, 0xb02a, (edid_ext_block & (~BIT(3))));
443
444 lt9611uxc_unlock(lt9611uxc);
445
446 msleep(100);
447
448 ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
449
450 /*
451 * Compare first 8 bytes of EDID header (0th block) and 2nd block to confirm
452 * that 2nd EDID block data is read successfully by lt9611uxc
453 */
> 454 while (!ret && 0 == memcmp(&edid_header, &buf, 8) && retry_cnt-- > 0) {
455 msleep(100);
456 ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
457 }
458 } else {
459 ret = lt9611uxc_read_edid_block(lt9611uxc, block, buf, len);
460 }
461
462 return ret;
463 };
464
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On Sun, May 17, 2026 at 11:44:49PM +0530, 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. > > Extend the driver to support up to 4 EDID blocks by re-triggering > EDID access after the first 2 blocks are read. For block 2, clear > the EDID ready flag in 0xb02a so the bridge can expose the remaining > blocks, then retry the read until the expected EDID is returned. Won't this affect re-reading of the EDID? If so, we might need to reset the flag at the block0 path too. > > Also cache the full EDID blob in the driver and reuse it until the > next HPD disconnect event, so repeated EDID reads do not re-query > the bridge. Separte commit, separate justification. Most of the drivers don't use the cache, so, I'd say, most likely no. > > Signed-off-by: Ravi Agola <raviagol@qti.qualcomm.com> > Signed-off-by: Vishnu Saini <vishnu.saini@oss.qualcomm.com> > --- > drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 84 ++++++++++++++++++++++++++---- > 1 file changed, 73 insertions(+), 11 deletions(-) > -- With best wishes Dmitry
On Sun, May 17, 2026 at 11:58:55PM +0300, Dmitry Baryshkov wrote: > On Sun, May 17, 2026 at 11:44:49PM +0530, 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. > > > > Extend the driver to support up to 4 EDID blocks by re-triggering > > EDID access after the first 2 blocks are read. For block 2, clear > > the EDID ready flag in 0xb02a so the bridge can expose the remaining > > blocks, then retry the read until the expected EDID is returned. > > Won't this affect re-reading of the EDID? If so, we might need to reset > the flag at the block0 path too. Yes, edid will be invalid while reading again, that's why trying to cache it. Correct edid received after HPD. Will try reset the flag at block0 > > > > Also cache the full EDID blob in the driver and reuse it until the > > next HPD disconnect event, so repeated EDID reads do not re-query > > the bridge. > > Separte commit, separate justification. Most of the drivers don't use > the cache, so, I'd say, most likely no. If flag reset at block0 gives correct edid we don't have to cache it, just that it will take few extra ms to load the edid data again. Lontium also shared the updated firmware to load upto 4 block edid, will check with them on upstreaming plan. > > > > Signed-off-by: Ravi Agola <raviagol@qti.qualcomm.com> > > Signed-off-by: Vishnu Saini <vishnu.saini@oss.qualcomm.com> > > --- > > drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 84 ++++++++++++++++++++++++++---- > > 1 file changed, 73 insertions(+), 11 deletions(-) > > > -- > With best wishes > Dmitry
© 2016 - 2026 Red Hat, Inc.