diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/4470-drm-amd-display-don-t-create-new-dc_sink-if-nothing-.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.14.71/4470-drm-amd-display-don-t-create-new-dc_sink-if-nothing-.patch | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/4470-drm-amd-display-don-t-create-new-dc_sink-if-nothing-.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/4470-drm-amd-display-don-t-create-new-dc_sink-if-nothing-.patch new file mode 100644 index 00000000..c06e641a --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/4470-drm-amd-display-don-t-create-new-dc_sink-if-nothing-.patch @@ -0,0 +1,198 @@ +From a5fb0c76a967f9db863b611301ee9f236801a6ed Mon Sep 17 00:00:00 2001 +From: Samson Tam <Samson.Tam@amd.com> +Date: Fri, 13 Apr 2018 18:38:56 -0400 +Subject: [PATCH 4470/5725] drm/amd/display: don't create new dc_sink if + nothing changed at detection + +Signed-off-by: Samson Tam <Samson.Tam@amd.com> +Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> +Acked-by: Harry Wentland <harry.wentland@amd.com> +--- + drivers/gpu/drm/amd/display/dc/core/dc_link.c | 95 ++++++++++++++++++++++----- + 1 file changed, 77 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +index ea5d5ff..2fa5218 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +@@ -469,6 +469,13 @@ static void link_disconnect_sink(struct dc_link *link) + link->dpcd_sink_count = 0; + } + ++static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *link) ++{ ++ dc_sink_release(link->local_sink); ++ link->local_sink = prev_sink; ++} ++ ++ + static bool detect_dp( + struct dc_link *link, + struct display_sink_capability *sink_caps, +@@ -551,6 +558,17 @@ static bool detect_dp( + return true; + } + ++static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid) ++{ ++ if (old_edid->length != new_edid->length) ++ return false; ++ ++ if (new_edid->length == 0) ++ return false; ++ ++ return (memcmp(old_edid->raw_edid, new_edid->raw_edid, new_edid->length) == 0); ++} ++ + bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + { + struct dc_sink_init_data sink_init_data = { 0 }; +@@ -558,9 +576,13 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + uint8_t i; + bool converter_disable_audio = false; + struct audio_support *aud_support = &link->dc->res_pool->audio_support; ++ bool same_edid = false; + enum dc_edid_status edid_status; + struct dc_context *dc_ctx = link->ctx; + struct dc_sink *sink = NULL; ++ struct dc_sink *prev_sink = NULL; ++ struct dpcd_caps prev_dpcd_caps; ++ bool same_dpcd = true; + enum dc_connection_type new_connection_type = dc_connection_none; + DC_LOGGER_INIT(link->ctx->logger); + if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) +@@ -575,6 +597,11 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + link->local_sink) + return true; + ++ prev_sink = link->local_sink; ++ if (prev_sink != NULL) { ++ dc_sink_retain(prev_sink); ++ memcpy(&prev_dpcd_caps, &link->dpcd_caps, sizeof(struct dpcd_caps)); ++ } + link_disconnect_sink(link); + + if (new_connection_type != dc_connection_none) { +@@ -616,14 +643,25 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + link, + &sink_caps, + &converter_disable_audio, +- aud_support, reason)) ++ aud_support, reason)) { ++ if (prev_sink != NULL) ++ dc_sink_release(prev_sink); + return false; ++ } + ++ // Check if dpcp block is the same ++ if (prev_sink != NULL) { ++ if (memcmp(&link->dpcd_caps, &prev_dpcd_caps, sizeof(struct dpcd_caps))) ++ same_dpcd = false; ++ } + /* Active dongle downstream unplug */ + if (link->type == dc_connection_active_dongle + && link->dpcd_caps.sink_count. +- bits.SINK_COUNT == 0) ++ bits.SINK_COUNT == 0) { ++ if (prev_sink != NULL) ++ dc_sink_release(prev_sink); + return true; ++ } + + if (link->type == dc_connection_mst_branch) { + LINK_INFO("link=%d, mst branch is now Connected\n", +@@ -634,6 +672,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + * pbn_per_slot value leading to exception on dc_fixpt_div() + */ + link->verified_link_cap = link->reported_link_cap; ++ if (prev_sink != NULL) ++ dc_sink_release(prev_sink); + return false; + } + +@@ -643,6 +683,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + default: + DC_ERROR("Invalid connector type! signal:%d\n", + link->connector_signal); ++ if (prev_sink != NULL) ++ dc_sink_release(prev_sink); + return false; + } /* switch() */ + +@@ -665,6 +707,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + sink = dc_sink_create(&sink_init_data); + if (!sink) { + DC_ERROR("Failed to create sink!\n"); ++ if (prev_sink != NULL) ++ dc_sink_release(prev_sink); + return false; + } + +@@ -688,22 +732,33 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + break; + } + +- if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && +- sink_caps.transaction_type == +- DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { +- /* +- * TODO debug why Dell 2413 doesn't like +- * two link trainings +- */ ++ // Check if edid is the same ++ if ((prev_sink != NULL) && ((edid_status == EDID_THE_SAME) || (edid_status == EDID_OK))) ++ same_edid = is_same_edid(&prev_sink->dc_edid, &sink->dc_edid); + +- /* deal with non-mst cases */ +- dp_hbr_verify_link_cap(link, &link->reported_link_cap); +- } ++ // If both edid and dpcd are the same, then discard new sink and revert back to original sink ++ if ((same_edid) && (same_dpcd)) { ++ link_disconnect_remap(prev_sink, link); ++ sink = prev_sink; ++ prev_sink = NULL; ++ } else { ++ if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && ++ sink_caps.transaction_type == ++ DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { ++ /* ++ * TODO debug why Dell 2413 doesn't like ++ * two link trainings ++ */ ++ ++ /* deal with non-mst cases */ ++ dp_hbr_verify_link_cap(link, &link->reported_link_cap); ++ } + +- /* HDMI-DVI Dongle */ +- if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && +- !sink->edid_caps.edid_hdmi) +- sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK; ++ /* HDMI-DVI Dongle */ ++ if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && ++ !sink->edid_caps.edid_hdmi) ++ sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK; ++ } + + /* Connectivity log: detection */ + for (i = 0; i < sink->dc_edid.length / EDID_BLOCK_SIZE; i++) { +@@ -762,10 +817,14 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) + sink_caps.signal = SIGNAL_TYPE_NONE; + } + +- LINK_INFO("link=%d, dc_sink_in=%p is now %s\n", ++ LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p dpcd same=%d edid same=%d\n", + link->link_index, sink, + (sink_caps.signal == SIGNAL_TYPE_NONE ? +- "Disconnected":"Connected")); ++ "Disconnected":"Connected"), prev_sink, ++ same_dpcd, same_edid); ++ ++ if (prev_sink != NULL) ++ dc_sink_release(prev_sink); + + return true; + } +-- +2.7.4 + |