Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6402e80 authored by Dave Airlie's avatar Dave Airlie
Browse files

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
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -405,6 +405,14 @@ int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
		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++) {
		if (channel->num == idmac_lock_en_info[i].chnum)
			break;
+29 −0
Original line number Diff line number Diff line
@@ -73,6 +73,14 @@
#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_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_INPUT_WIDTH(v)		((v & 0xffff) << 0)
#define  IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v)		((v & 0xffff) << 16)
@@ -93,6 +101,7 @@ struct ipu_pre {
	dma_addr_t		buffer_paddr;
	void			*buffer_virt;
	bool			in_use;
	unsigned int		safe_window_end;
};

static DEFINE_MUTEX(ipu_pre_list_mutex);
@@ -160,6 +169,9 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
	u32 active_bpp = info->cpp[0] >> 1;
	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_NEXT_BUF);

@@ -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)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(5);
	unsigned short current_yblock;
	u32 val;

	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);
}

+7 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <drm/drm_fourcc.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/module.h>
@@ -329,6 +330,12 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
	val = IPU_PRG_REG_UPDATE_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);

	chan->enabled = true;