From: Alvin Lee <Alvin.Lee2@xxxxxxx> [Description] - Add debug option to enable SubVP for high refresh rate displays - For now limit the enabled modes based on a table in debug options - Currently disabled by default Reviewed-by: Jun Lei <Jun.Lei@xxxxxxx> Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@xxxxxxx> Signed-off-by: Alvin Lee <Alvin.Lee2@xxxxxxx> --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + .../drm/amd/display/dc/dcn32/dcn32_resource.c | 1 + .../drm/amd/display/dc/dcn32/dcn32_resource.h | 14 +++++ .../display/dc/dcn32/dcn32_resource_helpers.c | 15 +++++ .../amd/display/dc/dcn321/dcn321_resource.c | 1 + .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 62 ++++++++++++++++++- .../dc/dml/dcn32/display_mode_vba_32.c | 12 ++-- 7 files changed, 101 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 17afe7915f48..f52ab717ac7d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -882,6 +882,7 @@ struct dc_debug_options { bool disable_boot_optimizations; bool override_odm_optimization; bool minimize_dispclk_using_odm; + bool disable_subvp_high_refresh; }; struct gpu_info_soc_bounding_box_v1_0; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 0085ea78ea31..7feeba78c0c9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -728,6 +728,7 @@ static const struct dc_debug_options debug_defaults_drv = { .fpo_vactive_margin_us = 2000, // 2000us .disable_fpo_vactive = false, .disable_boot_optimizations = false, + .disable_subvp_high_refresh = true, }; static const struct dc_debug_options debug_defaults_diags = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h index 3937dbc1e552..04be01ae1ecf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h @@ -40,6 +40,7 @@ #define DCN3_2_VMIN_DISPCLK_HZ 717000000 #define DCN3_2_DCFCLK_DS_INIT_KHZ 10000 // Choose 10Mhz for init DCFCLK DS freq #define DCN3_2_MIN_ACTIVE_SWITCH_MARGIN_FPO_US 100 // Only allow FPO + Vactive if active margin >= 100 +#define SUBVP_HIGH_REFRESH_LIST_LEN 3 #define TO_DCN32_RES_POOL(pool)\ container_of(pool, struct dcn32_resource_pool, base) @@ -47,6 +48,15 @@ extern struct _vcs_dpi_ip_params_st dcn3_2_ip; extern struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc; +struct subvp_high_refresh_list { + int min_refresh; + int max_refresh; + struct resolution { + int width; + int height; + } res[SUBVP_HIGH_REFRESH_LIST_LEN]; +}; + struct dcn32_resource_pool { struct resource_pool base; }; @@ -151,10 +161,14 @@ struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stre bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe); +bool dcn32_allow_subvp_high_refresh_rate(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe); + unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans); double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *context); +bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int width, unsigned int height); + /* definitions for run time init of reg offsets */ /* CLK SRC */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index eeca16faf31a..df912c333bbd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -656,3 +656,18 @@ struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stre return fpo_candidate_stream; } + +bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int width, unsigned int height) +{ + bool is_native_scaling = false; + + if (pipe->stream->timing.h_addressable == width && + pipe->stream->timing.v_addressable == height && + pipe->plane_state->src_rect.width == width && + pipe->plane_state->src_rect.height == height && + pipe->plane_state->dst_rect.width == width && + pipe->plane_state->dst_rect.height == height) + is_native_scaling = true; + + return is_native_scaling; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index 138657c38afe..63bd6928c82f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -727,6 +727,7 @@ static const struct dc_debug_options debug_defaults_drv = { .fpo_vactive_margin_us = 2000, // 2000us .disable_fpo_vactive = false, .disable_boot_optimizations = false, + .disable_subvp_high_refresh = true, }; static const struct dc_debug_options debug_defaults_diags = { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 34ac5a1eb3ca..a73cacef6e48 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -35,6 +35,15 @@ #define DC_LOGGER_INIT(logger) +static const struct subvp_high_refresh_list subvp_high_refresh_list = { + .min_refresh = 120, + .max_refresh = 165, + .res = { + {.width = 3840, .height = 2160, }, + {.width = 3440, .height = 1440, }, + {.width = 2560, .height = 1440, }}, +}; + struct _vcs_dpi_ip_params_st dcn3_2_ip = { .gpuvm_enable = 0, .gpuvm_max_page_table_levels = 4, @@ -694,7 +703,9 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc, */ if (pipe->plane_state && !pipe->top_pipe && !dcn32_is_center_timing(pipe) && (!dcn32_is_psr_capable(pipe) || (context->stream_count == 1 && dc->caps.dmub_caps.subvp_psr)) && - pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && !pipe->plane_state->address.tmz_surface && + pipe->stream->mall_stream_config.type == SUBVP_NONE && + (refresh_rate < 120 || dcn32_allow_subvp_high_refresh_rate(dc, context, pipe)) && + !pipe->plane_state->address.tmz_surface && (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0 || (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] > 0 && dcn32_allow_subvp_with_active_margin(pipe)))) { @@ -2789,6 +2800,55 @@ bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe) return allow; } +/** + * ************************************************************************************************ + * dcn32_allow_subvp_high_refresh_rate: Determine if the high refresh rate config will allow subvp + * + * @param [in]: dc: Current DC state + * @param [in]: context: New DC state to be programmed + * @param [in]: pipe: Pipe to be considered for use in subvp + * + * On high refresh rate display configs, we will allow subvp under the following conditions: + * 1. Resolution is 3840x2160, 3440x1440, or 2560x1440 + * 2. Refresh rate is between 120hz - 165hz + * 3. No scaling + * 4. Freesync is inactive + * 5. For single display cases, freesync must be disabled + * + * @return: True if pipe can be used for subvp, false otherwise + * + * ************************************************************************************************ + */ +bool dcn32_allow_subvp_high_refresh_rate(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe) +{ + bool allow = false; + uint32_t refresh_rate = 0; + uint32_t min_refresh = subvp_high_refresh_list.min_refresh; + uint32_t max_refresh = subvp_high_refresh_list.max_refresh; + uint32_t i; + + if (!dc->debug.disable_subvp_high_refresh && pipe->stream && + pipe->plane_state && !pipe->stream->vrr_active_variable) { + refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 + + pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1) + / (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total); + if (refresh_rate >= min_refresh && refresh_rate <= max_refresh) { + for (i = 0; i < SUBVP_HIGH_REFRESH_LIST_LEN; i++) { + uint32_t width = subvp_high_refresh_list.res[i].width; + uint32_t height = subvp_high_refresh_list.res[i].height; + + if (dcn32_check_native_scaling_for_res(pipe, width, height)) { + if ((context->stream_count == 1 && !pipe->stream->allow_freesync) || context->stream_count > 1) { + allow = true; + break; + } + } + } + } + } + return allow; +} + /** * ******************************************************************************************* * dcn32_determine_max_vratio_prefetch: Determine max Vratio for prefetch by driver policy diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 13c7e7394b1c..66f44a013fe5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -2322,10 +2322,14 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l mode_lib->vba.LinkCapacitySupport[i] = true; for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) { if (mode_lib->vba.BlendingAndTiming[k] == k - && (mode_lib->vba.Output[k] == dm_dp || mode_lib->vba.Output[k] == dm_dp2p0 - || mode_lib->vba.Output[k] == dm_edp - || mode_lib->vba.Output[k] == dm_hdmi) - && mode_lib->vba.OutputBppPerState[i][k] == 0) { + && (mode_lib->vba.Output[k] == dm_dp || mode_lib->vba.Output[k] == dm_dp2p0 + || mode_lib->vba.Output[k] == dm_edp + || mode_lib->vba.Output[k] == dm_hdmi) + && mode_lib->vba.OutputBppPerState[i][k] == 0 && + (mode_lib->vba.UsesMALLForPStateChange[k] != dm_use_mall_pstate_change_phantom_pipe)) { + /* Phantom pipes don't consider DSC in DML, so it could fail link check. + * However, we don't care about the link for phantom pipes. + */ mode_lib->vba.LinkCapacitySupport[i] = false; } } -- 2.39.2