[PATCH 08/13] drm/amd/display: Synchronize displays with different timings

Nils Wallménius nils.wallmenius at gmail.com
Sun Feb 21 06:21:06 UTC 2021


Hi Bindu, an inline comment below.

Den fre 19 feb. 2021 23:16Bindu Ramamurthy <bindu.r at amd.com> skrev:

> From: Vladimir Stempen <vladimir.stempen at amd.com>
>
> [why]
>  Vendor based fan noise improvement
>
> [how]
> Report timing synchronizable when DP streams time frame
> difference is less than 0.05 percent. Adjust DP  DTOs and
> sync displays using  MASTER_UPDATE_LOCK_DB_X_Y
>
> Signed-off-by: Vladimir Stempen <vladimir.stempen at amd.com>
> Acked-by: Bindu Ramamurthy <bindu.r at amd.com>
> ---
>  drivers/gpu/drm/amd/display/dc/core/dc.c      |  28 ++-
>  .../gpu/drm/amd/display/dc/core/dc_resource.c |  43 ++++
>  drivers/gpu/drm/amd/display/dc/dc.h           |   3 +
>  drivers/gpu/drm/amd/display/dc/dc_hw_types.h  |   1 +
>  drivers/gpu/drm/amd/display/dc/dc_stream.h    |   3 +
>  .../drm/amd/display/dc/dce/dce_clock_source.c |  52 +++-
>  .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 225 ++++++++++++++++++
>  .../amd/display/dc/dcn10/dcn10_hw_sequencer.h |   5 +
>  .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.h |   2 +
>  .../display/dc/dcn10/dcn10_stream_encoder.c   |   1 -
>  .../gpu/drm/amd/display/dc/dcn20/dcn20_init.c |   1 +
>  .../gpu/drm/amd/display/dc/dcn20/dcn20_optc.c | 123 ++++++++++
>  .../drm/amd/display/dc/dcn20/dcn20_resource.c |   8 +-
>  .../dc/dcn30/dcn30_dio_stream_encoder.c       |   1 -
>  .../gpu/drm/amd/display/dc/inc/clock_source.h |   5 +
>  .../amd/display/dc/inc/hw/timing_generator.h  |  12 +
>  .../gpu/drm/amd/display/dc/inc/hw_sequencer.h |   3 +
>  drivers/gpu/drm/amd/display/dc/inc/resource.h |   4 +
>  18 files changed, 505 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c
> b/drivers/gpu/drm/amd/display/dc/core/dc.c
> index 2f56fa2c0bf4..39df5d2c0108 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
> @@ -1102,6 +1102,7 @@ static void program_timing_sync(
>
>         for (i = 0; i < pipe_count; i++) {
>                 int group_size = 1;
> +               enum timing_synchronization_type sync_type =
> NOT_SYNCHRONIZABLE;
>                 struct pipe_ctx *pipe_set[MAX_PIPES];
>
>                 if (!unsynced_pipes[i])
> @@ -1116,10 +1117,22 @@ static void program_timing_sync(
>                 for (j = i + 1; j < pipe_count; j++) {
>                         if (!unsynced_pipes[j])
>                                 continue;
> -
> -                       if (resource_are_streams_timing_synchronizable(
> +                       if (sync_type != TIMING_SYNCHRONIZABLE &&
> +                               dc->hwss.enable_vblanks_synchronization &&
> +
>  unsynced_pipes[j]->stream_res.tg->funcs->align_vblanks &&
> +                               resource_are_vblanks_synchronizable(
> +                                       unsynced_pipes[j]->stream,
> +                                       pipe_set[0]->stream)) {
> +                               sync_type = VBLANK_SYNCHRONIZABLE;
> +                               pipe_set[group_size] = unsynced_pipes[j];
> +                               unsynced_pipes[j] = NULL;
> +                               group_size++;
> +                       } else
> +                       if (sync_type != VBLANK_SYNCHRONIZABLE &&
> +                               resource_are_streams_timing_synchronizable(
>                                         unsynced_pipes[j]->stream,
>                                         pipe_set[0]->stream)) {
> +                               sync_type = TIMING_SYNCHRONIZABLE;
>                                 pipe_set[group_size] = unsynced_pipes[j];
>                                 unsynced_pipes[j] = NULL;
>                                 group_size++;
> @@ -1145,7 +1158,6 @@ static void program_timing_sync(
>                         }
>                 }
>
> -
>                 for (k = 0; k < group_size; k++) {
>                         struct dc_stream_status *status =
> dc_stream_get_status_from_state(ctx, pipe_set[k]->stream);
>
> @@ -1175,8 +1187,14 @@ static void program_timing_sync(
>                 }
>
>                 if (group_size > 1) {
> -                       dc->hwss.enable_timing_synchronization(
> -                               dc, group_index, group_size, pipe_set);
> +                       if (sync_type == TIMING_SYNCHRONIZABLE) {
> +                               dc->hwss.enable_timing_synchronization(
> +                                       dc, group_index, group_size,
> pipe_set);
> +                       } else
> +                               if (sync_type == VBLANK_SYNCHRONIZABLE) {
> +                               dc->hwss.enable_vblanks_synchronization(
> +                                       dc, group_index, group_size,
> pipe_set);
> +                               }
>                         group_index++;
>                 }
>                 num_group++;
> 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 0c26c2ade782..0241c9d96d7a 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> @@ -417,6 +417,49 @@ int resource_get_clock_source_reference(
>         return -1;
>  }
>
> +bool resource_are_vblanks_synchronizable(
> +       struct dc_stream_state *stream1,
> +       struct dc_stream_state *stream2)
> +{
> +       uint32_t base60_refresh_rates[] = {10, 20, 5};
> +       uint8_t i;
> +       uint8_t rr_count =
> sizeof(base60_refresh_rates)/sizeof(base60_refresh_rates[0]);
> +       int64_t frame_time_diff;
> +
> +       if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
> +
>  stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
> +               dc_is_dp_signal(stream1->signal) &&
> +               dc_is_dp_signal(stream2->signal) &&
> +               false == stream1->has_non_synchronizable_pclk &&
> +               false == stream2->has_non_synchronizable_pclk &&
> +               stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
> +               stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
> +               /* disable refresh rates higher than 60Hz for now */
> +               if
> (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
> +                               stream1->timing.v_total > 60)
> +                       return false;
> +               if
> (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
> +                               stream2->timing.v_total > 60)
> +                       return false;
> +               frame_time_diff = (int64_t)10000 *
> +                       stream1->timing.h_total *
> +                       stream1->timing.v_total *
> +                       stream2->timing.pix_clk_100hz /
> +                       stream1->timing.pix_clk_100hz /
> +                       stream2->timing.h_total /
> +                       stream2->timing.v_total;
> +               for (i = 0; i < rr_count; i++) {
> +                       int64_t diff = (frame_time_diff *
> base60_refresh_rates[i]) / 10 - 10000;
> +
> +                       if (diff < 0)
> +                               diff = -diff;
> +                       if (diff <
> stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
> +                               return true;
> +               }
> +       }
> +       return false;
> +}
> +
>  bool resource_are_streams_timing_synchronizable(
>         struct dc_stream_state *stream1,
>         struct dc_stream_state *stream2)
> diff --git a/drivers/gpu/drm/amd/display/dc/dc.h
> b/drivers/gpu/drm/amd/display/dc/dc.h
> index a10daf6655f9..9e631980fa1b 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc.h
> @@ -301,6 +301,8 @@ struct dc_config {
>  #if defined(CONFIG_DRM_AMD_DC_DCN)
>         bool clamp_min_dcfclk;
>  #endif
> +       uint64_t vblank_alignment_dto_params;
> +       uint8_t  vblank_alignment_max_frame_time_diff;
>  };
>
>  enum visual_confirm {
> @@ -528,6 +530,7 @@ struct dc_debug_options {
>         bool disable_dsc;
>         bool enable_dram_clock_change_one_display_vactive;
>         union mem_low_power_enable_options enable_mem_low_power;
> +       bool force_vblank_alignment;
>  };
>
>  struct dc_debug_data {
> diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
> b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
> index b41e6367b15e..48d3ed97ead9 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
> @@ -705,6 +705,7 @@ struct dc_crtc_timing_flags {
>  #ifndef TRIM_FSFT
>         uint32_t FAST_TRANSPORT: 1;
>  #endif
> +       uint32_t VBLANK_SYNCHRONIZABLE: 1;
>  };
>
>  enum dc_timing_3d_format {
> diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h
> b/drivers/gpu/drm/amd/display/dc/dc_stream.h
> index e243c01b9672..7fa998f97e7a 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
> @@ -228,6 +228,9 @@ struct dc_stream_state {
>         uint32_t stream_id;
>         bool is_dsc_enabled;
>         union stream_update_flags update_flags;
> +
> +       bool has_non_synchronizable_pclk;
> +       bool vblank_synchronized;
>  };
>
>  #define ABM_LEVEL_IMMEDIATE_DISABLE 255
> diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
> b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
> index dec58b3c42e4..6f47f9bab5ee 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
> +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
> @@ -1002,15 +1002,27 @@ static bool get_pixel_clk_frequency_100hz(
>  {
>         struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
>         unsigned int clock_hz = 0;
> +       unsigned int modulo_hz = 0;
>
>         if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
>                 clock_hz = REG_READ(PHASE[inst]);
>
> -               /* NOTE: There is agreement with VBIOS here that MODULO is
> -                * programmed equal to DPREFCLK, in which case PHASE will
> be
> -                * equivalent to pixel clock.
> -                */
> -               *pixel_clk_khz = clock_hz / 100;
> +               if
> (clock_source->ctx->dc->hwss.enable_vblanks_synchronization &&
> +
>  clock_source->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0) {
> +                       /* NOTE: In case VBLANK syncronization is enabled,
> MODULO may
> +                        * not be programmed equal to DPREFCLK
> +                        */
> +                       modulo_hz = REG_READ(MODULO[inst]);
> +                       *pixel_clk_khz = ((uint64_t)clock_hz*
> +
>  clock_source->ctx->dc->clk_mgr->dprefclk_khz*10)/
> +                               modulo_hz;
> +               } else {
> +                       /* NOTE: There is agreement with VBIOS here that
> MODULO is
> +                        * programmed equal to DPREFCLK, in which case
> PHASE will be
> +                        * equivalent to pixel clock.
> +                        */
> +                       *pixel_clk_khz = clock_hz / 100;
> +               }
>                 return true;
>         }
>
> @@ -1074,8 +1086,35 @@ static bool dcn20_program_pix_clk(
>                 struct pixel_clk_params *pix_clk_params,
>                 struct pll_settings *pll_settings)
>  {
> +       struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
> +       unsigned int inst = pix_clk_params->controller_id -
> CONTROLLER_ID_D0;
> +
>         dce112_program_pix_clk(clock_source, pix_clk_params, pll_settings);
>
> +       if (clock_source->ctx->dc->hwss.enable_vblanks_synchronization &&
> +
>  clock_source->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0) {
> +               /* NOTE: In case VBLANK syncronization is enabled,
> +                * we need to set modulo to default DPREFCLK first
> +                * dce112_program_pix_clk does not set default DPREFCLK
> +                */
> +               REG_WRITE(MODULO[inst],
> +                       clock_source->ctx->dc->clk_mgr->dprefclk_khz*1000);
> +       }
> +       return true;
> +}
> +
> +static bool dcn20_override_dp_pix_clk(
> +               struct clock_source *clock_source,
> +               unsigned int inst,
> +               unsigned int pixel_clk,
> +               unsigned int ref_clk)
> +{
> +       struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
> +
> +       REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 0);
> +       REG_WRITE(PHASE[inst], pixel_clk);
> +       REG_WRITE(MODULO[inst], ref_clk);
> +       REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
>         return true;
>  }
>
> @@ -1083,7 +1122,8 @@ static const struct clock_source_funcs
> dcn20_clk_src_funcs = {
>         .cs_power_down = dce110_clock_source_power_down,
>         .program_pix_clk = dcn20_program_pix_clk,
>         .get_pix_clk_dividers = dce112_get_pix_clk_dividers,
> -       .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
> +       .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz,
> +       .override_dp_pix_clk = dcn20_override_dp_pix_clk
>  };
>
>  #if defined(CONFIG_DRM_AMD_DC_DCN)
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
> b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
> index 89912bb5014f..669cee48b0b5 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
> @@ -1851,6 +1851,225 @@ static bool wait_for_reset_trigger_to_occur(
>         return rc;
>  }
>
> +uint64_t reduceSizeAndFraction(
> +       uint64_t *numerator,
> +       uint64_t *denominator,
> +       bool checkUint32Bounary)
> +{
> +       int i;
> +       bool ret = checkUint32Bounary == false;
> +       uint64_t max_int32 = 0xffffffff;
> +       uint64_t num, denom;
> +       uint16_t prime_numbers[] = {
> +               2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
> +               47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
> +               107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
> +               167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
> +               229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
> +               283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353,
> +               359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
> +               431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487,
> +               491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
> +               571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
> +               641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
> +               709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773,
> +               787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857,
> +               859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
> +               941, 947, 953, 967, 971, 977, 983, 991, 997};
> +       int count = ARRAY_SIZE(prime_numbers)/sizeof(prime_numbers[0]);
>

ARRAY_SIZE gives the number of elements, so this will limit iteration to
the first half of the prime_numbers array. Btw, the array can be "static
const".

BR
Nils
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/amd-gfx/attachments/20210221/0fc48d9b/attachment-0001.htm>


More information about the amd-gfx mailing list