Commit c7d6d511 authored by Maciej Purski's avatar Maciej Purski Committed by Andrzej Hajda

drm/bridge/sii8620: fix HDMI cable connection to dongle

MHL bridge is usually connected to TV via MHL dongle. Currently plugging
HDMI cable to dongle is handled improperly.

Fix it by splitting connecting of a dongle and a HDMI cable. The driver
should now handle unplugging a sink from a dongle and plugging a
different sink with new edid.

Tested on MHL1, MHL2 and MHL3 using various vendors' dongles both in
DVI and HDMI mode.
Signed-off-by: default avatarMaciej Purski <m.purski@samsung.com>
Signed-off-by: default avatarAndrzej Hajda <a.hajda@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1516705996-8928-1-git-send-email-m.purski@samsung.com
parent 95e85225
...@@ -83,6 +83,9 @@ struct sii8620 { ...@@ -83,6 +83,9 @@ struct sii8620 {
u8 devcap[MHL_DCAP_SIZE]; u8 devcap[MHL_DCAP_SIZE];
u8 xdevcap[MHL_XDC_SIZE]; u8 xdevcap[MHL_XDC_SIZE];
u8 avif[HDMI_INFOFRAME_SIZE(AVI)]; u8 avif[HDMI_INFOFRAME_SIZE(AVI)];
bool feature_complete;
bool devcap_read;
bool sink_detected;
struct edid *edid; struct edid *edid;
unsigned int gen2_write_burst:1; unsigned int gen2_write_burst:1;
enum sii8620_mt_state mt_state; enum sii8620_mt_state mt_state;
...@@ -479,7 +482,7 @@ static void sii8620_update_array(u8 *dst, u8 *src, int count) ...@@ -479,7 +482,7 @@ static void sii8620_update_array(u8 *dst, u8 *src, int count)
} }
} }
static void sii8620_sink_detected(struct sii8620 *ctx, int ret) static void sii8620_identify_sink(struct sii8620 *ctx)
{ {
static const char * const sink_str[] = { static const char * const sink_str[] = {
[SINK_NONE] = "NONE", [SINK_NONE] = "NONE",
...@@ -490,7 +493,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret) ...@@ -490,7 +493,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret)
char sink_name[20]; char sink_name[20];
struct device *dev = ctx->dev; struct device *dev = ctx->dev;
if (ret < 0) if (!ctx->sink_detected || !ctx->devcap_read)
return; return;
sii8620_fetch_edid(ctx); sii8620_fetch_edid(ctx);
...@@ -499,6 +502,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret) ...@@ -499,6 +502,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret)
sii8620_mhl_disconnected(ctx); sii8620_mhl_disconnected(ctx);
return; return;
} }
sii8620_set_upstream_edid(ctx);
if (drm_detect_hdmi_monitor(ctx->edid)) if (drm_detect_hdmi_monitor(ctx->edid))
ctx->sink_type = SINK_HDMI; ctx->sink_type = SINK_HDMI;
...@@ -511,15 +515,6 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret) ...@@ -511,15 +515,6 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret)
sink_str[ctx->sink_type], sink_name); sink_str[ctx->sink_type], sink_name);
} }
static void sii8620_edid_read(struct sii8620 *ctx, int ret)
{
if (ret < 0)
return;
sii8620_set_upstream_edid(ctx);
sii8620_enable_hpd(ctx);
}
static void sii8620_mr_devcap(struct sii8620 *ctx) static void sii8620_mr_devcap(struct sii8620 *ctx)
{ {
u8 dcap[MHL_DCAP_SIZE]; u8 dcap[MHL_DCAP_SIZE];
...@@ -535,6 +530,8 @@ static void sii8620_mr_devcap(struct sii8620 *ctx) ...@@ -535,6 +530,8 @@ static void sii8620_mr_devcap(struct sii8620 *ctx)
dcap[MHL_DCAP_ADOPTER_ID_H], dcap[MHL_DCAP_ADOPTER_ID_L], dcap[MHL_DCAP_ADOPTER_ID_H], dcap[MHL_DCAP_ADOPTER_ID_L],
dcap[MHL_DCAP_DEVICE_ID_H], dcap[MHL_DCAP_DEVICE_ID_L]); dcap[MHL_DCAP_DEVICE_ID_H], dcap[MHL_DCAP_DEVICE_ID_L]);
sii8620_update_array(ctx->devcap, dcap, MHL_DCAP_SIZE); sii8620_update_array(ctx->devcap, dcap, MHL_DCAP_SIZE);
ctx->devcap_read = true;
sii8620_identify_sink(ctx);
} }
static void sii8620_mr_xdevcap(struct sii8620 *ctx) static void sii8620_mr_xdevcap(struct sii8620 *ctx)
...@@ -1506,6 +1503,16 @@ static void sii8620_set_mode(struct sii8620 *ctx, enum sii8620_mode mode) ...@@ -1506,6 +1503,16 @@ static void sii8620_set_mode(struct sii8620 *ctx, enum sii8620_mode mode)
); );
} }
static void sii8620_hpd_unplugged(struct sii8620 *ctx)
{
sii8620_disable_hpd(ctx);
ctx->sink_type = SINK_NONE;
ctx->sink_detected = false;
ctx->feature_complete = false;
kfree(ctx->edid);
ctx->edid = NULL;
}
static void sii8620_disconnect(struct sii8620 *ctx) static void sii8620_disconnect(struct sii8620 *ctx)
{ {
sii8620_disable_gen2_write_burst(ctx); sii8620_disable_gen2_write_burst(ctx);
...@@ -1533,7 +1540,7 @@ static void sii8620_disconnect(struct sii8620 *ctx) ...@@ -1533,7 +1540,7 @@ static void sii8620_disconnect(struct sii8620 *ctx)
REG_MHL_DP_CTL6, 0x2A, REG_MHL_DP_CTL6, 0x2A,
REG_MHL_DP_CTL7, 0x03 REG_MHL_DP_CTL7, 0x03
); );
sii8620_disable_hpd(ctx); sii8620_hpd_unplugged(ctx);
sii8620_write_seq_static(ctx, sii8620_write_seq_static(ctx,
REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE, REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE,
REG_MHL_COC_CTL1, 0x07, REG_MHL_COC_CTL1, 0x07,
...@@ -1581,10 +1588,8 @@ static void sii8620_disconnect(struct sii8620 *ctx) ...@@ -1581,10 +1588,8 @@ static void sii8620_disconnect(struct sii8620 *ctx)
memset(ctx->xstat, 0, sizeof(ctx->xstat)); memset(ctx->xstat, 0, sizeof(ctx->xstat));
memset(ctx->devcap, 0, sizeof(ctx->devcap)); memset(ctx->devcap, 0, sizeof(ctx->devcap));
memset(ctx->xdevcap, 0, sizeof(ctx->xdevcap)); memset(ctx->xdevcap, 0, sizeof(ctx->xdevcap));
ctx->devcap_read = false;
ctx->cbus_status = 0; ctx->cbus_status = 0;
ctx->sink_type = SINK_NONE;
kfree(ctx->edid);
ctx->edid = NULL;
sii8620_mt_cleanup(ctx); sii8620_mt_cleanup(ctx);
} }
...@@ -1675,9 +1680,6 @@ static void sii8620_status_changed_path(struct sii8620 *ctx) ...@@ -1675,9 +1680,6 @@ static void sii8620_status_changed_path(struct sii8620 *ctx)
sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE), sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
MHL_DST_LM_CLK_MODE_NORMAL MHL_DST_LM_CLK_MODE_NORMAL
| MHL_DST_LM_PATH_ENABLED); | MHL_DST_LM_PATH_ENABLED);
if (!sii8620_is_mhl3(ctx))
sii8620_mt_read_devcap(ctx, false);
sii8620_mt_set_cont(ctx, sii8620_sink_detected);
} else { } else {
sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE), sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
MHL_DST_LM_CLK_MODE_NORMAL); MHL_DST_LM_CLK_MODE_NORMAL);
...@@ -1694,9 +1696,14 @@ static void sii8620_msc_mr_write_stat(struct sii8620 *ctx) ...@@ -1694,9 +1696,14 @@ static void sii8620_msc_mr_write_stat(struct sii8620 *ctx)
sii8620_update_array(ctx->stat, st, MHL_DST_SIZE); sii8620_update_array(ctx->stat, st, MHL_DST_SIZE);
sii8620_update_array(ctx->xstat, xst, MHL_XDS_SIZE); sii8620_update_array(ctx->xstat, xst, MHL_XDS_SIZE);
if (ctx->stat[MHL_DST_CONNECTED_RDY] & MHL_DST_CONN_DCAP_RDY) if (ctx->stat[MHL_DST_CONNECTED_RDY] & st[MHL_DST_CONNECTED_RDY] &
MHL_DST_CONN_DCAP_RDY) {
sii8620_status_dcap_ready(ctx); sii8620_status_dcap_ready(ctx);
if (!sii8620_is_mhl3(ctx))
sii8620_mt_read_devcap(ctx, false);
}
if (st[MHL_DST_LINK_MODE] & MHL_DST_LM_PATH_ENABLED) if (st[MHL_DST_LINK_MODE] & MHL_DST_LM_PATH_ENABLED)
sii8620_status_changed_path(ctx); sii8620_status_changed_path(ctx);
} }
...@@ -1780,8 +1787,11 @@ static void sii8620_msc_mr_set_int(struct sii8620 *ctx) ...@@ -1780,8 +1787,11 @@ static void sii8620_msc_mr_set_int(struct sii8620 *ctx)
} }
if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_REQ) if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_REQ)
sii8620_send_features(ctx); sii8620_send_features(ctx);
if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_COMPLETE) if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_COMPLETE) {
sii8620_edid_read(ctx, 0); ctx->feature_complete = true;
if (ctx->edid)
sii8620_enable_hpd(ctx);
}
} }
static struct sii8620_mt_msg *sii8620_msc_msg_first(struct sii8620 *ctx) static struct sii8620_mt_msg *sii8620_msc_msg_first(struct sii8620 *ctx)
...@@ -1856,6 +1866,15 @@ static void sii8620_irq_msc(struct sii8620 *ctx) ...@@ -1856,6 +1866,15 @@ static void sii8620_irq_msc(struct sii8620 *ctx)
if (stat & BIT_CBUS_MSC_MR_WRITE_STAT) if (stat & BIT_CBUS_MSC_MR_WRITE_STAT)
sii8620_msc_mr_write_stat(ctx); sii8620_msc_mr_write_stat(ctx);
if (stat & BIT_CBUS_HPD_CHG) {
if (ctx->cbus_status & BIT_CBUS_STATUS_CBUS_HPD) {
ctx->sink_detected = true;
sii8620_identify_sink(ctx);
} else {
sii8620_hpd_unplugged(ctx);
}
}
if (stat & BIT_CBUS_MSC_MR_SET_INT) if (stat & BIT_CBUS_MSC_MR_SET_INT)
sii8620_msc_mr_set_int(ctx); sii8620_msc_mr_set_int(ctx);
...@@ -1967,11 +1986,11 @@ static void sii8620_irq_ddc(struct sii8620 *ctx) ...@@ -1967,11 +1986,11 @@ static void sii8620_irq_ddc(struct sii8620 *ctx)
if (stat & BIT_DDC_CMD_DONE) { if (stat & BIT_DDC_CMD_DONE) {
sii8620_write(ctx, REG_INTR3_MASK, 0); sii8620_write(ctx, REG_INTR3_MASK, 0);
if (sii8620_is_mhl3(ctx)) if (sii8620_is_mhl3(ctx) && !ctx->feature_complete)
sii8620_mt_set_int(ctx, MHL_INT_REG(RCHANGE), sii8620_mt_set_int(ctx, MHL_INT_REG(RCHANGE),
MHL_INT_RC_FEAT_REQ); MHL_INT_RC_FEAT_REQ);
else else
sii8620_edid_read(ctx, 0); sii8620_enable_hpd(ctx);
} }
sii8620_write(ctx, REG_INTR3, stat); sii8620_write(ctx, REG_INTR3, stat);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment