diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 125 |
1 files changed, 108 insertions, 17 deletions
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 e47828e3b6d5..4548320217fc 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 @@ -131,7 +131,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { .urgent_latency_pixel_data_only_us = 4.0, .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, .urgent_latency_vm_data_only_us = 4.0, - .fclk_change_latency_us = 20, + .fclk_change_latency_us = 25, .usr_retraining_latency_us = 2, .smn_latency_us = 2, .mall_allocated_for_dcn_mbytes = 64, @@ -1270,7 +1270,7 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context) for (i = 0; i < dc->res_pool->pipe_count; i++) { if (!context->res_ctx.pipe_ctx[i].stream) continue; - if (link_is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i])) + if (dc->link_srv->dp_is_128b_132b_signal(&context->res_ctx.pipe_ctx[i])) return true; } return false; @@ -1927,6 +1927,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, unsigned int min_dram_speed_mts_margin; bool need_fclk_lat_as_dummy = false; bool is_subvp_p_drr = false; + struct dc_stream_state *fpo_candidate_stream = NULL; dc_assert_fp_enabled(); @@ -1960,11 +1961,19 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, } context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false; + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]) + context->streams[i]->fpo_in_use = false; + } - if (!pstate_en) { + if (!pstate_en || (!dc->debug.disable_fpo_optimizations && + pstate_en && vlevel != 0)) { /* only when the mclk switch can not be natural, is the fw based vblank stretch attempted */ - context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = - dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(dc, context); + fpo_candidate_stream = dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(dc, context); + if (fpo_candidate_stream) { + fpo_candidate_stream->fpo_in_use = true; + context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = true; + } if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { dummy_latency_index = dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(dc, @@ -1985,11 +1994,25 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us; } - dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false); - maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb; - dcfclk_from_fw_based_mclk_switching = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb]; - pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] != - dm_dram_clock_change_unsupported; + dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel_temp, false); + if (vlevel_temp < vlevel) { + vlevel = vlevel_temp; + maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb; + dcfclk_from_fw_based_mclk_switching = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb]; + pstate_en = true; + } else { + /* Restore FCLK latency and re-run validation to go back to original validation + * output if we find that enabling FPO does not give us any benefit (i.e. lower + * voltage level) + */ + context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false; + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]) + context->streams[i]->fpo_in_use = false; + } + context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.fclk_change_latency_us; + dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false); + } } } @@ -2142,7 +2165,13 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, * DCFCLK: Min, as reported by PM FW, when available * UCLK: Min, as reported by PM FW, when available */ - dc->res_pool->funcs->update_soc_for_wm_a(dc, context); + + /* For set A set the correct latency values (i.e. non-dummy values) unconditionally + */ + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; + context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us; + context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us; + context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; @@ -2188,10 +2217,6 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; - if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { - dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(dc, context); - } - /* revert fclk lat changes if required */ if (need_fclk_lat_as_dummy) context->bw_ctx.dml.soc.fclk_change_latency_us = @@ -2315,6 +2340,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, num_dcfclk_dpms++; } + if (num_dcfclk_dpms > 0 && bw_params->clk_table.entries[0].fclk_mhz > min_fclk_mhz) + min_fclk_mhz = bw_params->clk_table.entries[0].fclk_mhz; + if (!max_dcfclk_mhz || !max_dispclk_mhz || !max_dtbclk_mhz) return -1; @@ -2423,7 +2451,6 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, for (i = *num_entries - 1; i >= 0 ; i--) { if (table[i].fabricclk_mhz < min_fclk_mhz) { table[i].fabricclk_mhz = min_fclk_mhz; - break; } } } @@ -2432,7 +2459,6 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, for (i = *num_entries - 1; i >= 0 ; i--) { if (table[i].dcfclk_mhz < min_dcfclk_mhz) { table[i].dcfclk_mhz = min_dcfclk_mhz; - break; } } @@ -2780,3 +2806,68 @@ double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *conte } return max_vratio_pre; } + +/** + * dcn32_assign_fpo_vactive_candidate - Assign the FPO stream candidate for FPO + VActive case + * + * This function chooses the FPO candidate stream for FPO + VActive cases (2 stream config). + * For FPO + VAtive cases, the assumption is that one display has ActiveMargin > 0, and the + * other display has ActiveMargin <= 0. This function will choose the pipe/stream that has + * ActiveMargin <= 0 to be the FPO stream candidate if found. + * + * + * @param [in]: dc - current dc state + * @param [in]: context - new dc state + * @param [out]: fpo_candidate_stream - pointer to FPO stream candidate if one is found + * + * Return: void + */ +void dcn32_assign_fpo_vactive_candidate(struct dc *dc, const struct dc_state *context, struct dc_stream_state **fpo_candidate_stream) +{ + unsigned int i, pipe_idx; + const struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (!pipe->stream) + continue; + + if (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) { + *fpo_candidate_stream = pipe->stream; + break; + } + pipe_idx++; + } +} + +/** + * dcn32_find_vactive_pipe - Determines if the config has a pipe that can switch in VACTIVE + * + * @param [in]: dc - current dc state + * @param [in]: context - new dc state + * @param [in]: vactive_margin_req_us - The vactive marign required for a vactive pipe to be + * considered "found" + * + * Return: True if VACTIVE display is found, false otherwise + */ +bool dcn32_find_vactive_pipe(struct dc *dc, const struct dc_state *context, uint32_t vactive_margin_req_us) +{ + unsigned int i, pipe_idx; + const struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + bool vactive_found = false; + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (!pipe->stream) + continue; + + if (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] >= vactive_margin_req_us) { + vactive_found = true; + break; + } + pipe_idx++; + } + return vactive_found; +} |