diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch new file mode 100644 index 00000000..6a5551c8 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch @@ -0,0 +1,291 @@ +From 7f28003bfe1aa912541f2c24a80bddb86be24b05 Mon Sep 17 00:00:00 2001 +From: Joshua Aberback <joshua.aberback@amd.com> +Date: Mon, 29 Apr 2019 17:21:19 -0400 +Subject: [PATCH 1968/2940] drm/amd/display: Program VTG params after + programming Global Sync + +[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> +--- + .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 3 + + .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 115 ++++++++++-------- + .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 3 + + .../amd/display/dc/inc/hw/timing_generator.h | 2 + + 4 files changed, 73 insertions(+), 50 deletions(-) + +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 58d3fd742eab..faded9fb15b4 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 +@@ -2284,6 +2284,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); + + } +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 3bddaedcb527..13fe638c9d9c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +@@ -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); +@@ -1451,6 +1465,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) +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 7bb414c35d13..651b8caa4b9f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +@@ -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__ */ +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 e4b0de0089af..0b8c6896581f 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,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 +-- +2.17.1 + |