From: Alvin Lee <Alvin.Lee2@xxxxxxx> [Description] * Pass in pipe index for FPO cmd to DMCUB - This change will pass in the pipe index for each stream that is using FPO - This change is in preparation to enable FPO + VActive * Use per pipe P-State force for FPO - For FPO, instead of using max watermarks value for P-State disallow, use per pipe p-state force instead - This is in preparation to enable FPO + VActive Reviewed-by: Jun Lei <Jun.Lei@xxxxxxx> Acked-by: Qingqing Zhuo <qingqing.zhuo@xxxxxxx> Signed-off-by: Alvin Lee <Alvin.Lee2@xxxxxxx> --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 46 +++++++++++-------- drivers/gpu/drm/amd/display/dc/dc_stream.h | 1 + .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 10 ++++ .../drm/amd/display/dc/dcn30/dcn30_resource.c | 2 + .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c | 10 ++++ .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h | 2 + .../drm/amd/display/dc/dcn32/dcn32_hwseq.c | 41 ++++++++++------- .../drm/amd/display/dc/dcn32/dcn32_hwseq.h | 2 +- .../gpu/drm/amd/display/dc/dcn32/dcn32_init.c | 2 +- .../drm/amd/display/dc/dml/dcn30/dcn30_fpu.c | 4 ++ .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 8 ++-- drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 1 + .../amd/display/dc/inc/hw_sequencer_private.h | 2 +- 13 files changed, 88 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index b5c6501c28fc..8f26f7245104 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -302,27 +302,31 @@ static uint8_t dc_dmub_srv_get_pipes_for_stream(struct dc *dc, struct dc_stream_ return pipes; } -static int dc_dmub_srv_get_timing_generator_offset(struct dc *dc, struct dc_stream_state *stream) +static void dc_dmub_srv_populate_fams_pipe_info(struct dc *dc, struct dc_state *context, + struct pipe_ctx *head_pipe, + struct dmub_cmd_fw_assisted_mclk_switch_pipe_data *fams_pipe_data) { - int tg_inst = 0; - int i = 0; + int j; - for (i = 0; i < MAX_PIPES; i++) { - struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + // TODO: Uncomment once FW headers are updated in driver + //fams_pipe_data->pipe_index[pipe_idx++] = head_pipe->plane_res.hubp->inst; + for (j = 0; j < dc->res_pool->pipe_count; j++) { + struct pipe_ctx *split_pipe = &context->res_ctx.pipe_ctx[j]; - if (pipe->stream == stream && pipe->stream_res.tg) { - tg_inst = pipe->stream_res.tg->inst; - break; + if (split_pipe->stream == head_pipe->stream && (split_pipe->top_pipe || split_pipe->prev_odm_pipe)) { + // TODO: Uncomment once FW headers are updated in driver + //fams_pipe_data->pipe_index[pipe_idx++] = split_pipe->plane_res.hubp->inst; } } - return tg_inst; + // TODO: Uncomment once FW headers are updated in driver + //fams_pipe_data->pipe_count = pipe_idx; } bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, struct dc_state *context) { union dmub_rb_cmd cmd = { 0 }; struct dmub_cmd_fw_assisted_mclk_switch_config *config_data = &cmd.fw_assisted_mclk_switch.config_data; - int i = 0; + int i = 0, k = 0; int ramp_up_num_steps = 1; // TODO: Ramp is currently disabled. Reenable it. uint8_t visual_confirm_enabled; @@ -337,17 +341,21 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru cmd.fw_assisted_mclk_switch.config_data.fams_enabled = should_manage_pstate; cmd.fw_assisted_mclk_switch.config_data.visual_confirm_enabled = visual_confirm_enabled; - for (i = 0; context && i < context->stream_count; i++) { - struct dc_stream_state *stream = context->streams[i]; - uint8_t min_refresh_in_hz = (stream->timing.min_refresh_in_uhz + 999999) / 1000000; - int tg_inst = dc_dmub_srv_get_timing_generator_offset(dc, stream); + for (i = 0, k = 0; context && i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - config_data->pipe_data[tg_inst].pix_clk_100hz = stream->timing.pix_clk_100hz; - config_data->pipe_data[tg_inst].min_refresh_in_hz = min_refresh_in_hz; - config_data->pipe_data[tg_inst].max_ramp_step = ramp_up_num_steps; - config_data->pipe_data[tg_inst].pipes = dc_dmub_srv_get_pipes_for_stream(dc, stream); + if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream && pipe->stream->fpo_in_use) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + uint8_t min_refresh_in_hz = (pipe->stream->timing.min_refresh_in_uhz + 999999) / 1000000; + + config_data->pipe_data[k].pix_clk_100hz = pipe->stream->timing.pix_clk_100hz; + config_data->pipe_data[k].min_refresh_in_hz = min_refresh_in_hz; + config_data->pipe_data[k].max_ramp_step = ramp_up_num_steps; + config_data->pipe_data[k].pipes = dc_dmub_srv_get_pipes_for_stream(dc, pipe->stream); + dc_dmub_srv_populate_fams_pipe_info(dc, context, pipe, &config_data->pipe_data[k]); + k++; + } } - cmd.fw_assisted_mclk_switch.header.payload_bytes = sizeof(cmd.fw_assisted_mclk_switch) - sizeof(cmd.fw_assisted_mclk_switch.header); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 567452599659..181a3408cc61 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -293,6 +293,7 @@ struct dc_stream_state { bool has_non_synchronizable_pclk; bool vblank_synchronized; + bool fpo_in_use; struct mall_stream_config mall_stream_config; }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 9ca162ea0d07..5403e9399a46 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1993,6 +1993,16 @@ void dcn20_post_unlock_program_front_end( } } + /* P-State support transitions: + * Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe + * FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally) + * Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe + * FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe + * FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes + */ + if (hwseq && hwseq->funcs.update_force_pstate) + dc->hwseq->funcs.update_force_pstate(dc, context); + /* Only program the MALL registers after all the main and phantom pipes * are done programming. */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index c9e45da6ccd1..965f5ceb33f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -2016,6 +2016,8 @@ bool dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, if (context->streams[0]->vrr_active_variable) return false; + context->streams[0]->fpo_in_use = true; + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c index fe0cd177744c..2d604f7ee782 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c @@ -47,6 +47,15 @@ void hubp32_update_force_pstate_disallow(struct hubp *hubp, bool pstate_disallow DATA_UCLK_PSTATE_FORCE_VALUE, 0); } +void hubp32_update_force_cursor_pstate_disallow(struct hubp *hubp, bool pstate_disallow) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE_2(UCLK_PSTATE_FORCE, + CURSOR_UCLK_PSTATE_FORCE_EN, pstate_disallow, + CURSOR_UCLK_PSTATE_FORCE_VALUE, 0); +} + void hubp32_update_mall_sel(struct hubp *hubp, uint32_t mall_sel, bool c_cursor) { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); @@ -188,6 +197,7 @@ static struct hubp_funcs dcn32_hubp_funcs = { .hubp_set_flip_int = hubp1_set_flip_int, .hubp_in_blank = hubp1_in_blank, .hubp_update_force_pstate_disallow = hubp32_update_force_pstate_disallow, + .hubp_update_force_cursor_pstate_disallow = hubp32_update_force_cursor_pstate_disallow, .phantom_hubp_post_enable = hubp32_phantom_hubp_post_enable, .hubp_update_mall_sel = hubp32_update_mall_sel, .hubp_prepare_subvp_buffering = hubp32_prepare_subvp_buffering diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h index d5e5ed8ab869..d2acbc129609 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h @@ -46,6 +46,8 @@ void hubp32_update_force_pstate_disallow(struct hubp *hubp, bool pstate_disallow); +void hubp32_update_force_cursor_pstate_disallow(struct hubp *hubp, bool pstate_disallow); + void hubp32_update_mall_sel(struct hubp *hubp, uint32_t mall_sel, bool c_cursor); void hubp32_prepare_subvp_buffering(struct hubp *hubp, bool enable); diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index 42255c22605d..5ee9c5a74ecb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -571,39 +571,50 @@ bool dcn32_set_output_transfer_func(struct dc *dc, return ret; } -/* Program P-State force value according to if pipe is using SubVP or not: +/* Program P-State force value according to if pipe is using SubVP / FPO or not: * 1. Reset P-State force on all pipes first * 2. For each main pipe, force P-State disallow (P-State allow moderated by DMUB) */ -void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context) +void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context) { int i; - int num_subvp = 0; - /* Unforce p-state for each pipe + + /* Unforce p-state for each pipe if it is not FPO or SubVP. + * For FPO and SubVP, if it's already forced disallow, leave + * it as disallow. */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = pipe->plane_res.hubp; - if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) - hubp->funcs->hubp_update_force_pstate_disallow(hubp, false); - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN) - num_subvp++; + if (!pipe->stream || (pipe->stream && !(pipe->stream->mall_stream_config.type == SUBVP_MAIN || + pipe->stream->fpo_in_use))) { + if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) + hubp->funcs->hubp_update_force_pstate_disallow(hubp, false); + if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow) + hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, false); + } } - if (num_subvp == 0) - return; - /* Loop through each pipe -- for each subvp main pipe force p-state allow equal to false. */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = pipe->plane_res.hubp; - if (pipe->stream && pipe->plane_state && (pipe->stream->mall_stream_config.type == SUBVP_MAIN)) { - struct hubp *hubp = pipe->plane_res.hubp; + if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) + hubp->funcs->hubp_update_force_pstate_disallow(hubp, true); + } + if (pipe->stream && pipe->stream->fpo_in_use) { if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) hubp->funcs->hubp_update_force_pstate_disallow(hubp, true); + /* For now only force cursor p-state disallow for FPO + * Needs to be added for subvp once FW side gets updated + */ + if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow) + hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, true); } } } @@ -677,10 +688,6 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context) if (hws && hws->funcs.update_mall_sel) hws->funcs.update_mall_sel(dc, context); - //update subvp force pstate - if (hws && hws->funcs.subvp_update_force_pstate) - dc->hwseq->funcs.subvp_update_force_pstate(dc, context); - // Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h index 2a5376eb9d66..6694c1d14aa3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h @@ -67,7 +67,7 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context); void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context); -void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context); +void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context); void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c index dcb81662884f..8085f2acb1a9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c @@ -149,7 +149,7 @@ static const struct hwseq_private_funcs dcn32_private_funcs = { .dccg_init = dcn20_dccg_init, .set_mcm_luts = dcn32_set_mcm_luts, .program_mall_pipe_config = dcn32_program_mall_pipe_config, - .subvp_update_force_pstate = dcn32_subvp_update_force_pstate, + .update_force_pstate = dcn32_update_force_pstate, .update_mall_sel = dcn32_update_mall_sel, .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c index ecfa395f5fa8..80972ee5e55b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c @@ -389,6 +389,10 @@ void dcn30_fpu_calculate_wm_and_dlg( dc_assert_fp_enabled(); 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) { /* only when the mclk switch can not be natural, is the fw based vblank stretch attempted */ 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 6ab60facc091..1e26adf987cc 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 @@ -1960,6 +1960,10 @@ 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 || (!dc->debug.disable_fpo_optimizations && pstate_en && vlevel != 0)) { @@ -2199,10 +2203,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 = diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index b5d353c41aa9..ccf8861483a0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -203,6 +203,7 @@ struct hubp_funcs { void (*hubp_soft_reset)(struct hubp *hubp, bool reset); void (*hubp_update_force_pstate_disallow)(struct hubp *hubp, bool allow); + void (*hubp_update_force_cursor_pstate_disallow)(struct hubp *hubp, bool allow); void (*hubp_update_mall_sel)(struct hubp *hubp, uint32_t mall_sel, bool c_cursor); void (*hubp_prepare_subvp_buffering)(struct hubp *hubp, bool enable); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h index 5f63b67975cf..4513544559be 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h @@ -154,7 +154,7 @@ struct hwseq_private_funcs { void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable); #ifdef CONFIG_DRM_AMD_DC_FP void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context); - void (*subvp_update_force_pstate)(struct dc *dc, struct dc_state *context); + void (*update_force_pstate)(struct dc *dc, struct dc_state *context); void (*update_mall_sel)(struct dc *dc, struct dc_state *context); unsigned int (*calculate_dccg_k1_k2_values)(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, -- 2.34.1