Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: For FPO and SubVP/DRR configs program vmin/max sel

For FPO and SubVP/DRR cases we need to ensure to program
OTG_V_TOTAL_MIN/MAX_SEL, otherwise stretching the vblank in FPO / SubVP
/ DRR cases will not have any effect and we could hit underflow /
corruption.

Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Acked-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
Signed-off-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Alvin Lee and committed by
Alex Deucher
6b2b782a 59f1622a

+62 -24
+14
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
··· 4986 4986 return DC_OK; 4987 4987 } 4988 4988 4989 + bool resource_subvp_in_use(struct dc *dc, 4990 + struct dc_state *context) 4991 + { 4992 + uint32_t i; 4993 + 4994 + for (i = 0; i < dc->res_pool->pipe_count; i++) { 4995 + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 4996 + 4997 + if (dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) 4998 + return true; 4999 + } 5000 + return false; 5001 + } 5002 + 4989 5003 bool check_subvp_sw_cursor_fallback_req(const struct dc *dc, struct dc_stream_state *stream) 4990 5004 { 4991 5005 if (!dc->debug.disable_subvp_high_refresh && is_subvp_high_refresh_candidate(stream))
-14
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
··· 183 183 return true; 184 184 } 185 185 186 - bool dcn32_subvp_in_use(struct dc *dc, 187 - struct dc_state *context) 188 - { 189 - uint32_t i; 190 - 191 - for (i = 0; i < dc->res_pool->pipe_count; i++) { 192 - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 193 - 194 - if (dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) 195 - return true; 196 - } 197 - return false; 198 - } 199 - 200 186 bool dcn32_mpo_in_use(struct dc_state *context) 201 187 { 202 188 uint32_t i;
+6 -5
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
··· 33 33 #include "dcn30/dcn30_resource.h" 34 34 #include "link.h" 35 35 #include "dc_state_priv.h" 36 + #include "resource.h" 36 37 37 38 #define DC_LOGGER_INIT(logger) 38 39 ··· 292 291 293 292 /* for subvp + DRR case, if subvp pipes are still present we support pstate */ 294 293 if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported && 295 - dcn32_subvp_in_use(dc, context)) 294 + resource_subvp_in_use(dc, context)) 296 295 vba->DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = temp_clock_change_support; 297 296 298 297 if (vlevel < context->bw_ctx.dml.vba.soc.num_states && ··· 2273 2272 unsigned int dummy_latency_index = 0; 2274 2273 int maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb; 2275 2274 unsigned int min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed; 2276 - bool subvp_in_use = dcn32_subvp_in_use(dc, context); 2275 + bool subvp_active = resource_subvp_in_use(dc, context); 2277 2276 unsigned int min_dram_speed_mts_margin; 2278 2277 bool need_fclk_lat_as_dummy = false; 2279 2278 bool is_subvp_p_drr = false; ··· 2282 2281 dc_assert_fp_enabled(); 2283 2282 2284 2283 /* need to find dummy latency index for subvp */ 2285 - if (subvp_in_use) { 2284 + if (subvp_active) { 2286 2285 /* Override DRAMClockChangeSupport for SubVP + DRR case where the DRR cannot switch without stretching it's VBLANK */ 2287 2286 if (!pstate_en) { 2288 2287 context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp; ··· 2468 2467 dc->clk_mgr->bw_params->clk_table.entries[min_dram_speed_mts_offset].memclk_mhz * 16; 2469 2468 } 2470 2469 2471 - if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && !subvp_in_use) { 2470 + if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && !subvp_active) { 2472 2471 /* find largest table entry that is lower than dram speed, 2473 2472 * but lower than DPM0 still uses DPM0 2474 2473 */ ··· 3528 3527 void dcn32_override_min_req_memclk(struct dc *dc, struct dc_state *context) 3529 3528 { 3530 3529 // WA: restrict FPO and SubVP to use first non-strobe mode (DCN32 BW issue) 3531 - if ((context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dcn32_subvp_in_use(dc, context)) && 3530 + if ((context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || resource_subvp_in_use(dc, context)) && 3532 3531 dc->dml.soc.num_chans <= 8) { 3533 3532 int num_mclk_levels = dc->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_memclk_levels; 3534 3533
+37
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
··· 1882 1882 } 1883 1883 } 1884 1884 1885 + static void update_vmin_vmax_fams(struct dc *dc, 1886 + struct dc_state *context) 1887 + { 1888 + uint32_t i; 1889 + struct drr_params params = {0}; 1890 + bool subvp_in_use = resource_subvp_in_use(dc, context); 1891 + 1892 + for (i = 0; i < dc->res_pool->pipe_count; i++) { 1893 + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 1894 + 1895 + if (resource_is_pipe_type(pipe, OTG_MASTER) && 1896 + ((subvp_in_use && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM && 1897 + pipe->stream->allow_freesync) || (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && pipe->stream->fpo_in_use))) { 1898 + if (!pipe->stream->vrr_active_variable && !pipe->stream->vrr_active_fixed) { 1899 + struct timing_generator *tg = context->res_ctx.pipe_ctx[i].stream_res.tg; 1900 + 1901 + /* DRR should be configured already if we're in active variable 1902 + * or active fixed, so only program if we're not in this state 1903 + */ 1904 + params.vertical_total_min = pipe->stream->timing.v_total; 1905 + params.vertical_total_max = pipe->stream->timing.v_total; 1906 + tg->funcs->set_drr(tg, &params); 1907 + } 1908 + } else { 1909 + if (resource_is_pipe_type(pipe, OTG_MASTER) && 1910 + !pipe->stream->vrr_active_variable && 1911 + !pipe->stream->vrr_active_fixed) { 1912 + struct timing_generator *tg = context->res_ctx.pipe_ctx[i].stream_res.tg; 1913 + params.vertical_total_min = 0; 1914 + params.vertical_total_max = 0; 1915 + tg->funcs->set_drr(tg, &params); 1916 + } 1917 + } 1918 + } 1919 + } 1920 + 1885 1921 void dcn20_program_front_end_for_ctx( 1886 1922 struct dc *dc, 1887 1923 struct dc_state *context) ··· 1994 1958 && context->res_ctx.pipe_ctx[i].stream) 1995 1959 hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); 1996 1960 1961 + update_vmin_vmax_fams(dc, context); 1997 1962 1998 1963 /* Disconnect mpcc */ 1999 1964 for (i = 0; i < dc->res_pool->pipe_count; i++)
+3
drivers/gpu/drm/amd/display/dc/inc/resource.h
··· 609 609 struct pipe_ctx *sec_pipe, 610 610 bool odm); 611 611 612 + bool resource_subvp_in_use(struct dc *dc, 613 + struct dc_state *context); 614 + 612 615 /* A test harness interface that modifies dp encoder resources in the given dc 613 616 * state and bypasses the need to revalidate. The interface assumes that the 614 617 * test harness interface is called with pre-validated link config stored in the
+1 -1
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
··· 1899 1899 1900 1900 static struct dc_cap_funcs cap_funcs = { 1901 1901 .get_dcc_compression_cap = dcn20_get_dcc_compression_cap, 1902 - .get_subvp_en = dcn32_subvp_in_use, 1902 + .get_subvp_en = resource_subvp_in_use, 1903 1903 }; 1904 1904 1905 1905 void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context,
-3
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h
··· 131 131 bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc, 132 132 struct dc_state *context); 133 133 134 - bool dcn32_subvp_in_use(struct dc *dc, 135 - struct dc_state *context); 136 - 137 134 bool dcn32_mpo_in_use(struct dc_state *context); 138 135 139 136 bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context);
+1 -1
drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
··· 1574 1574 1575 1575 static struct dc_cap_funcs cap_funcs = { 1576 1576 .get_dcc_compression_cap = dcn20_get_dcc_compression_cap, 1577 - .get_subvp_en = dcn32_subvp_in_use, 1577 + .get_subvp_en = resource_subvp_in_use, 1578 1578 }; 1579 1579 1580 1580 static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)