diff options
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.patch | 286 |
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 + |