}
 }
 
+/**
+ * wait_for_blank_complete - wait for all active OPPs to finish pending blank
+ * pattern updates
+ *
+ * @dc: [in] dc reference
+ * @context: [in] hardware context in use
+ */
+static void wait_for_blank_complete(struct dc *dc,
+               struct dc_state *context)
+{
+       struct pipe_ctx *opp_head;
+       struct dce_hwseq *hws = dc->hwseq;
+       int i;
+
+       if (!hws->funcs.wait_for_blank_complete)
+               return;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               opp_head = &context->res_ctx.pipe_ctx[i];
+
+               if (!resource_is_pipe_type(opp_head, OPP_HEAD) ||
+                               dc_state_get_pipe_subvp_type(context, opp_head) == SUBVP_PHANTOM)
+                       continue;
+
+               hws->funcs.wait_for_blank_complete(opp_head->stream_res.opp);
+       }
+}
+
+static void wait_for_odm_update_pending_complete(struct dc *dc, struct dc_state *context)
+{
+       struct pipe_ctx *otg_master;
+       struct timing_generator *tg;
+       int i;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               otg_master = &context->res_ctx.pipe_ctx[i];
+               if (!resource_is_pipe_type(otg_master, OTG_MASTER) ||
+                               dc_state_get_pipe_subvp_type(context, otg_master) == SUBVP_PHANTOM)
+                       continue;
+               tg = otg_master->stream_res.tg;
+               if (tg->funcs->wait_odm_doublebuffer_pending_clear)
+                       tg->funcs->wait_odm_doublebuffer_pending_clear(tg);
+       }
+
+       /* ODM update may require to reprogram blank pattern for each OPP */
+       wait_for_blank_complete(dc, context);
+}
+
 static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context)
 {
        int i;
                context->stream_count == 0) {
                /* Must wait for no flips to be pending before doing optimize bw */
                wait_for_no_pipes_pending(dc, context);
+               /*
+                * optimized dispclk depends on ODM setup. Need to wait for ODM
+                * update pending complete before optimizing bandwidth.
+                */
+               wait_for_odm_update_pending_complete(dc, context);
                /* pplib is notified if disp_num changed */
                dc->hwss.optimize_bandwidth(dc, context);
                /* Need to do otg sync again as otg could be out of sync due to otg
                top_pipe_to_program->stream->update_flags.raw = 0;
 }
 
-static void wait_for_outstanding_hw_updates(struct dc *dc, const struct dc_state *dc_context)
+static void wait_for_outstanding_hw_updates(struct dc *dc, struct dc_state *dc_context)
 {
 /*
  * This function calls HWSS to wait for any potentially double buffered
                        }
                }
        }
+       wait_for_odm_update_pending_complete(dc, dc_context);
 }
 
 static void commit_planes_for_stream(struct dc *dc,
 
                .opp_set_disp_pattern_generator = NULL,
                .opp_program_dpg_dimensions = NULL,
                .dpg_is_blanked = NULL,
+               .dpg_is_pending = NULL,
                .opp_destroy = opp1_destroy
 };
 
 
                (double_buffer_pending == 0);
 }
 
+bool opp2_dpg_is_pending(struct output_pixel_processor *opp)
+{
+       struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp);
+       uint32_t double_buffer_pending;
+       uint32_t dpg_en;
+
+       REG_GET(DPG_CONTROL, DPG_EN, &dpg_en);
+
+       REG_GET(DPG_STATUS, DPG_DOUBLE_BUFFER_PENDING, &double_buffer_pending);
+
+       return (dpg_en == 1 && double_buffer_pending == 1);
+}
+
 void opp2_program_left_edge_extra_pixel (
                struct output_pixel_processor *opp,
                bool count)
                .opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator,
                .opp_program_dpg_dimensions = opp2_program_dpg_dimensions,
                .dpg_is_blanked = opp2_dpg_is_blanked,
+               .dpg_is_pending = opp2_dpg_is_pending,
                .opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
                .opp_destroy = opp1_destroy,
                .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
 
 
 bool opp2_dpg_is_blanked(struct output_pixel_processor *opp);
 
+bool opp2_dpg_is_pending(struct output_pixel_processor *opp);
+
 void opp2_dpg_set_blank_color(
                struct output_pixel_processor *opp,
                const struct tg_color *color);
 
                .opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator,
                .opp_program_dpg_dimensions = opp2_program_dpg_dimensions,
                .dpg_is_blanked = opp2_dpg_is_blanked,
+               .dpg_is_pending = opp2_dpg_is_pending,
                .opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
                .opp_destroy = opp1_destroy,
                .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
 
        int counter;
 
        for (counter = 0; counter < 1000; counter++) {
-               if (opp->funcs->dpg_is_blanked(opp))
+               if (!opp->funcs->dpg_is_pending(opp))
                        break;
 
                udelay(100);
                return false;
        }
 
-       return true;
+       return opp->funcs->dpg_is_blanked(opp);
 }
 
 bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)
 
        bool (*dpg_is_blanked)(
                        struct output_pixel_processor *opp);
 
+       bool (*dpg_is_pending)(struct output_pixel_processor *opp);
+
+
        void (*opp_dpg_set_blank_color)(
                        struct output_pixel_processor *opp,
                        const struct tg_color *color);
 
 
        void (*init_odm)(struct timing_generator *tg);
        void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg);
+       void (*wait_odm_doublebuffer_pending_clear)(struct timing_generator *tg);
 };
 
 #endif
 
        type OTG_CRC_DATA_STREAM_SPLIT_MODE;\
        type OTG_CRC_DATA_FORMAT;\
        type OTG_V_TOTAL_LAST_USED_BY_DRR;\
-       type OTG_DRR_TIMING_DBUF_UPDATE_PENDING;
+       type OTG_DRR_TIMING_DBUF_UPDATE_PENDING;\
+       type OTG_H_TIMING_DIV_MODE_DB_UPDATE_PENDING;
 
 #define TG_REG_FIELD_LIST_DCN3_2(type) \
        type OTG_H_TIMING_DIV_MODE_MANUAL;
 
        }
 }
 
+void optc32_wait_odm_doublebuffer_pending_clear(struct timing_generator *tg)
+{
+       struct optc *optc1 = DCN10TG_FROM_TG(tg);
+
+       REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL, OTG_H_TIMING_DIV_MODE_DB_UPDATE_PENDING, 0, 2, 50000);
+}
+
 void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
                .set_odm_bypass = optc32_set_odm_bypass,
                .set_odm_combine = optc32_set_odm_combine,
                .get_odm_combine_segments = optc32_get_odm_combine_segments,
+               .wait_odm_doublebuffer_pending_clear = optc32_wait_odm_doublebuffer_pending_clear,
                .set_h_timing_div_manual_mode = optc32_set_h_timing_div_manual_mode,
                .get_optc_source = optc2_get_optc_source,
                .set_out_mux = optc3_set_out_mux,
 
 void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combine_segments);
 void optc32_set_odm_bypass(struct timing_generator *optc,
                const struct dc_crtc_timing *dc_crtc_timing);
+void optc32_wait_odm_doublebuffer_pending_clear(struct timing_generator *tg);
 
 #endif /* __DC_OPTC_DCN32_H__ */