OSDN Git Service

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 bf0db87..66bb0e7 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 0afe81e..533b0f3 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 7bb414c..651b8ca 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 e4b0de0..0b8c689 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