stream_update->adjust->v_total_min,
                                        stream_update->adjust->v_total_max);
 
-                       if (stream_update->periodic_vsync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt)
-                               pipe_ctx->stream_res.tg->funcs->program_vline_interrupt(
-                                       pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE0, &stream->periodic_vsync_config);
+                       if (stream_update->periodic_interrupt0 &&
+                                       dc->hwss.setup_periodic_interrupt)
+                               dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE0);
 
-                       if (stream_update->enhanced_sync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt)
-                               pipe_ctx->stream_res.tg->funcs->program_vline_interrupt(
-                                       pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE1, &stream->enhanced_sync_config);
+                       if (stream_update->periodic_interrupt1 &&
+                                       dc->hwss.setup_periodic_interrupt)
+                               dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE1);
 
                        if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) ||
                                        stream_update->vrr_infopacket ||
 
        bool dummy;
 };
 
-union vline_config {
-       unsigned int line_number;
-       unsigned long long delta_in_ns;
+enum vertical_interrupt_ref_point {
+       START_V_UPDATE = 0,
+       START_V_SYNC,
+       INVALID_POINT
+
+       //For now, only v_update interrupt is used.
+       //START_V_BLANK,
+       //START_V_ACTIVE
+};
+
+struct periodic_interrupt_config {
+       enum vertical_interrupt_ref_point ref_point;
+       int lines_offset;
 };
 
 
        /* DMCU info */
        unsigned int abm_level;
 
-       union vline_config periodic_vsync_config;
-       union vline_config enhanced_sync_config;
+       struct periodic_interrupt_config periodic_interrupt0;
+       struct periodic_interrupt_config periodic_interrupt1;
 
        /* from core_stream struct */
        struct dc_context *ctx;
        struct dc_info_packet *hdr_static_metadata;
        unsigned int *abm_level;
 
-       union vline_config *periodic_vsync_config;
-       union vline_config *enhanced_sync_config;
+       struct periodic_interrupt_config *periodic_interrupt0;
+       struct periodic_interrupt_config *periodic_interrupt1;
 
        struct dc_crtc_timing_adjust *adjust;
        struct dc_info_packet *vrr_infopacket;
 
        if (!pipe_ctx->stream->apply_seamless_boot_optimization)
                dc->hwss.enable_stream_timing(pipe_ctx, context, dc);
 
-       if (pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt)
-               pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt(
-                                               pipe_ctx->stream_res.tg,
-                                                       &stream->timing);
+       if (dc->hwss.setup_vupdate_interrupt)
+               dc->hwss.setup_vupdate_interrupt(pipe_ctx);
 
        params.vertical_total_min = stream->adjust.v_total_min;
        params.vertical_total_max = stream->adjust.v_total_max;
 
                        pipe_ctx->plane_res.dpp, &opt_attr);
 }
 
+/**
+* apply_front_porch_workaround  TODO FPGA still need?
+*
+* 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 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;
+       }
+}
+
+int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx)
+{
+       struct timing_generator *optc = pipe_ctx->stream_res.tg;
+       const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing;
+       struct dc_crtc_timing patched_crtc_timing;
+       int vesa_sync_start;
+       int asic_blank_end;
+       int interlace_factor;
+       int vertical_line_start;
+
+       patched_crtc_timing = *dc_crtc_timing;
+       apply_front_porch_workaround(&patched_crtc_timing);
+
+       interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1;
+
+       vesa_sync_start = patched_crtc_timing.v_addressable +
+                       patched_crtc_timing.v_border_bottom +
+                       patched_crtc_timing.v_front_porch;
+
+       asic_blank_end = (patched_crtc_timing.v_total -
+                       vesa_sync_start -
+                       patched_crtc_timing.v_border_top)
+                       * interlace_factor;
+
+       vertical_line_start = asic_blank_end -
+                       optc->dlg_otg_param.vstartup_start + 1;
+
+       return vertical_line_start;
+}
+
+static void calc_vupdate_position(
+               struct pipe_ctx *pipe_ctx,
+               uint32_t *start_line,
+               uint32_t *end_line)
+{
+       const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing;
+       int vline_int_offset_from_vupdate =
+                       pipe_ctx->stream->periodic_interrupt0.lines_offset;
+       int vupdate_offset_from_vsync = get_vupdate_offset_from_vsync(pipe_ctx);
+       int start_position;
+
+       if (vline_int_offset_from_vupdate > 0)
+               vline_int_offset_from_vupdate--;
+       else if (vline_int_offset_from_vupdate < 0)
+               vline_int_offset_from_vupdate++;
+
+       start_position = vline_int_offset_from_vupdate + vupdate_offset_from_vsync;
+
+       if (start_position >= 0)
+               *start_line = start_position;
+       else
+               *start_line = dc_crtc_timing->v_total + start_position - 1;
+
+       *end_line = *start_line + 2;
+
+       if (*end_line >= dc_crtc_timing->v_total)
+               *end_line = 2;
+}
+
+static void cal_vline_position(
+               struct pipe_ctx *pipe_ctx,
+               enum vline_select vline,
+               uint32_t *start_line,
+               uint32_t *end_line)
+{
+       enum vertical_interrupt_ref_point ref_point = INVALID_POINT;
+
+       if (vline == VLINE0)
+               ref_point = pipe_ctx->stream->periodic_interrupt0.ref_point;
+       else if (vline == VLINE1)
+               ref_point = pipe_ctx->stream->periodic_interrupt1.ref_point;
+
+       switch (ref_point) {
+       case START_V_UPDATE:
+               calc_vupdate_position(
+                               pipe_ctx,
+                               start_line,
+                               end_line);
+               break;
+       case START_V_SYNC:
+               // Suppose to do nothing because vsync is 0;
+               break;
+       default:
+               ASSERT(0);
+               break;
+       }
+}
+
+static void dcn10_setup_periodic_interrupt(
+               struct pipe_ctx *pipe_ctx,
+               enum vline_select vline)
+{
+       struct timing_generator *tg = pipe_ctx->stream_res.tg;
+
+       if (vline == VLINE0) {
+               uint32_t start_line = 0;
+               uint32_t end_line = 0;
+
+               cal_vline_position(pipe_ctx, vline, &start_line, &end_line);
+
+               tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line);
+
+       } else if (vline == VLINE1) {
+               pipe_ctx->stream_res.tg->funcs->setup_vertical_interrupt1(
+                               tg,
+                               pipe_ctx->stream->periodic_interrupt1.lines_offset);
+       }
+}
+
+static void dcn10_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx)
+{
+       struct timing_generator *tg = pipe_ctx->stream_res.tg;
+       int start_line = get_vupdate_offset_from_vsync(pipe_ctx);
+
+       if (start_line < 0) {
+               ASSERT(0);
+               start_line = 0;
+       }
+
+       if (tg->funcs->setup_vertical_interrupt2)
+               tg->funcs->setup_vertical_interrupt2(tg, start_line);
+}
+
 static const struct hw_sequencer_funcs dcn10_funcs = {
        .program_gamut_remap = program_gamut_remap,
        .init_hw = dcn10_init_hw,
        .set_cursor_attribute = dcn10_set_cursor_attribute,
        .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
        .disable_stream_gating = NULL,
-       .enable_stream_gating = NULL
+       .enable_stream_gating = NULL,
+       .setup_periodic_interrupt = dcn10_setup_periodic_interrupt,
+       .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt
 };
 
 
 
                struct dc_state *context,
                const struct dc_stream_state *stream);
 
+int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx);
+
 #endif /* __DC_HWSS_DCN10_H__ */
 
                OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
 }
 
-static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing)
-{
-       struct dc_crtc_timing patched_crtc_timing;
-       int vesa_sync_start;
-       int asic_blank_end;
-       int interlace_factor;
-       int vertical_line_start;
-
-       patched_crtc_timing = *dc_crtc_timing;
-       optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
-
-       vesa_sync_start = patched_crtc_timing.h_addressable +
-                       patched_crtc_timing.h_border_right +
-                       patched_crtc_timing.h_front_porch;
-
-       asic_blank_end = patched_crtc_timing.h_total -
-                       vesa_sync_start -
-                       patched_crtc_timing.h_border_left;
-
-       interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1;
-
-       vesa_sync_start = patched_crtc_timing.v_addressable +
-                       patched_crtc_timing.v_border_bottom +
-                       patched_crtc_timing.v_front_porch;
-
-       asic_blank_end = (patched_crtc_timing.v_total -
-                       vesa_sync_start -
-                       patched_crtc_timing.v_border_top)
-                       * interlace_factor;
-
-       vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
-       if (vertical_line_start < 0) {
-               ASSERT(0);
-               vertical_line_start = 0;
-       }
-
-       return vertical_line_start;
-}
-
-static void calc_vline_position(
+void optc1_setup_vertical_interrupt0(
                struct timing_generator *optc,
-               const struct dc_crtc_timing *dc_crtc_timing,
-               unsigned long long vsync_delta,
-               uint32_t *start_line,
-               uint32_t *end_line)
+               uint32_t start_line,
+               uint32_t end_line)
 {
-       unsigned long long req_delta_tens_of_usec = div64_u64((vsync_delta + 9999), 10000);
-       unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_100hz + 999), 1000);
-       uint32_t req_delta_lines = (uint32_t) div64_u64(
-                       (req_delta_tens_of_usec * pix_clk_hundreds_khz + dc_crtc_timing->h_total - 1),
-                                                               dc_crtc_timing->h_total);
-
-       uint32_t vsync_line = get_start_vline(optc, dc_crtc_timing);
-
-       if (req_delta_lines != 0)
-                       req_delta_lines--;
-
-               if (req_delta_lines > vsync_line)
-                       *start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) - 1;
-               else
-                       *start_line = vsync_line - req_delta_lines;
-
-               *end_line = *start_line + 2;
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
 
-               if (*end_line >= dc_crtc_timing->v_total)
-                       *end_line = 2;
+       REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0,
+                       OTG_VERTICAL_INTERRUPT0_LINE_START, start_line,
+                       OTG_VERTICAL_INTERRUPT0_LINE_END, end_line);
 }
 
-void optc1_program_vline_interrupt(
+void optc1_setup_vertical_interrupt1(
                struct timing_generator *optc,
-               const struct dc_crtc_timing *dc_crtc_timing,
-               enum vline_select vline,
-               const union vline_config *vline_config)
+               uint32_t start_line)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
-       uint32_t start_line = 0;
-       uint32_t end_line = 0;
-
-       switch (vline) {
-       case VLINE0:
-               calc_vline_position(optc, dc_crtc_timing, vline_config->delta_in_ns, &start_line, &end_line);
-               REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0,
-                               OTG_VERTICAL_INTERRUPT0_LINE_START, start_line,
-                               OTG_VERTICAL_INTERRUPT0_LINE_END, end_line);
-               break;
-       case VLINE1:
-               REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0,
-                                       OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->line_number);
-               break;
-       default:
-               break;
-       }
+
+       REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0,
+                               OTG_VERTICAL_INTERRUPT1_LINE_START, start_line);
 }
 
-void optc1_program_vupdate_interrupt(
+void optc1_setup_vertical_interrupt2(
                struct timing_generator *optc,
-               const struct dc_crtc_timing *dc_crtc_timing)
+               uint32_t start_line)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
-       int32_t vertical_line_start;
-       uint32_t asic_blank_end;
-       uint32_t vesa_sync_start;
-       struct dc_crtc_timing patched_crtc_timing;
-
-       patched_crtc_timing = *dc_crtc_timing;
-       optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
-
-       /* 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 +
-                       patched_crtc_timing.h_front_porch;
-
-       asic_blank_end = patched_crtc_timing.h_total -
-                       vesa_sync_start -
-                       patched_crtc_timing.h_border_left;
-
-       /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt,
-        * program the reg for interrupt postition.
-        */
-       vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
-       if (vertical_line_start < 0)
-               vertical_line_start = 0;
 
        REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
-                       OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start);
+                       OTG_VERTICAL_INTERRUPT2_LINE_START, start_line);
 }
 
 /**
 static const struct timing_generator_funcs dcn10_tg_funcs = {
                .validate_timing = optc1_validate_timing,
                .program_timing = optc1_program_timing,
-               .program_vline_interrupt = optc1_program_vline_interrupt,
-               .program_vupdate_interrupt = optc1_program_vupdate_interrupt,
+               .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
+               .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1,
+               .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2,
                .program_global_sync = optc1_program_global_sync,
                .enable_crtc = optc1_enable_crtc,
                .disable_crtc = optc1_disable_crtc,
 
        const struct dc_crtc_timing *dc_crtc_timing,
        bool use_vbios);
 
-void optc1_program_vline_interrupt(
+void optc1_setup_vertical_interrupt0(
                struct timing_generator *optc,
-               const struct dc_crtc_timing *dc_crtc_timing,
-               enum vline_select vline,
-               const union vline_config *vline_config);
+               uint32_t start_line,
+               uint32_t end_line);
+void optc1_setup_vertical_interrupt1(
+               struct timing_generator *optc,
+               uint32_t start_line);
+void optc1_setup_vertical_interrupt2(
+               struct timing_generator *optc,
+               uint32_t start_line);
 
 void optc1_program_global_sync(
                struct timing_generator *optc);
 
 
 struct drr_params;
 
-union vline_config;
-
-
-enum vline_select {
-       VLINE0,
-       VLINE1,
-       VLINE2
-};
 
 struct timing_generator_funcs {
        bool (*validate_timing)(struct timing_generator *tg,
        void (*program_timing)(struct timing_generator *tg,
                                                        const struct dc_crtc_timing *timing,
                                                        bool use_vbios);
-       void (*program_vline_interrupt)(
+       void (*setup_vertical_interrupt0)(
+                       struct timing_generator *optc,
+                       uint32_t start_line,
+                       uint32_t end_line);
+       void (*setup_vertical_interrupt1)(
+                       struct timing_generator *optc,
+                       uint32_t start_line);
+       void (*setup_vertical_interrupt2)(
                        struct timing_generator *optc,
-                       const struct dc_crtc_timing *dc_crtc_timing,
-                       enum vline_select vline,
-                       const union vline_config *vline_config);
+                       uint32_t start_line);
 
-       void (*program_vupdate_interrupt)(struct timing_generator *optc,
-                       const struct dc_crtc_timing *dc_crtc_timing);
        bool (*enable_crtc)(struct timing_generator *tg);
        bool (*disable_crtc)(struct timing_generator *tg);
        bool (*is_counter_moving)(struct timing_generator *tg);
 
        PIPE_GATING_CONTROL_INIT
 };
 
+enum vline_select {
+       VLINE0,
+       VLINE1
+};
+
 struct dce_hwseq_wa {
        bool blnd_crtc_trigger;
        bool DEGVIDCN10_253;
        void (*set_cursor_attribute)(struct pipe_ctx *pipe);
        void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe);
 
+       void (*setup_periodic_interrupt)(struct pipe_ctx *pipe_ctx, enum vline_select vline);
+       void (*setup_vupdate_interrupt)(struct pipe_ctx *pipe_ctx);
+
 };
 
 void color_space_to_black_color(