From: Dillon Varone <[email protected]>

[WHY&HOW]
VTG params should be corrected based on HW expectation:
- FP2 = v_bp - vstartup_start (if vstartup is after vsync), else 0
- vcount_init = OTG SOF position from vsync (0) or vtotal
  depending on vstartup position

Signed-off-by: Dillon Varone <[email protected]>
Signed-off-by: Fangzhi Zuo <[email protected]>
Reviewed-by: Alvin Lee <[email protected]>
---
 .../amd/display/dc/optc/dcn60/dcn60_optc.c    | 83 ++++++++++++++++++-
 1 file changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn60/dcn60_optc.c 
b/drivers/gpu/drm/amd/display/dc/optc/dcn60/dcn60_optc.c
index bfeb3c8fc8f5..1257a540bc59 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn60/dcn60_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn60/dcn60_optc.c
@@ -23,6 +23,87 @@
 #define FN(reg_name, field_name) \
        optc1->tg_shift->field_name, optc1->tg_mask->field_name
 
+/*
+ * apply_front_porch_workaround
+ *
+ * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for 
progressive.
+ */
+static void apply_front_porch_workaround(
+       struct dc_crtc_timing *timing)
+{
+       if (timing->flags.INTERLACE == 1) {
+               if (timing->v_front_porch < 2)
+                       timing->v_front_porch = 2;
+       } else {
+               if (timing->v_front_porch < 1)
+                       timing->v_front_porch = 1;
+       }
+}
+
+/**
+ * optc60_set_vtg_params - Set Vertical Timing Generator (VTG) parameters
+ *
+ * @optc: timing_generator struct used to extract the optc parameters
+ * @dc_crtc_timing: Timing parameters configured
+ * @program_fp2: Boolean value indicating if FP2 will be programmed or not
+ *
+ * OTG is responsible for generating the global sync signals, including
+ * vertical timing information for each HUBP in the dcfclk domain. Each VTG is
+ * associated with one OTG that provides HUBP with vertical timing information
+ * (i.e., there is 1:1 correspondence between OTG and VTG). This function is
+ * responsible for setting the OTG parameters to the VTG during the pipe
+ * programming.
+ */
+static void optc60_set_vtg_params(struct timing_generator *optc,
+               const struct dc_crtc_timing *dc_crtc_timing, bool program_fp2)
+{
+       struct dc_crtc_timing patched_crtc_timing;
+       uint32_t v_bp;
+       uint32_t v_init;
+       uint32_t v_fp2;
+       bool vstartup_after_vsync;
+
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+       patched_crtc_timing = *dc_crtc_timing;
+       apply_front_porch_workaround(&patched_crtc_timing);
+
+       /* v_bp (end of blank): lines from vsync (0) to end of blank */
+       v_bp = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch -
+                       patched_crtc_timing.v_border_bottom -
+                       patched_crtc_timing.v_addressable -
+                       patched_crtc_timing.v_border_top;
+
+       vstartup_after_vsync = (uint32_t)optc1->vstartup_start < v_bp;
+
+       /* if vstartup is before vsync, fp2 is the offset, otherwise 0 */
+       v_fp2 = !vstartup_after_vsync ?
+                       optc1->vstartup_start - v_bp :
+                       0;
+
+       /* vcount_init should be OTG SOF (vstartup) position from vsync (0) or
+        * vtotal depending on the position of vstartup.
+        */
+       v_init = !vstartup_after_vsync ?
+                       patched_crtc_timing.v_total - v_fp2 - 1 : // OTG SOF 
before VSYNC
+                       patched_crtc_timing.v_total - 1; // OTG SOF is VSYNC
+
+       /* Interlace */
+       if (REG(OTG_INTERLACE_CONTROL)) {
+               if (patched_crtc_timing.flags.INTERLACE == 1) {
+                       v_init = v_init / 2;
+                       if ((uint32_t)((optc1->vstartup_start/2)*2) > v_bp)
+                               v_fp2 = v_fp2 / 2;
+               }
+       }
+
+       if (program_fp2)
+               REG_UPDATE_2(CONTROL,
+                               VTG0_FP2, v_fp2,
+                               VTG0_VCOUNT_INIT, v_init);
+       else
+               REG_UPDATE(CONTROL, VTG0_VCOUNT_INIT, v_init);
+}
 static const struct timing_generator_funcs dcn60_tg_funcs = {
                .validate_timing = optc1_validate_timing,
                .program_timing = optc1_program_timing,
@@ -78,7 +159,7 @@ static const struct timing_generator_funcs dcn60_tg_funcs = {
                .set_vtotal_change_limit = optc3_set_vtotal_change_limit,
                .set_gsl = optc2_set_gsl,
                .set_gsl_source_select = NULL,
-               .set_vtg_params = optc1_set_vtg_params,
+               .set_vtg_params = optc60_set_vtg_params,
                .program_manual_trigger = optc2_program_manual_trigger,
                .setup_manual_trigger = optc2_setup_manual_trigger,
                .get_hw_timing = optc1_get_hw_timing,
-- 
2.53.0

Reply via email to