diff options
author | Dave Airlie <airlied@redhat.com> | 2017-10-13 03:32:30 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-10-13 03:32:30 -0400 |
commit | a6402e80fa655bdc68d66784054cb4e65376b82f (patch) | |
tree | c66da930e0f7fd8df3222f03eb47eaf7a682649a | |
parent | 09980771815545a552b3a3e05d0ed283fa013602 (diff) | |
parent | 11aff4b4c7c4b7257660ef890920f2ac72911ed0 (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.c | 8 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-pre.c | 29 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prg.c | 7 |
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 | ||
98 | static DEFINE_MUTEX(ipu_pre_list_mutex); | 107 | static 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 | ||
200 | void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr) | 212 | void 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; |