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,