summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mcde/mcde_display.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2020-08-09 00:31:21 +0200
committerLinus Walleij <linus.walleij@linaro.org>2020-08-13 16:39:19 +0200
commitc4842d4d0f744bf419a1b011fa3ce0ed98fcdc10 (patch)
tree3e67ddaa1882b3460dc685c87edd6d3a12c8d7c2 /drivers/gpu/drm/mcde/mcde_display.c
parentf6fd1d70609ca691ee5dc0d2748b6eeaa57a9535 (diff)
downloadlinux-c4842d4d0f744bf419a1b011fa3ce0ed98fcdc10.tar.bz2
drm/mcde: Fix display pipeline restart
To make sure that the MCDE is in a reasonable state during set-up, perform a reset by power cycling the block by dropping the on-chip regulator reference after probe. The display subsystem (DSS) has no dedicated reset line so dropping the EPOD regulator is the only real way of resetting it. We introduce code to enable and disable the regulator in the display enable/disable callbacks. We move the generic MCDE setup such as muxing of DPI signals and masking of interrupts to the display handling. When we drop the power to the whole display subsystem, not only MCDE but also the DSI links lose their state. Therefore we move the DSI block reset and hardware initialization code to the mcde_dsi_bridge_pre_enable() callback so this happens every time we start up the bridge, as we may have lost the power. We move the final disablement of the interrupts and clocks to the mcde_dsi_bridge_post_disable() callback rather than have it in the mcde_dsi_bridge_disable() callback, as some control messages may still be sent over the DSI host after the bridge has been shut down. This (together with a patch for the corresponding panel) makes the Samsung GT-S7710 successfully disable and re-enable its display, cutting all power while disabled and re-initializing the hardware when coming back up. Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Cc: newbytee@protonmail.com Cc: Stephan Gerhold <stephan@gerhold.net> Link: https://patchwork.freedesktop.org/patch/msgid/20200808223122.1492124-3-linus.walleij@linaro.org
Diffstat (limited to 'drivers/gpu/drm/mcde/mcde_display.c')
-rw-r--r--drivers/gpu/drm/mcde/mcde_display.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
index cbc7c0c4955a..d608cc894e01 100644
--- a/drivers/gpu/drm/mcde/mcde_display.c
+++ b/drivers/gpu/drm/mcde/mcde_display.c
@@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-buf.h>
+#include <linux/regulator/consumer.h>
#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
@@ -879,6 +880,14 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
u32 formatter_frame;
u32 pkt_div;
u32 val;
+ int ret;
+
+ /* This powers up the entire MCDE block and the DSI hardware */
+ ret = regulator_enable(mcde->epod);
+ if (ret) {
+ dev_err(drm->dev, "can't re-enable EPOD regulator\n");
+ return;
+ }
dev_info(drm->dev, "enable MCDE, %d x %d format %s\n",
mode->hdisplay, mode->vdisplay,
@@ -889,6 +898,26 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
return;
}
+ /* Set up the main control, watermark level at 7 */
+ val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT;
+ /* 24 bits DPI: connect LSB Ch B to D[0:7] */
+ val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT;
+ /* TV out: connect LSB Ch B to D[8:15] */
+ val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT;
+ /* Don't care about this muxing */
+ val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT;
+ /* 24 bits DPI: connect MID Ch B to D[24:31] */
+ val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT;
+ /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */
+ val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT;
+ /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */
+ writel(val, mcde->regs + MCDE_CONF0);
+
+ /* Clear any pending interrupts */
+ mcde_display_disable_irqs(mcde);
+ writel(0, mcde->regs + MCDE_IMSCERR);
+ writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR);
+
dev_info(drm->dev, "output in %s mode, format %dbpp\n",
(mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ?
"VIDEO" : "CMD",
@@ -1005,6 +1034,11 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
dev_dbg(mcde->dev, "started MCDE video FIFO flow\n");
}
+ /* Enable automatic clock gating */
+ val = readl(mcde->regs + MCDE_CR);
+ val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN;
+ writel(val, mcde->regs + MCDE_CR);
+
dev_info(drm->dev, "MCDE display is enabled\n");
}
@@ -1014,6 +1048,7 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
struct drm_device *drm = crtc->dev;
struct mcde *mcde = to_mcde(drm);
struct drm_pending_vblank_event *event;
+ int ret;
drm_crtc_vblank_off(crtc);
@@ -1029,6 +1064,12 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
spin_unlock_irq(&crtc->dev->event_lock);
}
+ ret = regulator_disable(mcde->epod);
+ if (ret)
+ dev_err(drm->dev, "can't disable EPOD regulator\n");
+ /* Make sure we are powered down (before we may power up again) */
+ usleep_range(50000, 70000);
+
dev_info(drm->dev, "MCDE display is disabled\n");
}