diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index fb1f373d08a1..d89a097ba936 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -202,7 +202,7 @@ static int dce12_get_dp_ref_freq_khz(struct dccg *clk) { struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); - return dccg_adjust_dp_ref_freq_for_ss(clk_dce, 600000); + return dccg_adjust_dp_ref_freq_for_ss(clk_dce, clk_dce->dprefclk_khz); } static enum dm_pp_clocks_state dce_get_required_clocks_state( @@ -255,10 +255,12 @@ static int dce_set_clock( pxl_clk_params.target_pixel_clock = requested_clk_khz; pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS; - bp->funcs->program_display_engine_pll(bp, &pxl_clk_params); + if (clk_dce->dfs_bypass_active) + pxl_clk_params.flags.SET_DISPCLK_DFS_BYPASS = true; - if (clk_dce->dfs_bypass_enabled) { + bp->funcs->program_display_engine_pll(bp, &pxl_clk_params); + if (clk_dce->dfs_bypass_active) { /* Cache the fixed display clock*/ clk_dce->dfs_bypass_disp_clk = pxl_clk_params.dfs_bypass_display_clock; @@ -466,6 +468,9 @@ static void dce12_update_clocks(struct dccg *dccg, { struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; + /* TODO: Investigate why this is needed to fix display corruption. */ + new_clocks->dispclk_khz = new_clocks->dispclk_khz * 115 / 100; + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; @@ -659,6 +664,11 @@ static void dce_update_clocks(struct dccg *dccg, bool safe_to_lower) { struct dm_pp_power_level_change_request level_change_req; + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(dccg); + + /* TODO: Investigate why this is needed to fix display corruption. */ + if (!clk_dce->dfs_bypass_active) + new_clocks->dispclk_khz = new_clocks->dispclk_khz * 115 / 100; level_change_req.power_level = dce_get_required_clocks_state(dccg, new_clocks); /* get max clock state from PPLIB */ @@ -674,6 +684,61 @@ static void dce_update_clocks(struct dccg *dccg, } } +static bool dce_update_dfs_bypass( + struct dccg *dccg, + struct dc *dc, + struct dc_state *context, + int requested_clock_khz) +{ + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(dccg); + struct resource_context *res_ctx = &context->res_ctx; + enum signal_type signal_type = SIGNAL_TYPE_NONE; + bool was_active = clk_dce->dfs_bypass_active; + int i; + + /* Disable DFS bypass by default. */ + clk_dce->dfs_bypass_active = false; + + /* Check that DFS bypass is available. */ + if (!clk_dce->dfs_bypass_enabled) + goto update; + + /* Check if the requested display clock is below the threshold. */ + if (requested_clock_khz >= 400000) + goto update; + + /* DFS-bypass should only be enabled on single stream setups */ + if (context->stream_count != 1) + goto update; + + /* Check that the stream's signal type is an embedded panel */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (res_ctx->pipe_ctx[i].stream) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; + + signal_type = pipe_ctx->stream->sink->link->connector_signal; + break; + } + } + + if (signal_type == SIGNAL_TYPE_EDP || + signal_type == SIGNAL_TYPE_LVDS) + clk_dce->dfs_bypass_active = true; + +update: + /* Update the clock state. We don't need to respect safe_to_lower + * because DFS bypass should always be greater than the current + * display clock frequency. + */ + if (was_active != clk_dce->dfs_bypass_active) { + dccg->clks.dispclk_khz = + dccg->funcs->set_dispclk(dccg, dccg->clks.dispclk_khz); + return true; + } + + return false; +} + #ifdef CONFIG_DRM_AMD_DC_DCN1_0 static const struct display_clock_funcs dcn1_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, @@ -697,7 +762,8 @@ static const struct display_clock_funcs dce112_funcs = { static const struct display_clock_funcs dce110_funcs = { .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, .set_dispclk = dce_psr_set_clock, - .update_clocks = dce_update_clocks + .update_clocks = dce_update_clocks, + .update_dfs_bypass = dce_update_dfs_bypass }; static const struct display_clock_funcs dce_funcs = { @@ -824,6 +890,7 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) dce_dccg_construct( clk_dce, ctx, NULL, NULL, NULL); + clk_dce->dprefclk_khz = 600000; clk_dce->base.funcs = &dce120_funcs; return &clk_dce->base; @@ -851,6 +918,7 @@ struct dccg *dcn1_dccg_create(struct dc_context *ctx) clk_dce->dprefclk_ss_divider = 1000; clk_dce->ss_on_dprefclk = false; + clk_dce->dprefclk_khz = 600000; if (bp->integrated_info) clk_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; if (clk_dce->dentist_vco_freq_khz == 0) { |