From: Ravi Agola <[email protected]> The lt9611uxc driver previously limited EDID reading to 2 blocks, which restricted support for displays that provide more than two EDID blocks. This change enables the driver to read and pass up to 4 EDID blocks from the LT9611UXC to drm_edid calls. As a result, the driver now supports displays with up to 4 EDID block.
Signed-off-by: Ravi Agola <[email protected]> Signed-off-by: Nilesh Laad <[email protected]> --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 93 ++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 4d989381904c..7fe481c7acf8 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,11 @@ struct lt9611uxc { /* can be accessed from different threads, so protect this with ocm_lock */ bool hdmi_connected; uint8_t fw_version; + + bool edid_available; + unsigned int num_edid_blocks; + uint8_t edid_raw[EDID_BLOCK_SIZE * EDID_NUM_BLOCKS]; + }; #define LT9611_PAGE_CONTROL 0xff @@ -170,8 +175,12 @@ static void lt9611uxc_hpd_work(struct work_struct *work) connected = lt9611uxc->hdmi_connected; mutex_unlock(<9611uxc->ocm_lock); - if (!connected) + if (!connected) { lt9611uxc->edid_read = false; + lt9611uxc->edid_available = false; + lt9611uxc->num_edid_blocks = 0; + memset(lt9611uxc->edid_raw, 0, EDID_BLOCK_SIZE * EDID_NUM_BLOCKS); + } drm_bridge_hpd_notify(<9611uxc->bridge, connected ? @@ -387,10 +396,32 @@ 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) +{ + int ret; + + lt9611uxc_lock(lt9611uxc); + + regmap_write(lt9611uxc->regmap, 0xb00a, (block%2) * EDID_BLOCK_SIZE); + + ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, + <9611uxc->edid_raw[block*EDID_BLOCK_SIZE], EDID_BLOCK_SIZE); + 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; if (len > EDID_BLOCK_SIZE) return -EINVAL; @@ -398,19 +429,59 @@ 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 edid is read once, provide same edid data till next hpd event + */ + if (lt9611uxc->edid_available && (block < lt9611uxc->num_edid_blocks)) + memcpy(buf, <9611uxc->edid_raw[EDID_BLOCK_SIZE*block], EDID_BLOCK_SIZE); + else { + /* + * read number of block available in edid data + */ + if (block == 0) { + lt9611uxc_lock(lt9611uxc); + ret = regmap_read(lt9611uxc->regmap, 0xb02a, &edid_ext_block); + if (ret) + dev_err(lt9611uxc->dev, "edid block read failed: %d\n", ret); + else + lt9611uxc->num_edid_blocks = edid_ext_block & 0x7; + lt9611uxc_unlock(lt9611uxc); + } - regmap_write(lt9611uxc->regmap, 0xb00b, 0x10); + /* read edid block */ + ret = lt9611uxc_read_edid_block(lt9611uxc, block); + + /* compare first 4 bytes of 0th and 2nd block to confirm + * that 2nd edid block data is read successfully by lt9611uxc + */ + while ((block == 2) && 0 == memcmp(<9611uxc->edid_raw[block*EDID_BLOCK_SIZE], + <9611uxc->edid_raw[(block%2)*EDID_BLOCK_SIZE], 4) + && retry_cnt-- > 0) { + msleep(100); + ret = lt9611uxc_read_edid_block(lt9611uxc, block); + } - regmap_write(lt9611uxc->regmap, 0xb00a, block * EDID_BLOCK_SIZE); + /* if more than 2 edid block are available, reset edid ready + * flag once 0th and 1st edid block read is completed + * so lt9611uxc read 2nd and 3rd block + */ + if (block == 1 && lt9611uxc->num_edid_blocks > 2) { + lt9611uxc_lock(lt9611uxc); + regmap_write(lt9611uxc->regmap, 0xb02a, (edid_ext_block & (~BIT(3)))); + lt9611uxc_unlock(lt9611uxc); + msleep(100); + } - ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len); - if (ret) - dev_err(lt9611uxc->dev, "edid read failed: %d\n", ret); + /* set edid available to true once all edid blocks read successfully */ + if (block == (lt9611uxc->num_edid_blocks-1) && ret == 0) + lt9611uxc->edid_available = true; - lt9611uxc_unlock(lt9611uxc); + /* copy edid block data into buffer */ + if (ret == 0) + memcpy(buf, <9611uxc->edid_raw[EDID_BLOCK_SIZE*block], EDID_BLOCK_SIZE); + } - return 0; + return ret; }; static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *bridge, --- base-commit: 3ea699b56d31c2a5140d9fac309ff5e0f2041411 change-id: 20260202-extend-edid-support-b5a4f76d1832 prerequisite-message-id: [email protected] prerequisite-patch-id: bbe63ef7dc85903a286cefd9aa09f1e2e96351b1 Best regards, -- Nilesh Laad <[email protected]>
