From: Wenjing Liu <wenjing....@amd.com>

[why]
Switching between DSC clock or disable DSC block are not double buffered update.
Corruption is observed if these updates happen before DSC double buffered
disconnection.

[how]
Move DSC disable and refclk reset to post unlock update. Wait for DSC double 
buffered
disconnection and all mpccs are disconnected before reset DSC clock.

Reviewed-by: Samson Tam <samson....@amd.com>
Acked-by: Tom Chung <chiahsuan.ch...@amd.com>
Signed-off-by: Wenjing Liu <wenjing....@amd.com>
---
 .../drm/amd/display/dc/dcn401/dcn401_dccg.c   | 31 +++------
 .../drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c  | 18 +++--
 .../drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h  |  3 +-
 .../amd/display/dc/dsc/dcn401/dcn401_dsc.c    | 17 +++--
 drivers/gpu/drm/amd/display/dc/dsc/dsc.h      |  1 +
 .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c   | 43 ++++++++++++
 .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c   | 33 ++++-----
 .../amd/display/dc/hwss/dcn32/dcn32_hwseq.h   |  2 +
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 69 +++++++++++++++++++
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.h |  2 +
 .../amd/display/dc/hwss/dcn401/dcn401_init.c  |  2 +-
 drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h  |  3 +-
 .../gpu/drm/amd/display/dc/link/link_dpms.c   | 10 ++-
 .../amd/display/dc/optc/dcn401/dcn401_optc.c  |  1 +
 14 files changed, 180 insertions(+), 55 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn401/dcn401_dccg.c 
b/drivers/gpu/drm/amd/display/dc/dcn401/dcn401_dccg.c
index c06bf4a38dbc..72cbff8632dd 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn401/dcn401_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn401/dcn401_dccg.c
@@ -726,34 +726,35 @@ void dccg401_init(struct dccg *dccg)
        }
 }
 
-static void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst)
+static void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst, bool 
enable)
 {
        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, 1,
+                               DSCCLK0_DTO_PHASE, phase,
                                DSCCLK0_DTO_MODULO, 1);
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1, DSCCLK0_DTO_DB_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, 1,
+                               DSCCLK1_DTO_PHASE, phase,
                                DSCCLK1_DTO_MODULO, 1);
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1, DSCCLK1_DTO_DB_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, 1,
+                               DSCCLK2_DTO_PHASE, phase,
                                DSCCLK2_DTO_MODULO, 1);
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1, DSCCLK2_DTO_DB_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, 1,
+                               DSCCLK3_DTO_PHASE, phase,
                                DSCCLK3_DTO_MODULO, 1);
-               REG_UPDATE_2(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1, DSCCLK3_DTO_DB_EN, 
1);
                break;
        default:
                BREAK_TO_DEBUGGER();
@@ -769,27 +770,15 @@ 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, 1);
                break;
        case 1:
                REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 0);
-               REG_UPDATE_2(DSCCLK1_DTO_PARAM,
-                               DSCCLK1_DTO_PHASE, 0,
-                               DSCCLK1_DTO_MODULO, 1);
                break;
        case 2:
                REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 0);
-               REG_UPDATE_2(DSCCLK2_DTO_PARAM,
-                               DSCCLK2_DTO_PHASE, 0,
-                               DSCCLK2_DTO_MODULO, 1);
                break;
        case 3:
                REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 0);
-               REG_UPDATE_2(DSCCLK3_DTO_PARAM,
-                               DSCCLK3_DTO_PHASE, 0,
-                               DSCCLK3_DTO_MODULO, 1);
                break;
        default:
                return;
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c 
b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c
index c9ae2d8f0096..d6b2334d5364 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c
@@ -40,6 +40,7 @@ static void dsc2_set_config(struct display_stream_compressor 
*dsc, const struct
 static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe);
 static void dsc2_disable(struct display_stream_compressor *dsc);
 static void dsc2_disconnect(struct display_stream_compressor *dsc);
+static void dsc2_wait_disconnect_pending_clear(struct 
display_stream_compressor *dsc);
 
 static const struct dsc_funcs dcn20_dsc_funcs = {
        .dsc_get_enc_caps = dsc2_get_enc_caps,
@@ -50,6 +51,7 @@ static const struct dsc_funcs dcn20_dsc_funcs = {
        .dsc_enable = dsc2_enable,
        .dsc_disable = dsc2_disable,
        .dsc_disconnect = dsc2_disconnect,
+       .dsc_wait_disconnect_pending_clear = dsc2_wait_disconnect_pending_clear,
 };
 
 /* Macro definitios for REG_SET macros*/
@@ -260,16 +262,12 @@ static void dsc2_disable(struct display_stream_compressor 
*dsc)
 {
        struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
        int dsc_clock_en;
-       int dsc_fw_config;
-       int enabled_opp_pipe;
 
        DC_LOG_DSC("disable DSC %d", dsc->inst);
 
        REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en);
-       REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, 
&dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe);
-       if (!dsc_clock_en || !dsc_fw_config) {
-               DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already disabled!", 
dsc->inst, enabled_opp_pipe);
-               ASSERT(0);
+       if (!dsc_clock_en) {
+               DC_LOG_DSC("DSC %d already disabled!", dsc->inst);
        }
 
        REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG,
@@ -279,6 +277,13 @@ static void dsc2_disable(struct display_stream_compressor 
*dsc)
                DSC_CLOCK_EN, 0);
 }
 
+static void dsc2_wait_disconnect_pending_clear(struct 
display_stream_compressor *dsc)
+{
+       struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
+
+       REG_WAIT(DSCRM_DSC_FORWARD_CONFIG, 
DSCRM_DSC_DOUBLE_BUFFER_REG_UPDATE_PENDING, 0, 2, 50000);
+}
+
 static void dsc2_disconnect(struct display_stream_compressor *dsc)
 {
        struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
@@ -777,4 +782,3 @@ static void dsc_write_to_registers(struct 
display_stream_compressor *dsc, const
                RANGE_BPG_OFFSET14, 
reg_vals->pps.rc_range_params[14].range_bpg_offset);
 
 }
-
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h 
b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h
index 59a3f56b8543..a136b26c914c 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h
@@ -453,7 +453,8 @@
        type DSCCIF_UPDATE_TAKEN_STATUS; \
        type DSCCIF_UPDATE_TAKEN_ACK; \
        type DSCRM_DSC_FORWARD_EN; \
-       type DSCRM_DSC_OPP_PIPE_SOURCE
+       type DSCRM_DSC_OPP_PIPE_SOURCE; \
+       type DSCRM_DSC_DOUBLE_BUFFER_REG_UPDATE_PENDING
 
 struct dcn20_dsc_registers {
        uint32_t DSC_TOP_CONTROL;
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c 
b/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c
index b90710726840..845686d57919 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn401/dcn401_dsc.c
@@ -21,6 +21,7 @@ static void dsc401_set_config(struct 
display_stream_compressor *dsc, const struc
 static void dsc401_enable(struct display_stream_compressor *dsc, int opp_pipe);
 static void dsc401_disable(struct display_stream_compressor *dsc);
 static void dsc401_disconnect(struct display_stream_compressor *dsc);
+static void dsc401_wait_disconnect_pending_clear(struct 
display_stream_compressor *dsc);
 
 const struct dsc_funcs dcn401_dsc_funcs = {
        .dsc_get_enc_caps = dsc2_get_enc_caps,
@@ -31,6 +32,7 @@ const struct dsc_funcs dcn401_dsc_funcs = {
        .dsc_enable = dsc401_enable,
        .dsc_disable = dsc401_disable,
        .dsc_disconnect = dsc401_disconnect,
+       .dsc_wait_disconnect_pending_clear = 
dsc401_wait_disconnect_pending_clear,
 };
 
 /* Macro definitios for REG_SET macros*/
@@ -231,16 +233,12 @@ static void dsc401_disable(struct 
display_stream_compressor *dsc)
 {
        struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc);
        int dsc_clock_en;
-       int dsc_fw_config;
-       int enabled_opp_pipe;
 
        DC_LOG_DSC("disable DSC %d", dsc->inst);
 
        REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en);
-       REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, 
&dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe);
-       if (!dsc_clock_en || !dsc_fw_config) {
-               DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already disabled!", 
dsc->inst, enabled_opp_pipe);
-               ASSERT(0);
+       if (!dsc_clock_en) {
+               DC_LOG_DSC("DSC %d already disabled!", dsc->inst);
        }
 
        REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG,
@@ -250,6 +248,13 @@ static void dsc401_disable(struct 
display_stream_compressor *dsc)
                DSC_CLOCK_EN, 0);
 }
 
+static void dsc401_wait_disconnect_pending_clear(struct 
display_stream_compressor *dsc)
+{
+       struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc);
+
+       REG_WAIT(DSCRM_DSC_FORWARD_CONFIG, 
DSCRM_DSC_DOUBLE_BUFFER_REG_UPDATE_PENDING, 0, 2, 50000);
+}
+
 static void dsc401_disconnect(struct display_stream_compressor *dsc)
 {
        struct dcn401_dsc *dsc401 = TO_DCN401_DSC(dsc);
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dsc.h 
b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h
index 4b27f29d0d80..1ebce5426a58 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dsc.h
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h
@@ -107,6 +107,7 @@ struct dsc_funcs {
        void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe);
        void (*dsc_disable)(struct display_stream_compressor *dsc);
        void (*dsc_disconnect)(struct display_stream_compressor *dsc);
+       void (*dsc_wait_disconnect_pending_clear)(struct 
display_stream_compressor *dsc);
 };
 
 #endif
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
index 5812b0938cd3..5623a48cf3fd 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
@@ -2158,6 +2158,43 @@ void dcn20_program_front_end_for_ctx(
        }
 }
 
+/* post_unlock_reset_opp - the function wait for corresponding double
+ * buffered pending status clear and reset opp head pipe's none double buffered
+ * registers to their initial state.
+ */
+static void post_unlock_reset_opp(struct dc *dc,
+               struct pipe_ctx *opp_head)
+{
+       struct display_stream_compressor *dsc = opp_head->stream_res.dsc;
+       struct dccg *dccg = dc->res_pool->dccg;
+
+       /*
+        * wait for all DPP pipes in current mpc blending tree completes double
+        * buffered disconnection before resetting OPP
+        */
+       dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, opp_head);
+
+       if (dsc) {
+               bool is_dsc_ungated = false;
+
+               if (dc->hwseq->funcs.dsc_pg_status)
+                       is_dsc_ungated = 
dc->hwseq->funcs.dsc_pg_status(dc->hwseq, dsc->inst);
+
+               if (is_dsc_ungated) {
+                       /*
+                        * seamless update specific where we will postpone non
+                        * double buffered DSCCLK disable logic in post unlock
+                        * sequence after DSC is disconnected from OPP but not
+                        * yet power gated.
+                        */
+                       dsc->funcs->dsc_wait_disconnect_pending_clear(dsc);
+                       if (dccg->funcs->set_ref_dscclk)
+                               dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
+                       dsc->funcs->dsc_disable(dsc);
+               }
+       }
+}
+
 void dcn20_post_unlock_program_front_end(
                struct dc *dc,
                struct dc_state *context)
@@ -2167,6 +2204,12 @@ void dcn20_post_unlock_program_front_end(
        unsigned int polling_interval_us = 1;
        struct dce_hwseq *hwseq = dc->hwseq;
 
+       for (i = 0; i < dc->res_pool->pipe_count; i++)
+               if 
(resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
+                               
!resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))
+                       post_unlock_reset_opp(dc,
+                                       
&dc->current_state->res_ctx.pipe_ctx[i]);
+
        for (i = 0; i < dc->res_pool->pipe_count; i++)
                if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
                        dc->hwss.disable_plane(dc, dc->current_state, 
&dc->current_state->res_ctx.pipe_ctx[i]);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
index ba4b2786f440..df0fceb11ae1 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
@@ -60,8 +60,7 @@
 #define REG(reg)\
        hws->regs->reg
 #define DC_LOGGER \
-       stream->ctx->logger
-
+       dc->ctx->logger
 
 #undef FN
 #define FN(reg_name, field_name) \
@@ -75,17 +74,19 @@ void dcn32_dsc_pg_control(
        uint32_t power_gate = power_on ? 0 : 1;
        uint32_t pwr_status = power_on ? 0 : 2;
        uint32_t org_ip_request_cntl = 0;
+       struct dc *dc = hws->ctx->dc;
 
-       if (hws->ctx->dc->debug.disable_dsc_power_gate)
+       if (dc->debug.disable_dsc_power_gate)
                return;
 
-       if (!hws->ctx->dc->debug.enable_double_buffered_dsc_pg_support)
+       if (!dc->debug.enable_double_buffered_dsc_pg_support)
                return;
 
        REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
        if (org_ip_request_cntl == 0)
                REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
 
+       DC_LOG_DSC("%s DSC power gate for inst %d", power_gate ? "enable" : 
"disable", dsc_inst);
        switch (dsc_inst) {
        case 0: /* DSC0 */
                REG_UPDATE(DOMAIN16_PG_CONFIG,
@@ -963,7 +964,7 @@ void dcn32_init_hw(struct dc *dc)
        }
 }
 
-static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
 {
        struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
        struct dc *dc = pipe_ctx->stream->ctx->dc;
@@ -1005,7 +1006,7 @@ static void update_dsc_on_stream(struct pipe_ctx 
*pipe_ctx, bool enable)
                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);
+                       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;
 
@@ -1013,7 +1014,7 @@ static void update_dsc_on_stream(struct pipe_ctx 
*pipe_ctx, bool enable)
                        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);
+                               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;
@@ -1032,15 +1033,15 @@ static void update_dsc_on_stream(struct pipe_ctx 
*pipe_ctx, bool enable)
                                pipe_ctx->stream_res.tg,
                                OPTC_DSC_DISABLED, 0, 0);
 
-               /* disable DSC block */
-               if (dccg->funcs->set_ref_dscclk)
-                       dccg->funcs->set_ref_dscclk(dccg, 
pipe_ctx->stream_res.dsc->inst);
+               /* 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);
                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_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);
+                       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);
                }
        }
 }
@@ -1098,7 +1099,7 @@ void dcn32_update_odm(struct dc *dc, struct dc_state 
*context, struct pipe_ctx *
        if (pipe_ctx->stream_res.dsc) {
                struct pipe_ctx *current_pipe_ctx = 
&dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
 
-               update_dsc_on_stream(pipe_ctx, 
pipe_ctx->stream->timing.flags.DSC);
+               dcn32_update_dsc_on_stream(pipe_ctx, 
pipe_ctx->stream->timing.flags.DSC);
 
                /* Check if no longer using pipe for ODM, then need to 
disconnect DSC for that pipe */
                if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe 
&&
@@ -1106,8 +1107,8 @@ void dcn32_update_odm(struct dc *dc, struct dc_state 
*context, struct pipe_ctx *
                        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_ref_dscclk)
-                               dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
+                       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);
                }
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
index c510f3a652ad..4621163b4b98 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
@@ -71,6 +71,8 @@ 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);
 
+void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable);
+
 unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, 
unsigned int *k1_div, unsigned int *k2_div);
 
 void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct 
dc_state *context);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index ba9c27e05787..11c20b17a7d0 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -1541,6 +1541,75 @@ void dcn401_fams2_update_config(struct dc *dc, struct 
dc_state *context, bool en
        dc_dmub_srv_fams2_update_config(dc, context, enable && fams2_required);
 }
 
+static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context,
+               struct pipe_ctx *otg_master)
+{
+       int i;
+       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 =
+                       
&dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx];
+       int old_opp_head_count = resource_get_opp_heads_for_otg_master(
+                       old_otg_master, &dc->current_state->res_ctx,
+                       old_opp_heads);
+
+       if (otg_master->stream_res.dsc)
+               dcn32_update_dsc_on_stream(otg_master,
+                               otg_master->stream->timing.flags.DSC);
+       if (old_otg_master->stream_res.dsc) {
+               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);
+                               old_pipe->stream_res.dsc->funcs->dsc_disconnect(
+                                               old_pipe->stream_res.dsc);
+                       }
+               }
+       }
+}
+
+void dcn401_update_odm(struct dc *dc, struct dc_state *context,
+               struct pipe_ctx *otg_master)
+{
+       struct pipe_ctx *opp_heads[MAX_PIPES];
+       int opp_inst[MAX_PIPES] = {0};
+       int opp_head_count;
+       int i;
+
+       opp_head_count = resource_get_opp_heads_for_otg_master(
+                       otg_master, &context->res_ctx, opp_heads);
+
+       for (i = 0; i < opp_head_count; i++)
+               opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
+       if (opp_head_count > 1)
+               otg_master->stream_res.tg->funcs->set_odm_combine(
+                               otg_master->stream_res.tg,
+                               opp_inst, opp_head_count,
+                               &otg_master->stream->timing);
+       else
+               otg_master->stream_res.tg->funcs->set_odm_bypass(
+                               otg_master->stream_res.tg,
+                               &otg_master->stream->timing);
+
+       for (i = 0; i < opp_head_count; i++)
+               opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
+                               opp_heads[i]->stream_res.opp,
+                               true);
+
+       update_dsc_for_odm_change(dc, context, otg_master);
+
+       if (!resource_is_pipe_type(otg_master, DPP_PIPE))
+               /*
+                * blank pattern is generated by OPP, reprogram blank pattern
+                * due to OPP count change
+                */
+               dc->hwseq->funcs.blank_pixel_data(dc, otg_master, true);
+}
+
 void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx,
                struct dc_link_settings *link_settings)
 {
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
index 16084ae1d31d..dd5bae93dc05 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
@@ -74,4 +74,6 @@ void dcn401_fams2_update_config(struct dc *dc, struct 
dc_state *context, bool en
 void dcn401_fams2_global_control_lock_fast(union block_sequence_params 
*params);
 void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings 
*link_settings);
 
+void dcn401_update_odm(struct dc *dc, struct dc_state *context,
+               struct pipe_ctx *otg_master);
 #endif /* __DC_HWSS_DCN401_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
index 56c4b28c1f2e..b9fcde08fdc8 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
@@ -124,7 +124,7 @@ static const struct hwseq_private_funcs 
dcn401_private_funcs = {
        .enable_power_gating_plane = dcn32_enable_power_gating_plane,
        .hubp_pg_control = dcn32_hubp_pg_control,
        .program_all_writeback_pipes_in_tree = 
dcn30_program_all_writeback_pipes_in_tree,
-       .update_odm = dcn32_update_odm,
+       .update_odm = dcn401_update_odm,
        .dsc_pg_control = dcn32_dsc_pg_control,
        .dsc_pg_status = dcn32_dsc_pg_status,
        .set_hdr_multiplier = dcn10_set_hdr_multiplier,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h 
b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
index d4c7885fc916..867bc67aabfa 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -208,7 +208,8 @@ struct dccg_funcs {
                        uint32_t otg_inst);
        void (*set_dto_dscclk)(
                        struct dccg *dccg,
-                       uint32_t dsc_inst);
+                       uint32_t dsc_inst,
+                       bool enable);
        void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst);
 };
 
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c 
b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index 8402ca0695cc..955c720fb565 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -820,14 +820,14 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, 
bool enable)
                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);
+                       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;
 
                        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);
+                               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,10 +879,16 @@ 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);
+                       
odm_pipe->stream_res.dsc->funcs->dsc_disconnect(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);
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c 
b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
index fd030e5b9de6..099658bcd77f 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
@@ -456,6 +456,7 @@ static struct timing_generator_funcs dcn401_tg_funcs = {
                .set_dwb_source = NULL,
                .set_odm_bypass = optc401_set_odm_bypass,
                .set_odm_combine = optc401_set_odm_combine,
+               .wait_odm_doublebuffer_pending_clear = 
optc32_wait_odm_doublebuffer_pending_clear,
                .set_h_timing_div_manual_mode = 
optc401_set_h_timing_div_manual_mode,
                .get_optc_source = optc2_get_optc_source,
                .set_out_mux = optc401_set_out_mux,
-- 
2.34.1

Reply via email to