aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-10-13 03:32:30 -0400
committerDave Airlie <airlied@redhat.com>2017-10-13 03:32:30 -0400
commita6402e80fa655bdc68d66784054cb4e65376b82f (patch)
treec66da930e0f7fd8df3222f03eb47eaf7a682649a
parent09980771815545a552b3a3e05d0ed283fa013602 (diff)
parent11aff4b4c7c4b7257660ef890920f2ac72911ed0 (diff)
Merge tag 'imx-drm-fixes-2017-10-12' of git://git.pengutronix.de/git/pza/linux into drm-fixes
drm/imx: i.MX5 regression fix and i.MX6QP PRE/PRG stability fixes - Disable channel burst locking on IPUv3EX (i.MX51) and IPUv3M (i.MX53). This fixes a regression introduced by commit 790cb4c7c954 ("drm/imx: lock scanout transfers for consecutive bursts"). - Give PRG a head start. Waiting for both double buffers to fill up before enabling the IPU improves startup reliability. - Avoid PRE control register updates during unsafe window, workaround for ERR009624. * tag 'imx-drm-fixes-2017-10-12' of git://git.pengutronix.de/git/pza/linux: gpu: ipu-v3: pre: implement workaround for ERR009624 gpu: ipu-v3: prg: wait for double buffers to be filled on channel startup gpu: ipu-v3: Allow channel burst locking on i.MX6 only
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c8
-rw-r--r--drivers/gpu/ipu-v3/ipu-pre.c29
-rw-r--r--drivers/gpu/ipu-v3/ipu-prg.c7
3 files changed, 44 insertions, 0 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 6a573d21d3cc..658fa2d3e40c 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -405,6 +405,14 @@ int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
405 return -EINVAL; 405 return -EINVAL;
406 } 406 }
407 407
408 /*
409 * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
410 * i.MX53 channel arbitration locking doesn't seem to work properly.
411 * Allow enabling the lock feature on IPUv3H / i.MX6 only.
412 */
413 if (bursts && ipu->ipu_type != IPUV3H)
414 return -EINVAL;
415
408 for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) { 416 for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
409 if (channel->num == idmac_lock_en_info[i].chnum) 417 if (channel->num == idmac_lock_en_info[i].chnum)
410 break; 418 break;
diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c
index c35f74c83065..c860a7997cb5 100644
--- a/drivers/gpu/ipu-v3/ipu-pre.c
+++ b/drivers/gpu/ipu-v3/ipu-pre.c
@@ -73,6 +73,14 @@
73#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1) 73#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1)
74#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4) 74#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
75 75
76#define IPU_PRE_STORE_ENG_STATUS 0x120
77#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK 0xffff
78#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
79#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK 0x3fff
80#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
81#define IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL (1 << 30)
82#define IPU_PRE_STORE_ENG_STATUS_STORE_FIELD (1 << 31)
83
76#define IPU_PRE_STORE_ENG_SIZE 0x130 84#define IPU_PRE_STORE_ENG_SIZE 0x130
77#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0) 85#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0)
78#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16) 86#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16)
@@ -93,6 +101,7 @@ struct ipu_pre {
93 dma_addr_t buffer_paddr; 101 dma_addr_t buffer_paddr;
94 void *buffer_virt; 102 void *buffer_virt;
95 bool in_use; 103 bool in_use;
104 unsigned int safe_window_end;
96}; 105};
97 106
98static DEFINE_MUTEX(ipu_pre_list_mutex); 107static DEFINE_MUTEX(ipu_pre_list_mutex);
@@ -160,6 +169,9 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
160 u32 active_bpp = info->cpp[0] >> 1; 169 u32 active_bpp = info->cpp[0] >> 1;
161 u32 val; 170 u32 val;
162 171
172 /* calculate safe window for ctrl register updates */
173 pre->safe_window_end = height - 2;
174
163 writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF); 175 writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
164 writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF); 176 writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
165 177
@@ -199,7 +211,24 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
199 211
200void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr) 212void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
201{ 213{
214 unsigned long timeout = jiffies + msecs_to_jiffies(5);
215 unsigned short current_yblock;
216 u32 val;
217
202 writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF); 218 writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
219
220 do {
221 if (time_after(jiffies, timeout)) {
222 dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
223 return;
224 }
225
226 val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
227 current_yblock =
228 (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
229 IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
230 } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
231
203 writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET); 232 writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
204} 233}
205 234
diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c
index ecc9ea44dc50..0013ca9f72c8 100644
--- a/drivers/gpu/ipu-v3/ipu-prg.c
+++ b/drivers/gpu/ipu-v3/ipu-prg.c
@@ -14,6 +14,7 @@
14#include <drm/drm_fourcc.h> 14#include <drm/drm_fourcc.h>
15#include <linux/clk.h> 15#include <linux/clk.h>
16#include <linux/err.h> 16#include <linux/err.h>
17#include <linux/iopoll.h>
17#include <linux/mfd/syscon.h> 18#include <linux/mfd/syscon.h>
18#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 19#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
19#include <linux/module.h> 20#include <linux/module.h>
@@ -329,6 +330,12 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
329 val = IPU_PRG_REG_UPDATE_REG_UPDATE; 330 val = IPU_PRG_REG_UPDATE_REG_UPDATE;
330 writel(val, prg->regs + IPU_PRG_REG_UPDATE); 331 writel(val, prg->regs + IPU_PRG_REG_UPDATE);
331 332
333 /* wait for both double buffers to be filled */
334 readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
335 (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
336 (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
337 5, 1000);
338
332 clk_disable_unprepare(prg->clk_ipg); 339 clk_disable_unprepare(prg->clk_ipg);
333 340
334 chan->enabled = true; 341 chan->enabled = true;