static u32 crtc_flush_all(struct drm_crtc *crtc)
 {
        struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-       struct mdp5_hw_mixer *mixer;
+       struct mdp5_hw_mixer *mixer, *r_mixer;
        struct drm_plane *plane;
        uint32_t flush_mask = 0;
 
        mixer = mdp5_cstate->pipeline.mixer;
        flush_mask |= mdp_ctl_flush_mask_lm(mixer->lm);
 
+       r_mixer = mdp5_cstate->pipeline.r_mixer;
+       if (r_mixer)
+               flush_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
+
        return crtc_flush(crtc, flush_mask);
 }
 
 
        if (ctl && !crtc->state->enable) {
                /* set STAGE_UNUSED for all layers */
-               mdp5_ctl_blend(ctl, pipeline, NULL, 0, 0);
+               mdp5_ctl_blend(ctl, pipeline, NULL, NULL, 0, 0);
                /* XXX: What to do here? */
                /* mdp5_crtc->ctl = NULL; */
        }
        }
 }
 
+/*
+ * left/right pipe offsets for the stage array used in blend_setup()
+ */
+#define PIPE_LEFT      0
+#define PIPE_RIGHT     1
+
 /*
  * blend_setup() - blend all the planes of a CRTC
  *
        const struct mdp_format *format;
        struct mdp5_hw_mixer *mixer = pipeline->mixer;
        uint32_t lm = mixer->lm;
+       struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
+       uint32_t r_lm = r_mixer ? r_mixer->lm : 0;
        struct mdp5_ctl *ctl = mdp5_cstate->ctl;
        uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
        unsigned long flags;
-       enum mdp5_pipe stage[STAGE_MAX + 1] = { SSPP_NONE };
+       enum mdp5_pipe stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { SSPP_NONE };
+       enum mdp5_pipe r_stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { SSPP_NONE };
        int i, plane_cnt = 0;
        bool bg_alpha_enabled = false;
        u32 mixer_op_mode = 0;
        drm_atomic_crtc_for_each_plane(plane, crtc) {
                pstate = to_mdp5_plane_state(plane->state);
                pstates[pstate->stage] = pstate;
-               stage[pstate->stage] = mdp5_plane_pipe(plane);
+               stage[pstate->stage][PIPE_LEFT] = mdp5_plane_pipe(plane);
+               /*
+                * if we have a right mixer, stage the same pipe as we
+                * have on the left mixer
+                */
+               if (r_mixer)
+                       r_stage[pstate->stage][PIPE_LEFT] =
+                                               mdp5_plane_pipe(plane);
+
                plane_cnt++;
        }
 
                                blender(i)), fg_alpha);
                mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
                                blender(i)), bg_alpha);
+               if (r_mixer) {
+                       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(r_lm,
+                                       blender(i)), blend_op);
+                       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(r_lm,
+                                       blender(i)), fg_alpha);
+                       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(r_lm,
+                                       blender(i)), bg_alpha);
+               }
        }
 
        mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm), mixer_op_mode);
+       if (r_mixer)
+               mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm),
+                          mixer_op_mode);
 
-       mdp5_ctl_blend(ctl, pipeline, stage, plane_cnt, ctl_blend_flags);
-
+       mdp5_ctl_blend(ctl, pipeline, stage, r_stage, plane_cnt,
+                      ctl_blend_flags);
 out:
        spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
 }
        struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
        struct mdp5_hw_mixer *mixer = mdp5_cstate->pipeline.mixer;
+       struct mdp5_hw_mixer *r_mixer = mdp5_cstate->pipeline.r_mixer;
        uint32_t lm = mixer->lm;
        unsigned long flags;
        struct drm_display_mode *mode;
        mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(lm),
                        MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
                        MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
+       if (r_mixer)
+               mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(r_mixer->lm),
+                          MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
+                          MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
        spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
 }
 
        if (!ctl)
                return -EINVAL;
 
+       /* don't support LM cursors when we we have source split enabled */
+       if (mdp5_cstate->pipeline.r_mixer)
+               return -EINVAL;
+
        if (!handle) {
                DBG("Cursor off");
                cursor_enable = false;
        uint32_t roi_h;
        unsigned long flags;
 
+       /* don't support LM cursors when we we have source split enabled */
+       if (mdp5_cstate->pipeline.r_mixer)
+               return -EINVAL;
+
        /* In case the CRTC is disabled, just drop the cursor update */
        if (unlikely(!crtc->state->enable))
                return 0;
 {
        struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(state);
        struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+       struct mdp5_kms *mdp5_kms = get_kms(state->crtc);
 
        if (WARN_ON(!pipeline))
                return;
 
        drm_printf(p, "\thwmixer=%s\n", pipeline->mixer ?
                        pipeline->mixer->name : "(null)");
+
+       if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
+               drm_printf(p, "\tright hwmixer=%s\n", pipeline->r_mixer ?
+                          pipeline->r_mixer->name : "(null)");
 }
 
 static void mdp5_crtc_reset(struct drm_crtc *crtc)
 
        struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
        struct mdp5_interface *intf = pipeline->intf;
        struct mdp5_hw_mixer *mixer = pipeline->mixer;
+       struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
 
        ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm) |
                          mdp_ctl_flush_mask_encoder(intf);
+       if (r_mixer)
+               ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
 
        /* Virtual interfaces need not set a display intf (e.g.: Writeback) */
        if (!mdp5_cfg_intf_is_virtual(intf->type))
 {
        struct mdp5_interface *intf = pipeline->intf;
        struct mdp5_hw_mixer *mixer = pipeline->mixer;
+       struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
 
        ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm);
+       if (r_mixer)
+               ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
 
        /*
         * Writeback encoder needs to program & flush
                return -EINVAL;
        }
 
+       if (pipeline->r_mixer) {
+               dev_err(ctl_mgr->dev->dev, "unsupported configuration");
+               return -EINVAL;
+       }
+
        spin_lock_irqsave(&ctl->hw_lock, flags);
 
        blend_cfg = ctl_read(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm));
        }
 }
 
+#define PIPE_LEFT      0
+#define PIPE_RIGHT     1
 int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
-                  enum mdp5_pipe *stage, u32 stage_cnt, u32 ctl_blend_op_flags)
+                  enum mdp5_pipe stage[][MAX_PIPE_STAGE],
+                  enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
+                  u32 stage_cnt, u32 ctl_blend_op_flags)
 {
        struct mdp5_hw_mixer *mixer = pipeline->mixer;
+       struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
        unsigned long flags;
        u32 blend_cfg = 0, blend_ext_cfg = 0;
+       u32 r_blend_cfg = 0, r_blend_ext_cfg = 0;
        int i, start_stage;
 
        if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
                start_stage = STAGE0;
                blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
+               if (r_mixer)
+                       r_blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
        } else {
                start_stage = STAGE_BASE;
        }
 
        for (i = start_stage; stage_cnt && i <= STAGE_MAX; i++) {
-               blend_cfg |= mdp_ctl_blend_mask(stage[i], i);
-               blend_ext_cfg |= mdp_ctl_blend_ext_mask(stage[i], i);
+               blend_cfg |=
+                       mdp_ctl_blend_mask(stage[i][PIPE_LEFT], i);
+               blend_ext_cfg |=
+                       mdp_ctl_blend_ext_mask(stage[i][PIPE_LEFT], i);
+               if (r_mixer) {
+                       r_blend_cfg |=
+                               mdp_ctl_blend_mask(r_stage[i][PIPE_LEFT], i);
+                       r_blend_ext_cfg |=
+                               mdp_ctl_blend_ext_mask(r_stage[i][PIPE_LEFT], i);
+               }
        }
 
        spin_lock_irqsave(&ctl->hw_lock, flags);
        ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
        ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, mixer->lm),
                  blend_ext_cfg);
+       if (r_mixer) {
+               ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, r_mixer->lm),
+                         r_blend_cfg);
+               ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, r_mixer->lm),
+                         r_blend_ext_cfg);
+       }
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
 
        ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(mixer->lm);
+       if (r_mixer)
+               ctl->pending_ctl_trigger |= mdp_ctl_flush_mask_lm(r_mixer->lm);
 
        DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", mixer->lm,
                blend_cfg, blend_ext_cfg);
+       if (r_mixer)
+               DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x",
+                   r_mixer->lm, r_blend_cfg, r_blend_ext_cfg);
 
        return 0;
 }