mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0,
                            fifo_wtrmrk);
 
+       /*
+        * This brings up the DSI bridge which is tightly connected
+        * to the MCDE DSI formatter.
+        *
+        * FIXME: if we want to use another formatter, such as DPI,
+        * we need to be more elaborate here and select the appropriate
+        * bridge.
+        */
+       mcde_dsi_enable(mcde->bridge);
+
        /* Configure the DSI formatter 0 for the DSI panel output */
        mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0,
                                     formatter_frame, pkt_size);
 
        drm_crtc_vblank_on(crtc);
 
-       if (mcde_flow_is_video(mcde)) {
-               /*
-                * Keep FIFO permanently enabled in video mode,
-                * otherwise MCDE will stop feeding data to the panel.
-                */
+       /*
+        * If we're using oneshot mode we don't start the flow
+        * until each time the display is given an update, and
+        * then we disable it immediately after. For all other
+        * modes (command or video) we start the FIFO flow
+        * right here. This is necessary for the hardware to
+        * behave right.
+        */
+       if (mcde->flow_mode != MCDE_COMMAND_ONESHOT_FLOW) {
                mcde_enable_fifo(mcde, MCDE_FIFO_A);
                dev_dbg(mcde->dev, "started MCDE video FIFO flow\n");
        }
 
-       /* Enable automatic clock gating */
+       /* Enable MCDE with automatic clock gating */
        val = readl(mcde->regs + MCDE_CR);
        val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN;
        writel(val, mcde->regs + MCDE_CR);
        /* Disable FIFO A flow */
        mcde_disable_fifo(mcde, MCDE_FIFO_A, true);
 
+       /* This disables the DSI bridge */
+       mcde_dsi_disable(mcde->bridge);
+
        event = crtc->state->event;
        if (event) {
                crtc->state->event = NULL;
        if (fb) {
                mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0));
                dev_info_once(mcde->dev, "first update of display contents\n");
-               /* The flow is already active in video mode */
-               if (!mcde_flow_is_video(mcde) && mcde->flow_active == 0)
+               /*
+                * Usually the flow is already active, unless we are in
+                * oneshot mode, then we need to kick the flow right here.
+                */
+               if (mcde->flow_active == 0)
                        mcde_start_flow(mcde);
        } else {
                /*
 
        dev_info(d->dev, "DSI link enabled\n");
 }
 
-
-static void mcde_dsi_bridge_enable(struct drm_bridge *bridge)
-{
-       struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
-       u32 val;
-
-       if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
-               /* Enable video mode */
-               val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
-               val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN;
-               writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
-       }
-
-       dev_info(d->dev, "enable DSI master\n");
-};
-
-static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge)
+/*
+ * Notice that this is called from inside the display controller
+ * and not from the bridge callbacks.
+ */
+void mcde_dsi_enable(struct drm_bridge *bridge)
 {
        struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
        unsigned long hs_freq, lp_freq;
                val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC;
                val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA;
                writel(val, d->regs + DSI_VID_MODE_STS_CTL);
+
+               /* Enable video mode */
+               val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
+               val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN;
+               writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
        } else {
                /* Command mode, clear IF1 ID */
                val = readl(d->regs + DSI_CMD_MODE_CTL);
                val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK;
                writel(val, d->regs + DSI_CMD_MODE_CTL);
        }
+
+       dev_info(d->dev, "enabled MCDE DSI master\n");
 }
 
 static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
        }
 }
 
-static void mcde_dsi_bridge_disable(struct drm_bridge *bridge)
+/*
+ * Notice that this is called from inside the display controller
+ * and not from the bridge callbacks.
+ */
+void mcde_dsi_disable(struct drm_bridge *bridge)
 {
        struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
        u32 val;
                /* Stop command mode */
                mcde_dsi_wait_for_command_mode_stop(d);
        }
-}
-
-static void mcde_dsi_bridge_post_disable(struct drm_bridge *bridge)
-{
-       struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
 
        /*
         * Stop clocks and terminate any DSI traffic here so the panel can
 static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = {
        .attach = mcde_dsi_bridge_attach,
        .mode_set = mcde_dsi_bridge_mode_set,
-       .disable = mcde_dsi_bridge_disable,
-       .enable = mcde_dsi_bridge_enable,
-       .pre_enable = mcde_dsi_bridge_pre_enable,
-       .post_disable = mcde_dsi_bridge_post_disable,
 };
 
 static int mcde_dsi_bind(struct device *dev, struct device *master,