aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch291
1 files changed, 291 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1968-drm-amd-display-Program-VTG-params-after-programming.patch b/meta-amd-bsp/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/meta-amd-bsp/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
+