if (dc_is_dp_signal(link->connector_signal)) {
                unsigned int pix_clk_100hz;
+               uint32_t numOdmPipes = 1;
+               uint32_t id_src[4] = {0};
 
                dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
                        dc->res_pool->dp_clock_source,
                        tg_inst, &pix_clk_100hz);
 
+               if (tg->funcs->get_optc_source)
+                       tg->funcs->get_optc_source(tg,
+                                               &numOdmPipes, &id_src[0], &id_src[1]);
+
+               if (numOdmPipes == 2)
+                       pix_clk_100hz *= 2;
+               if (numOdmPipes == 4)
+                       pix_clk_100hz *= 4;
+
+               // Note: In rare cases, HW pixclk may differ from crtc's pixclk
+               // slightly due to rounding issues in 10 kHz units.
                if (crtc_timing->pix_clk_100hz != pix_clk_100hz)
                        return false;
 
 
 {
        struct dc_link *link = stream->link;
        unsigned int i, inst, tg_inst = 0;
+       uint32_t numPipes = 1;
+       uint32_t id_src[4] = {0};
 
        /* Check for enabled DIG to identify enabled display */
        if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
        if (!res_ctx->pipe_ctx[tg_inst].stream) {
                struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
 
-               pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
-               pipe_ctx->plane_res.mi = pool->mis[tg_inst];
-               pipe_ctx->plane_res.hubp = pool->hubps[tg_inst];
-               pipe_ctx->plane_res.ipp = pool->ipps[tg_inst];
-               pipe_ctx->plane_res.xfm = pool->transforms[tg_inst];
-               pipe_ctx->plane_res.dpp = pool->dpps[tg_inst];
-               pipe_ctx->stream_res.opp = pool->opps[tg_inst];
-
-               if (pool->dpps[tg_inst]) {
-                       pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst;
-
-                       // Read DPP->MPCC->OPP Pipe from HW State
-                       if (pool->mpc->funcs->read_mpcc_state) {
-                               struct mpcc_state s = {0};
-
-                               pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
-
-                               if (s.dpp_id < MAX_MPCC)
-                                       pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = s.dpp_id;
-
-                               if (s.bot_mpcc_id < MAX_MPCC)
-                                       pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
-                                                       &pool->mpc->mpcc_array[s.bot_mpcc_id];
+               id_src[0] = tg_inst;
+
+               if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
+                       pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
+                                       &numPipes, &id_src[0], &id_src[1]);
+
+               for (i = 0; i < numPipes; i++) {
+                       //Check if src id invalid
+                       if (id_src[i] == 0xf)
+                               return -1;
+
+                       pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
+                       pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
+                       pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
+                       pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
+                       pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
+                       pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
+                       pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
+
+                       if (pool->dpps[id_src[i]]) {
+                               pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst;
+
+                               if (pool->mpc->funcs->read_mpcc_state) {
+                                       struct mpcc_state s = {0};
+                                       pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
+                                       if (s.dpp_id < MAX_MPCC)
+                                               pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
+                                                               s.dpp_id;
+                                       if (s.bot_mpcc_id < MAX_MPCC)
+                                               pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
+                                                               &pool->mpc->mpcc_array[s.bot_mpcc_id];
+                                       if (s.opp_id < MAX_OPP)
+                                               pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
+                               }
+                       }
+                       pipe_ctx->pipe_idx = id_src[i];
 
-                               if (s.opp_id < MAX_OPP)
-                                       pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
+                       if (id_src[i] >= pool->timing_generator_count) {
+                               id_src[i] = pool->timing_generator_count - 1;
+                               pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
+                               pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
                        }
+
+                       pipe_ctx->stream = stream;
                }
-               pipe_ctx->pipe_idx = tg_inst;
 
-               pipe_ctx->stream = stream;
-               return tg_inst;
+               if (numPipes == 2) {
+                       stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
+                       res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
+                       res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
+                       res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
+                       res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
+               } else
+                       stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;
+
+               return id_src[0];
        }
 
        return -1;
 
 {
        int i;
        struct dce_hwseq *hws = dc->hwseq;
+       struct hubbub *hubbub = dc->res_pool->hubbub;
        bool can_apply_seamless_boot = false;
 
        for (i = 0; i < context->stream_count; i++) {
                }
        }
 
+       /* Reset det size */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+               struct hubp *hubp = dc->res_pool->hubps[i];
+
+               /* Do not need to reset for seamless boot */
+               if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
+                       continue;
+
+               if (hubbub && hubp) {
+                       if (hubbub->funcs->program_det_size)
+                               hubbub->funcs->program_det_size(hubbub, hubp->inst, 0);
+               }
+       }
+
        /* num_opp will be equal to number of mpcc */
        for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
                pipe_ctx->stream_res.tg = NULL;
                pipe_ctx->plane_res.hubp = NULL;
 
+               if (tg->funcs->is_tg_enabled(tg)) {
+                       if (tg->funcs->init_odm)
+                               tg->funcs->init_odm(tg);
+               }
+
                tg->funcs->tg_init(tg);
        }
 
 
        }
 }
 
+void optc3_init_odm(struct timing_generator *optc)
+{
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+       REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0,
+                       OPTC_NUM_OF_INPUT_SEGMENT, 0,
+                       OPTC_SEG0_SRC_SEL, optc->inst,
+                       OPTC_SEG1_SRC_SEL, 0xf,
+                       OPTC_SEG2_SRC_SEL, 0xf,
+                       OPTC_SEG3_SRC_SEL, 0xf
+                       );
+
+       REG_SET(OTG_H_TIMING_CNTL, 0,
+                       OTG_H_TIMING_DIV_MODE, 0);
+
+       REG_SET(OPTC_MEMORY_CONFIG, 0,
+                       OPTC_MEM_SEL, 0);
+       optc1->opp_count = 1;
+}
+
 static struct timing_generator_funcs dcn31_tg_funcs = {
                .validate_timing = optc1_validate_timing,
                .program_timing = optc1_program_timing,
                .program_manual_trigger = optc2_program_manual_trigger,
                .setup_manual_trigger = optc2_setup_manual_trigger,
                .get_hw_timing = optc1_get_hw_timing,
+               .init_odm = optc3_init_odm,
 };
 
 void dcn31_timing_generator_init(struct optc *optc1)