drm/amd/display: Apply ODM 2:1 policy for single display configuration
authorSamson Tam <Samson.Tam@amd.com>
Fri, 27 May 2022 01:12:23 +0000 (21:12 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 5 Jul 2022 20:11:08 +0000 (16:11 -0400)
[Why]
Most of the time, a single display uses the ODM combine. When using
multi-display, we use ODM combine only if it is necessary. These cases
are not flexible enough for us, and we can improve them to take
advantage of our hardware. We want to have more control over the ODM
policy.

[How]
This commit add a new debug flag named
enable_single_display_2to1_odm_policy to control the ODM policy and
another flag named enable_dp_dig_pixel_rate_div_policy to fine control
the ODM combine. This is possible by adding a new "pipe.dest" parameter
that can be set to ODM 2:1 combined if we use a single display. For
dynamic ODM combine, when using DP-DIG, DCN applies K2=2 settings for
ODM combine. Note that this feature affects the following registers:

- timing.pix_clk_100khz -> DP_VID_M, DP_VID_N
- requested_pix_clk_100hz -> DP_DTOn_PHASE
- OTGn_PIXEL_RATE_DIVK2
- DP_PIXEL_PER_CYCLE_PROCESSING_MODE
- DIG_FIFO_OUTPUT_PIXEL_MODE
- DP_VID_N_MUL

Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Samson Tam <Samson.Tam@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/dc.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h

index 447647ac3d808c0686cb3940ffb905e3f4aed40c..7fa46e35bac6391dff4cb3aa139eb7bf6ecaeb51 100644 (file)
@@ -748,6 +748,8 @@ struct dc_debug_options {
        enum dml_hostvm_override_opts dml_hostvm_override;
        bool use_legacy_soc_bb_mechanism;
        bool exit_idle_opt_for_cursor_updates;
+       bool enable_single_display_2to1_odm_policy;
+       bool enable_dp_dig_pixel_rate_div_policy;
 };
 
 struct gpu_info_soc_bounding_box_v1_0;
index 7802d603f79600d2cc53324b867dbdafc9d38319..0b1ef76e32684f10cd5849a1a711723a6d7188eb 100644 (file)
@@ -1237,6 +1237,8 @@ static void get_pixel_clock_parameters(
        int opp_cnt = 1;
        struct dc_link *link = stream->link;
        struct link_encoder *link_enc = NULL;
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
+       struct dce_hwseq *hws = dc->hwseq;
 
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
                opp_cnt++;
@@ -1268,6 +1270,11 @@ static void get_pixel_clock_parameters(
        else if (optc2_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2)
                pixel_clk_params->requested_pix_clk_100hz /= 2;
 
+       else if (hws->funcs.is_dp_dig_pixel_rate_div_policy) {
+               if (hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx))
+                       pixel_clk_params->requested_pix_clk_100hz /= 2;
+       }
+
        if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
                pixel_clk_params->requested_pix_clk_100hz *= 2;
 
index f16c4fcdf9e9c4791da8ce5ba04b05b20b952a91..da7d2243664fbf27ae4f4d32664da9dcd902f564 100644 (file)
@@ -249,6 +249,7 @@ static void enc32_stream_encoder_dp_unblank(
                const struct encoder_unblank_param *param)
 {
        struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+       struct dc *dc = enc->ctx->dc;
 
        if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {
                uint32_t n_vid = 0x8000;
@@ -257,7 +258,8 @@ static void enc32_stream_encoder_dp_unblank(
                uint64_t m_vid_l = n_vid;
 
                /* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */
-               if (is_two_pixels_per_containter(&param->timing) || param->opp_cnt > 1) {
+               if (is_two_pixels_per_containter(&param->timing) || param->opp_cnt > 1
+                       || dc->debug.enable_dp_dig_pixel_rate_div_policy) {
                        /*this logic should be the same in get_pixel_clock_parameters() */
                        n_multiply = 1;
                }
index aa9eb229199b923dfbc3654e203d489b37da0d83..cbc93f5a428e5aa93d6c1b61e055e67f6143bc14 100644 (file)
@@ -1083,6 +1083,7 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
 {
        struct dc_stream_state *stream = pipe_ctx->stream;
        unsigned int odm_combine_factor = 0;
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
 
        odm_combine_factor = get_odm_config(pipe_ctx, NULL);
 
@@ -1102,9 +1103,7 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
                        *k1_div = PIXEL_RATE_DIV_BY_2;
                        *k2_div = PIXEL_RATE_DIV_BY_2;
                } else {
-                       if (odm_combine_factor == 1)
-                               *k2_div = PIXEL_RATE_DIV_BY_4;
-                       else if (odm_combine_factor == 2)
+                       if ((odm_combine_factor == 2) || dc->debug.enable_dp_dig_pixel_rate_div_policy)
                                *k2_div = PIXEL_RATE_DIV_BY_2;
                }
        }
@@ -1124,10 +1123,61 @@ void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
                return;
 
        odm_combine_factor = get_odm_config(pipe_ctx, NULL);
-       if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1)
+       if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1
+               || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx))
                pix_per_cycle = 2;
 
        if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode)
                pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc,
                                pix_per_cycle);
 }
+
+void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
+               struct dc_link_settings *link_settings)
+{
+       struct encoder_unblank_param params = {0};
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
+       struct dce_hwseq *hws = link->dc->hwseq;
+       struct pipe_ctx *odm_pipe;
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
+       uint32_t pix_per_cycle = 1;
+
+       params.opp_cnt = 1;
+       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+               params.opp_cnt++;
+
+       /* only 3 items below are used by unblank */
+       params.timing = pipe_ctx->stream->timing;
+
+       params.link_settings.link_rate = link_settings->link_rate;
+
+       if (is_dp_128b_132b_signal(pipe_ctx)) {
+               /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
+               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
+                               pipe_ctx->stream_res.hpo_dp_stream_enc,
+                               pipe_ctx->stream_res.tg->inst);
+       } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+               if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1
+                       || dc->debug.enable_dp_dig_pixel_rate_div_policy) {
+                       params.timing.pix_clk_100hz /= 2;
+                       pix_per_cycle = 2;
+               }
+               pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
+                               pipe_ctx->stream_res.stream_enc, pix_per_cycle > 1);
+               pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
+       }
+
+       if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
+               hws->funcs.edp_backlight_control(link, true);
+}
+
+bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)
+{
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
+
+       if (dc_is_dp_signal(pipe_ctx->stream->signal) && !is_dp_128b_132b_signal(pipe_ctx) &&
+               dc->debug.enable_dp_dig_pixel_rate_div_policy)
+               return true;
+       return false;
+}
index 18227d58c51d255a1b57657a51eebdba36ae8092..083f3aeb54f01ff645cb10c60baf0f3fdaf51d2f 100644 (file)
@@ -79,4 +79,9 @@ void dcn32_subvp_pipe_control_lock(struct dc *dc,
                struct pipe_ctx *top_pipe_to_program,
                bool subvp_prev_use);
 
+void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
+               struct dc_link_settings *link_settings);
+
+bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx);
+
 #endif /* __DC_HWSS_DCN32_H__ */
index 19d8a30b3358a3f23e735d86f0ede8f10ad9c2a4..30361ebe7d22f47bce8516e24c78c7772d422af1 100644 (file)
@@ -50,7 +50,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
        .send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
        .enable_stream = dcn20_enable_stream,
        .disable_stream = dce110_disable_stream,
-       .unblank_stream = dcn20_unblank_stream,
+       .unblank_stream = dcn32_unblank_stream,
        .blank_stream = dce110_blank_stream,
        .enable_audio_stream = dce110_enable_audio_stream,
        .disable_audio_stream = dce110_disable_audio_stream,
@@ -143,6 +143,7 @@ static const struct hwseq_private_funcs dcn32_private_funcs = {
        .update_mall_sel = dcn32_update_mall_sel,
        .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values,
        .set_pixels_per_cycle = dcn32_set_pixels_per_cycle,
+       .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy,
 };
 
 void dcn32_hw_sequencer_init_functions(struct dc *dc)
index 9434eedde1bf0ed018160121cdf63be518d7ca6a..468c18acfcdcfa9e3df75e22a6d95718358cc5df 100644 (file)
@@ -3036,6 +3036,12 @@ int dcn32_populate_dml_pipes_from_context(
                                break;
                        }
                }
+
+               pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal;
+               if (context->stream_count == 1) {
+                       if (dc->debug.enable_single_display_2to1_odm_policy)
+                               pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1;
+               }
                pipe_cnt++;
        }
 
index 00acf2079b06f031c1b0894f963e50b301fdd28a..b5d7e251ed8121cbb870f740e1aa036827a16768 100644 (file)
@@ -497,6 +497,7 @@ struct _vcs_dpi_display_pipe_dest_params_st {
        unsigned int vtotal_min;
        unsigned int refresh_rate;
        bool synchronize_timings;
+       unsigned int odm_combine_policy;
 };
 
 struct _vcs_dpi_display_pipe_params_st {
index 2676710a5f2b6c2b6ed33657f8318d65ad290e36..74e17f5da8dc59759afe56f49343613a26e8977c 100644 (file)
@@ -561,7 +561,8 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib)
                mode_lib->vba.GPUVMMinPageSizeKBytes[mode_lib->vba.NumberOfActivePlanes] = src->gpuvm_min_page_size_kbytes;
                mode_lib->vba.RefreshRate[mode_lib->vba.NumberOfActivePlanes] = dst->refresh_rate; //todo remove this
                mode_lib->vba.OutputLinkDPRate[mode_lib->vba.NumberOfActivePlanes] = dout->dp_rate;
-               mode_lib->vba.ODMUse[mode_lib->vba.NumberOfActivePlanes] = dst->odm_combine;
+
+               mode_lib->vba.ODMUse[mode_lib->vba.NumberOfActivePlanes] = dst->odm_combine_policy;
                //TODO: Need to assign correct values to dp_multistream vars
                mode_lib->vba.OutputMultistreamEn[mode_lib->vba.NumberOfActiveSurfaces] = dout->dp_multistream_en;
                mode_lib->vba.OutputMultistreamId[mode_lib->vba.NumberOfActiveSurfaces] = dout->dp_multistream_id;
index 2b2e5b8089629788fb3386766af1a8cd6d675e4c..1cdea0efe5c1ac23b8f606e06daa5abc3c67bfd4 100644 (file)
@@ -154,6 +154,7 @@ struct hwseq_private_funcs {
                        unsigned int *k1_div,
                        unsigned int *k2_div);
        void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx);
+       bool (*is_dp_dig_pixel_rate_div_policy)(struct pipe_ctx *pipe_ctx);
 #endif
 };