drm/amd/display: add support for DTO genarated dscclk
authorWenjing Liu <wenjing.liu@amd.com>
Fri, 1 Dec 2023 13:25:20 +0000 (06:25 -0700)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 6 Dec 2023 20:22:34 +0000 (15:22 -0500)
Current implementation will choose to use refclk as dscclk. This is not
recommended by hardware team as refclk is a fixed value which could
cause unnecessary power consumption or it could be not enough for large
DSC timings. So we are adding new interfaces so we could switch to use
dynamically generated DSCCLK by DTO. So DSCCLK is programmable based on
current pixel clock and dispclk.

Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: Chaitanya Dhere <chaitanya.dhere@amd.com>
Acked-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
drivers/gpu/drm/amd/display/dc/link/link_dpms.c

index 5f7f474ef51c9a4104731fa6743a1ad553175005..5c323718ec906d68288c89e2c4935f66c06f7e2b 100644 (file)
@@ -989,9 +989,22 @@ static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
 static void 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;
        struct dc_stream_state *stream = pipe_ctx->stream;
        struct pipe_ctx *odm_pipe;
        int opp_cnt = 1;
+       struct dccg *dccg = dc->res_pool->dccg;
+       /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN
+        * register access hung. When DSCCLk is based on refclk, DSCCLk is always a
+        * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is
+        * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings
+        * with DSC such as 480p60Hz, the dispclk could be low enough to trigger
+        * this problem. We are implementing a workaround here to keep using dscclk
+        * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e
+        * 48Mhz) pixel clock to avoid hitting this problem.
+        */
+       bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) &&
+                       stream->timing.pix_clk_100hz > 480000;
 
        ASSERT(dsc);
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
@@ -1014,12 +1027,16 @@ 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);
                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);
                        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);
                }
                dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
                dsc_cfg.pic_width *= opp_cnt;
@@ -1039,9 +1056,13 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
                                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);
                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);
                }
        }
@@ -1124,6 +1145,10 @@ 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_ref_dscclk)
+                               dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
                        /* disconnect DSC block from stream */
                        dsc->funcs->dsc_disconnect(dsc);
                }
index ce2f0c0e82bd65c67af0b725fd3ed26fbcd369ec..6b44557fcb1a81231fe4a36d7e48cd13f5271051 100644 (file)
@@ -201,6 +201,10 @@ 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);
+       void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst);
 };
 
 #endif //__DAL_DCCG_H__
index b16b2e14312e9ef64a41a16974dc75af1d878867..5fe8b4871c77614eb0fd46421db49fb79197e6f7 100644 (file)
@@ -776,10 +776,26 @@ static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
  */
 void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
 {
+       /* TODO: Move this to HWSS as this is hardware programming sequence not a
+        * link layer sequence
+        */
        struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
        struct dc_stream_state *stream = pipe_ctx->stream;
        struct pipe_ctx *odm_pipe;
        int opp_cnt = 1;
+       struct dccg *dccg = dc->res_pool->dccg;
+       /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN
+        * register access hung. When DSCCLk is based on refclk, DSCCLk is always a
+        * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is
+        * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings
+        * with DSC such as 480p60Hz, the dispclk could be low enough to trigger
+        * this problem. We are implementing a workaround here to keep using dscclk
+        * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e
+        * 48Mhz) pixel clock to avoid hitting this problem.
+        */
+       bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) &&
+                       stream->timing.pix_clk_100hz > 480000;
        DC_LOGGER_INIT(dsc->ctx->logger);
 
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
@@ -802,11 +818,15 @@ 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);
                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);
                }
                dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
                dsc_cfg.pic_width *= opp_cnt;
@@ -856,9 +876,14 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
                }
 
                /* disable DSC block */
+               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)
+               for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+                       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);
+               }
        }
 }