diff options
| -rw-r--r-- | drivers/gpu/drm/mcde/mcde_display.c | 36 | ||||
| -rw-r--r-- | drivers/gpu/drm/mcde/mcde_drm.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/mcde/mcde_dsi.c | 44 |
3 files changed, 47 insertions, 35 deletions
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index d608cc894e01..c271e5bf042e 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -999,6 +999,16 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, 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); @@ -1025,16 +1035,20 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, 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); @@ -1055,6 +1069,9 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) /* 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; @@ -1164,8 +1181,11 @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, 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 { /* diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h index 9f197f4e9ced..8253e2f9993e 100644 --- a/drivers/gpu/drm/mcde/mcde_drm.h +++ b/drivers/gpu/drm/mcde/mcde_drm.h @@ -97,6 +97,8 @@ static inline bool mcde_flow_is_video(struct mcde *mcde) bool mcde_dsi_irq(struct mipi_dsi_device *mdsi); void mcde_dsi_te_request(struct mipi_dsi_device *mdsi); +void mcde_dsi_enable(struct drm_bridge *bridge); +void mcde_dsi_disable(struct drm_bridge *bridge); extern struct platform_driver mcde_dsi_driver; void mcde_display_irq(struct mcde *mcde); diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index ae3d146912f2..ae70f76bfb89 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -826,23 +826,11 @@ static void mcde_dsi_start(struct mcde_dsi *d) 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; @@ -920,6 +908,11 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) 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); @@ -932,6 +925,8 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) 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, @@ -994,7 +989,11 @@ static void mcde_dsi_wait_for_video_mode_stop(struct mcde_dsi *d) } } -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; @@ -1009,11 +1008,6 @@ static void mcde_dsi_bridge_disable(struct drm_bridge *bridge) /* 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 @@ -1052,10 +1046,6 @@ static int mcde_dsi_bridge_attach(struct drm_bridge *bridge, 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, |