drm/amd/display: Ensure DRR triggers in BP
authorEryk Brol <eryk.brol@amd.com>
Tue, 23 Apr 2019 15:53:52 +0000 (11:53 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 31 May 2019 15:39:30 +0000 (10:39 -0500)
[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 <eryk.brol@amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h

index 53b76e0de9403572fac9f69c0f65bf11c693d025..64dff3fc1f7b138249e8ab4ec0c7bf26b611f905 100644 (file)
@@ -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,
index 79c3a372584f7817de17bb95623610c4b5a0308f..5012b6755dc898df9bcb4c3425bfea8030c4bf5a 100644 (file)
@@ -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,
index 189bdab929a55651c40245c3de205c6ef65b5fdb..4da138ded8b7d9289ae62e599710bc4a0ada2712 100644 (file)
@@ -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;
index 7ee3c60cdc1874217cf8b388a0b91260b4ac1b23..b5ca1764e2a2a1c9b4f225e198f6897cf7a879ae 100644 (file)
@@ -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;
index 533b0f3cf6c3514c49f9befeaf8fa81967ab7ff6..e4b850a2d31f5cf64f8b67f31d465829fe8294b7 100644 (file)
@@ -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)
index 70fd56fa56c57b048be959d810ee06988431af97..444c56c8104f7ad85a5151d15e4da44ef0799b9e 100644 (file)
        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) \
index 0b8c6896581f11d7af9f3de853c264ff52ae26e6..a89d0cf59cca4d8f77329c3539e7e5af85ae8152 100644 (file)
@@ -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);
 };