Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 66 additions & 13 deletions drivers/gpu/drm/bridge/lontium-lt9611uxc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -171,10 +171,9 @@ static void lt9611uxc_hpd_work(struct work_struct *work)

mutex_lock(&lt9611uxc->ocm_lock);
connected = lt9611uxc->hdmi_connected;
mutex_unlock(&lt9611uxc->ocm_lock);

if (!connected)
lt9611uxc->edid_read = false;
mutex_unlock(&lt9611uxc->ocm_lock);

drm_bridge_hpd_notify(&lt9611uxc->bridge,
connected ?
Expand Down Expand Up @@ -392,31 +391,85 @@ 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;

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)
Expand Down