|
@@ -83,6 +83,9 @@ struct sii8620 {
|
|
|
u8 devcap[MHL_DCAP_SIZE];
|
|
|
u8 xdevcap[MHL_XDC_SIZE];
|
|
|
u8 avif[HDMI_INFOFRAME_SIZE(AVI)];
|
|
|
+ bool feature_complete;
|
|
|
+ bool devcap_read;
|
|
|
+ bool sink_detected;
|
|
|
struct edid *edid;
|
|
|
unsigned int gen2_write_burst:1;
|
|
|
enum sii8620_mt_state mt_state;
|
|
@@ -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[] = {
|
|
|
[SINK_NONE] = "NONE",
|
|
@@ -490,7 +493,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret)
|
|
|
char sink_name[20];
|
|
|
struct device *dev = ctx->dev;
|
|
|
|
|
|
- if (ret < 0)
|
|
|
+ if (!ctx->sink_detected || !ctx->devcap_read)
|
|
|
return;
|
|
|
|
|
|
sii8620_fetch_edid(ctx);
|
|
@@ -499,6 +502,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret)
|
|
|
sii8620_mhl_disconnected(ctx);
|
|
|
return;
|
|
|
}
|
|
|
+ sii8620_set_upstream_edid(ctx);
|
|
|
|
|
|
if (drm_detect_hdmi_monitor(ctx->edid))
|
|
|
ctx->sink_type = SINK_HDMI;
|
|
@@ -511,15 +515,6 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret)
|
|
|
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)
|
|
|
{
|
|
|
u8 dcap[MHL_DCAP_SIZE];
|
|
@@ -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_DEVICE_ID_H], dcap[MHL_DCAP_DEVICE_ID_L]);
|
|
|
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)
|
|
@@ -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)
|
|
|
{
|
|
|
sii8620_disable_gen2_write_burst(ctx);
|
|
@@ -1533,7 +1540,7 @@ static void sii8620_disconnect(struct sii8620 *ctx)
|
|
|
REG_MHL_DP_CTL6, 0x2A,
|
|
|
REG_MHL_DP_CTL7, 0x03
|
|
|
);
|
|
|
- sii8620_disable_hpd(ctx);
|
|
|
+ sii8620_hpd_unplugged(ctx);
|
|
|
sii8620_write_seq_static(ctx,
|
|
|
REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE,
|
|
|
REG_MHL_COC_CTL1, 0x07,
|
|
@@ -1581,10 +1588,8 @@ static void sii8620_disconnect(struct sii8620 *ctx)
|
|
|
memset(ctx->xstat, 0, sizeof(ctx->xstat));
|
|
|
memset(ctx->devcap, 0, sizeof(ctx->devcap));
|
|
|
memset(ctx->xdevcap, 0, sizeof(ctx->xdevcap));
|
|
|
+ ctx->devcap_read = false;
|
|
|
ctx->cbus_status = 0;
|
|
|
- ctx->sink_type = SINK_NONE;
|
|
|
- kfree(ctx->edid);
|
|
|
- ctx->edid = NULL;
|
|
|
sii8620_mt_cleanup(ctx);
|
|
|
}
|
|
|
|
|
@@ -1675,9 +1680,6 @@ static void sii8620_status_changed_path(struct sii8620 *ctx)
|
|
|
sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
|
|
|
MHL_DST_LM_CLK_MODE_NORMAL
|
|
|
| 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 {
|
|
|
sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
|
|
|
MHL_DST_LM_CLK_MODE_NORMAL);
|
|
@@ -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->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);
|
|
|
|
|
|
+ if (!sii8620_is_mhl3(ctx))
|
|
|
+ sii8620_mt_read_devcap(ctx, false);
|
|
|
+ }
|
|
|
+
|
|
|
if (st[MHL_DST_LINK_MODE] & MHL_DST_LM_PATH_ENABLED)
|
|
|
sii8620_status_changed_path(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)
|
|
|
sii8620_send_features(ctx);
|
|
|
- if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_COMPLETE)
|
|
|
- sii8620_edid_read(ctx, 0);
|
|
|
+ if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_COMPLETE) {
|
|
|
+ ctx->feature_complete = true;
|
|
|
+ if (ctx->edid)
|
|
|
+ sii8620_enable_hpd(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)
|
|
|
if (stat & BIT_CBUS_MSC_MR_WRITE_STAT)
|
|
|
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)
|
|
|
sii8620_msc_mr_set_int(ctx);
|
|
|
|
|
@@ -1967,11 +1986,11 @@ static void sii8620_irq_ddc(struct sii8620 *ctx)
|
|
|
|
|
|
if (stat & BIT_DDC_CMD_DONE) {
|
|
|
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),
|
|
|
MHL_INT_RC_FEAT_REQ);
|
|
|
else
|
|
|
- sii8620_edid_read(ctx, 0);
|
|
|
+ sii8620_enable_hpd(ctx);
|
|
|
}
|
|
|
sii8620_write(ctx, REG_INTR3, stat);
|
|
|
}
|