drm/mcde: dsi: Enable clocks in pre_enable() instead of mode_set()
The DSI initialization sequence incorrectly assumes that the mode_set() function of the DRM bridge is always called when (re-)enabling the display. This is not necessarily the case. Keeping the device idle in the framebuffer console for a while results in the display being turned off using the disable() function. However, as soon as any key is pressed only (pre_)enable() are called. mode_set() is skipped because the mode has not been changed. In this case, the DSI HS/LP clocks are never turned back on, preventing the display from working. Fix this by moving a part of the initialization sequence from mode_set() to pre_enable(). Keep most of the video mode setup in mode_set() since most of the registers are only dependent on the mode that is set for the panel - there is no need to write them again each time we re-enable the display. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> Tested-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20191106165835.2863-7-stephan@gerhold.net
This commit is contained in:
parent
1f79c60e10
commit
3c5824bdc4
|
@ -562,21 +562,6 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
|
||||||
DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT;
|
DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT;
|
||||||
writel(val, d->regs + DSI_VID_VCA_SETTING2);
|
writel(val, d->regs + DSI_VID_VCA_SETTING2);
|
||||||
|
|
||||||
/* Put IF1 into video mode */
|
|
||||||
val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
|
|
||||||
val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE;
|
|
||||||
writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
|
|
||||||
|
|
||||||
/* Disable command mode on IF1 */
|
|
||||||
val = readl(d->regs + DSI_CMD_MODE_CTL);
|
|
||||||
val &= ~DSI_CMD_MODE_CTL_IF1_LP_EN;
|
|
||||||
writel(val, d->regs + DSI_CMD_MODE_CTL);
|
|
||||||
|
|
||||||
/* Enable some error interrupts */
|
|
||||||
val = readl(d->regs + DSI_VID_MODE_STS_CTL);
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mcde_dsi_start(struct mcde_dsi *d)
|
static void mcde_dsi_start(struct mcde_dsi *d)
|
||||||
|
@ -700,26 +685,13 @@ static void mcde_dsi_bridge_enable(struct drm_bridge *bridge)
|
||||||
dev_info(d->dev, "enable DSI master\n");
|
dev_info(d->dev, "enable DSI master\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
|
static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge)
|
||||||
const struct drm_display_mode *mode,
|
|
||||||
const struct drm_display_mode *adj)
|
|
||||||
{
|
{
|
||||||
struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
|
struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
|
||||||
unsigned long pixel_clock_hz = mode->clock * 1000;
|
|
||||||
unsigned long hs_freq, lp_freq;
|
unsigned long hs_freq, lp_freq;
|
||||||
u32 val;
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!d->mdsi) {
|
|
||||||
dev_err(d->dev, "no DSI device attached to encoder!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_info(d->dev, "set DSI master to %dx%d %lu Hz %s mode\n",
|
|
||||||
mode->hdisplay, mode->vdisplay, pixel_clock_hz,
|
|
||||||
(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD"
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Copy maximum clock frequencies */
|
/* Copy maximum clock frequencies */
|
||||||
if (d->mdsi->lp_rate)
|
if (d->mdsi->lp_rate)
|
||||||
lp_freq = d->mdsi->lp_rate;
|
lp_freq = d->mdsi->lp_rate;
|
||||||
|
@ -758,7 +730,21 @@ static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
|
||||||
d->hs_freq);
|
d->hs_freq);
|
||||||
|
|
||||||
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
|
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
|
||||||
mcde_dsi_setup_video_mode(d, mode);
|
/* Put IF1 into video mode */
|
||||||
|
val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
|
||||||
|
val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE;
|
||||||
|
writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
|
||||||
|
|
||||||
|
/* Disable command mode on IF1 */
|
||||||
|
val = readl(d->regs + DSI_CMD_MODE_CTL);
|
||||||
|
val &= ~DSI_CMD_MODE_CTL_IF1_LP_EN;
|
||||||
|
writel(val, d->regs + DSI_CMD_MODE_CTL);
|
||||||
|
|
||||||
|
/* Enable some error interrupts */
|
||||||
|
val = readl(d->regs + DSI_VID_MODE_STS_CTL);
|
||||||
|
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);
|
||||||
} else {
|
} else {
|
||||||
/* Command mode, clear IF1 ID */
|
/* Command mode, clear IF1 ID */
|
||||||
val = readl(d->regs + DSI_CMD_MODE_CTL);
|
val = readl(d->regs + DSI_CMD_MODE_CTL);
|
||||||
|
@ -772,6 +758,26 @@ static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
|
||||||
|
const struct drm_display_mode *mode,
|
||||||
|
const struct drm_display_mode *adj)
|
||||||
|
{
|
||||||
|
struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
|
||||||
|
|
||||||
|
if (!d->mdsi) {
|
||||||
|
dev_err(d->dev, "no DSI device attached to encoder!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(d->dev, "set DSI master to %dx%d %u Hz %s mode\n",
|
||||||
|
mode->hdisplay, mode->vdisplay, mode->clock * 1000,
|
||||||
|
(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO)
|
||||||
|
mcde_dsi_setup_video_mode(d, mode);
|
||||||
|
}
|
||||||
|
|
||||||
static void mcde_dsi_wait_for_command_mode_stop(struct mcde_dsi *d)
|
static void mcde_dsi_wait_for_command_mode_stop(struct mcde_dsi *d)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -863,6 +869,7 @@ static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = {
|
||||||
.mode_set = mcde_dsi_bridge_mode_set,
|
.mode_set = mcde_dsi_bridge_mode_set,
|
||||||
.disable = mcde_dsi_bridge_disable,
|
.disable = mcde_dsi_bridge_disable,
|
||||||
.enable = mcde_dsi_bridge_enable,
|
.enable = mcde_dsi_bridge_enable,
|
||||||
|
.pre_enable = mcde_dsi_bridge_pre_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mcde_dsi_bind(struct device *dev, struct device *master,
|
static int mcde_dsi_bind(struct device *dev, struct device *master,
|
||||||
|
|
Loading…
Reference in New Issue