From: George Shen <[email protected]> [Why] The current DSC block programming sequence is intertwined with the stream encoder DSC-related programming. Logically, the programming of the DSC (front end) and stream encoder (back end) blocks should be independent of each other.
[How] Create a new hwseq function config_dsc to handle the DSC block programming sequence. Reviewed-by: Dillon Varone <[email protected]> Signed-off-by: George Shen <[email protected]> Signed-off-by: Ivan Lipski <[email protected]> --- .../amd/display/dc/hwss/dcn60/dcn60_hwseq.c | 95 +++++++++++++++++++ .../amd/display/dc/hwss/dcn60/dcn60_hwseq.h | 1 + .../amd/display/dc/hwss/dcn60/dcn60_init.c | 1 + .../drm/amd/display/dc/hwss/hw_sequencer.h | 1 + 4 files changed, 98 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c index f8254dfe1ce7..e2dddbc170f8 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c @@ -53,6 +53,101 @@ #define FN(reg_name, field_name) \ hws->shifts->field_name, hws->masks->field_name +bool dcn60_configure_dsc(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; + struct dccg *dccg = dc->res_pool->dccg; + struct dsc_config dsc_cfg = {0}; + struct dsc_optc_config dsc_optc_cfg = {0}; + uint32_t odm_count = 1; + + /* 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 use_dto = dccg->funcs->set_dto_dscclk && stream->timing.pix_clk_100hz > 480000; + + if (!dsc) + return false; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + odm_count++; + + if (enable) { + dsc_cfg.pic_width = (stream->timing.h_addressable + + pipe_ctx->dsc_padding_params.dsc_hactive_padding + + stream->timing.h_border_left + stream->timing.h_border_right) / odm_count; + dsc_cfg.pic_height = stream->timing.v_addressable + + stream->timing.v_border_top + stream->timing.v_border_bottom; + dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; + dsc_cfg.color_depth = stream->timing.display_color_depth; + dsc_cfg.is_odm = pipe_ctx->next_odm_pipe != NULL; + dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % odm_count == 0); + dsc_cfg.dc_dsc_cfg.num_slices_h /= odm_count; + + if (use_dto) + dccg->funcs->set_dto_dscclk(dccg, dsc->inst, + (uint32_t)dsc_cfg.dc_dsc_cfg.num_slices_h); + if (!dsc->funcs->dsc_prepare_config(dsc, &dsc_cfg, &dsc_optc_cfg)) { + ASSERT(false); + return false; + } + dsc->funcs->dsc_set_config(dsc); + dsc->funcs->dsc_enable(dsc, (int)pipe_ctx->stream_res.opp->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); + if (!odm_dsc) + return false; + if (use_dto) + dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, + (uint32_t)dsc_cfg.dc_dsc_cfg.num_slices_h); + if (!odm_dsc->funcs->dsc_prepare_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg)) { + ASSERT(false); + return false; + } + odm_dsc->funcs->dsc_set_config(odm_dsc); + odm_dsc->funcs->dsc_enable(odm_dsc, (int)odm_pipe->stream_res.opp->inst); + } + + { + enum optc_dsc_mode mode = dsc_optc_cfg.is_pixel_format_444 ? + OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; + + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, mode, + dsc_optc_cfg.bytes_per_pixel, dsc_optc_cfg.slice_width); + } + return true; + } + + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, OPTC_DSC_DISABLED, 0, 0); + + for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; + + if (!odm_dsc) + continue; + odm_dsc->funcs->dsc_disconnect(odm_dsc); + odm_dsc->funcs->dsc_disable(odm_dsc); + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, (uint32_t)odm_dsc->inst); + } + return true; +} + bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params) { struct dpp *dpp_base = params->dpp; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h index b880988ff1fc..44eb30608feb 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h @@ -31,5 +31,6 @@ void dcn60_program_perfmon(struct dc *dc, struct dc_state *context); bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable); bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params); +bool dcn60_configure_dsc(struct pipe_ctx *pipe_ctx, bool enable); #endif /* __DC_HWSS_DCN60_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c index 80125c3596ce..7b488753fe50 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c @@ -25,6 +25,7 @@ static const struct hw_sequencer_funcs dcn60_funcs = { .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, .post_unlock_program_front_end = dcn50_post_unlock_program_front_end, .update_plane_addr = dcn20_update_plane_addr, + .configure_dsc = dcn60_configure_dsc, .prepare_plane_addr_update = dcn20_prepare_plane_addr_update, .update_dchub = dcn10_update_dchub, .update_pending_status = dcn10_update_pending_status, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index 7de59001453c..8f4ed80385fc 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -1413,6 +1413,7 @@ struct hw_sequencer_funcs { struct dc_state *context); void (*update_plane_addr)(const struct dc *dc, struct pipe_ctx *pipe_ctx); + bool (*configure_dsc)(struct pipe_ctx *pipe_ctx, bool enable); void (*prepare_plane_addr_update)(const struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_plane_address *addr_to_program, -- 2.43.0
