From: Chris Park <[email protected]>

[WHY]
Some DSC timing failed at bandwidth validation due to hactive
can't be evenly divided on each ODM segment.

[HOW]
Borrow from hblank to increase hactive to support these timing.

Cc: Mario Limonciello <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: [email protected]
Reviewed-by: Wenjing Liu <[email protected]>
Signed-off-by: Chris Park <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
---
 .../gpu/drm/amd/display/dc/core/dc_resource.c | 42 ++++++++++++++++++-
 drivers/gpu/drm/amd/display/dc/dc.h           |  1 +
 .../gpu/drm/amd/display/dc/dc_spl_translate.c |  2 +-
 .../dc/dml2/dml21/dml21_translation_helper.c  | 21 +++++++++-
 .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c   |  3 +-
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c |  7 +++-
 .../gpu/drm/amd/display/dc/inc/core_types.h   |  2 +
 .../gpu/drm/amd/display/dc/link/link_dpms.c   |  3 +-
 .../dc/resource/dcn32/dcn32_resource.c        |  1 +
 9 files changed, 75 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 619fad17de55..626f75b6ad00 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -2094,7 +2094,8 @@ int resource_get_odm_slice_dst_width(struct pipe_ctx 
*otg_master,
        count = resource_get_odm_slice_count(otg_master);
        h_active = timing->h_addressable +
                        timing->h_border_left +
-                       timing->h_border_right;
+                       timing->h_border_right +
+                       otg_master->hblank_borrow;
        width = h_active / count;
 
        if (otg_master->stream_res.tg)
@@ -4026,6 +4027,41 @@ enum dc_status dc_validate_with_context(struct dc *dc,
        return res;
 }
 
+/**
+ * decide_hblank_borrow - Decides the horizontal blanking borrow value for a 
given pipe context.
+ * @pipe_ctx: Pointer to the pipe context structure.
+ *
+ * This function calculates the horizontal blanking borrow value for a given 
pipe context based on the
+ * display stream compression (DSC) configuration. If the horizontal active 
pixels (hactive) are less
+ * than the total width of the DSC slices, it sets the hblank_borrow value to 
the difference. If the
+ * total horizontal timing minus the hblank_borrow value is less than 32, it 
resets the hblank_borrow
+ * value to 0.
+ */
+static void decide_hblank_borrow(struct pipe_ctx *pipe_ctx)
+{
+       uint32_t hactive;
+       uint32_t ceil_slice_width;
+       struct dc_stream_state *stream = NULL;
+
+       if (!pipe_ctx)
+               return;
+
+       stream = pipe_ctx->stream;
+
+       if (stream->timing.flags.DSC) {
+               hactive = stream->timing.h_addressable + 
stream->timing.h_border_left + stream->timing.h_border_right;
+
+               /* Assume if determined slices does not divide Hactive evenly, 
Hborrow is needed for padding*/
+               if (hactive % stream->timing.dsc_cfg.num_slices_h != 0) {
+                       ceil_slice_width = (hactive / 
stream->timing.dsc_cfg.num_slices_h) + 1;
+                       pipe_ctx->hblank_borrow = ceil_slice_width * 
stream->timing.dsc_cfg.num_slices_h - hactive;
+
+                       if (stream->timing.h_total - hactive - 
pipe_ctx->hblank_borrow < 32)
+                               pipe_ctx->hblank_borrow = 0;
+               }
+       }
+}
+
 /**
  * dc_validate_global_state() - Determine if hardware can support a given state
  *
@@ -4064,6 +4100,10 @@ enum dc_status dc_validate_global_state(
                        if (pipe_ctx->stream != stream)
                                continue;
 
+                       /* Decide whether hblank borrow is needed and save it 
in pipe_ctx */
+                       if (dc->debug.enable_hblank_borrow)
+                               decide_hblank_borrow(pipe_ctx);
+
                        if (dc->res_pool->funcs->patch_unknown_plane_state &&
                                        pipe_ctx->plane_state &&
                                        
pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h 
b/drivers/gpu/drm/amd/display/dc/dc.h
index 5f1b3ce67cd1..ec64061080fa 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1070,6 +1070,7 @@ struct dc_debug_options {
        unsigned int scale_to_sharpness_policy;
        bool skip_full_updated_if_possible;
        unsigned int enable_oled_edp_power_up_opt;
+       bool enable_hblank_borrow;
 };
 
 
diff --git a/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c 
b/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c
index 2fee0b92f1f5..a4907cfe3f08 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c
@@ -122,7 +122,7 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx 
*pipe_ctx, struct spl
        spl_in->odm_slice_index = resource_get_odm_slice_index(pipe_ctx);
        // Make spl input basic out info output_size width point to stream h 
active
        spl_in->basic_out.output_size.width =
-               stream->timing.h_addressable + stream->timing.h_border_left + 
stream->timing.h_border_right;
+               stream->timing.h_addressable + stream->timing.h_border_left + 
stream->timing.h_border_right + pipe_ctx->hblank_borrow;
        // Make spl input basic out info output_size height point to v active
        spl_in->basic_out.output_size.height =
                stream->timing.v_addressable + stream->timing.v_border_bottom + 
stream->timing.v_border_top;
diff --git 
a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c 
b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c
index f66493528f42..c6a5a8614679 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c
@@ -445,6 +445,21 @@ static void 
populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf
        timing->vblank_nom = timing->v_total - timing->v_active;
 }
 
+/**
+ * adjust_dml21_hblank_timing_config_from_pipe_ctx - Adjusts the horizontal 
blanking timing configuration
+ *                                                   based on the pipe context.
+ * @timing: Pointer to the dml2_timing_cfg structure to be adjusted.
+ * @pipe: Pointer to the pipe_ctx structure containing the horizontal blanking 
borrow value.
+ *
+ * This function modifies the horizontal active and blank end timings by 
adding and subtracting
+ * the horizontal blanking borrow value from the pipe context, respectively.
+ */
+static void adjust_dml21_hblank_timing_config_from_pipe_ctx(struct 
dml2_timing_cfg *timing, struct pipe_ctx *pipe)
+{
+       timing->h_active += pipe->hblank_borrow;
+       timing->h_blank_end -= pipe->hblank_borrow;
+}
+
 static void populate_dml21_output_config_from_stream_state(struct 
dml2_link_output_cfg *output,
                struct dc_stream_state *stream, const struct pipe_ctx *pipe)
 {
@@ -732,6 +747,7 @@ static const struct scaler_data *get_scaler_data_for_plane(
                        temp_pipe->plane_state = pipe->plane_state;
                        temp_pipe->plane_res.scl_data.taps = 
pipe->plane_res.scl_data.taps;
                        temp_pipe->stream_res = pipe->stream_res;
+                       temp_pipe->hblank_borrow = pipe->hblank_borrow;
                        
dml_ctx->config.callbacks.build_scaling_params(temp_pipe);
                        break;
                }
@@ -996,6 +1012,7 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct 
dc *in_dc, struct dc_s
 
                ASSERT(disp_cfg_stream_location >= 0 && 
disp_cfg_stream_location <= __DML2_WRAPPER_MAX_STREAMS_PLANES__);
                
populate_dml21_timing_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing,
 context->streams[stream_index], dml_ctx);
+               
adjust_dml21_hblank_timing_config_from_pipe_ctx(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing,
 &context->res_ctx.pipe_ctx[stream_index]);
                
populate_dml21_output_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].output,
 context->streams[stream_index], &context->res_ctx.pipe_ctx[stream_index]);
                
populate_dml21_stream_overrides_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location],
 context->streams[stream_index]);
 
@@ -1134,12 +1151,12 @@ void dml21_populate_pipe_ctx_dlg_params(struct 
dml2_context *dml_ctx, struct dc_
        struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
        union dml2_global_sync_programming *global_sync = 
&stream_programming->global_sync;
 
-       hactive = timing->h_addressable + timing->h_border_left + 
timing->h_border_right;
+       hactive = timing->h_addressable + timing->h_border_left + 
timing->h_border_right + pipe_ctx->hblank_borrow;
        vactive = timing->v_addressable + timing->v_border_bottom + 
timing->v_border_top;
        hblank_start = pipe_ctx->stream->timing.h_total - 
pipe_ctx->stream->timing.h_front_porch;
        vblank_start = pipe_ctx->stream->timing.v_total - 
pipe_ctx->stream->timing.v_front_porch;
 
-       hblank_end = hblank_start - timing->h_addressable - 
timing->h_border_left - timing->h_border_right;
+       hblank_end = hblank_start - timing->h_addressable - 
timing->h_border_left - timing->h_border_right - pipe_ctx->hblank_borrow;
        vblank_end = vblank_start - timing->v_addressable - 
timing->v_border_top - timing->v_border_bottom;
 
        if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, 
pipe_ctx) == SUBVP_PHANTOM) {
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 d7f8b2dcaa6b..fa11f075d1f9 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
@@ -1049,7 +1049,8 @@ void dcn32_update_dsc_on_stream(struct pipe_ctx 
*pipe_ctx, bool enable)
                }
 
                /* Enable DSC hw block */
-               dsc_cfg.pic_width = (stream->timing.h_addressable + 
stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
+               dsc_cfg.pic_width = (stream->timing.h_addressable + 
pipe_ctx->hblank_borrow +
+                               stream->timing.h_border_left + 
stream->timing.h_border_right) / opp_cnt;
                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;
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 5de11e2837c0..307782592789 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
@@ -820,6 +820,7 @@ enum dc_status dcn401_enable_stream_timing(
        int opp_cnt = 1;
        int opp_inst[MAX_PIPES] = {0};
        struct pipe_ctx *opp_heads[MAX_PIPES] = {0};
+       struct dc_crtc_timing patched_crtc_timing = stream->timing;
        bool manual_mode;
        unsigned int tmds_div = PIXEL_RATE_DIV_NA;
        unsigned int unused_div = PIXEL_RATE_DIV_NA;
@@ -874,9 +875,13 @@ enum dc_status dcn401_enable_stream_timing(
        if (dc->hwseq->funcs.PLAT_58856_wa && 
(!dc_is_dp_signal(stream->signal)))
                dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
 
+       /* if we are borrowing from hblank, h_addressable needs to be adjusted 
*/
+       if (dc->debug.enable_hblank_borrow)
+               patched_crtc_timing.h_addressable = 
patched_crtc_timing.h_addressable + pipe_ctx->hblank_borrow;
+
        pipe_ctx->stream_res.tg->funcs->program_timing(
                        pipe_ctx->stream_res.tg,
-                       &stream->timing,
+                       &patched_crtc_timing,
                        pipe_ctx->pipe_dlg_param.vready_offset,
                        pipe_ctx->pipe_dlg_param.vstartup_start,
                        pipe_ctx->pipe_dlg_param.vupdate_offset,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h 
b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index 3061dca47dd2..2edd5b38ce4f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -478,6 +478,8 @@ struct pipe_ctx {
        /* subvp_index: only valid if the pipe is a SUBVP_MAIN*/
        uint8_t subvp_index;
        struct pixel_rate_divider pixel_rate_divider;
+       /* pixels borrowed from hblank to hactive */
+       uint8_t hblank_borrow;
 };
 
 /* Data used for dynamic link encoder assignment.
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 41cab9ad6885..5d66bfc7fe6e 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -808,7 +808,8 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool 
enable)
                enum optc_dsc_mode optc_dsc_mode;
 
                /* Enable DSC hw block */
-               dsc_cfg.pic_width = (stream->timing.h_addressable + 
stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
+               dsc_cfg.pic_width = (stream->timing.h_addressable + 
pipe_ctx->hblank_borrow +
+                               stream->timing.h_border_left + 
stream->timing.h_border_right) / opp_cnt;
                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;
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c 
b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
index 984d23bcbc27..12d247a7ec45 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
@@ -2804,6 +2804,7 @@ struct pipe_ctx 
*dcn32_acquire_free_pipe_as_secondary_opp_head(
                free_pipe->plane_res.xfm = pool->transforms[free_pipe_idx];
                free_pipe->plane_res.dpp = pool->dpps[free_pipe_idx];
                free_pipe->plane_res.mpcc_inst = 
pool->dpps[free_pipe_idx]->inst;
+               free_pipe->hblank_borrow = otg_master->hblank_borrow;
                if (free_pipe->stream->timing.flags.DSC == 1) {
                        dcn20_acquire_dsc(free_pipe->stream->ctx->dc,
                                        &new_ctx->res_ctx,
-- 
2.43.0

Reply via email to