Skip to content

Commit f718002

Browse files
committed
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: Linus Walleij <[email protected]> Acked-by: Daniel Vetter <[email protected]> Cc: [email protected] Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 8d0441c commit f718002

File tree

1 file changed

+21
-1
lines changed

1 file changed

+21
-1
lines changed

drivers/gpu/drm/tve200/tve200_display.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/version.h>
1515
#include <linux/dma-buf.h>
1616
#include <linux/of_graph.h>
17+
#include <linux/delay.h>
1718

1819
#include <drm/drm_fb_cma_helper.h>
1920
#include <drm/drm_fourcc.h>
@@ -130,9 +131,25 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
130131
struct drm_connector *connector = priv->connector;
131132
u32 format = fb->format->format;
132133
u32 ctrl1 = 0;
134+
int retries;
133135

134136
clk_prepare_enable(priv->clk);
135137

138+
/* Reset the TVE200 and wait for it to come back online */
139+
writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
140+
for (retries = 0; retries < 5; retries++) {
141+
usleep_range(30000, 50000);
142+
if (readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET)
143+
continue;
144+
else
145+
break;
146+
}
147+
if (retries == 5 &&
148+
readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET) {
149+
dev_err(drm->dev, "can't get hardware out of reset\n");
150+
return;
151+
}
152+
136153
/* Function 1 */
137154
ctrl1 |= TVE200_CTRL_CSMODE;
138155
/* Interlace mode for CCIR656: parameterize? */
@@ -230,8 +247,9 @@ static void tve200_display_disable(struct drm_simple_display_pipe *pipe)
230247

231248
drm_crtc_vblank_off(crtc);
232249

233-
/* Disable and Power Down */
250+
/* Disable put into reset and Power Down */
234251
writel(0, priv->regs + TVE200_CTRL);
252+
writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
235253

236254
clk_disable_unprepare(priv->clk);
237255
}
@@ -279,6 +297,8 @@ static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
279297
struct drm_device *drm = crtc->dev;
280298
struct tve200_drm_dev_private *priv = drm->dev_private;
281299

300+
/* Clear any IRQs and enable */
301+
writel(0xFF, priv->regs + TVE200_INT_CLR);
282302
writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN);
283303
return 0;
284304
}

0 commit comments

Comments
 (0)