drm/amd/display: Disable MPC rate control on ODM pipe update
authorGeorge Shen <george.shen@amd.com>
Thu, 5 Dec 2024 21:58:21 +0000 (16:58 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 18 Dec 2024 17:21:50 +0000 (12:21 -0500)
[Why]
Seamless boot skips MPC init for the active pipe, resulting in stale MPC
rate control state being retained. This will cause issues since other
logic assumes it is disabled (as DCN30 and newer does not need it).

[How]
Disable MPC rate control on ODM pipe update to cover the seamless boot
case.

Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: George Shen <george.shen@amd.com>
Signed-off-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c
drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.h

index 9b88eb7..be26c92 100644 (file)
@@ -162,6 +162,8 @@ void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx
        int opp_inst[MAX_PIPES] = {0};
        int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
        int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
+       struct mpc *mpc = dc->res_pool->mpc;
+       int i;
 
        opp_cnt = get_odm_config(pipe_ctx, opp_inst);
 
@@ -174,6 +176,16 @@ void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx
                pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
 
+       if (mpc->funcs->set_out_rate_control) {
+               for (i = 0; i < opp_cnt; ++i) {
+                       mpc->funcs->set_out_rate_control(
+                                       mpc, opp_inst[i],
+                                       false,
+                                       0,
+                                       NULL);
+               }
+       }
+
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
                                odm_pipe->stream_res.opp,
index e599cdc..d5f76cc 100644 (file)
@@ -426,6 +426,8 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
        int opp_inst[MAX_PIPES] = {0};
        int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
        int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
+       struct mpc *mpc = dc->res_pool->mpc;
+       int i;
 
        opp_cnt = get_odm_config(pipe_ctx, opp_inst);
 
@@ -438,6 +440,16 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
 
+       if (mpc->funcs->set_out_rate_control) {
+               for (i = 0; i < opp_cnt; ++i) {
+                       mpc->funcs->set_out_rate_control(
+                                       mpc, opp_inst[i],
+                                       false,
+                                       0,
+                                       NULL);
+               }
+       }
+
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
                                odm_pipe->stream_res.opp,
index fe26fde..85298b8 100644 (file)
@@ -110,6 +110,23 @@ void mpc3_disable_dwb_mux(
                MPC_DWB0_MUX, 0xf);
 }
 
+void mpc3_set_out_rate_control(
+       struct mpc *mpc,
+       int opp_id,
+       bool enable,
+       bool rate_2x_mode,
+       struct mpc_dwb_flow_control *flow_control)
+{
+       struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc);
+
+       /* Always disable mpc out rate and flow control.
+        * MPC flow rate control is not needed for DCN30 and above.
+        */
+       REG_UPDATE_2(MUX[opp_id],
+                       MPC_OUT_RATE_CONTROL_DISABLE, 1,
+                       MPC_OUT_RATE_CONTROL, 0);
+}
+
 enum dc_lut_mode mpc3_get_ogam_current(struct mpc *mpc, int mpcc_id)
 {
        /*Contrary to DCN2 and DCN1 wherein a single status register field holds this info;
@@ -1519,6 +1536,7 @@ static const struct mpc_funcs dcn30_mpc_funcs = {
        .set_dwb_mux = mpc3_set_dwb_mux,
        .disable_dwb_mux = mpc3_disable_dwb_mux,
        .is_dwb_idle = mpc3_is_dwb_idle,
+       .set_out_rate_control = mpc3_set_out_rate_control,
        .set_gamut_remap = mpc3_set_gamut_remap,
        .program_shaper = mpc3_program_shaper,
        .acquire_rmu = mpcc3_acquire_rmu,
index ce93003..103f299 100644 (file)
@@ -1085,6 +1085,13 @@ bool mpc3_is_dwb_idle(
        struct mpc *mpc,
        int dwb_id);
 
+void mpc3_set_out_rate_control(
+       struct mpc *mpc,
+       int opp_id,
+       bool enable,
+       bool rate_2x_mode,
+       struct mpc_dwb_flow_control *flow_control);
+
 void mpc3_power_on_ogam_lut(
        struct mpc *mpc, int mpcc_id,
        bool power_on);