@@ -247,6 +247,15 @@ enum adv7511_input_sync_pulse {
ADV7511_INPUT_SYNC_PULSE_NONE = 3,
};
+enum adv7511_ddc_status {
+ ADV7511_DDC_STATUS_IN_RESET = 0,
+ ADV7511_DDC_STATUS_READING_EDID = 1,
+ ADV7511_DDC_STATUS_WAIT_HDCP = 2,
+ ADV7511_DDC_STATUS_INIT_HDCP = 3,
+ ADV7511_DDC_STATUS_HDCP_ENABLED = 4,
+ ADV7511_DDC_STATUS_INIT_HDCP_REPEATER = 5,
+};
+
/**
* enum adv7511_sync_polarity - Polarity for the input sync signals
* @ADV7511_SYNC_POLARITY_PASSTHROUGH: Sync polarity matches that of
@@ -533,6 +533,48 @@ static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout)
return adv7511->edid_read ? 0 : -EIO;
}
+static int adv7511_wait_for_hdcp(struct adv7511 *adv7511)
+{
+ struct device *dev = &adv7511->i2c_edid->dev;
+ unsigned int status = 0;
+ const int interval = 25;
+ int timeout = 100;
+ int ret = -EINVAL;
+
+ for (; timeout > 0; timeout -= interval) {
+ ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS,
+ &status);
+ if (ret < 0)
+ return ret;
+
+ status &= 0x0F;
+
+ switch (status) {
+ case ADV7511_DDC_STATUS_IN_RESET:
+ case ADV7511_DDC_STATUS_READING_EDID:
+ case ADV7511_DDC_STATUS_HDCP_ENABLED:
+ return 0;
+ case ADV7511_DDC_STATUS_WAIT_HDCP:
+ case ADV7511_DDC_STATUS_INIT_HDCP:
+ case ADV7511_DDC_STATUS_INIT_HDCP_REPEATER:
+ dev_dbg(dev, "DDC status 0x%x\n", status);
+ break;
+ default:
+ dev_err(dev, "Unknown status 0x%x\n", status);
+ return -EIO;
+ }
+
+ msleep(interval);
+ }
+
+ if (status) {
+ dev_warn(dev, "Stuck in HDCP state 0x%x\n", status);
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
+
static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
size_t len)
{
@@ -547,21 +589,20 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
return -EINVAL;
if (adv7511->current_edid_segment != edid_segment) {
- unsigned int status;
-
- ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS,
- &status);
+ /*
+ * EDID and HDCP shares memory so make sure HDCP is done before
+ * reading EDID.
+ */
+ ret = adv7511_wait_for_hdcp(adv7511);
if (ret < 0)
return ret;
- if (status != 2) {
- adv7511->edid_read = false;
- regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT,
- edid_segment);
- ret = adv7511_wait_for_edid(adv7511, 200);
- if (ret < 0)
- return ret;
- }
+ adv7511->edid_read = false;
+ regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT,
+ edid_segment);
+ ret = adv7511_wait_for_edid(adv7511, 200);
+ if (ret < 0)
+ return ret;
/* Break this apart, hopefully more I2C controllers will
* support 64 byte transfers than 256 byte transfers
Change check of DDC status. Instead of silently not reading EDID when in "IDLE" state [1]. Wait for HDCP being initialized because the EDID and HDCP block shares memory [2]. [1] ADV7511 Programming Guide revision G: Table 11: DDCController Status: 0xC8 [3:0] DDC Controller State 0b0000 In Reset (No Hot Plug Detected) 0b0001 Reading EDID 0b0010 IDLE (Waiting for HDCP Requested) 0b0011 Initializing HDCP 0b0100 HDCP Enabled 0b0101 Initializing HDCP Repeater [2] ADV7511 Programming Guide revision G: 4.6.1.1 EDID Definitions: EDID and HDCP use a shared memory space. During HDCP repeater initialization, the EDID data is overwritten with HDCP information. EDID is not re-read after HDCP initialization. If the user would like to re-buffer an EDID segment the EDID re-read register described in section 4.6.1.4 should be used. Fixes: 9c8af882bf12 ("drm: Add adv7511 encoder driver") Signed-off-by: Emil Svendsen <emas@bang-olufsen.dk> --- drivers/gpu/drm/bridge/adv7511/adv7511.h | 9 +++ drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 65 ++++++++++++++++---- 2 files changed, 62 insertions(+), 12 deletions(-)