drm/amd/display: Program VTG params after programming Global Sync
authorJoshua Aberback <joshua.aberback@amd.com>
Mon, 29 Apr 2019 21:21:19 +0000 (17:21 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 24 May 2019 17:21:00 +0000 (12:21 -0500)
[Why]
VTG has a parameter FP2, which is defined as:
    if VSTARTUP is before VSYNC:
        FP2 = number of lines in between VSTARTUP and VSYNC
    else
        FP2 = 0
Currently, FP2 is only programmed during "program_timing". However, the
position of VSTARTUP is affected by the prefetching requirements on all pipes,
so the position might change when we do memory request control on another pipe, so we need
to make sure that FP2 stays up-to-date whenever we adjust VSTARTUP.

[How]
 - refactor VTG_CONTROL programming into a new function "set_vtg_params"
 - call it after calling "program_global_sync"
   - make sure it's called after because it relies on the cached dlg params

Signed-off-by: Joshua Aberback <joshua.aberback@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Acked-by: Jun Lei <Jun.Lei@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
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 bf0db874d99fc815d854ba030b9eebb8d762a4a0..66bb0e7db25c519fe8f3fde32151a554f8d5787c 100644 (file)
@@ -2285,6 +2285,9 @@ static void program_all_pipe_in_tree(
                                pipe_ctx->pipe_dlg_param.vupdate_offset,
                                pipe_ctx->pipe_dlg_param.vupdate_width);
 
+               pipe_ctx->stream_res.tg->funcs->set_vtg_params(
+                               pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
+
                dc->hwss.blank_pixel_data(dc, pipe_ctx, blank);
 
        }
index 0afe81ed023b2e3c17fe48fdd8a6eb7bab6ca3eb..533b0f3cf6c3514c49f9befeaf8fa81967ab7ff6 100644 (file)
@@ -46,9 +46,7 @@
 * This is a workaround for a bug that has existed since R5xx and has not been
 * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
 */
-static void optc1_apply_front_porch_workaround(
-       struct timing_generator *optc,
-       struct dc_crtc_timing *timing)
+static void apply_front_porch_workaround(struct dc_crtc_timing *timing)
 {
        if (timing->flags.INTERLACE == 1) {
                if (timing->v_front_porch < 2)
@@ -149,17 +147,14 @@ void optc1_program_timing(
        bool use_vbios)
 {
        struct dc_crtc_timing patched_crtc_timing;
-       uint32_t vesa_sync_start;
        uint32_t asic_blank_end;
        uint32_t asic_blank_start;
        uint32_t v_total;
        uint32_t v_sync_end;
-       uint32_t v_init, v_fp2;
        uint32_t h_sync_polarity, v_sync_polarity;
        uint32_t start_point = 0;
        uint32_t field_num = 0;
        uint32_t h_div_2;
-       int32_t vertical_line_start;
 
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
 
@@ -169,7 +164,7 @@ void optc1_program_timing(
        optc1->vupdate_offset = vupdate_offset;
        optc1->vupdate_width = vupdate_width;
        patched_crtc_timing = *dc_crtc_timing;
-       optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
+       apply_front_porch_workaround(&patched_crtc_timing);
 
        /* Load horizontal timing */
 
@@ -182,24 +177,16 @@ void optc1_program_timing(
                        OTG_H_SYNC_A_START, 0,
                        OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width);
 
-       /* asic_h_blank_end = HsyncWidth + HbackPorch =
-        * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart -
-        * vesa.h_left_border
-        */
-       vesa_sync_start = patched_crtc_timing.h_addressable +
-                       patched_crtc_timing.h_border_right +
+       /* blank_start = line end - front porch */
+       asic_blank_start = patched_crtc_timing.h_total -
                        patched_crtc_timing.h_front_porch;
 
-       asic_blank_end = patched_crtc_timing.h_total -
-                       vesa_sync_start -
+       /* blank_end = blank_start - active */
+       asic_blank_end = asic_blank_start -
+                       patched_crtc_timing.h_border_right -
+                       patched_crtc_timing.h_addressable -
                        patched_crtc_timing.h_border_left;
 
-       /* h_blank_start = v_blank_end + v_active */
-       asic_blank_start = asic_blank_end +
-                       patched_crtc_timing.h_border_left +
-                       patched_crtc_timing.h_addressable +
-                       patched_crtc_timing.h_border_right;
-
        REG_UPDATE_2(OTG_H_BLANK_START_END,
                        OTG_H_BLANK_START, asic_blank_start,
                        OTG_H_BLANK_END, asic_blank_end);
@@ -231,24 +218,15 @@ void optc1_program_timing(
                        OTG_V_SYNC_A_START, 0,
                        OTG_V_SYNC_A_END, v_sync_end);
 
-       vesa_sync_start = patched_crtc_timing.v_addressable +
-                       patched_crtc_timing.v_border_bottom +
+       /* blank_start = frame end - front porch */
+       asic_blank_start = patched_crtc_timing.v_total -
                        patched_crtc_timing.v_front_porch;
 
-       asic_blank_end = (patched_crtc_timing.v_total -
-                       vesa_sync_start -
-                       patched_crtc_timing.v_border_top);
-
-       /* v_blank_start = v_blank_end + v_active */
-       asic_blank_start = asic_blank_end +
-                       (patched_crtc_timing.v_border_top +
-                       patched_crtc_timing.v_addressable +
-                       patched_crtc_timing.v_border_bottom);
-
-       vertical_line_start = asic_blank_end - optc1->vstartup_start + 1;
-       v_fp2 = 0;
-       if (vertical_line_start < 0)
-               v_fp2 = -vertical_line_start;
+       /* blank_end = blank_start - active */
+       asic_blank_end = asic_blank_start -
+                       patched_crtc_timing.v_border_bottom -
+                       patched_crtc_timing.v_addressable -
+                       patched_crtc_timing.v_border_top;
 
        REG_UPDATE_2(OTG_V_BLANK_START_END,
                        OTG_V_BLANK_START, asic_blank_start,
@@ -261,10 +239,9 @@ void optc1_program_timing(
        REG_UPDATE(OTG_V_SYNC_A_CNTL,
                OTG_V_SYNC_A_POL, v_sync_polarity);
 
-       v_init = asic_blank_start;
        if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT ||
-               optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
-               optc1->signal == SIGNAL_TYPE_EDP) {
+                       optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
+                       optc1->signal == SIGNAL_TYPE_EDP) {
                start_point = 1;
                if (patched_crtc_timing.flags.INTERLACE == 1)
                        field_num = 1;
@@ -272,13 +249,10 @@ void optc1_program_timing(
 
        /* Interlace */
        if (REG(OTG_INTERLACE_CONTROL)) {
-               if (patched_crtc_timing.flags.INTERLACE == 1) {
+               if (patched_crtc_timing.flags.INTERLACE == 1)
                        REG_UPDATE(OTG_INTERLACE_CONTROL,
                                        OTG_INTERLACE_ENABLE, 1);
-                       v_init = v_init / 2;
-                       if ((optc1->vstartup_start/2)*2 > asic_blank_end)
-                               v_fp2 = v_fp2 / 2;
-               } else
+               else
                        REG_UPDATE(OTG_INTERLACE_CONTROL,
                                        OTG_INTERLACE_ENABLE, 0);
        }
@@ -287,21 +261,19 @@ void optc1_program_timing(
        REG_UPDATE(CONTROL,
                        VTG0_ENABLE, 0);
 
-       REG_UPDATE_2(CONTROL,
-                       VTG0_FP2, v_fp2,
-                       VTG0_VCOUNT_INIT, v_init);
-
        /* original code is using VTG offset to address OTG reg, seems wrong */
        REG_UPDATE_2(OTG_CONTROL,
                        OTG_START_POINT_CNTL, start_point,
                        OTG_FIELD_NUMBER_CNTL, field_num);
 
-       optc1_program_global_sync(optc,
+       optc->funcs->program_global_sync(optc,
                        vready_offset,
                        vstartup_start,
                        vupdate_offset,
                        vupdate_width);
 
+       optc->funcs->set_vtg_params(optc, dc_crtc_timing);
+
        /* TODO
         * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1
         * program_horz_count_by_2
@@ -319,6 +291,48 @@ void optc1_program_timing(
 
 }
 
+void optc1_set_vtg_params(struct timing_generator *optc,
+               const struct dc_crtc_timing *dc_crtc_timing)
+{
+       struct dc_crtc_timing patched_crtc_timing;
+       uint32_t asic_blank_end;
+       uint32_t v_init;
+       uint32_t v_fp2 = 0;
+       int32_t vertical_line_start;
+
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+       patched_crtc_timing = *dc_crtc_timing;
+       apply_front_porch_workaround(&patched_crtc_timing);
+
+       /* VCOUNT_INIT is the start of blank */
+       v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch;
+
+       /* end of blank = v_init - active */
+       asic_blank_end = v_init -
+                       patched_crtc_timing.v_border_bottom -
+                       patched_crtc_timing.v_addressable -
+                       patched_crtc_timing.v_border_top;
+
+       /* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */
+       vertical_line_start = asic_blank_end - optc1->vstartup_start + 1;
+       if (vertical_line_start < 0)
+               v_fp2 = -vertical_line_start;
+
+       /* Interlace */
+       if (REG(OTG_INTERLACE_CONTROL)) {
+               if (patched_crtc_timing.flags.INTERLACE == 1) {
+                       v_init = v_init / 2;
+                       if ((optc1->vstartup_start/2)*2 > asic_blank_end)
+                               v_fp2 = v_fp2 / 2;
+               }
+       }
+
+       REG_UPDATE_2(CONTROL,
+                       VTG0_FP2, v_fp2,
+                       VTG0_VCOUNT_INIT, v_init);
+}
+
 void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
@@ -1443,6 +1457,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
                .clear_optc_underflow = optc1_clear_optc_underflow,
                .get_crc = optc1_get_crc,
                .configure_crc = optc1_configure_crc,
+               .set_vtg_params = optc1_set_vtg_params,
 };
 
 void dcn10_timing_generator_init(struct optc *optc1)
index 7bb414c35d13e3335bfe445a5c486439d184f5e5..651b8caa4b9f9a9ba19c8a84ea801a3a5d25956a 100644 (file)
@@ -597,4 +597,7 @@ bool optc1_get_crc(struct timing_generator *optc,
 
 bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing);
 
+void optc1_set_vtg_params(struct timing_generator *optc,
+               const struct dc_crtc_timing *dc_crtc_timing);
+
 #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */
index e4b0de0089af36f0be18ece49b7c3b351156832c..0b8c6896581f11d7af9f3de853c264ff52ae26e6 100644 (file)
@@ -238,6 +238,8 @@ struct timing_generator_funcs {
        bool (*get_crc)(struct timing_generator *tg,
                        uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb);
 
+       void (*set_vtg_params)(struct timing_generator *optc,
+                       const struct dc_crtc_timing *dc_crtc_timing);
 };
 
 #endif