aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4051-drm-amd-display-fix-hotplug-during-display-off.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4051-drm-amd-display-fix-hotplug-during-display-off.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4051-drm-amd-display-fix-hotplug-during-display-off.patch286
1 files changed, 286 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4051-drm-amd-display-fix-hotplug-during-display-off.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4051-drm-amd-display-fix-hotplug-during-display-off.patch
new file mode 100644
index 00000000..72854024
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4051-drm-amd-display-fix-hotplug-during-display-off.patch
@@ -0,0 +1,286 @@
+From 5bf22bc8d5732211aa6f4ebd81c91acd1ae3a3eb Mon Sep 17 00:00:00 2001
+From: Joseph Gravenor <joseph.gravenor@amd.com>
+Date: Wed, 4 Sep 2019 12:43:05 -0400
+Subject: [PATCH 4051/4256] drm/amd/display: fix hotplug during display off
+
+[why]
+HPD is not suppressed when we lower
+clocks on renoir. B/c of this we do link
+training when the 48mhz refclk is off, which
+will cause ASIC hang.
+
+[how]
+Exit optimized power state for detection purpose.
+
+Signed-off-by: Joseph Gravenor <joseph.gravenor@amd.com>
+Reviewed-by: Eric Yang <eric.yang2@amd.com>
+Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
+---
+ .../amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c | 82 +++++++++++++++++--
+ .../amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h | 1 -
+ .../dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c | 15 +++-
+ .../dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h | 2 +-
+ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 21 ++++-
+ drivers/gpu/drm/amd/display/dc/dc.h | 7 +-
+ .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 7 ++
+ 7 files changed, 119 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
+index 787f94d815f4..c0e58434be39 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
+@@ -52,6 +52,44 @@
+ #define REG(reg_name) \
+ (CLK_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
+
++
++/* TODO: evaluate how to lower or disable all dcn clocks in screen off case */
++int rn_get_active_display_cnt_wa(
++ struct dc *dc,
++ struct dc_state *context)
++{
++ int i, display_count;
++ bool hdmi_present = false;
++
++ display_count = 0;
++ for (i = 0; i < context->stream_count; i++) {
++ const struct dc_stream_state *stream = context->streams[i];
++
++ if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ hdmi_present = true;
++ }
++
++ for (i = 0; i < dc->link_count; i++) {
++ const struct dc_link *link = dc->links[i];
++
++ /*
++ * Only notify active stream or virtual stream.
++ * Need to notify virtual stream to work around
++ * headless case. HPD does not fire when system is in
++ * S0i2.
++ */
++ /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
++ if (link->link_enc->funcs->is_dig_enabled(link->link_enc))
++ display_count++;
++ }
++
++ /* WA for hang on HDMI after display off back back on*/
++ if (display_count == 0 && hdmi_present)
++ display_count = 1;
++
++ return display_count;
++}
++
+ void rn_update_clocks(struct clk_mgr *clk_mgr_base,
+ struct dc_state *context,
+ bool safe_to_lower)
+@@ -62,17 +100,36 @@ void rn_update_clocks(struct clk_mgr *clk_mgr_base,
+ int display_count;
+ bool update_dppclk = false;
+ bool update_dispclk = false;
+- bool enter_display_off = false;
+ bool dpp_clock_lowered = false;
+- struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
+
+- display_count = clk_mgr_helper_get_active_display_cnt(dc, context);
++ struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
+
+- if (display_count == 0)
+- enter_display_off = true;
++ if (dc->work_arounds.skip_clock_update)
++ return;
+
+- if (enter_display_off == safe_to_lower) {
+- rn_vbios_smu_set_display_count(clk_mgr, display_count);
++ /*
++ * if it is safe to lower, but we are already in the lower state, we don't have to do anything
++ * also if safe to lower is false, we just go in the higher state
++ */
++ if (safe_to_lower) {
++ /* check that we're not already in lower */
++ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_OPTIMIZED) {
++
++ display_count = rn_get_active_display_cnt_wa(dc, context);
++ /* if we can go lower, go lower */
++ if (display_count == 0) {
++ rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_OPTIMIZED);
++ /* update power state */
++ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_OPTIMIZED;
++ }
++ }
++ } else {
++ /* check that we're not already in the normal state */
++ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_NORMAL) {
++ rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_NORMAL);
++ /* update power state */
++ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_NORMAL;
++ }
+ }
+
+ if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz)) {
+@@ -329,10 +386,19 @@ void rn_enable_pme_wa(struct clk_mgr *clk_mgr_base)
+ rn_vbios_smu_enable_pme_wa(clk_mgr);
+ }
+
++void rn_init_clocks(struct clk_mgr *clk_mgr)
++{
++ memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
++ // Assumption is that boot state always supports pstate
++ clk_mgr->clks.p_state_change_support = true;
++ clk_mgr->clks.prev_p_state_change_support = true;
++ clk_mgr->clks.pwr_state = DCN_PWR_STATE_NORMAL;
++}
++
+ static struct clk_mgr_funcs dcn21_funcs = {
+ .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .update_clocks = rn_update_clocks,
+- .init_clocks = dcn2_init_clocks,
++ .init_clocks = rn_init_clocks,
+ .enable_pme_wa = rn_enable_pme_wa,
+ /* .dump_clk_registers = rn_dump_clk_registers */
+ };
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h
+index aadec06fde10..958939049add 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h
+@@ -30,7 +30,6 @@ struct rn_clk_registers {
+ uint32_t CLK1_CLK0_CURRENT_CNT; /* DPREFCLK */
+ };
+
+-
+ void rn_clk_mgr_construct(struct dc_context *ctx,
+ struct clk_mgr_internal *clk_mgr,
+ struct pp_smu_funcs *pp_smu,
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
+index 50984c1811bb..fd919b82e902 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
+@@ -175,12 +175,19 @@ int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_
+ return actual_dppclk_set_mhz * 1000;
+ }
+
+-void rn_vbios_smu_set_display_count(struct clk_mgr_internal *clk_mgr, int display_count)
++void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, enum dcn_pwr_state state)
+ {
++ int disp_count;
++
++ if (state == DCN_PWR_STATE_OPTIMIZED)
++ disp_count = 0;
++ else
++ disp_count = 1;
++
+ rn_vbios_smu_send_msg_with_param(
+- clk_mgr,
+- VBIOSSMC_MSG_SetDisplayCount,
+- display_count);
++ clk_mgr,
++ VBIOSSMC_MSG_SetDisplayCount,
++ disp_count);
+ }
+
+ void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr)
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h
+index da3a49487c6d..fe2986a2c7a2 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h
+@@ -33,7 +33,7 @@ int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int reque
+ int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz);
+ void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz);
+ int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz);
+-void rn_vbios_smu_set_display_count(struct clk_mgr_internal *clk_mgr, int display_count);
++void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, int display_count);
+ void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr);
+ void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr);
+
+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 ca4a57510e8c..80ddde0f0262 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+@@ -741,7 +741,7 @@ static bool wait_for_alt_mode(struct dc_link *link)
+ * This does not create remote sinks but will trigger DM
+ * to start MST detection if a branch is detected.
+ */
+-bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
++bool dc_link_detect_helper(struct dc_link *link, enum dc_detect_reason reason)
+ {
+ struct dc_sink_init_data sink_init_data = { 0 };
+ struct display_sink_capability sink_caps = { 0 };
+@@ -757,6 +757,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
+ bool same_dpcd = true;
+ enum dc_connection_type new_connection_type = dc_connection_none;
+ bool perform_dp_seamless_boot = false;
++
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ if (dc_is_virtual_signal(link->connector_signal))
+@@ -1063,6 +1064,24 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
+ dc_sink_release(prev_sink);
+
+ return true;
++
++}
++
++bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
++{
++ const struct dc *dc = link->dc;
++ bool ret;
++ /* get out of low power state */
++
++ if (dc->hwss.exit_optimized_pwr_state)
++ dc->hwss.exit_optimized_pwr_state(dc, dc->current_state);
++
++ ret = dc_link_detect_helper(link, reason);
++
++ if (dc->hwss.optimize_pwr_state)
++ dc->hwss.optimize_pwr_state(dc, dc->current_state);
++
++ return ret;
+ }
+
+ bool dc_link_get_hpd_state(struct dc_link *dc_link)
+diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
+index 9185297d93c4..0921f9101025 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc.h
++++ b/drivers/gpu/drm/amd/display/dc/dc.h
+@@ -246,6 +246,11 @@ enum wm_report_mode {
+ WM_REPORT_OVERRIDE = 1,
+ };
+
++enum dcn_pwr_state {
++ DCN_PWR_STATE_OPTIMIZED = 0,
++ DCN_PWR_STATE_NORMAL = 1
++};
++
+ /*
+ * For any clocks that may differ per pipe
+ * only the max is stored in this structure
+@@ -260,7 +265,7 @@ struct dc_clocks {
+ int phyclk_khz;
+ int dramclk_khz;
+ bool p_state_change_support;
+-
++ enum dcn_pwr_state pwr_state;
+ /*
+ * Elements below are not compared for the purposes of
+ * optimization required
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+index cbac3b61da94..de9d0a312180 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+@@ -232,6 +232,13 @@ struct hw_sequencer_funcs {
+ struct dc *dc,
+ struct dc_state *context);
+
++ void (*exit_optimized_pwr_state)(
++ const struct dc *dc,
++ struct dc_state *context);
++ void (*optimize_pwr_state)(
++ const struct dc *dc,
++ struct dc_state *context);
++
+ #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
+ bool (*update_bandwidth)(
+ struct dc *dc,
+--
+2.17.1
+