unsigned int completion)
 {
        struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
+       bool complete = completion == VSP1_DL_FRAME_END_COMPLETED;
 
        if (drm_pipe->du_complete)
-               drm_pipe->du_complete(drm_pipe->du_private,
-                                     completion & VSP1_DL_FRAME_END_COMPLETED);
+               drm_pipe->du_complete(drm_pipe->du_private, complete);
+
+       if (completion & VSP1_DL_FRAME_END_INTERNAL) {
+               drm_pipe->force_bru_release = false;
+               wake_up(&drm_pipe->wait_queue);
+       }
 }
 
 /* -----------------------------------------------------------------------------
 }
 
 /* Setup the BRU source pad. */
+static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
+                                        struct vsp1_pipeline *pipe);
+static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe);
+
 static int vsp1_du_pipeline_setup_bru(struct vsp1_device *vsp1,
                                      struct vsp1_pipeline *pipe)
 {
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
        };
+       struct vsp1_entity *bru;
        int ret;
 
+       /*
+        * Pick a BRU:
+        * - If we need more than two inputs, use the main BRU.
+        * - Otherwise, if we are not forced to release our BRU, keep it.
+        * - Else, use any free BRU (randomly starting with the main BRU).
+        */
+       if (pipe->num_inputs > 2)
+               bru = &vsp1->bru->entity;
+       else if (pipe->bru && !drm_pipe->force_bru_release)
+               bru = pipe->bru;
+       else if (!vsp1->bru->entity.pipe)
+               bru = &vsp1->bru->entity;
+       else
+               bru = &vsp1->brs->entity;
+
+       /* Switch BRU if needed. */
+       if (bru != pipe->bru) {
+               struct vsp1_entity *released_bru = NULL;
+
+               /* Release our BRU if we have one. */
+               if (pipe->bru) {
+                       /*
+                        * The BRU might be acquired by the other pipeline in
+                        * the next step. We must thus remove it from the list
+                        * of entities for this pipeline. The other pipeline's
+                        * hardware configuration will reconfigure the BRU
+                        * routing.
+                        *
+                        * However, if the other pipeline doesn't acquire our
+                        * BRU, we need to keep it in the list, otherwise the
+                        * hardware configuration step won't disconnect it from
+                        * the pipeline. To solve this, store the released BRU
+                        * pointer to add it back to the list of entities later
+                        * if it isn't acquired by the other pipeline.
+                        */
+                       released_bru = pipe->bru;
+
+                       list_del(&pipe->bru->list_pipe);
+                       pipe->bru->sink = NULL;
+                       pipe->bru->pipe = NULL;
+                       pipe->bru = NULL;
+               }
+
+               /*
+                * If the BRU we need is in use, force the owner pipeline to
+                * switch to the other BRU and wait until the switch completes.
+                */
+               if (bru->pipe) {
+                       struct vsp1_drm_pipeline *owner_pipe;
+
+                       owner_pipe = to_vsp1_drm_pipeline(bru->pipe);
+                       owner_pipe->force_bru_release = true;
+
+                       vsp1_du_pipeline_setup_inputs(vsp1, &owner_pipe->pipe);
+                       vsp1_du_pipeline_configure(&owner_pipe->pipe);
+
+                       ret = wait_event_timeout(owner_pipe->wait_queue,
+                                                !owner_pipe->force_bru_release,
+                                                msecs_to_jiffies(500));
+                       if (ret == 0)
+                               dev_warn(vsp1->dev,
+                                        "DRM pipeline %u reconfiguration timeout\n",
+                                        owner_pipe->pipe.lif->index);
+               }
+
+               /*
+                * If the BRU we have released previously hasn't been acquired
+                * by the other pipeline, add it back to the entities list (with
+                * the pipe pointer NULL) to let vsp1_du_pipeline_configure()
+                * disconnect it from the hardware pipeline.
+                */
+               if (released_bru && !released_bru->pipe)
+                       list_add_tail(&released_bru->list_pipe,
+                                     &pipe->entities);
+
+               /* Add the BRU to the pipeline. */
+               pipe->bru = bru;
+               pipe->bru->pipe = pipe;
+               pipe->bru->sink = &pipe->output->entity;
+               pipe->bru->sink_pad = 0;
+
+               list_add_tail(&pipe->bru->list_pipe, &pipe->entities);
+       }
+
        /*
         * Configure the format on the BRU source and verify that it matches the
         * requested format. We don't set the media bus code as it is configured
                                         struct vsp1_pipeline *pipe)
 {
        struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
-       struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
+       struct vsp1_bru *bru;
        unsigned int i;
        int ret;
 
                struct vsp1_rwpf *rpf = vsp1->rpf[i];
                unsigned int j;
 
-               /*
-                * Make sure we don't accept more inputs than the hardware can
-                * handle. This is a temporary fix to avoid display stall, we
-                * need to instead allocate the BRU or BRS to display pipelines
-                * dynamically based on the number of planes they each use.
-                */
-               if (pipe->num_inputs >= pipe->bru->source_pad)
-                       pipe->inputs[i] = NULL;
-
                if (!pipe->inputs[i])
                        continue;
 
                return ret;
        }
 
+       bru = to_bru(&pipe->bru->subdev);
+
        /* Setup the RPF input pipeline for every enabled input. */
        for (i = 0; i < pipe->bru->source_pad; ++i) {
                struct vsp1_rwpf *rpf = inputs[i];
 /* Configure all entities in the pipeline. */
 static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
 {
+       struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
        struct vsp1_entity *entity;
        struct vsp1_entity *next;
        struct vsp1_dl_list *dl;
                }
        }
 
-       vsp1_dl_list_commit(dl, false);
+       vsp1_dl_list_commit(dl, drm_pipe->force_bru_release);
 }
 
 /* -----------------------------------------------------------------------------
        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
        struct vsp1_drm_pipeline *drm_pipe;
        struct vsp1_pipeline *pipe;
-       struct vsp1_bru *bru;
        unsigned long flags;
        unsigned int i;
        int ret;
 
        drm_pipe = &vsp1->drm->pipe[pipe_index];
        pipe = &drm_pipe->pipe;
-       bru = to_bru(&pipe->bru->subdev);
 
        if (!cfg) {
+               struct vsp1_bru *bru;
+
+               mutex_lock(&vsp1->drm->lock);
+
+               bru = to_bru(&pipe->bru->subdev);
+
                /*
                 * NULL configuration means the CRTC is being disabled, stop
                 * the pipeline and turn the light off.
                drm_pipe->du_complete = NULL;
                pipe->num_inputs = 0;
 
+               list_del(&pipe->bru->list_pipe);
+               pipe->bru->pipe = NULL;
+               pipe->bru = NULL;
+
+               mutex_unlock(&vsp1->drm->lock);
+
                vsp1_dlm_reset(pipe->output->dlm);
                vsp1_device_put(vsp1);
 
        dev_dbg(vsp1->dev, "%s: configuring LIF%u with format %ux%u\n",
                __func__, pipe_index, cfg->width, cfg->height);
 
+       mutex_lock(&vsp1->drm->lock);
+
        /* Setup formats through the pipeline. */
        ret = vsp1_du_pipeline_setup_inputs(vsp1, pipe);
        if (ret < 0)
-               return ret;
+               goto unlock;
 
        ret = vsp1_du_pipeline_setup_output(vsp1, pipe);
        if (ret < 0)
-               return ret;
+               goto unlock;
 
        /* Enable the VSP1. */
        ret = vsp1_device_get(vsp1);
        if (ret < 0)
-               return ret;
+               goto unlock;
 
        /*
         * Register a callback to allow us to notify the DRM driver of frame
        /* Configure all entities in the pipeline. */
        vsp1_du_pipeline_configure(pipe);
 
+unlock:
+       mutex_unlock(&vsp1->drm->lock);
+
+       if (ret < 0)
+               return ret;
+
        /* Start the pipeline. */
        spin_lock_irqsave(&pipe->irqlock, flags);
        vsp1_pipeline_run(pipe);
  */
 void vsp1_du_atomic_begin(struct device *dev, unsigned int pipe_index)
 {
+       struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+
+       mutex_lock(&vsp1->drm->lock);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
 
        vsp1_du_pipeline_setup_inputs(vsp1, pipe);
        vsp1_du_pipeline_configure(pipe);
+       mutex_unlock(&vsp1->drm->lock);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
 
        if (!vsp1->drm)
                return -ENOMEM;
 
+       mutex_init(&vsp1->drm->lock);
+
        /* Create one DRM pipeline per LIF. */
        for (i = 0; i < vsp1->info->lif_count; ++i) {
                struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i];
                struct vsp1_pipeline *pipe = &drm_pipe->pipe;
 
+               init_waitqueue_head(&drm_pipe->wait_queue);
+
                vsp1_pipeline_init(pipe);
 
                pipe->frame_end = vsp1_du_pipeline_frame_end;
 
                /*
-                * The DRM pipeline is static, add entities manually. The first
-                * pipeline uses the BRU and the second pipeline the BRS.
+                * The output side of the DRM pipeline is static, add the
+                * corresponding entities manually.
                 */
-               pipe->bru = i == 0 ? &vsp1->bru->entity : &vsp1->brs->entity;
                pipe->output = vsp1->wpf[i];
                pipe->lif = &vsp1->lif[i]->entity;
 
-               pipe->bru->pipe = pipe;
-               pipe->bru->sink = &pipe->output->entity;
-               pipe->bru->sink_pad = 0;
-               list_add_tail(&pipe->bru->list_pipe, &pipe->entities);
-
                pipe->output->entity.pipe = pipe;
                pipe->output->entity.sink = pipe->lif;
                pipe->output->entity.sink_pad = 0;
 
 void vsp1_drm_cleanup(struct vsp1_device *vsp1)
 {
+       mutex_destroy(&vsp1->drm->lock);
 }