diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 1c0e97030419e..779e398e4aaa6 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -28,7 +28,7 @@ #include #define EDID_BLOCK_SIZE 128 -#define EDID_NUM_BLOCKS 2 +#define EDID_NUM_BLOCKS 4 #define FW_FILE "lt9611uxc_fw.bin" @@ -171,10 +171,9 @@ static void lt9611uxc_hpd_work(struct work_struct *work) mutex_lock(<9611uxc->ocm_lock); connected = lt9611uxc->hdmi_connected; - mutex_unlock(<9611uxc->ocm_lock); - if (!connected) lt9611uxc->edid_read = false; + mutex_unlock(<9611uxc->ocm_lock); drm_bridge_hpd_notify(<9611uxc->bridge, connected ? @@ -392,10 +391,36 @@ static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc) 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; @@ -403,20 +428,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)