Hi Bindu, an inline comment below. Den fre 19 feb. 2021 23:16Bindu Ramamurthy skrev: > From: Vladimir Stempen > > [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 > Acked-by: Bindu Ramamurthy > --- > 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