]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
drm/amd/display: fix dscclk programming sequence on DCN401
authorWenjing Liu <wenjing.liu@amd.com>
Tue, 25 Jun 2024 19:22:25 +0000 (15:22 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 23 Jul 2024 21:07:10 +0000 (17:07 -0400)
[why]
The mux to switch between refclk and dto_dsc_clk is non double buffered.
However dto dsc clk's phase and modulo divider registers are currently
configured as double buffered update. This causes a problem when we switch to
use dto dsc clk and program phase and modulo in the same sequence. In this
sequence dsc clk is switched to dto but the clock divider programming doesn't
take effect until next frame. When we try to program DSCC registers, SMN bus
will hang because dto dsc clk divider phase is set to 0.

[how]
Configure phase and modulo to take effect immediately. Always switch to dto dsc
clk before DSC clock is unagted. Switch back to refclk after DSC clock is gated.

Acked-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
Reviewed-by: Jerry Zuo <jerry.zuo@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h
drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.h
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
drivers/gpu/drm/amd/display/dc/link/link_dpms.c

index 1e02928612446d6977bb512a19fdbe149404be55..6ac2bd86c4dbb7f46e3591cd6fc059f97c2773f6 100644 (file)
        type SYMCLK32_LE3_SRC_SEL;\
        type SYMCLK32_LE2_EN;\
        type SYMCLK32_LE3_EN;\
-       type DP_DTO_ENABLE[MAX_PIPES];\
-       type DSCCLK0_DTO_DB_EN;\
-       type DSCCLK1_DTO_DB_EN;\
-       type DSCCLK2_DTO_DB_EN;\
-       type DSCCLK3_DTO_DB_EN;
+       type DP_DTO_ENABLE[MAX_PIPES];
 
 struct dccg_shift {
        DCCG_REG_FIELD_LIST(uint8_t)
index 07f1f396ba52aa02af2ad10ea7e0c965aed32cd9..0b889004509ad0977afa775c7b73a4ad6e688819 100644 (file)
@@ -730,35 +730,35 @@ void dccg401_init(struct dccg *dccg)
        }
 }
 
-static void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst, bool enable)
+static void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
-       uint32_t phase = enable ? 1 : 0;
 
        switch (inst) {
        case 0:
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1, DSCCLK0_DTO_DB_EN, 1);
                REG_UPDATE_2(DSCCLK0_DTO_PARAM,
-                               DSCCLK0_DTO_PHASE, phase,
+                               DSCCLK0_DTO_PHASE, 1,
                                DSCCLK0_DTO_MODULO, 1);
+               REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1);
+
                break;
        case 1:
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1, DSCCLK1_DTO_DB_EN, 1);
                REG_UPDATE_2(DSCCLK1_DTO_PARAM,
-                               DSCCLK1_DTO_PHASE, phase,
+                               DSCCLK1_DTO_PHASE, 1,
                                DSCCLK1_DTO_MODULO, 1);
+               REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
                break;
        case 2:
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1, DSCCLK2_DTO_DB_EN, 1);
                REG_UPDATE_2(DSCCLK2_DTO_PARAM,
-                               DSCCLK2_DTO_PHASE, phase,
+                               DSCCLK2_DTO_PHASE, 1,
                                DSCCLK2_DTO_MODULO, 1);
+               REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
                break;
        case 3:
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1, DSCCLK3_DTO_DB_EN, 1);
                REG_UPDATE_2(DSCCLK3_DTO_PARAM,
-                               DSCCLK3_DTO_PHASE, phase,
+                               DSCCLK3_DTO_PHASE, 1,
                                DSCCLK3_DTO_MODULO, 1);
+               REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1);
                break;
        default:
                BREAK_TO_DEBUGGER();
@@ -774,15 +774,27 @@ static void dccg401_set_ref_dscclk(struct dccg *dccg,
        switch (dsc_inst) {
        case 0:
                REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 0);
+               REG_UPDATE_2(DSCCLK0_DTO_PARAM,
+                               DSCCLK0_DTO_PHASE, 0,
+                               DSCCLK0_DTO_MODULO, 0);
                break;
        case 1:
                REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 0);
+               REG_UPDATE_2(DSCCLK1_DTO_PARAM,
+                               DSCCLK1_DTO_PHASE, 0,
+                               DSCCLK1_DTO_MODULO, 0);
                break;
        case 2:
                REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 0);
+               REG_UPDATE_2(DSCCLK2_DTO_PARAM,
+                               DSCCLK2_DTO_PHASE, 0,
+                               DSCCLK2_DTO_MODULO, 0);
                break;
        case 3:
                REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 0);
+               REG_UPDATE_2(DSCCLK3_DTO_PARAM,
+                               DSCCLK3_DTO_PHASE, 0,
+                               DSCCLK3_DTO_MODULO, 0);
                break;
        default:
                return;
index 8bcddc8363472b9ae87334202144698533bbc59d..a196ce9e81279ab6842abc0a454b6ca188521eba 100644 (file)
        DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_EN, mask_sh),\
        DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_EN, mask_sh),\
        DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_EN, mask_sh),\
-       DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_DTO_DB_EN, mask_sh),\
-       DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_DTO_DB_EN, mask_sh),\
-       DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_DB_EN, mask_sh),\
-       DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_DTO_DB_EN, mask_sh),\
        DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, mask_sh),\
        DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_MODULO, mask_sh),\
        DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, mask_sh),\
index 2532ad410cb5664b8e1f751e6684f261073da9cd..ea9bedf65d848295c424696ce8e3c48650850f85 100644 (file)
@@ -2186,9 +2186,9 @@ static void post_unlock_reset_opp(struct dc *dc,
                         * yet power gated.
                         */
                        dsc->funcs->dsc_wait_disconnect_pending_clear(dsc);
+                       dsc->funcs->dsc_disable(dsc);
                        if (dccg->funcs->set_ref_dscclk)
                                dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
-                       dsc->funcs->dsc_disable(dsc);
                }
        }
 }
index 05d8f81daa064d72549af336c24f943eb3307123..4534843ba66a118cce63f1cc3ff215da166a5f54 100644 (file)
@@ -1029,24 +1029,20 @@ void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
                ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
                dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
 
+               if (should_use_dto_dscclk)
+                       dccg->funcs->set_dto_dscclk(dccg, dsc->inst);
                dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
                dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
-               if (should_use_dto_dscclk)
-                       dccg->funcs->set_dto_dscclk(dccg, dsc->inst, true);
                for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                        struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
 
                        ASSERT(odm_dsc);
+                       if (should_use_dto_dscclk)
+                               dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst);
                        odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
                        odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
-                       if (should_use_dto_dscclk)
-                               dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, true);
                }
-               dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
-               dsc_cfg.pic_width *= opp_cnt;
-
                optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
-
                /* Enable DSC in OPTC */
                DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
                pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
@@ -1060,13 +1056,9 @@ void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
                                OPTC_DSC_DISABLED, 0, 0);
 
                /* only disconnect DSC block, DSC is disabled when OPP head pipe is reset */
-               if (dccg->funcs->set_dto_dscclk)
-                       dccg->funcs->set_dto_dscclk(dccg, pipe_ctx->stream_res.dsc->inst, false);
-               dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
+               dsc->funcs->dsc_disconnect(pipe_ctx->stream_res.dsc);
                for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                        ASSERT(odm_pipe->stream_res.dsc);
-                       if (dccg->funcs->set_dto_dscclk)
-                               dccg->funcs->set_dto_dscclk(dccg, odm_pipe->stream_res.dsc->inst, false);
                        odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc);
                }
        }
@@ -1137,10 +1129,7 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe &&
                                current_pipe_ctx->next_odm_pipe->stream_res.dsc) {
                        struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc;
-                       struct dccg *dccg = dc->res_pool->dccg;
 
-                       if (dccg->funcs->set_dto_dscclk)
-                               dccg->funcs->set_dto_dscclk(dccg, dsc->inst, false);
                        /* disconnect DSC block from stream */
                        dsc->funcs->dsc_disconnect(dsc);
                }
index 2c50c0f745a0be589c5307a66bcbba9cd0e204ac..b9378f18c020e434cdcf88a7b9f208c312f8a9af 100644 (file)
@@ -1542,7 +1542,6 @@ static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context,
        struct pipe_ctx *old_pipe;
        struct pipe_ctx *new_pipe;
        struct pipe_ctx *old_opp_heads[MAX_PIPES];
-       struct dccg *dccg = dc->res_pool->dccg;
        struct pipe_ctx *old_otg_master;
        int old_opp_head_count = 0;
 
@@ -1568,12 +1567,9 @@ static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context,
                for (i = 0; i < old_opp_head_count; i++) {
                        old_pipe = old_opp_heads[i];
                        new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx];
-                       if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc) {
-                               dccg->funcs->set_dto_dscclk(dccg,
-                                               old_pipe->stream_res.dsc->inst, false);
+                       if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc)
                                old_pipe->stream_res.dsc->funcs->dsc_disconnect(
                                                old_pipe->stream_res.dsc);
-                       }
                }
        }
 }
index 4fb1aacee894be9677f16f37f4b2d4b0397fa510..d619eb229a62ae09e099fc11530530b7821f5378 100644 (file)
@@ -211,10 +211,7 @@ struct dccg_funcs {
                        struct dccg *dccg,
                        enum streamclk_source src,
                        uint32_t otg_inst);
-       void (*set_dto_dscclk)(
-                       struct dccg *dccg,
-                       uint32_t dsc_inst,
-                       bool enable);
+       void (*set_dto_dscclk)(struct dccg *dccg, uint32_t dsc_inst);
        void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst);
 };
 
index 65607589495f44e75b8d8dbd14f3a12b432ecfb8..d6550b904b164e9d84fcfe77c9b91abdd23925f5 100644 (file)
@@ -817,17 +817,17 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
                ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
                dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
 
+               if (should_use_dto_dscclk)
+                       dccg->funcs->set_dto_dscclk(dccg, dsc->inst);
                dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
                dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
-               if (should_use_dto_dscclk)
-                       dccg->funcs->set_dto_dscclk(dccg, dsc->inst, true);
                for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                        struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
 
+                       if (should_use_dto_dscclk)
+                               dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst);
                        odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
                        odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
-                       if (should_use_dto_dscclk)
-                               dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, true);
                }
                dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
                dsc_cfg.pic_width *= opp_cnt;
@@ -879,19 +879,32 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
                }
 
                /* disable DSC block */
-               if (dccg->funcs->set_dto_dscclk)
-                       dccg->funcs->set_dto_dscclk(dccg, pipe_ctx->stream_res.dsc->inst, false);
-               pipe_ctx->stream_res.dsc->funcs->dsc_disconnect(pipe_ctx->stream_res.dsc);
-               if (dccg->funcs->set_ref_dscclk)
-                       dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst);
-               pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
-               for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
-                       if (dccg->funcs->set_dto_dscclk)
-                               dccg->funcs->set_dto_dscclk(dccg, odm_pipe->stream_res.dsc->inst, false);
+               for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                        odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc);
+                       /*
+                        * TODO - dsc_disconnect is a double buffered register.
+                        * by the time we call dsc_disable, dsc may still remain
+                        * connected to OPP. In this case OPTC will no longer
+                        * get correct pixel data because DSCC is off. However
+                        * we also can't wait for the  disconnect pending
+                        * complete, because this function can be called
+                        * with/without OTG master lock acquired. When the lock
+                        * is acquired we will never get pending complete until
+                        * we release the lock later. So there is no easy way to
+                        * solve this problem especially when the lock is
+                        * acquired. DSC is a front end hw block it should be
+                        * programmed as part of front end sequence, where the
+                        * commit sequence without lock and update sequence
+                        * with lock are completely separated. However because
+                        * we are programming dsc as part of back end link
+                        * programming sequence, we don't know if front end OPTC
+                        * master lock is acquired. The back end should be
+                        * agnostic to front end lock. DSC programming shouldn't
+                        * belong to this sequence.
+                        */
+                       odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
                        if (dccg->funcs->set_ref_dscclk)
                                dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst);
-                       odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
                }
        }
 }