From: Eryk Brol Date: Tue, 23 Apr 2019 15:53:52 +0000 (-0400) Subject: drm/amd/display: Ensure DRR triggers in BP X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=e63e2491ad92036e844230b6373ae07923552f6c;p=openwrt%2Fstaging%2Fblogic.git drm/amd/display: Ensure DRR triggers in BP [Why] In the previous implementation DRR event sometimes came in during FP2 region which is a keep-out zone. This would cause the frame not to latch until the next frame which resulted in heavy flicker. To fix this we need to make sure that it triggers in the BP. [How] 1. Remove DRR programming during flip 2. Setup manual trigger for DRR event and trigger it after surface programming is complete Signed-off-by: Eryk Brol Reviewed-by: Aric Cyr Acked-by: Leo Li Signed-off-by: Alex Deucher --- diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 53b76e0de940..64dff3fc1f7b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5127,6 +5127,11 @@ static void update_freesync_state_on_stream( amdgpu_dm_vrr_active(new_crtc_state)) { mod_freesync_handle_v_update(dm->freesync_module, new_stream, &vrr_params); + + /* Need to call this before the frame ends. */ + dc_stream_adjust_vmin_vmax(dm->dc, + new_crtc_state->stream, + &vrr_params.adjust); } } @@ -5465,11 +5470,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, } if (acrtc_state->stream) { - - if (acrtc_state->freesync_timing_changed) - bundle->stream_update.adjust = - &acrtc_state->stream->adjust; - if (acrtc_state->freesync_vrr_info_changed) bundle->stream_update.vrr_infopacket = &acrtc_state->stream->vrr_infopacket; @@ -5490,6 +5490,20 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, if (acrtc_state->abm_level != dm_old_crtc_state->abm_level) bundle->stream_update.abm_level = &acrtc_state->abm_level; + /* + * If FreeSync state on the stream has changed then we need to + * re-adjust the min/max bounds now that DC doesn't handle this + * as part of commit. + */ + if (amdgpu_dm_vrr_active(dm_old_crtc_state) != + amdgpu_dm_vrr_active(acrtc_state)) { + spin_lock_irqsave(&pcrtc->dev->event_lock, flags); + dc_stream_adjust_vmin_vmax( + dm->dc, acrtc_state->stream, + &acrtc_state->vrr_params.adjust); + spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags); + } + mutex_lock(&dm->dc_lock); dc_commit_updates_for_stream(dm->dc, bundle->surface_updates, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 79c3a372584f..5012b6755dc8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -263,7 +263,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream == stream && pipe->stream_res.stream_enc) { + if (pipe->stream == stream && pipe->stream_res.tg) { pipe->stream->adjust = *adjust; dc->hwss.set_drr(&pipe, 1, @@ -1745,13 +1745,6 @@ static void commit_planes_do_stream_update(struct dc *dc, pipe_ctx->stream && pipe_ctx->stream == stream) { - /* Fast update*/ - // VRR program can be done as part of FAST UPDATE - if (stream_update->adjust) - dc->hwss.set_drr(&pipe_ctx, 1, - stream_update->adjust->v_total_min, - stream_update->adjust->v_total_max); - if (stream_update->periodic_interrupt0 && dc->hwss.setup_periodic_interrupt) dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE0); @@ -1909,6 +1902,20 @@ static void commit_planes_for_stream(struct dc *dc, dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false); } + + // Fire manual trigger + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->top_pipe || + !pipe_ctx->stream || + pipe_ctx->stream != stream || + !srf_updates[i].flip_addr) + continue; + + if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger) + pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg); + } } void dc_commit_updates_for_stream(struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 189bdab929a5..4da138ded8b7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -172,7 +172,6 @@ struct dc_stream_update { struct periodic_interrupt_config *periodic_interrupt0; struct periodic_interrupt_config *periodic_interrupt1; - struct dc_crtc_timing_adjust *adjust; struct dc_info_packet *vrr_infopacket; struct dc_info_packet *vsc_infopacket; struct dc_info_packet *vsp_infopacket; 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 7ee3c60cdc18..b5ca1764e2a2 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 @@ -2506,8 +2506,8 @@ static void set_drr(struct pipe_ctx **pipe_ctx, { int i = 0; struct drr_params params = {0}; - // DRR should set trigger event to monitor surface update event - unsigned int event_triggers = 0x80; + // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow + unsigned int event_triggers = 0x800; params.vertical_total_max = vmax; params.vertical_total_min = vmin; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 533b0f3cf6c3..e4b850a2d31f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -791,6 +791,32 @@ void optc1_set_static_screen_control( OTG_STATIC_SCREEN_FRAME_COUNT, 2); } +void optc1_setup_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL2, 0, + MANUAL_FLOW_CONTROL_SEL, optc->inst); + + REG_SET_8(OTG_TRIGA_CNTL, 0, + OTG_TRIGA_SOURCE_SELECT, 22, + OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, + OTG_TRIGA_POLARITY_SELECT, 0, + OTG_TRIGA_FREQUENCY_SELECT, 0, + OTG_TRIGA_DELAY, 0, + OTG_TRIGA_CLEAR, 1); +} + +void optc1_program_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, + MANUAL_FLOW_CONTROL, 1); +} + /** ***************************************************************************** @@ -823,6 +849,10 @@ void optc1_set_drr( OTG_FORCE_LOCK_ON_EVENT, 0, OTG_SET_V_TOTAL_MIN_MASK_EN, 0, OTG_SET_V_TOTAL_MIN_MASK, 0); + + // Setup manual flow control for EOF via TRIG_A + optc->funcs->setup_manual_trigger(optc); + } else { REG_UPDATE_4(OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, 0, @@ -1458,6 +1488,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .get_crc = optc1_get_crc, .configure_crc = optc1_configure_crc, .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc1_program_manual_trigger, + .setup_manual_trigger = optc1_setup_manual_trigger }; void dcn10_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 70fd56fa56c5..444c56c8104f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -85,13 +85,17 @@ SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ - SR(GSL_SOURCE_SELECT) + SR(GSL_SOURCE_SELECT),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst) + #define TG_COMMON_REG_LIST_DCN1_0(inst) \ TG_COMMON_REG_LIST_DCN(inst),\ SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\ SRI(OTG_TEST_PATTERN_CONTROL, OTG, inst),\ - SRI(OTG_TEST_PATTERN_COLOR, OTG, inst) + SRI(OTG_TEST_PATTERN_COLOR, OTG, inst),\ + SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst) struct dcn_optc_registers { @@ -125,6 +129,8 @@ struct dcn_optc_registers { uint32_t OTG_V_TOTAL_MIN; uint32_t OTG_V_TOTAL_CONTROL; uint32_t OTG_TRIGA_CNTL; + uint32_t OTG_TRIGA_MANUAL_TRIG; + uint32_t OTG_MANUAL_FLOW_CONTROL; uint32_t OTG_FORCE_COUNT_NOW_CNTL; uint32_t OTG_STATIC_SCREEN_CONTROL; uint32_t OTG_STATUS_FRAME_COUNT; @@ -215,6 +221,11 @@ struct dcn_optc_registers { SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ @@ -271,8 +282,8 @@ struct dcn_optc_registers { SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh) - + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh) #define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\ TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ @@ -287,7 +298,8 @@ struct dcn_optc_registers { SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_COLOR_FORMAT, mask_sh),\ SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_MASK, mask_sh),\ SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_DATA, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh) + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh),\ + SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh),\ #define TG_REG_FIELD_LIST_DCN1_0(type) \ type VSTARTUP_START;\ @@ -343,6 +355,11 @@ struct dcn_optc_registers { type OTG_TRIGA_SOURCE_PIPE_SELECT;\ type OTG_TRIGA_RISING_EDGE_DETECT_CNTL;\ type OTG_TRIGA_FALLING_EDGE_DETECT_CNTL;\ + type OTG_TRIGA_POLARITY_SELECT;\ + type OTG_TRIGA_FREQUENCY_SELECT;\ + type OTG_TRIGA_DELAY;\ + type OTG_TRIGA_CLEAR;\ + type OTG_TRIGA_MANUAL_TRIG;\ type OTG_STATIC_SCREEN_EVENT_MASK;\ type OTG_STATIC_SCREEN_FRAME_COUNT;\ type OTG_FRAME_COUNT;\ @@ -421,7 +438,9 @@ struct dcn_optc_registers { type OTG_CRC0_WINDOWB_Y_END;\ type GSL0_READY_SOURCE_SEL;\ type GSL1_READY_SOURCE_SEL;\ - type GSL2_READY_SOURCE_SEL; + type GSL2_READY_SOURCE_SEL;\ + type MANUAL_FLOW_CONTROL;\ + type MANUAL_FLOW_CONTROL_SEL; #define TG_REG_FIELD_LIST(type) \ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 0b8c6896581f..a89d0cf59cca 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -238,6 +238,9 @@ struct timing_generator_funcs { bool (*get_crc)(struct timing_generator *tg, uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb); + void (*program_manual_trigger)(struct timing_generator *optc); + void (*setup_manual_trigger)(struct timing_generator *optc); + void (*set_vtg_params)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); };