Commit f7180022 authored by Linus Walleij's avatar Linus Walleij

drm/tve200: Stabilize enable/disable

The TVE200 will occasionally print a bunch of lost interrupts
and similar dmesg messages, sometimes during boot and sometimes
after disabling and coming back to enablement. This is probably
because the hardware is left in an unknown state by the boot
loader that displays a logo.

This can be fixed by bringing the controller into a known state
by resetting the controller while enabling it. We retry reset 5
times like the vendor driver does. We also put the controller
into reset before de-clocking it and clear all interrupts before
enabling the vblank IRQ.

This makes the video enable/disable/enable cycle rock solid
on the D-Link DIR-685. Tested extensively.
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Cc: stable@vger.kernel.org
Link: https://patchwork.freedesktop.org/patch/msgid/20200820203144.271081-1-linus.walleij@linaro.org
parent 8d0441cf
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <linux/dma-buf.h> #include <linux/dma-buf.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/delay.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
...@@ -130,9 +131,25 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe, ...@@ -130,9 +131,25 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
struct drm_connector *connector = priv->connector; struct drm_connector *connector = priv->connector;
u32 format = fb->format->format; u32 format = fb->format->format;
u32 ctrl1 = 0; u32 ctrl1 = 0;
int retries;
clk_prepare_enable(priv->clk); clk_prepare_enable(priv->clk);
/* Reset the TVE200 and wait for it to come back online */
writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
for (retries = 0; retries < 5; retries++) {
usleep_range(30000, 50000);
if (readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET)
continue;
else
break;
}
if (retries == 5 &&
readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET) {
dev_err(drm->dev, "can't get hardware out of reset\n");
return;
}
/* Function 1 */ /* Function 1 */
ctrl1 |= TVE200_CTRL_CSMODE; ctrl1 |= TVE200_CTRL_CSMODE;
/* Interlace mode for CCIR656: parameterize? */ /* Interlace mode for CCIR656: parameterize? */
...@@ -230,8 +247,9 @@ static void tve200_display_disable(struct drm_simple_display_pipe *pipe) ...@@ -230,8 +247,9 @@ static void tve200_display_disable(struct drm_simple_display_pipe *pipe)
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
/* Disable and Power Down */ /* Disable put into reset and Power Down */
writel(0, priv->regs + TVE200_CTRL); writel(0, priv->regs + TVE200_CTRL);
writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
} }
...@@ -279,6 +297,8 @@ static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe) ...@@ -279,6 +297,8 @@ static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
struct drm_device *drm = crtc->dev; struct drm_device *drm = crtc->dev;
struct tve200_drm_dev_private *priv = drm->dev_private; struct tve200_drm_dev_private *priv = drm->dev_private;
/* Clear any IRQs and enable */
writel(0xFF, priv->regs + TVE200_INT_CLR);
writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN); writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment