summaryrefslogtreecommitdiff
path: root/drivers/gpu/imx/dpu
diff options
context:
space:
mode:
authorLiu Ying <victor.liu@nxp.com>2018-01-12 17:42:21 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commitcd2e870471763d88e26caddeba96347cf073b197 (patch)
treee368d46c3a5ec746bc6a9d8f45018086c8121e99 /drivers/gpu/imx/dpu
parent9de5d1467fcce19530d223dd13fe53e581ed76ce (diff)
MLK-17371 gpu: imx: dpu: framegen: Use better timeout value to wait for ENSTS
The DPU spec tells us that we need to wait for all pending frames to be completed when a display stream is disabled. It turns out that the hardcoded 60-microsecond timeout value is not enough for some low refresh rate video modes, e.g., 1920x1080@24, which makes the display stream be disabled incorrectly(leave the hardware an incorrect machine status). The SoC design indicates that there are two pending frames to complete in the worst case. This patch waits for at most three frame duration(which is enough for sure) so that the hardware may flush out all the pending frames. In case the clock subsystem provides us a pixel clock with wrong rate and causes the timeout value be unreasonably long, we truncate it to wait for at most three seconds. Signed-off-by: Liu Ying <victor.liu@nxp.com>
Diffstat (limited to 'drivers/gpu/imx/dpu')
-rw-r--r--drivers/gpu/imx/dpu/dpu-framegen.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/drivers/gpu/imx/dpu/dpu-framegen.c b/drivers/gpu/imx/dpu/dpu-framegen.c
index ffbea6618041..fb4ff105fd6f 100644
--- a/drivers/gpu/imx/dpu/dpu-framegen.c
+++ b/drivers/gpu/imx/dpu/dpu-framegen.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
- * Copyright 2017 NXP
+ * Copyright 2017-2018 NXP
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -96,6 +96,8 @@ typedef enum {
#define FGSREPD 0x90
#define FGSRFTD 0x94
+#define KHZ 1000
+
struct dpu_framegen {
void __iomem *base;
struct clk *clk_pll;
@@ -348,17 +350,47 @@ void framegen_panic_displaymode(struct dpu_framegen *fg, fgdm_t mode)
}
EXPORT_SYMBOL_GPL(framegen_panic_displaymode);
-void framegen_wait_done(struct dpu_framegen *fg)
+void framegen_wait_done(struct dpu_framegen *fg, struct drm_display_mode *m)
{
- unsigned long timeout = jiffies + msecs_to_jiffies(60);
+ unsigned long timeout, pending_framedur_jiffies;
+ int frame_size = m->crtc_htotal * m->crtc_vtotal;
+ int dotclock, pending_framedur_ns;
u32 val;
+ dotclock = clk_get_rate(fg->clk_disp) / KHZ;
+ if (dotclock == 0) {
+ /* fall back to display mode's clock */
+ dotclock = m->crtc_clock;
+
+ dev_warn(fg->dpu->dev,
+ "pixel clock for FrameGen%d is zero\n", fg->id);
+ }
+
+ /*
+ * The SoC designer indicates that there are two pending frames
+ * to complete in the worst case.
+ * So, three pending frames are enough for sure.
+ */
+ pending_framedur_ns = div_u64((u64) 3 * frame_size * 1000000, dotclock);
+ pending_framedur_jiffies = nsecs_to_jiffies(pending_framedur_ns);
+ if (pending_framedur_jiffies > (3 * HZ)) {
+ pending_framedur_jiffies = 3 * HZ;
+
+ dev_warn(fg->dpu->dev,
+ "truncate FrameGen%d pending frame duration to 3sec\n",
+ fg->id);
+ }
+ timeout = jiffies + pending_framedur_jiffies;
+
mutex_lock(&fg->mutex);
do {
val = dpu_fg_read(fg, FGENSTS);
} while ((val & ENSTS) && time_before(jiffies, timeout));
mutex_unlock(&fg->mutex);
+ dev_dbg(fg->dpu->dev, "FrameGen%d pending frame duration is %ums\n",
+ fg->id, jiffies_to_msecs(pending_framedur_jiffies));
+
if (val & ENSTS)
dev_err(fg->dpu->dev, "failed to wait for FrameGen%d done\n",
fg->id);