Commit a6402e80 authored by Dave Airlie's avatar Dave Airlie

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 790cb4c7 ("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
parents 09980771 11aff4b4
...@@ -405,6 +405,14 @@ int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts) ...@@ -405,6 +405,14 @@ int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
return -EINVAL; return -EINVAL;
} }
/*
* IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
* i.MX53 channel arbitration locking doesn't seem to work properly.
* Allow enabling the lock feature on IPUv3H / i.MX6 only.
*/
if (bursts && ipu->ipu_type != IPUV3H)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) { for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
if (channel->num == idmac_lock_en_info[i].chnum) if (channel->num == idmac_lock_en_info[i].chnum)
break; break;
......
...@@ -73,6 +73,14 @@ ...@@ -73,6 +73,14 @@
#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1) #define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1)
#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4) #define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
#define IPU_PRE_STORE_ENG_STATUS 0x120
#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK 0xffff
#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK 0x3fff
#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
#define IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL (1 << 30)
#define IPU_PRE_STORE_ENG_STATUS_STORE_FIELD (1 << 31)
#define IPU_PRE_STORE_ENG_SIZE 0x130 #define IPU_PRE_STORE_ENG_SIZE 0x130
#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0) #define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0)
#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16) #define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16)
...@@ -93,6 +101,7 @@ struct ipu_pre { ...@@ -93,6 +101,7 @@ struct ipu_pre {
dma_addr_t buffer_paddr; dma_addr_t buffer_paddr;
void *buffer_virt; void *buffer_virt;
bool in_use; bool in_use;
unsigned int safe_window_end;
}; };
static DEFINE_MUTEX(ipu_pre_list_mutex); static DEFINE_MUTEX(ipu_pre_list_mutex);
...@@ -160,6 +169,9 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width, ...@@ -160,6 +169,9 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
u32 active_bpp = info->cpp[0] >> 1; u32 active_bpp = info->cpp[0] >> 1;
u32 val; u32 val;
/* calculate safe window for ctrl register updates */
pre->safe_window_end = height - 2;
writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF); writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF); writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
...@@ -199,7 +211,24 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width, ...@@ -199,7 +211,24 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr) void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
{ {
unsigned long timeout = jiffies + msecs_to_jiffies(5);
unsigned short current_yblock;
u32 val;
writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF); writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
do {
if (time_after(jiffies, timeout)) {
dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
return;
}
val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
current_yblock =
(val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
} while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET); writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -329,6 +330,12 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, ...@@ -329,6 +330,12 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
val = IPU_PRG_REG_UPDATE_REG_UPDATE; val = IPU_PRG_REG_UPDATE_REG_UPDATE;
writel(val, prg->regs + IPU_PRG_REG_UPDATE); writel(val, prg->regs + IPU_PRG_REG_UPDATE);
/* wait for both double buffers to be filled */
readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
(val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
(val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
5, 1000);
clk_disable_unprepare(prg->clk_ipg); clk_disable_unprepare(prg->clk_ipg);
chan->enabled = true; chan->enabled = true;
......
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