struct dcn_otg_state s = {0};
                int pix_clk = 0;
 
-               optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
+               if (tg->funcs->read_otg_state)
+                       tg->funcs->read_otg_state(tg, &s);
+
                pix_clk = dc->current_state->res_ctx.pipe_ctx[i].stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
 
                //only print if OTG master is enabled
                struct timing_generator *tg = pool->timing_generators[i];
                struct dcn_otg_state s = {0};
 
-               optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
+               if (tg->funcs->read_otg_state)
+                       tg->funcs->read_otg_state(tg, &s);
 
                if (s.otg_enabled & 1)
                        tg->funcs->clear_optc_underflow(tg);
 
                struct timing_generator *tg = pool->timing_generators[i];
                struct dcn_otg_state s = {0};
                /* Read shared OTG state registers for all DCNx */
-               optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
+               if (tg->funcs->read_otg_state)
+                       tg->funcs->read_otg_state(tg, &s);
 
                /*
                 * For DCN2 and greater, a register on the OPP is used to
 
        enum signal_type signal;
 };
 
-struct dcn_otg_state {
-       uint32_t v_blank_start;
-       uint32_t v_blank_end;
-       uint32_t v_sync_a_pol;
-       uint32_t v_total;
-       uint32_t v_total_max;
-       uint32_t v_total_min;
-       uint32_t v_total_min_sel;
-       uint32_t v_total_max_sel;
-       uint32_t v_sync_a_start;
-       uint32_t v_sync_a_end;
-       uint32_t h_blank_start;
-       uint32_t h_blank_end;
-       uint32_t h_sync_a_start;
-       uint32_t h_sync_a_end;
-       uint32_t h_sync_a_pol;
-       uint32_t h_total;
-       uint32_t underflow_occurred_status;
-       uint32_t otg_enabled;
-       uint32_t blank_enabled;
-       uint32_t vertical_interrupt1_en;
-       uint32_t vertical_interrupt1_line;
-       uint32_t vertical_interrupt2_en;
-       uint32_t vertical_interrupt2_line;
-       uint32_t otg_master_update_lock;
-       uint32_t otg_double_buffer_control;
-};
-
-void optc1_read_otg_state(struct optc *optc1, struct dcn_otg_state *s);
+void optc1_read_otg_state(struct timing_generator *optc, struct dcn_otg_state *s);
 
 bool optc1_get_hw_timing(struct timing_generator *tg, struct dc_crtc_timing *hw_crtc_timing);
 
 
        bool reset;
 };
 
+struct dcn_otg_state {
+       uint32_t v_blank_start;
+       uint32_t v_blank_end;
+       uint32_t v_sync_a_pol;
+       uint32_t v_total;
+       uint32_t v_total_max;
+       uint32_t v_total_min;
+       uint32_t v_total_min_sel;
+       uint32_t v_total_max_sel;
+       uint32_t v_sync_a_start;
+       uint32_t v_sync_a_end;
+       uint32_t h_blank_start;
+       uint32_t h_blank_end;
+       uint32_t h_sync_a_start;
+       uint32_t h_sync_a_end;
+       uint32_t h_sync_a_pol;
+       uint32_t h_total;
+       uint32_t underflow_occurred_status;
+       uint32_t otg_enabled;
+       uint32_t blank_enabled;
+       uint32_t vertical_interrupt1_en;
+       uint32_t vertical_interrupt1_line;
+       uint32_t vertical_interrupt2_en;
+       uint32_t vertical_interrupt2_line;
+       uint32_t vertical_interrupt2_dest;
+       uint32_t otg_master_update_lock;
+       uint32_t otg_double_buffer_control;
+};
+
 /**
  * struct timing_generator - Entry point to Output Timing Generator feature.
  */
        bool (*get_pipe_update_pending)(struct timing_generator *tg);
        void (*set_vupdate_keepout)(struct timing_generator *tg, bool enable);
        bool (*wait_update_lock_status)(struct timing_generator *tg, bool locked);
+       void (*read_otg_state)(struct timing_generator *tg, struct dcn_otg_state *s);
 };
 
 #endif
 
        if (tg == NULL || hw_crtc_timing == NULL)
                return false;
 
-       optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
+       optc1_read_otg_state(tg, &s);
 
        hw_crtc_timing->h_total = s.h_total + 1;
        hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end);
 }
 
 
-void optc1_read_otg_state(struct optc *optc1,
+void optc1_read_otg_state(struct timing_generator *optc,
                struct dcn_otg_state *s)
 {
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
        REG_GET(OTG_CONTROL,
                        OTG_MASTER_EN, &s->otg_enabled);
 
                .setup_manual_trigger = optc1_setup_manual_trigger,
                .get_hw_timing = optc1_get_hw_timing,
                .is_two_pixels_per_container = optc1_is_two_pixels_per_container,
+               .read_otg_state = optc1_read_otg_state,
 };
 
 void dcn10_timing_generator_init(struct optc *optc1)
 
        uint32_t OPTC_WIDTH_CONTROL2;
        uint32_t OTG_PSTATE_REGISTER;
        uint32_t OTG_PIPE_UPDATE_STATUS;
+       uint32_t INTERRUPT_DEST;
 };
 
 #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\
        type OTG_DC_REG_UPDATE_PENDING;\
        type OTG_CURSOR_UPDATE_PENDING;\
        type OTG_VUPDATE_KEEPOUT_STATUS;\
+       type OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST;
 
 #define TG_REG_FIELD_LIST_DCN3_2(type) \
        type OTG_H_TIMING_DIV_MODE_MANUAL;
 
                .get_hw_timing = optc1_get_hw_timing,
                .align_vblanks = optc2_align_vblanks,
                .is_two_pixels_per_container = optc1_is_two_pixels_per_container,
+               .read_otg_state = optc1_read_otg_state,
 };
 
 void dcn20_timing_generator_init(struct optc *optc1)
 
                .setup_manual_trigger = optc2_setup_manual_trigger,
                .get_hw_timing = optc1_get_hw_timing,
                .is_two_pixels_per_container = optc1_is_two_pixels_per_container,
+               .read_otg_state = optc1_read_otg_state,
 };
 
 void dcn201_timing_generator_init(struct optc *optc1)
 
                .get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
                .get_otg_double_buffer_pending = optc3_get_otg_update_pending,
                .get_pipe_update_pending = optc3_get_pipe_update_pending,
+               .read_otg_state = optc1_read_otg_state,
 };
 
 void dcn30_timing_generator_init(struct optc *optc1)
 
                .get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
                .get_otg_double_buffer_pending = optc3_get_otg_update_pending,
                .get_pipe_update_pending = optc3_get_pipe_update_pending,
+               .read_otg_state = optc1_read_otg_state,
 };
 
 void dcn301_timing_generator_init(struct optc *optc1)
 
        optc1->opp_count = 1;
 }
 
+void optc31_read_otg_state(struct timing_generator *optc,
+               struct dcn_otg_state *s)
+{
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+       REG_GET(OTG_CONTROL,
+                       OTG_MASTER_EN, &s->otg_enabled);
+
+       REG_GET_2(OTG_V_BLANK_START_END,
+                       OTG_V_BLANK_START, &s->v_blank_start,
+                       OTG_V_BLANK_END, &s->v_blank_end);
+
+       REG_GET(OTG_V_SYNC_A_CNTL,
+                       OTG_V_SYNC_A_POL, &s->v_sync_a_pol);
+
+       REG_GET(OTG_V_TOTAL,
+                       OTG_V_TOTAL, &s->v_total);
+
+       REG_GET(OTG_V_TOTAL_MAX,
+                       OTG_V_TOTAL_MAX, &s->v_total_max);
+
+       REG_GET(OTG_V_TOTAL_MIN,
+                       OTG_V_TOTAL_MIN, &s->v_total_min);
+
+       REG_GET(OTG_V_TOTAL_CONTROL,
+                       OTG_V_TOTAL_MAX_SEL, &s->v_total_max_sel);
+
+       REG_GET(OTG_V_TOTAL_CONTROL,
+                       OTG_V_TOTAL_MIN_SEL, &s->v_total_min_sel);
+
+       REG_GET_2(OTG_V_SYNC_A,
+                       OTG_V_SYNC_A_START, &s->v_sync_a_start,
+                       OTG_V_SYNC_A_END, &s->v_sync_a_end);
+
+       REG_GET_2(OTG_H_BLANK_START_END,
+                       OTG_H_BLANK_START, &s->h_blank_start,
+                       OTG_H_BLANK_END, &s->h_blank_end);
+
+       REG_GET_2(OTG_H_SYNC_A,
+                       OTG_H_SYNC_A_START, &s->h_sync_a_start,
+                       OTG_H_SYNC_A_END, &s->h_sync_a_end);
+
+       REG_GET(OTG_H_SYNC_A_CNTL,
+                       OTG_H_SYNC_A_POL, &s->h_sync_a_pol);
+
+       REG_GET(OTG_H_TOTAL,
+                       OTG_H_TOTAL, &s->h_total);
+
+       REG_GET(OPTC_INPUT_GLOBAL_CONTROL,
+                       OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status);
+
+       REG_GET(OTG_VERTICAL_INTERRUPT1_CONTROL,
+                       OTG_VERTICAL_INTERRUPT1_INT_ENABLE, &s->vertical_interrupt1_en);
+
+       REG_GET(OTG_VERTICAL_INTERRUPT1_POSITION,
+                               OTG_VERTICAL_INTERRUPT1_LINE_START, &s->vertical_interrupt1_line);
+
+       REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL,
+                       OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &s->vertical_interrupt2_en);
+
+       REG_GET(OTG_VERTICAL_INTERRUPT2_POSITION,
+                       OTG_VERTICAL_INTERRUPT2_LINE_START, &s->vertical_interrupt2_line);
+
+       REG_GET(INTERRUPT_DEST,
+                       OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, &s->vertical_interrupt2_dest);
+
+       s->otg_master_update_lock = REG_READ(OTG_MASTER_UPDATE_LOCK);
+       s->otg_double_buffer_control = REG_READ(OTG_DOUBLE_BUFFER_CONTROL);
+}
+
 static struct timing_generator_funcs dcn31_tg_funcs = {
                .validate_timing = optc1_validate_timing,
                .program_timing = optc1_program_timing,
                .get_hw_timing = optc1_get_hw_timing,
                .init_odm = optc3_init_odm,
                .is_two_pixels_per_container = optc1_is_two_pixels_per_container,
+               .read_otg_state = optc31_read_otg_state,
 };
 
 void dcn31_timing_generator_init(struct optc *optc1)
 
        SRI(OTG_CRC_CNTL2, OTG, inst),\
        SR(DWB_SOURCE_SELECT),\
        SRI(OTG_DRR_CONTROL, OTG, inst),\
-       SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst)
+       SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst),\
+       SRI(INTERRUPT_DEST, OTG, inst)
 
 #define OPTC_COMMON_MASK_SH_LIST_DCN3_1(mask_sh)\
        SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
+       SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
 
 void dcn31_timing_generator_init(struct optc *optc1);
 
 
 void optc3_init_odm(struct timing_generator *optc);
 
+void optc31_read_otg_state(struct timing_generator *optc,
+               struct dcn_otg_state *s);
+
 #endif /* __DC_OPTC_DCN31_H__ */
 
                .set_odm_combine = optc314_set_odm_combine,
                .set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode,
                .is_two_pixels_per_container = optc1_is_two_pixels_per_container,
+               .read_otg_state = optc31_read_otg_state,
 };
 
 void dcn314_timing_generator_init(struct optc *optc1)
 
        SRI(OPTC_WIDTH_CONTROL, ODM, inst),\
        SRI(OPTC_MEMORY_CONFIG, ODM, inst),\
        SRI(OTG_DRR_CONTROL, OTG, inst),\
-       SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst)
+       SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst),\
+       SRI(INTERRUPT_DEST, OTG, inst)
 
 #define OPTC_COMMON_MASK_SH_LIST_DCN3_14(mask_sh)\
        SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
+       SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
 
 void dcn314_timing_generator_init(struct optc *optc1);
 
 
                .get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
                .get_otg_double_buffer_pending = optc3_get_otg_update_pending,
                .get_pipe_update_pending = optc3_get_pipe_update_pending,
+               .read_otg_state = optc31_read_otg_state,
 };
 
 void dcn32_timing_generator_init(struct optc *optc1)
 
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
-       SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh)
+       SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
+       SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
 
 void dcn32_timing_generator_init(struct optc *optc1);
 void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode);
 
                .init_odm = optc3_init_odm,
                .set_long_vtotal = optc35_set_long_vtotal,
                .is_two_pixels_per_container = optc1_is_two_pixels_per_container,
+               .read_otg_state = optc31_read_otg_state,
 };
 
 void dcn35_timing_generator_init(struct optc *optc1)
 
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
-       SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh)
+       SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
+       SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
 
 void dcn35_timing_generator_init(struct optc *optc1);
 
 
                .get_pipe_update_pending = optc3_get_pipe_update_pending,
                .set_vupdate_keepout = optc401_set_vupdate_keepout,
                .wait_update_lock_status = optc401_wait_update_lock_status,
+               .read_otg_state = optc31_read_otg_state,
 };
 
 void dcn401_timing_generator_init(struct optc *optc1)
 
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
-       SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh)
+       SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
+       SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
 
 void dcn401_timing_generator_init(struct optc *optc1);
 
 
       SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst),                                  \
       SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst),                                  \
       SRI_ARR(OTG_DRR_CONTROL, OTG, inst),                                     \
-         SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst)
+      SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst),                              \
+      SRI_ARR(INTERRUPT_DEST, OTG, inst)
 
 /* HUBP */
 
 
        SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst),\
        SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst),\
        SRI_ARR(OTG_DRR_CONTROL, OTG, inst),\
-       SRI2_ARR(OPTC_CLOCK_CONTROL, OPTC, inst)
+       SRI2_ARR(OPTC_CLOCK_CONTROL, OPTC, inst),\
+       SRI_ARR(INTERRUPT_DEST, OTG, inst)
 
 /* DPP */
 #define DPP_REG_LIST_DCN35_RI(id)\
 
        SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst),                                  \
        SRI_ARR(OTG_DRR_CONTROL, OTG, inst),                                     \
        SRI_ARR(OTG_PSTATE_REGISTER, OTG, inst),                                 \
-       SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst)
+       SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst),                              \
+       SRI_ARR(INTERRUPT_DEST, OTG, inst)
 
 /* HUBBUB */
 #define HUBBUB_REG_LIST_DCN4_01_RI(id)                                       \