1 From a7782c6e5e37b2b406221827b177c2bfcc8825cd Mon Sep 17 00:00:00 2001
2 From: Liu Ying <victor.liu@nxp.com>
3 Date: Tue, 22 Jan 2019 17:08:01 +0800
4 Subject: [PATCH] gpu: Move ipu-v3 to imx folder
6 The new imx folder may contain ipu-v3 and dpu common drivers.
8 Signed-off-by: Liu Ying <victor.liu@nxp.com>
9 [ Aisheng: fix source path ]
10 Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
12 drivers/gpu/Makefile | 2 +-
13 drivers/gpu/imx/Kconfig | 1 +
14 drivers/gpu/imx/Makefile | 1 +
15 drivers/gpu/imx/ipu-v3/Kconfig | 11 +
16 drivers/gpu/imx/ipu-v3/Makefile | 10 +
17 drivers/gpu/imx/ipu-v3/ipu-common.c | 1565 ++++++++++++++++++
18 drivers/gpu/imx/ipu-v3/ipu-cpmem.c | 976 +++++++++++
19 drivers/gpu/imx/ipu-v3/ipu-csi.c | 821 +++++++++
20 drivers/gpu/imx/ipu-v3/ipu-dc.c | 420 +++++
21 drivers/gpu/imx/ipu-v3/ipu-di.c | 745 +++++++++
22 drivers/gpu/imx/ipu-v3/ipu-dmfc.c | 214 +++
23 drivers/gpu/imx/ipu-v3/ipu-dp.c | 357 ++++
24 drivers/gpu/imx/ipu-v3/ipu-ic.c | 761 +++++++++
25 drivers/gpu/imx/ipu-v3/ipu-image-convert.c | 2475 ++++++++++++++++++++++++++++
26 drivers/gpu/imx/ipu-v3/ipu-pre.c | 346 ++++
27 drivers/gpu/imx/ipu-v3/ipu-prg.c | 483 ++++++
28 drivers/gpu/imx/ipu-v3/ipu-prv.h | 274 +++
29 drivers/gpu/imx/ipu-v3/ipu-smfc.c | 202 +++
30 drivers/gpu/imx/ipu-v3/ipu-vdi.c | 234 +++
31 drivers/gpu/ipu-v3/Kconfig | 11 -
32 drivers/gpu/ipu-v3/Makefile | 10 -
33 drivers/gpu/ipu-v3/ipu-common.c | 1565 ------------------
34 drivers/gpu/ipu-v3/ipu-cpmem.c | 976 -----------
35 drivers/gpu/ipu-v3/ipu-csi.c | 821 ---------
36 drivers/gpu/ipu-v3/ipu-dc.c | 420 -----
37 drivers/gpu/ipu-v3/ipu-di.c | 745 ---------
38 drivers/gpu/ipu-v3/ipu-dmfc.c | 214 ---
39 drivers/gpu/ipu-v3/ipu-dp.c | 357 ----
40 drivers/gpu/ipu-v3/ipu-ic.c | 761 ---------
41 drivers/gpu/ipu-v3/ipu-image-convert.c | 2475 ----------------------------
42 drivers/gpu/ipu-v3/ipu-pre.c | 346 ----
43 drivers/gpu/ipu-v3/ipu-prg.c | 483 ------
44 drivers/gpu/ipu-v3/ipu-prv.h | 274 ---
45 drivers/gpu/ipu-v3/ipu-smfc.c | 202 ---
46 drivers/gpu/ipu-v3/ipu-vdi.c | 234 ---
47 drivers/video/Kconfig | 2 +-
48 36 files changed, 9898 insertions(+), 9896 deletions(-)
49 create mode 100644 drivers/gpu/imx/Kconfig
50 create mode 100644 drivers/gpu/imx/Makefile
51 create mode 100644 drivers/gpu/imx/ipu-v3/Kconfig
52 create mode 100644 drivers/gpu/imx/ipu-v3/Makefile
53 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-common.c
54 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-cpmem.c
55 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-csi.c
56 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-dc.c
57 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-di.c
58 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-dmfc.c
59 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-dp.c
60 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-ic.c
61 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-image-convert.c
62 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-pre.c
63 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-prg.c
64 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-prv.h
65 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-smfc.c
66 create mode 100644 drivers/gpu/imx/ipu-v3/ipu-vdi.c
67 delete mode 100644 drivers/gpu/ipu-v3/Kconfig
68 delete mode 100644 drivers/gpu/ipu-v3/Makefile
69 delete mode 100644 drivers/gpu/ipu-v3/ipu-common.c
70 delete mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
71 delete mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
72 delete mode 100644 drivers/gpu/ipu-v3/ipu-dc.c
73 delete mode 100644 drivers/gpu/ipu-v3/ipu-di.c
74 delete mode 100644 drivers/gpu/ipu-v3/ipu-dmfc.c
75 delete mode 100644 drivers/gpu/ipu-v3/ipu-dp.c
76 delete mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
77 delete mode 100644 drivers/gpu/ipu-v3/ipu-image-convert.c
78 delete mode 100644 drivers/gpu/ipu-v3/ipu-pre.c
79 delete mode 100644 drivers/gpu/ipu-v3/ipu-prg.c
80 delete mode 100644 drivers/gpu/ipu-v3/ipu-prv.h
81 delete mode 100644 drivers/gpu/ipu-v3/ipu-smfc.c
82 delete mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c
84 --- a/drivers/gpu/Makefile
85 +++ b/drivers/gpu/Makefile
87 # taken to initialize them in the correct order. Link order is the only way
88 # to ensure this currently.
89 obj-$(CONFIG_TEGRA_HOST1X) += host1x/
92 -obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
94 +++ b/drivers/gpu/imx/Kconfig
96 +source "drivers/gpu/imx/ipu-v3/Kconfig"
98 +++ b/drivers/gpu/imx/Makefile
100 +obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
102 +++ b/drivers/gpu/imx/ipu-v3/Kconfig
104 +# SPDX-License-Identifier: GPL-2.0-only
105 +config IMX_IPUV3_CORE
106 + tristate "IPUv3 core support"
107 + depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
108 + depends on DRM || !DRM # if DRM=m, this can't be 'y'
110 + select GENERIC_ALLOCATOR if DRM
111 + select GENERIC_IRQ_CHIP
113 + Choose this if you have a i.MX5/6 system and want to use the Image
114 + Processing Unit. This option only enables IPU base support.
116 +++ b/drivers/gpu/imx/ipu-v3/Makefile
118 +# SPDX-License-Identifier: GPL-2.0
119 +obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
121 +imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
122 + ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
123 + ipu-image-convert.o ipu-smfc.o ipu-vdi.o
126 + imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
129 +++ b/drivers/gpu/imx/ipu-v3/ipu-common.c
131 +// SPDX-License-Identifier: GPL-2.0-or-later
133 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
134 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
136 +#include <linux/module.h>
137 +#include <linux/export.h>
138 +#include <linux/types.h>
139 +#include <linux/reset.h>
140 +#include <linux/platform_device.h>
141 +#include <linux/err.h>
142 +#include <linux/spinlock.h>
143 +#include <linux/delay.h>
144 +#include <linux/interrupt.h>
145 +#include <linux/io.h>
146 +#include <linux/clk.h>
147 +#include <linux/list.h>
148 +#include <linux/irq.h>
149 +#include <linux/irqchip/chained_irq.h>
150 +#include <linux/irqdomain.h>
151 +#include <linux/of_device.h>
152 +#include <linux/of_graph.h>
154 +#include <drm/drm_fourcc.h>
156 +#include <video/imx-ipu-v3.h>
157 +#include "ipu-prv.h"
159 +static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
161 + return readl(ipu->cm_reg + offset);
164 +static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
166 + writel(value, ipu->cm_reg + offset);
169 +int ipu_get_num(struct ipu_soc *ipu)
173 +EXPORT_SYMBOL_GPL(ipu_get_num);
175 +void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
179 + val = ipu_cm_read(ipu, IPU_SRM_PRI2);
180 + val &= ~DP_S_SRM_MODE_MASK;
181 + val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
183 + ipu_cm_write(ipu, val, IPU_SRM_PRI2);
185 +EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
187 +enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
189 + switch (drm_fourcc) {
190 + case DRM_FORMAT_ARGB1555:
191 + case DRM_FORMAT_ABGR1555:
192 + case DRM_FORMAT_RGBA5551:
193 + case DRM_FORMAT_BGRA5551:
194 + case DRM_FORMAT_RGB565:
195 + case DRM_FORMAT_BGR565:
196 + case DRM_FORMAT_RGB888:
197 + case DRM_FORMAT_BGR888:
198 + case DRM_FORMAT_ARGB4444:
199 + case DRM_FORMAT_XRGB8888:
200 + case DRM_FORMAT_XBGR8888:
201 + case DRM_FORMAT_RGBX8888:
202 + case DRM_FORMAT_BGRX8888:
203 + case DRM_FORMAT_ARGB8888:
204 + case DRM_FORMAT_ABGR8888:
205 + case DRM_FORMAT_RGBA8888:
206 + case DRM_FORMAT_BGRA8888:
207 + case DRM_FORMAT_RGB565_A8:
208 + case DRM_FORMAT_BGR565_A8:
209 + case DRM_FORMAT_RGB888_A8:
210 + case DRM_FORMAT_BGR888_A8:
211 + case DRM_FORMAT_RGBX8888_A8:
212 + case DRM_FORMAT_BGRX8888_A8:
213 + return IPUV3_COLORSPACE_RGB;
214 + case DRM_FORMAT_YUYV:
215 + case DRM_FORMAT_UYVY:
216 + case DRM_FORMAT_YUV420:
217 + case DRM_FORMAT_YVU420:
218 + case DRM_FORMAT_YUV422:
219 + case DRM_FORMAT_YVU422:
220 + case DRM_FORMAT_YUV444:
221 + case DRM_FORMAT_YVU444:
222 + case DRM_FORMAT_NV12:
223 + case DRM_FORMAT_NV21:
224 + case DRM_FORMAT_NV16:
225 + case DRM_FORMAT_NV61:
226 + return IPUV3_COLORSPACE_YUV;
228 + return IPUV3_COLORSPACE_UNKNOWN;
231 +EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
233 +enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
235 + switch (pixelformat) {
236 + case V4L2_PIX_FMT_YUV420:
237 + case V4L2_PIX_FMT_YVU420:
238 + case V4L2_PIX_FMT_YUV422P:
239 + case V4L2_PIX_FMT_UYVY:
240 + case V4L2_PIX_FMT_YUYV:
241 + case V4L2_PIX_FMT_NV12:
242 + case V4L2_PIX_FMT_NV21:
243 + case V4L2_PIX_FMT_NV16:
244 + case V4L2_PIX_FMT_NV61:
245 + return IPUV3_COLORSPACE_YUV;
246 + case V4L2_PIX_FMT_RGB565:
247 + case V4L2_PIX_FMT_BGR24:
248 + case V4L2_PIX_FMT_RGB24:
249 + case V4L2_PIX_FMT_ABGR32:
250 + case V4L2_PIX_FMT_XBGR32:
251 + case V4L2_PIX_FMT_BGRA32:
252 + case V4L2_PIX_FMT_BGRX32:
253 + case V4L2_PIX_FMT_RGBA32:
254 + case V4L2_PIX_FMT_RGBX32:
255 + case V4L2_PIX_FMT_ARGB32:
256 + case V4L2_PIX_FMT_XRGB32:
257 + return IPUV3_COLORSPACE_RGB;
259 + return IPUV3_COLORSPACE_UNKNOWN;
262 +EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
264 +bool ipu_pixelformat_is_planar(u32 pixelformat)
266 + switch (pixelformat) {
267 + case V4L2_PIX_FMT_YUV420:
268 + case V4L2_PIX_FMT_YVU420:
269 + case V4L2_PIX_FMT_YUV422P:
270 + case V4L2_PIX_FMT_NV12:
271 + case V4L2_PIX_FMT_NV21:
272 + case V4L2_PIX_FMT_NV16:
273 + case V4L2_PIX_FMT_NV61:
279 +EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
281 +enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
283 + switch (mbus_code & 0xf000) {
285 + return IPUV3_COLORSPACE_RGB;
287 + return IPUV3_COLORSPACE_YUV;
289 + return IPUV3_COLORSPACE_UNKNOWN;
292 +EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
294 +int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
296 + switch (pixelformat) {
297 + case V4L2_PIX_FMT_YUV420:
298 + case V4L2_PIX_FMT_YVU420:
299 + case V4L2_PIX_FMT_YUV422P:
300 + case V4L2_PIX_FMT_NV12:
301 + case V4L2_PIX_FMT_NV21:
302 + case V4L2_PIX_FMT_NV16:
303 + case V4L2_PIX_FMT_NV61:
305 + * for the planar YUV formats, the stride passed to
306 + * cpmem must be the stride in bytes of the Y plane.
307 + * And all the planar YUV formats have an 8-bit
310 + return (8 * pixel_stride) >> 3;
311 + case V4L2_PIX_FMT_RGB565:
312 + case V4L2_PIX_FMT_YUYV:
313 + case V4L2_PIX_FMT_UYVY:
314 + return (16 * pixel_stride) >> 3;
315 + case V4L2_PIX_FMT_BGR24:
316 + case V4L2_PIX_FMT_RGB24:
317 + return (24 * pixel_stride) >> 3;
318 + case V4L2_PIX_FMT_BGR32:
319 + case V4L2_PIX_FMT_RGB32:
320 + case V4L2_PIX_FMT_XBGR32:
321 + case V4L2_PIX_FMT_XRGB32:
322 + return (32 * pixel_stride) >> 3;
329 +EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
331 +int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
332 + bool hflip, bool vflip)
358 + *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
361 +EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
363 +int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
364 + bool hflip, bool vflip)
368 + r90 = ((u32)mode >> 2) & 0x1;
369 + hf = ((u32)mode >> 1) & 0x1;
370 + vf = ((u32)mode >> 0) & 0x1;
374 + switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
375 + case IPU_ROTATE_NONE:
378 + case IPU_ROTATE_90_RIGHT:
381 + case IPU_ROTATE_180:
384 + case IPU_ROTATE_90_LEFT:
393 +EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
395 +struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
397 + struct ipuv3_channel *channel;
399 + dev_dbg(ipu->dev, "%s %d\n", __func__, num);
402 + return ERR_PTR(-ENODEV);
404 + mutex_lock(&ipu->channel_lock);
406 + list_for_each_entry(channel, &ipu->channels, list) {
407 + if (channel->num == num) {
408 + channel = ERR_PTR(-EBUSY);
413 + channel = kzalloc(sizeof(*channel), GFP_KERNEL);
415 + channel = ERR_PTR(-ENOMEM);
419 + channel->num = num;
420 + channel->ipu = ipu;
421 + list_add(&channel->list, &ipu->channels);
424 + mutex_unlock(&ipu->channel_lock);
428 +EXPORT_SYMBOL_GPL(ipu_idmac_get);
430 +void ipu_idmac_put(struct ipuv3_channel *channel)
432 + struct ipu_soc *ipu = channel->ipu;
434 + dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
436 + mutex_lock(&ipu->channel_lock);
438 + list_del(&channel->list);
441 + mutex_unlock(&ipu->channel_lock);
443 +EXPORT_SYMBOL_GPL(ipu_idmac_put);
445 +#define idma_mask(ch) (1 << ((ch) & 0x1f))
448 + * This is an undocumented feature, a write one to a channel bit in
449 + * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
450 + * internal current buffer pointer so that transfers start from buffer
451 + * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
452 + * only says these are read-only registers). This operation is required
453 + * for channel linking to work correctly, for instance video capture
454 + * pipelines that carry out image rotations will fail after the first
455 + * streaming unless this function is called for each channel before
456 + * re-enabling the channels.
458 +static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
460 + struct ipu_soc *ipu = channel->ipu;
461 + unsigned int chno = channel->num;
463 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
466 +void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
469 + struct ipu_soc *ipu = channel->ipu;
470 + unsigned long flags;
473 + spin_lock_irqsave(&ipu->lock, flags);
475 + reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
477 + reg |= idma_mask(channel->num);
479 + reg &= ~idma_mask(channel->num);
480 + ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
482 + __ipu_idmac_reset_current_buffer(channel);
484 + spin_unlock_irqrestore(&ipu->lock, flags);
486 +EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
488 +static const struct {
492 +} idmac_lock_en_info[] = {
493 + { .chnum = 5, .reg = IDMAC_CH_LOCK_EN_1, .shift = 0, },
494 + { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift = 2, },
495 + { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift = 4, },
496 + { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift = 6, },
497 + { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift = 8, },
498 + { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
499 + { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
500 + { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
501 + { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
502 + { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
503 + { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
504 + { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift = 0, },
505 + { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift = 2, },
506 + { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift = 4, },
507 + { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift = 6, },
508 + { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift = 8, },
509 + { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
512 +int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
514 + struct ipu_soc *ipu = channel->ipu;
515 + unsigned long flags;
516 + u32 bursts, regval;
519 + switch (num_bursts) {
522 + bursts = 0x00; /* locking disabled */
538 + * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
539 + * i.MX53 channel arbitration locking doesn't seem to work properly.
540 + * Allow enabling the lock feature on IPUv3H / i.MX6 only.
542 + if (bursts && ipu->ipu_type != IPUV3H)
545 + for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
546 + if (channel->num == idmac_lock_en_info[i].chnum)
549 + if (i >= ARRAY_SIZE(idmac_lock_en_info))
552 + spin_lock_irqsave(&ipu->lock, flags);
554 + regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
555 + regval &= ~(0x03 << idmac_lock_en_info[i].shift);
556 + regval |= (bursts << idmac_lock_en_info[i].shift);
557 + ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
559 + spin_unlock_irqrestore(&ipu->lock, flags);
563 +EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
565 +int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
567 + unsigned long lock_flags;
570 + spin_lock_irqsave(&ipu->lock, lock_flags);
572 + val = ipu_cm_read(ipu, IPU_DISP_GEN);
574 + if (mask & IPU_CONF_DI0_EN)
575 + val |= IPU_DI0_COUNTER_RELEASE;
576 + if (mask & IPU_CONF_DI1_EN)
577 + val |= IPU_DI1_COUNTER_RELEASE;
579 + ipu_cm_write(ipu, val, IPU_DISP_GEN);
581 + val = ipu_cm_read(ipu, IPU_CONF);
583 + ipu_cm_write(ipu, val, IPU_CONF);
585 + spin_unlock_irqrestore(&ipu->lock, lock_flags);
589 +EXPORT_SYMBOL_GPL(ipu_module_enable);
591 +int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
593 + unsigned long lock_flags;
596 + spin_lock_irqsave(&ipu->lock, lock_flags);
598 + val = ipu_cm_read(ipu, IPU_CONF);
600 + ipu_cm_write(ipu, val, IPU_CONF);
602 + val = ipu_cm_read(ipu, IPU_DISP_GEN);
604 + if (mask & IPU_CONF_DI0_EN)
605 + val &= ~IPU_DI0_COUNTER_RELEASE;
606 + if (mask & IPU_CONF_DI1_EN)
607 + val &= ~IPU_DI1_COUNTER_RELEASE;
609 + ipu_cm_write(ipu, val, IPU_DISP_GEN);
611 + spin_unlock_irqrestore(&ipu->lock, lock_flags);
615 +EXPORT_SYMBOL_GPL(ipu_module_disable);
617 +int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
619 + struct ipu_soc *ipu = channel->ipu;
620 + unsigned int chno = channel->num;
622 + return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
624 +EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
626 +bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
628 + struct ipu_soc *ipu = channel->ipu;
629 + unsigned long flags;
632 + spin_lock_irqsave(&ipu->lock, flags);
635 + reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
638 + reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
641 + reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
644 + spin_unlock_irqrestore(&ipu->lock, flags);
646 + return ((reg & idma_mask(channel->num)) != 0);
648 +EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
650 +void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
652 + struct ipu_soc *ipu = channel->ipu;
653 + unsigned int chno = channel->num;
654 + unsigned long flags;
656 + spin_lock_irqsave(&ipu->lock, flags);
658 + /* Mark buffer as ready. */
660 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
662 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
664 + spin_unlock_irqrestore(&ipu->lock, flags);
666 +EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
668 +void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
670 + struct ipu_soc *ipu = channel->ipu;
671 + unsigned int chno = channel->num;
672 + unsigned long flags;
674 + spin_lock_irqsave(&ipu->lock, flags);
676 + ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
679 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
682 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
685 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
690 + ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
692 + spin_unlock_irqrestore(&ipu->lock, flags);
694 +EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
696 +int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
698 + struct ipu_soc *ipu = channel->ipu;
700 + unsigned long flags;
702 + spin_lock_irqsave(&ipu->lock, flags);
704 + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
705 + val |= idma_mask(channel->num);
706 + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
708 + spin_unlock_irqrestore(&ipu->lock, flags);
712 +EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
714 +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
716 + return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
718 +EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
720 +int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
722 + struct ipu_soc *ipu = channel->ipu;
723 + unsigned long timeout;
725 + timeout = jiffies + msecs_to_jiffies(ms);
726 + while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
727 + idma_mask(channel->num)) {
728 + if (time_after(jiffies, timeout))
735 +EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
737 +int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
739 + struct ipu_soc *ipu = channel->ipu;
741 + unsigned long flags;
743 + spin_lock_irqsave(&ipu->lock, flags);
745 + /* Disable DMA channel(s) */
746 + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
747 + val &= ~idma_mask(channel->num);
748 + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
750 + __ipu_idmac_reset_current_buffer(channel);
752 + /* Set channel buffers NOT to be ready */
753 + ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
755 + if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
756 + idma_mask(channel->num)) {
757 + ipu_cm_write(ipu, idma_mask(channel->num),
758 + IPU_CHA_BUF0_RDY(channel->num));
761 + if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
762 + idma_mask(channel->num)) {
763 + ipu_cm_write(ipu, idma_mask(channel->num),
764 + IPU_CHA_BUF1_RDY(channel->num));
767 + ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
769 + /* Reset the double buffer */
770 + val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
771 + val &= ~idma_mask(channel->num);
772 + ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
774 + spin_unlock_irqrestore(&ipu->lock, flags);
778 +EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
781 + * The imx6 rev. D TRM says that enabling the WM feature will increase
782 + * a channel's priority. Refer to Table 36-8 Calculated priority value.
783 + * The sub-module that is the sink or source for the channel must enable
784 + * watermark signal for this to take effect (SMFC_WM for instance).
786 +void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
788 + struct ipu_soc *ipu = channel->ipu;
789 + unsigned long flags;
792 + spin_lock_irqsave(&ipu->lock, flags);
794 + val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
796 + val |= 1 << (channel->num % 32);
798 + val &= ~(1 << (channel->num % 32));
799 + ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
801 + spin_unlock_irqrestore(&ipu->lock, flags);
803 +EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
805 +static int ipu_memory_reset(struct ipu_soc *ipu)
807 + unsigned long timeout;
809 + ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
811 + timeout = jiffies + msecs_to_jiffies(1000);
812 + while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
813 + if (time_after(jiffies, timeout))
822 + * Set the source mux for the given CSI. Selects either parallel or
823 + * MIPI CSI2 sources.
825 +void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
827 + unsigned long flags;
830 + mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
831 + IPU_CONF_CSI0_DATA_SOURCE;
833 + spin_lock_irqsave(&ipu->lock, flags);
835 + val = ipu_cm_read(ipu, IPU_CONF);
840 + ipu_cm_write(ipu, val, IPU_CONF);
842 + spin_unlock_irqrestore(&ipu->lock, flags);
844 +EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
847 + * Set the source mux for the IC. Selects either CSI[01] or the VDI.
849 +void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
851 + unsigned long flags;
854 + spin_lock_irqsave(&ipu->lock, flags);
856 + val = ipu_cm_read(ipu, IPU_CONF);
858 + val |= IPU_CONF_IC_INPUT;
860 + val &= ~IPU_CONF_IC_INPUT;
863 + val |= IPU_CONF_CSI_SEL;
865 + val &= ~IPU_CONF_CSI_SEL;
867 + ipu_cm_write(ipu, val, IPU_CONF);
869 + spin_unlock_irqrestore(&ipu->lock, flags);
871 +EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
874 +/* Frame Synchronization Unit Channel Linking */
876 +struct fsu_link_reg_info {
883 +struct fsu_link_info {
884 + struct fsu_link_reg_info src;
885 + struct fsu_link_reg_info sink;
888 +static const struct fsu_link_info fsu_link_info[] = {
890 + .src = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
891 + FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
892 + .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
893 + FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
895 + .src = { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
896 + FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
897 + .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
898 + FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
900 + .src = { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
901 + FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
902 + .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
903 + FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
905 + .src = { IPUV3_CHANNEL_CSI_DIRECT, 0 },
906 + .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
907 + FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
911 +static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
915 + for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
916 + if (src == fsu_link_info[i].src.chno &&
917 + sink == fsu_link_info[i].sink.chno)
918 + return &fsu_link_info[i];
925 + * Links a source channel to a sink channel in the FSU.
927 +int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
929 + const struct fsu_link_info *link;
930 + u32 src_reg, sink_reg;
931 + unsigned long flags;
933 + link = find_fsu_link_info(src_ch, sink_ch);
937 + spin_lock_irqsave(&ipu->lock, flags);
939 + if (link->src.mask) {
940 + src_reg = ipu_cm_read(ipu, link->src.reg);
941 + src_reg &= ~link->src.mask;
942 + src_reg |= link->src.val;
943 + ipu_cm_write(ipu, src_reg, link->src.reg);
946 + if (link->sink.mask) {
947 + sink_reg = ipu_cm_read(ipu, link->sink.reg);
948 + sink_reg &= ~link->sink.mask;
949 + sink_reg |= link->sink.val;
950 + ipu_cm_write(ipu, sink_reg, link->sink.reg);
953 + spin_unlock_irqrestore(&ipu->lock, flags);
956 +EXPORT_SYMBOL_GPL(ipu_fsu_link);
959 + * Unlinks source and sink channels in the FSU.
961 +int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
963 + const struct fsu_link_info *link;
964 + u32 src_reg, sink_reg;
965 + unsigned long flags;
967 + link = find_fsu_link_info(src_ch, sink_ch);
971 + spin_lock_irqsave(&ipu->lock, flags);
973 + if (link->src.mask) {
974 + src_reg = ipu_cm_read(ipu, link->src.reg);
975 + src_reg &= ~link->src.mask;
976 + ipu_cm_write(ipu, src_reg, link->src.reg);
979 + if (link->sink.mask) {
980 + sink_reg = ipu_cm_read(ipu, link->sink.reg);
981 + sink_reg &= ~link->sink.mask;
982 + ipu_cm_write(ipu, sink_reg, link->sink.reg);
985 + spin_unlock_irqrestore(&ipu->lock, flags);
988 +EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
990 +/* Link IDMAC channels in the FSU */
991 +int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
993 + return ipu_fsu_link(src->ipu, src->num, sink->num);
995 +EXPORT_SYMBOL_GPL(ipu_idmac_link);
997 +/* Unlink IDMAC channels in the FSU */
998 +int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
1000 + return ipu_fsu_unlink(src->ipu, src->num, sink->num);
1002 +EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
1004 +struct ipu_devtype {
1006 + unsigned long cm_ofs;
1007 + unsigned long cpmem_ofs;
1008 + unsigned long srm_ofs;
1009 + unsigned long tpm_ofs;
1010 + unsigned long csi0_ofs;
1011 + unsigned long csi1_ofs;
1012 + unsigned long ic_ofs;
1013 + unsigned long disp0_ofs;
1014 + unsigned long disp1_ofs;
1015 + unsigned long dc_tmpl_ofs;
1016 + unsigned long vdi_ofs;
1017 + enum ipuv3_type type;
1020 +static struct ipu_devtype ipu_type_imx51 = {
1021 + .name = "IPUv3EX",
1022 + .cm_ofs = 0x1e000000,
1023 + .cpmem_ofs = 0x1f000000,
1024 + .srm_ofs = 0x1f040000,
1025 + .tpm_ofs = 0x1f060000,
1026 + .csi0_ofs = 0x1e030000,
1027 + .csi1_ofs = 0x1e038000,
1028 + .ic_ofs = 0x1e020000,
1029 + .disp0_ofs = 0x1e040000,
1030 + .disp1_ofs = 0x1e048000,
1031 + .dc_tmpl_ofs = 0x1f080000,
1032 + .vdi_ofs = 0x1e068000,
1036 +static struct ipu_devtype ipu_type_imx53 = {
1038 + .cm_ofs = 0x06000000,
1039 + .cpmem_ofs = 0x07000000,
1040 + .srm_ofs = 0x07040000,
1041 + .tpm_ofs = 0x07060000,
1042 + .csi0_ofs = 0x06030000,
1043 + .csi1_ofs = 0x06038000,
1044 + .ic_ofs = 0x06020000,
1045 + .disp0_ofs = 0x06040000,
1046 + .disp1_ofs = 0x06048000,
1047 + .dc_tmpl_ofs = 0x07080000,
1048 + .vdi_ofs = 0x06068000,
1052 +static struct ipu_devtype ipu_type_imx6q = {
1054 + .cm_ofs = 0x00200000,
1055 + .cpmem_ofs = 0x00300000,
1056 + .srm_ofs = 0x00340000,
1057 + .tpm_ofs = 0x00360000,
1058 + .csi0_ofs = 0x00230000,
1059 + .csi1_ofs = 0x00238000,
1060 + .ic_ofs = 0x00220000,
1061 + .disp0_ofs = 0x00240000,
1062 + .disp1_ofs = 0x00248000,
1063 + .dc_tmpl_ofs = 0x00380000,
1064 + .vdi_ofs = 0x00268000,
1068 +static const struct of_device_id imx_ipu_dt_ids[] = {
1069 + { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
1070 + { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
1071 + { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
1072 + { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
1073 + { /* sentinel */ }
1075 +MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
1077 +static int ipu_submodules_init(struct ipu_soc *ipu,
1078 + struct platform_device *pdev, unsigned long ipu_base,
1079 + struct clk *ipu_clk)
1083 + struct device *dev = &pdev->dev;
1084 + const struct ipu_devtype *devtype = ipu->devtype;
1086 + ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
1092 + ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
1093 + IPU_CONF_CSI0_EN, ipu_clk);
1099 + ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
1100 + IPU_CONF_CSI1_EN, ipu_clk);
1106 + ret = ipu_ic_init(ipu, dev,
1107 + ipu_base + devtype->ic_ofs,
1108 + ipu_base + devtype->tpm_ofs);
1114 + ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
1115 + IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
1116 + IPU_CONF_IC_INPUT);
1122 + ret = ipu_image_convert_init(ipu, dev);
1124 + unit = "image_convert";
1125 + goto err_image_convert;
1128 + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
1129 + IPU_CONF_DI0_EN, ipu_clk);
1135 + ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
1136 + IPU_CONF_DI1_EN, ipu_clk);
1142 + ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
1143 + IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
1145 + unit = "dc_template";
1149 + ret = ipu_dmfc_init(ipu, dev, ipu_base +
1150 + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
1156 + ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
1162 + ret = ipu_smfc_init(ipu, dev, ipu_base +
1163 + devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
1174 + ipu_dmfc_exit(ipu);
1178 + ipu_di_exit(ipu, 1);
1180 + ipu_di_exit(ipu, 0);
1182 + ipu_image_convert_exit(ipu);
1184 + ipu_vdi_exit(ipu);
1188 + ipu_csi_exit(ipu, 1);
1190 + ipu_csi_exit(ipu, 0);
1192 + ipu_cpmem_exit(ipu);
1194 + dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
1198 +static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
1200 + unsigned long status;
1203 + for (i = 0; i < num_regs; i++) {
1205 + status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
1206 + status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
1208 + for_each_set_bit(bit, &status, 32) {
1209 + irq = irq_linear_revmap(ipu->domain,
1210 + regs[i] * 32 + bit);
1212 + generic_handle_irq(irq);
1217 +static void ipu_irq_handler(struct irq_desc *desc)
1219 + struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
1220 + struct irq_chip *chip = irq_desc_get_chip(desc);
1221 + static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
1223 + chained_irq_enter(chip, desc);
1225 + ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
1227 + chained_irq_exit(chip, desc);
1230 +static void ipu_err_irq_handler(struct irq_desc *desc)
1232 + struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
1233 + struct irq_chip *chip = irq_desc_get_chip(desc);
1234 + static const int int_reg[] = { 4, 5, 8, 9};
1236 + chained_irq_enter(chip, desc);
1238 + ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
1240 + chained_irq_exit(chip, desc);
1243 +int ipu_map_irq(struct ipu_soc *ipu, int irq)
1247 + virq = irq_linear_revmap(ipu->domain, irq);
1249 + virq = irq_create_mapping(ipu->domain, irq);
1253 +EXPORT_SYMBOL_GPL(ipu_map_irq);
1255 +int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
1256 + enum ipu_channel_irq irq_type)
1258 + return ipu_map_irq(ipu, irq_type + channel->num);
1260 +EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
1262 +static void ipu_submodules_exit(struct ipu_soc *ipu)
1264 + ipu_smfc_exit(ipu);
1266 + ipu_dmfc_exit(ipu);
1268 + ipu_di_exit(ipu, 1);
1269 + ipu_di_exit(ipu, 0);
1270 + ipu_image_convert_exit(ipu);
1271 + ipu_vdi_exit(ipu);
1273 + ipu_csi_exit(ipu, 1);
1274 + ipu_csi_exit(ipu, 0);
1275 + ipu_cpmem_exit(ipu);
1278 +static int platform_remove_devices_fn(struct device *dev, void *unused)
1280 + struct platform_device *pdev = to_platform_device(dev);
1282 + platform_device_unregister(pdev);
1287 +static void platform_device_unregister_children(struct platform_device *pdev)
1289 + device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
1292 +struct ipu_platform_reg {
1293 + struct ipu_client_platformdata pdata;
1297 +/* These must be in the order of the corresponding device tree port nodes */
1298 +static struct ipu_platform_reg client_reg[] = {
1302 + .dma[0] = IPUV3_CHANNEL_CSI0,
1303 + .dma[1] = -EINVAL,
1305 + .name = "imx-ipuv3-csi",
1309 + .dma[0] = IPUV3_CHANNEL_CSI1,
1310 + .dma[1] = -EINVAL,
1312 + .name = "imx-ipuv3-csi",
1317 + .dp = IPU_DP_FLOW_SYNC_BG,
1318 + .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
1319 + .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
1321 + .name = "imx-ipuv3-crtc",
1327 + .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
1328 + .dma[1] = -EINVAL,
1330 + .name = "imx-ipuv3-crtc",
1334 +static DEFINE_MUTEX(ipu_client_id_mutex);
1335 +static int ipu_client_id;
1337 +static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
1339 + struct device *dev = ipu->dev;
1343 + mutex_lock(&ipu_client_id_mutex);
1344 + id = ipu_client_id;
1345 + ipu_client_id += ARRAY_SIZE(client_reg);
1346 + mutex_unlock(&ipu_client_id_mutex);
1348 + for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
1349 + struct ipu_platform_reg *reg = &client_reg[i];
1350 + struct platform_device *pdev;
1351 + struct device_node *of_node;
1353 + /* Associate subdevice with the corresponding port node */
1354 + of_node = of_graph_get_port_by_id(dev->of_node, i);
1357 + "no port@%d node in %pOF, not using %s%d\n",
1359 + (i / 2) ? "DI" : "CSI", i % 2);
1363 + pdev = platform_device_alloc(reg->name, id++);
1366 + goto err_register;
1369 + pdev->dev.parent = dev;
1371 + reg->pdata.of_node = of_node;
1372 + ret = platform_device_add_data(pdev, ®->pdata,
1373 + sizeof(reg->pdata));
1375 + ret = platform_device_add(pdev);
1377 + platform_device_put(pdev);
1378 + goto err_register;
1385 + platform_device_unregister_children(to_platform_device(dev));
1391 +static int ipu_irq_init(struct ipu_soc *ipu)
1393 + struct irq_chip_generic *gc;
1394 + struct irq_chip_type *ct;
1395 + unsigned long unused[IPU_NUM_IRQS / 32] = {
1396 + 0x400100d0, 0xffe000fd,
1397 + 0x400100d0, 0xffe000fd,
1398 + 0x400100d0, 0xffe000fd,
1399 + 0x4077ffff, 0xffe7e1fd,
1400 + 0x23fffffe, 0x8880fff0,
1401 + 0xf98fe7d0, 0xfff81fff,
1402 + 0x400100d0, 0xffe000fd,
1407 + ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
1408 + &irq_generic_chip_ops, ipu);
1409 + if (!ipu->domain) {
1410 + dev_err(ipu->dev, "failed to add irq domain\n");
1414 + ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
1415 + handle_level_irq, 0, 0, 0);
1417 + dev_err(ipu->dev, "failed to alloc generic irq chips\n");
1418 + irq_domain_remove(ipu->domain);
1422 + /* Mask and clear all interrupts */
1423 + for (i = 0; i < IPU_NUM_IRQS; i += 32) {
1424 + ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
1425 + ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
1428 + for (i = 0; i < IPU_NUM_IRQS; i += 32) {
1429 + gc = irq_get_domain_generic_chip(ipu->domain, i);
1430 + gc->reg_base = ipu->cm_reg;
1431 + gc->unused = unused[i / 32];
1432 + ct = gc->chip_types;
1433 + ct->chip.irq_ack = irq_gc_ack_set_bit;
1434 + ct->chip.irq_mask = irq_gc_mask_clr_bit;
1435 + ct->chip.irq_unmask = irq_gc_mask_set_bit;
1436 + ct->regs.ack = IPU_INT_STAT(i / 32);
1437 + ct->regs.mask = IPU_INT_CTRL(i / 32);
1440 + irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
1441 + irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
1447 +static void ipu_irq_exit(struct ipu_soc *ipu)
1451 + irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
1452 + irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
1454 + /* TODO: remove irq_domain_generic_chips */
1456 + for (i = 0; i < IPU_NUM_IRQS; i++) {
1457 + irq = irq_linear_revmap(ipu->domain, i);
1459 + irq_dispose_mapping(irq);
1462 + irq_domain_remove(ipu->domain);
1465 +void ipu_dump(struct ipu_soc *ipu)
1469 + dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
1470 + ipu_cm_read(ipu, IPU_CONF));
1471 + dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
1472 + ipu_idmac_read(ipu, IDMAC_CONF));
1473 + dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
1474 + ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
1475 + dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
1476 + ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
1477 + dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
1478 + ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
1479 + dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
1480 + ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
1481 + dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
1482 + ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
1483 + dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
1484 + ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
1485 + dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
1486 + ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
1487 + dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
1488 + ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
1489 + dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
1490 + ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
1491 + dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
1492 + ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
1493 + dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
1494 + ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
1495 + dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
1496 + ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
1497 + for (i = 0; i < 15; i++)
1498 + dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
1499 + ipu_cm_read(ipu, IPU_INT_CTRL(i)));
1501 +EXPORT_SYMBOL_GPL(ipu_dump);
1503 +static int ipu_probe(struct platform_device *pdev)
1505 + struct device_node *np = pdev->dev.of_node;
1506 + struct ipu_soc *ipu;
1507 + struct resource *res;
1508 + unsigned long ipu_base;
1509 + int ret, irq_sync, irq_err;
1510 + const struct ipu_devtype *devtype;
1512 + devtype = of_device_get_match_data(&pdev->dev);
1516 + irq_sync = platform_get_irq(pdev, 0);
1517 + irq_err = platform_get_irq(pdev, 1);
1518 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1520 + dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
1521 + irq_sync, irq_err);
1523 + if (!res || irq_sync < 0 || irq_err < 0)
1526 + ipu_base = res->start;
1528 + ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
1532 + ipu->id = of_alias_get_id(np, "ipu");
1536 + if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
1537 + IS_ENABLED(CONFIG_DRM)) {
1538 + ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
1539 + "fsl,prg", ipu->id);
1540 + if (!ipu->prg_priv)
1541 + return -EPROBE_DEFER;
1544 + ipu->devtype = devtype;
1545 + ipu->ipu_type = devtype->type;
1547 + spin_lock_init(&ipu->lock);
1548 + mutex_init(&ipu->channel_lock);
1549 + INIT_LIST_HEAD(&ipu->channels);
1551 + dev_dbg(&pdev->dev, "cm_reg: 0x%08lx\n",
1552 + ipu_base + devtype->cm_ofs);
1553 + dev_dbg(&pdev->dev, "idmac: 0x%08lx\n",
1554 + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
1555 + dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n",
1556 + ipu_base + devtype->cpmem_ofs);
1557 + dev_dbg(&pdev->dev, "csi0: 0x%08lx\n",
1558 + ipu_base + devtype->csi0_ofs);
1559 + dev_dbg(&pdev->dev, "csi1: 0x%08lx\n",
1560 + ipu_base + devtype->csi1_ofs);
1561 + dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
1562 + ipu_base + devtype->ic_ofs);
1563 + dev_dbg(&pdev->dev, "disp0: 0x%08lx\n",
1564 + ipu_base + devtype->disp0_ofs);
1565 + dev_dbg(&pdev->dev, "disp1: 0x%08lx\n",
1566 + ipu_base + devtype->disp1_ofs);
1567 + dev_dbg(&pdev->dev, "srm: 0x%08lx\n",
1568 + ipu_base + devtype->srm_ofs);
1569 + dev_dbg(&pdev->dev, "tpm: 0x%08lx\n",
1570 + ipu_base + devtype->tpm_ofs);
1571 + dev_dbg(&pdev->dev, "dc: 0x%08lx\n",
1572 + ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
1573 + dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
1574 + ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
1575 + dev_dbg(&pdev->dev, "dmfc: 0x%08lx\n",
1576 + ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
1577 + dev_dbg(&pdev->dev, "vdi: 0x%08lx\n",
1578 + ipu_base + devtype->vdi_ofs);
1580 + ipu->cm_reg = devm_ioremap(&pdev->dev,
1581 + ipu_base + devtype->cm_ofs, PAGE_SIZE);
1582 + ipu->idmac_reg = devm_ioremap(&pdev->dev,
1583 + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
1586 + if (!ipu->cm_reg || !ipu->idmac_reg)
1589 + ipu->clk = devm_clk_get(&pdev->dev, "bus");
1590 + if (IS_ERR(ipu->clk)) {
1591 + ret = PTR_ERR(ipu->clk);
1592 + dev_err(&pdev->dev, "clk_get failed with %d", ret);
1596 + platform_set_drvdata(pdev, ipu);
1598 + ret = clk_prepare_enable(ipu->clk);
1600 + dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
1604 + ipu->dev = &pdev->dev;
1605 + ipu->irq_sync = irq_sync;
1606 + ipu->irq_err = irq_err;
1608 + ret = device_reset(&pdev->dev);
1610 + dev_err(&pdev->dev, "failed to reset: %d\n", ret);
1611 + goto out_failed_reset;
1613 + ret = ipu_memory_reset(ipu);
1615 + goto out_failed_reset;
1617 + ret = ipu_irq_init(ipu);
1619 + goto out_failed_irq;
1621 + /* Set MCU_T to divide MCU access window into 2 */
1622 + ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
1625 + ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
1627 + goto failed_submodules_init;
1629 + ret = ipu_add_client_devices(ipu, ipu_base);
1631 + dev_err(&pdev->dev, "adding client devices failed with %d\n",
1633 + goto failed_add_clients;
1636 + dev_info(&pdev->dev, "%s probed\n", devtype->name);
1640 +failed_add_clients:
1641 + ipu_submodules_exit(ipu);
1642 +failed_submodules_init:
1643 + ipu_irq_exit(ipu);
1646 + clk_disable_unprepare(ipu->clk);
1650 +static int ipu_remove(struct platform_device *pdev)
1652 + struct ipu_soc *ipu = platform_get_drvdata(pdev);
1654 + platform_device_unregister_children(pdev);
1655 + ipu_submodules_exit(ipu);
1656 + ipu_irq_exit(ipu);
1658 + clk_disable_unprepare(ipu->clk);
1663 +static struct platform_driver imx_ipu_driver = {
1665 + .name = "imx-ipuv3",
1666 + .of_match_table = imx_ipu_dt_ids,
1668 + .probe = ipu_probe,
1669 + .remove = ipu_remove,
1672 +static struct platform_driver * const drivers[] = {
1673 +#if IS_ENABLED(CONFIG_DRM)
1680 +static int __init imx_ipu_init(void)
1682 + return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
1684 +module_init(imx_ipu_init);
1686 +static void __exit imx_ipu_exit(void)
1688 + platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
1690 +module_exit(imx_ipu_exit);
1692 +MODULE_ALIAS("platform:imx-ipuv3");
1693 +MODULE_DESCRIPTION("i.MX IPU v3 driver");
1694 +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
1695 +MODULE_LICENSE("GPL");
1697 +++ b/drivers/gpu/imx/ipu-v3/ipu-cpmem.c
1699 +// SPDX-License-Identifier: GPL-2.0-or-later
1701 + * Copyright (C) 2012 Mentor Graphics Inc.
1702 + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
1704 +#include <linux/types.h>
1705 +#include <linux/bitrev.h>
1706 +#include <linux/io.h>
1707 +#include <linux/sizes.h>
1708 +#include <drm/drm_fourcc.h>
1709 +#include "ipu-prv.h"
1711 +struct ipu_cpmem_word {
1716 +struct ipu_ch_param {
1717 + struct ipu_cpmem_word word[2];
1721 + struct ipu_ch_param __iomem *base;
1725 + struct ipu_soc *ipu;
1728 +#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
1730 +#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
1731 +#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
1732 +#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
1733 +#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
1734 +#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
1735 +#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
1736 +#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
1738 +#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
1739 +#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
1740 +#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
1741 +#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
1742 +#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
1743 +#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
1744 +#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
1745 +#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
1746 +#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
1747 +#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
1748 +#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
1749 +#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
1750 +#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
1751 +#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
1752 +#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
1753 +#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
1754 +#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
1755 +#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
1756 +#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
1757 +#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
1758 +#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
1759 +#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
1760 +#define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3)
1761 +#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
1762 +#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
1763 +#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
1764 +#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
1765 +#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
1766 +#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
1767 +#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
1768 +#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
1769 +#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
1770 +#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
1771 +#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
1772 +#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
1773 +#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
1774 +#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
1775 +#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
1776 +#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
1777 +#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
1778 +#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
1779 +#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
1780 +#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
1781 +#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
1782 +#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
1783 +#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
1784 +#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
1785 +#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
1786 +#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
1787 +#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
1788 +#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
1790 +static inline struct ipu_ch_param __iomem *
1791 +ipu_get_cpmem(struct ipuv3_channel *ch)
1793 + struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
1795 + return cpmem->base + ch->num;
1798 +static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
1800 + struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
1801 + u32 bit = (wbs >> 8) % 160;
1802 + u32 size = wbs & 0xff;
1803 + u32 word = (wbs >> 8) / 160;
1805 + u32 ofs = bit % 32;
1806 + u32 mask = (1 << size) - 1;
1809 + pr_debug("%s %d %d %d\n", __func__, word, bit , size);
1811 + val = readl(&base->word[word].data[i]);
1812 + val &= ~(mask << ofs);
1814 + writel(val, &base->word[word].data[i]);
1816 + if ((bit + size - 1) / 32 > i) {
1817 + val = readl(&base->word[word].data[i + 1]);
1818 + val &= ~(mask >> (ofs ? (32 - ofs) : 0));
1819 + val |= v >> (ofs ? (32 - ofs) : 0);
1820 + writel(val, &base->word[word].data[i + 1]);
1824 +static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
1826 + struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
1827 + u32 bit = (wbs >> 8) % 160;
1828 + u32 size = wbs & 0xff;
1829 + u32 word = (wbs >> 8) / 160;
1831 + u32 ofs = bit % 32;
1832 + u32 mask = (1 << size) - 1;
1835 + pr_debug("%s %d %d %d\n", __func__, word, bit , size);
1837 + val = (readl(&base->word[word].data[i]) >> ofs) & mask;
1839 + if ((bit + size - 1) / 32 > i) {
1842 + tmp = readl(&base->word[word].data[i + 1]);
1843 + tmp &= mask >> (ofs ? (32 - ofs) : 0);
1844 + val |= tmp << (ofs ? (32 - ofs) : 0);
1851 + * The V4L2 spec defines packed RGB formats in memory byte order, which from
1852 + * point of view of the IPU corresponds to little-endian words with the first
1853 + * component in the least significant bits.
1854 + * The DRM pixel formats and IPU internal representation are ordered the other
1855 + * way around, with the first named component ordered at the most significant
1856 + * bits. Further, V4L2 formats are not well defined:
1857 + * https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
1858 + * We choose the interpretation which matches GStreamer behavior.
1860 +static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
1862 + switch (pixelformat) {
1863 + case V4L2_PIX_FMT_RGB565:
1865 + * Here we choose the 'corrected' interpretation of RGBP, a
1866 + * little-endian 16-bit word with the red component at the most
1867 + * significant bits:
1868 + * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
1870 + return DRM_FORMAT_RGB565;
1871 + case V4L2_PIX_FMT_BGR24:
1872 + /* B G R <=> [24:0] R:G:B */
1873 + return DRM_FORMAT_RGB888;
1874 + case V4L2_PIX_FMT_RGB24:
1875 + /* R G B <=> [24:0] B:G:R */
1876 + return DRM_FORMAT_BGR888;
1877 + case V4L2_PIX_FMT_BGR32:
1878 + /* B G R A <=> [32:0] A:B:G:R */
1879 + return DRM_FORMAT_XRGB8888;
1880 + case V4L2_PIX_FMT_RGB32:
1881 + /* R G B A <=> [32:0] A:B:G:R */
1882 + return DRM_FORMAT_XBGR8888;
1883 + case V4L2_PIX_FMT_ABGR32:
1884 + /* B G R A <=> [32:0] A:R:G:B */
1885 + return DRM_FORMAT_ARGB8888;
1886 + case V4L2_PIX_FMT_XBGR32:
1887 + /* B G R X <=> [32:0] X:R:G:B */
1888 + return DRM_FORMAT_XRGB8888;
1889 + case V4L2_PIX_FMT_BGRA32:
1890 + /* A B G R <=> [32:0] R:G:B:A */
1891 + return DRM_FORMAT_RGBA8888;
1892 + case V4L2_PIX_FMT_BGRX32:
1893 + /* X B G R <=> [32:0] R:G:B:X */
1894 + return DRM_FORMAT_RGBX8888;
1895 + case V4L2_PIX_FMT_RGBA32:
1896 + /* R G B A <=> [32:0] A:B:G:R */
1897 + return DRM_FORMAT_ABGR8888;
1898 + case V4L2_PIX_FMT_RGBX32:
1899 + /* R G B X <=> [32:0] X:B:G:R */
1900 + return DRM_FORMAT_XBGR8888;
1901 + case V4L2_PIX_FMT_ARGB32:
1902 + /* A R G B <=> [32:0] B:G:R:A */
1903 + return DRM_FORMAT_BGRA8888;
1904 + case V4L2_PIX_FMT_XRGB32:
1905 + /* X R G B <=> [32:0] B:G:R:X */
1906 + return DRM_FORMAT_BGRX8888;
1907 + case V4L2_PIX_FMT_UYVY:
1908 + return DRM_FORMAT_UYVY;
1909 + case V4L2_PIX_FMT_YUYV:
1910 + return DRM_FORMAT_YUYV;
1911 + case V4L2_PIX_FMT_YUV420:
1912 + return DRM_FORMAT_YUV420;
1913 + case V4L2_PIX_FMT_YUV422P:
1914 + return DRM_FORMAT_YUV422;
1915 + case V4L2_PIX_FMT_YVU420:
1916 + return DRM_FORMAT_YVU420;
1917 + case V4L2_PIX_FMT_NV12:
1918 + return DRM_FORMAT_NV12;
1919 + case V4L2_PIX_FMT_NV16:
1920 + return DRM_FORMAT_NV16;
1926 +void ipu_cpmem_zero(struct ipuv3_channel *ch)
1928 + struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
1929 + void __iomem *base = p;
1932 + for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
1933 + writel(0, base + i * sizeof(u32));
1935 +EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
1937 +void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
1939 + ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
1940 + ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
1942 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
1944 +void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
1946 + ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
1948 +EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
1950 +void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
1952 + ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
1954 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
1956 +void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
1958 + struct ipu_soc *ipu = ch->ipu;
1961 + if (ipu->ipu_type == IPUV3EX)
1962 + ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
1964 + val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
1965 + val |= 1 << (ch->num % 32);
1966 + ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
1968 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
1970 +void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
1972 + WARN_ON_ONCE(buf & 0x7);
1975 + ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
1977 + ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
1979 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
1981 +void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
1983 + WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
1985 + ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
1986 + ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
1988 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
1990 +void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
1993 + u32 ilo, sly, sluv;
1997 + ilo = 0x100000 - (stride / 8);
2002 + sly = (stride * 2) - 1;
2004 + switch (pixelformat) {
2005 + case V4L2_PIX_FMT_YUV420:
2006 + case V4L2_PIX_FMT_YVU420:
2007 + sluv = stride / 2 - 1;
2009 + case V4L2_PIX_FMT_NV12:
2010 + sluv = stride - 1;
2012 + case V4L2_PIX_FMT_YUV422P:
2013 + sluv = stride - 1;
2015 + case V4L2_PIX_FMT_NV16:
2016 + sluv = stride * 2 - 1;
2023 + ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
2024 + ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
2025 + ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
2027 + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
2029 +EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
2031 +void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
2034 + ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
2036 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
2038 +int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
2040 + return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
2042 +EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
2044 +void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
2046 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
2048 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
2050 +void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
2052 + ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
2054 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
2056 +void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
2057 + enum ipu_rotate_mode rot)
2059 + u32 temp_rot = bitrev8(rot) >> 5;
2061 + ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
2063 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
2065 +int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
2066 + const struct ipu_rgb *rgb)
2068 + int bpp = 0, npb = 0, ro, go, bo, to;
2070 + ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
2071 + go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
2072 + bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
2073 + to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
2075 + ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
2076 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
2077 + ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
2078 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
2079 + ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
2080 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
2082 + if (rgb->transp.length) {
2083 + ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
2084 + rgb->transp.length - 1);
2085 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
2087 + ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
2088 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
2089 + rgb->bits_per_pixel);
2092 + switch (rgb->bits_per_pixel) {
2112 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
2113 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
2114 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
2118 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
2120 +int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
2122 + int bpp = 0, npb = 0;
2145 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
2146 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
2147 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
2151 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
2153 +void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
2155 + switch (pixel_format) {
2156 + case V4L2_PIX_FMT_UYVY:
2157 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
2158 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
2159 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
2161 + case V4L2_PIX_FMT_YUYV:
2162 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
2163 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
2164 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
2168 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
2170 +void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
2171 + unsigned int uv_stride,
2172 + unsigned int u_offset, unsigned int v_offset)
2174 + WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
2176 + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
2177 + ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
2178 + ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
2180 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
2182 +static const struct ipu_rgb def_xrgb_32 = {
2183 + .red = { .offset = 16, .length = 8, },
2184 + .green = { .offset = 8, .length = 8, },
2185 + .blue = { .offset = 0, .length = 8, },
2186 + .transp = { .offset = 24, .length = 8, },
2187 + .bits_per_pixel = 32,
2190 +static const struct ipu_rgb def_xbgr_32 = {
2191 + .red = { .offset = 0, .length = 8, },
2192 + .green = { .offset = 8, .length = 8, },
2193 + .blue = { .offset = 16, .length = 8, },
2194 + .transp = { .offset = 24, .length = 8, },
2195 + .bits_per_pixel = 32,
2198 +static const struct ipu_rgb def_rgbx_32 = {
2199 + .red = { .offset = 24, .length = 8, },
2200 + .green = { .offset = 16, .length = 8, },
2201 + .blue = { .offset = 8, .length = 8, },
2202 + .transp = { .offset = 0, .length = 8, },
2203 + .bits_per_pixel = 32,
2206 +static const struct ipu_rgb def_bgrx_32 = {
2207 + .red = { .offset = 8, .length = 8, },
2208 + .green = { .offset = 16, .length = 8, },
2209 + .blue = { .offset = 24, .length = 8, },
2210 + .transp = { .offset = 0, .length = 8, },
2211 + .bits_per_pixel = 32,
2214 +static const struct ipu_rgb def_rgb_24 = {
2215 + .red = { .offset = 16, .length = 8, },
2216 + .green = { .offset = 8, .length = 8, },
2217 + .blue = { .offset = 0, .length = 8, },
2218 + .transp = { .offset = 0, .length = 0, },
2219 + .bits_per_pixel = 24,
2222 +static const struct ipu_rgb def_bgr_24 = {
2223 + .red = { .offset = 0, .length = 8, },
2224 + .green = { .offset = 8, .length = 8, },
2225 + .blue = { .offset = 16, .length = 8, },
2226 + .transp = { .offset = 0, .length = 0, },
2227 + .bits_per_pixel = 24,
2230 +static const struct ipu_rgb def_rgb_16 = {
2231 + .red = { .offset = 11, .length = 5, },
2232 + .green = { .offset = 5, .length = 6, },
2233 + .blue = { .offset = 0, .length = 5, },
2234 + .transp = { .offset = 0, .length = 0, },
2235 + .bits_per_pixel = 16,
2238 +static const struct ipu_rgb def_bgr_16 = {
2239 + .red = { .offset = 0, .length = 5, },
2240 + .green = { .offset = 5, .length = 6, },
2241 + .blue = { .offset = 11, .length = 5, },
2242 + .transp = { .offset = 0, .length = 0, },
2243 + .bits_per_pixel = 16,
2246 +static const struct ipu_rgb def_argb_16 = {
2247 + .red = { .offset = 10, .length = 5, },
2248 + .green = { .offset = 5, .length = 5, },
2249 + .blue = { .offset = 0, .length = 5, },
2250 + .transp = { .offset = 15, .length = 1, },
2251 + .bits_per_pixel = 16,
2254 +static const struct ipu_rgb def_argb_16_4444 = {
2255 + .red = { .offset = 8, .length = 4, },
2256 + .green = { .offset = 4, .length = 4, },
2257 + .blue = { .offset = 0, .length = 4, },
2258 + .transp = { .offset = 12, .length = 4, },
2259 + .bits_per_pixel = 16,
2262 +static const struct ipu_rgb def_abgr_16 = {
2263 + .red = { .offset = 0, .length = 5, },
2264 + .green = { .offset = 5, .length = 5, },
2265 + .blue = { .offset = 10, .length = 5, },
2266 + .transp = { .offset = 15, .length = 1, },
2267 + .bits_per_pixel = 16,
2270 +static const struct ipu_rgb def_rgba_16 = {
2271 + .red = { .offset = 11, .length = 5, },
2272 + .green = { .offset = 6, .length = 5, },
2273 + .blue = { .offset = 1, .length = 5, },
2274 + .transp = { .offset = 0, .length = 1, },
2275 + .bits_per_pixel = 16,
2278 +static const struct ipu_rgb def_bgra_16 = {
2279 + .red = { .offset = 1, .length = 5, },
2280 + .green = { .offset = 6, .length = 5, },
2281 + .blue = { .offset = 11, .length = 5, },
2282 + .transp = { .offset = 0, .length = 1, },
2283 + .bits_per_pixel = 16,
2286 +#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
2287 +#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2288 + (pix->width * ((y) / 2) / 2) + (x) / 2)
2289 +#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2290 + (pix->width * pix->height / 4) + \
2291 + (pix->width * ((y) / 2) / 2) + (x) / 2)
2292 +#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2293 + (pix->width * (y) / 2) + (x) / 2)
2294 +#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2295 + (pix->width * pix->height / 2) + \
2296 + (pix->width * (y) / 2) + (x) / 2)
2297 +#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2298 + (pix->width * ((y) / 2)) + (x))
2299 +#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2300 + (pix->width * y) + (x))
2302 +#define NUM_ALPHA_CHANNELS 7
2304 +/* See Table 37-12. Alpha channels mapping. */
2305 +static int ipu_channel_albm(int ch_num)
2308 + case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: return 0;
2309 + case IPUV3_CHANNEL_G_MEM_IC_PP: return 1;
2310 + case IPUV3_CHANNEL_MEM_FG_SYNC: return 2;
2311 + case IPUV3_CHANNEL_MEM_FG_ASYNC: return 3;
2312 + case IPUV3_CHANNEL_MEM_BG_SYNC: return 4;
2313 + case IPUV3_CHANNEL_MEM_BG_ASYNC: return 5;
2314 + case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
2320 +static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
2322 + struct ipu_soc *ipu = ch->ipu;
2326 + albm = ipu_channel_albm(ch->num);
2330 + ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
2331 + ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
2332 + ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
2334 + val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
2335 + val |= BIT(ch->num);
2336 + ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
2339 +int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
2341 + switch (drm_fourcc) {
2342 + case DRM_FORMAT_YUV420:
2343 + case DRM_FORMAT_YVU420:
2345 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
2347 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2349 + case DRM_FORMAT_YUV422:
2350 + case DRM_FORMAT_YVU422:
2352 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
2354 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2356 + case DRM_FORMAT_YUV444:
2357 + case DRM_FORMAT_YVU444:
2359 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
2361 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2363 + case DRM_FORMAT_NV12:
2365 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
2367 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2369 + case DRM_FORMAT_NV16:
2371 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
2373 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2375 + case DRM_FORMAT_UYVY:
2377 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
2379 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
2381 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2383 + case DRM_FORMAT_YUYV:
2385 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
2387 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
2389 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2391 + case DRM_FORMAT_ABGR8888:
2392 + case DRM_FORMAT_XBGR8888:
2393 + ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
2395 + case DRM_FORMAT_ARGB8888:
2396 + case DRM_FORMAT_XRGB8888:
2397 + ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
2399 + case DRM_FORMAT_RGBA8888:
2400 + case DRM_FORMAT_RGBX8888:
2401 + case DRM_FORMAT_RGBX8888_A8:
2402 + ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
2404 + case DRM_FORMAT_BGRA8888:
2405 + case DRM_FORMAT_BGRX8888:
2406 + case DRM_FORMAT_BGRX8888_A8:
2407 + ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
2409 + case DRM_FORMAT_BGR888:
2410 + case DRM_FORMAT_BGR888_A8:
2411 + ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
2413 + case DRM_FORMAT_RGB888:
2414 + case DRM_FORMAT_RGB888_A8:
2415 + ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
2417 + case DRM_FORMAT_RGB565:
2418 + case DRM_FORMAT_RGB565_A8:
2419 + ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
2421 + case DRM_FORMAT_BGR565:
2422 + case DRM_FORMAT_BGR565_A8:
2423 + ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
2425 + case DRM_FORMAT_ARGB1555:
2426 + ipu_cpmem_set_format_rgb(ch, &def_argb_16);
2428 + case DRM_FORMAT_ABGR1555:
2429 + ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
2431 + case DRM_FORMAT_RGBA5551:
2432 + ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
2434 + case DRM_FORMAT_BGRA5551:
2435 + ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
2437 + case DRM_FORMAT_ARGB4444:
2438 + ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
2444 + switch (drm_fourcc) {
2445 + case DRM_FORMAT_RGB565_A8:
2446 + case DRM_FORMAT_BGR565_A8:
2447 + case DRM_FORMAT_RGB888_A8:
2448 + case DRM_FORMAT_BGR888_A8:
2449 + case DRM_FORMAT_RGBX8888_A8:
2450 + case DRM_FORMAT_BGRX8888_A8:
2451 + ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
2452 + ipu_cpmem_set_separate_alpha(ch);
2460 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
2462 +int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
2464 + struct v4l2_pix_format *pix = &image->pix;
2465 + int offset, u_offset, v_offset;
2468 + pr_debug("%s: resolution: %dx%d stride: %d\n",
2469 + __func__, pix->width, pix->height,
2470 + pix->bytesperline);
2472 + ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
2473 + ipu_cpmem_set_stride(ch, pix->bytesperline);
2475 + ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
2477 + switch (pix->pixelformat) {
2478 + case V4L2_PIX_FMT_YUV420:
2479 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2480 + u_offset = image->u_offset ?
2481 + image->u_offset : U_OFFSET(pix, image->rect.left,
2482 + image->rect.top) - offset;
2483 + v_offset = image->v_offset ?
2484 + image->v_offset : V_OFFSET(pix, image->rect.left,
2485 + image->rect.top) - offset;
2487 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
2488 + u_offset, v_offset);
2490 + case V4L2_PIX_FMT_YVU420:
2491 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2492 + u_offset = image->u_offset ?
2493 + image->u_offset : V_OFFSET(pix, image->rect.left,
2494 + image->rect.top) - offset;
2495 + v_offset = image->v_offset ?
2496 + image->v_offset : U_OFFSET(pix, image->rect.left,
2497 + image->rect.top) - offset;
2499 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
2500 + u_offset, v_offset);
2502 + case V4L2_PIX_FMT_YUV422P:
2503 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2504 + u_offset = image->u_offset ?
2505 + image->u_offset : U2_OFFSET(pix, image->rect.left,
2506 + image->rect.top) - offset;
2507 + v_offset = image->v_offset ?
2508 + image->v_offset : V2_OFFSET(pix, image->rect.left,
2509 + image->rect.top) - offset;
2511 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
2512 + u_offset, v_offset);
2514 + case V4L2_PIX_FMT_NV12:
2515 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2516 + u_offset = image->u_offset ?
2517 + image->u_offset : UV_OFFSET(pix, image->rect.left,
2518 + image->rect.top) - offset;
2519 + v_offset = image->v_offset ? image->v_offset : 0;
2521 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
2522 + u_offset, v_offset);
2524 + case V4L2_PIX_FMT_NV16:
2525 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2526 + u_offset = image->u_offset ?
2527 + image->u_offset : UV2_OFFSET(pix, image->rect.left,
2528 + image->rect.top) - offset;
2529 + v_offset = image->v_offset ? image->v_offset : 0;
2531 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
2532 + u_offset, v_offset);
2534 + case V4L2_PIX_FMT_UYVY:
2535 + case V4L2_PIX_FMT_YUYV:
2536 + case V4L2_PIX_FMT_RGB565:
2537 + offset = image->rect.left * 2 +
2538 + image->rect.top * pix->bytesperline;
2540 + case V4L2_PIX_FMT_RGB32:
2541 + case V4L2_PIX_FMT_BGR32:
2542 + case V4L2_PIX_FMT_ABGR32:
2543 + case V4L2_PIX_FMT_XBGR32:
2544 + case V4L2_PIX_FMT_BGRA32:
2545 + case V4L2_PIX_FMT_BGRX32:
2546 + case V4L2_PIX_FMT_RGBA32:
2547 + case V4L2_PIX_FMT_RGBX32:
2548 + case V4L2_PIX_FMT_ARGB32:
2549 + case V4L2_PIX_FMT_XRGB32:
2550 + offset = image->rect.left * 4 +
2551 + image->rect.top * pix->bytesperline;
2553 + case V4L2_PIX_FMT_RGB24:
2554 + case V4L2_PIX_FMT_BGR24:
2555 + offset = image->rect.left * 3 +
2556 + image->rect.top * pix->bytesperline;
2558 + case V4L2_PIX_FMT_SBGGR8:
2559 + case V4L2_PIX_FMT_SGBRG8:
2560 + case V4L2_PIX_FMT_SGRBG8:
2561 + case V4L2_PIX_FMT_SRGGB8:
2562 + case V4L2_PIX_FMT_GREY:
2563 + offset = image->rect.left + image->rect.top * pix->bytesperline;
2565 + case V4L2_PIX_FMT_SBGGR16:
2566 + case V4L2_PIX_FMT_SGBRG16:
2567 + case V4L2_PIX_FMT_SGRBG16:
2568 + case V4L2_PIX_FMT_SRGGB16:
2569 + case V4L2_PIX_FMT_Y16:
2570 + offset = image->rect.left * 2 +
2571 + image->rect.top * pix->bytesperline;
2574 + /* This should not happen */
2580 + ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
2581 + ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
2585 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
2587 +void ipu_cpmem_dump(struct ipuv3_channel *ch)
2589 + struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
2590 + struct ipu_soc *ipu = ch->ipu;
2591 + int chno = ch->num;
2593 + dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
2594 + readl(&p->word[0].data[0]),
2595 + readl(&p->word[0].data[1]),
2596 + readl(&p->word[0].data[2]),
2597 + readl(&p->word[0].data[3]),
2598 + readl(&p->word[0].data[4]));
2599 + dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
2600 + readl(&p->word[1].data[0]),
2601 + readl(&p->word[1].data[1]),
2602 + readl(&p->word[1].data[2]),
2603 + readl(&p->word[1].data[3]),
2604 + readl(&p->word[1].data[4]));
2605 + dev_dbg(ipu->dev, "PFS 0x%x, ",
2606 + ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
2607 + dev_dbg(ipu->dev, "BPP 0x%x, ",
2608 + ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
2609 + dev_dbg(ipu->dev, "NPB 0x%x\n",
2610 + ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
2612 + dev_dbg(ipu->dev, "FW %d, ",
2613 + ipu_ch_param_read_field(ch, IPU_FIELD_FW));
2614 + dev_dbg(ipu->dev, "FH %d, ",
2615 + ipu_ch_param_read_field(ch, IPU_FIELD_FH));
2616 + dev_dbg(ipu->dev, "EBA0 0x%x\n",
2617 + ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
2618 + dev_dbg(ipu->dev, "EBA1 0x%x\n",
2619 + ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
2620 + dev_dbg(ipu->dev, "Stride %d\n",
2621 + ipu_ch_param_read_field(ch, IPU_FIELD_SL));
2622 + dev_dbg(ipu->dev, "scan_order %d\n",
2623 + ipu_ch_param_read_field(ch, IPU_FIELD_SO));
2624 + dev_dbg(ipu->dev, "uv_stride %d\n",
2625 + ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
2626 + dev_dbg(ipu->dev, "u_offset 0x%x\n",
2627 + ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
2628 + dev_dbg(ipu->dev, "v_offset 0x%x\n",
2629 + ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
2631 + dev_dbg(ipu->dev, "Width0 %d+1, ",
2632 + ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
2633 + dev_dbg(ipu->dev, "Width1 %d+1, ",
2634 + ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
2635 + dev_dbg(ipu->dev, "Width2 %d+1, ",
2636 + ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
2637 + dev_dbg(ipu->dev, "Width3 %d+1, ",
2638 + ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
2639 + dev_dbg(ipu->dev, "Offset0 %d, ",
2640 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
2641 + dev_dbg(ipu->dev, "Offset1 %d, ",
2642 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
2643 + dev_dbg(ipu->dev, "Offset2 %d, ",
2644 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
2645 + dev_dbg(ipu->dev, "Offset3 %d\n",
2646 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
2648 +EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
2650 +int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
2652 + struct ipu_cpmem *cpmem;
2654 + cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
2658 + ipu->cpmem_priv = cpmem;
2660 + spin_lock_init(&cpmem->lock);
2661 + cpmem->base = devm_ioremap(dev, base, SZ_128K);
2665 + dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
2666 + base, cpmem->base);
2672 +void ipu_cpmem_exit(struct ipu_soc *ipu)
2676 +++ b/drivers/gpu/imx/ipu-v3/ipu-csi.c
2678 +// SPDX-License-Identifier: GPL-2.0-or-later
2680 + * Copyright (C) 2012-2014 Mentor Graphics Inc.
2681 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
2683 +#include <linux/export.h>
2684 +#include <linux/module.h>
2685 +#include <linux/types.h>
2686 +#include <linux/errno.h>
2687 +#include <linux/delay.h>
2688 +#include <linux/io.h>
2689 +#include <linux/err.h>
2690 +#include <linux/platform_device.h>
2691 +#include <linux/videodev2.h>
2692 +#include <uapi/linux/v4l2-mediabus.h>
2693 +#include <linux/clk.h>
2694 +#include <linux/clk-provider.h>
2695 +#include <linux/clkdev.h>
2697 +#include "ipu-prv.h"
2700 + void __iomem *base;
2703 + struct clk *clk_ipu; /* IPU bus clock */
2706 + struct ipu_soc *ipu;
2709 +/* CSI Register Offsets */
2710 +#define CSI_SENS_CONF 0x0000
2711 +#define CSI_SENS_FRM_SIZE 0x0004
2712 +#define CSI_ACT_FRM_SIZE 0x0008
2713 +#define CSI_OUT_FRM_CTRL 0x000c
2714 +#define CSI_TST_CTRL 0x0010
2715 +#define CSI_CCIR_CODE_1 0x0014
2716 +#define CSI_CCIR_CODE_2 0x0018
2717 +#define CSI_CCIR_CODE_3 0x001c
2718 +#define CSI_MIPI_DI 0x0020
2719 +#define CSI_SKIP 0x0024
2720 +#define CSI_CPD_CTRL 0x0028
2721 +#define CSI_CPD_RC(n) (0x002c + ((n)*4))
2722 +#define CSI_CPD_RS(n) (0x004c + ((n)*4))
2723 +#define CSI_CPD_GRC(n) (0x005c + ((n)*4))
2724 +#define CSI_CPD_GRS(n) (0x007c + ((n)*4))
2725 +#define CSI_CPD_GBC(n) (0x008c + ((n)*4))
2726 +#define CSI_CPD_GBS(n) (0x00Ac + ((n)*4))
2727 +#define CSI_CPD_BC(n) (0x00Bc + ((n)*4))
2728 +#define CSI_CPD_BS(n) (0x00Dc + ((n)*4))
2729 +#define CSI_CPD_OFFSET1 0x00ec
2730 +#define CSI_CPD_OFFSET2 0x00f0
2732 +/* CSI Register Fields */
2733 +#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
2734 +#define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700
2735 +#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L
2736 +#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
2737 +#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
2738 +#define CSI_SENS_CONF_DATA_FMT_BAYER 3L
2739 +#define CSI_SENS_CONF_DATA_FMT_RGB565 4L
2740 +#define CSI_SENS_CONF_DATA_FMT_RGB555 5L
2741 +#define CSI_SENS_CONF_DATA_FMT_RGB444 6L
2742 +#define CSI_SENS_CONF_DATA_FMT_JPEG 7L
2744 +#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
2745 +#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
2746 +#define CSI_SENS_CONF_DATA_POL_SHIFT 2
2747 +#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
2748 +#define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070
2749 +#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
2750 +#define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7
2751 +#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11
2752 +#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
2753 +#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
2755 +#define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000
2756 +#define CSI_SENS_CONF_DATA_DEST_SHIFT 24
2757 +#define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000
2758 +#define CSI_SENS_CONF_JPEG8_EN_SHIFT 27
2759 +#define CSI_SENS_CONF_JPEG_EN_SHIFT 28
2760 +#define CSI_SENS_CONF_FORCE_EOF_SHIFT 29
2761 +#define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31
2763 +#define CSI_DATA_DEST_IC 2
2764 +#define CSI_DATA_DEST_IDMAC 4
2766 +#define CSI_CCIR_ERR_DET_EN 0x01000000
2767 +#define CSI_HORI_DOWNSIZE_EN 0x80000000
2768 +#define CSI_VERT_DOWNSIZE_EN 0x40000000
2769 +#define CSI_TEST_GEN_MODE_EN 0x01000000
2771 +#define CSI_HSC_MASK 0x1fff0000
2772 +#define CSI_HSC_SHIFT 16
2773 +#define CSI_VSC_MASK 0x00000fff
2774 +#define CSI_VSC_SHIFT 0
2776 +#define CSI_TEST_GEN_R_MASK 0x000000ff
2777 +#define CSI_TEST_GEN_R_SHIFT 0
2778 +#define CSI_TEST_GEN_G_MASK 0x0000ff00
2779 +#define CSI_TEST_GEN_G_SHIFT 8
2780 +#define CSI_TEST_GEN_B_MASK 0x00ff0000
2781 +#define CSI_TEST_GEN_B_SHIFT 16
2783 +#define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007
2784 +#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0
2785 +#define CSI_SKIP_SMFC_MASK 0x000000f8
2786 +#define CSI_SKIP_SMFC_SHIFT 3
2787 +#define CSI_ID_2_SKIP_MASK 0x00000300
2788 +#define CSI_ID_2_SKIP_SHIFT 8
2790 +#define CSI_COLOR_FIRST_ROW_MASK 0x00000002
2791 +#define CSI_COLOR_FIRST_COMP_MASK 0x00000001
2793 +/* MIPI CSI-2 data types */
2794 +#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
2795 +#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
2796 +#define MIPI_DT_YUV422 0x1e /* UYVY... */
2797 +#define MIPI_DT_RGB444 0x20
2798 +#define MIPI_DT_RGB555 0x21
2799 +#define MIPI_DT_RGB565 0x22
2800 +#define MIPI_DT_RGB666 0x23
2801 +#define MIPI_DT_RGB888 0x24
2802 +#define MIPI_DT_RAW6 0x28
2803 +#define MIPI_DT_RAW7 0x29
2804 +#define MIPI_DT_RAW8 0x2a
2805 +#define MIPI_DT_RAW10 0x2b
2806 +#define MIPI_DT_RAW12 0x2c
2807 +#define MIPI_DT_RAW14 0x2d
2810 + * Bitfield of CSI bus signal polarities and modes.
2812 +struct ipu_csi_bus_config {
2813 + unsigned data_width:4;
2814 + unsigned clk_mode:3;
2815 + unsigned ext_vsync:1;
2816 + unsigned vsync_pol:1;
2817 + unsigned hsync_pol:1;
2818 + unsigned pixclk_pol:1;
2819 + unsigned data_pol:1;
2820 + unsigned sens_clksrc:1;
2821 + unsigned pack_tight:1;
2822 + unsigned force_eof:1;
2823 + unsigned data_en_pol:1;
2825 + unsigned data_fmt;
2830 + * Enumeration of CSI data bus widths.
2832 +enum ipu_csi_data_width {
2833 + IPU_CSI_DATA_WIDTH_4 = 0,
2834 + IPU_CSI_DATA_WIDTH_8 = 1,
2835 + IPU_CSI_DATA_WIDTH_10 = 3,
2836 + IPU_CSI_DATA_WIDTH_12 = 5,
2837 + IPU_CSI_DATA_WIDTH_16 = 9,
2841 + * Enumeration of CSI clock modes.
2843 +enum ipu_csi_clk_mode {
2844 + IPU_CSI_CLK_MODE_GATED_CLK,
2845 + IPU_CSI_CLK_MODE_NONGATED_CLK,
2846 + IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
2847 + IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
2848 + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
2849 + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
2850 + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
2851 + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
2854 +static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
2856 + return readl(csi->base + offset);
2859 +static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
2862 + writel(value, csi->base + offset);
2866 + * Set mclk division ratio for generating test mode mclk. Only used
2867 + * for test generator.
2869 +static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
2875 + div_ratio = (ipu_clk / pixel_clk) - 1;
2877 + if (div_ratio > 0xFF || div_ratio < 0) {
2878 + dev_err(csi->ipu->dev,
2879 + "value of pixel_clk extends normal range\n");
2883 + temp = ipu_csi_read(csi, CSI_SENS_CONF);
2884 + temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
2885 + ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
2892 + * Find the CSI data format and data width for the given V4L2 media
2893 + * bus pixel format code.
2895 +static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
2896 + enum v4l2_mbus_type mbus_type)
2898 + switch (mbus_code) {
2899 + case MEDIA_BUS_FMT_BGR565_2X8_BE:
2900 + case MEDIA_BUS_FMT_BGR565_2X8_LE:
2901 + case MEDIA_BUS_FMT_RGB565_2X8_BE:
2902 + case MEDIA_BUS_FMT_RGB565_2X8_LE:
2903 + if (mbus_type == V4L2_MBUS_CSI2_DPHY)
2904 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
2906 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2907 + cfg->mipi_dt = MIPI_DT_RGB565;
2908 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2910 + case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
2911 + case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
2912 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
2913 + cfg->mipi_dt = MIPI_DT_RGB444;
2914 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2916 + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
2917 + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
2918 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
2919 + cfg->mipi_dt = MIPI_DT_RGB555;
2920 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2922 + case MEDIA_BUS_FMT_RGB888_1X24:
2923 + case MEDIA_BUS_FMT_BGR888_1X24:
2924 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
2925 + cfg->mipi_dt = MIPI_DT_RGB888;
2926 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2928 + case MEDIA_BUS_FMT_UYVY8_2X8:
2929 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
2930 + cfg->mipi_dt = MIPI_DT_YUV422;
2931 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2933 + case MEDIA_BUS_FMT_YUYV8_2X8:
2934 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
2935 + cfg->mipi_dt = MIPI_DT_YUV422;
2936 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2938 + case MEDIA_BUS_FMT_UYVY8_1X16:
2939 + case MEDIA_BUS_FMT_YUYV8_1X16:
2940 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2941 + cfg->mipi_dt = MIPI_DT_YUV422;
2942 + cfg->data_width = IPU_CSI_DATA_WIDTH_16;
2944 + case MEDIA_BUS_FMT_SBGGR8_1X8:
2945 + case MEDIA_BUS_FMT_SGBRG8_1X8:
2946 + case MEDIA_BUS_FMT_SGRBG8_1X8:
2947 + case MEDIA_BUS_FMT_SRGGB8_1X8:
2948 + case MEDIA_BUS_FMT_Y8_1X8:
2949 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2950 + cfg->mipi_dt = MIPI_DT_RAW8;
2951 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2953 + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
2954 + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
2955 + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
2956 + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
2957 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
2958 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
2959 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
2960 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
2961 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2962 + cfg->mipi_dt = MIPI_DT_RAW10;
2963 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2965 + case MEDIA_BUS_FMT_SBGGR10_1X10:
2966 + case MEDIA_BUS_FMT_SGBRG10_1X10:
2967 + case MEDIA_BUS_FMT_SGRBG10_1X10:
2968 + case MEDIA_BUS_FMT_SRGGB10_1X10:
2969 + case MEDIA_BUS_FMT_Y10_1X10:
2970 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2971 + cfg->mipi_dt = MIPI_DT_RAW10;
2972 + cfg->data_width = IPU_CSI_DATA_WIDTH_10;
2974 + case MEDIA_BUS_FMT_SBGGR12_1X12:
2975 + case MEDIA_BUS_FMT_SGBRG12_1X12:
2976 + case MEDIA_BUS_FMT_SGRBG12_1X12:
2977 + case MEDIA_BUS_FMT_SRGGB12_1X12:
2978 + case MEDIA_BUS_FMT_Y12_1X12:
2979 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2980 + cfg->mipi_dt = MIPI_DT_RAW12;
2981 + cfg->data_width = IPU_CSI_DATA_WIDTH_12;
2983 + case MEDIA_BUS_FMT_JPEG_1X8:
2985 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
2986 + cfg->mipi_dt = MIPI_DT_RAW8;
2987 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2996 +/* translate alternate field mode based on given standard */
2997 +static inline enum v4l2_field
2998 +ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
3000 + return (field != V4L2_FIELD_ALTERNATE) ? field :
3001 + ((std & V4L2_STD_525_60) ?
3002 + V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
3006 + * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
3008 +static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
3009 + const struct v4l2_mbus_config *mbus_cfg,
3010 + const struct v4l2_mbus_framefmt *mbus_fmt)
3014 + memset(csicfg, 0, sizeof(*csicfg));
3016 + ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
3020 + switch (mbus_cfg->type) {
3021 + case V4L2_MBUS_PARALLEL:
3022 + csicfg->ext_vsync = 1;
3023 + csicfg->vsync_pol = (mbus_cfg->flags &
3024 + V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
3025 + csicfg->hsync_pol = (mbus_cfg->flags &
3026 + V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
3027 + csicfg->pixclk_pol = (mbus_cfg->flags &
3028 + V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
3029 + csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
3031 + case V4L2_MBUS_BT656:
3032 + csicfg->ext_vsync = 0;
3033 + if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
3034 + mbus_fmt->field == V4L2_FIELD_ALTERNATE)
3035 + csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
3037 + csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
3039 + case V4L2_MBUS_CSI2_DPHY:
3041 + * MIPI CSI-2 requires non gated clock mode, all other
3042 + * parameters are not applicable for MIPI CSI-2 bus.
3044 + csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
3047 + /* will never get here, keep compiler quiet */
3055 +ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
3056 + const struct v4l2_mbus_framefmt *infmt,
3057 + const struct v4l2_mbus_framefmt *outfmt,
3060 + enum v4l2_field infield, outfield;
3063 + /* get translated field type of input and output */
3064 + infield = ipu_csi_translate_field(infmt->field, std);
3065 + outfield = ipu_csi_translate_field(outfmt->field, std);
3068 + * Write the H-V-F codes the CSI will match against the
3069 + * incoming data for start/end of active and blanking
3070 + * field intervals. If input and output field types are
3071 + * sequential but not the same (one is SEQ_BT and the other
3072 + * is SEQ_TB), swap the F-bit so that the CSI will capture
3073 + * field 1 lines before field 0 lines.
3075 + swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
3076 + V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
3077 + infield != outfield);
3079 + if (!swap_fields) {
3081 + * Field0BlankEnd = 110, Field0BlankStart = 010
3082 + * Field0ActiveEnd = 100, Field0ActiveStart = 000
3083 + * Field1BlankEnd = 111, Field1BlankStart = 011
3084 + * Field1ActiveEnd = 101, Field1ActiveStart = 001
3086 + ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
3088 + ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
3090 + dev_dbg(csi->ipu->dev, "capture field swap\n");
3092 + /* same as above but with F-bit inverted */
3093 + ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
3095 + ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
3098 + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
3104 +int ipu_csi_init_interface(struct ipu_csi *csi,
3105 + const struct v4l2_mbus_config *mbus_cfg,
3106 + const struct v4l2_mbus_framefmt *infmt,
3107 + const struct v4l2_mbus_framefmt *outfmt)
3109 + struct ipu_csi_bus_config cfg;
3110 + unsigned long flags;
3111 + u32 width, height, data = 0;
3115 + ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
3119 + /* set default sensor frame width and height */
3120 + width = infmt->width;
3121 + height = infmt->height;
3122 + if (infmt->field == V4L2_FIELD_ALTERNATE)
3125 + /* Set the CSI_SENS_CONF register remaining fields */
3126 + data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
3127 + cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
3128 + cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
3129 + cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
3130 + cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
3131 + cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
3132 + cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
3133 + cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
3134 + cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
3135 + cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
3136 + cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
3138 + spin_lock_irqsave(&csi->lock, flags);
3140 + ipu_csi_write(csi, data, CSI_SENS_CONF);
3142 + /* Set CCIR registers */
3144 + switch (cfg.clk_mode) {
3145 + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
3146 + ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
3147 + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
3149 + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
3150 + if (width == 720 && height == 480) {
3151 + std = V4L2_STD_NTSC;
3153 + } else if (width == 720 && height == 576) {
3154 + std = V4L2_STD_PAL;
3157 + dev_err(csi->ipu->dev,
3158 + "Unsupported interlaced video mode\n");
3163 + ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
3167 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
3168 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
3169 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
3170 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
3171 + ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
3173 + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
3175 + case IPU_CSI_CLK_MODE_GATED_CLK:
3176 + case IPU_CSI_CLK_MODE_NONGATED_CLK:
3177 + ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
3181 + /* Setup sensor frame size */
3182 + ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
3183 + CSI_SENS_FRM_SIZE);
3185 + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
3186 + ipu_csi_read(csi, CSI_SENS_CONF));
3187 + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
3188 + ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
3191 + spin_unlock_irqrestore(&csi->lock, flags);
3195 +EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
3197 +bool ipu_csi_is_interlaced(struct ipu_csi *csi)
3199 + unsigned long flags;
3200 + u32 sensor_protocol;
3202 + spin_lock_irqsave(&csi->lock, flags);
3204 + (ipu_csi_read(csi, CSI_SENS_CONF) &
3205 + CSI_SENS_CONF_SENS_PRTCL_MASK) >>
3206 + CSI_SENS_CONF_SENS_PRTCL_SHIFT;
3207 + spin_unlock_irqrestore(&csi->lock, flags);
3209 + switch (sensor_protocol) {
3210 + case IPU_CSI_CLK_MODE_GATED_CLK:
3211 + case IPU_CSI_CLK_MODE_NONGATED_CLK:
3212 + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
3213 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
3214 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
3216 + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
3217 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
3218 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
3221 + dev_err(csi->ipu->dev,
3222 + "CSI %d sensor protocol unsupported\n", csi->id);
3226 +EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
3228 +void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
3230 + unsigned long flags;
3233 + spin_lock_irqsave(&csi->lock, flags);
3235 + reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
3236 + w->width = (reg & 0xFFFF) + 1;
3237 + w->height = (reg >> 16 & 0xFFFF) + 1;
3239 + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
3240 + w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
3241 + w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
3243 + spin_unlock_irqrestore(&csi->lock, flags);
3245 +EXPORT_SYMBOL_GPL(ipu_csi_get_window);
3247 +void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
3249 + unsigned long flags;
3252 + spin_lock_irqsave(&csi->lock, flags);
3254 + ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
3255 + CSI_ACT_FRM_SIZE);
3257 + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
3258 + reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
3259 + reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
3260 + ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
3262 + spin_unlock_irqrestore(&csi->lock, flags);
3264 +EXPORT_SYMBOL_GPL(ipu_csi_set_window);
3266 +void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
3268 + unsigned long flags;
3271 + spin_lock_irqsave(&csi->lock, flags);
3273 + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
3274 + reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
3275 + reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
3276 + (vert ? CSI_VERT_DOWNSIZE_EN : 0);
3277 + ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
3279 + spin_unlock_irqrestore(&csi->lock, flags);
3281 +EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
3283 +void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
3284 + u32 r_value, u32 g_value, u32 b_value,
3287 + unsigned long flags;
3288 + u32 ipu_clk = clk_get_rate(csi->clk_ipu);
3291 + spin_lock_irqsave(&csi->lock, flags);
3293 + temp = ipu_csi_read(csi, CSI_TST_CTRL);
3296 + temp &= ~CSI_TEST_GEN_MODE_EN;
3297 + ipu_csi_write(csi, temp, CSI_TST_CTRL);
3299 + /* Set sensb_mclk div_ratio */
3300 + ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
3302 + temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
3303 + CSI_TEST_GEN_B_MASK);
3304 + temp |= CSI_TEST_GEN_MODE_EN;
3305 + temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
3306 + (g_value << CSI_TEST_GEN_G_SHIFT) |
3307 + (b_value << CSI_TEST_GEN_B_SHIFT);
3308 + ipu_csi_write(csi, temp, CSI_TST_CTRL);
3311 + spin_unlock_irqrestore(&csi->lock, flags);
3313 +EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
3315 +int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
3316 + struct v4l2_mbus_framefmt *mbus_fmt)
3318 + struct ipu_csi_bus_config cfg;
3319 + unsigned long flags;
3326 + ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
3330 + spin_lock_irqsave(&csi->lock, flags);
3332 + temp = ipu_csi_read(csi, CSI_MIPI_DI);
3333 + temp &= ~(0xff << (vc * 8));
3334 + temp |= (cfg.mipi_dt << (vc * 8));
3335 + ipu_csi_write(csi, temp, CSI_MIPI_DI);
3337 + spin_unlock_irqrestore(&csi->lock, flags);
3341 +EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
3343 +int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
3344 + u32 max_ratio, u32 id)
3346 + unsigned long flags;
3349 + if (max_ratio > 5 || id > 3)
3352 + spin_lock_irqsave(&csi->lock, flags);
3354 + temp = ipu_csi_read(csi, CSI_SKIP);
3355 + temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
3356 + CSI_SKIP_SMFC_MASK);
3357 + temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
3358 + (id << CSI_ID_2_SKIP_SHIFT) |
3359 + (skip << CSI_SKIP_SMFC_SHIFT);
3360 + ipu_csi_write(csi, temp, CSI_SKIP);
3362 + spin_unlock_irqrestore(&csi->lock, flags);
3366 +EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
3368 +int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
3370 + unsigned long flags;
3371 + u32 csi_sens_conf, dest;
3373 + if (csi_dest == IPU_CSI_DEST_IDMAC)
3374 + dest = CSI_DATA_DEST_IDMAC;
3376 + dest = CSI_DATA_DEST_IC; /* IC or VDIC */
3378 + spin_lock_irqsave(&csi->lock, flags);
3380 + csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
3381 + csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
3382 + csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
3383 + ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
3385 + spin_unlock_irqrestore(&csi->lock, flags);
3389 +EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
3391 +int ipu_csi_enable(struct ipu_csi *csi)
3393 + ipu_module_enable(csi->ipu, csi->module);
3397 +EXPORT_SYMBOL_GPL(ipu_csi_enable);
3399 +int ipu_csi_disable(struct ipu_csi *csi)
3401 + ipu_module_disable(csi->ipu, csi->module);
3405 +EXPORT_SYMBOL_GPL(ipu_csi_disable);
3407 +struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
3409 + unsigned long flags;
3410 + struct ipu_csi *csi, *ret;
3413 + return ERR_PTR(-EINVAL);
3415 + csi = ipu->csi_priv[id];
3418 + spin_lock_irqsave(&csi->lock, flags);
3421 + ret = ERR_PTR(-EBUSY);
3425 + csi->inuse = true;
3427 + spin_unlock_irqrestore(&csi->lock, flags);
3430 +EXPORT_SYMBOL_GPL(ipu_csi_get);
3432 +void ipu_csi_put(struct ipu_csi *csi)
3434 + unsigned long flags;
3436 + spin_lock_irqsave(&csi->lock, flags);
3437 + csi->inuse = false;
3438 + spin_unlock_irqrestore(&csi->lock, flags);
3440 +EXPORT_SYMBOL_GPL(ipu_csi_put);
3442 +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
3443 + unsigned long base, u32 module, struct clk *clk_ipu)
3445 + struct ipu_csi *csi;
3450 + csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
3454 + ipu->csi_priv[id] = csi;
3456 + spin_lock_init(&csi->lock);
3457 + csi->module = module;
3459 + csi->clk_ipu = clk_ipu;
3460 + csi->base = devm_ioremap(dev, base, PAGE_SIZE);
3464 + dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
3465 + id, base, csi->base);
3471 +void ipu_csi_exit(struct ipu_soc *ipu, int id)
3475 +void ipu_csi_dump(struct ipu_csi *csi)
3477 + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n",
3478 + ipu_csi_read(csi, CSI_SENS_CONF));
3479 + dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
3480 + ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
3481 + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n",
3482 + ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
3483 + dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n",
3484 + ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
3485 + dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n",
3486 + ipu_csi_read(csi, CSI_TST_CTRL));
3487 + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n",
3488 + ipu_csi_read(csi, CSI_CCIR_CODE_1));
3489 + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n",
3490 + ipu_csi_read(csi, CSI_CCIR_CODE_2));
3491 + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n",
3492 + ipu_csi_read(csi, CSI_CCIR_CODE_3));
3493 + dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n",
3494 + ipu_csi_read(csi, CSI_MIPI_DI));
3495 + dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n",
3496 + ipu_csi_read(csi, CSI_SKIP));
3498 +EXPORT_SYMBOL_GPL(ipu_csi_dump);
3500 +++ b/drivers/gpu/imx/ipu-v3/ipu-dc.c
3502 +// SPDX-License-Identifier: GPL-2.0-or-later
3504 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
3505 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
3508 +#include <linux/export.h>
3509 +#include <linux/module.h>
3510 +#include <linux/types.h>
3511 +#include <linux/errno.h>
3512 +#include <linux/delay.h>
3513 +#include <linux/interrupt.h>
3514 +#include <linux/io.h>
3516 +#include <video/imx-ipu-v3.h>
3517 +#include "ipu-prv.h"
3519 +#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2)
3520 +#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2)
3522 +#define DC_EVT_NF 0
3523 +#define DC_EVT_NL 1
3524 +#define DC_EVT_EOF 2
3525 +#define DC_EVT_NFIELD 3
3526 +#define DC_EVT_EOL 4
3527 +#define DC_EVT_EOFIELD 5
3528 +#define DC_EVT_NEW_ADDR 6
3529 +#define DC_EVT_NEW_CHAN 7
3530 +#define DC_EVT_NEW_DATA 8
3532 +#define DC_EVT_NEW_ADDR_W_0 0
3533 +#define DC_EVT_NEW_ADDR_W_1 1
3534 +#define DC_EVT_NEW_CHAN_W_0 2
3535 +#define DC_EVT_NEW_CHAN_W_1 3
3536 +#define DC_EVT_NEW_DATA_W_0 4
3537 +#define DC_EVT_NEW_DATA_W_1 5
3538 +#define DC_EVT_NEW_ADDR_R_0 6
3539 +#define DC_EVT_NEW_ADDR_R_1 7
3540 +#define DC_EVT_NEW_CHAN_R_0 8
3541 +#define DC_EVT_NEW_CHAN_R_1 9
3542 +#define DC_EVT_NEW_DATA_R_0 10
3543 +#define DC_EVT_NEW_DATA_R_1 11
3545 +#define DC_WR_CH_CONF 0x0
3546 +#define DC_WR_CH_ADDR 0x4
3547 +#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2)
3549 +#define DC_GEN 0xd4
3550 +#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4)
3551 +#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4)
3552 +#define DC_STAT 0x1c8
3554 +#define WROD(lf) (0x18 | ((lf) << 1))
3558 +#define SYNC_WAVE 0
3559 +#define NULL_WAVE (-1)
3561 +#define DC_GEN_SYNC_1_6_SYNC (2 << 1)
3562 +#define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
3564 +#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0)
3565 +#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0)
3566 +#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0)
3567 +#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0)
3568 +#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3)
3569 +#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3)
3570 +#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4)
3571 +#define DC_WR_CH_CONF_FIELD_MODE (1 << 9)
3572 +#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5)
3573 +#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5)
3574 +#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2)
3575 +#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3)
3577 +#define IPU_DC_NUM_CHANNELS 10
3579 +struct ipu_dc_priv;
3583 + IPU_DC_MAP_RGB565,
3584 + IPU_DC_MAP_GBR24, /* TVEv2 */
3585 + IPU_DC_MAP_BGR666,
3586 + IPU_DC_MAP_LVDS666,
3591 + /* The display interface number assigned to this dc channel */
3593 + void __iomem *base;
3594 + struct ipu_dc_priv *priv;
3599 +struct ipu_dc_priv {
3600 + void __iomem *dc_reg;
3601 + void __iomem *dc_tmpl_reg;
3602 + struct ipu_soc *ipu;
3603 + struct device *dev;
3604 + struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
3605 + struct mutex mutex;
3606 + struct completion comp;
3610 +static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
3614 + reg = readl(dc->base + DC_RL_CH(event));
3615 + reg &= ~(0xffff << (16 * (event & 0x1)));
3616 + reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
3617 + writel(reg, dc->base + DC_RL_CH(event));
3620 +static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
3621 + int map, int wave, int glue, int sync, int stop)
3623 + struct ipu_dc_priv *priv = dc->priv;
3626 + if (opcode == WCLK) {
3627 + reg1 = (operand << 20) & 0xfff00000;
3628 + reg2 = operand >> 12 | opcode << 1 | stop << 9;
3629 + } else if (opcode == WRG) {
3630 + reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
3631 + reg2 = operand >> 17 | opcode << 7 | stop << 9;
3633 + reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
3634 + reg2 = operand >> 12 | opcode << 4 | stop << 9;
3636 + writel(reg1, priv->dc_tmpl_reg + word * 8);
3637 + writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
3640 +static int ipu_bus_format_to_map(u32 fmt)
3645 + /* fall-through */
3646 + case MEDIA_BUS_FMT_RGB888_1X24:
3647 + return IPU_DC_MAP_RGB24;
3648 + case MEDIA_BUS_FMT_RGB565_1X16:
3649 + return IPU_DC_MAP_RGB565;
3650 + case MEDIA_BUS_FMT_GBR888_1X24:
3651 + return IPU_DC_MAP_GBR24;
3652 + case MEDIA_BUS_FMT_RGB666_1X18:
3653 + return IPU_DC_MAP_BGR666;
3654 + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
3655 + return IPU_DC_MAP_LVDS666;
3656 + case MEDIA_BUS_FMT_BGR888_1X24:
3657 + return IPU_DC_MAP_BGR24;
3661 +int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
3662 + u32 bus_format, u32 width)
3664 + struct ipu_dc_priv *priv = dc->priv;
3669 + dc->di = ipu_di_get_num(di);
3671 + map = ipu_bus_format_to_map(bus_format);
3674 + * In interlaced mode we need more counters to create the asymmetric
3675 + * per-field VSYNC signals. The pixel active signal synchronising DC
3676 + * to DI moves to signal generator #6 (see ipu-di.c). In progressive
3677 + * mode counter #5 is used.
3679 + sync = interlaced ? 6 : 5;
3681 + /* Reserve 5 microcode template words for each DI */
3688 + dc_link_event(dc, DC_EVT_NL, addr, 3);
3689 + dc_link_event(dc, DC_EVT_EOL, addr, 2);
3690 + dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
3692 + /* Init template microcode */
3693 + dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
3695 + dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
3696 + dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
3697 + dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
3699 + /* Init template microcode */
3700 + dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
3701 + dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
3702 + dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
3703 + dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
3706 + dc_link_event(dc, DC_EVT_NF, 0, 0);
3707 + dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
3708 + dc_link_event(dc, DC_EVT_EOF, 0, 0);
3709 + dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
3710 + dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
3711 + dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
3713 + reg = readl(dc->base + DC_WR_CH_CONF);
3715 + reg |= DC_WR_CH_CONF_FIELD_MODE;
3717 + reg &= ~DC_WR_CH_CONF_FIELD_MODE;
3718 + writel(reg, dc->base + DC_WR_CH_CONF);
3720 + writel(0x0, dc->base + DC_WR_CH_ADDR);
3721 + writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
3725 +EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
3727 +void ipu_dc_enable(struct ipu_soc *ipu)
3729 + struct ipu_dc_priv *priv = ipu->dc_priv;
3731 + mutex_lock(&priv->mutex);
3733 + if (!priv->use_count)
3734 + ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
3736 + priv->use_count++;
3738 + mutex_unlock(&priv->mutex);
3740 +EXPORT_SYMBOL_GPL(ipu_dc_enable);
3742 +void ipu_dc_enable_channel(struct ipu_dc *dc)
3746 + reg = readl(dc->base + DC_WR_CH_CONF);
3747 + reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
3748 + writel(reg, dc->base + DC_WR_CH_CONF);
3750 +EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
3752 +void ipu_dc_disable_channel(struct ipu_dc *dc)
3756 + val = readl(dc->base + DC_WR_CH_CONF);
3757 + val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
3758 + writel(val, dc->base + DC_WR_CH_CONF);
3760 +EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
3762 +void ipu_dc_disable(struct ipu_soc *ipu)
3764 + struct ipu_dc_priv *priv = ipu->dc_priv;
3766 + mutex_lock(&priv->mutex);
3768 + priv->use_count--;
3769 + if (!priv->use_count)
3770 + ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
3772 + if (priv->use_count < 0)
3773 + priv->use_count = 0;
3775 + mutex_unlock(&priv->mutex);
3777 +EXPORT_SYMBOL_GPL(ipu_dc_disable);
3779 +static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
3780 + int byte_num, int offset, int mask)
3782 + int ptr = map * 3 + byte_num;
3785 + reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
3786 + reg &= ~(0xffff << (16 * (ptr & 0x1)));
3787 + reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
3788 + writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
3790 + reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
3791 + reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
3792 + reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
3793 + writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
3796 +static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
3798 + u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
3800 + writel(reg & ~(0xffff << (16 * (map & 0x1))),
3801 + priv->dc_reg + DC_MAP_CONF_PTR(map));
3804 +struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
3806 + struct ipu_dc_priv *priv = ipu->dc_priv;
3807 + struct ipu_dc *dc;
3809 + if (channel >= IPU_DC_NUM_CHANNELS)
3810 + return ERR_PTR(-ENODEV);
3812 + dc = &priv->channels[channel];
3814 + mutex_lock(&priv->mutex);
3817 + mutex_unlock(&priv->mutex);
3818 + return ERR_PTR(-EBUSY);
3821 + dc->in_use = true;
3823 + mutex_unlock(&priv->mutex);
3827 +EXPORT_SYMBOL_GPL(ipu_dc_get);
3829 +void ipu_dc_put(struct ipu_dc *dc)
3831 + struct ipu_dc_priv *priv = dc->priv;
3833 + mutex_lock(&priv->mutex);
3834 + dc->in_use = false;
3835 + mutex_unlock(&priv->mutex);
3837 +EXPORT_SYMBOL_GPL(ipu_dc_put);
3839 +int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
3840 + unsigned long base, unsigned long template_base)
3842 + struct ipu_dc_priv *priv;
3843 + static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
3844 + 0x78, 0, 0x94, 0xb4};
3847 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3851 + mutex_init(&priv->mutex);
3855 + priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
3856 + priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
3857 + if (!priv->dc_reg || !priv->dc_tmpl_reg)
3860 + for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
3861 + priv->channels[i].chno = i;
3862 + priv->channels[i].priv = priv;
3863 + priv->channels[i].base = priv->dc_reg + channel_offsets[i];
3866 + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
3867 + DC_WR_CH_CONF_PROG_DI_ID,
3868 + priv->channels[1].base + DC_WR_CH_CONF);
3869 + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
3870 + priv->channels[5].base + DC_WR_CH_CONF);
3872 + writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
3873 + priv->dc_reg + DC_GEN);
3875 + ipu->dc_priv = priv;
3877 + dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
3878 + base, template_base);
3881 + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
3882 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
3883 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
3884 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
3887 + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
3888 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
3889 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
3890 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
3893 + ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
3894 + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
3895 + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
3896 + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
3899 + ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
3900 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
3901 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
3902 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
3905 + ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
3906 + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
3907 + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
3908 + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
3911 + ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
3912 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
3913 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
3914 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
3919 +void ipu_dc_exit(struct ipu_soc *ipu)
3923 +++ b/drivers/gpu/imx/ipu-v3/ipu-di.c
3925 +// SPDX-License-Identifier: GPL-2.0-or-later
3927 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
3928 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
3930 +#include <linux/export.h>
3931 +#include <linux/module.h>
3932 +#include <linux/types.h>
3933 +#include <linux/errno.h>
3934 +#include <linux/io.h>
3935 +#include <linux/err.h>
3936 +#include <linux/platform_device.h>
3938 +#include <video/imx-ipu-v3.h>
3939 +#include "ipu-prv.h"
3942 + void __iomem *base;
3945 + struct clk *clk_di; /* display input clock */
3946 + struct clk *clk_ipu; /* IPU bus clock */
3947 + struct clk *clk_di_pixel; /* resulting pixel clock */
3949 + struct ipu_soc *ipu;
3952 +static DEFINE_MUTEX(di_mutex);
3954 +struct di_sync_config {
3961 + int cnt_polarity_gen_en;
3962 + int cnt_polarity_clr_src;
3963 + int cnt_polarity_trigger_src;
3978 + DI_PIN_SER_CLK = 0,
3979 + DI_PIN_SER_RS = 1,
3982 +enum di_sync_wave {
3985 + DI_SYNC_INT_HSYNC = 2,
3986 + DI_SYNC_HSYNC = 3,
3987 + DI_SYNC_VSYNC = 4,
3990 + DI_SYNC_CNT1 = 2, /* counter >= 2 only */
3991 + DI_SYNC_CNT4 = 5, /* counter >= 5 only */
3992 + DI_SYNC_CNT5 = 6, /* counter >= 6 only */
3995 +#define SYNC_WAVE 0
3997 +#define DI_GENERAL 0x0000
3998 +#define DI_BS_CLKGEN0 0x0004
3999 +#define DI_BS_CLKGEN1 0x0008
4000 +#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
4001 +#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
4002 +#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
4003 +#define DI_SYNC_AS_GEN 0x0054
4004 +#define DI_DW_GEN(gen) (0x0058 + 4 * (gen))
4005 +#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set)))
4006 +#define DI_SER_CONF 0x015c
4007 +#define DI_SSC 0x0160
4008 +#define DI_POL 0x0164
4009 +#define DI_AW0 0x0168
4010 +#define DI_AW1 0x016c
4011 +#define DI_SCR_CONF 0x0170
4012 +#define DI_STAT 0x0174
4014 +#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19)
4015 +#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16)
4016 +#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3)
4017 +#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0)
4019 +#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29)
4020 +#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25)
4021 +#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12)
4022 +#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9)
4023 +#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16)
4024 +#define DI_SW_GEN1_CNT_UP(x) (x)
4025 +#define DI_SW_GEN1_AUTO_RELOAD (0x10000000)
4027 +#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24
4028 +#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16
4030 +#define DI_GEN_POLARITY_1 (1 << 0)
4031 +#define DI_GEN_POLARITY_2 (1 << 1)
4032 +#define DI_GEN_POLARITY_3 (1 << 2)
4033 +#define DI_GEN_POLARITY_4 (1 << 3)
4034 +#define DI_GEN_POLARITY_5 (1 << 4)
4035 +#define DI_GEN_POLARITY_6 (1 << 5)
4036 +#define DI_GEN_POLARITY_7 (1 << 6)
4037 +#define DI_GEN_POLARITY_8 (1 << 7)
4038 +#define DI_GEN_POLARITY_DISP_CLK (1 << 17)
4039 +#define DI_GEN_DI_CLK_EXT (1 << 20)
4040 +#define DI_GEN_DI_VSYNC_EXT (1 << 21)
4042 +#define DI_POL_DRDY_DATA_POLARITY (1 << 7)
4043 +#define DI_POL_DRDY_POLARITY_15 (1 << 4)
4045 +#define DI_VSYNC_SEL_OFFSET 13
4047 +static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
4049 + return readl(di->base + offset);
4052 +static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
4054 + writel(value, di->base + offset);
4057 +static void ipu_di_data_wave_config(struct ipu_di *di,
4059 + int access_size, int component_size)
4062 + reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
4063 + (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
4064 + ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
4067 +static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
4068 + int set, int up, int down)
4072 + reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
4073 + reg &= ~(0x3 << (di_pin * 2));
4074 + reg |= set << (di_pin * 2);
4075 + ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
4077 + ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
4080 +static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
4081 + int start, int count)
4086 + for (i = 0; i < count; i++) {
4087 + struct di_sync_config *c = &config[i];
4088 + int wave_gen = start + i + 1;
4090 + if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
4091 + (c->repeat_count >= 0x1000) ||
4092 + (c->cnt_up >= 0x400) ||
4093 + (c->cnt_down >= 0x400)) {
4094 + dev_err(di->ipu->dev, "DI%d counters out of range.\n",
4099 + reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
4100 + DI_SW_GEN0_RUN_SRC(c->run_src) |
4101 + DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
4102 + DI_SW_GEN0_OFFSET_SRC(c->offset_src);
4103 + ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
4105 + reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
4106 + DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
4107 + DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
4108 + c->cnt_polarity_trigger_src) |
4109 + DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
4110 + DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
4111 + DI_SW_GEN1_CNT_UP(c->cnt_up);
4113 + /* Enable auto reload */
4114 + if (c->repeat_count == 0)
4115 + reg |= DI_SW_GEN1_AUTO_RELOAD;
4117 + ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
4119 + reg = ipu_di_read(di, DI_STP_REP(wave_gen));
4120 + reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
4121 + reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
4122 + ipu_di_write(di, reg, DI_STP_REP(wave_gen));
4126 +static void ipu_di_sync_config_interlaced(struct ipu_di *di,
4127 + struct ipu_di_signal_cfg *sig)
4129 + u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
4130 + sig->mode.hback_porch + sig->mode.hfront_porch;
4131 + u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
4132 + sig->mode.vback_porch + sig->mode.vfront_porch;
4133 + struct di_sync_config cfg[] = {
4135 + /* 1: internal VSYNC for each frame */
4136 + .run_count = v_total * 2 - 1,
4137 + .run_src = 3, /* == counter 7 */
4139 + /* PIN2: HSYNC waveform */
4140 + .run_count = h_total - 1,
4141 + .run_src = DI_SYNC_CLK,
4142 + .cnt_polarity_gen_en = 1,
4143 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
4144 + .cnt_down = sig->mode.hsync_len * 2,
4146 + /* PIN3: VSYNC waveform */
4147 + .run_count = v_total - 1,
4148 + .run_src = 4, /* == counter 7 */
4149 + .cnt_polarity_gen_en = 1,
4150 + .cnt_polarity_trigger_src = 4, /* == counter 7 */
4151 + .cnt_down = sig->mode.vsync_len * 2,
4152 + .cnt_clr_src = DI_SYNC_CNT1,
4155 + .run_count = v_total / 2,
4156 + .run_src = DI_SYNC_HSYNC,
4157 + .offset_count = h_total / 2,
4158 + .offset_src = DI_SYNC_CLK,
4159 + .repeat_count = 2,
4160 + .cnt_clr_src = DI_SYNC_CNT1,
4162 + /* 5: Active lines */
4163 + .run_src = DI_SYNC_HSYNC,
4164 + .offset_count = (sig->mode.vsync_len +
4165 + sig->mode.vback_porch) / 2,
4166 + .offset_src = DI_SYNC_HSYNC,
4167 + .repeat_count = sig->mode.vactive / 2,
4168 + .cnt_clr_src = DI_SYNC_CNT4,
4170 + /* 6: Active pixel, referenced by DC */
4171 + .run_src = DI_SYNC_CLK,
4172 + .offset_count = sig->mode.hsync_len +
4173 + sig->mode.hback_porch,
4174 + .offset_src = DI_SYNC_CLK,
4175 + .repeat_count = sig->mode.hactive,
4176 + .cnt_clr_src = DI_SYNC_CNT5,
4178 + /* 7: Half line HSYNC */
4179 + .run_count = h_total / 2 - 1,
4180 + .run_src = DI_SYNC_CLK,
4184 + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
4186 + ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
4189 +static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
4190 + struct ipu_di_signal_cfg *sig, int div)
4192 + u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
4193 + sig->mode.hback_porch + sig->mode.hfront_porch;
4194 + u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
4195 + sig->mode.vback_porch + sig->mode.vfront_porch;
4196 + struct di_sync_config cfg[] = {
4198 + /* 1: INT_HSYNC */
4199 + .run_count = h_total - 1,
4200 + .run_src = DI_SYNC_CLK,
4203 + .run_count = h_total - 1,
4204 + .run_src = DI_SYNC_CLK,
4205 + .offset_count = div * sig->v_to_h_sync,
4206 + .offset_src = DI_SYNC_CLK,
4207 + .cnt_polarity_gen_en = 1,
4208 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
4209 + .cnt_down = sig->mode.hsync_len * 2,
4212 + .run_count = v_total - 1,
4213 + .run_src = DI_SYNC_INT_HSYNC,
4214 + .cnt_polarity_gen_en = 1,
4215 + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
4216 + .cnt_down = sig->mode.vsync_len * 2,
4218 + /* 4: Line Active */
4219 + .run_src = DI_SYNC_HSYNC,
4220 + .offset_count = sig->mode.vsync_len +
4221 + sig->mode.vback_porch,
4222 + .offset_src = DI_SYNC_HSYNC,
4223 + .repeat_count = sig->mode.vactive,
4224 + .cnt_clr_src = DI_SYNC_VSYNC,
4226 + /* 5: Pixel Active, referenced by DC */
4227 + .run_src = DI_SYNC_CLK,
4228 + .offset_count = sig->mode.hsync_len +
4229 + sig->mode.hback_porch,
4230 + .offset_src = DI_SYNC_CLK,
4231 + .repeat_count = sig->mode.hactive,
4232 + .cnt_clr_src = 5, /* Line Active */
4243 + /* can't use #7 and #8 for line active and pixel active counters */
4244 + struct di_sync_config cfg_vga[] = {
4246 + /* 1: INT_HSYNC */
4247 + .run_count = h_total - 1,
4248 + .run_src = DI_SYNC_CLK,
4251 + .run_count = v_total - 1,
4252 + .run_src = DI_SYNC_INT_HSYNC,
4254 + /* 3: Line Active */
4255 + .run_src = DI_SYNC_INT_HSYNC,
4256 + .offset_count = sig->mode.vsync_len +
4257 + sig->mode.vback_porch,
4258 + .offset_src = DI_SYNC_INT_HSYNC,
4259 + .repeat_count = sig->mode.vactive,
4260 + .cnt_clr_src = 3 /* VSYNC */,
4262 + /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
4263 + .run_count = h_total - 1,
4264 + .run_src = DI_SYNC_CLK,
4265 + .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
4266 + .offset_src = DI_SYNC_CLK,
4267 + .cnt_polarity_gen_en = 1,
4268 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
4269 + .cnt_down = sig->mode.hsync_len * 2,
4271 + /* 5: Pixel Active signal to DC */
4272 + .run_src = DI_SYNC_CLK,
4273 + .offset_count = sig->mode.hsync_len +
4274 + sig->mode.hback_porch,
4275 + .offset_src = DI_SYNC_CLK,
4276 + .repeat_count = sig->mode.hactive,
4277 + .cnt_clr_src = 4, /* Line Active */
4279 + /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
4280 + .run_count = v_total - 1,
4281 + .run_src = DI_SYNC_INT_HSYNC,
4282 + .offset_count = 1, /* magic value from Freescale TVE driver */
4283 + .offset_src = DI_SYNC_INT_HSYNC,
4284 + .cnt_polarity_gen_en = 1,
4285 + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
4286 + .cnt_down = sig->mode.vsync_len * 2,
4288 + /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
4289 + .run_count = h_total - 1,
4290 + .run_src = DI_SYNC_CLK,
4291 + .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
4292 + .offset_src = DI_SYNC_CLK,
4293 + .cnt_polarity_gen_en = 1,
4294 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
4295 + .cnt_down = sig->mode.hsync_len * 2,
4297 + /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
4298 + .run_count = v_total - 1,
4299 + .run_src = DI_SYNC_INT_HSYNC,
4300 + .offset_count = 1, /* magic value from Freescale TVE driver */
4301 + .offset_src = DI_SYNC_INT_HSYNC,
4302 + .cnt_polarity_gen_en = 1,
4303 + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
4304 + .cnt_down = sig->mode.vsync_len * 2,
4310 + ipu_di_write(di, v_total - 1, DI_SCR_CONF);
4311 + if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
4312 + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
4314 + ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
4317 +static void ipu_di_config_clock(struct ipu_di *di,
4318 + const struct ipu_di_signal_cfg *sig)
4324 + if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
4326 + * CLKMODE_EXT means we must use the DI clock: this is
4327 + * needed for things like LVDS which needs to feed the
4328 + * DI and LDB with the same pixel clock.
4332 + if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
4334 + * CLKMODE_SYNC means that we want the DI to be
4335 + * clocked at the same rate as the parent clock.
4336 + * This is needed (eg) for LDB which needs to be
4337 + * fed with the same pixel clock. We assume that
4338 + * the LDB clock has already been set correctly.
4343 + * We can use the divider. We should really have
4344 + * a flag here indicating whether the bridge can
4345 + * cope with a fractional divider or not. For the
4346 + * time being, let's go for simplicitly and
4349 + unsigned long in_rate;
4352 + clk_set_rate(clk, sig->mode.pixelclock);
4354 + in_rate = clk_get_rate(clk);
4355 + div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
4356 + div = clamp(div, 1U, 255U);
4358 + clkgen0 = div << 4;
4362 + * For other interfaces, we can arbitarily select between
4363 + * the DI specific clock and the internal IPU clock. See
4364 + * DI_GENERAL bit 20. We select the IPU clock if it can
4365 + * give us a clock rate within 1% of the requested frequency,
4366 + * otherwise we use the DI clock.
4368 + unsigned long rate, clkrate;
4369 + unsigned div, error;
4371 + clkrate = clk_get_rate(di->clk_ipu);
4372 + div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
4373 + div = clamp(div, 1U, 255U);
4374 + rate = clkrate / div;
4376 + error = rate / (sig->mode.pixelclock / 1000);
4378 + dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
4379 + rate, div, (signed)(error - 1000) / 10, error % 10);
4381 + /* Allow a 1% error */
4382 + if (error < 1010 && error >= 990) {
4383 + clk = di->clk_ipu;
4385 + clkgen0 = div << 4;
4387 + unsigned long in_rate;
4392 + clk_set_rate(clk, sig->mode.pixelclock);
4394 + in_rate = clk_get_rate(clk);
4395 + div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
4396 + div = clamp(div, 1U, 255U);
4398 + clkgen0 = div << 4;
4402 + di->clk_di_pixel = clk;
4404 + /* Set the divider */
4405 + ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
4408 + * Set the high/low periods. Bits 24:16 give us the falling edge,
4409 + * and bits 8:0 give the rising edge. LSB is fraction, and is
4410 + * based on the divider above. We want a 50% duty cycle, so set
4411 + * the falling edge to be half the divider.
4413 + ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
4415 + /* Finally select the input clock */
4416 + val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
4417 + if (clk == di->clk_di)
4418 + val |= DI_GEN_DI_CLK_EXT;
4419 + ipu_di_write(di, val, DI_GENERAL);
4421 + dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
4422 + sig->mode.pixelclock,
4423 + clk_get_rate(di->clk_ipu),
4424 + clk_get_rate(di->clk_di),
4425 + clk == di->clk_di ? "DI" : "IPU",
4426 + clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
4430 + * This function is called to adjust a video mode to IPU restrictions.
4431 + * It is meant to be called from drm crtc mode_fixup() methods.
4433 +int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
4437 + if (mode->vfront_porch >= 2)
4440 + diff = 2 - mode->vfront_porch;
4442 + if (mode->vback_porch >= diff) {
4443 + mode->vfront_porch = 2;
4444 + mode->vback_porch -= diff;
4445 + } else if (mode->vsync_len > diff) {
4446 + mode->vfront_porch = 2;
4447 + mode->vsync_len = mode->vsync_len - diff;
4449 + dev_warn(di->ipu->dev, "failed to adjust videomode\n");
4453 + dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
4456 +EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
4458 +static u32 ipu_di_gen_polarity(int pin)
4462 + return DI_GEN_POLARITY_1;
4464 + return DI_GEN_POLARITY_2;
4466 + return DI_GEN_POLARITY_3;
4468 + return DI_GEN_POLARITY_4;
4470 + return DI_GEN_POLARITY_5;
4472 + return DI_GEN_POLARITY_6;
4474 + return DI_GEN_POLARITY_7;
4476 + return DI_GEN_POLARITY_8;
4481 +int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
4484 + u32 di_gen, vsync_cnt;
4487 + dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
4488 + di->id, sig->mode.hactive, sig->mode.vactive);
4490 + dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
4491 + clk_get_rate(di->clk_ipu),
4492 + clk_get_rate(di->clk_di),
4493 + sig->mode.pixelclock);
4495 + mutex_lock(&di_mutex);
4497 + ipu_di_config_clock(di, sig);
4499 + div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
4500 + div = div / 16; /* Now divider is integer portion */
4502 + /* Setup pixel clock timing */
4503 + /* Down time is half of period */
4504 + ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
4506 + ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
4507 + ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
4509 + di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
4510 + di_gen |= DI_GEN_DI_VSYNC_EXT;
4512 + if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
4513 + ipu_di_sync_config_interlaced(di, sig);
4515 + /* set y_sel = 1 */
4516 + di_gen |= 0x10000000;
4520 + ipu_di_sync_config_noninterlaced(di, sig, div);
4525 + * TODO: change only for TVEv2, parallel display
4528 + if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
4532 + if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
4533 + di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
4534 + if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
4535 + di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
4538 + di_gen |= DI_GEN_POLARITY_DISP_CLK;
4540 + ipu_di_write(di, di_gen, DI_GENERAL);
4542 + ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
4545 + reg = ipu_di_read(di, DI_POL);
4546 + reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
4548 + if (sig->enable_pol)
4549 + reg |= DI_POL_DRDY_POLARITY_15;
4550 + if (sig->data_pol)
4551 + reg |= DI_POL_DRDY_DATA_POLARITY;
4553 + ipu_di_write(di, reg, DI_POL);
4555 + mutex_unlock(&di_mutex);
4559 +EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
4561 +int ipu_di_enable(struct ipu_di *di)
4565 + WARN_ON(IS_ERR(di->clk_di_pixel));
4567 + ret = clk_prepare_enable(di->clk_di_pixel);
4571 + ipu_module_enable(di->ipu, di->module);
4575 +EXPORT_SYMBOL_GPL(ipu_di_enable);
4577 +int ipu_di_disable(struct ipu_di *di)
4579 + WARN_ON(IS_ERR(di->clk_di_pixel));
4581 + ipu_module_disable(di->ipu, di->module);
4583 + clk_disable_unprepare(di->clk_di_pixel);
4587 +EXPORT_SYMBOL_GPL(ipu_di_disable);
4589 +int ipu_di_get_num(struct ipu_di *di)
4593 +EXPORT_SYMBOL_GPL(ipu_di_get_num);
4595 +static DEFINE_MUTEX(ipu_di_lock);
4597 +struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
4599 + struct ipu_di *di;
4602 + return ERR_PTR(-EINVAL);
4604 + di = ipu->di_priv[disp];
4606 + mutex_lock(&ipu_di_lock);
4609 + di = ERR_PTR(-EBUSY);
4615 + mutex_unlock(&ipu_di_lock);
4619 +EXPORT_SYMBOL_GPL(ipu_di_get);
4621 +void ipu_di_put(struct ipu_di *di)
4623 + mutex_lock(&ipu_di_lock);
4625 + di->inuse = false;
4627 + mutex_unlock(&ipu_di_lock);
4629 +EXPORT_SYMBOL_GPL(ipu_di_put);
4631 +int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
4632 + unsigned long base,
4633 + u32 module, struct clk *clk_ipu)
4635 + struct ipu_di *di;
4640 + di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
4644 + ipu->di_priv[id] = di;
4646 + di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
4647 + if (IS_ERR(di->clk_di))
4648 + return PTR_ERR(di->clk_di);
4650 + di->module = module;
4652 + di->clk_ipu = clk_ipu;
4653 + di->base = devm_ioremap(dev, base, PAGE_SIZE);
4657 + ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
4659 + dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
4660 + id, base, di->base);
4661 + di->inuse = false;
4667 +void ipu_di_exit(struct ipu_soc *ipu, int id)
4671 +++ b/drivers/gpu/imx/ipu-v3/ipu-dmfc.c
4673 +// SPDX-License-Identifier: GPL-2.0-or-later
4675 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
4676 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
4678 +#include <linux/export.h>
4679 +#include <linux/types.h>
4680 +#include <linux/errno.h>
4681 +#include <linux/io.h>
4683 +#include <video/imx-ipu-v3.h>
4684 +#include "ipu-prv.h"
4686 +#define DMFC_RD_CHAN 0x0000
4687 +#define DMFC_WR_CHAN 0x0004
4688 +#define DMFC_WR_CHAN_DEF 0x0008
4689 +#define DMFC_DP_CHAN 0x000c
4690 +#define DMFC_DP_CHAN_DEF 0x0010
4691 +#define DMFC_GENERAL1 0x0014
4692 +#define DMFC_GENERAL2 0x0018
4693 +#define DMFC_IC_CTRL 0x001c
4694 +#define DMFC_WR_CHAN_ALT 0x0020
4695 +#define DMFC_WR_CHAN_DEF_ALT 0x0024
4696 +#define DMFC_DP_CHAN_ALT 0x0028
4697 +#define DMFC_DP_CHAN_DEF_ALT 0x002c
4698 +#define DMFC_GENERAL1_ALT 0x0030
4699 +#define DMFC_STAT 0x0034
4701 +#define DMFC_WR_CHAN_1_28 0
4702 +#define DMFC_WR_CHAN_2_41 8
4703 +#define DMFC_WR_CHAN_1C_42 16
4704 +#define DMFC_WR_CHAN_2C_43 24
4706 +#define DMFC_DP_CHAN_5B_23 0
4707 +#define DMFC_DP_CHAN_5F_27 8
4708 +#define DMFC_DP_CHAN_6B_24 16
4709 +#define DMFC_DP_CHAN_6F_29 24
4711 +struct dmfc_channel_data {
4713 + unsigned long channel_reg;
4714 + unsigned long shift;
4715 + unsigned eot_shift;
4716 + unsigned max_fifo_lines;
4719 +static const struct dmfc_channel_data dmfcdata[] = {
4721 + .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
4722 + .channel_reg = DMFC_DP_CHAN,
4723 + .shift = DMFC_DP_CHAN_5B_23,
4725 + .max_fifo_lines = 3,
4727 + .ipu_channel = 24,
4728 + .channel_reg = DMFC_DP_CHAN,
4729 + .shift = DMFC_DP_CHAN_6B_24,
4731 + .max_fifo_lines = 1,
4733 + .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
4734 + .channel_reg = DMFC_DP_CHAN,
4735 + .shift = DMFC_DP_CHAN_5F_27,
4737 + .max_fifo_lines = 2,
4739 + .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
4740 + .channel_reg = DMFC_WR_CHAN,
4741 + .shift = DMFC_WR_CHAN_1_28,
4743 + .max_fifo_lines = 2,
4745 + .ipu_channel = 29,
4746 + .channel_reg = DMFC_DP_CHAN,
4747 + .shift = DMFC_DP_CHAN_6F_29,
4749 + .max_fifo_lines = 1,
4753 +#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
4755 +struct ipu_dmfc_priv;
4757 +struct dmfc_channel {
4759 + struct ipu_soc *ipu;
4760 + struct ipu_dmfc_priv *priv;
4761 + const struct dmfc_channel_data *data;
4764 +struct ipu_dmfc_priv {
4765 + struct ipu_soc *ipu;
4766 + struct device *dev;
4767 + struct dmfc_channel channels[DMFC_NUM_CHANNELS];
4768 + struct mutex mutex;
4769 + void __iomem *base;
4773 +int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
4775 + struct ipu_dmfc_priv *priv = dmfc->priv;
4776 + mutex_lock(&priv->mutex);
4778 + if (!priv->use_count)
4779 + ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
4781 + priv->use_count++;
4783 + mutex_unlock(&priv->mutex);
4787 +EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
4789 +void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
4791 + struct ipu_dmfc_priv *priv = dmfc->priv;
4793 + mutex_lock(&priv->mutex);
4795 + priv->use_count--;
4797 + if (!priv->use_count)
4798 + ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
4800 + if (priv->use_count < 0)
4801 + priv->use_count = 0;
4803 + mutex_unlock(&priv->mutex);
4805 +EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
4807 +void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
4809 + struct ipu_dmfc_priv *priv = dmfc->priv;
4812 + mutex_lock(&priv->mutex);
4814 + dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
4816 + if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
4817 + dmfc_gen1 |= 1 << dmfc->data->eot_shift;
4819 + dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
4821 + writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
4823 + mutex_unlock(&priv->mutex);
4825 +EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
4827 +struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
4829 + struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
4832 + for (i = 0; i < DMFC_NUM_CHANNELS; i++)
4833 + if (dmfcdata[i].ipu_channel == ipu_channel)
4834 + return &priv->channels[i];
4835 + return ERR_PTR(-ENODEV);
4837 +EXPORT_SYMBOL_GPL(ipu_dmfc_get);
4839 +void ipu_dmfc_put(struct dmfc_channel *dmfc)
4842 +EXPORT_SYMBOL_GPL(ipu_dmfc_put);
4844 +int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
4845 + struct clk *ipu_clk)
4847 + struct ipu_dmfc_priv *priv;
4850 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4854 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
4860 + mutex_init(&priv->mutex);
4862 + ipu->dmfc_priv = priv;
4864 + for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
4865 + priv->channels[i].priv = priv;
4866 + priv->channels[i].ipu = ipu;
4867 + priv->channels[i].data = &dmfcdata[i];
4869 + if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
4870 + dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
4871 + dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
4872 + priv->channels[i].slots = 2;
4875 + writel(0x00000050, priv->base + DMFC_WR_CHAN);
4876 + writel(0x00005654, priv->base + DMFC_DP_CHAN);
4877 + writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
4878 + writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
4879 + writel(0x00000003, priv->base + DMFC_GENERAL1);
4884 +void ipu_dmfc_exit(struct ipu_soc *ipu)
4888 +++ b/drivers/gpu/imx/ipu-v3/ipu-dp.c
4890 +// SPDX-License-Identifier: GPL-2.0-or-later
4892 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
4893 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
4895 +#include <linux/export.h>
4896 +#include <linux/kernel.h>
4897 +#include <linux/types.h>
4898 +#include <linux/errno.h>
4899 +#include <linux/io.h>
4900 +#include <linux/err.h>
4902 +#include <video/imx-ipu-v3.h>
4903 +#include "ipu-prv.h"
4906 +#define DP_ASYNC0 0x60
4907 +#define DP_ASYNC1 0xBC
4909 +#define DP_COM_CONF 0x0
4910 +#define DP_GRAPH_WIND_CTRL 0x0004
4911 +#define DP_FG_POS 0x0008
4912 +#define DP_CSC_A_0 0x0044
4913 +#define DP_CSC_A_1 0x0048
4914 +#define DP_CSC_A_2 0x004C
4915 +#define DP_CSC_A_3 0x0050
4916 +#define DP_CSC_0 0x0054
4917 +#define DP_CSC_1 0x0058
4919 +#define DP_COM_CONF_FG_EN (1 << 0)
4920 +#define DP_COM_CONF_GWSEL (1 << 1)
4921 +#define DP_COM_CONF_GWAM (1 << 2)
4922 +#define DP_COM_CONF_GWCKE (1 << 3)
4923 +#define DP_COM_CONF_CSC_DEF_MASK (3 << 8)
4924 +#define DP_COM_CONF_CSC_DEF_OFFSET 8
4925 +#define DP_COM_CONF_CSC_DEF_FG (3 << 8)
4926 +#define DP_COM_CONF_CSC_DEF_BG (2 << 8)
4927 +#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8)
4929 +#define IPUV3_NUM_FLOWS 3
4931 +struct ipu_dp_priv;
4937 + enum ipu_color_space in_cs;
4941 + struct ipu_dp foreground;
4942 + struct ipu_dp background;
4943 + enum ipu_color_space out_cs;
4944 + void __iomem *base;
4945 + struct ipu_dp_priv *priv;
4948 +struct ipu_dp_priv {
4949 + struct ipu_soc *ipu;
4950 + struct device *dev;
4951 + void __iomem *base;
4952 + struct ipu_flow flow[IPUV3_NUM_FLOWS];
4953 + struct mutex mutex;
4957 +static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
4959 +static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
4961 + if (dp->foreground)
4962 + return container_of(dp, struct ipu_flow, foreground);
4964 + return container_of(dp, struct ipu_flow, background);
4967 +int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
4968 + u8 alpha, bool bg_chan)
4970 + struct ipu_flow *flow = to_flow(dp);
4971 + struct ipu_dp_priv *priv = flow->priv;
4974 + mutex_lock(&priv->mutex);
4976 + reg = readl(flow->base + DP_COM_CONF);
4978 + reg &= ~DP_COM_CONF_GWSEL;
4980 + reg |= DP_COM_CONF_GWSEL;
4981 + writel(reg, flow->base + DP_COM_CONF);
4984 + reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
4985 + writel(reg | ((u32) alpha << 24),
4986 + flow->base + DP_GRAPH_WIND_CTRL);
4988 + reg = readl(flow->base + DP_COM_CONF);
4989 + writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
4991 + reg = readl(flow->base + DP_COM_CONF);
4992 + writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
4995 + ipu_srm_dp_update(priv->ipu, true);
4997 + mutex_unlock(&priv->mutex);
5001 +EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
5003 +int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
5005 + struct ipu_flow *flow = to_flow(dp);
5006 + struct ipu_dp_priv *priv = flow->priv;
5008 + writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
5010 + ipu_srm_dp_update(priv->ipu, true);
5014 +EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
5016 +static void ipu_dp_csc_init(struct ipu_flow *flow,
5017 + enum ipu_color_space in,
5018 + enum ipu_color_space out,
5023 + reg = readl(flow->base + DP_COM_CONF);
5024 + reg &= ~DP_COM_CONF_CSC_DEF_MASK;
5027 + writel(reg, flow->base + DP_COM_CONF);
5031 + if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
5032 + writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
5033 + writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
5034 + writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
5035 + writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
5036 + writel(0x3d6 | (0x0000 << 16) | (2 << 30),
5037 + flow->base + DP_CSC_0);
5038 + writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
5039 + flow->base + DP_CSC_1);
5041 + writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
5042 + writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
5043 + writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
5044 + writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
5045 + writel(0x000 | (0x3e42 << 16) | (1 << 30),
5046 + flow->base + DP_CSC_0);
5047 + writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
5048 + flow->base + DP_CSC_1);
5053 + writel(reg, flow->base + DP_COM_CONF);
5056 +int ipu_dp_setup_channel(struct ipu_dp *dp,
5057 + enum ipu_color_space in,
5058 + enum ipu_color_space out)
5060 + struct ipu_flow *flow = to_flow(dp);
5061 + struct ipu_dp_priv *priv = flow->priv;
5063 + mutex_lock(&priv->mutex);
5067 + if (!dp->foreground)
5068 + flow->out_cs = out;
5070 + if (flow->foreground.in_cs == flow->background.in_cs) {
5072 + * foreground and background are of same colorspace, put
5073 + * colorspace converter after combining unit.
5075 + ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
5076 + DP_COM_CONF_CSC_DEF_BOTH);
5078 + if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
5079 + flow->foreground.in_cs == flow->out_cs)
5081 + * foreground identical to output, apply color
5082 + * conversion on background
5084 + ipu_dp_csc_init(flow, flow->background.in_cs,
5085 + flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
5087 + ipu_dp_csc_init(flow, flow->foreground.in_cs,
5088 + flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
5091 + ipu_srm_dp_update(priv->ipu, true);
5093 + mutex_unlock(&priv->mutex);
5097 +EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
5099 +int ipu_dp_enable(struct ipu_soc *ipu)
5101 + struct ipu_dp_priv *priv = ipu->dp_priv;
5103 + mutex_lock(&priv->mutex);
5105 + if (!priv->use_count)
5106 + ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
5108 + priv->use_count++;
5110 + mutex_unlock(&priv->mutex);
5114 +EXPORT_SYMBOL_GPL(ipu_dp_enable);
5116 +int ipu_dp_enable_channel(struct ipu_dp *dp)
5118 + struct ipu_flow *flow = to_flow(dp);
5119 + struct ipu_dp_priv *priv = flow->priv;
5122 + if (!dp->foreground)
5125 + mutex_lock(&priv->mutex);
5127 + reg = readl(flow->base + DP_COM_CONF);
5128 + reg |= DP_COM_CONF_FG_EN;
5129 + writel(reg, flow->base + DP_COM_CONF);
5131 + ipu_srm_dp_update(priv->ipu, true);
5133 + mutex_unlock(&priv->mutex);
5137 +EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
5139 +void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
5141 + struct ipu_flow *flow = to_flow(dp);
5142 + struct ipu_dp_priv *priv = flow->priv;
5145 + dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
5147 + if (!dp->foreground)
5150 + mutex_lock(&priv->mutex);
5152 + reg = readl(flow->base + DP_COM_CONF);
5153 + csc = reg & DP_COM_CONF_CSC_DEF_MASK;
5154 + reg &= ~DP_COM_CONF_CSC_DEF_MASK;
5155 + if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
5156 + reg |= DP_COM_CONF_CSC_DEF_BG;
5158 + reg &= ~DP_COM_CONF_FG_EN;
5159 + writel(reg, flow->base + DP_COM_CONF);
5161 + writel(0, flow->base + DP_FG_POS);
5162 + ipu_srm_dp_update(priv->ipu, sync);
5164 + mutex_unlock(&priv->mutex);
5166 +EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
5168 +void ipu_dp_disable(struct ipu_soc *ipu)
5170 + struct ipu_dp_priv *priv = ipu->dp_priv;
5172 + mutex_lock(&priv->mutex);
5174 + priv->use_count--;
5176 + if (!priv->use_count)
5177 + ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
5179 + if (priv->use_count < 0)
5180 + priv->use_count = 0;
5182 + mutex_unlock(&priv->mutex);
5184 +EXPORT_SYMBOL_GPL(ipu_dp_disable);
5186 +struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
5188 + struct ipu_dp_priv *priv = ipu->dp_priv;
5189 + struct ipu_dp *dp;
5191 + if ((flow >> 1) >= IPUV3_NUM_FLOWS)
5192 + return ERR_PTR(-EINVAL);
5195 + dp = &priv->flow[flow >> 1].foreground;
5197 + dp = &priv->flow[flow >> 1].background;
5200 + return ERR_PTR(-EBUSY);
5202 + dp->in_use = true;
5206 +EXPORT_SYMBOL_GPL(ipu_dp_get);
5208 +void ipu_dp_put(struct ipu_dp *dp)
5210 + dp->in_use = false;
5212 +EXPORT_SYMBOL_GPL(ipu_dp_put);
5214 +int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
5216 + struct ipu_dp_priv *priv;
5219 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5225 + ipu->dp_priv = priv;
5227 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
5231 + mutex_init(&priv->mutex);
5233 + for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
5234 + priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
5235 + priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
5236 + priv->flow[i].foreground.foreground = true;
5237 + priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
5238 + priv->flow[i].priv = priv;
5244 +void ipu_dp_exit(struct ipu_soc *ipu)
5248 +++ b/drivers/gpu/imx/ipu-v3/ipu-ic.c
5250 +// SPDX-License-Identifier: GPL-2.0-or-later
5252 + * Copyright (C) 2012-2014 Mentor Graphics Inc.
5253 + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
5256 +#include <linux/types.h>
5257 +#include <linux/init.h>
5258 +#include <linux/errno.h>
5259 +#include <linux/spinlock.h>
5260 +#include <linux/bitrev.h>
5261 +#include <linux/io.h>
5262 +#include <linux/err.h>
5263 +#include <linux/sizes.h>
5264 +#include "ipu-prv.h"
5266 +/* IC Register Offsets */
5267 +#define IC_CONF 0x0000
5268 +#define IC_PRP_ENC_RSC 0x0004
5269 +#define IC_PRP_VF_RSC 0x0008
5270 +#define IC_PP_RSC 0x000C
5271 +#define IC_CMBP_1 0x0010
5272 +#define IC_CMBP_2 0x0014
5273 +#define IC_IDMAC_1 0x0018
5274 +#define IC_IDMAC_2 0x001C
5275 +#define IC_IDMAC_3 0x0020
5276 +#define IC_IDMAC_4 0x0024
5278 +/* IC Register Fields */
5279 +#define IC_CONF_PRPENC_EN (1 << 0)
5280 +#define IC_CONF_PRPENC_CSC1 (1 << 1)
5281 +#define IC_CONF_PRPENC_ROT_EN (1 << 2)
5282 +#define IC_CONF_PRPVF_EN (1 << 8)
5283 +#define IC_CONF_PRPVF_CSC1 (1 << 9)
5284 +#define IC_CONF_PRPVF_CSC2 (1 << 10)
5285 +#define IC_CONF_PRPVF_CMB (1 << 11)
5286 +#define IC_CONF_PRPVF_ROT_EN (1 << 12)
5287 +#define IC_CONF_PP_EN (1 << 16)
5288 +#define IC_CONF_PP_CSC1 (1 << 17)
5289 +#define IC_CONF_PP_CSC2 (1 << 18)
5290 +#define IC_CONF_PP_CMB (1 << 19)
5291 +#define IC_CONF_PP_ROT_EN (1 << 20)
5292 +#define IC_CONF_IC_GLB_LOC_A (1 << 28)
5293 +#define IC_CONF_KEY_COLOR_EN (1 << 29)
5294 +#define IC_CONF_RWS_EN (1 << 30)
5295 +#define IC_CONF_CSI_MEM_WR_EN (1 << 31)
5297 +#define IC_IDMAC_1_CB0_BURST_16 (1 << 0)
5298 +#define IC_IDMAC_1_CB1_BURST_16 (1 << 1)
5299 +#define IC_IDMAC_1_CB2_BURST_16 (1 << 2)
5300 +#define IC_IDMAC_1_CB3_BURST_16 (1 << 3)
5301 +#define IC_IDMAC_1_CB4_BURST_16 (1 << 4)
5302 +#define IC_IDMAC_1_CB5_BURST_16 (1 << 5)
5303 +#define IC_IDMAC_1_CB6_BURST_16 (1 << 6)
5304 +#define IC_IDMAC_1_CB7_BURST_16 (1 << 7)
5305 +#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11)
5306 +#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11
5307 +#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14)
5308 +#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14
5309 +#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17)
5310 +#define IC_IDMAC_1_PP_ROT_OFFSET 17
5311 +#define IC_IDMAC_1_PP_FLIP_RS (1 << 22)
5312 +#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21)
5313 +#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20)
5315 +#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0)
5316 +#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
5317 +#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10)
5318 +#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10
5319 +#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20)
5320 +#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20
5322 +#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0)
5323 +#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0
5324 +#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10)
5325 +#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10
5326 +#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20)
5327 +#define IC_IDMAC_3_PP_WIDTH_OFFSET 20
5329 +struct ic_task_regoffs {
5334 +struct ic_task_bitfields {
5336 + u32 ic_conf_rot_en;
5337 + u32 ic_conf_cmb_en;
5338 + u32 ic_conf_csc1_en;
5339 + u32 ic_conf_csc2_en;
5340 + u32 ic_cmb_galpha_bit;
5343 +static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
5344 + [IC_TASK_ENCODER] = {
5345 + .rsc = IC_PRP_ENC_RSC,
5346 + .tpmem_csc = {0x2008, 0},
5348 + [IC_TASK_VIEWFINDER] = {
5349 + .rsc = IC_PRP_VF_RSC,
5350 + .tpmem_csc = {0x4028, 0x4040},
5352 + [IC_TASK_POST_PROCESSOR] = {
5354 + .tpmem_csc = {0x6060, 0x6078},
5358 +static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
5359 + [IC_TASK_ENCODER] = {
5360 + .ic_conf_en = IC_CONF_PRPENC_EN,
5361 + .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
5362 + .ic_conf_cmb_en = 0, /* NA */
5363 + .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
5364 + .ic_conf_csc2_en = 0, /* NA */
5365 + .ic_cmb_galpha_bit = 0, /* NA */
5367 + [IC_TASK_VIEWFINDER] = {
5368 + .ic_conf_en = IC_CONF_PRPVF_EN,
5369 + .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
5370 + .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
5371 + .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
5372 + .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
5373 + .ic_cmb_galpha_bit = 0,
5375 + [IC_TASK_POST_PROCESSOR] = {
5376 + .ic_conf_en = IC_CONF_PP_EN,
5377 + .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
5378 + .ic_conf_cmb_en = IC_CONF_PP_CMB,
5379 + .ic_conf_csc1_en = IC_CONF_PP_CSC1,
5380 + .ic_conf_csc2_en = IC_CONF_PP_CSC2,
5381 + .ic_cmb_galpha_bit = 8,
5385 +struct ipu_ic_priv;
5388 + enum ipu_ic_task task;
5389 + const struct ic_task_regoffs *reg;
5390 + const struct ic_task_bitfields *bit;
5392 + struct ipu_ic_colorspace in_cs;
5393 + struct ipu_ic_colorspace g_in_cs;
5394 + struct ipu_ic_colorspace out_cs;
5400 + struct ipu_ic_priv *priv;
5403 +struct ipu_ic_priv {
5404 + void __iomem *base;
5405 + void __iomem *tpmem_base;
5407 + struct ipu_soc *ipu;
5409 + int irt_use_count;
5410 + struct ipu_ic task[IC_NUM_TASKS];
5413 +static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
5415 + return readl(ic->priv->base + offset);
5418 +static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
5420 + writel(value, ic->priv->base + offset);
5423 +static int init_csc(struct ipu_ic *ic,
5424 + const struct ipu_ic_csc *csc,
5427 + struct ipu_ic_priv *priv = ic->priv;
5428 + u32 __iomem *base;
5429 + const u16 (*c)[3];
5433 + base = (u32 __iomem *)
5434 + (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
5436 + /* Cast to unsigned */
5437 + c = (const u16 (*)[3])csc->params.coeff;
5438 + a = (const u16 *)csc->params.offset;
5440 + param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
5441 + ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
5442 + writel(param, base++);
5444 + param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
5445 + (csc->params.sat << 10);
5446 + writel(param, base++);
5448 + param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
5449 + ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
5450 + writel(param, base++);
5452 + param = ((a[1] & 0x1fe0) >> 5);
5453 + writel(param, base++);
5455 + param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
5456 + ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
5457 + writel(param, base++);
5459 + param = ((a[2] & 0x1fe0) >> 5);
5460 + writel(param, base++);
5465 +static int calc_resize_coeffs(struct ipu_ic *ic,
5466 + u32 in_size, u32 out_size,
5467 + u32 *resize_coeff,
5468 + u32 *downsize_coeff)
5470 + struct ipu_ic_priv *priv = ic->priv;
5471 + struct ipu_soc *ipu = priv->ipu;
5472 + u32 temp_size, temp_downsize;
5475 + * Input size cannot be more than 4096, and output size cannot
5476 + * be more than 1024
5478 + if (in_size > 4096) {
5479 + dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
5482 + if (out_size > 1024) {
5483 + dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
5487 + /* Cannot downsize more than 4:1 */
5488 + if ((out_size << 2) < in_size) {
5489 + dev_err(ipu->dev, "Unsupported downsize\n");
5493 + /* Compute downsizing coefficient */
5494 + temp_downsize = 0;
5495 + temp_size = in_size;
5496 + while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
5497 + (temp_downsize < 2)) {
5501 + *downsize_coeff = temp_downsize;
5504 + * compute resizing coefficient using the following equation:
5505 + * resize_coeff = M * (SI - 1) / (SO - 1)
5506 + * where M = 2^13, SI = input size, SO = output size
5508 + *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
5509 + if (*resize_coeff >= 16384L) {
5510 + dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
5511 + *resize_coeff = 0x3FFF;
5517 +void ipu_ic_task_enable(struct ipu_ic *ic)
5519 + struct ipu_ic_priv *priv = ic->priv;
5520 + unsigned long flags;
5523 + spin_lock_irqsave(&priv->lock, flags);
5525 + ic_conf = ipu_ic_read(ic, IC_CONF);
5527 + ic_conf |= ic->bit->ic_conf_en;
5530 + ic_conf |= ic->bit->ic_conf_rot_en;
5532 + if (ic->in_cs.cs != ic->out_cs.cs)
5533 + ic_conf |= ic->bit->ic_conf_csc1_en;
5535 + if (ic->graphics) {
5536 + ic_conf |= ic->bit->ic_conf_cmb_en;
5537 + ic_conf |= ic->bit->ic_conf_csc1_en;
5539 + if (ic->g_in_cs.cs != ic->out_cs.cs)
5540 + ic_conf |= ic->bit->ic_conf_csc2_en;
5543 + ipu_ic_write(ic, ic_conf, IC_CONF);
5545 + spin_unlock_irqrestore(&priv->lock, flags);
5547 +EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
5549 +void ipu_ic_task_disable(struct ipu_ic *ic)
5551 + struct ipu_ic_priv *priv = ic->priv;
5552 + unsigned long flags;
5555 + spin_lock_irqsave(&priv->lock, flags);
5557 + ic_conf = ipu_ic_read(ic, IC_CONF);
5559 + ic_conf &= ~(ic->bit->ic_conf_en |
5560 + ic->bit->ic_conf_csc1_en |
5561 + ic->bit->ic_conf_rot_en);
5562 + if (ic->bit->ic_conf_csc2_en)
5563 + ic_conf &= ~ic->bit->ic_conf_csc2_en;
5564 + if (ic->bit->ic_conf_cmb_en)
5565 + ic_conf &= ~ic->bit->ic_conf_cmb_en;
5567 + ipu_ic_write(ic, ic_conf, IC_CONF);
5569 + spin_unlock_irqrestore(&priv->lock, flags);
5571 +EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
5573 +int ipu_ic_task_graphics_init(struct ipu_ic *ic,
5574 + const struct ipu_ic_colorspace *g_in_cs,
5575 + bool galpha_en, u32 galpha,
5576 + bool colorkey_en, u32 colorkey)
5578 + struct ipu_ic_priv *priv = ic->priv;
5579 + struct ipu_ic_csc csc2;
5580 + unsigned long flags;
5584 + if (ic->task == IC_TASK_ENCODER)
5587 + spin_lock_irqsave(&priv->lock, flags);
5589 + ic_conf = ipu_ic_read(ic, IC_CONF);
5591 + if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
5592 + struct ipu_ic_csc csc1;
5594 + ret = ipu_ic_calc_csc(&csc1,
5595 + V4L2_YCBCR_ENC_601,
5596 + V4L2_QUANTIZATION_FULL_RANGE,
5597 + IPUV3_COLORSPACE_RGB,
5598 + V4L2_YCBCR_ENC_601,
5599 + V4L2_QUANTIZATION_FULL_RANGE,
5600 + IPUV3_COLORSPACE_RGB);
5604 + /* need transparent CSC1 conversion */
5605 + ret = init_csc(ic, &csc1, 0);
5610 + ic->g_in_cs = *g_in_cs;
5611 + csc2.in_cs = ic->g_in_cs;
5612 + csc2.out_cs = ic->out_cs;
5614 + ret = __ipu_ic_calc_csc(&csc2);
5618 + ret = init_csc(ic, &csc2, 1);
5623 + ic_conf |= IC_CONF_IC_GLB_LOC_A;
5624 + reg = ipu_ic_read(ic, IC_CMBP_1);
5625 + reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
5626 + reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
5627 + ipu_ic_write(ic, reg, IC_CMBP_1);
5629 + ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
5631 + if (colorkey_en) {
5632 + ic_conf |= IC_CONF_KEY_COLOR_EN;
5633 + ipu_ic_write(ic, colorkey, IC_CMBP_2);
5635 + ic_conf &= ~IC_CONF_KEY_COLOR_EN;
5637 + ipu_ic_write(ic, ic_conf, IC_CONF);
5639 + ic->graphics = true;
5641 + spin_unlock_irqrestore(&priv->lock, flags);
5644 +EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
5646 +int ipu_ic_task_init_rsc(struct ipu_ic *ic,
5647 + const struct ipu_ic_csc *csc,
5648 + int in_width, int in_height,
5649 + int out_width, int out_height,
5652 + struct ipu_ic_priv *priv = ic->priv;
5653 + u32 downsize_coeff, resize_coeff;
5654 + unsigned long flags;
5658 + /* Setup vertical resizing */
5660 + ret = calc_resize_coeffs(ic, in_height, out_height,
5661 + &resize_coeff, &downsize_coeff);
5665 + rsc = (downsize_coeff << 30) | (resize_coeff << 16);
5667 + /* Setup horizontal resizing */
5668 + ret = calc_resize_coeffs(ic, in_width, out_width,
5669 + &resize_coeff, &downsize_coeff);
5673 + rsc |= (downsize_coeff << 14) | resize_coeff;
5676 + spin_lock_irqsave(&priv->lock, flags);
5678 + ipu_ic_write(ic, rsc, ic->reg->rsc);
5680 + /* Setup color space conversion */
5681 + ic->in_cs = csc->in_cs;
5682 + ic->out_cs = csc->out_cs;
5684 + ret = init_csc(ic, csc, 0);
5686 + spin_unlock_irqrestore(&priv->lock, flags);
5690 +int ipu_ic_task_init(struct ipu_ic *ic,
5691 + const struct ipu_ic_csc *csc,
5692 + int in_width, int in_height,
5693 + int out_width, int out_height)
5695 + return ipu_ic_task_init_rsc(ic, csc,
5696 + in_width, in_height,
5697 + out_width, out_height, 0);
5699 +EXPORT_SYMBOL_GPL(ipu_ic_task_init);
5701 +int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
5702 + u32 width, u32 height, int burst_size,
5703 + enum ipu_rotate_mode rot)
5705 + struct ipu_ic_priv *priv = ic->priv;
5706 + struct ipu_soc *ipu = priv->ipu;
5707 + u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
5708 + u32 temp_rot = bitrev8(rot) >> 5;
5709 + bool need_hor_flip = false;
5710 + unsigned long flags;
5713 + if ((burst_size != 8) && (burst_size != 16)) {
5714 + dev_err(ipu->dev, "Illegal burst length for IC\n");
5721 + if (temp_rot & 0x2) /* Need horizontal flip */
5722 + need_hor_flip = true;
5724 + spin_lock_irqsave(&priv->lock, flags);
5726 + ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
5727 + ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
5728 + ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
5730 + switch (channel->num) {
5731 + case IPUV3_CHANNEL_IC_PP_MEM:
5732 + if (burst_size == 16)
5733 + ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
5735 + ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
5737 + if (need_hor_flip)
5738 + ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
5740 + ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
5742 + ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
5743 + ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
5745 + ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
5746 + ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
5748 + case IPUV3_CHANNEL_MEM_IC_PP:
5749 + if (burst_size == 16)
5750 + ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
5752 + ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
5754 + case IPUV3_CHANNEL_MEM_ROT_PP:
5755 + ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
5756 + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
5758 + case IPUV3_CHANNEL_MEM_IC_PRP_VF:
5759 + if (burst_size == 16)
5760 + ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
5762 + ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
5764 + case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
5765 + if (burst_size == 16)
5766 + ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
5768 + ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
5770 + if (need_hor_flip)
5771 + ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
5773 + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
5775 + ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
5776 + ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
5778 + ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
5779 + ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
5781 + case IPUV3_CHANNEL_MEM_ROT_ENC:
5782 + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
5783 + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
5785 + case IPUV3_CHANNEL_IC_PRP_VF_MEM:
5786 + if (burst_size == 16)
5787 + ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
5789 + ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
5791 + if (need_hor_flip)
5792 + ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
5794 + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
5796 + ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
5797 + ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
5799 + ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
5800 + ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
5802 + case IPUV3_CHANNEL_MEM_ROT_VF:
5803 + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
5804 + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
5806 + case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
5807 + if (burst_size == 16)
5808 + ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
5810 + ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
5812 + case IPUV3_CHANNEL_G_MEM_IC_PP:
5813 + if (burst_size == 16)
5814 + ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
5816 + ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
5818 + case IPUV3_CHANNEL_VDI_MEM_IC_VF:
5819 + if (burst_size == 16)
5820 + ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
5822 + ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
5828 + ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
5829 + ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
5830 + ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
5832 + if (ipu_rot_mode_is_irt(rot))
5833 + ic->rotation = true;
5836 + spin_unlock_irqrestore(&priv->lock, flags);
5839 +EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
5841 +static void ipu_irt_enable(struct ipu_ic *ic)
5843 + struct ipu_ic_priv *priv = ic->priv;
5845 + if (!priv->irt_use_count)
5846 + ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
5848 + priv->irt_use_count++;
5851 +static void ipu_irt_disable(struct ipu_ic *ic)
5853 + struct ipu_ic_priv *priv = ic->priv;
5855 + if (priv->irt_use_count) {
5856 + if (!--priv->irt_use_count)
5857 + ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
5861 +int ipu_ic_enable(struct ipu_ic *ic)
5863 + struct ipu_ic_priv *priv = ic->priv;
5864 + unsigned long flags;
5866 + spin_lock_irqsave(&priv->lock, flags);
5868 + if (!priv->use_count)
5869 + ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
5871 + priv->use_count++;
5874 + ipu_irt_enable(ic);
5876 + spin_unlock_irqrestore(&priv->lock, flags);
5880 +EXPORT_SYMBOL_GPL(ipu_ic_enable);
5882 +int ipu_ic_disable(struct ipu_ic *ic)
5884 + struct ipu_ic_priv *priv = ic->priv;
5885 + unsigned long flags;
5887 + spin_lock_irqsave(&priv->lock, flags);
5889 + priv->use_count--;
5891 + if (!priv->use_count)
5892 + ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
5894 + if (priv->use_count < 0)
5895 + priv->use_count = 0;
5898 + ipu_irt_disable(ic);
5900 + ic->rotation = ic->graphics = false;
5902 + spin_unlock_irqrestore(&priv->lock, flags);
5906 +EXPORT_SYMBOL_GPL(ipu_ic_disable);
5908 +struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
5910 + struct ipu_ic_priv *priv = ipu->ic_priv;
5911 + unsigned long flags;
5912 + struct ipu_ic *ic, *ret;
5914 + if (task >= IC_NUM_TASKS)
5915 + return ERR_PTR(-EINVAL);
5917 + ic = &priv->task[task];
5919 + spin_lock_irqsave(&priv->lock, flags);
5922 + ret = ERR_PTR(-EBUSY);
5926 + ic->in_use = true;
5930 + spin_unlock_irqrestore(&priv->lock, flags);
5933 +EXPORT_SYMBOL_GPL(ipu_ic_get);
5935 +void ipu_ic_put(struct ipu_ic *ic)
5937 + struct ipu_ic_priv *priv = ic->priv;
5938 + unsigned long flags;
5940 + spin_lock_irqsave(&priv->lock, flags);
5941 + ic->in_use = false;
5942 + spin_unlock_irqrestore(&priv->lock, flags);
5944 +EXPORT_SYMBOL_GPL(ipu_ic_put);
5946 +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
5947 + unsigned long base, unsigned long tpmem_base)
5949 + struct ipu_ic_priv *priv;
5952 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5956 + ipu->ic_priv = priv;
5958 + spin_lock_init(&priv->lock);
5959 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
5962 + priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
5963 + if (!priv->tpmem_base)
5966 + dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
5970 + for (i = 0; i < IC_NUM_TASKS; i++) {
5971 + priv->task[i].task = i;
5972 + priv->task[i].priv = priv;
5973 + priv->task[i].reg = &ic_task_reg[i];
5974 + priv->task[i].bit = &ic_task_bit[i];
5980 +void ipu_ic_exit(struct ipu_soc *ipu)
5984 +void ipu_ic_dump(struct ipu_ic *ic)
5986 + struct ipu_ic_priv *priv = ic->priv;
5987 + struct ipu_soc *ipu = priv->ipu;
5989 + dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
5990 + ipu_ic_read(ic, IC_CONF));
5991 + dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
5992 + ipu_ic_read(ic, IC_PRP_ENC_RSC));
5993 + dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
5994 + ipu_ic_read(ic, IC_PRP_VF_RSC));
5995 + dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
5996 + ipu_ic_read(ic, IC_PP_RSC));
5997 + dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
5998 + ipu_ic_read(ic, IC_CMBP_1));
5999 + dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
6000 + ipu_ic_read(ic, IC_CMBP_2));
6001 + dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
6002 + ipu_ic_read(ic, IC_IDMAC_1));
6003 + dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
6004 + ipu_ic_read(ic, IC_IDMAC_2));
6005 + dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
6006 + ipu_ic_read(ic, IC_IDMAC_3));
6007 + dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
6008 + ipu_ic_read(ic, IC_IDMAC_4));
6010 +EXPORT_SYMBOL_GPL(ipu_ic_dump);
6012 +++ b/drivers/gpu/imx/ipu-v3/ipu-image-convert.c
6014 +// SPDX-License-Identifier: GPL-2.0-or-later
6016 + * Copyright (C) 2012-2016 Mentor Graphics Inc.
6018 + * Queued image conversion support, with tiling and rotation.
6021 +#include <linux/interrupt.h>
6022 +#include <linux/dma-mapping.h>
6023 +#include <video/imx-ipu-image-convert.h>
6024 +#include "ipu-prv.h"
6027 + * The IC Resizer has a restriction that the output frame from the
6028 + * resizer must be 1024 or less in both width (pixels) and height
6031 + * The image converter attempts to split up a conversion when
6032 + * the desired output (converted) frame resolution exceeds the
6033 + * IC resizer limit of 1024 in either dimension.
6035 + * If either dimension of the output frame exceeds the limit, the
6036 + * dimension is split into 1, 2, or 4 equal stripes, for a maximum
6037 + * of 4*4 or 16 tiles. A conversion is then carried out for each
6038 + * tile (but taking care to pass the full frame stride length to
6039 + * the DMA channel's parameter memory!). IDMA double-buffering is used
6040 + * to convert each tile back-to-back when possible (see note below
6041 + * when double_buffering boolean is set).
6043 + * Note that the input frame must be split up into the same number
6044 + * of tiles as the output frame:
6046 + * +---------+-----+
6047 + * +-----+---+ | A | B |
6049 + * +-----+---+ --> +---------+-----+
6050 + * | C | D | | C | D |
6051 + * +-----+---+ | | |
6052 + * +---------+-----+
6054 + * Clockwise 90° rotations are handled by first rescaling into a
6055 + * reusable temporary tile buffer and then rotating with the 8x8
6056 + * block rotator, writing to the correct destination:
6060 + * +-----+---+ +---------+ | C | A |
6061 + * | A | B | | A,B, | | | | |
6062 + * +-----+---+ --> | C,D | | --> | | |
6063 + * | C | D | +---------+ +-----+-----+
6064 + * +-----+---+ | D | B |
6068 + * If the 8x8 block rotator is used, horizontal or vertical flipping
6069 + * is done during the rotation step, otherwise flipping is done
6070 + * during the scaling step.
6071 + * With rotation or flipping, tile order changes between input and
6072 + * output image. Tiles are numbered row major from top left to bottom
6073 + * right for both input and output image.
6076 +#define MAX_STRIPES_W 4
6077 +#define MAX_STRIPES_H 4
6078 +#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
6085 +enum ipu_image_convert_type {
6086 + IMAGE_CONVERT_IN = 0,
6087 + IMAGE_CONVERT_OUT,
6090 +struct ipu_image_convert_dma_buf {
6093 + unsigned long len;
6096 +struct ipu_image_convert_dma_chan {
6106 +/* dimensions of one tile */
6107 +struct ipu_image_tile {
6112 + /* size and strides are in bytes */
6116 + /* start Y or packed offset of this tile */
6118 + /* offset from start to tile in U plane, for planar formats */
6120 + /* offset from start to tile in V plane, for planar formats */
6124 +struct ipu_image_convert_image {
6125 + struct ipu_image base;
6126 + enum ipu_image_convert_type type;
6128 + const struct ipu_image_pixfmt *fmt;
6129 + unsigned int stride;
6131 + /* # of rows (horizontal stripes) if dest height is > 1024 */
6132 + unsigned int num_rows;
6133 + /* # of columns (vertical stripes) if dest width is > 1024 */
6134 + unsigned int num_cols;
6136 + struct ipu_image_tile tile[MAX_TILES];
6139 +struct ipu_image_pixfmt {
6140 + u32 fourcc; /* V4L2 fourcc */
6141 + int bpp; /* total bpp */
6142 + int uv_width_dec; /* decimation in width for U/V planes */
6143 + int uv_height_dec; /* decimation in height for U/V planes */
6144 + bool planar; /* planar format */
6145 + bool uv_swapped; /* U and V planes are swapped */
6146 + bool uv_packed; /* partial planar (U and V in same plane) */
6149 +struct ipu_image_convert_ctx;
6150 +struct ipu_image_convert_chan;
6151 +struct ipu_image_convert_priv;
6153 +struct ipu_image_convert_ctx {
6154 + struct ipu_image_convert_chan *chan;
6156 + ipu_image_convert_cb_t complete;
6157 + void *complete_context;
6159 + /* Source/destination image data and rotation mode */
6160 + struct ipu_image_convert_image in;
6161 + struct ipu_image_convert_image out;
6162 + struct ipu_ic_csc csc;
6163 + enum ipu_rotate_mode rot_mode;
6164 + u32 downsize_coeff_h;
6165 + u32 downsize_coeff_v;
6166 + u32 image_resize_coeff_h;
6167 + u32 image_resize_coeff_v;
6168 + u32 resize_coeffs_h[MAX_STRIPES_W];
6169 + u32 resize_coeffs_v[MAX_STRIPES_H];
6171 + /* intermediate buffer for rotation */
6172 + struct ipu_image_convert_dma_buf rot_intermediate[2];
6174 + /* current buffer number for double buffering */
6178 + struct completion aborted;
6180 + /* can we use double-buffering for this conversion operation? */
6181 + bool double_buffering;
6182 + /* num_rows * num_cols */
6183 + unsigned int num_tiles;
6184 + /* next tile to process */
6185 + unsigned int next_tile;
6186 + /* where to place converted tile in dest image */
6187 + unsigned int out_tile_map[MAX_TILES];
6189 + struct list_head list;
6192 +struct ipu_image_convert_chan {
6193 + struct ipu_image_convert_priv *priv;
6195 + enum ipu_ic_task ic_task;
6196 + const struct ipu_image_convert_dma_chan *dma_ch;
6198 + struct ipu_ic *ic;
6199 + struct ipuv3_channel *in_chan;
6200 + struct ipuv3_channel *out_chan;
6201 + struct ipuv3_channel *rotation_in_chan;
6202 + struct ipuv3_channel *rotation_out_chan;
6204 + /* the IPU end-of-frame irqs */
6206 + int rot_out_eof_irq;
6208 + spinlock_t irqlock;
6210 + /* list of convert contexts */
6211 + struct list_head ctx_list;
6212 + /* queue of conversion runs */
6213 + struct list_head pending_q;
6214 + /* queue of completed runs */
6215 + struct list_head done_q;
6217 + /* the current conversion run */
6218 + struct ipu_image_convert_run *current_run;
6221 +struct ipu_image_convert_priv {
6222 + struct ipu_image_convert_chan chan[IC_NUM_TASKS];
6223 + struct ipu_soc *ipu;
6226 +static const struct ipu_image_convert_dma_chan
6227 +image_convert_dma_chan[IC_NUM_TASKS] = {
6228 + [IC_TASK_VIEWFINDER] = {
6229 + .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
6230 + .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
6231 + .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
6232 + .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
6233 + .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
6234 + .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
6235 + .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
6237 + [IC_TASK_POST_PROCESSOR] = {
6238 + .in = IPUV3_CHANNEL_MEM_IC_PP,
6239 + .out = IPUV3_CHANNEL_IC_PP_MEM,
6240 + .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
6241 + .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
6245 +static const struct ipu_image_pixfmt image_convert_formats[] = {
6247 + .fourcc = V4L2_PIX_FMT_RGB565,
6250 + .fourcc = V4L2_PIX_FMT_RGB24,
6253 + .fourcc = V4L2_PIX_FMT_BGR24,
6256 + .fourcc = V4L2_PIX_FMT_RGB32,
6259 + .fourcc = V4L2_PIX_FMT_BGR32,
6262 + .fourcc = V4L2_PIX_FMT_XRGB32,
6265 + .fourcc = V4L2_PIX_FMT_XBGR32,
6268 + .fourcc = V4L2_PIX_FMT_BGRX32,
6271 + .fourcc = V4L2_PIX_FMT_RGBX32,
6274 + .fourcc = V4L2_PIX_FMT_YUYV,
6276 + .uv_width_dec = 2,
6277 + .uv_height_dec = 1,
6279 + .fourcc = V4L2_PIX_FMT_UYVY,
6281 + .uv_width_dec = 2,
6282 + .uv_height_dec = 1,
6284 + .fourcc = V4L2_PIX_FMT_YUV420,
6287 + .uv_width_dec = 2,
6288 + .uv_height_dec = 2,
6290 + .fourcc = V4L2_PIX_FMT_YVU420,
6293 + .uv_width_dec = 2,
6294 + .uv_height_dec = 2,
6295 + .uv_swapped = true,
6297 + .fourcc = V4L2_PIX_FMT_NV12,
6300 + .uv_width_dec = 2,
6301 + .uv_height_dec = 2,
6302 + .uv_packed = true,
6304 + .fourcc = V4L2_PIX_FMT_YUV422P,
6307 + .uv_width_dec = 2,
6308 + .uv_height_dec = 1,
6310 + .fourcc = V4L2_PIX_FMT_NV16,
6313 + .uv_width_dec = 2,
6314 + .uv_height_dec = 1,
6315 + .uv_packed = true,
6319 +static const struct ipu_image_pixfmt *get_format(u32 fourcc)
6321 + const struct ipu_image_pixfmt *ret = NULL;
6324 + for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
6325 + if (image_convert_formats[i].fourcc == fourcc) {
6326 + ret = &image_convert_formats[i];
6334 +static void dump_format(struct ipu_image_convert_ctx *ctx,
6335 + struct ipu_image_convert_image *ic_image)
6337 + struct ipu_image_convert_chan *chan = ctx->chan;
6338 + struct ipu_image_convert_priv *priv = chan->priv;
6340 + dev_dbg(priv->ipu->dev,
6341 + "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
6342 + chan->ic_task, ctx,
6343 + ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
6344 + ic_image->base.pix.width, ic_image->base.pix.height,
6345 + ic_image->num_cols, ic_image->num_rows,
6346 + ic_image->fmt->fourcc & 0xff,
6347 + (ic_image->fmt->fourcc >> 8) & 0xff,
6348 + (ic_image->fmt->fourcc >> 16) & 0xff,
6349 + (ic_image->fmt->fourcc >> 24) & 0xff);
6352 +int ipu_image_convert_enum_format(int index, u32 *fourcc)
6354 + const struct ipu_image_pixfmt *fmt;
6356 + if (index >= (int)ARRAY_SIZE(image_convert_formats))
6359 + /* Format found */
6360 + fmt = &image_convert_formats[index];
6361 + *fourcc = fmt->fourcc;
6364 +EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
6366 +static void free_dma_buf(struct ipu_image_convert_priv *priv,
6367 + struct ipu_image_convert_dma_buf *buf)
6370 + dma_free_coherent(priv->ipu->dev,
6371 + buf->len, buf->virt, buf->phys);
6376 +static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
6377 + struct ipu_image_convert_dma_buf *buf,
6380 + buf->len = PAGE_ALIGN(size);
6381 + buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
6382 + GFP_DMA | GFP_KERNEL);
6384 + dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
6391 +static inline int num_stripes(int dim)
6393 + return (dim - 1) / 1024 + 1;
6397 + * Calculate downsizing coefficients, which are the same for all tiles,
6398 + * and initial bilinear resizing coefficients, which are used to find the
6399 + * best seam positions.
6400 + * Also determine the number of tiles necessary to guarantee that no tile
6401 + * is larger than 1024 pixels in either dimension at the output and between
6402 + * IC downsizing and main processing sections.
6404 +static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
6405 + struct ipu_image *in,
6406 + struct ipu_image *out)
6408 + u32 downsized_width = in->rect.width;
6409 + u32 downsized_height = in->rect.height;
6410 + u32 downsize_coeff_v = 0;
6411 + u32 downsize_coeff_h = 0;
6412 + u32 resized_width = out->rect.width;
6413 + u32 resized_height = out->rect.height;
6414 + u32 resize_coeff_h;
6415 + u32 resize_coeff_v;
6419 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6420 + resized_width = out->rect.height;
6421 + resized_height = out->rect.width;
6424 + /* Do not let invalid input lead to an endless loop below */
6425 + if (WARN_ON(resized_width == 0 || resized_height == 0))
6428 + while (downsized_width >= resized_width * 2) {
6429 + downsized_width >>= 1;
6430 + downsize_coeff_h++;
6433 + while (downsized_height >= resized_height * 2) {
6434 + downsized_height >>= 1;
6435 + downsize_coeff_v++;
6439 + * Calculate the bilinear resizing coefficients that could be used if
6440 + * we were converting with a single tile. The bottom right output pixel
6441 + * should sample as close as possible to the bottom right input pixel
6442 + * out of the decimator, but not overshoot it:
6444 + resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
6445 + resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
6448 + * Both the output of the IC downsizing section before being passed to
6449 + * the IC main processing section and the final output of the IC main
6450 + * processing section must be <= 1024 pixels in both dimensions.
6452 + cols = num_stripes(max_t(u32, downsized_width, resized_width));
6453 + rows = num_stripes(max_t(u32, downsized_height, resized_height));
6455 + dev_dbg(ctx->chan->priv->ipu->dev,
6456 + "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
6457 + __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
6458 + resize_coeff_v, cols, rows);
6460 + if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
6461 + resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
6464 + ctx->downsize_coeff_h = downsize_coeff_h;
6465 + ctx->downsize_coeff_v = downsize_coeff_v;
6466 + ctx->image_resize_coeff_h = resize_coeff_h;
6467 + ctx->image_resize_coeff_v = resize_coeff_v;
6468 + ctx->in.num_cols = cols;
6469 + ctx->in.num_rows = rows;
6474 +#define round_closest(x, y) round_down((x) + (y)/2, (y))
6477 + * Find the best aligned seam position for the given column / row index.
6478 + * Rotation and image offsets are out of scope.
6480 + * @index: column / row index, used to calculate valid interval
6481 + * @in_edge: input right / bottom edge
6482 + * @out_edge: output right / bottom edge
6483 + * @in_align: input alignment, either horizontal 8-byte line start address
6484 + * alignment, or pixel alignment due to image format
6485 + * @out_align: output alignment, either horizontal 8-byte line start address
6486 + * alignment, or pixel alignment due to image format or rotator
6488 + * @in_burst: horizontal input burst size in case of horizontal flip
6489 + * @out_burst: horizontal output burst size or rotator block size
6490 + * @downsize_coeff: downsizing section coefficient
6491 + * @resize_coeff: main processing section resizing coefficient
6492 + * @_in_seam: aligned input seam position return value
6493 + * @_out_seam: aligned output seam position return value
6495 +static void find_best_seam(struct ipu_image_convert_ctx *ctx,
6496 + unsigned int index,
6497 + unsigned int in_edge,
6498 + unsigned int out_edge,
6499 + unsigned int in_align,
6500 + unsigned int out_align,
6501 + unsigned int in_burst,
6502 + unsigned int out_burst,
6503 + unsigned int downsize_coeff,
6504 + unsigned int resize_coeff,
6508 + struct device *dev = ctx->chan->priv->ipu->dev;
6509 + unsigned int out_pos;
6510 + /* Input / output seam position candidates */
6511 + unsigned int out_seam = 0;
6512 + unsigned int in_seam = 0;
6513 + unsigned int min_diff = UINT_MAX;
6514 + unsigned int out_start;
6515 + unsigned int out_end;
6516 + unsigned int in_start;
6517 + unsigned int in_end;
6519 + /* Start within 1024 pixels of the right / bottom edge */
6520 + out_start = max_t(int, index * out_align, out_edge - 1024);
6521 + /* End before having to add more columns to the left / rows above */
6522 + out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
6525 + * Limit input seam position to make sure that the downsized input tile
6526 + * to the right or bottom does not exceed 1024 pixels.
6528 + in_start = max_t(int, index * in_align,
6529 + in_edge - (1024 << downsize_coeff));
6530 + in_end = min_t(unsigned int, in_edge,
6531 + index * (1024 << downsize_coeff) + 1);
6534 + * Output tiles must start at a multiple of 8 bytes horizontally and
6535 + * possibly at an even line horizontally depending on the pixel format.
6536 + * Only consider output aligned positions for the seam.
6538 + out_start = round_up(out_start, out_align);
6539 + for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
6540 + unsigned int in_pos;
6541 + unsigned int in_pos_aligned;
6542 + unsigned int in_pos_rounded;
6543 + unsigned int abs_diff;
6546 + * Tiles in the right row / bottom column may not be allowed to
6547 + * overshoot horizontally / vertically. out_burst may be the
6548 + * actual DMA burst size, or the rotator block size.
6550 + if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
6554 + * Input sample position, corresponding to out_pos, 19.13 fixed
6557 + in_pos = (out_pos * resize_coeff) << downsize_coeff;
6559 + * The closest input sample position that we could actually
6560 + * start the input tile at, 19.13 fixed point.
6562 + in_pos_aligned = round_closest(in_pos, 8192U * in_align);
6563 + /* Convert 19.13 fixed point to integer */
6564 + in_pos_rounded = in_pos_aligned / 8192U;
6566 + if (in_pos_rounded < in_start)
6568 + if (in_pos_rounded >= in_end)
6571 + if ((in_burst > 1) &&
6572 + (in_edge - in_pos_rounded) % in_burst)
6575 + if (in_pos < in_pos_aligned)
6576 + abs_diff = in_pos_aligned - in_pos;
6578 + abs_diff = in_pos - in_pos_aligned;
6580 + if (abs_diff < min_diff) {
6581 + in_seam = in_pos_rounded;
6582 + out_seam = out_pos;
6583 + min_diff = abs_diff;
6587 + *_out_seam = out_seam;
6588 + *_in_seam = in_seam;
6590 + dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
6591 + __func__, out_seam, out_align, out_start, out_end,
6592 + in_seam, in_align, in_start, in_end, min_diff / 8192,
6593 + DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
6597 + * Tile left edges are required to be aligned to multiples of 8 bytes
6600 +static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
6603 + return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
6605 + return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
6609 + * Tile top edge alignment is only limited by chroma subsampling.
6611 +static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
6613 + return fmt->uv_height_dec > 1 ? 2 : 1;
6616 +static inline u32 tile_width_align(enum ipu_image_convert_type type,
6617 + const struct ipu_image_pixfmt *fmt,
6618 + enum ipu_rotate_mode rot_mode)
6620 + if (type == IMAGE_CONVERT_IN) {
6622 + * The IC burst reads 8 pixels at a time. Reading beyond the
6623 + * end of the line is usually acceptable. Those pixels are
6624 + * ignored, unless the IC has to write the scaled line in
6627 + return (!ipu_rot_mode_is_irt(rot_mode) &&
6628 + (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
6632 + * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
6633 + * formats to guarantee 8-byte aligned line start addresses in the
6634 + * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
6635 + * for all other formats.
6637 + return (ipu_rot_mode_is_irt(rot_mode) &&
6638 + fmt->planar && !fmt->uv_packed) ?
6639 + 8 * fmt->uv_width_dec : 8;
6642 +static inline u32 tile_height_align(enum ipu_image_convert_type type,
6643 + const struct ipu_image_pixfmt *fmt,
6644 + enum ipu_rotate_mode rot_mode)
6646 + if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
6650 + * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
6651 + * formats to guarantee 8-byte aligned line start addresses in the
6652 + * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
6653 + * for all other formats.
6655 + return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
6659 + * Fill in left position and width and for all tiles in an input column, and
6660 + * for all corresponding output tiles. If the 90° rotator is used, the output
6661 + * tiles are in a row, and output tile top position and height are set.
6663 +static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
6665 + struct ipu_image_convert_image *in,
6666 + unsigned int in_left, unsigned int in_width,
6667 + struct ipu_image_convert_image *out,
6668 + unsigned int out_left, unsigned int out_width)
6670 + unsigned int row, tile_idx;
6671 + struct ipu_image_tile *in_tile, *out_tile;
6673 + for (row = 0; row < in->num_rows; row++) {
6674 + tile_idx = in->num_cols * row + col;
6675 + in_tile = &in->tile[tile_idx];
6676 + out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
6678 + in_tile->left = in_left;
6679 + in_tile->width = in_width;
6681 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6682 + out_tile->top = out_left;
6683 + out_tile->height = out_width;
6685 + out_tile->left = out_left;
6686 + out_tile->width = out_width;
6692 + * Fill in top position and height and for all tiles in an input row, and
6693 + * for all corresponding output tiles. If the 90° rotator is used, the output
6694 + * tiles are in a column, and output tile left position and width are set.
6696 +static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
6697 + struct ipu_image_convert_image *in,
6698 + unsigned int in_top, unsigned int in_height,
6699 + struct ipu_image_convert_image *out,
6700 + unsigned int out_top, unsigned int out_height)
6702 + unsigned int col, tile_idx;
6703 + struct ipu_image_tile *in_tile, *out_tile;
6705 + for (col = 0; col < in->num_cols; col++) {
6706 + tile_idx = in->num_cols * row + col;
6707 + in_tile = &in->tile[tile_idx];
6708 + out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
6710 + in_tile->top = in_top;
6711 + in_tile->height = in_height;
6713 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6714 + out_tile->left = out_top;
6715 + out_tile->width = out_height;
6717 + out_tile->top = out_top;
6718 + out_tile->height = out_height;
6724 + * Find the best horizontal and vertical seam positions to split into tiles.
6725 + * Minimize the fractional part of the input sampling position for the
6726 + * top / left pixels of each tile.
6728 +static void find_seams(struct ipu_image_convert_ctx *ctx,
6729 + struct ipu_image_convert_image *in,
6730 + struct ipu_image_convert_image *out)
6732 + struct device *dev = ctx->chan->priv->ipu->dev;
6733 + unsigned int resized_width = out->base.rect.width;
6734 + unsigned int resized_height = out->base.rect.height;
6737 + unsigned int in_left_align = tile_left_align(in->fmt);
6738 + unsigned int in_top_align = tile_top_align(in->fmt);
6739 + unsigned int out_left_align = tile_left_align(out->fmt);
6740 + unsigned int out_top_align = tile_top_align(out->fmt);
6741 + unsigned int out_width_align = tile_width_align(out->type, out->fmt,
6743 + unsigned int out_height_align = tile_height_align(out->type, out->fmt,
6745 + unsigned int in_right = in->base.rect.width;
6746 + unsigned int in_bottom = in->base.rect.height;
6747 + unsigned int out_right = out->base.rect.width;
6748 + unsigned int out_bottom = out->base.rect.height;
6749 + unsigned int flipped_out_left;
6750 + unsigned int flipped_out_top;
6752 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6753 + /* Switch width/height and align top left to IRT block size */
6754 + resized_width = out->base.rect.height;
6755 + resized_height = out->base.rect.width;
6756 + out_left_align = out_height_align;
6757 + out_top_align = out_width_align;
6758 + out_width_align = out_left_align;
6759 + out_height_align = out_top_align;
6760 + out_right = out->base.rect.height;
6761 + out_bottom = out->base.rect.width;
6764 + for (col = in->num_cols - 1; col > 0; col--) {
6765 + bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
6766 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
6767 + bool allow_out_overshoot = (col < in->num_cols - 1) &&
6768 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
6769 + unsigned int in_left;
6770 + unsigned int out_left;
6773 + * Align input width to burst length if the scaling step flips
6777 + find_best_seam(ctx, col,
6778 + in_right, out_right,
6779 + in_left_align, out_left_align,
6780 + allow_in_overshoot ? 1 : 8 /* burst length */,
6781 + allow_out_overshoot ? 1 : out_width_align,
6782 + ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
6783 + &in_left, &out_left);
6785 + if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
6786 + flipped_out_left = resized_width - out_right;
6788 + flipped_out_left = out_left;
6790 + fill_tile_column(ctx, col, in, in_left, in_right - in_left,
6791 + out, flipped_out_left, out_right - out_left);
6793 + dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
6794 + in_left, in_right - in_left,
6795 + flipped_out_left, out_right - out_left);
6797 + in_right = in_left;
6798 + out_right = out_left;
6801 + flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
6802 + resized_width - out_right : 0;
6804 + fill_tile_column(ctx, 0, in, 0, in_right,
6805 + out, flipped_out_left, out_right);
6807 + dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
6808 + in_right, flipped_out_left, out_right);
6810 + for (row = in->num_rows - 1; row > 0; row--) {
6811 + bool allow_overshoot = row < in->num_rows - 1;
6812 + unsigned int in_top;
6813 + unsigned int out_top;
6815 + find_best_seam(ctx, row,
6816 + in_bottom, out_bottom,
6817 + in_top_align, out_top_align,
6818 + 1, allow_overshoot ? 1 : out_height_align,
6819 + ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
6820 + &in_top, &out_top);
6822 + if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
6823 + ipu_rot_mode_is_irt(ctx->rot_mode))
6824 + flipped_out_top = resized_height - out_bottom;
6826 + flipped_out_top = out_top;
6828 + fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
6829 + out, flipped_out_top, out_bottom - out_top);
6831 + dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
6832 + in_top, in_bottom - in_top,
6833 + flipped_out_top, out_bottom - out_top);
6835 + in_bottom = in_top;
6836 + out_bottom = out_top;
6839 + if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
6840 + ipu_rot_mode_is_irt(ctx->rot_mode))
6841 + flipped_out_top = resized_height - out_bottom;
6843 + flipped_out_top = 0;
6845 + fill_tile_row(ctx, 0, in, 0, in_bottom,
6846 + out, flipped_out_top, out_bottom);
6848 + dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
6849 + in_bottom, flipped_out_top, out_bottom);
6852 +static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
6853 + struct ipu_image_convert_image *image)
6855 + struct ipu_image_convert_chan *chan = ctx->chan;
6856 + struct ipu_image_convert_priv *priv = chan->priv;
6857 + unsigned int max_width = 1024;
6858 + unsigned int max_height = 1024;
6861 + if (image->type == IMAGE_CONVERT_IN) {
6862 + /* Up to 4096x4096 input tile size */
6863 + max_width <<= ctx->downsize_coeff_h;
6864 + max_height <<= ctx->downsize_coeff_v;
6867 + for (i = 0; i < ctx->num_tiles; i++) {
6868 + struct ipu_image_tile *tile;
6869 + const unsigned int row = i / image->num_cols;
6870 + const unsigned int col = i % image->num_cols;
6872 + if (image->type == IMAGE_CONVERT_OUT)
6873 + tile = &image->tile[ctx->out_tile_map[i]];
6875 + tile = &image->tile[i];
6877 + tile->size = ((tile->height * image->fmt->bpp) >> 3) *
6880 + if (image->fmt->planar) {
6881 + tile->stride = tile->width;
6882 + tile->rot_stride = tile->height;
6885 + (image->fmt->bpp * tile->width) >> 3;
6886 + tile->rot_stride =
6887 + (image->fmt->bpp * tile->height) >> 3;
6890 + dev_dbg(priv->ipu->dev,
6891 + "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
6892 + chan->ic_task, ctx,
6893 + image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
6895 + tile->width, tile->height, tile->left, tile->top);
6897 + if (!tile->width || tile->width > max_width ||
6898 + !tile->height || tile->height > max_height) {
6899 + dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
6900 + image->type == IMAGE_CONVERT_IN ? "input" :
6901 + "output", tile->width, tile->height);
6910 + * Use the rotation transformation to find the tile coordinates
6911 + * (row, col) of a tile in the destination frame that corresponds
6912 + * to the given tile coordinates of a source frame. The destination
6913 + * coordinate is then converted to a tile index.
6915 +static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
6916 + int src_row, int src_col)
6918 + struct ipu_image_convert_chan *chan = ctx->chan;
6919 + struct ipu_image_convert_priv *priv = chan->priv;
6920 + struct ipu_image_convert_image *s_image = &ctx->in;
6921 + struct ipu_image_convert_image *d_image = &ctx->out;
6922 + int dst_row, dst_col;
6924 + /* with no rotation it's a 1:1 mapping */
6925 + if (ctx->rot_mode == IPU_ROTATE_NONE)
6926 + return src_row * s_image->num_cols + src_col;
6929 + * before doing the transform, first we have to translate
6930 + * source row,col for an origin in the center of s_image
6932 + src_row = src_row * 2 - (s_image->num_rows - 1);
6933 + src_col = src_col * 2 - (s_image->num_cols - 1);
6935 + /* do the rotation transform */
6936 + if (ctx->rot_mode & IPU_ROT_BIT_90) {
6937 + dst_col = -src_row;
6938 + dst_row = src_col;
6940 + dst_col = src_col;
6941 + dst_row = src_row;
6945 + if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
6946 + dst_col = -dst_col;
6947 + if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
6948 + dst_row = -dst_row;
6950 + dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
6951 + chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
6954 + * finally translate dest row,col using an origin in upper
6957 + dst_row += d_image->num_rows - 1;
6958 + dst_col += d_image->num_cols - 1;
6962 + return dst_row * d_image->num_cols + dst_col;
6966 + * Fill the out_tile_map[] with transformed destination tile indeces.
6968 +static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
6970 + struct ipu_image_convert_image *s_image = &ctx->in;
6971 + unsigned int row, col, tile = 0;
6973 + for (row = 0; row < s_image->num_rows; row++) {
6974 + for (col = 0; col < s_image->num_cols; col++) {
6975 + ctx->out_tile_map[tile] =
6976 + transform_tile_index(ctx, row, col);
6982 +static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
6983 + struct ipu_image_convert_image *image)
6985 + struct ipu_image_convert_chan *chan = ctx->chan;
6986 + struct ipu_image_convert_priv *priv = chan->priv;
6987 + const struct ipu_image_pixfmt *fmt = image->fmt;
6988 + unsigned int row, col, tile = 0;
6989 + u32 H, top, y_stride, uv_stride;
6990 + u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
6991 + u32 y_row_off, y_col_off, y_off;
6992 + u32 y_size, uv_size;
6994 + /* setup some convenience vars */
6995 + H = image->base.pix.height;
6997 + y_stride = image->stride;
6998 + uv_stride = y_stride / fmt->uv_width_dec;
6999 + if (fmt->uv_packed)
7002 + y_size = H * y_stride;
7003 + uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
7005 + for (row = 0; row < image->num_rows; row++) {
7006 + top = image->tile[tile].top;
7007 + y_row_off = top * y_stride;
7008 + uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
7010 + for (col = 0; col < image->num_cols; col++) {
7011 + y_col_off = image->tile[tile].left;
7012 + uv_col_off = y_col_off / fmt->uv_width_dec;
7013 + if (fmt->uv_packed)
7016 + y_off = y_row_off + y_col_off;
7017 + uv_off = uv_row_off + uv_col_off;
7019 + u_off = y_size - y_off + uv_off;
7020 + v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
7021 + if (fmt->uv_swapped) {
7027 + image->tile[tile].offset = y_off;
7028 + image->tile[tile].u_off = u_off;
7029 + image->tile[tile++].v_off = v_off;
7031 + if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
7032 + dev_err(priv->ipu->dev,
7033 + "task %u: ctx %p: %s@[%d,%d]: "
7034 + "y_off %08x, u_off %08x, v_off %08x\n",
7035 + chan->ic_task, ctx,
7036 + image->type == IMAGE_CONVERT_IN ?
7037 + "Input" : "Output", row, col,
7038 + y_off, u_off, v_off);
7047 +static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
7048 + struct ipu_image_convert_image *image)
7050 + struct ipu_image_convert_chan *chan = ctx->chan;
7051 + struct ipu_image_convert_priv *priv = chan->priv;
7052 + const struct ipu_image_pixfmt *fmt = image->fmt;
7053 + unsigned int row, col, tile = 0;
7054 + u32 bpp, stride, offset;
7055 + u32 row_off, col_off;
7057 + /* setup some convenience vars */
7058 + stride = image->stride;
7061 + for (row = 0; row < image->num_rows; row++) {
7062 + row_off = image->tile[tile].top * stride;
7064 + for (col = 0; col < image->num_cols; col++) {
7065 + col_off = (image->tile[tile].left * bpp) >> 3;
7067 + offset = row_off + col_off;
7069 + image->tile[tile].offset = offset;
7070 + image->tile[tile].u_off = 0;
7071 + image->tile[tile++].v_off = 0;
7073 + if (offset & 0x7) {
7074 + dev_err(priv->ipu->dev,
7075 + "task %u: ctx %p: %s@[%d,%d]: "
7077 + chan->ic_task, ctx,
7078 + image->type == IMAGE_CONVERT_IN ?
7079 + "Input" : "Output", row, col,
7080 + row_off + col_off);
7089 +static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
7090 + struct ipu_image_convert_image *image)
7092 + if (image->fmt->planar)
7093 + return calc_tile_offsets_planar(ctx, image);
7095 + return calc_tile_offsets_packed(ctx, image);
7099 + * Calculate the resizing ratio for the IC main processing section given input
7100 + * size, fixed downsizing coefficient, and output size.
7101 + * Either round to closest for the next tile's first pixel to minimize seams
7102 + * and distortion (for all but right column / bottom row), or round down to
7103 + * avoid sampling beyond the edges of the input image for this tile's last
7105 + * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
7107 +static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
7108 + u32 output_size, bool allow_overshoot)
7110 + u32 downsized = input_size >> downsize_coeff;
7112 + if (allow_overshoot)
7113 + return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
7115 + return 8192 * (downsized - 1) / (output_size - 1);
7119 + * Slightly modify resize coefficients per tile to hide the bilinear
7120 + * interpolator reset at tile borders, shifting the right / bottom edge
7121 + * by up to a half input pixel. This removes noticeable seams between
7122 + * tiles at higher upscaling factors.
7124 +static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
7126 + struct ipu_image_convert_chan *chan = ctx->chan;
7127 + struct ipu_image_convert_priv *priv = chan->priv;
7128 + struct ipu_image_tile *in_tile, *out_tile;
7129 + unsigned int col, row, tile_idx;
7130 + unsigned int last_output;
7132 + for (col = 0; col < ctx->in.num_cols; col++) {
7133 + bool closest = (col < ctx->in.num_cols - 1) &&
7134 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
7135 + u32 resized_width;
7136 + u32 resize_coeff_h;
7140 + in_tile = &ctx->in.tile[tile_idx];
7141 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7143 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
7144 + resized_width = out_tile->height;
7146 + resized_width = out_tile->width;
7148 + resize_coeff_h = calc_resize_coeff(in_tile->width,
7149 + ctx->downsize_coeff_h,
7150 + resized_width, closest);
7152 + dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
7153 + __func__, col, resize_coeff_h);
7156 + * With the horizontal scaling factor known, round up resized
7157 + * width (output width or height) to burst size.
7159 + resized_width = round_up(resized_width, 8);
7162 + * Calculate input width from the last accessed input pixel
7163 + * given resized width and scaling coefficients. Round up to
7166 + last_output = resized_width - 1;
7167 + if (closest && ((last_output * resize_coeff_h) % 8192))
7169 + in_width = round_up(
7170 + (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
7171 + << ctx->downsize_coeff_h, 8);
7173 + for (row = 0; row < ctx->in.num_rows; row++) {
7174 + tile_idx = row * ctx->in.num_cols + col;
7175 + in_tile = &ctx->in.tile[tile_idx];
7176 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7178 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
7179 + out_tile->height = resized_width;
7181 + out_tile->width = resized_width;
7183 + in_tile->width = in_width;
7186 + ctx->resize_coeffs_h[col] = resize_coeff_h;
7189 + for (row = 0; row < ctx->in.num_rows; row++) {
7190 + bool closest = (row < ctx->in.num_rows - 1) &&
7191 + !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
7192 + u32 resized_height;
7193 + u32 resize_coeff_v;
7196 + tile_idx = row * ctx->in.num_cols;
7197 + in_tile = &ctx->in.tile[tile_idx];
7198 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7200 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
7201 + resized_height = out_tile->width;
7203 + resized_height = out_tile->height;
7205 + resize_coeff_v = calc_resize_coeff(in_tile->height,
7206 + ctx->downsize_coeff_v,
7207 + resized_height, closest);
7209 + dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
7210 + __func__, row, resize_coeff_v);
7213 + * With the vertical scaling factor known, round up resized
7214 + * height (output width or height) to IDMAC limitations.
7216 + resized_height = round_up(resized_height, 2);
7219 + * Calculate input width from the last accessed input pixel
7220 + * given resized height and scaling coefficients. Align to
7221 + * IDMAC restrictions.
7223 + last_output = resized_height - 1;
7224 + if (closest && ((last_output * resize_coeff_v) % 8192))
7226 + in_height = round_up(
7227 + (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
7228 + << ctx->downsize_coeff_v, 2);
7230 + for (col = 0; col < ctx->in.num_cols; col++) {
7231 + tile_idx = row * ctx->in.num_cols + col;
7232 + in_tile = &ctx->in.tile[tile_idx];
7233 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7235 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
7236 + out_tile->width = resized_height;
7238 + out_tile->height = resized_height;
7240 + in_tile->height = in_height;
7243 + ctx->resize_coeffs_v[row] = resize_coeff_v;
7248 + * return the number of runs in given queue (pending_q or done_q)
7249 + * for this context. hold irqlock when calling.
7251 +static int get_run_count(struct ipu_image_convert_ctx *ctx,
7252 + struct list_head *q)
7254 + struct ipu_image_convert_run *run;
7257 + lockdep_assert_held(&ctx->chan->irqlock);
7259 + list_for_each_entry(run, q, list) {
7260 + if (run->ctx == ctx)
7267 +static void convert_stop(struct ipu_image_convert_run *run)
7269 + struct ipu_image_convert_ctx *ctx = run->ctx;
7270 + struct ipu_image_convert_chan *chan = ctx->chan;
7271 + struct ipu_image_convert_priv *priv = chan->priv;
7273 + dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
7274 + __func__, chan->ic_task, ctx, run);
7276 + /* disable IC tasks and the channels */
7277 + ipu_ic_task_disable(chan->ic);
7278 + ipu_idmac_disable_channel(chan->in_chan);
7279 + ipu_idmac_disable_channel(chan->out_chan);
7281 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7282 + ipu_idmac_disable_channel(chan->rotation_in_chan);
7283 + ipu_idmac_disable_channel(chan->rotation_out_chan);
7284 + ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
7287 + ipu_ic_disable(chan->ic);
7290 +static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
7291 + struct ipuv3_channel *channel,
7292 + struct ipu_image_convert_image *image,
7293 + enum ipu_rotate_mode rot_mode,
7294 + bool rot_swap_width_height,
7295 + unsigned int tile)
7297 + struct ipu_image_convert_chan *chan = ctx->chan;
7298 + unsigned int burst_size;
7299 + u32 width, height, stride;
7300 + dma_addr_t addr0, addr1 = 0;
7301 + struct ipu_image tile_image;
7302 + unsigned int tile_idx[2];
7304 + if (image->type == IMAGE_CONVERT_OUT) {
7305 + tile_idx[0] = ctx->out_tile_map[tile];
7306 + tile_idx[1] = ctx->out_tile_map[1];
7308 + tile_idx[0] = tile;
7312 + if (rot_swap_width_height) {
7313 + width = image->tile[tile_idx[0]].height;
7314 + height = image->tile[tile_idx[0]].width;
7315 + stride = image->tile[tile_idx[0]].rot_stride;
7316 + addr0 = ctx->rot_intermediate[0].phys;
7317 + if (ctx->double_buffering)
7318 + addr1 = ctx->rot_intermediate[1].phys;
7320 + width = image->tile[tile_idx[0]].width;
7321 + height = image->tile[tile_idx[0]].height;
7322 + stride = image->stride;
7323 + addr0 = image->base.phys0 +
7324 + image->tile[tile_idx[0]].offset;
7325 + if (ctx->double_buffering)
7326 + addr1 = image->base.phys0 +
7327 + image->tile[tile_idx[1]].offset;
7330 + ipu_cpmem_zero(channel);
7332 + memset(&tile_image, 0, sizeof(tile_image));
7333 + tile_image.pix.width = tile_image.rect.width = width;
7334 + tile_image.pix.height = tile_image.rect.height = height;
7335 + tile_image.pix.bytesperline = stride;
7336 + tile_image.pix.pixelformat = image->fmt->fourcc;
7337 + tile_image.phys0 = addr0;
7338 + tile_image.phys1 = addr1;
7339 + if (image->fmt->planar && !rot_swap_width_height) {
7340 + tile_image.u_offset = image->tile[tile_idx[0]].u_off;
7341 + tile_image.v_offset = image->tile[tile_idx[0]].v_off;
7344 + ipu_cpmem_set_image(channel, &tile_image);
7347 + ipu_cpmem_set_rotation(channel, rot_mode);
7350 + * Skip writing U and V components to odd rows in the output
7351 + * channels for planar 4:2:0.
7353 + if ((channel == chan->out_chan ||
7354 + channel == chan->rotation_out_chan) &&
7355 + image->fmt->planar && image->fmt->uv_height_dec == 2)
7356 + ipu_cpmem_skip_odd_chroma_rows(channel);
7358 + if (channel == chan->rotation_in_chan ||
7359 + channel == chan->rotation_out_chan) {
7361 + ipu_cpmem_set_block_mode(channel);
7363 + burst_size = (width % 16) ? 8 : 16;
7365 + ipu_cpmem_set_burstsize(channel, burst_size);
7367 + ipu_ic_task_idma_init(chan->ic, channel, width, height,
7368 + burst_size, rot_mode);
7371 + * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
7372 + * only do this when there is no PRG present.
7374 + if (!channel->ipu->prg_priv)
7375 + ipu_cpmem_set_axi_id(channel, 1);
7377 + ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
7380 +static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
7382 + struct ipu_image_convert_ctx *ctx = run->ctx;
7383 + struct ipu_image_convert_chan *chan = ctx->chan;
7384 + struct ipu_image_convert_priv *priv = chan->priv;
7385 + struct ipu_image_convert_image *s_image = &ctx->in;
7386 + struct ipu_image_convert_image *d_image = &ctx->out;
7387 + unsigned int dst_tile = ctx->out_tile_map[tile];
7388 + unsigned int dest_width, dest_height;
7389 + unsigned int col, row;
7393 + dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
7394 + __func__, chan->ic_task, ctx, run, tile, dst_tile);
7396 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7397 + /* swap width/height for resizer */
7398 + dest_width = d_image->tile[dst_tile].height;
7399 + dest_height = d_image->tile[dst_tile].width;
7401 + dest_width = d_image->tile[dst_tile].width;
7402 + dest_height = d_image->tile[dst_tile].height;
7405 + row = tile / s_image->num_cols;
7406 + col = tile % s_image->num_cols;
7408 + rsc = (ctx->downsize_coeff_v << 30) |
7409 + (ctx->resize_coeffs_v[row] << 16) |
7410 + (ctx->downsize_coeff_h << 14) |
7411 + (ctx->resize_coeffs_h[col]);
7413 + dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
7414 + __func__, s_image->tile[tile].width,
7415 + s_image->tile[tile].height, dest_width, dest_height, rsc);
7417 + /* setup the IC resizer and CSC */
7418 + ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
7419 + s_image->tile[tile].width,
7420 + s_image->tile[tile].height,
7425 + dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
7429 + /* init the source MEM-->IC PP IDMAC channel */
7430 + init_idmac_channel(ctx, chan->in_chan, s_image,
7431 + IPU_ROTATE_NONE, false, tile);
7433 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7434 + /* init the IC PP-->MEM IDMAC channel */
7435 + init_idmac_channel(ctx, chan->out_chan, d_image,
7436 + IPU_ROTATE_NONE, true, tile);
7438 + /* init the MEM-->IC PP ROT IDMAC channel */
7439 + init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
7440 + ctx->rot_mode, true, tile);
7442 + /* init the destination IC PP ROT-->MEM IDMAC channel */
7443 + init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
7444 + IPU_ROTATE_NONE, false, tile);
7446 + /* now link IC PP-->MEM to MEM-->IC PP ROT */
7447 + ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
7449 + /* init the destination IC PP-->MEM IDMAC channel */
7450 + init_idmac_channel(ctx, chan->out_chan, d_image,
7451 + ctx->rot_mode, false, tile);
7454 + /* enable the IC */
7455 + ipu_ic_enable(chan->ic);
7457 + /* set buffers ready */
7458 + ipu_idmac_select_buffer(chan->in_chan, 0);
7459 + ipu_idmac_select_buffer(chan->out_chan, 0);
7460 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
7461 + ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
7462 + if (ctx->double_buffering) {
7463 + ipu_idmac_select_buffer(chan->in_chan, 1);
7464 + ipu_idmac_select_buffer(chan->out_chan, 1);
7465 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
7466 + ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
7469 + /* enable the channels! */
7470 + ipu_idmac_enable_channel(chan->in_chan);
7471 + ipu_idmac_enable_channel(chan->out_chan);
7472 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7473 + ipu_idmac_enable_channel(chan->rotation_in_chan);
7474 + ipu_idmac_enable_channel(chan->rotation_out_chan);
7477 + ipu_ic_task_enable(chan->ic);
7479 + ipu_cpmem_dump(chan->in_chan);
7480 + ipu_cpmem_dump(chan->out_chan);
7481 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7482 + ipu_cpmem_dump(chan->rotation_in_chan);
7483 + ipu_cpmem_dump(chan->rotation_out_chan);
7486 + ipu_dump(priv->ipu);
7491 +/* hold irqlock when calling */
7492 +static int do_run(struct ipu_image_convert_run *run)
7494 + struct ipu_image_convert_ctx *ctx = run->ctx;
7495 + struct ipu_image_convert_chan *chan = ctx->chan;
7497 + lockdep_assert_held(&chan->irqlock);
7499 + ctx->in.base.phys0 = run->in_phys;
7500 + ctx->out.base.phys0 = run->out_phys;
7502 + ctx->cur_buf_num = 0;
7503 + ctx->next_tile = 1;
7505 + /* remove run from pending_q and set as current */
7506 + list_del(&run->list);
7507 + chan->current_run = run;
7509 + return convert_start(run, 0);
7512 +/* hold irqlock when calling */
7513 +static void run_next(struct ipu_image_convert_chan *chan)
7515 + struct ipu_image_convert_priv *priv = chan->priv;
7516 + struct ipu_image_convert_run *run, *tmp;
7519 + lockdep_assert_held(&chan->irqlock);
7521 + list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
7522 + /* skip contexts that are aborting */
7523 + if (run->ctx->aborting) {
7524 + dev_dbg(priv->ipu->dev,
7525 + "%s: task %u: skipping aborting ctx %p run %p\n",
7526 + __func__, chan->ic_task, run->ctx, run);
7530 + ret = do_run(run);
7535 + * something went wrong with start, add the run
7536 + * to done q and continue to the next run in the
7539 + run->status = ret;
7540 + list_add_tail(&run->list, &chan->done_q);
7541 + chan->current_run = NULL;
7545 +static void empty_done_q(struct ipu_image_convert_chan *chan)
7547 + struct ipu_image_convert_priv *priv = chan->priv;
7548 + struct ipu_image_convert_run *run;
7549 + unsigned long flags;
7551 + spin_lock_irqsave(&chan->irqlock, flags);
7553 + while (!list_empty(&chan->done_q)) {
7554 + run = list_entry(chan->done_q.next,
7555 + struct ipu_image_convert_run,
7558 + list_del(&run->list);
7560 + dev_dbg(priv->ipu->dev,
7561 + "%s: task %u: completing ctx %p run %p with %d\n",
7562 + __func__, chan->ic_task, run->ctx, run, run->status);
7564 + /* call the completion callback and free the run */
7565 + spin_unlock_irqrestore(&chan->irqlock, flags);
7566 + run->ctx->complete(run, run->ctx->complete_context);
7567 + spin_lock_irqsave(&chan->irqlock, flags);
7570 + spin_unlock_irqrestore(&chan->irqlock, flags);
7574 + * the bottom half thread clears out the done_q, calling the
7575 + * completion handler for each.
7577 +static irqreturn_t do_bh(int irq, void *dev_id)
7579 + struct ipu_image_convert_chan *chan = dev_id;
7580 + struct ipu_image_convert_priv *priv = chan->priv;
7581 + struct ipu_image_convert_ctx *ctx;
7582 + unsigned long flags;
7584 + dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
7587 + empty_done_q(chan);
7589 + spin_lock_irqsave(&chan->irqlock, flags);
7592 + * the done_q is cleared out, signal any contexts
7593 + * that are aborting that abort can complete.
7595 + list_for_each_entry(ctx, &chan->ctx_list, list) {
7596 + if (ctx->aborting) {
7597 + dev_dbg(priv->ipu->dev,
7598 + "%s: task %u: signaling abort for ctx %p\n",
7599 + __func__, chan->ic_task, ctx);
7600 + complete_all(&ctx->aborted);
7604 + spin_unlock_irqrestore(&chan->irqlock, flags);
7606 + dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
7609 + return IRQ_HANDLED;
7612 +static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
7614 + unsigned int cur_tile = ctx->next_tile - 1;
7615 + unsigned int next_tile = ctx->next_tile;
7617 + if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
7618 + ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
7619 + ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
7620 + ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
7621 + ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
7622 + ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
7623 + ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
7624 + ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
7630 +/* hold irqlock when calling */
7631 +static irqreturn_t do_irq(struct ipu_image_convert_run *run)
7633 + struct ipu_image_convert_ctx *ctx = run->ctx;
7634 + struct ipu_image_convert_chan *chan = ctx->chan;
7635 + struct ipu_image_tile *src_tile, *dst_tile;
7636 + struct ipu_image_convert_image *s_image = &ctx->in;
7637 + struct ipu_image_convert_image *d_image = &ctx->out;
7638 + struct ipuv3_channel *outch;
7639 + unsigned int dst_idx;
7641 + lockdep_assert_held(&chan->irqlock);
7643 + outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
7644 + chan->rotation_out_chan : chan->out_chan;
7647 + * It is difficult to stop the channel DMA before the channels
7648 + * enter the paused state. Without double-buffering the channels
7649 + * are always in a paused state when the EOF irq occurs, so it
7650 + * is safe to stop the channels now. For double-buffering we
7651 + * just ignore the abort until the operation completes, when it
7652 + * is safe to shut down.
7654 + if (ctx->aborting && !ctx->double_buffering) {
7655 + convert_stop(run);
7656 + run->status = -EIO;
7660 + if (ctx->next_tile == ctx->num_tiles) {
7662 + * the conversion is complete
7664 + convert_stop(run);
7670 + * not done, place the next tile buffers.
7672 + if (!ctx->double_buffering) {
7673 + if (ic_settings_changed(ctx)) {
7674 + convert_stop(run);
7675 + convert_start(run, ctx->next_tile);
7677 + src_tile = &s_image->tile[ctx->next_tile];
7678 + dst_idx = ctx->out_tile_map[ctx->next_tile];
7679 + dst_tile = &d_image->tile[dst_idx];
7681 + ipu_cpmem_set_buffer(chan->in_chan, 0,
7682 + s_image->base.phys0 +
7683 + src_tile->offset);
7684 + ipu_cpmem_set_buffer(outch, 0,
7685 + d_image->base.phys0 +
7686 + dst_tile->offset);
7687 + if (s_image->fmt->planar)
7688 + ipu_cpmem_set_uv_offset(chan->in_chan,
7691 + if (d_image->fmt->planar)
7692 + ipu_cpmem_set_uv_offset(outch,
7696 + ipu_idmac_select_buffer(chan->in_chan, 0);
7697 + ipu_idmac_select_buffer(outch, 0);
7699 + } else if (ctx->next_tile < ctx->num_tiles - 1) {
7701 + src_tile = &s_image->tile[ctx->next_tile + 1];
7702 + dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
7703 + dst_tile = &d_image->tile[dst_idx];
7705 + ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
7706 + s_image->base.phys0 + src_tile->offset);
7707 + ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
7708 + d_image->base.phys0 + dst_tile->offset);
7710 + ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
7711 + ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
7713 + ctx->cur_buf_num ^= 1;
7717 + return IRQ_HANDLED;
7719 + list_add_tail(&run->list, &chan->done_q);
7720 + chan->current_run = NULL;
7722 + return IRQ_WAKE_THREAD;
7725 +static irqreturn_t norotate_irq(int irq, void *data)
7727 + struct ipu_image_convert_chan *chan = data;
7728 + struct ipu_image_convert_ctx *ctx;
7729 + struct ipu_image_convert_run *run;
7730 + unsigned long flags;
7733 + spin_lock_irqsave(&chan->irqlock, flags);
7735 + /* get current run and its context */
7736 + run = chan->current_run;
7744 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7745 + /* this is a rotation operation, just ignore */
7746 + spin_unlock_irqrestore(&chan->irqlock, flags);
7747 + return IRQ_HANDLED;
7750 + ret = do_irq(run);
7752 + spin_unlock_irqrestore(&chan->irqlock, flags);
7756 +static irqreturn_t rotate_irq(int irq, void *data)
7758 + struct ipu_image_convert_chan *chan = data;
7759 + struct ipu_image_convert_priv *priv = chan->priv;
7760 + struct ipu_image_convert_ctx *ctx;
7761 + struct ipu_image_convert_run *run;
7762 + unsigned long flags;
7765 + spin_lock_irqsave(&chan->irqlock, flags);
7767 + /* get current run and its context */
7768 + run = chan->current_run;
7776 + if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
7777 + /* this was NOT a rotation operation, shouldn't happen */
7778 + dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
7779 + spin_unlock_irqrestore(&chan->irqlock, flags);
7780 + return IRQ_HANDLED;
7783 + ret = do_irq(run);
7785 + spin_unlock_irqrestore(&chan->irqlock, flags);
7790 + * try to force the completion of runs for this ctx. Called when
7791 + * abort wait times out in ipu_image_convert_abort().
7793 +static void force_abort(struct ipu_image_convert_ctx *ctx)
7795 + struct ipu_image_convert_chan *chan = ctx->chan;
7796 + struct ipu_image_convert_run *run;
7797 + unsigned long flags;
7799 + spin_lock_irqsave(&chan->irqlock, flags);
7801 + run = chan->current_run;
7802 + if (run && run->ctx == ctx) {
7803 + convert_stop(run);
7804 + run->status = -EIO;
7805 + list_add_tail(&run->list, &chan->done_q);
7806 + chan->current_run = NULL;
7810 + spin_unlock_irqrestore(&chan->irqlock, flags);
7812 + empty_done_q(chan);
7815 +static void release_ipu_resources(struct ipu_image_convert_chan *chan)
7817 + if (chan->out_eof_irq >= 0)
7818 + free_irq(chan->out_eof_irq, chan);
7819 + if (chan->rot_out_eof_irq >= 0)
7820 + free_irq(chan->rot_out_eof_irq, chan);
7822 + if (!IS_ERR_OR_NULL(chan->in_chan))
7823 + ipu_idmac_put(chan->in_chan);
7824 + if (!IS_ERR_OR_NULL(chan->out_chan))
7825 + ipu_idmac_put(chan->out_chan);
7826 + if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
7827 + ipu_idmac_put(chan->rotation_in_chan);
7828 + if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
7829 + ipu_idmac_put(chan->rotation_out_chan);
7830 + if (!IS_ERR_OR_NULL(chan->ic))
7831 + ipu_ic_put(chan->ic);
7833 + chan->in_chan = chan->out_chan = chan->rotation_in_chan =
7834 + chan->rotation_out_chan = NULL;
7835 + chan->out_eof_irq = chan->rot_out_eof_irq = -1;
7838 +static int get_ipu_resources(struct ipu_image_convert_chan *chan)
7840 + const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
7841 + struct ipu_image_convert_priv *priv = chan->priv;
7845 + chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
7846 + if (IS_ERR(chan->ic)) {
7847 + dev_err(priv->ipu->dev, "could not acquire IC\n");
7848 + ret = PTR_ERR(chan->ic);
7852 + /* get IDMAC channels */
7853 + chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
7854 + chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
7855 + if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
7856 + dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
7861 + chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
7862 + chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
7863 + if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
7864 + dev_err(priv->ipu->dev,
7865 + "could not acquire idmac rotation channels\n");
7870 + /* acquire the EOF interrupts */
7871 + chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
7875 + ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
7876 + 0, "ipu-ic", chan);
7878 + dev_err(priv->ipu->dev, "could not acquire irq %d\n",
7879 + chan->out_eof_irq);
7880 + chan->out_eof_irq = -1;
7884 + chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
7885 + chan->rotation_out_chan,
7888 + ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
7889 + 0, "ipu-ic", chan);
7891 + dev_err(priv->ipu->dev, "could not acquire irq %d\n",
7892 + chan->rot_out_eof_irq);
7893 + chan->rot_out_eof_irq = -1;
7899 + release_ipu_resources(chan);
7903 +static int fill_image(struct ipu_image_convert_ctx *ctx,
7904 + struct ipu_image_convert_image *ic_image,
7905 + struct ipu_image *image,
7906 + enum ipu_image_convert_type type)
7908 + struct ipu_image_convert_priv *priv = ctx->chan->priv;
7910 + ic_image->base = *image;
7911 + ic_image->type = type;
7913 + ic_image->fmt = get_format(image->pix.pixelformat);
7914 + if (!ic_image->fmt) {
7915 + dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
7916 + type == IMAGE_CONVERT_OUT ? "Output" : "Input");
7920 + if (ic_image->fmt->planar)
7921 + ic_image->stride = ic_image->base.pix.width;
7923 + ic_image->stride = ic_image->base.pix.bytesperline;
7928 +/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
7929 +static unsigned int clamp_align(unsigned int x, unsigned int min,
7930 + unsigned int max, unsigned int align)
7932 + /* Bits that must be zero to be aligned */
7933 + unsigned int mask = ~((1 << align) - 1);
7935 + /* Clamp to aligned min and max */
7936 + x = clamp(x, (min + ~mask) & mask, max & mask);
7938 + /* Round to nearest aligned value */
7940 + x = (x + (1 << (align - 1))) & mask;
7945 +/* Adjusts input/output images to IPU restrictions */
7946 +void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
7947 + enum ipu_rotate_mode rot_mode)
7949 + const struct ipu_image_pixfmt *infmt, *outfmt;
7950 + u32 w_align_out, h_align_out;
7951 + u32 w_align_in, h_align_in;
7953 + infmt = get_format(in->pix.pixelformat);
7954 + outfmt = get_format(out->pix.pixelformat);
7956 + /* set some default pixel formats if needed */
7958 + in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
7959 + infmt = get_format(V4L2_PIX_FMT_RGB24);
7962 + out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
7963 + outfmt = get_format(V4L2_PIX_FMT_RGB24);
7966 + /* image converter does not handle fields */
7967 + in->pix.field = out->pix.field = V4L2_FIELD_NONE;
7969 + /* resizer cannot downsize more than 4:1 */
7970 + if (ipu_rot_mode_is_irt(rot_mode)) {
7971 + out->pix.height = max_t(__u32, out->pix.height,
7972 + in->pix.width / 4);
7973 + out->pix.width = max_t(__u32, out->pix.width,
7974 + in->pix.height / 4);
7976 + out->pix.width = max_t(__u32, out->pix.width,
7977 + in->pix.width / 4);
7978 + out->pix.height = max_t(__u32, out->pix.height,
7979 + in->pix.height / 4);
7982 + /* align input width/height */
7983 + w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
7985 + h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
7987 + in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
7989 + in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
7992 + /* align output width/height */
7993 + w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
7995 + h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
7997 + out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
7999 + out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
8002 + /* set input/output strides and image sizes */
8003 + in->pix.bytesperline = infmt->planar ?
8004 + clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
8006 + clamp_align((in->pix.width * infmt->bpp) >> 3,
8007 + ((2 << w_align_in) * infmt->bpp) >> 3,
8008 + (MAX_W * infmt->bpp) >> 3,
8010 + in->pix.sizeimage = infmt->planar ?
8011 + (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
8012 + in->pix.height * in->pix.bytesperline;
8013 + out->pix.bytesperline = outfmt->planar ? out->pix.width :
8014 + (out->pix.width * outfmt->bpp) >> 3;
8015 + out->pix.sizeimage = outfmt->planar ?
8016 + (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
8017 + out->pix.height * out->pix.bytesperline;
8019 +EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
8022 + * this is used by ipu_image_convert_prepare() to verify set input and
8023 + * output images are valid before starting the conversion. Clients can
8024 + * also call it before calling ipu_image_convert_prepare().
8026 +int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
8027 + enum ipu_rotate_mode rot_mode)
8029 + struct ipu_image testin, testout;
8034 + ipu_image_convert_adjust(&testin, &testout, rot_mode);
8036 + if (testin.pix.width != in->pix.width ||
8037 + testin.pix.height != in->pix.height ||
8038 + testout.pix.width != out->pix.width ||
8039 + testout.pix.height != out->pix.height)
8044 +EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
8047 + * Call ipu_image_convert_prepare() to prepare for the conversion of
8048 + * given images and rotation mode. Returns a new conversion context.
8050 +struct ipu_image_convert_ctx *
8051 +ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
8052 + struct ipu_image *in, struct ipu_image *out,
8053 + enum ipu_rotate_mode rot_mode,
8054 + ipu_image_convert_cb_t complete,
8055 + void *complete_context)
8057 + struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
8058 + struct ipu_image_convert_image *s_image, *d_image;
8059 + struct ipu_image_convert_chan *chan;
8060 + struct ipu_image_convert_ctx *ctx;
8061 + unsigned long flags;
8066 + if (!in || !out || !complete ||
8067 + (ic_task != IC_TASK_VIEWFINDER &&
8068 + ic_task != IC_TASK_POST_PROCESSOR))
8069 + return ERR_PTR(-EINVAL);
8071 + /* verify the in/out images before continuing */
8072 + ret = ipu_image_convert_verify(in, out, rot_mode);
8074 + dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
8076 + return ERR_PTR(ret);
8079 + chan = &priv->chan[ic_task];
8081 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
8083 + return ERR_PTR(-ENOMEM);
8085 + dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
8086 + chan->ic_task, ctx);
8089 + init_completion(&ctx->aborted);
8091 + ctx->rot_mode = rot_mode;
8093 + /* Sets ctx->in.num_rows/cols as well */
8094 + ret = calc_image_resize_coefficients(ctx, in, out);
8098 + s_image = &ctx->in;
8099 + d_image = &ctx->out;
8101 + /* set tiling and rotation */
8102 + if (ipu_rot_mode_is_irt(rot_mode)) {
8103 + d_image->num_rows = s_image->num_cols;
8104 + d_image->num_cols = s_image->num_rows;
8106 + d_image->num_rows = s_image->num_rows;
8107 + d_image->num_cols = s_image->num_cols;
8110 + ctx->num_tiles = d_image->num_cols * d_image->num_rows;
8112 + ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
8115 + ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
8119 + calc_out_tile_map(ctx);
8121 + find_seams(ctx, s_image, d_image);
8123 + ret = calc_tile_dimensions(ctx, s_image);
8127 + ret = calc_tile_offsets(ctx, s_image);
8131 + calc_tile_dimensions(ctx, d_image);
8132 + ret = calc_tile_offsets(ctx, d_image);
8136 + calc_tile_resize_coefficients(ctx);
8138 + ret = ipu_ic_calc_csc(&ctx->csc,
8139 + s_image->base.pix.ycbcr_enc,
8140 + s_image->base.pix.quantization,
8141 + ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
8142 + d_image->base.pix.ycbcr_enc,
8143 + d_image->base.pix.quantization,
8144 + ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
8148 + dump_format(ctx, s_image);
8149 + dump_format(ctx, d_image);
8151 + ctx->complete = complete;
8152 + ctx->complete_context = complete_context;
8155 + * Can we use double-buffering for this operation? If there is
8156 + * only one tile (the whole image can be converted in a single
8157 + * operation) there's no point in using double-buffering. Also,
8158 + * the IPU's IDMAC channels allow only a single U and V plane
8159 + * offset shared between both buffers, but these offsets change
8160 + * for every tile, and therefore would have to be updated for
8161 + * each buffer which is not possible. So double-buffering is
8162 + * impossible when either the source or destination images are
8163 + * a planar format (YUV420, YUV422P, etc.). Further, differently
8164 + * sized tiles or different resizing coefficients per tile
8165 + * prevent double-buffering as well.
8167 + ctx->double_buffering = (ctx->num_tiles > 1 &&
8168 + !s_image->fmt->planar &&
8169 + !d_image->fmt->planar);
8170 + for (i = 1; i < ctx->num_tiles; i++) {
8171 + if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
8172 + ctx->in.tile[i].height != ctx->in.tile[0].height ||
8173 + ctx->out.tile[i].width != ctx->out.tile[0].width ||
8174 + ctx->out.tile[i].height != ctx->out.tile[0].height) {
8175 + ctx->double_buffering = false;
8179 + for (i = 1; i < ctx->in.num_cols; i++) {
8180 + if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
8181 + ctx->double_buffering = false;
8185 + for (i = 1; i < ctx->in.num_rows; i++) {
8186 + if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
8187 + ctx->double_buffering = false;
8192 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
8193 + unsigned long intermediate_size = d_image->tile[0].size;
8195 + for (i = 1; i < ctx->num_tiles; i++) {
8196 + if (d_image->tile[i].size > intermediate_size)
8197 + intermediate_size = d_image->tile[i].size;
8200 + ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
8201 + intermediate_size);
8204 + if (ctx->double_buffering) {
8205 + ret = alloc_dma_buf(priv,
8206 + &ctx->rot_intermediate[1],
8207 + intermediate_size);
8209 + goto out_free_dmabuf0;
8213 + spin_lock_irqsave(&chan->irqlock, flags);
8215 + get_res = list_empty(&chan->ctx_list);
8217 + list_add_tail(&ctx->list, &chan->ctx_list);
8219 + spin_unlock_irqrestore(&chan->irqlock, flags);
8222 + ret = get_ipu_resources(chan);
8224 + goto out_free_dmabuf1;
8230 + free_dma_buf(priv, &ctx->rot_intermediate[1]);
8231 + spin_lock_irqsave(&chan->irqlock, flags);
8232 + list_del(&ctx->list);
8233 + spin_unlock_irqrestore(&chan->irqlock, flags);
8235 + free_dma_buf(priv, &ctx->rot_intermediate[0]);
8238 + return ERR_PTR(ret);
8240 +EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
8243 + * Carry out a single image conversion run. Only the physaddr's of the input
8244 + * and output image buffers are needed. The conversion context must have
8245 + * been created previously with ipu_image_convert_prepare().
8247 +int ipu_image_convert_queue(struct ipu_image_convert_run *run)
8249 + struct ipu_image_convert_chan *chan;
8250 + struct ipu_image_convert_priv *priv;
8251 + struct ipu_image_convert_ctx *ctx;
8252 + unsigned long flags;
8255 + if (!run || !run->ctx || !run->in_phys || !run->out_phys)
8260 + priv = chan->priv;
8262 + dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
8263 + chan->ic_task, ctx, run);
8265 + INIT_LIST_HEAD(&run->list);
8267 + spin_lock_irqsave(&chan->irqlock, flags);
8269 + if (ctx->aborting) {
8274 + list_add_tail(&run->list, &chan->pending_q);
8276 + if (!chan->current_run) {
8277 + ret = do_run(run);
8279 + chan->current_run = NULL;
8282 + spin_unlock_irqrestore(&chan->irqlock, flags);
8285 +EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
8287 +/* Abort any active or pending conversions for this context */
8288 +static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
8290 + struct ipu_image_convert_chan *chan = ctx->chan;
8291 + struct ipu_image_convert_priv *priv = chan->priv;
8292 + struct ipu_image_convert_run *run, *active_run, *tmp;
8293 + unsigned long flags;
8294 + int run_count, ret;
8296 + spin_lock_irqsave(&chan->irqlock, flags);
8298 + /* move all remaining pending runs in this context to done_q */
8299 + list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
8300 + if (run->ctx != ctx)
8302 + run->status = -EIO;
8303 + list_move_tail(&run->list, &chan->done_q);
8306 + run_count = get_run_count(ctx, &chan->done_q);
8307 + active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
8308 + chan->current_run : NULL;
8311 + reinit_completion(&ctx->aborted);
8313 + ctx->aborting = true;
8315 + spin_unlock_irqrestore(&chan->irqlock, flags);
8317 + if (!run_count && !active_run) {
8318 + dev_dbg(priv->ipu->dev,
8319 + "%s: task %u: no abort needed for ctx %p\n",
8320 + __func__, chan->ic_task, ctx);
8324 + if (!active_run) {
8325 + empty_done_q(chan);
8329 + dev_dbg(priv->ipu->dev,
8330 + "%s: task %u: wait for completion: %d runs\n",
8331 + __func__, chan->ic_task, run_count);
8333 + ret = wait_for_completion_timeout(&ctx->aborted,
8334 + msecs_to_jiffies(10000));
8336 + dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
8341 +void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
8343 + __ipu_image_convert_abort(ctx);
8344 + ctx->aborting = false;
8346 +EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
8348 +/* Unprepare image conversion context */
8349 +void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
8351 + struct ipu_image_convert_chan *chan = ctx->chan;
8352 + struct ipu_image_convert_priv *priv = chan->priv;
8353 + unsigned long flags;
8356 + /* make sure no runs are hanging around */
8357 + __ipu_image_convert_abort(ctx);
8359 + dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
8360 + chan->ic_task, ctx);
8362 + spin_lock_irqsave(&chan->irqlock, flags);
8364 + list_del(&ctx->list);
8366 + put_res = list_empty(&chan->ctx_list);
8368 + spin_unlock_irqrestore(&chan->irqlock, flags);
8371 + release_ipu_resources(chan);
8373 + free_dma_buf(priv, &ctx->rot_intermediate[1]);
8374 + free_dma_buf(priv, &ctx->rot_intermediate[0]);
8378 +EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
8381 + * "Canned" asynchronous single image conversion. Allocates and returns
8382 + * a new conversion run. On successful return the caller must free the
8383 + * run and call ipu_image_convert_unprepare() after conversion completes.
8385 +struct ipu_image_convert_run *
8386 +ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
8387 + struct ipu_image *in, struct ipu_image *out,
8388 + enum ipu_rotate_mode rot_mode,
8389 + ipu_image_convert_cb_t complete,
8390 + void *complete_context)
8392 + struct ipu_image_convert_ctx *ctx;
8393 + struct ipu_image_convert_run *run;
8396 + ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
8397 + complete, complete_context);
8399 + return ERR_CAST(ctx);
8401 + run = kzalloc(sizeof(*run), GFP_KERNEL);
8403 + ipu_image_convert_unprepare(ctx);
8404 + return ERR_PTR(-ENOMEM);
8408 + run->in_phys = in->phys0;
8409 + run->out_phys = out->phys0;
8411 + ret = ipu_image_convert_queue(run);
8413 + ipu_image_convert_unprepare(ctx);
8415 + return ERR_PTR(ret);
8420 +EXPORT_SYMBOL_GPL(ipu_image_convert);
8422 +/* "Canned" synchronous single image conversion */
8423 +static void image_convert_sync_complete(struct ipu_image_convert_run *run,
8426 + struct completion *comp = data;
8431 +int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
8432 + struct ipu_image *in, struct ipu_image *out,
8433 + enum ipu_rotate_mode rot_mode)
8435 + struct ipu_image_convert_run *run;
8436 + struct completion comp;
8439 + init_completion(&comp);
8441 + run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
8442 + image_convert_sync_complete, &comp);
8444 + return PTR_ERR(run);
8446 + ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
8447 + ret = (ret == 0) ? -ETIMEDOUT : 0;
8449 + ipu_image_convert_unprepare(run->ctx);
8454 +EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
8456 +int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
8458 + struct ipu_image_convert_priv *priv;
8461 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
8465 + ipu->image_convert_priv = priv;
8468 + for (i = 0; i < IC_NUM_TASKS; i++) {
8469 + struct ipu_image_convert_chan *chan = &priv->chan[i];
8471 + chan->ic_task = i;
8472 + chan->priv = priv;
8473 + chan->dma_ch = &image_convert_dma_chan[i];
8474 + chan->out_eof_irq = -1;
8475 + chan->rot_out_eof_irq = -1;
8477 + spin_lock_init(&chan->irqlock);
8478 + INIT_LIST_HEAD(&chan->ctx_list);
8479 + INIT_LIST_HEAD(&chan->pending_q);
8480 + INIT_LIST_HEAD(&chan->done_q);
8486 +void ipu_image_convert_exit(struct ipu_soc *ipu)
8490 +++ b/drivers/gpu/imx/ipu-v3/ipu-pre.c
8492 +// SPDX-License-Identifier: GPL-2.0-only
8494 + * Copyright (c) 2017 Lucas Stach, Pengutronix
8497 +#include <drm/drm_fourcc.h>
8498 +#include <linux/clk.h>
8499 +#include <linux/err.h>
8500 +#include <linux/genalloc.h>
8501 +#include <linux/module.h>
8502 +#include <linux/of.h>
8503 +#include <linux/platform_device.h>
8504 +#include <video/imx-ipu-v3.h>
8506 +#include "ipu-prv.h"
8508 +#define IPU_PRE_MAX_WIDTH 2048
8509 +#define IPU_PRE_NUM_SCANLINES 8
8511 +#define IPU_PRE_CTRL 0x000
8512 +#define IPU_PRE_CTRL_SET 0x004
8513 +#define IPU_PRE_CTRL_ENABLE (1 << 0)
8514 +#define IPU_PRE_CTRL_BLOCK_EN (1 << 1)
8515 +#define IPU_PRE_CTRL_BLOCK_16 (1 << 2)
8516 +#define IPU_PRE_CTRL_SDW_UPDATE (1 << 4)
8517 +#define IPU_PRE_CTRL_VFLIP (1 << 5)
8518 +#define IPU_PRE_CTRL_SO (1 << 6)
8519 +#define IPU_PRE_CTRL_INTERLACED_FIELD (1 << 7)
8520 +#define IPU_PRE_CTRL_HANDSHAKE_EN (1 << 8)
8521 +#define IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v) ((v & 0x3) << 9)
8522 +#define IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN (1 << 11)
8523 +#define IPU_PRE_CTRL_EN_REPEAT (1 << 28)
8524 +#define IPU_PRE_CTRL_TPR_REST_SEL (1 << 29)
8525 +#define IPU_PRE_CTRL_CLKGATE (1 << 30)
8526 +#define IPU_PRE_CTRL_SFTRST (1 << 31)
8528 +#define IPU_PRE_CUR_BUF 0x030
8530 +#define IPU_PRE_NEXT_BUF 0x040
8532 +#define IPU_PRE_TPR_CTRL 0x070
8533 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT(v) ((v & 0xff) << 0)
8534 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK 0xff
8535 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT (1 << 0)
8536 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF (1 << 4)
8537 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF (1 << 5)
8538 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED (1 << 6)
8540 +#define IPU_PRE_PREFETCH_ENG_CTRL 0x080
8541 +#define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0)
8542 +#define IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v) ((v & 0x7) << 1)
8543 +#define IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
8544 +#define IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v) ((v & 0x7) << 8)
8545 +#define IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS (1 << 11)
8546 +#define IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE (1 << 12)
8547 +#define IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP (1 << 14)
8548 +#define IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN (1 << 15)
8550 +#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE 0x0a0
8551 +#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v) ((v & 0xffff) << 0)
8552 +#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v) ((v & 0xffff) << 16)
8554 +#define IPU_PRE_PREFETCH_ENG_PITCH 0x0d0
8555 +#define IPU_PRE_PREFETCH_ENG_PITCH_Y(v) ((v & 0xffff) << 0)
8556 +#define IPU_PRE_PREFETCH_ENG_PITCH_UV(v) ((v & 0xffff) << 16)
8558 +#define IPU_PRE_STORE_ENG_CTRL 0x110
8559 +#define IPU_PRE_STORE_ENG_CTRL_STORE_EN (1 << 0)
8560 +#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1)
8561 +#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
8563 +#define IPU_PRE_STORE_ENG_STATUS 0x120
8564 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK 0xffff
8565 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
8566 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK 0x3fff
8567 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
8568 +#define IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL (1 << 30)
8569 +#define IPU_PRE_STORE_ENG_STATUS_STORE_FIELD (1 << 31)
8571 +#define IPU_PRE_STORE_ENG_SIZE 0x130
8572 +#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0)
8573 +#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16)
8575 +#define IPU_PRE_STORE_ENG_PITCH 0x140
8576 +#define IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v) ((v & 0xffff) << 0)
8578 +#define IPU_PRE_STORE_ENG_ADDR 0x150
8581 + struct list_head list;
8582 + struct device *dev;
8584 + void __iomem *regs;
8585 + struct clk *clk_axi;
8586 + struct gen_pool *iram;
8588 + dma_addr_t buffer_paddr;
8589 + void *buffer_virt;
8591 + unsigned int safe_window_end;
8592 + unsigned int last_bufaddr;
8595 +static DEFINE_MUTEX(ipu_pre_list_mutex);
8596 +static LIST_HEAD(ipu_pre_list);
8597 +static int available_pres;
8599 +int ipu_pre_get_available_count(void)
8601 + return available_pres;
8605 +ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
8607 + struct device_node *pre_node = of_parse_phandle(dev->of_node,
8609 + struct ipu_pre *pre;
8611 + mutex_lock(&ipu_pre_list_mutex);
8612 + list_for_each_entry(pre, &ipu_pre_list, list) {
8613 + if (pre_node == pre->dev->of_node) {
8614 + mutex_unlock(&ipu_pre_list_mutex);
8615 + device_link_add(dev, pre->dev,
8616 + DL_FLAG_AUTOREMOVE_CONSUMER);
8617 + of_node_put(pre_node);
8621 + mutex_unlock(&ipu_pre_list_mutex);
8623 + of_node_put(pre_node);
8628 +int ipu_pre_get(struct ipu_pre *pre)
8635 + /* first get the engine out of reset and remove clock gating */
8636 + writel(0, pre->regs + IPU_PRE_CTRL);
8638 + /* init defaults that should be applied to all streams */
8639 + val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
8640 + IPU_PRE_CTRL_HANDSHAKE_EN |
8641 + IPU_PRE_CTRL_TPR_REST_SEL |
8642 + IPU_PRE_CTRL_SDW_UPDATE;
8643 + writel(val, pre->regs + IPU_PRE_CTRL);
8645 + pre->in_use = true;
8649 +void ipu_pre_put(struct ipu_pre *pre)
8651 + writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
8653 + pre->in_use = false;
8656 +void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
8657 + unsigned int height, unsigned int stride, u32 format,
8658 + uint64_t modifier, unsigned int bufaddr)
8660 + const struct drm_format_info *info = drm_format_info(format);
8661 + u32 active_bpp = info->cpp[0] >> 1;
8664 + /* calculate safe window for ctrl register updates */
8665 + if (modifier == DRM_FORMAT_MOD_LINEAR)
8666 + pre->safe_window_end = height - 2;
8668 + pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
8670 + writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
8671 + writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
8672 + pre->last_bufaddr = bufaddr;
8674 + val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
8675 + IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
8676 + IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
8677 + IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
8678 + IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
8679 + writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
8681 + val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
8682 + IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
8683 + writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
8685 + val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
8686 + writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
8688 + val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
8689 + IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
8690 + IPU_PRE_STORE_ENG_CTRL_STORE_EN;
8691 + writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
8693 + val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
8694 + IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
8695 + writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
8697 + val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
8698 + writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
8700 + writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
8702 + val = readl(pre->regs + IPU_PRE_TPR_CTRL);
8703 + val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
8704 + if (modifier != DRM_FORMAT_MOD_LINEAR) {
8705 + /* only support single buffer formats for now */
8706 + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
8707 + if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
8708 + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
8709 + if (info->cpp[0] == 2)
8710 + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
8712 + writel(val, pre->regs + IPU_PRE_TPR_CTRL);
8714 + val = readl(pre->regs + IPU_PRE_CTRL);
8715 + val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
8716 + IPU_PRE_CTRL_SDW_UPDATE;
8717 + if (modifier == DRM_FORMAT_MOD_LINEAR)
8718 + val &= ~IPU_PRE_CTRL_BLOCK_EN;
8720 + val |= IPU_PRE_CTRL_BLOCK_EN;
8721 + writel(val, pre->regs + IPU_PRE_CTRL);
8724 +void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
8726 + unsigned long timeout = jiffies + msecs_to_jiffies(5);
8727 + unsigned short current_yblock;
8730 + if (bufaddr == pre->last_bufaddr)
8733 + writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
8734 + pre->last_bufaddr = bufaddr;
8737 + if (time_after(jiffies, timeout)) {
8738 + dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
8742 + val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
8744 + (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
8745 + IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
8746 + } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
8748 + writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
8751 +bool ipu_pre_update_pending(struct ipu_pre *pre)
8753 + return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
8754 + IPU_PRE_CTRL_SDW_UPDATE);
8757 +u32 ipu_pre_get_baddr(struct ipu_pre *pre)
8759 + return (u32)pre->buffer_paddr;
8762 +static int ipu_pre_probe(struct platform_device *pdev)
8764 + struct device *dev = &pdev->dev;
8765 + struct resource *res;
8766 + struct ipu_pre *pre;
8768 + pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
8772 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8773 + pre->regs = devm_ioremap_resource(&pdev->dev, res);
8774 + if (IS_ERR(pre->regs))
8775 + return PTR_ERR(pre->regs);
8777 + pre->clk_axi = devm_clk_get(dev, "axi");
8778 + if (IS_ERR(pre->clk_axi))
8779 + return PTR_ERR(pre->clk_axi);
8781 + pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
8783 + return -EPROBE_DEFER;
8786 + * Allocate IRAM buffer with maximum size. This could be made dynamic,
8787 + * but as there is no other user of this IRAM region and we can fit all
8788 + * max sized buffers into it, there is no need yet.
8790 + pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
8791 + IPU_PRE_NUM_SCANLINES * 4,
8792 + &pre->buffer_paddr);
8793 + if (!pre->buffer_virt)
8796 + clk_prepare_enable(pre->clk_axi);
8799 + platform_set_drvdata(pdev, pre);
8800 + mutex_lock(&ipu_pre_list_mutex);
8801 + list_add(&pre->list, &ipu_pre_list);
8803 + mutex_unlock(&ipu_pre_list_mutex);
8808 +static int ipu_pre_remove(struct platform_device *pdev)
8810 + struct ipu_pre *pre = platform_get_drvdata(pdev);
8812 + mutex_lock(&ipu_pre_list_mutex);
8813 + list_del(&pre->list);
8815 + mutex_unlock(&ipu_pre_list_mutex);
8817 + clk_disable_unprepare(pre->clk_axi);
8819 + if (pre->buffer_virt)
8820 + gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
8821 + IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
8825 +static const struct of_device_id ipu_pre_dt_ids[] = {
8826 + { .compatible = "fsl,imx6qp-pre", },
8827 + { /* sentinel */ },
8830 +struct platform_driver ipu_pre_drv = {
8831 + .probe = ipu_pre_probe,
8832 + .remove = ipu_pre_remove,
8834 + .name = "imx-ipu-pre",
8835 + .of_match_table = ipu_pre_dt_ids,
8839 +++ b/drivers/gpu/imx/ipu-v3/ipu-prg.c
8841 +// SPDX-License-Identifier: GPL-2.0-only
8843 + * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
8846 +#include <drm/drm_fourcc.h>
8847 +#include <linux/clk.h>
8848 +#include <linux/err.h>
8849 +#include <linux/iopoll.h>
8850 +#include <linux/mfd/syscon.h>
8851 +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
8852 +#include <linux/module.h>
8853 +#include <linux/of.h>
8854 +#include <linux/platform_device.h>
8855 +#include <linux/pm_runtime.h>
8856 +#include <linux/regmap.h>
8857 +#include <video/imx-ipu-v3.h>
8859 +#include "ipu-prv.h"
8861 +#define IPU_PRG_CTL 0x00
8862 +#define IPU_PRG_CTL_BYPASS(i) (1 << (0 + i))
8863 +#define IPU_PRG_CTL_SOFT_ARID_MASK 0x3
8864 +#define IPU_PRG_CTL_SOFT_ARID_SHIFT(i) (8 + i * 2)
8865 +#define IPU_PRG_CTL_SOFT_ARID(i, v) ((v & 0x3) << (8 + 2 * i))
8866 +#define IPU_PRG_CTL_SO(i) (1 << (16 + i))
8867 +#define IPU_PRG_CTL_VFLIP(i) (1 << (19 + i))
8868 +#define IPU_PRG_CTL_BLOCK_MODE(i) (1 << (22 + i))
8869 +#define IPU_PRG_CTL_CNT_LOAD_EN(i) (1 << (25 + i))
8870 +#define IPU_PRG_CTL_SOFTRST (1 << 30)
8871 +#define IPU_PRG_CTL_SHADOW_EN (1 << 31)
8873 +#define IPU_PRG_STATUS 0x04
8874 +#define IPU_PRG_STATUS_BUFFER0_READY(i) (1 << (0 + i * 2))
8875 +#define IPU_PRG_STATUS_BUFFER1_READY(i) (1 << (1 + i * 2))
8877 +#define IPU_PRG_QOS 0x08
8878 +#define IPU_PRG_QOS_ARID_MASK 0xf
8879 +#define IPU_PRG_QOS_ARID_SHIFT(i) (0 + i * 4)
8881 +#define IPU_PRG_REG_UPDATE 0x0c
8882 +#define IPU_PRG_REG_UPDATE_REG_UPDATE (1 << 0)
8884 +#define IPU_PRG_STRIDE(i) (0x10 + i * 0x4)
8885 +#define IPU_PRG_STRIDE_STRIDE_MASK 0x3fff
8887 +#define IPU_PRG_CROP_LINE 0x1c
8889 +#define IPU_PRG_THD 0x20
8891 +#define IPU_PRG_BADDR(i) (0x24 + i * 0x4)
8893 +#define IPU_PRG_OFFSET(i) (0x30 + i * 0x4)
8895 +#define IPU_PRG_ILO(i) (0x3c + i * 0x4)
8897 +#define IPU_PRG_HEIGHT(i) (0x48 + i * 0x4)
8898 +#define IPU_PRG_HEIGHT_PRE_HEIGHT_MASK 0xfff
8899 +#define IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT 0
8900 +#define IPU_PRG_HEIGHT_IPU_HEIGHT_MASK 0xfff
8901 +#define IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT 16
8903 +struct ipu_prg_channel {
8909 + struct list_head list;
8910 + struct device *dev;
8913 + void __iomem *regs;
8914 + struct clk *clk_ipg, *clk_axi;
8915 + struct regmap *iomuxc_gpr;
8916 + struct ipu_pre *pres[3];
8918 + struct ipu_prg_channel chan[3];
8921 +static DEFINE_MUTEX(ipu_prg_list_mutex);
8922 +static LIST_HEAD(ipu_prg_list);
8925 +ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
8927 + struct device_node *prg_node = of_parse_phandle(dev->of_node,
8929 + struct ipu_prg *prg;
8931 + mutex_lock(&ipu_prg_list_mutex);
8932 + list_for_each_entry(prg, &ipu_prg_list, list) {
8933 + if (prg_node == prg->dev->of_node) {
8934 + mutex_unlock(&ipu_prg_list_mutex);
8935 + device_link_add(dev, prg->dev,
8936 + DL_FLAG_AUTOREMOVE_CONSUMER);
8938 + of_node_put(prg_node);
8942 + mutex_unlock(&ipu_prg_list_mutex);
8944 + of_node_put(prg_node);
8949 +int ipu_prg_max_active_channels(void)
8951 + return ipu_pre_get_available_count();
8953 +EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
8955 +bool ipu_prg_present(struct ipu_soc *ipu)
8957 + if (ipu->prg_priv)
8962 +EXPORT_SYMBOL_GPL(ipu_prg_present);
8964 +bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
8965 + uint64_t modifier)
8967 + const struct drm_format_info *info = drm_format_info(format);
8969 + if (info->num_planes != 1)
8972 + switch (modifier) {
8973 + case DRM_FORMAT_MOD_LINEAR:
8974 + case DRM_FORMAT_MOD_VIVANTE_TILED:
8975 + case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
8981 +EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
8983 +int ipu_prg_enable(struct ipu_soc *ipu)
8985 + struct ipu_prg *prg = ipu->prg_priv;
8990 + return pm_runtime_get_sync(prg->dev);
8992 +EXPORT_SYMBOL_GPL(ipu_prg_enable);
8994 +void ipu_prg_disable(struct ipu_soc *ipu)
8996 + struct ipu_prg *prg = ipu->prg_priv;
9001 + pm_runtime_put(prg->dev);
9003 +EXPORT_SYMBOL_GPL(ipu_prg_disable);
9006 + * The channel configuartion functions below are not thread safe, as they
9007 + * must be only called from the atomic commit path in the DRM driver, which
9008 + * is properly serialized.
9010 +static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
9013 + * This isn't clearly documented in the RM, but IPU to PRG channel
9014 + * assignment is fixed, as only with this mapping the control signals
9017 + switch (ipu_chan) {
9018 + case IPUV3_CHANNEL_MEM_BG_SYNC:
9020 + case IPUV3_CHANNEL_MEM_FG_SYNC:
9022 + case IPUV3_CHANNEL_MEM_DC_SYNC:
9029 +static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
9033 + /* channel 0 is special as it is hardwired to one of the PREs */
9034 + if (prg_chan == 0) {
9035 + ret = ipu_pre_get(prg->pres[0]);
9038 + prg->chan[prg_chan].used_pre = 0;
9042 + for (i = 1; i < 3; i++) {
9043 + ret = ipu_pre_get(prg->pres[i]);
9048 + prg->chan[prg_chan].used_pre = i;
9050 + /* configure the PRE to PRG channel mux */
9051 + shift = (i == 1) ? 12 : 14;
9052 + mux = (prg->id << 1) | (prg_chan - 1);
9053 + regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
9054 + 0x3 << shift, mux << shift);
9056 + /* check other mux, must not point to same channel */
9057 + shift = (i == 1) ? 14 : 12;
9058 + regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
9059 + if (((val >> shift) & 0x3) == mux) {
9060 + regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
9062 + (mux ^ 0x1) << shift);
9070 + dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
9074 +static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
9076 + struct ipu_prg_channel *chan = &prg->chan[prg_chan];
9078 + ipu_pre_put(prg->pres[chan->used_pre]);
9079 + chan->used_pre = -1;
9082 +void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
9084 + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
9085 + struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
9086 + struct ipu_prg_channel *chan;
9092 + chan = &prg->chan[prg_chan];
9093 + if (!chan->enabled)
9096 + pm_runtime_get_sync(prg->dev);
9098 + val = readl(prg->regs + IPU_PRG_CTL);
9099 + val |= IPU_PRG_CTL_BYPASS(prg_chan);
9100 + writel(val, prg->regs + IPU_PRG_CTL);
9102 + val = IPU_PRG_REG_UPDATE_REG_UPDATE;
9103 + writel(val, prg->regs + IPU_PRG_REG_UPDATE);
9105 + pm_runtime_put(prg->dev);
9107 + ipu_prg_put_pre(prg, prg_chan);
9109 + chan->enabled = false;
9111 +EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
9113 +int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
9114 + unsigned int axi_id, unsigned int width,
9115 + unsigned int height, unsigned int stride,
9116 + u32 format, uint64_t modifier, unsigned long *eba)
9118 + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
9119 + struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
9120 + struct ipu_prg_channel *chan;
9127 + chan = &prg->chan[prg_chan];
9129 + if (chan->enabled) {
9130 + ipu_pre_update(prg->pres[chan->used_pre], *eba);
9134 + ret = ipu_prg_get_pre(prg, prg_chan);
9138 + ipu_pre_configure(prg->pres[chan->used_pre],
9139 + width, height, stride, format, modifier, *eba);
9142 + pm_runtime_get_sync(prg->dev);
9144 + val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
9145 + writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
9147 + val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
9148 + IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
9149 + ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
9150 + IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
9151 + writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
9153 + val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
9155 + writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
9157 + val = readl(prg->regs + IPU_PRG_CTL);
9158 + /* config AXI ID */
9159 + val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
9160 + IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
9161 + val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
9162 + /* enable channel */
9163 + val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
9164 + writel(val, prg->regs + IPU_PRG_CTL);
9166 + val = IPU_PRG_REG_UPDATE_REG_UPDATE;
9167 + writel(val, prg->regs + IPU_PRG_REG_UPDATE);
9169 + /* wait for both double buffers to be filled */
9170 + readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
9171 + (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
9172 + (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
9175 + pm_runtime_put(prg->dev);
9177 + chan->enabled = true;
9180 +EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
9182 +bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
9184 + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
9185 + struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
9186 + struct ipu_prg_channel *chan;
9191 + chan = &prg->chan[prg_chan];
9192 + WARN_ON(!chan->enabled);
9194 + return ipu_pre_update_pending(prg->pres[chan->used_pre]);
9196 +EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
9198 +static int ipu_prg_probe(struct platform_device *pdev)
9200 + struct device *dev = &pdev->dev;
9201 + struct resource *res;
9202 + struct ipu_prg *prg;
9206 + prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
9210 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9211 + prg->regs = devm_ioremap_resource(&pdev->dev, res);
9212 + if (IS_ERR(prg->regs))
9213 + return PTR_ERR(prg->regs);
9216 + prg->clk_ipg = devm_clk_get(dev, "ipg");
9217 + if (IS_ERR(prg->clk_ipg))
9218 + return PTR_ERR(prg->clk_ipg);
9220 + prg->clk_axi = devm_clk_get(dev, "axi");
9221 + if (IS_ERR(prg->clk_axi))
9222 + return PTR_ERR(prg->clk_axi);
9225 + syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
9226 + if (IS_ERR(prg->iomuxc_gpr))
9227 + return PTR_ERR(prg->iomuxc_gpr);
9229 + for (i = 0; i < 3; i++) {
9230 + prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
9231 + if (!prg->pres[i])
9232 + return -EPROBE_DEFER;
9235 + ret = clk_prepare_enable(prg->clk_ipg);
9239 + ret = clk_prepare_enable(prg->clk_axi);
9241 + clk_disable_unprepare(prg->clk_ipg);
9245 + /* init to free running mode */
9246 + val = readl(prg->regs + IPU_PRG_CTL);
9247 + val |= IPU_PRG_CTL_SHADOW_EN;
9248 + writel(val, prg->regs + IPU_PRG_CTL);
9250 + /* disable address threshold */
9251 + writel(0xffffffff, prg->regs + IPU_PRG_THD);
9253 + pm_runtime_set_active(dev);
9254 + pm_runtime_enable(dev);
9257 + platform_set_drvdata(pdev, prg);
9258 + mutex_lock(&ipu_prg_list_mutex);
9259 + list_add(&prg->list, &ipu_prg_list);
9260 + mutex_unlock(&ipu_prg_list_mutex);
9265 +static int ipu_prg_remove(struct platform_device *pdev)
9267 + struct ipu_prg *prg = platform_get_drvdata(pdev);
9269 + mutex_lock(&ipu_prg_list_mutex);
9270 + list_del(&prg->list);
9271 + mutex_unlock(&ipu_prg_list_mutex);
9277 +static int prg_suspend(struct device *dev)
9279 + struct ipu_prg *prg = dev_get_drvdata(dev);
9281 + clk_disable_unprepare(prg->clk_axi);
9282 + clk_disable_unprepare(prg->clk_ipg);
9287 +static int prg_resume(struct device *dev)
9289 + struct ipu_prg *prg = dev_get_drvdata(dev);
9292 + ret = clk_prepare_enable(prg->clk_ipg);
9296 + ret = clk_prepare_enable(prg->clk_axi);
9298 + clk_disable_unprepare(prg->clk_ipg);
9306 +static const struct dev_pm_ops prg_pm_ops = {
9307 + SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
9310 +static const struct of_device_id ipu_prg_dt_ids[] = {
9311 + { .compatible = "fsl,imx6qp-prg", },
9312 + { /* sentinel */ },
9315 +struct platform_driver ipu_prg_drv = {
9316 + .probe = ipu_prg_probe,
9317 + .remove = ipu_prg_remove,
9319 + .name = "imx-ipu-prg",
9320 + .pm = &prg_pm_ops,
9321 + .of_match_table = ipu_prg_dt_ids,
9325 +++ b/drivers/gpu/imx/ipu-v3/ipu-prv.h
9327 +/* SPDX-License-Identifier: GPL-2.0-or-later */
9329 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
9330 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
9332 +#ifndef __IPU_PRV_H__
9333 +#define __IPU_PRV_H__
9337 +#include <linux/types.h>
9338 +#include <linux/device.h>
9339 +#include <linux/clk.h>
9340 +#include <linux/platform_device.h>
9342 +#include <video/imx-ipu-v3.h>
9344 +#define IPU_MCU_T_DEFAULT 8
9345 +#define IPU_CM_IDMAC_REG_OFS 0x00008000
9346 +#define IPU_CM_IC_REG_OFS 0x00020000
9347 +#define IPU_CM_IRT_REG_OFS 0x00028000
9348 +#define IPU_CM_CSI0_REG_OFS 0x00030000
9349 +#define IPU_CM_CSI1_REG_OFS 0x00038000
9350 +#define IPU_CM_SMFC_REG_OFS 0x00050000
9351 +#define IPU_CM_DC_REG_OFS 0x00058000
9352 +#define IPU_CM_DMFC_REG_OFS 0x00060000
9354 +/* Register addresses */
9355 +/* IPU Common registers */
9356 +#define IPU_CM_REG(offset) (offset)
9358 +#define IPU_CONF IPU_CM_REG(0)
9360 +#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0)
9361 +#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4)
9362 +#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8)
9363 +#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac)
9364 +#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0)
9365 +#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4)
9366 +#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8)
9367 +#define IPU_SKIP IPU_CM_REG(0x00bc)
9368 +#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0)
9369 +#define IPU_DISP_GEN IPU_CM_REG(0x00c4)
9370 +#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8)
9371 +#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc)
9372 +#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0)
9373 +#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4)
9374 +#define IPU_SNOOP IPU_CM_REG(0x00d8)
9375 +#define IPU_MEM_RST IPU_CM_REG(0x00dc)
9376 +#define IPU_PM IPU_CM_REG(0x00e0)
9377 +#define IPU_GPR IPU_CM_REG(0x00e4)
9378 +#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
9379 +#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
9380 +#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32))
9381 +#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244)
9382 +#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248)
9383 +#define IPU_SRM_STAT IPU_CM_REG(0x024C)
9384 +#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250)
9385 +#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
9386 +#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
9387 +#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
9388 +#define IPU_CHA_BUF2_RDY(ch) IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
9389 +#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
9390 +#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
9392 +#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n))
9393 +#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n))
9396 +#define DP_S_SRM_MODE_MASK (0x3 << 3)
9397 +#define DP_S_SRM_MODE_NOW (0x3 << 3)
9398 +#define DP_S_SRM_MODE_NEXT_FRAME (0x1 << 3)
9400 +/* FS_PROC_FLOW1 */
9401 +#define FS_PRPENC_ROT_SRC_SEL_MASK (0xf << 0)
9402 +#define FS_PRPENC_ROT_SRC_SEL_ENC (0x7 << 0)
9403 +#define FS_PRPVF_ROT_SRC_SEL_MASK (0xf << 8)
9404 +#define FS_PRPVF_ROT_SRC_SEL_VF (0x8 << 8)
9405 +#define FS_PP_SRC_SEL_MASK (0xf << 12)
9406 +#define FS_PP_ROT_SRC_SEL_MASK (0xf << 16)
9407 +#define FS_PP_ROT_SRC_SEL_PP (0x5 << 16)
9408 +#define FS_VDI1_SRC_SEL_MASK (0x3 << 20)
9409 +#define FS_VDI3_SRC_SEL_MASK (0x3 << 20)
9410 +#define FS_PRP_SRC_SEL_MASK (0xf << 24)
9411 +#define FS_VDI_SRC_SEL_MASK (0x3 << 28)
9412 +#define FS_VDI_SRC_SEL_CSI_DIRECT (0x1 << 28)
9413 +#define FS_VDI_SRC_SEL_VDOA (0x2 << 28)
9415 +/* FS_PROC_FLOW2 */
9416 +#define FS_PRP_ENC_DEST_SEL_MASK (0xf << 0)
9417 +#define FS_PRP_ENC_DEST_SEL_IRT_ENC (0x1 << 0)
9418 +#define FS_PRPVF_DEST_SEL_MASK (0xf << 4)
9419 +#define FS_PRPVF_DEST_SEL_IRT_VF (0x1 << 4)
9420 +#define FS_PRPVF_ROT_DEST_SEL_MASK (0xf << 8)
9421 +#define FS_PP_DEST_SEL_MASK (0xf << 12)
9422 +#define FS_PP_DEST_SEL_IRT_PP (0x3 << 12)
9423 +#define FS_PP_ROT_DEST_SEL_MASK (0xf << 16)
9424 +#define FS_PRPENC_ROT_DEST_SEL_MASK (0xf << 20)
9425 +#define FS_PRP_DEST_SEL_MASK (0xf << 24)
9427 +#define IPU_DI0_COUNTER_RELEASE (1 << 24)
9428 +#define IPU_DI1_COUNTER_RELEASE (1 << 25)
9430 +#define IPU_IDMAC_REG(offset) (offset)
9432 +#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
9433 +#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
9434 +#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c)
9435 +#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
9436 +#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
9437 +#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
9438 +#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024)
9439 +#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028)
9440 +#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c)
9441 +#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030)
9442 +#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034)
9443 +#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
9444 +#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
9446 +#define IPU_NUM_IRQS (32 * 15)
9449 + IPU_CONF_CSI0_EN = (1 << 0),
9450 + IPU_CONF_CSI1_EN = (1 << 1),
9451 + IPU_CONF_IC_EN = (1 << 2),
9452 + IPU_CONF_ROT_EN = (1 << 3),
9453 + IPU_CONF_ISP_EN = (1 << 4),
9454 + IPU_CONF_DP_EN = (1 << 5),
9455 + IPU_CONF_DI0_EN = (1 << 6),
9456 + IPU_CONF_DI1_EN = (1 << 7),
9457 + IPU_CONF_SMFC_EN = (1 << 8),
9458 + IPU_CONF_DC_EN = (1 << 9),
9459 + IPU_CONF_DMFC_EN = (1 << 10),
9461 + IPU_CONF_VDI_EN = (1 << 12),
9463 + IPU_CONF_IDMAC_DIS = (1 << 22),
9465 + IPU_CONF_IC_DMFC_SEL = (1 << 25),
9466 + IPU_CONF_IC_DMFC_SYNC = (1 << 26),
9467 + IPU_CONF_VDI_DMFC_SYNC = (1 << 27),
9469 + IPU_CONF_CSI0_DATA_SOURCE = (1 << 28),
9470 + IPU_CONF_CSI1_DATA_SOURCE = (1 << 29),
9471 + IPU_CONF_IC_INPUT = (1 << 30),
9472 + IPU_CONF_CSI_SEL = (1 << 31),
9475 +struct ipuv3_channel {
9477 + struct ipu_soc *ipu;
9478 + struct list_head list;
9483 +struct ipu_dc_priv;
9484 +struct ipu_dmfc_priv;
9486 +struct ipu_ic_priv;
9488 +struct ipu_image_convert_priv;
9489 +struct ipu_smfc_priv;
9493 +struct ipu_devtype;
9496 + struct device *dev;
9497 + const struct ipu_devtype *devtype;
9498 + enum ipuv3_type ipu_type;
9500 + struct mutex channel_lock;
9501 + struct list_head channels;
9503 + void __iomem *cm_reg;
9504 + void __iomem *idmac_reg;
9513 + struct irq_domain *domain;
9515 + struct ipu_cpmem *cpmem_priv;
9516 + struct ipu_dc_priv *dc_priv;
9517 + struct ipu_dp_priv *dp_priv;
9518 + struct ipu_dmfc_priv *dmfc_priv;
9519 + struct ipu_di *di_priv[2];
9520 + struct ipu_csi *csi_priv[2];
9521 + struct ipu_ic_priv *ic_priv;
9522 + struct ipu_vdi *vdi_priv;
9523 + struct ipu_image_convert_priv *image_convert_priv;
9524 + struct ipu_smfc_priv *smfc_priv;
9525 + struct ipu_prg *prg_priv;
9528 +static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
9530 + return readl(ipu->idmac_reg + offset);
9533 +static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
9536 + writel(value, ipu->idmac_reg + offset);
9539 +void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
9541 +int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
9542 +int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
9544 +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
9546 +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
9547 + unsigned long base, u32 module, struct clk *clk_ipu);
9548 +void ipu_csi_exit(struct ipu_soc *ipu, int id);
9550 +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
9551 + unsigned long base, unsigned long tpmem_base);
9552 +void ipu_ic_exit(struct ipu_soc *ipu);
9554 +int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
9555 + unsigned long base, u32 module);
9556 +void ipu_vdi_exit(struct ipu_soc *ipu);
9558 +int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
9559 +void ipu_image_convert_exit(struct ipu_soc *ipu);
9561 +int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
9562 + unsigned long base, u32 module, struct clk *ipu_clk);
9563 +void ipu_di_exit(struct ipu_soc *ipu, int id);
9565 +int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
9566 + struct clk *ipu_clk);
9567 +void ipu_dmfc_exit(struct ipu_soc *ipu);
9569 +int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
9570 +void ipu_dp_exit(struct ipu_soc *ipu);
9572 +int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
9573 + unsigned long template_base);
9574 +void ipu_dc_exit(struct ipu_soc *ipu);
9576 +int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
9577 +void ipu_cpmem_exit(struct ipu_soc *ipu);
9579 +int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
9580 +void ipu_smfc_exit(struct ipu_soc *ipu);
9582 +struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
9584 +int ipu_pre_get_available_count(void);
9585 +int ipu_pre_get(struct ipu_pre *pre);
9586 +void ipu_pre_put(struct ipu_pre *pre);
9587 +u32 ipu_pre_get_baddr(struct ipu_pre *pre);
9588 +void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
9589 + unsigned int height, unsigned int stride, u32 format,
9590 + uint64_t modifier, unsigned int bufaddr);
9591 +void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
9592 +bool ipu_pre_update_pending(struct ipu_pre *pre);
9594 +struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
9597 +extern struct platform_driver ipu_pre_drv;
9598 +extern struct platform_driver ipu_prg_drv;
9600 +#endif /* __IPU_PRV_H__ */
9602 +++ b/drivers/gpu/imx/ipu-v3/ipu-smfc.c
9604 +// SPDX-License-Identifier: GPL-2.0-or-later
9606 + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
9608 +#include <linux/export.h>
9609 +#include <linux/types.h>
9610 +#include <linux/init.h>
9611 +#include <linux/io.h>
9612 +#include <linux/errno.h>
9613 +#include <linux/spinlock.h>
9614 +#include <linux/delay.h>
9615 +#include <linux/clk.h>
9616 +#include <video/imx-ipu-v3.h>
9618 +#include "ipu-prv.h"
9621 + struct ipu_smfc_priv *priv;
9626 +struct ipu_smfc_priv {
9627 + void __iomem *base;
9629 + struct ipu_soc *ipu;
9630 + struct ipu_smfc channel[4];
9634 +/*SMFC Registers */
9635 +#define SMFC_MAP 0x0000
9636 +#define SMFC_WMC 0x0004
9637 +#define SMFC_BS 0x0008
9639 +int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
9641 + struct ipu_smfc_priv *priv = smfc->priv;
9642 + unsigned long flags;
9645 + spin_lock_irqsave(&priv->lock, flags);
9647 + shift = smfc->chno * 4;
9648 + val = readl(priv->base + SMFC_BS);
9649 + val &= ~(0xf << shift);
9650 + val |= burstsize << shift;
9651 + writel(val, priv->base + SMFC_BS);
9653 + spin_unlock_irqrestore(&priv->lock, flags);
9657 +EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
9659 +int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
9661 + struct ipu_smfc_priv *priv = smfc->priv;
9662 + unsigned long flags;
9665 + spin_lock_irqsave(&priv->lock, flags);
9667 + shift = smfc->chno * 3;
9668 + val = readl(priv->base + SMFC_MAP);
9669 + val &= ~(0x7 << shift);
9670 + val |= ((csi_id << 2) | mipi_id) << shift;
9671 + writel(val, priv->base + SMFC_MAP);
9673 + spin_unlock_irqrestore(&priv->lock, flags);
9677 +EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
9679 +int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
9681 + struct ipu_smfc_priv *priv = smfc->priv;
9682 + unsigned long flags;
9685 + spin_lock_irqsave(&priv->lock, flags);
9687 + shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
9688 + val = readl(priv->base + SMFC_WMC);
9689 + val &= ~(0x3f << shift);
9690 + val |= ((clr_level << 3) | set_level) << shift;
9691 + writel(val, priv->base + SMFC_WMC);
9693 + spin_unlock_irqrestore(&priv->lock, flags);
9697 +EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
9699 +int ipu_smfc_enable(struct ipu_smfc *smfc)
9701 + struct ipu_smfc_priv *priv = smfc->priv;
9702 + unsigned long flags;
9704 + spin_lock_irqsave(&priv->lock, flags);
9706 + if (!priv->use_count)
9707 + ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
9709 + priv->use_count++;
9711 + spin_unlock_irqrestore(&priv->lock, flags);
9715 +EXPORT_SYMBOL_GPL(ipu_smfc_enable);
9717 +int ipu_smfc_disable(struct ipu_smfc *smfc)
9719 + struct ipu_smfc_priv *priv = smfc->priv;
9720 + unsigned long flags;
9722 + spin_lock_irqsave(&priv->lock, flags);
9724 + priv->use_count--;
9726 + if (!priv->use_count)
9727 + ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
9729 + if (priv->use_count < 0)
9730 + priv->use_count = 0;
9732 + spin_unlock_irqrestore(&priv->lock, flags);
9736 +EXPORT_SYMBOL_GPL(ipu_smfc_disable);
9738 +struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
9740 + struct ipu_smfc_priv *priv = ipu->smfc_priv;
9741 + struct ipu_smfc *smfc, *ret;
9742 + unsigned long flags;
9745 + return ERR_PTR(-EINVAL);
9747 + smfc = &priv->channel[chno];
9750 + spin_lock_irqsave(&priv->lock, flags);
9752 + if (smfc->inuse) {
9753 + ret = ERR_PTR(-EBUSY);
9757 + smfc->inuse = true;
9759 + spin_unlock_irqrestore(&priv->lock, flags);
9762 +EXPORT_SYMBOL_GPL(ipu_smfc_get);
9764 +void ipu_smfc_put(struct ipu_smfc *smfc)
9766 + struct ipu_smfc_priv *priv = smfc->priv;
9767 + unsigned long flags;
9769 + spin_lock_irqsave(&priv->lock, flags);
9770 + smfc->inuse = false;
9771 + spin_unlock_irqrestore(&priv->lock, flags);
9773 +EXPORT_SYMBOL_GPL(ipu_smfc_put);
9775 +int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
9776 + unsigned long base)
9778 + struct ipu_smfc_priv *priv;
9781 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
9785 + ipu->smfc_priv = priv;
9786 + spin_lock_init(&priv->lock);
9789 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
9793 + for (i = 0; i < 4; i++) {
9794 + priv->channel[i].priv = priv;
9795 + priv->channel[i].chno = i;
9798 + pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
9803 +void ipu_smfc_exit(struct ipu_soc *ipu)
9807 +++ b/drivers/gpu/imx/ipu-v3/ipu-vdi.c
9809 +// SPDX-License-Identifier: GPL-2.0-or-later
9811 + * Copyright (C) 2012-2016 Mentor Graphics Inc.
9812 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
9814 +#include <linux/io.h>
9815 +#include "ipu-prv.h"
9818 + void __iomem *base;
9822 + struct ipu_soc *ipu;
9826 +/* VDI Register Offsets */
9827 +#define VDI_FSIZE 0x0000
9828 +#define VDI_C 0x0004
9830 +/* VDI Register Fields */
9831 +#define VDI_C_CH_420 (0 << 1)
9832 +#define VDI_C_CH_422 (1 << 1)
9833 +#define VDI_C_MOT_SEL_MASK (0x3 << 2)
9834 +#define VDI_C_MOT_SEL_FULL (2 << 2)
9835 +#define VDI_C_MOT_SEL_LOW (1 << 2)
9836 +#define VDI_C_MOT_SEL_MED (0 << 2)
9837 +#define VDI_C_BURST_SIZE1_4 (3 << 4)
9838 +#define VDI_C_BURST_SIZE2_4 (3 << 8)
9839 +#define VDI_C_BURST_SIZE3_4 (3 << 12)
9840 +#define VDI_C_BURST_SIZE_MASK 0xF
9841 +#define VDI_C_BURST_SIZE1_OFFSET 4
9842 +#define VDI_C_BURST_SIZE2_OFFSET 8
9843 +#define VDI_C_BURST_SIZE3_OFFSET 12
9844 +#define VDI_C_VWM1_SET_1 (0 << 16)
9845 +#define VDI_C_VWM1_SET_2 (1 << 16)
9846 +#define VDI_C_VWM1_CLR_2 (1 << 19)
9847 +#define VDI_C_VWM3_SET_1 (0 << 22)
9848 +#define VDI_C_VWM3_SET_2 (1 << 22)
9849 +#define VDI_C_VWM3_CLR_2 (1 << 25)
9850 +#define VDI_C_TOP_FIELD_MAN_1 (1 << 30)
9851 +#define VDI_C_TOP_FIELD_AUTO_1 (1 << 31)
9853 +static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
9855 + return readl(vdi->base + offset);
9858 +static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
9859 + unsigned int offset)
9861 + writel(value, vdi->base + offset);
9864 +void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
9866 + bool top_field_0 = false;
9867 + unsigned long flags;
9871 + case V4L2_FIELD_INTERLACED_TB:
9872 + case V4L2_FIELD_SEQ_TB:
9873 + case V4L2_FIELD_TOP:
9874 + top_field_0 = true;
9876 + case V4L2_FIELD_INTERLACED_BT:
9877 + case V4L2_FIELD_SEQ_BT:
9878 + case V4L2_FIELD_BOTTOM:
9879 + top_field_0 = false;
9882 + top_field_0 = (std & V4L2_STD_525_60) ? true : false;
9886 + spin_lock_irqsave(&vdi->lock, flags);
9888 + reg = ipu_vdi_read(vdi, VDI_C);
9890 + reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
9892 + reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
9893 + ipu_vdi_write(vdi, reg, VDI_C);
9895 + spin_unlock_irqrestore(&vdi->lock, flags);
9897 +EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
9899 +void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
9901 + unsigned long flags;
9904 + spin_lock_irqsave(&vdi->lock, flags);
9906 + reg = ipu_vdi_read(vdi, VDI_C);
9908 + reg &= ~VDI_C_MOT_SEL_MASK;
9910 + switch (motion_sel) {
9912 + reg |= VDI_C_MOT_SEL_MED;
9915 + reg |= VDI_C_MOT_SEL_FULL;
9918 + reg |= VDI_C_MOT_SEL_LOW;
9922 + ipu_vdi_write(vdi, reg, VDI_C);
9924 + spin_unlock_irqrestore(&vdi->lock, flags);
9926 +EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
9928 +void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
9930 + unsigned long flags;
9931 + u32 pixel_fmt, reg;
9933 + spin_lock_irqsave(&vdi->lock, flags);
9935 + reg = ((yres - 1) << 16) | (xres - 1);
9936 + ipu_vdi_write(vdi, reg, VDI_FSIZE);
9939 + * Full motion, only vertical filter is used.
9940 + * Burst size is 4 accesses
9942 + if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
9943 + code == MEDIA_BUS_FMT_UYVY8_1X16 ||
9944 + code == MEDIA_BUS_FMT_YUYV8_2X8 ||
9945 + code == MEDIA_BUS_FMT_YUYV8_1X16)
9946 + pixel_fmt = VDI_C_CH_422;
9948 + pixel_fmt = VDI_C_CH_420;
9950 + reg = ipu_vdi_read(vdi, VDI_C);
9952 + reg |= VDI_C_BURST_SIZE2_4;
9953 + reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
9954 + reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
9955 + ipu_vdi_write(vdi, reg, VDI_C);
9957 + spin_unlock_irqrestore(&vdi->lock, flags);
9959 +EXPORT_SYMBOL_GPL(ipu_vdi_setup);
9961 +void ipu_vdi_unsetup(struct ipu_vdi *vdi)
9963 + unsigned long flags;
9965 + spin_lock_irqsave(&vdi->lock, flags);
9966 + ipu_vdi_write(vdi, 0, VDI_FSIZE);
9967 + ipu_vdi_write(vdi, 0, VDI_C);
9968 + spin_unlock_irqrestore(&vdi->lock, flags);
9970 +EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
9972 +int ipu_vdi_enable(struct ipu_vdi *vdi)
9974 + unsigned long flags;
9976 + spin_lock_irqsave(&vdi->lock, flags);
9978 + if (!vdi->use_count)
9979 + ipu_module_enable(vdi->ipu, vdi->module);
9983 + spin_unlock_irqrestore(&vdi->lock, flags);
9987 +EXPORT_SYMBOL_GPL(ipu_vdi_enable);
9989 +int ipu_vdi_disable(struct ipu_vdi *vdi)
9991 + unsigned long flags;
9993 + spin_lock_irqsave(&vdi->lock, flags);
9995 + if (vdi->use_count) {
9996 + if (!--vdi->use_count)
9997 + ipu_module_disable(vdi->ipu, vdi->module);
10000 + spin_unlock_irqrestore(&vdi->lock, flags);
10004 +EXPORT_SYMBOL_GPL(ipu_vdi_disable);
10006 +struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
10008 + return ipu->vdi_priv;
10010 +EXPORT_SYMBOL_GPL(ipu_vdi_get);
10012 +void ipu_vdi_put(struct ipu_vdi *vdi)
10015 +EXPORT_SYMBOL_GPL(ipu_vdi_put);
10017 +int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
10018 + unsigned long base, u32 module)
10020 + struct ipu_vdi *vdi;
10022 + vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
10026 + ipu->vdi_priv = vdi;
10028 + spin_lock_init(&vdi->lock);
10029 + vdi->module = module;
10030 + vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
10034 + dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
10040 +void ipu_vdi_exit(struct ipu_soc *ipu)
10043 --- a/drivers/gpu/ipu-v3/Kconfig
10046 -# SPDX-License-Identifier: GPL-2.0-only
10047 -config IMX_IPUV3_CORE
10048 - tristate "IPUv3 core support"
10049 - depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
10050 - depends on DRM || !DRM # if DRM=m, this can't be 'y'
10051 - select BITREVERSE
10052 - select GENERIC_ALLOCATOR if DRM
10053 - select GENERIC_IRQ_CHIP
10055 - Choose this if you have a i.MX5/6 system and want to use the Image
10056 - Processing Unit. This option only enables IPU base support.
10057 --- a/drivers/gpu/ipu-v3/Makefile
10060 -# SPDX-License-Identifier: GPL-2.0
10061 -obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
10063 -imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
10064 - ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
10065 - ipu-image-convert.o ipu-smfc.o ipu-vdi.o
10068 - imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
10070 --- a/drivers/gpu/ipu-v3/ipu-common.c
10073 -// SPDX-License-Identifier: GPL-2.0-or-later
10075 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
10076 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
10078 -#include <linux/module.h>
10079 -#include <linux/export.h>
10080 -#include <linux/types.h>
10081 -#include <linux/reset.h>
10082 -#include <linux/platform_device.h>
10083 -#include <linux/err.h>
10084 -#include <linux/spinlock.h>
10085 -#include <linux/delay.h>
10086 -#include <linux/interrupt.h>
10087 -#include <linux/io.h>
10088 -#include <linux/clk.h>
10089 -#include <linux/list.h>
10090 -#include <linux/irq.h>
10091 -#include <linux/irqchip/chained_irq.h>
10092 -#include <linux/irqdomain.h>
10093 -#include <linux/of_device.h>
10094 -#include <linux/of_graph.h>
10096 -#include <drm/drm_fourcc.h>
10098 -#include <video/imx-ipu-v3.h>
10099 -#include "ipu-prv.h"
10101 -static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
10103 - return readl(ipu->cm_reg + offset);
10106 -static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
10108 - writel(value, ipu->cm_reg + offset);
10111 -int ipu_get_num(struct ipu_soc *ipu)
10115 -EXPORT_SYMBOL_GPL(ipu_get_num);
10117 -void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
10121 - val = ipu_cm_read(ipu, IPU_SRM_PRI2);
10122 - val &= ~DP_S_SRM_MODE_MASK;
10123 - val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
10124 - DP_S_SRM_MODE_NOW;
10125 - ipu_cm_write(ipu, val, IPU_SRM_PRI2);
10127 -EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
10129 -enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
10131 - switch (drm_fourcc) {
10132 - case DRM_FORMAT_ARGB1555:
10133 - case DRM_FORMAT_ABGR1555:
10134 - case DRM_FORMAT_RGBA5551:
10135 - case DRM_FORMAT_BGRA5551:
10136 - case DRM_FORMAT_RGB565:
10137 - case DRM_FORMAT_BGR565:
10138 - case DRM_FORMAT_RGB888:
10139 - case DRM_FORMAT_BGR888:
10140 - case DRM_FORMAT_ARGB4444:
10141 - case DRM_FORMAT_XRGB8888:
10142 - case DRM_FORMAT_XBGR8888:
10143 - case DRM_FORMAT_RGBX8888:
10144 - case DRM_FORMAT_BGRX8888:
10145 - case DRM_FORMAT_ARGB8888:
10146 - case DRM_FORMAT_ABGR8888:
10147 - case DRM_FORMAT_RGBA8888:
10148 - case DRM_FORMAT_BGRA8888:
10149 - case DRM_FORMAT_RGB565_A8:
10150 - case DRM_FORMAT_BGR565_A8:
10151 - case DRM_FORMAT_RGB888_A8:
10152 - case DRM_FORMAT_BGR888_A8:
10153 - case DRM_FORMAT_RGBX8888_A8:
10154 - case DRM_FORMAT_BGRX8888_A8:
10155 - return IPUV3_COLORSPACE_RGB;
10156 - case DRM_FORMAT_YUYV:
10157 - case DRM_FORMAT_UYVY:
10158 - case DRM_FORMAT_YUV420:
10159 - case DRM_FORMAT_YVU420:
10160 - case DRM_FORMAT_YUV422:
10161 - case DRM_FORMAT_YVU422:
10162 - case DRM_FORMAT_YUV444:
10163 - case DRM_FORMAT_YVU444:
10164 - case DRM_FORMAT_NV12:
10165 - case DRM_FORMAT_NV21:
10166 - case DRM_FORMAT_NV16:
10167 - case DRM_FORMAT_NV61:
10168 - return IPUV3_COLORSPACE_YUV;
10170 - return IPUV3_COLORSPACE_UNKNOWN;
10173 -EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
10175 -enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
10177 - switch (pixelformat) {
10178 - case V4L2_PIX_FMT_YUV420:
10179 - case V4L2_PIX_FMT_YVU420:
10180 - case V4L2_PIX_FMT_YUV422P:
10181 - case V4L2_PIX_FMT_UYVY:
10182 - case V4L2_PIX_FMT_YUYV:
10183 - case V4L2_PIX_FMT_NV12:
10184 - case V4L2_PIX_FMT_NV21:
10185 - case V4L2_PIX_FMT_NV16:
10186 - case V4L2_PIX_FMT_NV61:
10187 - return IPUV3_COLORSPACE_YUV;
10188 - case V4L2_PIX_FMT_RGB565:
10189 - case V4L2_PIX_FMT_BGR24:
10190 - case V4L2_PIX_FMT_RGB24:
10191 - case V4L2_PIX_FMT_ABGR32:
10192 - case V4L2_PIX_FMT_XBGR32:
10193 - case V4L2_PIX_FMT_BGRA32:
10194 - case V4L2_PIX_FMT_BGRX32:
10195 - case V4L2_PIX_FMT_RGBA32:
10196 - case V4L2_PIX_FMT_RGBX32:
10197 - case V4L2_PIX_FMT_ARGB32:
10198 - case V4L2_PIX_FMT_XRGB32:
10199 - return IPUV3_COLORSPACE_RGB;
10201 - return IPUV3_COLORSPACE_UNKNOWN;
10204 -EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
10206 -bool ipu_pixelformat_is_planar(u32 pixelformat)
10208 - switch (pixelformat) {
10209 - case V4L2_PIX_FMT_YUV420:
10210 - case V4L2_PIX_FMT_YVU420:
10211 - case V4L2_PIX_FMT_YUV422P:
10212 - case V4L2_PIX_FMT_NV12:
10213 - case V4L2_PIX_FMT_NV21:
10214 - case V4L2_PIX_FMT_NV16:
10215 - case V4L2_PIX_FMT_NV61:
10221 -EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
10223 -enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
10225 - switch (mbus_code & 0xf000) {
10227 - return IPUV3_COLORSPACE_RGB;
10229 - return IPUV3_COLORSPACE_YUV;
10231 - return IPUV3_COLORSPACE_UNKNOWN;
10234 -EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
10236 -int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
10238 - switch (pixelformat) {
10239 - case V4L2_PIX_FMT_YUV420:
10240 - case V4L2_PIX_FMT_YVU420:
10241 - case V4L2_PIX_FMT_YUV422P:
10242 - case V4L2_PIX_FMT_NV12:
10243 - case V4L2_PIX_FMT_NV21:
10244 - case V4L2_PIX_FMT_NV16:
10245 - case V4L2_PIX_FMT_NV61:
10247 - * for the planar YUV formats, the stride passed to
10248 - * cpmem must be the stride in bytes of the Y plane.
10249 - * And all the planar YUV formats have an 8-bit
10252 - return (8 * pixel_stride) >> 3;
10253 - case V4L2_PIX_FMT_RGB565:
10254 - case V4L2_PIX_FMT_YUYV:
10255 - case V4L2_PIX_FMT_UYVY:
10256 - return (16 * pixel_stride) >> 3;
10257 - case V4L2_PIX_FMT_BGR24:
10258 - case V4L2_PIX_FMT_RGB24:
10259 - return (24 * pixel_stride) >> 3;
10260 - case V4L2_PIX_FMT_BGR32:
10261 - case V4L2_PIX_FMT_RGB32:
10262 - case V4L2_PIX_FMT_XBGR32:
10263 - case V4L2_PIX_FMT_XRGB32:
10264 - return (32 * pixel_stride) >> 3;
10271 -EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
10273 -int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
10274 - bool hflip, bool vflip)
10278 - switch (degrees) {
10280 - vf = hf = r90 = 0;
10291 - vf = hf = r90 = 1;
10297 - hf ^= (u32)hflip;
10298 - vf ^= (u32)vflip;
10300 - *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
10303 -EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
10305 -int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
10306 - bool hflip, bool vflip)
10310 - r90 = ((u32)mode >> 2) & 0x1;
10311 - hf = ((u32)mode >> 1) & 0x1;
10312 - vf = ((u32)mode >> 0) & 0x1;
10313 - hf ^= (u32)hflip;
10314 - vf ^= (u32)vflip;
10316 - switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
10317 - case IPU_ROTATE_NONE:
10320 - case IPU_ROTATE_90_RIGHT:
10323 - case IPU_ROTATE_180:
10326 - case IPU_ROTATE_90_LEFT:
10335 -EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
10337 -struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
10339 - struct ipuv3_channel *channel;
10341 - dev_dbg(ipu->dev, "%s %d\n", __func__, num);
10344 - return ERR_PTR(-ENODEV);
10346 - mutex_lock(&ipu->channel_lock);
10348 - list_for_each_entry(channel, &ipu->channels, list) {
10349 - if (channel->num == num) {
10350 - channel = ERR_PTR(-EBUSY);
10355 - channel = kzalloc(sizeof(*channel), GFP_KERNEL);
10357 - channel = ERR_PTR(-ENOMEM);
10361 - channel->num = num;
10362 - channel->ipu = ipu;
10363 - list_add(&channel->list, &ipu->channels);
10366 - mutex_unlock(&ipu->channel_lock);
10370 -EXPORT_SYMBOL_GPL(ipu_idmac_get);
10372 -void ipu_idmac_put(struct ipuv3_channel *channel)
10374 - struct ipu_soc *ipu = channel->ipu;
10376 - dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
10378 - mutex_lock(&ipu->channel_lock);
10380 - list_del(&channel->list);
10383 - mutex_unlock(&ipu->channel_lock);
10385 -EXPORT_SYMBOL_GPL(ipu_idmac_put);
10387 -#define idma_mask(ch) (1 << ((ch) & 0x1f))
10390 - * This is an undocumented feature, a write one to a channel bit in
10391 - * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
10392 - * internal current buffer pointer so that transfers start from buffer
10393 - * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
10394 - * only says these are read-only registers). This operation is required
10395 - * for channel linking to work correctly, for instance video capture
10396 - * pipelines that carry out image rotations will fail after the first
10397 - * streaming unless this function is called for each channel before
10398 - * re-enabling the channels.
10400 -static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
10402 - struct ipu_soc *ipu = channel->ipu;
10403 - unsigned int chno = channel->num;
10405 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
10408 -void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
10409 - bool doublebuffer)
10411 - struct ipu_soc *ipu = channel->ipu;
10412 - unsigned long flags;
10415 - spin_lock_irqsave(&ipu->lock, flags);
10417 - reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
10418 - if (doublebuffer)
10419 - reg |= idma_mask(channel->num);
10421 - reg &= ~idma_mask(channel->num);
10422 - ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
10424 - __ipu_idmac_reset_current_buffer(channel);
10426 - spin_unlock_irqrestore(&ipu->lock, flags);
10428 -EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
10430 -static const struct {
10434 -} idmac_lock_en_info[] = {
10435 - { .chnum = 5, .reg = IDMAC_CH_LOCK_EN_1, .shift = 0, },
10436 - { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift = 2, },
10437 - { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift = 4, },
10438 - { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift = 6, },
10439 - { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift = 8, },
10440 - { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
10441 - { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
10442 - { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
10443 - { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
10444 - { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
10445 - { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
10446 - { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift = 0, },
10447 - { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift = 2, },
10448 - { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift = 4, },
10449 - { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift = 6, },
10450 - { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift = 8, },
10451 - { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
10454 -int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
10456 - struct ipu_soc *ipu = channel->ipu;
10457 - unsigned long flags;
10458 - u32 bursts, regval;
10461 - switch (num_bursts) {
10464 - bursts = 0x00; /* locking disabled */
10480 - * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
10481 - * i.MX53 channel arbitration locking doesn't seem to work properly.
10482 - * Allow enabling the lock feature on IPUv3H / i.MX6 only.
10484 - if (bursts && ipu->ipu_type != IPUV3H)
10487 - for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
10488 - if (channel->num == idmac_lock_en_info[i].chnum)
10491 - if (i >= ARRAY_SIZE(idmac_lock_en_info))
10494 - spin_lock_irqsave(&ipu->lock, flags);
10496 - regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
10497 - regval &= ~(0x03 << idmac_lock_en_info[i].shift);
10498 - regval |= (bursts << idmac_lock_en_info[i].shift);
10499 - ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
10501 - spin_unlock_irqrestore(&ipu->lock, flags);
10505 -EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
10507 -int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
10509 - unsigned long lock_flags;
10512 - spin_lock_irqsave(&ipu->lock, lock_flags);
10514 - val = ipu_cm_read(ipu, IPU_DISP_GEN);
10516 - if (mask & IPU_CONF_DI0_EN)
10517 - val |= IPU_DI0_COUNTER_RELEASE;
10518 - if (mask & IPU_CONF_DI1_EN)
10519 - val |= IPU_DI1_COUNTER_RELEASE;
10521 - ipu_cm_write(ipu, val, IPU_DISP_GEN);
10523 - val = ipu_cm_read(ipu, IPU_CONF);
10525 - ipu_cm_write(ipu, val, IPU_CONF);
10527 - spin_unlock_irqrestore(&ipu->lock, lock_flags);
10531 -EXPORT_SYMBOL_GPL(ipu_module_enable);
10533 -int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
10535 - unsigned long lock_flags;
10538 - spin_lock_irqsave(&ipu->lock, lock_flags);
10540 - val = ipu_cm_read(ipu, IPU_CONF);
10542 - ipu_cm_write(ipu, val, IPU_CONF);
10544 - val = ipu_cm_read(ipu, IPU_DISP_GEN);
10546 - if (mask & IPU_CONF_DI0_EN)
10547 - val &= ~IPU_DI0_COUNTER_RELEASE;
10548 - if (mask & IPU_CONF_DI1_EN)
10549 - val &= ~IPU_DI1_COUNTER_RELEASE;
10551 - ipu_cm_write(ipu, val, IPU_DISP_GEN);
10553 - spin_unlock_irqrestore(&ipu->lock, lock_flags);
10557 -EXPORT_SYMBOL_GPL(ipu_module_disable);
10559 -int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
10561 - struct ipu_soc *ipu = channel->ipu;
10562 - unsigned int chno = channel->num;
10564 - return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
10566 -EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
10568 -bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
10570 - struct ipu_soc *ipu = channel->ipu;
10571 - unsigned long flags;
10574 - spin_lock_irqsave(&ipu->lock, flags);
10575 - switch (buf_num) {
10577 - reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
10580 - reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
10583 - reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
10586 - spin_unlock_irqrestore(&ipu->lock, flags);
10588 - return ((reg & idma_mask(channel->num)) != 0);
10590 -EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
10592 -void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
10594 - struct ipu_soc *ipu = channel->ipu;
10595 - unsigned int chno = channel->num;
10596 - unsigned long flags;
10598 - spin_lock_irqsave(&ipu->lock, flags);
10600 - /* Mark buffer as ready. */
10601 - if (buf_num == 0)
10602 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
10604 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
10606 - spin_unlock_irqrestore(&ipu->lock, flags);
10608 -EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
10610 -void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
10612 - struct ipu_soc *ipu = channel->ipu;
10613 - unsigned int chno = channel->num;
10614 - unsigned long flags;
10616 - spin_lock_irqsave(&ipu->lock, flags);
10618 - ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
10619 - switch (buf_num) {
10621 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
10624 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
10627 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
10632 - ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
10634 - spin_unlock_irqrestore(&ipu->lock, flags);
10636 -EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
10638 -int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
10640 - struct ipu_soc *ipu = channel->ipu;
10642 - unsigned long flags;
10644 - spin_lock_irqsave(&ipu->lock, flags);
10646 - val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
10647 - val |= idma_mask(channel->num);
10648 - ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
10650 - spin_unlock_irqrestore(&ipu->lock, flags);
10654 -EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
10656 -bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
10658 - return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
10660 -EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
10662 -int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
10664 - struct ipu_soc *ipu = channel->ipu;
10665 - unsigned long timeout;
10667 - timeout = jiffies + msecs_to_jiffies(ms);
10668 - while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
10669 - idma_mask(channel->num)) {
10670 - if (time_after(jiffies, timeout))
10671 - return -ETIMEDOUT;
10677 -EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
10679 -int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
10681 - struct ipu_soc *ipu = channel->ipu;
10683 - unsigned long flags;
10685 - spin_lock_irqsave(&ipu->lock, flags);
10687 - /* Disable DMA channel(s) */
10688 - val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
10689 - val &= ~idma_mask(channel->num);
10690 - ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
10692 - __ipu_idmac_reset_current_buffer(channel);
10694 - /* Set channel buffers NOT to be ready */
10695 - ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
10697 - if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
10698 - idma_mask(channel->num)) {
10699 - ipu_cm_write(ipu, idma_mask(channel->num),
10700 - IPU_CHA_BUF0_RDY(channel->num));
10703 - if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
10704 - idma_mask(channel->num)) {
10705 - ipu_cm_write(ipu, idma_mask(channel->num),
10706 - IPU_CHA_BUF1_RDY(channel->num));
10709 - ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
10711 - /* Reset the double buffer */
10712 - val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
10713 - val &= ~idma_mask(channel->num);
10714 - ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
10716 - spin_unlock_irqrestore(&ipu->lock, flags);
10720 -EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
10723 - * The imx6 rev. D TRM says that enabling the WM feature will increase
10724 - * a channel's priority. Refer to Table 36-8 Calculated priority value.
10725 - * The sub-module that is the sink or source for the channel must enable
10726 - * watermark signal for this to take effect (SMFC_WM for instance).
10728 -void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
10730 - struct ipu_soc *ipu = channel->ipu;
10731 - unsigned long flags;
10734 - spin_lock_irqsave(&ipu->lock, flags);
10736 - val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
10738 - val |= 1 << (channel->num % 32);
10740 - val &= ~(1 << (channel->num % 32));
10741 - ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
10743 - spin_unlock_irqrestore(&ipu->lock, flags);
10745 -EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
10747 -static int ipu_memory_reset(struct ipu_soc *ipu)
10749 - unsigned long timeout;
10751 - ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
10753 - timeout = jiffies + msecs_to_jiffies(1000);
10754 - while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
10755 - if (time_after(jiffies, timeout))
10764 - * Set the source mux for the given CSI. Selects either parallel or
10765 - * MIPI CSI2 sources.
10767 -void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
10769 - unsigned long flags;
10772 - mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
10773 - IPU_CONF_CSI0_DATA_SOURCE;
10775 - spin_lock_irqsave(&ipu->lock, flags);
10777 - val = ipu_cm_read(ipu, IPU_CONF);
10782 - ipu_cm_write(ipu, val, IPU_CONF);
10784 - spin_unlock_irqrestore(&ipu->lock, flags);
10786 -EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
10789 - * Set the source mux for the IC. Selects either CSI[01] or the VDI.
10791 -void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
10793 - unsigned long flags;
10796 - spin_lock_irqsave(&ipu->lock, flags);
10798 - val = ipu_cm_read(ipu, IPU_CONF);
10800 - val |= IPU_CONF_IC_INPUT;
10802 - val &= ~IPU_CONF_IC_INPUT;
10805 - val |= IPU_CONF_CSI_SEL;
10807 - val &= ~IPU_CONF_CSI_SEL;
10809 - ipu_cm_write(ipu, val, IPU_CONF);
10811 - spin_unlock_irqrestore(&ipu->lock, flags);
10813 -EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
10816 -/* Frame Synchronization Unit Channel Linking */
10818 -struct fsu_link_reg_info {
10825 -struct fsu_link_info {
10826 - struct fsu_link_reg_info src;
10827 - struct fsu_link_reg_info sink;
10830 -static const struct fsu_link_info fsu_link_info[] = {
10832 - .src = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
10833 - FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
10834 - .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
10835 - FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
10837 - .src = { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
10838 - FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
10839 - .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
10840 - FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
10842 - .src = { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
10843 - FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
10844 - .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
10845 - FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
10847 - .src = { IPUV3_CHANNEL_CSI_DIRECT, 0 },
10848 - .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
10849 - FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
10853 -static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
10857 - for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
10858 - if (src == fsu_link_info[i].src.chno &&
10859 - sink == fsu_link_info[i].sink.chno)
10860 - return &fsu_link_info[i];
10867 - * Links a source channel to a sink channel in the FSU.
10869 -int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
10871 - const struct fsu_link_info *link;
10872 - u32 src_reg, sink_reg;
10873 - unsigned long flags;
10875 - link = find_fsu_link_info(src_ch, sink_ch);
10879 - spin_lock_irqsave(&ipu->lock, flags);
10881 - if (link->src.mask) {
10882 - src_reg = ipu_cm_read(ipu, link->src.reg);
10883 - src_reg &= ~link->src.mask;
10884 - src_reg |= link->src.val;
10885 - ipu_cm_write(ipu, src_reg, link->src.reg);
10888 - if (link->sink.mask) {
10889 - sink_reg = ipu_cm_read(ipu, link->sink.reg);
10890 - sink_reg &= ~link->sink.mask;
10891 - sink_reg |= link->sink.val;
10892 - ipu_cm_write(ipu, sink_reg, link->sink.reg);
10895 - spin_unlock_irqrestore(&ipu->lock, flags);
10898 -EXPORT_SYMBOL_GPL(ipu_fsu_link);
10901 - * Unlinks source and sink channels in the FSU.
10903 -int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
10905 - const struct fsu_link_info *link;
10906 - u32 src_reg, sink_reg;
10907 - unsigned long flags;
10909 - link = find_fsu_link_info(src_ch, sink_ch);
10913 - spin_lock_irqsave(&ipu->lock, flags);
10915 - if (link->src.mask) {
10916 - src_reg = ipu_cm_read(ipu, link->src.reg);
10917 - src_reg &= ~link->src.mask;
10918 - ipu_cm_write(ipu, src_reg, link->src.reg);
10921 - if (link->sink.mask) {
10922 - sink_reg = ipu_cm_read(ipu, link->sink.reg);
10923 - sink_reg &= ~link->sink.mask;
10924 - ipu_cm_write(ipu, sink_reg, link->sink.reg);
10927 - spin_unlock_irqrestore(&ipu->lock, flags);
10930 -EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
10932 -/* Link IDMAC channels in the FSU */
10933 -int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
10935 - return ipu_fsu_link(src->ipu, src->num, sink->num);
10937 -EXPORT_SYMBOL_GPL(ipu_idmac_link);
10939 -/* Unlink IDMAC channels in the FSU */
10940 -int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
10942 - return ipu_fsu_unlink(src->ipu, src->num, sink->num);
10944 -EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
10946 -struct ipu_devtype {
10947 - const char *name;
10948 - unsigned long cm_ofs;
10949 - unsigned long cpmem_ofs;
10950 - unsigned long srm_ofs;
10951 - unsigned long tpm_ofs;
10952 - unsigned long csi0_ofs;
10953 - unsigned long csi1_ofs;
10954 - unsigned long ic_ofs;
10955 - unsigned long disp0_ofs;
10956 - unsigned long disp1_ofs;
10957 - unsigned long dc_tmpl_ofs;
10958 - unsigned long vdi_ofs;
10959 - enum ipuv3_type type;
10962 -static struct ipu_devtype ipu_type_imx51 = {
10963 - .name = "IPUv3EX",
10964 - .cm_ofs = 0x1e000000,
10965 - .cpmem_ofs = 0x1f000000,
10966 - .srm_ofs = 0x1f040000,
10967 - .tpm_ofs = 0x1f060000,
10968 - .csi0_ofs = 0x1e030000,
10969 - .csi1_ofs = 0x1e038000,
10970 - .ic_ofs = 0x1e020000,
10971 - .disp0_ofs = 0x1e040000,
10972 - .disp1_ofs = 0x1e048000,
10973 - .dc_tmpl_ofs = 0x1f080000,
10974 - .vdi_ofs = 0x1e068000,
10978 -static struct ipu_devtype ipu_type_imx53 = {
10979 - .name = "IPUv3M",
10980 - .cm_ofs = 0x06000000,
10981 - .cpmem_ofs = 0x07000000,
10982 - .srm_ofs = 0x07040000,
10983 - .tpm_ofs = 0x07060000,
10984 - .csi0_ofs = 0x06030000,
10985 - .csi1_ofs = 0x06038000,
10986 - .ic_ofs = 0x06020000,
10987 - .disp0_ofs = 0x06040000,
10988 - .disp1_ofs = 0x06048000,
10989 - .dc_tmpl_ofs = 0x07080000,
10990 - .vdi_ofs = 0x06068000,
10994 -static struct ipu_devtype ipu_type_imx6q = {
10995 - .name = "IPUv3H",
10996 - .cm_ofs = 0x00200000,
10997 - .cpmem_ofs = 0x00300000,
10998 - .srm_ofs = 0x00340000,
10999 - .tpm_ofs = 0x00360000,
11000 - .csi0_ofs = 0x00230000,
11001 - .csi1_ofs = 0x00238000,
11002 - .ic_ofs = 0x00220000,
11003 - .disp0_ofs = 0x00240000,
11004 - .disp1_ofs = 0x00248000,
11005 - .dc_tmpl_ofs = 0x00380000,
11006 - .vdi_ofs = 0x00268000,
11010 -static const struct of_device_id imx_ipu_dt_ids[] = {
11011 - { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
11012 - { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
11013 - { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
11014 - { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
11015 - { /* sentinel */ }
11017 -MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
11019 -static int ipu_submodules_init(struct ipu_soc *ipu,
11020 - struct platform_device *pdev, unsigned long ipu_base,
11021 - struct clk *ipu_clk)
11025 - struct device *dev = &pdev->dev;
11026 - const struct ipu_devtype *devtype = ipu->devtype;
11028 - ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
11034 - ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
11035 - IPU_CONF_CSI0_EN, ipu_clk);
11041 - ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
11042 - IPU_CONF_CSI1_EN, ipu_clk);
11048 - ret = ipu_ic_init(ipu, dev,
11049 - ipu_base + devtype->ic_ofs,
11050 - ipu_base + devtype->tpm_ofs);
11056 - ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
11057 - IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
11058 - IPU_CONF_IC_INPUT);
11064 - ret = ipu_image_convert_init(ipu, dev);
11066 - unit = "image_convert";
11067 - goto err_image_convert;
11070 - ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
11071 - IPU_CONF_DI0_EN, ipu_clk);
11077 - ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
11078 - IPU_CONF_DI1_EN, ipu_clk);
11084 - ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
11085 - IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
11087 - unit = "dc_template";
11091 - ret = ipu_dmfc_init(ipu, dev, ipu_base +
11092 - devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
11098 - ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
11104 - ret = ipu_smfc_init(ipu, dev, ipu_base +
11105 - devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
11114 - ipu_dp_exit(ipu);
11116 - ipu_dmfc_exit(ipu);
11118 - ipu_dc_exit(ipu);
11120 - ipu_di_exit(ipu, 1);
11122 - ipu_di_exit(ipu, 0);
11124 - ipu_image_convert_exit(ipu);
11125 -err_image_convert:
11126 - ipu_vdi_exit(ipu);
11128 - ipu_ic_exit(ipu);
11130 - ipu_csi_exit(ipu, 1);
11132 - ipu_csi_exit(ipu, 0);
11134 - ipu_cpmem_exit(ipu);
11136 - dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
11140 -static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
11142 - unsigned long status;
11145 - for (i = 0; i < num_regs; i++) {
11147 - status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
11148 - status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
11150 - for_each_set_bit(bit, &status, 32) {
11151 - irq = irq_linear_revmap(ipu->domain,
11152 - regs[i] * 32 + bit);
11154 - generic_handle_irq(irq);
11159 -static void ipu_irq_handler(struct irq_desc *desc)
11161 - struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
11162 - struct irq_chip *chip = irq_desc_get_chip(desc);
11163 - static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
11165 - chained_irq_enter(chip, desc);
11167 - ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
11169 - chained_irq_exit(chip, desc);
11172 -static void ipu_err_irq_handler(struct irq_desc *desc)
11174 - struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
11175 - struct irq_chip *chip = irq_desc_get_chip(desc);
11176 - static const int int_reg[] = { 4, 5, 8, 9};
11178 - chained_irq_enter(chip, desc);
11180 - ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
11182 - chained_irq_exit(chip, desc);
11185 -int ipu_map_irq(struct ipu_soc *ipu, int irq)
11189 - virq = irq_linear_revmap(ipu->domain, irq);
11191 - virq = irq_create_mapping(ipu->domain, irq);
11195 -EXPORT_SYMBOL_GPL(ipu_map_irq);
11197 -int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
11198 - enum ipu_channel_irq irq_type)
11200 - return ipu_map_irq(ipu, irq_type + channel->num);
11202 -EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
11204 -static void ipu_submodules_exit(struct ipu_soc *ipu)
11206 - ipu_smfc_exit(ipu);
11207 - ipu_dp_exit(ipu);
11208 - ipu_dmfc_exit(ipu);
11209 - ipu_dc_exit(ipu);
11210 - ipu_di_exit(ipu, 1);
11211 - ipu_di_exit(ipu, 0);
11212 - ipu_image_convert_exit(ipu);
11213 - ipu_vdi_exit(ipu);
11214 - ipu_ic_exit(ipu);
11215 - ipu_csi_exit(ipu, 1);
11216 - ipu_csi_exit(ipu, 0);
11217 - ipu_cpmem_exit(ipu);
11220 -static int platform_remove_devices_fn(struct device *dev, void *unused)
11222 - struct platform_device *pdev = to_platform_device(dev);
11224 - platform_device_unregister(pdev);
11229 -static void platform_device_unregister_children(struct platform_device *pdev)
11231 - device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
11234 -struct ipu_platform_reg {
11235 - struct ipu_client_platformdata pdata;
11236 - const char *name;
11239 -/* These must be in the order of the corresponding device tree port nodes */
11240 -static struct ipu_platform_reg client_reg[] = {
11244 - .dma[0] = IPUV3_CHANNEL_CSI0,
11245 - .dma[1] = -EINVAL,
11247 - .name = "imx-ipuv3-csi",
11251 - .dma[0] = IPUV3_CHANNEL_CSI1,
11252 - .dma[1] = -EINVAL,
11254 - .name = "imx-ipuv3-csi",
11259 - .dp = IPU_DP_FLOW_SYNC_BG,
11260 - .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
11261 - .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
11263 - .name = "imx-ipuv3-crtc",
11269 - .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
11270 - .dma[1] = -EINVAL,
11272 - .name = "imx-ipuv3-crtc",
11276 -static DEFINE_MUTEX(ipu_client_id_mutex);
11277 -static int ipu_client_id;
11279 -static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
11281 - struct device *dev = ipu->dev;
11285 - mutex_lock(&ipu_client_id_mutex);
11286 - id = ipu_client_id;
11287 - ipu_client_id += ARRAY_SIZE(client_reg);
11288 - mutex_unlock(&ipu_client_id_mutex);
11290 - for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
11291 - struct ipu_platform_reg *reg = &client_reg[i];
11292 - struct platform_device *pdev;
11293 - struct device_node *of_node;
11295 - /* Associate subdevice with the corresponding port node */
11296 - of_node = of_graph_get_port_by_id(dev->of_node, i);
11299 - "no port@%d node in %pOF, not using %s%d\n",
11301 - (i / 2) ? "DI" : "CSI", i % 2);
11305 - pdev = platform_device_alloc(reg->name, id++);
11308 - goto err_register;
11311 - pdev->dev.parent = dev;
11313 - reg->pdata.of_node = of_node;
11314 - ret = platform_device_add_data(pdev, ®->pdata,
11315 - sizeof(reg->pdata));
11317 - ret = platform_device_add(pdev);
11319 - platform_device_put(pdev);
11320 - goto err_register;
11327 - platform_device_unregister_children(to_platform_device(dev));
11333 -static int ipu_irq_init(struct ipu_soc *ipu)
11335 - struct irq_chip_generic *gc;
11336 - struct irq_chip_type *ct;
11337 - unsigned long unused[IPU_NUM_IRQS / 32] = {
11338 - 0x400100d0, 0xffe000fd,
11339 - 0x400100d0, 0xffe000fd,
11340 - 0x400100d0, 0xffe000fd,
11341 - 0x4077ffff, 0xffe7e1fd,
11342 - 0x23fffffe, 0x8880fff0,
11343 - 0xf98fe7d0, 0xfff81fff,
11344 - 0x400100d0, 0xffe000fd,
11349 - ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
11350 - &irq_generic_chip_ops, ipu);
11351 - if (!ipu->domain) {
11352 - dev_err(ipu->dev, "failed to add irq domain\n");
11356 - ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
11357 - handle_level_irq, 0, 0, 0);
11359 - dev_err(ipu->dev, "failed to alloc generic irq chips\n");
11360 - irq_domain_remove(ipu->domain);
11364 - /* Mask and clear all interrupts */
11365 - for (i = 0; i < IPU_NUM_IRQS; i += 32) {
11366 - ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
11367 - ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
11370 - for (i = 0; i < IPU_NUM_IRQS; i += 32) {
11371 - gc = irq_get_domain_generic_chip(ipu->domain, i);
11372 - gc->reg_base = ipu->cm_reg;
11373 - gc->unused = unused[i / 32];
11374 - ct = gc->chip_types;
11375 - ct->chip.irq_ack = irq_gc_ack_set_bit;
11376 - ct->chip.irq_mask = irq_gc_mask_clr_bit;
11377 - ct->chip.irq_unmask = irq_gc_mask_set_bit;
11378 - ct->regs.ack = IPU_INT_STAT(i / 32);
11379 - ct->regs.mask = IPU_INT_CTRL(i / 32);
11382 - irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
11383 - irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
11389 -static void ipu_irq_exit(struct ipu_soc *ipu)
11393 - irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
11394 - irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
11396 - /* TODO: remove irq_domain_generic_chips */
11398 - for (i = 0; i < IPU_NUM_IRQS; i++) {
11399 - irq = irq_linear_revmap(ipu->domain, i);
11401 - irq_dispose_mapping(irq);
11404 - irq_domain_remove(ipu->domain);
11407 -void ipu_dump(struct ipu_soc *ipu)
11411 - dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
11412 - ipu_cm_read(ipu, IPU_CONF));
11413 - dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
11414 - ipu_idmac_read(ipu, IDMAC_CONF));
11415 - dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
11416 - ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
11417 - dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
11418 - ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
11419 - dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
11420 - ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
11421 - dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
11422 - ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
11423 - dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
11424 - ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
11425 - dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
11426 - ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
11427 - dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
11428 - ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
11429 - dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
11430 - ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
11431 - dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
11432 - ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
11433 - dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
11434 - ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
11435 - dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
11436 - ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
11437 - dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
11438 - ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
11439 - for (i = 0; i < 15; i++)
11440 - dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
11441 - ipu_cm_read(ipu, IPU_INT_CTRL(i)));
11443 -EXPORT_SYMBOL_GPL(ipu_dump);
11445 -static int ipu_probe(struct platform_device *pdev)
11447 - struct device_node *np = pdev->dev.of_node;
11448 - struct ipu_soc *ipu;
11449 - struct resource *res;
11450 - unsigned long ipu_base;
11451 - int ret, irq_sync, irq_err;
11452 - const struct ipu_devtype *devtype;
11454 - devtype = of_device_get_match_data(&pdev->dev);
11458 - irq_sync = platform_get_irq(pdev, 0);
11459 - irq_err = platform_get_irq(pdev, 1);
11460 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
11462 - dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
11463 - irq_sync, irq_err);
11465 - if (!res || irq_sync < 0 || irq_err < 0)
11468 - ipu_base = res->start;
11470 - ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
11474 - ipu->id = of_alias_get_id(np, "ipu");
11478 - if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
11479 - IS_ENABLED(CONFIG_DRM)) {
11480 - ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
11481 - "fsl,prg", ipu->id);
11482 - if (!ipu->prg_priv)
11483 - return -EPROBE_DEFER;
11486 - ipu->devtype = devtype;
11487 - ipu->ipu_type = devtype->type;
11489 - spin_lock_init(&ipu->lock);
11490 - mutex_init(&ipu->channel_lock);
11491 - INIT_LIST_HEAD(&ipu->channels);
11493 - dev_dbg(&pdev->dev, "cm_reg: 0x%08lx\n",
11494 - ipu_base + devtype->cm_ofs);
11495 - dev_dbg(&pdev->dev, "idmac: 0x%08lx\n",
11496 - ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
11497 - dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n",
11498 - ipu_base + devtype->cpmem_ofs);
11499 - dev_dbg(&pdev->dev, "csi0: 0x%08lx\n",
11500 - ipu_base + devtype->csi0_ofs);
11501 - dev_dbg(&pdev->dev, "csi1: 0x%08lx\n",
11502 - ipu_base + devtype->csi1_ofs);
11503 - dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
11504 - ipu_base + devtype->ic_ofs);
11505 - dev_dbg(&pdev->dev, "disp0: 0x%08lx\n",
11506 - ipu_base + devtype->disp0_ofs);
11507 - dev_dbg(&pdev->dev, "disp1: 0x%08lx\n",
11508 - ipu_base + devtype->disp1_ofs);
11509 - dev_dbg(&pdev->dev, "srm: 0x%08lx\n",
11510 - ipu_base + devtype->srm_ofs);
11511 - dev_dbg(&pdev->dev, "tpm: 0x%08lx\n",
11512 - ipu_base + devtype->tpm_ofs);
11513 - dev_dbg(&pdev->dev, "dc: 0x%08lx\n",
11514 - ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
11515 - dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
11516 - ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
11517 - dev_dbg(&pdev->dev, "dmfc: 0x%08lx\n",
11518 - ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
11519 - dev_dbg(&pdev->dev, "vdi: 0x%08lx\n",
11520 - ipu_base + devtype->vdi_ofs);
11522 - ipu->cm_reg = devm_ioremap(&pdev->dev,
11523 - ipu_base + devtype->cm_ofs, PAGE_SIZE);
11524 - ipu->idmac_reg = devm_ioremap(&pdev->dev,
11525 - ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
11528 - if (!ipu->cm_reg || !ipu->idmac_reg)
11531 - ipu->clk = devm_clk_get(&pdev->dev, "bus");
11532 - if (IS_ERR(ipu->clk)) {
11533 - ret = PTR_ERR(ipu->clk);
11534 - dev_err(&pdev->dev, "clk_get failed with %d", ret);
11538 - platform_set_drvdata(pdev, ipu);
11540 - ret = clk_prepare_enable(ipu->clk);
11542 - dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
11546 - ipu->dev = &pdev->dev;
11547 - ipu->irq_sync = irq_sync;
11548 - ipu->irq_err = irq_err;
11550 - ret = device_reset(&pdev->dev);
11552 - dev_err(&pdev->dev, "failed to reset: %d\n", ret);
11553 - goto out_failed_reset;
11555 - ret = ipu_memory_reset(ipu);
11557 - goto out_failed_reset;
11559 - ret = ipu_irq_init(ipu);
11561 - goto out_failed_irq;
11563 - /* Set MCU_T to divide MCU access window into 2 */
11564 - ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
11567 - ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
11569 - goto failed_submodules_init;
11571 - ret = ipu_add_client_devices(ipu, ipu_base);
11573 - dev_err(&pdev->dev, "adding client devices failed with %d\n",
11575 - goto failed_add_clients;
11578 - dev_info(&pdev->dev, "%s probed\n", devtype->name);
11582 -failed_add_clients:
11583 - ipu_submodules_exit(ipu);
11584 -failed_submodules_init:
11585 - ipu_irq_exit(ipu);
11588 - clk_disable_unprepare(ipu->clk);
11592 -static int ipu_remove(struct platform_device *pdev)
11594 - struct ipu_soc *ipu = platform_get_drvdata(pdev);
11596 - platform_device_unregister_children(pdev);
11597 - ipu_submodules_exit(ipu);
11598 - ipu_irq_exit(ipu);
11600 - clk_disable_unprepare(ipu->clk);
11605 -static struct platform_driver imx_ipu_driver = {
11607 - .name = "imx-ipuv3",
11608 - .of_match_table = imx_ipu_dt_ids,
11610 - .probe = ipu_probe,
11611 - .remove = ipu_remove,
11614 -static struct platform_driver * const drivers[] = {
11615 -#if IS_ENABLED(CONFIG_DRM)
11622 -static int __init imx_ipu_init(void)
11624 - return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
11626 -module_init(imx_ipu_init);
11628 -static void __exit imx_ipu_exit(void)
11630 - platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
11632 -module_exit(imx_ipu_exit);
11634 -MODULE_ALIAS("platform:imx-ipuv3");
11635 -MODULE_DESCRIPTION("i.MX IPU v3 driver");
11636 -MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
11637 -MODULE_LICENSE("GPL");
11638 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c
11641 -// SPDX-License-Identifier: GPL-2.0-or-later
11643 - * Copyright (C) 2012 Mentor Graphics Inc.
11644 - * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
11646 -#include <linux/types.h>
11647 -#include <linux/bitrev.h>
11648 -#include <linux/io.h>
11649 -#include <linux/sizes.h>
11650 -#include <drm/drm_fourcc.h>
11651 -#include "ipu-prv.h"
11653 -struct ipu_cpmem_word {
11658 -struct ipu_ch_param {
11659 - struct ipu_cpmem_word word[2];
11662 -struct ipu_cpmem {
11663 - struct ipu_ch_param __iomem *base;
11667 - struct ipu_soc *ipu;
11670 -#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
11672 -#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
11673 -#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
11674 -#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
11675 -#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
11676 -#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
11677 -#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
11678 -#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
11680 -#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
11681 -#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
11682 -#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
11683 -#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
11684 -#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
11685 -#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
11686 -#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
11687 -#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
11688 -#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
11689 -#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
11690 -#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
11691 -#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
11692 -#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
11693 -#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
11694 -#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
11695 -#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
11696 -#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
11697 -#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
11698 -#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
11699 -#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
11700 -#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
11701 -#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
11702 -#define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3)
11703 -#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
11704 -#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
11705 -#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
11706 -#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
11707 -#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
11708 -#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
11709 -#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
11710 -#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
11711 -#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
11712 -#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
11713 -#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
11714 -#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
11715 -#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
11716 -#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
11717 -#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
11718 -#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
11719 -#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
11720 -#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
11721 -#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
11722 -#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
11723 -#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
11724 -#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
11725 -#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
11726 -#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
11727 -#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
11728 -#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
11729 -#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
11730 -#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
11732 -static inline struct ipu_ch_param __iomem *
11733 -ipu_get_cpmem(struct ipuv3_channel *ch)
11735 - struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
11737 - return cpmem->base + ch->num;
11740 -static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
11742 - struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
11743 - u32 bit = (wbs >> 8) % 160;
11744 - u32 size = wbs & 0xff;
11745 - u32 word = (wbs >> 8) / 160;
11746 - u32 i = bit / 32;
11747 - u32 ofs = bit % 32;
11748 - u32 mask = (1 << size) - 1;
11751 - pr_debug("%s %d %d %d\n", __func__, word, bit , size);
11753 - val = readl(&base->word[word].data[i]);
11754 - val &= ~(mask << ofs);
11756 - writel(val, &base->word[word].data[i]);
11758 - if ((bit + size - 1) / 32 > i) {
11759 - val = readl(&base->word[word].data[i + 1]);
11760 - val &= ~(mask >> (ofs ? (32 - ofs) : 0));
11761 - val |= v >> (ofs ? (32 - ofs) : 0);
11762 - writel(val, &base->word[word].data[i + 1]);
11766 -static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
11768 - struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
11769 - u32 bit = (wbs >> 8) % 160;
11770 - u32 size = wbs & 0xff;
11771 - u32 word = (wbs >> 8) / 160;
11772 - u32 i = bit / 32;
11773 - u32 ofs = bit % 32;
11774 - u32 mask = (1 << size) - 1;
11777 - pr_debug("%s %d %d %d\n", __func__, word, bit , size);
11779 - val = (readl(&base->word[word].data[i]) >> ofs) & mask;
11781 - if ((bit + size - 1) / 32 > i) {
11784 - tmp = readl(&base->word[word].data[i + 1]);
11785 - tmp &= mask >> (ofs ? (32 - ofs) : 0);
11786 - val |= tmp << (ofs ? (32 - ofs) : 0);
11793 - * The V4L2 spec defines packed RGB formats in memory byte order, which from
11794 - * point of view of the IPU corresponds to little-endian words with the first
11795 - * component in the least significant bits.
11796 - * The DRM pixel formats and IPU internal representation are ordered the other
11797 - * way around, with the first named component ordered at the most significant
11798 - * bits. Further, V4L2 formats are not well defined:
11799 - * https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
11800 - * We choose the interpretation which matches GStreamer behavior.
11802 -static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
11804 - switch (pixelformat) {
11805 - case V4L2_PIX_FMT_RGB565:
11807 - * Here we choose the 'corrected' interpretation of RGBP, a
11808 - * little-endian 16-bit word with the red component at the most
11809 - * significant bits:
11810 - * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
11812 - return DRM_FORMAT_RGB565;
11813 - case V4L2_PIX_FMT_BGR24:
11814 - /* B G R <=> [24:0] R:G:B */
11815 - return DRM_FORMAT_RGB888;
11816 - case V4L2_PIX_FMT_RGB24:
11817 - /* R G B <=> [24:0] B:G:R */
11818 - return DRM_FORMAT_BGR888;
11819 - case V4L2_PIX_FMT_BGR32:
11820 - /* B G R A <=> [32:0] A:B:G:R */
11821 - return DRM_FORMAT_XRGB8888;
11822 - case V4L2_PIX_FMT_RGB32:
11823 - /* R G B A <=> [32:0] A:B:G:R */
11824 - return DRM_FORMAT_XBGR8888;
11825 - case V4L2_PIX_FMT_ABGR32:
11826 - /* B G R A <=> [32:0] A:R:G:B */
11827 - return DRM_FORMAT_ARGB8888;
11828 - case V4L2_PIX_FMT_XBGR32:
11829 - /* B G R X <=> [32:0] X:R:G:B */
11830 - return DRM_FORMAT_XRGB8888;
11831 - case V4L2_PIX_FMT_BGRA32:
11832 - /* A B G R <=> [32:0] R:G:B:A */
11833 - return DRM_FORMAT_RGBA8888;
11834 - case V4L2_PIX_FMT_BGRX32:
11835 - /* X B G R <=> [32:0] R:G:B:X */
11836 - return DRM_FORMAT_RGBX8888;
11837 - case V4L2_PIX_FMT_RGBA32:
11838 - /* R G B A <=> [32:0] A:B:G:R */
11839 - return DRM_FORMAT_ABGR8888;
11840 - case V4L2_PIX_FMT_RGBX32:
11841 - /* R G B X <=> [32:0] X:B:G:R */
11842 - return DRM_FORMAT_XBGR8888;
11843 - case V4L2_PIX_FMT_ARGB32:
11844 - /* A R G B <=> [32:0] B:G:R:A */
11845 - return DRM_FORMAT_BGRA8888;
11846 - case V4L2_PIX_FMT_XRGB32:
11847 - /* X R G B <=> [32:0] B:G:R:X */
11848 - return DRM_FORMAT_BGRX8888;
11849 - case V4L2_PIX_FMT_UYVY:
11850 - return DRM_FORMAT_UYVY;
11851 - case V4L2_PIX_FMT_YUYV:
11852 - return DRM_FORMAT_YUYV;
11853 - case V4L2_PIX_FMT_YUV420:
11854 - return DRM_FORMAT_YUV420;
11855 - case V4L2_PIX_FMT_YUV422P:
11856 - return DRM_FORMAT_YUV422;
11857 - case V4L2_PIX_FMT_YVU420:
11858 - return DRM_FORMAT_YVU420;
11859 - case V4L2_PIX_FMT_NV12:
11860 - return DRM_FORMAT_NV12;
11861 - case V4L2_PIX_FMT_NV16:
11862 - return DRM_FORMAT_NV16;
11868 -void ipu_cpmem_zero(struct ipuv3_channel *ch)
11870 - struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
11871 - void __iomem *base = p;
11874 - for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
11875 - writel(0, base + i * sizeof(u32));
11877 -EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
11879 -void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
11881 - ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
11882 - ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
11884 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
11886 -void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
11888 - ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
11890 -EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
11892 -void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
11894 - ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
11896 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
11898 -void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
11900 - struct ipu_soc *ipu = ch->ipu;
11903 - if (ipu->ipu_type == IPUV3EX)
11904 - ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
11906 - val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
11907 - val |= 1 << (ch->num % 32);
11908 - ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
11910 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
11912 -void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
11914 - WARN_ON_ONCE(buf & 0x7);
11917 - ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
11919 - ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
11921 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
11923 -void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
11925 - WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
11927 - ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
11928 - ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
11930 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
11932 -void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
11935 - u32 ilo, sly, sluv;
11937 - if (stride < 0) {
11938 - stride = -stride;
11939 - ilo = 0x100000 - (stride / 8);
11941 - ilo = stride / 8;
11944 - sly = (stride * 2) - 1;
11946 - switch (pixelformat) {
11947 - case V4L2_PIX_FMT_YUV420:
11948 - case V4L2_PIX_FMT_YVU420:
11949 - sluv = stride / 2 - 1;
11951 - case V4L2_PIX_FMT_NV12:
11952 - sluv = stride - 1;
11954 - case V4L2_PIX_FMT_YUV422P:
11955 - sluv = stride - 1;
11957 - case V4L2_PIX_FMT_NV16:
11958 - sluv = stride * 2 - 1;
11965 - ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
11966 - ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
11967 - ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
11969 - ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
11971 -EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
11973 -void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
11976 - ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
11978 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
11980 -int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
11982 - return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
11984 -EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
11986 -void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
11988 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
11990 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
11992 -void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
11994 - ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
11996 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
11998 -void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
11999 - enum ipu_rotate_mode rot)
12001 - u32 temp_rot = bitrev8(rot) >> 5;
12003 - ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
12005 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
12007 -int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
12008 - const struct ipu_rgb *rgb)
12010 - int bpp = 0, npb = 0, ro, go, bo, to;
12012 - ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
12013 - go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
12014 - bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
12015 - to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
12017 - ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
12018 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
12019 - ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
12020 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
12021 - ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
12022 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
12024 - if (rgb->transp.length) {
12025 - ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
12026 - rgb->transp.length - 1);
12027 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
12029 - ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
12030 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
12031 - rgb->bits_per_pixel);
12034 - switch (rgb->bits_per_pixel) {
12054 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
12055 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
12056 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
12060 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
12062 -int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
12064 - int bpp = 0, npb = 0;
12087 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
12088 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
12089 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
12093 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
12095 -void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
12097 - switch (pixel_format) {
12098 - case V4L2_PIX_FMT_UYVY:
12099 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
12100 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
12101 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
12103 - case V4L2_PIX_FMT_YUYV:
12104 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
12105 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
12106 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
12110 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
12112 -void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
12113 - unsigned int uv_stride,
12114 - unsigned int u_offset, unsigned int v_offset)
12116 - WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
12118 - ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
12119 - ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
12120 - ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
12122 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
12124 -static const struct ipu_rgb def_xrgb_32 = {
12125 - .red = { .offset = 16, .length = 8, },
12126 - .green = { .offset = 8, .length = 8, },
12127 - .blue = { .offset = 0, .length = 8, },
12128 - .transp = { .offset = 24, .length = 8, },
12129 - .bits_per_pixel = 32,
12132 -static const struct ipu_rgb def_xbgr_32 = {
12133 - .red = { .offset = 0, .length = 8, },
12134 - .green = { .offset = 8, .length = 8, },
12135 - .blue = { .offset = 16, .length = 8, },
12136 - .transp = { .offset = 24, .length = 8, },
12137 - .bits_per_pixel = 32,
12140 -static const struct ipu_rgb def_rgbx_32 = {
12141 - .red = { .offset = 24, .length = 8, },
12142 - .green = { .offset = 16, .length = 8, },
12143 - .blue = { .offset = 8, .length = 8, },
12144 - .transp = { .offset = 0, .length = 8, },
12145 - .bits_per_pixel = 32,
12148 -static const struct ipu_rgb def_bgrx_32 = {
12149 - .red = { .offset = 8, .length = 8, },
12150 - .green = { .offset = 16, .length = 8, },
12151 - .blue = { .offset = 24, .length = 8, },
12152 - .transp = { .offset = 0, .length = 8, },
12153 - .bits_per_pixel = 32,
12156 -static const struct ipu_rgb def_rgb_24 = {
12157 - .red = { .offset = 16, .length = 8, },
12158 - .green = { .offset = 8, .length = 8, },
12159 - .blue = { .offset = 0, .length = 8, },
12160 - .transp = { .offset = 0, .length = 0, },
12161 - .bits_per_pixel = 24,
12164 -static const struct ipu_rgb def_bgr_24 = {
12165 - .red = { .offset = 0, .length = 8, },
12166 - .green = { .offset = 8, .length = 8, },
12167 - .blue = { .offset = 16, .length = 8, },
12168 - .transp = { .offset = 0, .length = 0, },
12169 - .bits_per_pixel = 24,
12172 -static const struct ipu_rgb def_rgb_16 = {
12173 - .red = { .offset = 11, .length = 5, },
12174 - .green = { .offset = 5, .length = 6, },
12175 - .blue = { .offset = 0, .length = 5, },
12176 - .transp = { .offset = 0, .length = 0, },
12177 - .bits_per_pixel = 16,
12180 -static const struct ipu_rgb def_bgr_16 = {
12181 - .red = { .offset = 0, .length = 5, },
12182 - .green = { .offset = 5, .length = 6, },
12183 - .blue = { .offset = 11, .length = 5, },
12184 - .transp = { .offset = 0, .length = 0, },
12185 - .bits_per_pixel = 16,
12188 -static const struct ipu_rgb def_argb_16 = {
12189 - .red = { .offset = 10, .length = 5, },
12190 - .green = { .offset = 5, .length = 5, },
12191 - .blue = { .offset = 0, .length = 5, },
12192 - .transp = { .offset = 15, .length = 1, },
12193 - .bits_per_pixel = 16,
12196 -static const struct ipu_rgb def_argb_16_4444 = {
12197 - .red = { .offset = 8, .length = 4, },
12198 - .green = { .offset = 4, .length = 4, },
12199 - .blue = { .offset = 0, .length = 4, },
12200 - .transp = { .offset = 12, .length = 4, },
12201 - .bits_per_pixel = 16,
12204 -static const struct ipu_rgb def_abgr_16 = {
12205 - .red = { .offset = 0, .length = 5, },
12206 - .green = { .offset = 5, .length = 5, },
12207 - .blue = { .offset = 10, .length = 5, },
12208 - .transp = { .offset = 15, .length = 1, },
12209 - .bits_per_pixel = 16,
12212 -static const struct ipu_rgb def_rgba_16 = {
12213 - .red = { .offset = 11, .length = 5, },
12214 - .green = { .offset = 6, .length = 5, },
12215 - .blue = { .offset = 1, .length = 5, },
12216 - .transp = { .offset = 0, .length = 1, },
12217 - .bits_per_pixel = 16,
12220 -static const struct ipu_rgb def_bgra_16 = {
12221 - .red = { .offset = 1, .length = 5, },
12222 - .green = { .offset = 6, .length = 5, },
12223 - .blue = { .offset = 11, .length = 5, },
12224 - .transp = { .offset = 0, .length = 1, },
12225 - .bits_per_pixel = 16,
12228 -#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
12229 -#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12230 - (pix->width * ((y) / 2) / 2) + (x) / 2)
12231 -#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12232 - (pix->width * pix->height / 4) + \
12233 - (pix->width * ((y) / 2) / 2) + (x) / 2)
12234 -#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12235 - (pix->width * (y) / 2) + (x) / 2)
12236 -#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12237 - (pix->width * pix->height / 2) + \
12238 - (pix->width * (y) / 2) + (x) / 2)
12239 -#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12240 - (pix->width * ((y) / 2)) + (x))
12241 -#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12242 - (pix->width * y) + (x))
12244 -#define NUM_ALPHA_CHANNELS 7
12246 -/* See Table 37-12. Alpha channels mapping. */
12247 -static int ipu_channel_albm(int ch_num)
12249 - switch (ch_num) {
12250 - case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: return 0;
12251 - case IPUV3_CHANNEL_G_MEM_IC_PP: return 1;
12252 - case IPUV3_CHANNEL_MEM_FG_SYNC: return 2;
12253 - case IPUV3_CHANNEL_MEM_FG_ASYNC: return 3;
12254 - case IPUV3_CHANNEL_MEM_BG_SYNC: return 4;
12255 - case IPUV3_CHANNEL_MEM_BG_ASYNC: return 5;
12256 - case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
12262 -static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
12264 - struct ipu_soc *ipu = ch->ipu;
12268 - albm = ipu_channel_albm(ch->num);
12272 - ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
12273 - ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
12274 - ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
12276 - val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
12277 - val |= BIT(ch->num);
12278 - ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
12281 -int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
12283 - switch (drm_fourcc) {
12284 - case DRM_FORMAT_YUV420:
12285 - case DRM_FORMAT_YVU420:
12287 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
12289 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12291 - case DRM_FORMAT_YUV422:
12292 - case DRM_FORMAT_YVU422:
12294 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
12296 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12298 - case DRM_FORMAT_YUV444:
12299 - case DRM_FORMAT_YVU444:
12301 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
12303 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12305 - case DRM_FORMAT_NV12:
12307 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
12309 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12311 - case DRM_FORMAT_NV16:
12313 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
12315 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12317 - case DRM_FORMAT_UYVY:
12319 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
12321 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
12323 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12325 - case DRM_FORMAT_YUYV:
12327 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
12329 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
12331 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12333 - case DRM_FORMAT_ABGR8888:
12334 - case DRM_FORMAT_XBGR8888:
12335 - ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
12337 - case DRM_FORMAT_ARGB8888:
12338 - case DRM_FORMAT_XRGB8888:
12339 - ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
12341 - case DRM_FORMAT_RGBA8888:
12342 - case DRM_FORMAT_RGBX8888:
12343 - case DRM_FORMAT_RGBX8888_A8:
12344 - ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
12346 - case DRM_FORMAT_BGRA8888:
12347 - case DRM_FORMAT_BGRX8888:
12348 - case DRM_FORMAT_BGRX8888_A8:
12349 - ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
12351 - case DRM_FORMAT_BGR888:
12352 - case DRM_FORMAT_BGR888_A8:
12353 - ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
12355 - case DRM_FORMAT_RGB888:
12356 - case DRM_FORMAT_RGB888_A8:
12357 - ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
12359 - case DRM_FORMAT_RGB565:
12360 - case DRM_FORMAT_RGB565_A8:
12361 - ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
12363 - case DRM_FORMAT_BGR565:
12364 - case DRM_FORMAT_BGR565_A8:
12365 - ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
12367 - case DRM_FORMAT_ARGB1555:
12368 - ipu_cpmem_set_format_rgb(ch, &def_argb_16);
12370 - case DRM_FORMAT_ABGR1555:
12371 - ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
12373 - case DRM_FORMAT_RGBA5551:
12374 - ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
12376 - case DRM_FORMAT_BGRA5551:
12377 - ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
12379 - case DRM_FORMAT_ARGB4444:
12380 - ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
12386 - switch (drm_fourcc) {
12387 - case DRM_FORMAT_RGB565_A8:
12388 - case DRM_FORMAT_BGR565_A8:
12389 - case DRM_FORMAT_RGB888_A8:
12390 - case DRM_FORMAT_BGR888_A8:
12391 - case DRM_FORMAT_RGBX8888_A8:
12392 - case DRM_FORMAT_BGRX8888_A8:
12393 - ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
12394 - ipu_cpmem_set_separate_alpha(ch);
12402 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
12404 -int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
12406 - struct v4l2_pix_format *pix = &image->pix;
12407 - int offset, u_offset, v_offset;
12410 - pr_debug("%s: resolution: %dx%d stride: %d\n",
12411 - __func__, pix->width, pix->height,
12412 - pix->bytesperline);
12414 - ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
12415 - ipu_cpmem_set_stride(ch, pix->bytesperline);
12417 - ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
12419 - switch (pix->pixelformat) {
12420 - case V4L2_PIX_FMT_YUV420:
12421 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12422 - u_offset = image->u_offset ?
12423 - image->u_offset : U_OFFSET(pix, image->rect.left,
12424 - image->rect.top) - offset;
12425 - v_offset = image->v_offset ?
12426 - image->v_offset : V_OFFSET(pix, image->rect.left,
12427 - image->rect.top) - offset;
12429 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
12430 - u_offset, v_offset);
12432 - case V4L2_PIX_FMT_YVU420:
12433 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12434 - u_offset = image->u_offset ?
12435 - image->u_offset : V_OFFSET(pix, image->rect.left,
12436 - image->rect.top) - offset;
12437 - v_offset = image->v_offset ?
12438 - image->v_offset : U_OFFSET(pix, image->rect.left,
12439 - image->rect.top) - offset;
12441 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
12442 - u_offset, v_offset);
12444 - case V4L2_PIX_FMT_YUV422P:
12445 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12446 - u_offset = image->u_offset ?
12447 - image->u_offset : U2_OFFSET(pix, image->rect.left,
12448 - image->rect.top) - offset;
12449 - v_offset = image->v_offset ?
12450 - image->v_offset : V2_OFFSET(pix, image->rect.left,
12451 - image->rect.top) - offset;
12453 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
12454 - u_offset, v_offset);
12456 - case V4L2_PIX_FMT_NV12:
12457 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12458 - u_offset = image->u_offset ?
12459 - image->u_offset : UV_OFFSET(pix, image->rect.left,
12460 - image->rect.top) - offset;
12461 - v_offset = image->v_offset ? image->v_offset : 0;
12463 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
12464 - u_offset, v_offset);
12466 - case V4L2_PIX_FMT_NV16:
12467 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12468 - u_offset = image->u_offset ?
12469 - image->u_offset : UV2_OFFSET(pix, image->rect.left,
12470 - image->rect.top) - offset;
12471 - v_offset = image->v_offset ? image->v_offset : 0;
12473 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
12474 - u_offset, v_offset);
12476 - case V4L2_PIX_FMT_UYVY:
12477 - case V4L2_PIX_FMT_YUYV:
12478 - case V4L2_PIX_FMT_RGB565:
12479 - offset = image->rect.left * 2 +
12480 - image->rect.top * pix->bytesperline;
12482 - case V4L2_PIX_FMT_RGB32:
12483 - case V4L2_PIX_FMT_BGR32:
12484 - case V4L2_PIX_FMT_ABGR32:
12485 - case V4L2_PIX_FMT_XBGR32:
12486 - case V4L2_PIX_FMT_BGRA32:
12487 - case V4L2_PIX_FMT_BGRX32:
12488 - case V4L2_PIX_FMT_RGBA32:
12489 - case V4L2_PIX_FMT_RGBX32:
12490 - case V4L2_PIX_FMT_ARGB32:
12491 - case V4L2_PIX_FMT_XRGB32:
12492 - offset = image->rect.left * 4 +
12493 - image->rect.top * pix->bytesperline;
12495 - case V4L2_PIX_FMT_RGB24:
12496 - case V4L2_PIX_FMT_BGR24:
12497 - offset = image->rect.left * 3 +
12498 - image->rect.top * pix->bytesperline;
12500 - case V4L2_PIX_FMT_SBGGR8:
12501 - case V4L2_PIX_FMT_SGBRG8:
12502 - case V4L2_PIX_FMT_SGRBG8:
12503 - case V4L2_PIX_FMT_SRGGB8:
12504 - case V4L2_PIX_FMT_GREY:
12505 - offset = image->rect.left + image->rect.top * pix->bytesperline;
12507 - case V4L2_PIX_FMT_SBGGR16:
12508 - case V4L2_PIX_FMT_SGBRG16:
12509 - case V4L2_PIX_FMT_SGRBG16:
12510 - case V4L2_PIX_FMT_SRGGB16:
12511 - case V4L2_PIX_FMT_Y16:
12512 - offset = image->rect.left * 2 +
12513 - image->rect.top * pix->bytesperline;
12516 - /* This should not happen */
12522 - ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
12523 - ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
12527 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
12529 -void ipu_cpmem_dump(struct ipuv3_channel *ch)
12531 - struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
12532 - struct ipu_soc *ipu = ch->ipu;
12533 - int chno = ch->num;
12535 - dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
12536 - readl(&p->word[0].data[0]),
12537 - readl(&p->word[0].data[1]),
12538 - readl(&p->word[0].data[2]),
12539 - readl(&p->word[0].data[3]),
12540 - readl(&p->word[0].data[4]));
12541 - dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
12542 - readl(&p->word[1].data[0]),
12543 - readl(&p->word[1].data[1]),
12544 - readl(&p->word[1].data[2]),
12545 - readl(&p->word[1].data[3]),
12546 - readl(&p->word[1].data[4]));
12547 - dev_dbg(ipu->dev, "PFS 0x%x, ",
12548 - ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
12549 - dev_dbg(ipu->dev, "BPP 0x%x, ",
12550 - ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
12551 - dev_dbg(ipu->dev, "NPB 0x%x\n",
12552 - ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
12554 - dev_dbg(ipu->dev, "FW %d, ",
12555 - ipu_ch_param_read_field(ch, IPU_FIELD_FW));
12556 - dev_dbg(ipu->dev, "FH %d, ",
12557 - ipu_ch_param_read_field(ch, IPU_FIELD_FH));
12558 - dev_dbg(ipu->dev, "EBA0 0x%x\n",
12559 - ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
12560 - dev_dbg(ipu->dev, "EBA1 0x%x\n",
12561 - ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
12562 - dev_dbg(ipu->dev, "Stride %d\n",
12563 - ipu_ch_param_read_field(ch, IPU_FIELD_SL));
12564 - dev_dbg(ipu->dev, "scan_order %d\n",
12565 - ipu_ch_param_read_field(ch, IPU_FIELD_SO));
12566 - dev_dbg(ipu->dev, "uv_stride %d\n",
12567 - ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
12568 - dev_dbg(ipu->dev, "u_offset 0x%x\n",
12569 - ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
12570 - dev_dbg(ipu->dev, "v_offset 0x%x\n",
12571 - ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
12573 - dev_dbg(ipu->dev, "Width0 %d+1, ",
12574 - ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
12575 - dev_dbg(ipu->dev, "Width1 %d+1, ",
12576 - ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
12577 - dev_dbg(ipu->dev, "Width2 %d+1, ",
12578 - ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
12579 - dev_dbg(ipu->dev, "Width3 %d+1, ",
12580 - ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
12581 - dev_dbg(ipu->dev, "Offset0 %d, ",
12582 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
12583 - dev_dbg(ipu->dev, "Offset1 %d, ",
12584 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
12585 - dev_dbg(ipu->dev, "Offset2 %d, ",
12586 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
12587 - dev_dbg(ipu->dev, "Offset3 %d\n",
12588 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
12590 -EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
12592 -int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
12594 - struct ipu_cpmem *cpmem;
12596 - cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
12600 - ipu->cpmem_priv = cpmem;
12602 - spin_lock_init(&cpmem->lock);
12603 - cpmem->base = devm_ioremap(dev, base, SZ_128K);
12604 - if (!cpmem->base)
12607 - dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
12608 - base, cpmem->base);
12609 - cpmem->ipu = ipu;
12614 -void ipu_cpmem_exit(struct ipu_soc *ipu)
12617 --- a/drivers/gpu/ipu-v3/ipu-csi.c
12620 -// SPDX-License-Identifier: GPL-2.0-or-later
12622 - * Copyright (C) 2012-2014 Mentor Graphics Inc.
12623 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
12625 -#include <linux/export.h>
12626 -#include <linux/module.h>
12627 -#include <linux/types.h>
12628 -#include <linux/errno.h>
12629 -#include <linux/delay.h>
12630 -#include <linux/io.h>
12631 -#include <linux/err.h>
12632 -#include <linux/platform_device.h>
12633 -#include <linux/videodev2.h>
12634 -#include <uapi/linux/v4l2-mediabus.h>
12635 -#include <linux/clk.h>
12636 -#include <linux/clk-provider.h>
12637 -#include <linux/clkdev.h>
12639 -#include "ipu-prv.h"
12642 - void __iomem *base;
12645 - struct clk *clk_ipu; /* IPU bus clock */
12648 - struct ipu_soc *ipu;
12651 -/* CSI Register Offsets */
12652 -#define CSI_SENS_CONF 0x0000
12653 -#define CSI_SENS_FRM_SIZE 0x0004
12654 -#define CSI_ACT_FRM_SIZE 0x0008
12655 -#define CSI_OUT_FRM_CTRL 0x000c
12656 -#define CSI_TST_CTRL 0x0010
12657 -#define CSI_CCIR_CODE_1 0x0014
12658 -#define CSI_CCIR_CODE_2 0x0018
12659 -#define CSI_CCIR_CODE_3 0x001c
12660 -#define CSI_MIPI_DI 0x0020
12661 -#define CSI_SKIP 0x0024
12662 -#define CSI_CPD_CTRL 0x0028
12663 -#define CSI_CPD_RC(n) (0x002c + ((n)*4))
12664 -#define CSI_CPD_RS(n) (0x004c + ((n)*4))
12665 -#define CSI_CPD_GRC(n) (0x005c + ((n)*4))
12666 -#define CSI_CPD_GRS(n) (0x007c + ((n)*4))
12667 -#define CSI_CPD_GBC(n) (0x008c + ((n)*4))
12668 -#define CSI_CPD_GBS(n) (0x00Ac + ((n)*4))
12669 -#define CSI_CPD_BC(n) (0x00Bc + ((n)*4))
12670 -#define CSI_CPD_BS(n) (0x00Dc + ((n)*4))
12671 -#define CSI_CPD_OFFSET1 0x00ec
12672 -#define CSI_CPD_OFFSET2 0x00f0
12674 -/* CSI Register Fields */
12675 -#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
12676 -#define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700
12677 -#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L
12678 -#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
12679 -#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
12680 -#define CSI_SENS_CONF_DATA_FMT_BAYER 3L
12681 -#define CSI_SENS_CONF_DATA_FMT_RGB565 4L
12682 -#define CSI_SENS_CONF_DATA_FMT_RGB555 5L
12683 -#define CSI_SENS_CONF_DATA_FMT_RGB444 6L
12684 -#define CSI_SENS_CONF_DATA_FMT_JPEG 7L
12686 -#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
12687 -#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
12688 -#define CSI_SENS_CONF_DATA_POL_SHIFT 2
12689 -#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
12690 -#define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070
12691 -#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
12692 -#define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7
12693 -#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11
12694 -#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
12695 -#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
12697 -#define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000
12698 -#define CSI_SENS_CONF_DATA_DEST_SHIFT 24
12699 -#define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000
12700 -#define CSI_SENS_CONF_JPEG8_EN_SHIFT 27
12701 -#define CSI_SENS_CONF_JPEG_EN_SHIFT 28
12702 -#define CSI_SENS_CONF_FORCE_EOF_SHIFT 29
12703 -#define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31
12705 -#define CSI_DATA_DEST_IC 2
12706 -#define CSI_DATA_DEST_IDMAC 4
12708 -#define CSI_CCIR_ERR_DET_EN 0x01000000
12709 -#define CSI_HORI_DOWNSIZE_EN 0x80000000
12710 -#define CSI_VERT_DOWNSIZE_EN 0x40000000
12711 -#define CSI_TEST_GEN_MODE_EN 0x01000000
12713 -#define CSI_HSC_MASK 0x1fff0000
12714 -#define CSI_HSC_SHIFT 16
12715 -#define CSI_VSC_MASK 0x00000fff
12716 -#define CSI_VSC_SHIFT 0
12718 -#define CSI_TEST_GEN_R_MASK 0x000000ff
12719 -#define CSI_TEST_GEN_R_SHIFT 0
12720 -#define CSI_TEST_GEN_G_MASK 0x0000ff00
12721 -#define CSI_TEST_GEN_G_SHIFT 8
12722 -#define CSI_TEST_GEN_B_MASK 0x00ff0000
12723 -#define CSI_TEST_GEN_B_SHIFT 16
12725 -#define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007
12726 -#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0
12727 -#define CSI_SKIP_SMFC_MASK 0x000000f8
12728 -#define CSI_SKIP_SMFC_SHIFT 3
12729 -#define CSI_ID_2_SKIP_MASK 0x00000300
12730 -#define CSI_ID_2_SKIP_SHIFT 8
12732 -#define CSI_COLOR_FIRST_ROW_MASK 0x00000002
12733 -#define CSI_COLOR_FIRST_COMP_MASK 0x00000001
12735 -/* MIPI CSI-2 data types */
12736 -#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
12737 -#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
12738 -#define MIPI_DT_YUV422 0x1e /* UYVY... */
12739 -#define MIPI_DT_RGB444 0x20
12740 -#define MIPI_DT_RGB555 0x21
12741 -#define MIPI_DT_RGB565 0x22
12742 -#define MIPI_DT_RGB666 0x23
12743 -#define MIPI_DT_RGB888 0x24
12744 -#define MIPI_DT_RAW6 0x28
12745 -#define MIPI_DT_RAW7 0x29
12746 -#define MIPI_DT_RAW8 0x2a
12747 -#define MIPI_DT_RAW10 0x2b
12748 -#define MIPI_DT_RAW12 0x2c
12749 -#define MIPI_DT_RAW14 0x2d
12752 - * Bitfield of CSI bus signal polarities and modes.
12754 -struct ipu_csi_bus_config {
12755 - unsigned data_width:4;
12756 - unsigned clk_mode:3;
12757 - unsigned ext_vsync:1;
12758 - unsigned vsync_pol:1;
12759 - unsigned hsync_pol:1;
12760 - unsigned pixclk_pol:1;
12761 - unsigned data_pol:1;
12762 - unsigned sens_clksrc:1;
12763 - unsigned pack_tight:1;
12764 - unsigned force_eof:1;
12765 - unsigned data_en_pol:1;
12767 - unsigned data_fmt;
12768 - unsigned mipi_dt;
12772 - * Enumeration of CSI data bus widths.
12774 -enum ipu_csi_data_width {
12775 - IPU_CSI_DATA_WIDTH_4 = 0,
12776 - IPU_CSI_DATA_WIDTH_8 = 1,
12777 - IPU_CSI_DATA_WIDTH_10 = 3,
12778 - IPU_CSI_DATA_WIDTH_12 = 5,
12779 - IPU_CSI_DATA_WIDTH_16 = 9,
12783 - * Enumeration of CSI clock modes.
12785 -enum ipu_csi_clk_mode {
12786 - IPU_CSI_CLK_MODE_GATED_CLK,
12787 - IPU_CSI_CLK_MODE_NONGATED_CLK,
12788 - IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
12789 - IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
12790 - IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
12791 - IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
12792 - IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
12793 - IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
12796 -static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
12798 - return readl(csi->base + offset);
12801 -static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
12804 - writel(value, csi->base + offset);
12808 - * Set mclk division ratio for generating test mode mclk. Only used
12809 - * for test generator.
12811 -static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
12817 - div_ratio = (ipu_clk / pixel_clk) - 1;
12819 - if (div_ratio > 0xFF || div_ratio < 0) {
12820 - dev_err(csi->ipu->dev,
12821 - "value of pixel_clk extends normal range\n");
12825 - temp = ipu_csi_read(csi, CSI_SENS_CONF);
12826 - temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
12827 - ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
12834 - * Find the CSI data format and data width for the given V4L2 media
12835 - * bus pixel format code.
12837 -static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
12838 - enum v4l2_mbus_type mbus_type)
12840 - switch (mbus_code) {
12841 - case MEDIA_BUS_FMT_BGR565_2X8_BE:
12842 - case MEDIA_BUS_FMT_BGR565_2X8_LE:
12843 - case MEDIA_BUS_FMT_RGB565_2X8_BE:
12844 - case MEDIA_BUS_FMT_RGB565_2X8_LE:
12845 - if (mbus_type == V4L2_MBUS_CSI2_DPHY)
12846 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
12848 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12849 - cfg->mipi_dt = MIPI_DT_RGB565;
12850 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12852 - case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
12853 - case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
12854 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
12855 - cfg->mipi_dt = MIPI_DT_RGB444;
12856 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12858 - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
12859 - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
12860 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
12861 - cfg->mipi_dt = MIPI_DT_RGB555;
12862 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12864 - case MEDIA_BUS_FMT_RGB888_1X24:
12865 - case MEDIA_BUS_FMT_BGR888_1X24:
12866 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
12867 - cfg->mipi_dt = MIPI_DT_RGB888;
12868 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12870 - case MEDIA_BUS_FMT_UYVY8_2X8:
12871 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
12872 - cfg->mipi_dt = MIPI_DT_YUV422;
12873 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12875 - case MEDIA_BUS_FMT_YUYV8_2X8:
12876 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
12877 - cfg->mipi_dt = MIPI_DT_YUV422;
12878 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12880 - case MEDIA_BUS_FMT_UYVY8_1X16:
12881 - case MEDIA_BUS_FMT_YUYV8_1X16:
12882 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12883 - cfg->mipi_dt = MIPI_DT_YUV422;
12884 - cfg->data_width = IPU_CSI_DATA_WIDTH_16;
12886 - case MEDIA_BUS_FMT_SBGGR8_1X8:
12887 - case MEDIA_BUS_FMT_SGBRG8_1X8:
12888 - case MEDIA_BUS_FMT_SGRBG8_1X8:
12889 - case MEDIA_BUS_FMT_SRGGB8_1X8:
12890 - case MEDIA_BUS_FMT_Y8_1X8:
12891 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12892 - cfg->mipi_dt = MIPI_DT_RAW8;
12893 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12895 - case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
12896 - case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
12897 - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
12898 - case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
12899 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
12900 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
12901 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
12902 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
12903 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12904 - cfg->mipi_dt = MIPI_DT_RAW10;
12905 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12907 - case MEDIA_BUS_FMT_SBGGR10_1X10:
12908 - case MEDIA_BUS_FMT_SGBRG10_1X10:
12909 - case MEDIA_BUS_FMT_SGRBG10_1X10:
12910 - case MEDIA_BUS_FMT_SRGGB10_1X10:
12911 - case MEDIA_BUS_FMT_Y10_1X10:
12912 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12913 - cfg->mipi_dt = MIPI_DT_RAW10;
12914 - cfg->data_width = IPU_CSI_DATA_WIDTH_10;
12916 - case MEDIA_BUS_FMT_SBGGR12_1X12:
12917 - case MEDIA_BUS_FMT_SGBRG12_1X12:
12918 - case MEDIA_BUS_FMT_SGRBG12_1X12:
12919 - case MEDIA_BUS_FMT_SRGGB12_1X12:
12920 - case MEDIA_BUS_FMT_Y12_1X12:
12921 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12922 - cfg->mipi_dt = MIPI_DT_RAW12;
12923 - cfg->data_width = IPU_CSI_DATA_WIDTH_12;
12925 - case MEDIA_BUS_FMT_JPEG_1X8:
12927 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
12928 - cfg->mipi_dt = MIPI_DT_RAW8;
12929 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12938 -/* translate alternate field mode based on given standard */
12939 -static inline enum v4l2_field
12940 -ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
12942 - return (field != V4L2_FIELD_ALTERNATE) ? field :
12943 - ((std & V4L2_STD_525_60) ?
12944 - V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
12948 - * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
12950 -static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
12951 - const struct v4l2_mbus_config *mbus_cfg,
12952 - const struct v4l2_mbus_framefmt *mbus_fmt)
12956 - memset(csicfg, 0, sizeof(*csicfg));
12958 - ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
12962 - switch (mbus_cfg->type) {
12963 - case V4L2_MBUS_PARALLEL:
12964 - csicfg->ext_vsync = 1;
12965 - csicfg->vsync_pol = (mbus_cfg->flags &
12966 - V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
12967 - csicfg->hsync_pol = (mbus_cfg->flags &
12968 - V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
12969 - csicfg->pixclk_pol = (mbus_cfg->flags &
12970 - V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
12971 - csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
12973 - case V4L2_MBUS_BT656:
12974 - csicfg->ext_vsync = 0;
12975 - if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
12976 - mbus_fmt->field == V4L2_FIELD_ALTERNATE)
12977 - csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
12979 - csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
12981 - case V4L2_MBUS_CSI2_DPHY:
12983 - * MIPI CSI-2 requires non gated clock mode, all other
12984 - * parameters are not applicable for MIPI CSI-2 bus.
12986 - csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
12989 - /* will never get here, keep compiler quiet */
12997 -ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
12998 - const struct v4l2_mbus_framefmt *infmt,
12999 - const struct v4l2_mbus_framefmt *outfmt,
13002 - enum v4l2_field infield, outfield;
13003 - bool swap_fields;
13005 - /* get translated field type of input and output */
13006 - infield = ipu_csi_translate_field(infmt->field, std);
13007 - outfield = ipu_csi_translate_field(outfmt->field, std);
13010 - * Write the H-V-F codes the CSI will match against the
13011 - * incoming data for start/end of active and blanking
13012 - * field intervals. If input and output field types are
13013 - * sequential but not the same (one is SEQ_BT and the other
13014 - * is SEQ_TB), swap the F-bit so that the CSI will capture
13015 - * field 1 lines before field 0 lines.
13017 - swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
13018 - V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
13019 - infield != outfield);
13021 - if (!swap_fields) {
13023 - * Field0BlankEnd = 110, Field0BlankStart = 010
13024 - * Field0ActiveEnd = 100, Field0ActiveStart = 000
13025 - * Field1BlankEnd = 111, Field1BlankStart = 011
13026 - * Field1ActiveEnd = 101, Field1ActiveStart = 001
13028 - ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
13029 - CSI_CCIR_CODE_1);
13030 - ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
13032 - dev_dbg(csi->ipu->dev, "capture field swap\n");
13034 - /* same as above but with F-bit inverted */
13035 - ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
13036 - CSI_CCIR_CODE_1);
13037 - ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
13040 - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
13046 -int ipu_csi_init_interface(struct ipu_csi *csi,
13047 - const struct v4l2_mbus_config *mbus_cfg,
13048 - const struct v4l2_mbus_framefmt *infmt,
13049 - const struct v4l2_mbus_framefmt *outfmt)
13051 - struct ipu_csi_bus_config cfg;
13052 - unsigned long flags;
13053 - u32 width, height, data = 0;
13057 - ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
13061 - /* set default sensor frame width and height */
13062 - width = infmt->width;
13063 - height = infmt->height;
13064 - if (infmt->field == V4L2_FIELD_ALTERNATE)
13067 - /* Set the CSI_SENS_CONF register remaining fields */
13068 - data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
13069 - cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
13070 - cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
13071 - cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
13072 - cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
13073 - cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
13074 - cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
13075 - cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
13076 - cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
13077 - cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
13078 - cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
13080 - spin_lock_irqsave(&csi->lock, flags);
13082 - ipu_csi_write(csi, data, CSI_SENS_CONF);
13084 - /* Set CCIR registers */
13086 - switch (cfg.clk_mode) {
13087 - case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
13088 - ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
13089 - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
13091 - case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
13092 - if (width == 720 && height == 480) {
13093 - std = V4L2_STD_NTSC;
13095 - } else if (width == 720 && height == 576) {
13096 - std = V4L2_STD_PAL;
13099 - dev_err(csi->ipu->dev,
13100 - "Unsupported interlaced video mode\n");
13105 - ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
13109 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
13110 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
13111 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
13112 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
13113 - ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
13114 - CSI_CCIR_CODE_1);
13115 - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
13117 - case IPU_CSI_CLK_MODE_GATED_CLK:
13118 - case IPU_CSI_CLK_MODE_NONGATED_CLK:
13119 - ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
13123 - /* Setup sensor frame size */
13124 - ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
13125 - CSI_SENS_FRM_SIZE);
13127 - dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
13128 - ipu_csi_read(csi, CSI_SENS_CONF));
13129 - dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
13130 - ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
13133 - spin_unlock_irqrestore(&csi->lock, flags);
13137 -EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
13139 -bool ipu_csi_is_interlaced(struct ipu_csi *csi)
13141 - unsigned long flags;
13142 - u32 sensor_protocol;
13144 - spin_lock_irqsave(&csi->lock, flags);
13145 - sensor_protocol =
13146 - (ipu_csi_read(csi, CSI_SENS_CONF) &
13147 - CSI_SENS_CONF_SENS_PRTCL_MASK) >>
13148 - CSI_SENS_CONF_SENS_PRTCL_SHIFT;
13149 - spin_unlock_irqrestore(&csi->lock, flags);
13151 - switch (sensor_protocol) {
13152 - case IPU_CSI_CLK_MODE_GATED_CLK:
13153 - case IPU_CSI_CLK_MODE_NONGATED_CLK:
13154 - case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
13155 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
13156 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
13158 - case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
13159 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
13160 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
13163 - dev_err(csi->ipu->dev,
13164 - "CSI %d sensor protocol unsupported\n", csi->id);
13168 -EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
13170 -void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
13172 - unsigned long flags;
13175 - spin_lock_irqsave(&csi->lock, flags);
13177 - reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
13178 - w->width = (reg & 0xFFFF) + 1;
13179 - w->height = (reg >> 16 & 0xFFFF) + 1;
13181 - reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
13182 - w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
13183 - w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
13185 - spin_unlock_irqrestore(&csi->lock, flags);
13187 -EXPORT_SYMBOL_GPL(ipu_csi_get_window);
13189 -void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
13191 - unsigned long flags;
13194 - spin_lock_irqsave(&csi->lock, flags);
13196 - ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
13197 - CSI_ACT_FRM_SIZE);
13199 - reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
13200 - reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
13201 - reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
13202 - ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
13204 - spin_unlock_irqrestore(&csi->lock, flags);
13206 -EXPORT_SYMBOL_GPL(ipu_csi_set_window);
13208 -void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
13210 - unsigned long flags;
13213 - spin_lock_irqsave(&csi->lock, flags);
13215 - reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
13216 - reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
13217 - reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
13218 - (vert ? CSI_VERT_DOWNSIZE_EN : 0);
13219 - ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
13221 - spin_unlock_irqrestore(&csi->lock, flags);
13223 -EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
13225 -void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
13226 - u32 r_value, u32 g_value, u32 b_value,
13229 - unsigned long flags;
13230 - u32 ipu_clk = clk_get_rate(csi->clk_ipu);
13233 - spin_lock_irqsave(&csi->lock, flags);
13235 - temp = ipu_csi_read(csi, CSI_TST_CTRL);
13238 - temp &= ~CSI_TEST_GEN_MODE_EN;
13239 - ipu_csi_write(csi, temp, CSI_TST_CTRL);
13241 - /* Set sensb_mclk div_ratio */
13242 - ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
13244 - temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
13245 - CSI_TEST_GEN_B_MASK);
13246 - temp |= CSI_TEST_GEN_MODE_EN;
13247 - temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
13248 - (g_value << CSI_TEST_GEN_G_SHIFT) |
13249 - (b_value << CSI_TEST_GEN_B_SHIFT);
13250 - ipu_csi_write(csi, temp, CSI_TST_CTRL);
13253 - spin_unlock_irqrestore(&csi->lock, flags);
13255 -EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
13257 -int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
13258 - struct v4l2_mbus_framefmt *mbus_fmt)
13260 - struct ipu_csi_bus_config cfg;
13261 - unsigned long flags;
13268 - ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
13272 - spin_lock_irqsave(&csi->lock, flags);
13274 - temp = ipu_csi_read(csi, CSI_MIPI_DI);
13275 - temp &= ~(0xff << (vc * 8));
13276 - temp |= (cfg.mipi_dt << (vc * 8));
13277 - ipu_csi_write(csi, temp, CSI_MIPI_DI);
13279 - spin_unlock_irqrestore(&csi->lock, flags);
13283 -EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
13285 -int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
13286 - u32 max_ratio, u32 id)
13288 - unsigned long flags;
13291 - if (max_ratio > 5 || id > 3)
13294 - spin_lock_irqsave(&csi->lock, flags);
13296 - temp = ipu_csi_read(csi, CSI_SKIP);
13297 - temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
13298 - CSI_SKIP_SMFC_MASK);
13299 - temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
13300 - (id << CSI_ID_2_SKIP_SHIFT) |
13301 - (skip << CSI_SKIP_SMFC_SHIFT);
13302 - ipu_csi_write(csi, temp, CSI_SKIP);
13304 - spin_unlock_irqrestore(&csi->lock, flags);
13308 -EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
13310 -int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
13312 - unsigned long flags;
13313 - u32 csi_sens_conf, dest;
13315 - if (csi_dest == IPU_CSI_DEST_IDMAC)
13316 - dest = CSI_DATA_DEST_IDMAC;
13318 - dest = CSI_DATA_DEST_IC; /* IC or VDIC */
13320 - spin_lock_irqsave(&csi->lock, flags);
13322 - csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
13323 - csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
13324 - csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
13325 - ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
13327 - spin_unlock_irqrestore(&csi->lock, flags);
13331 -EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
13333 -int ipu_csi_enable(struct ipu_csi *csi)
13335 - ipu_module_enable(csi->ipu, csi->module);
13339 -EXPORT_SYMBOL_GPL(ipu_csi_enable);
13341 -int ipu_csi_disable(struct ipu_csi *csi)
13343 - ipu_module_disable(csi->ipu, csi->module);
13347 -EXPORT_SYMBOL_GPL(ipu_csi_disable);
13349 -struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
13351 - unsigned long flags;
13352 - struct ipu_csi *csi, *ret;
13355 - return ERR_PTR(-EINVAL);
13357 - csi = ipu->csi_priv[id];
13360 - spin_lock_irqsave(&csi->lock, flags);
13362 - if (csi->inuse) {
13363 - ret = ERR_PTR(-EBUSY);
13367 - csi->inuse = true;
13369 - spin_unlock_irqrestore(&csi->lock, flags);
13372 -EXPORT_SYMBOL_GPL(ipu_csi_get);
13374 -void ipu_csi_put(struct ipu_csi *csi)
13376 - unsigned long flags;
13378 - spin_lock_irqsave(&csi->lock, flags);
13379 - csi->inuse = false;
13380 - spin_unlock_irqrestore(&csi->lock, flags);
13382 -EXPORT_SYMBOL_GPL(ipu_csi_put);
13384 -int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
13385 - unsigned long base, u32 module, struct clk *clk_ipu)
13387 - struct ipu_csi *csi;
13392 - csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
13396 - ipu->csi_priv[id] = csi;
13398 - spin_lock_init(&csi->lock);
13399 - csi->module = module;
13401 - csi->clk_ipu = clk_ipu;
13402 - csi->base = devm_ioremap(dev, base, PAGE_SIZE);
13406 - dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
13407 - id, base, csi->base);
13413 -void ipu_csi_exit(struct ipu_soc *ipu, int id)
13417 -void ipu_csi_dump(struct ipu_csi *csi)
13419 - dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n",
13420 - ipu_csi_read(csi, CSI_SENS_CONF));
13421 - dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
13422 - ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
13423 - dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n",
13424 - ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
13425 - dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n",
13426 - ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
13427 - dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n",
13428 - ipu_csi_read(csi, CSI_TST_CTRL));
13429 - dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n",
13430 - ipu_csi_read(csi, CSI_CCIR_CODE_1));
13431 - dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n",
13432 - ipu_csi_read(csi, CSI_CCIR_CODE_2));
13433 - dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n",
13434 - ipu_csi_read(csi, CSI_CCIR_CODE_3));
13435 - dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n",
13436 - ipu_csi_read(csi, CSI_MIPI_DI));
13437 - dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n",
13438 - ipu_csi_read(csi, CSI_SKIP));
13440 -EXPORT_SYMBOL_GPL(ipu_csi_dump);
13441 --- a/drivers/gpu/ipu-v3/ipu-dc.c
13444 -// SPDX-License-Identifier: GPL-2.0-or-later
13446 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
13447 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
13450 -#include <linux/export.h>
13451 -#include <linux/module.h>
13452 -#include <linux/types.h>
13453 -#include <linux/errno.h>
13454 -#include <linux/delay.h>
13455 -#include <linux/interrupt.h>
13456 -#include <linux/io.h>
13458 -#include <video/imx-ipu-v3.h>
13459 -#include "ipu-prv.h"
13461 -#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2)
13462 -#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2)
13464 -#define DC_EVT_NF 0
13465 -#define DC_EVT_NL 1
13466 -#define DC_EVT_EOF 2
13467 -#define DC_EVT_NFIELD 3
13468 -#define DC_EVT_EOL 4
13469 -#define DC_EVT_EOFIELD 5
13470 -#define DC_EVT_NEW_ADDR 6
13471 -#define DC_EVT_NEW_CHAN 7
13472 -#define DC_EVT_NEW_DATA 8
13474 -#define DC_EVT_NEW_ADDR_W_0 0
13475 -#define DC_EVT_NEW_ADDR_W_1 1
13476 -#define DC_EVT_NEW_CHAN_W_0 2
13477 -#define DC_EVT_NEW_CHAN_W_1 3
13478 -#define DC_EVT_NEW_DATA_W_0 4
13479 -#define DC_EVT_NEW_DATA_W_1 5
13480 -#define DC_EVT_NEW_ADDR_R_0 6
13481 -#define DC_EVT_NEW_ADDR_R_1 7
13482 -#define DC_EVT_NEW_CHAN_R_0 8
13483 -#define DC_EVT_NEW_CHAN_R_1 9
13484 -#define DC_EVT_NEW_DATA_R_0 10
13485 -#define DC_EVT_NEW_DATA_R_1 11
13487 -#define DC_WR_CH_CONF 0x0
13488 -#define DC_WR_CH_ADDR 0x4
13489 -#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2)
13491 -#define DC_GEN 0xd4
13492 -#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4)
13493 -#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4)
13494 -#define DC_STAT 0x1c8
13496 -#define WROD(lf) (0x18 | ((lf) << 1))
13500 -#define SYNC_WAVE 0
13501 -#define NULL_WAVE (-1)
13503 -#define DC_GEN_SYNC_1_6_SYNC (2 << 1)
13504 -#define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
13506 -#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0)
13507 -#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0)
13508 -#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0)
13509 -#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0)
13510 -#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3)
13511 -#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3)
13512 -#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4)
13513 -#define DC_WR_CH_CONF_FIELD_MODE (1 << 9)
13514 -#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5)
13515 -#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5)
13516 -#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2)
13517 -#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3)
13519 -#define IPU_DC_NUM_CHANNELS 10
13521 -struct ipu_dc_priv;
13524 - IPU_DC_MAP_RGB24,
13525 - IPU_DC_MAP_RGB565,
13526 - IPU_DC_MAP_GBR24, /* TVEv2 */
13527 - IPU_DC_MAP_BGR666,
13528 - IPU_DC_MAP_LVDS666,
13529 - IPU_DC_MAP_BGR24,
13533 - /* The display interface number assigned to this dc channel */
13535 - void __iomem *base;
13536 - struct ipu_dc_priv *priv;
13541 -struct ipu_dc_priv {
13542 - void __iomem *dc_reg;
13543 - void __iomem *dc_tmpl_reg;
13544 - struct ipu_soc *ipu;
13545 - struct device *dev;
13546 - struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
13547 - struct mutex mutex;
13548 - struct completion comp;
13552 -static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
13556 - reg = readl(dc->base + DC_RL_CH(event));
13557 - reg &= ~(0xffff << (16 * (event & 0x1)));
13558 - reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
13559 - writel(reg, dc->base + DC_RL_CH(event));
13562 -static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
13563 - int map, int wave, int glue, int sync, int stop)
13565 - struct ipu_dc_priv *priv = dc->priv;
13568 - if (opcode == WCLK) {
13569 - reg1 = (operand << 20) & 0xfff00000;
13570 - reg2 = operand >> 12 | opcode << 1 | stop << 9;
13571 - } else if (opcode == WRG) {
13572 - reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
13573 - reg2 = operand >> 17 | opcode << 7 | stop << 9;
13575 - reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
13576 - reg2 = operand >> 12 | opcode << 4 | stop << 9;
13578 - writel(reg1, priv->dc_tmpl_reg + word * 8);
13579 - writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
13582 -static int ipu_bus_format_to_map(u32 fmt)
13587 - /* fall-through */
13588 - case MEDIA_BUS_FMT_RGB888_1X24:
13589 - return IPU_DC_MAP_RGB24;
13590 - case MEDIA_BUS_FMT_RGB565_1X16:
13591 - return IPU_DC_MAP_RGB565;
13592 - case MEDIA_BUS_FMT_GBR888_1X24:
13593 - return IPU_DC_MAP_GBR24;
13594 - case MEDIA_BUS_FMT_RGB666_1X18:
13595 - return IPU_DC_MAP_BGR666;
13596 - case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
13597 - return IPU_DC_MAP_LVDS666;
13598 - case MEDIA_BUS_FMT_BGR888_1X24:
13599 - return IPU_DC_MAP_BGR24;
13603 -int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
13604 - u32 bus_format, u32 width)
13606 - struct ipu_dc_priv *priv = dc->priv;
13611 - dc->di = ipu_di_get_num(di);
13613 - map = ipu_bus_format_to_map(bus_format);
13616 - * In interlaced mode we need more counters to create the asymmetric
13617 - * per-field VSYNC signals. The pixel active signal synchronising DC
13618 - * to DI moves to signal generator #6 (see ipu-di.c). In progressive
13619 - * mode counter #5 is used.
13621 - sync = interlaced ? 6 : 5;
13623 - /* Reserve 5 microcode template words for each DI */
13629 - if (interlaced) {
13630 - dc_link_event(dc, DC_EVT_NL, addr, 3);
13631 - dc_link_event(dc, DC_EVT_EOL, addr, 2);
13632 - dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
13634 - /* Init template microcode */
13635 - dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
13637 - dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
13638 - dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
13639 - dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
13641 - /* Init template microcode */
13642 - dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
13643 - dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
13644 - dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
13645 - dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
13648 - dc_link_event(dc, DC_EVT_NF, 0, 0);
13649 - dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
13650 - dc_link_event(dc, DC_EVT_EOF, 0, 0);
13651 - dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
13652 - dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
13653 - dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
13655 - reg = readl(dc->base + DC_WR_CH_CONF);
13657 - reg |= DC_WR_CH_CONF_FIELD_MODE;
13659 - reg &= ~DC_WR_CH_CONF_FIELD_MODE;
13660 - writel(reg, dc->base + DC_WR_CH_CONF);
13662 - writel(0x0, dc->base + DC_WR_CH_ADDR);
13663 - writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
13667 -EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
13669 -void ipu_dc_enable(struct ipu_soc *ipu)
13671 - struct ipu_dc_priv *priv = ipu->dc_priv;
13673 - mutex_lock(&priv->mutex);
13675 - if (!priv->use_count)
13676 - ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
13678 - priv->use_count++;
13680 - mutex_unlock(&priv->mutex);
13682 -EXPORT_SYMBOL_GPL(ipu_dc_enable);
13684 -void ipu_dc_enable_channel(struct ipu_dc *dc)
13688 - reg = readl(dc->base + DC_WR_CH_CONF);
13689 - reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
13690 - writel(reg, dc->base + DC_WR_CH_CONF);
13692 -EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
13694 -void ipu_dc_disable_channel(struct ipu_dc *dc)
13698 - val = readl(dc->base + DC_WR_CH_CONF);
13699 - val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
13700 - writel(val, dc->base + DC_WR_CH_CONF);
13702 -EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
13704 -void ipu_dc_disable(struct ipu_soc *ipu)
13706 - struct ipu_dc_priv *priv = ipu->dc_priv;
13708 - mutex_lock(&priv->mutex);
13710 - priv->use_count--;
13711 - if (!priv->use_count)
13712 - ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
13714 - if (priv->use_count < 0)
13715 - priv->use_count = 0;
13717 - mutex_unlock(&priv->mutex);
13719 -EXPORT_SYMBOL_GPL(ipu_dc_disable);
13721 -static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
13722 - int byte_num, int offset, int mask)
13724 - int ptr = map * 3 + byte_num;
13727 - reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
13728 - reg &= ~(0xffff << (16 * (ptr & 0x1)));
13729 - reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
13730 - writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
13732 - reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
13733 - reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
13734 - reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
13735 - writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
13738 -static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
13740 - u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
13742 - writel(reg & ~(0xffff << (16 * (map & 0x1))),
13743 - priv->dc_reg + DC_MAP_CONF_PTR(map));
13746 -struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
13748 - struct ipu_dc_priv *priv = ipu->dc_priv;
13749 - struct ipu_dc *dc;
13751 - if (channel >= IPU_DC_NUM_CHANNELS)
13752 - return ERR_PTR(-ENODEV);
13754 - dc = &priv->channels[channel];
13756 - mutex_lock(&priv->mutex);
13758 - if (dc->in_use) {
13759 - mutex_unlock(&priv->mutex);
13760 - return ERR_PTR(-EBUSY);
13763 - dc->in_use = true;
13765 - mutex_unlock(&priv->mutex);
13769 -EXPORT_SYMBOL_GPL(ipu_dc_get);
13771 -void ipu_dc_put(struct ipu_dc *dc)
13773 - struct ipu_dc_priv *priv = dc->priv;
13775 - mutex_lock(&priv->mutex);
13776 - dc->in_use = false;
13777 - mutex_unlock(&priv->mutex);
13779 -EXPORT_SYMBOL_GPL(ipu_dc_put);
13781 -int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
13782 - unsigned long base, unsigned long template_base)
13784 - struct ipu_dc_priv *priv;
13785 - static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
13786 - 0x78, 0, 0x94, 0xb4};
13789 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
13793 - mutex_init(&priv->mutex);
13797 - priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
13798 - priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
13799 - if (!priv->dc_reg || !priv->dc_tmpl_reg)
13802 - for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
13803 - priv->channels[i].chno = i;
13804 - priv->channels[i].priv = priv;
13805 - priv->channels[i].base = priv->dc_reg + channel_offsets[i];
13808 - writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
13809 - DC_WR_CH_CONF_PROG_DI_ID,
13810 - priv->channels[1].base + DC_WR_CH_CONF);
13811 - writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
13812 - priv->channels[5].base + DC_WR_CH_CONF);
13814 - writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
13815 - priv->dc_reg + DC_GEN);
13817 - ipu->dc_priv = priv;
13819 - dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
13820 - base, template_base);
13823 - ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
13824 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
13825 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
13826 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
13829 - ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
13830 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
13831 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
13832 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
13835 - ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
13836 - ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
13837 - ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
13838 - ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
13841 - ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
13842 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
13843 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
13844 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
13847 - ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
13848 - ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
13849 - ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
13850 - ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
13853 - ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
13854 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
13855 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
13856 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
13861 -void ipu_dc_exit(struct ipu_soc *ipu)
13864 --- a/drivers/gpu/ipu-v3/ipu-di.c
13867 -// SPDX-License-Identifier: GPL-2.0-or-later
13869 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
13870 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
13872 -#include <linux/export.h>
13873 -#include <linux/module.h>
13874 -#include <linux/types.h>
13875 -#include <linux/errno.h>
13876 -#include <linux/io.h>
13877 -#include <linux/err.h>
13878 -#include <linux/platform_device.h>
13880 -#include <video/imx-ipu-v3.h>
13881 -#include "ipu-prv.h"
13884 - void __iomem *base;
13887 - struct clk *clk_di; /* display input clock */
13888 - struct clk *clk_ipu; /* IPU bus clock */
13889 - struct clk *clk_di_pixel; /* resulting pixel clock */
13891 - struct ipu_soc *ipu;
13894 -static DEFINE_MUTEX(di_mutex);
13896 -struct di_sync_config {
13899 - int offset_count;
13901 - int repeat_count;
13903 - int cnt_polarity_gen_en;
13904 - int cnt_polarity_clr_src;
13905 - int cnt_polarity_trigger_src;
13920 - DI_PIN_SER_CLK = 0,
13921 - DI_PIN_SER_RS = 1,
13924 -enum di_sync_wave {
13925 - DI_SYNC_NONE = 0,
13927 - DI_SYNC_INT_HSYNC = 2,
13928 - DI_SYNC_HSYNC = 3,
13929 - DI_SYNC_VSYNC = 4,
13932 - DI_SYNC_CNT1 = 2, /* counter >= 2 only */
13933 - DI_SYNC_CNT4 = 5, /* counter >= 5 only */
13934 - DI_SYNC_CNT5 = 6, /* counter >= 6 only */
13937 -#define SYNC_WAVE 0
13939 -#define DI_GENERAL 0x0000
13940 -#define DI_BS_CLKGEN0 0x0004
13941 -#define DI_BS_CLKGEN1 0x0008
13942 -#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
13943 -#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
13944 -#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
13945 -#define DI_SYNC_AS_GEN 0x0054
13946 -#define DI_DW_GEN(gen) (0x0058 + 4 * (gen))
13947 -#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set)))
13948 -#define DI_SER_CONF 0x015c
13949 -#define DI_SSC 0x0160
13950 -#define DI_POL 0x0164
13951 -#define DI_AW0 0x0168
13952 -#define DI_AW1 0x016c
13953 -#define DI_SCR_CONF 0x0170
13954 -#define DI_STAT 0x0174
13956 -#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19)
13957 -#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16)
13958 -#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3)
13959 -#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0)
13961 -#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29)
13962 -#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25)
13963 -#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12)
13964 -#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9)
13965 -#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16)
13966 -#define DI_SW_GEN1_CNT_UP(x) (x)
13967 -#define DI_SW_GEN1_AUTO_RELOAD (0x10000000)
13969 -#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24
13970 -#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16
13972 -#define DI_GEN_POLARITY_1 (1 << 0)
13973 -#define DI_GEN_POLARITY_2 (1 << 1)
13974 -#define DI_GEN_POLARITY_3 (1 << 2)
13975 -#define DI_GEN_POLARITY_4 (1 << 3)
13976 -#define DI_GEN_POLARITY_5 (1 << 4)
13977 -#define DI_GEN_POLARITY_6 (1 << 5)
13978 -#define DI_GEN_POLARITY_7 (1 << 6)
13979 -#define DI_GEN_POLARITY_8 (1 << 7)
13980 -#define DI_GEN_POLARITY_DISP_CLK (1 << 17)
13981 -#define DI_GEN_DI_CLK_EXT (1 << 20)
13982 -#define DI_GEN_DI_VSYNC_EXT (1 << 21)
13984 -#define DI_POL_DRDY_DATA_POLARITY (1 << 7)
13985 -#define DI_POL_DRDY_POLARITY_15 (1 << 4)
13987 -#define DI_VSYNC_SEL_OFFSET 13
13989 -static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
13991 - return readl(di->base + offset);
13994 -static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
13996 - writel(value, di->base + offset);
13999 -static void ipu_di_data_wave_config(struct ipu_di *di,
14001 - int access_size, int component_size)
14004 - reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
14005 - (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
14006 - ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
14009 -static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
14010 - int set, int up, int down)
14014 - reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
14015 - reg &= ~(0x3 << (di_pin * 2));
14016 - reg |= set << (di_pin * 2);
14017 - ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
14019 - ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
14022 -static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
14023 - int start, int count)
14028 - for (i = 0; i < count; i++) {
14029 - struct di_sync_config *c = &config[i];
14030 - int wave_gen = start + i + 1;
14032 - if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
14033 - (c->repeat_count >= 0x1000) ||
14034 - (c->cnt_up >= 0x400) ||
14035 - (c->cnt_down >= 0x400)) {
14036 - dev_err(di->ipu->dev, "DI%d counters out of range.\n",
14041 - reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
14042 - DI_SW_GEN0_RUN_SRC(c->run_src) |
14043 - DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
14044 - DI_SW_GEN0_OFFSET_SRC(c->offset_src);
14045 - ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
14047 - reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
14048 - DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
14049 - DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
14050 - c->cnt_polarity_trigger_src) |
14051 - DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
14052 - DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
14053 - DI_SW_GEN1_CNT_UP(c->cnt_up);
14055 - /* Enable auto reload */
14056 - if (c->repeat_count == 0)
14057 - reg |= DI_SW_GEN1_AUTO_RELOAD;
14059 - ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
14061 - reg = ipu_di_read(di, DI_STP_REP(wave_gen));
14062 - reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
14063 - reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
14064 - ipu_di_write(di, reg, DI_STP_REP(wave_gen));
14068 -static void ipu_di_sync_config_interlaced(struct ipu_di *di,
14069 - struct ipu_di_signal_cfg *sig)
14071 - u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
14072 - sig->mode.hback_porch + sig->mode.hfront_porch;
14073 - u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
14074 - sig->mode.vback_porch + sig->mode.vfront_porch;
14075 - struct di_sync_config cfg[] = {
14077 - /* 1: internal VSYNC for each frame */
14078 - .run_count = v_total * 2 - 1,
14079 - .run_src = 3, /* == counter 7 */
14081 - /* PIN2: HSYNC waveform */
14082 - .run_count = h_total - 1,
14083 - .run_src = DI_SYNC_CLK,
14084 - .cnt_polarity_gen_en = 1,
14085 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
14086 - .cnt_down = sig->mode.hsync_len * 2,
14088 - /* PIN3: VSYNC waveform */
14089 - .run_count = v_total - 1,
14090 - .run_src = 4, /* == counter 7 */
14091 - .cnt_polarity_gen_en = 1,
14092 - .cnt_polarity_trigger_src = 4, /* == counter 7 */
14093 - .cnt_down = sig->mode.vsync_len * 2,
14094 - .cnt_clr_src = DI_SYNC_CNT1,
14097 - .run_count = v_total / 2,
14098 - .run_src = DI_SYNC_HSYNC,
14099 - .offset_count = h_total / 2,
14100 - .offset_src = DI_SYNC_CLK,
14101 - .repeat_count = 2,
14102 - .cnt_clr_src = DI_SYNC_CNT1,
14104 - /* 5: Active lines */
14105 - .run_src = DI_SYNC_HSYNC,
14106 - .offset_count = (sig->mode.vsync_len +
14107 - sig->mode.vback_porch) / 2,
14108 - .offset_src = DI_SYNC_HSYNC,
14109 - .repeat_count = sig->mode.vactive / 2,
14110 - .cnt_clr_src = DI_SYNC_CNT4,
14112 - /* 6: Active pixel, referenced by DC */
14113 - .run_src = DI_SYNC_CLK,
14114 - .offset_count = sig->mode.hsync_len +
14115 - sig->mode.hback_porch,
14116 - .offset_src = DI_SYNC_CLK,
14117 - .repeat_count = sig->mode.hactive,
14118 - .cnt_clr_src = DI_SYNC_CNT5,
14120 - /* 7: Half line HSYNC */
14121 - .run_count = h_total / 2 - 1,
14122 - .run_src = DI_SYNC_CLK,
14126 - ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
14128 - ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
14131 -static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
14132 - struct ipu_di_signal_cfg *sig, int div)
14134 - u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
14135 - sig->mode.hback_porch + sig->mode.hfront_porch;
14136 - u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
14137 - sig->mode.vback_porch + sig->mode.vfront_porch;
14138 - struct di_sync_config cfg[] = {
14140 - /* 1: INT_HSYNC */
14141 - .run_count = h_total - 1,
14142 - .run_src = DI_SYNC_CLK,
14144 - /* PIN2: HSYNC */
14145 - .run_count = h_total - 1,
14146 - .run_src = DI_SYNC_CLK,
14147 - .offset_count = div * sig->v_to_h_sync,
14148 - .offset_src = DI_SYNC_CLK,
14149 - .cnt_polarity_gen_en = 1,
14150 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
14151 - .cnt_down = sig->mode.hsync_len * 2,
14153 - /* PIN3: VSYNC */
14154 - .run_count = v_total - 1,
14155 - .run_src = DI_SYNC_INT_HSYNC,
14156 - .cnt_polarity_gen_en = 1,
14157 - .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
14158 - .cnt_down = sig->mode.vsync_len * 2,
14160 - /* 4: Line Active */
14161 - .run_src = DI_SYNC_HSYNC,
14162 - .offset_count = sig->mode.vsync_len +
14163 - sig->mode.vback_porch,
14164 - .offset_src = DI_SYNC_HSYNC,
14165 - .repeat_count = sig->mode.vactive,
14166 - .cnt_clr_src = DI_SYNC_VSYNC,
14168 - /* 5: Pixel Active, referenced by DC */
14169 - .run_src = DI_SYNC_CLK,
14170 - .offset_count = sig->mode.hsync_len +
14171 - sig->mode.hback_porch,
14172 - .offset_src = DI_SYNC_CLK,
14173 - .repeat_count = sig->mode.hactive,
14174 - .cnt_clr_src = 5, /* Line Active */
14185 - /* can't use #7 and #8 for line active and pixel active counters */
14186 - struct di_sync_config cfg_vga[] = {
14188 - /* 1: INT_HSYNC */
14189 - .run_count = h_total - 1,
14190 - .run_src = DI_SYNC_CLK,
14193 - .run_count = v_total - 1,
14194 - .run_src = DI_SYNC_INT_HSYNC,
14196 - /* 3: Line Active */
14197 - .run_src = DI_SYNC_INT_HSYNC,
14198 - .offset_count = sig->mode.vsync_len +
14199 - sig->mode.vback_porch,
14200 - .offset_src = DI_SYNC_INT_HSYNC,
14201 - .repeat_count = sig->mode.vactive,
14202 - .cnt_clr_src = 3 /* VSYNC */,
14204 - /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
14205 - .run_count = h_total - 1,
14206 - .run_src = DI_SYNC_CLK,
14207 - .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
14208 - .offset_src = DI_SYNC_CLK,
14209 - .cnt_polarity_gen_en = 1,
14210 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
14211 - .cnt_down = sig->mode.hsync_len * 2,
14213 - /* 5: Pixel Active signal to DC */
14214 - .run_src = DI_SYNC_CLK,
14215 - .offset_count = sig->mode.hsync_len +
14216 - sig->mode.hback_porch,
14217 - .offset_src = DI_SYNC_CLK,
14218 - .repeat_count = sig->mode.hactive,
14219 - .cnt_clr_src = 4, /* Line Active */
14221 - /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
14222 - .run_count = v_total - 1,
14223 - .run_src = DI_SYNC_INT_HSYNC,
14224 - .offset_count = 1, /* magic value from Freescale TVE driver */
14225 - .offset_src = DI_SYNC_INT_HSYNC,
14226 - .cnt_polarity_gen_en = 1,
14227 - .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
14228 - .cnt_down = sig->mode.vsync_len * 2,
14230 - /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
14231 - .run_count = h_total - 1,
14232 - .run_src = DI_SYNC_CLK,
14233 - .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
14234 - .offset_src = DI_SYNC_CLK,
14235 - .cnt_polarity_gen_en = 1,
14236 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
14237 - .cnt_down = sig->mode.hsync_len * 2,
14239 - /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
14240 - .run_count = v_total - 1,
14241 - .run_src = DI_SYNC_INT_HSYNC,
14242 - .offset_count = 1, /* magic value from Freescale TVE driver */
14243 - .offset_src = DI_SYNC_INT_HSYNC,
14244 - .cnt_polarity_gen_en = 1,
14245 - .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
14246 - .cnt_down = sig->mode.vsync_len * 2,
14252 - ipu_di_write(di, v_total - 1, DI_SCR_CONF);
14253 - if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
14254 - ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
14256 - ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
14259 -static void ipu_di_config_clock(struct ipu_di *di,
14260 - const struct ipu_di_signal_cfg *sig)
14263 - unsigned clkgen0;
14266 - if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
14268 - * CLKMODE_EXT means we must use the DI clock: this is
14269 - * needed for things like LVDS which needs to feed the
14270 - * DI and LDB with the same pixel clock.
14272 - clk = di->clk_di;
14274 - if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
14276 - * CLKMODE_SYNC means that we want the DI to be
14277 - * clocked at the same rate as the parent clock.
14278 - * This is needed (eg) for LDB which needs to be
14279 - * fed with the same pixel clock. We assume that
14280 - * the LDB clock has already been set correctly.
14282 - clkgen0 = 1 << 4;
14285 - * We can use the divider. We should really have
14286 - * a flag here indicating whether the bridge can
14287 - * cope with a fractional divider or not. For the
14288 - * time being, let's go for simplicitly and
14291 - unsigned long in_rate;
14294 - clk_set_rate(clk, sig->mode.pixelclock);
14296 - in_rate = clk_get_rate(clk);
14297 - div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
14298 - div = clamp(div, 1U, 255U);
14300 - clkgen0 = div << 4;
14304 - * For other interfaces, we can arbitarily select between
14305 - * the DI specific clock and the internal IPU clock. See
14306 - * DI_GENERAL bit 20. We select the IPU clock if it can
14307 - * give us a clock rate within 1% of the requested frequency,
14308 - * otherwise we use the DI clock.
14310 - unsigned long rate, clkrate;
14311 - unsigned div, error;
14313 - clkrate = clk_get_rate(di->clk_ipu);
14314 - div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
14315 - div = clamp(div, 1U, 255U);
14316 - rate = clkrate / div;
14318 - error = rate / (sig->mode.pixelclock / 1000);
14320 - dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
14321 - rate, div, (signed)(error - 1000) / 10, error % 10);
14323 - /* Allow a 1% error */
14324 - if (error < 1010 && error >= 990) {
14325 - clk = di->clk_ipu;
14327 - clkgen0 = div << 4;
14329 - unsigned long in_rate;
14332 - clk = di->clk_di;
14334 - clk_set_rate(clk, sig->mode.pixelclock);
14336 - in_rate = clk_get_rate(clk);
14337 - div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
14338 - div = clamp(div, 1U, 255U);
14340 - clkgen0 = div << 4;
14344 - di->clk_di_pixel = clk;
14346 - /* Set the divider */
14347 - ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
14350 - * Set the high/low periods. Bits 24:16 give us the falling edge,
14351 - * and bits 8:0 give the rising edge. LSB is fraction, and is
14352 - * based on the divider above. We want a 50% duty cycle, so set
14353 - * the falling edge to be half the divider.
14355 - ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
14357 - /* Finally select the input clock */
14358 - val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
14359 - if (clk == di->clk_di)
14360 - val |= DI_GEN_DI_CLK_EXT;
14361 - ipu_di_write(di, val, DI_GENERAL);
14363 - dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
14364 - sig->mode.pixelclock,
14365 - clk_get_rate(di->clk_ipu),
14366 - clk_get_rate(di->clk_di),
14367 - clk == di->clk_di ? "DI" : "IPU",
14368 - clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
14372 - * This function is called to adjust a video mode to IPU restrictions.
14373 - * It is meant to be called from drm crtc mode_fixup() methods.
14375 -int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
14379 - if (mode->vfront_porch >= 2)
14382 - diff = 2 - mode->vfront_porch;
14384 - if (mode->vback_porch >= diff) {
14385 - mode->vfront_porch = 2;
14386 - mode->vback_porch -= diff;
14387 - } else if (mode->vsync_len > diff) {
14388 - mode->vfront_porch = 2;
14389 - mode->vsync_len = mode->vsync_len - diff;
14391 - dev_warn(di->ipu->dev, "failed to adjust videomode\n");
14395 - dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
14398 -EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
14400 -static u32 ipu_di_gen_polarity(int pin)
14404 - return DI_GEN_POLARITY_1;
14406 - return DI_GEN_POLARITY_2;
14408 - return DI_GEN_POLARITY_3;
14410 - return DI_GEN_POLARITY_4;
14412 - return DI_GEN_POLARITY_5;
14414 - return DI_GEN_POLARITY_6;
14416 - return DI_GEN_POLARITY_7;
14418 - return DI_GEN_POLARITY_8;
14423 -int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
14426 - u32 di_gen, vsync_cnt;
14429 - dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
14430 - di->id, sig->mode.hactive, sig->mode.vactive);
14432 - dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
14433 - clk_get_rate(di->clk_ipu),
14434 - clk_get_rate(di->clk_di),
14435 - sig->mode.pixelclock);
14437 - mutex_lock(&di_mutex);
14439 - ipu_di_config_clock(di, sig);
14441 - div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
14442 - div = div / 16; /* Now divider is integer portion */
14444 - /* Setup pixel clock timing */
14445 - /* Down time is half of period */
14446 - ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
14448 - ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
14449 - ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
14451 - di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
14452 - di_gen |= DI_GEN_DI_VSYNC_EXT;
14454 - if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
14455 - ipu_di_sync_config_interlaced(di, sig);
14457 - /* set y_sel = 1 */
14458 - di_gen |= 0x10000000;
14462 - ipu_di_sync_config_noninterlaced(di, sig, div);
14467 - * TODO: change only for TVEv2, parallel display
14470 - if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
14474 - if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
14475 - di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
14476 - if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
14477 - di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
14479 - if (sig->clk_pol)
14480 - di_gen |= DI_GEN_POLARITY_DISP_CLK;
14482 - ipu_di_write(di, di_gen, DI_GENERAL);
14484 - ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
14487 - reg = ipu_di_read(di, DI_POL);
14488 - reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
14490 - if (sig->enable_pol)
14491 - reg |= DI_POL_DRDY_POLARITY_15;
14492 - if (sig->data_pol)
14493 - reg |= DI_POL_DRDY_DATA_POLARITY;
14495 - ipu_di_write(di, reg, DI_POL);
14497 - mutex_unlock(&di_mutex);
14501 -EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
14503 -int ipu_di_enable(struct ipu_di *di)
14507 - WARN_ON(IS_ERR(di->clk_di_pixel));
14509 - ret = clk_prepare_enable(di->clk_di_pixel);
14513 - ipu_module_enable(di->ipu, di->module);
14517 -EXPORT_SYMBOL_GPL(ipu_di_enable);
14519 -int ipu_di_disable(struct ipu_di *di)
14521 - WARN_ON(IS_ERR(di->clk_di_pixel));
14523 - ipu_module_disable(di->ipu, di->module);
14525 - clk_disable_unprepare(di->clk_di_pixel);
14529 -EXPORT_SYMBOL_GPL(ipu_di_disable);
14531 -int ipu_di_get_num(struct ipu_di *di)
14535 -EXPORT_SYMBOL_GPL(ipu_di_get_num);
14537 -static DEFINE_MUTEX(ipu_di_lock);
14539 -struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
14541 - struct ipu_di *di;
14544 - return ERR_PTR(-EINVAL);
14546 - di = ipu->di_priv[disp];
14548 - mutex_lock(&ipu_di_lock);
14551 - di = ERR_PTR(-EBUSY);
14555 - di->inuse = true;
14557 - mutex_unlock(&ipu_di_lock);
14561 -EXPORT_SYMBOL_GPL(ipu_di_get);
14563 -void ipu_di_put(struct ipu_di *di)
14565 - mutex_lock(&ipu_di_lock);
14567 - di->inuse = false;
14569 - mutex_unlock(&ipu_di_lock);
14571 -EXPORT_SYMBOL_GPL(ipu_di_put);
14573 -int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
14574 - unsigned long base,
14575 - u32 module, struct clk *clk_ipu)
14577 - struct ipu_di *di;
14582 - di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
14586 - ipu->di_priv[id] = di;
14588 - di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
14589 - if (IS_ERR(di->clk_di))
14590 - return PTR_ERR(di->clk_di);
14592 - di->module = module;
14594 - di->clk_ipu = clk_ipu;
14595 - di->base = devm_ioremap(dev, base, PAGE_SIZE);
14599 - ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
14601 - dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
14602 - id, base, di->base);
14603 - di->inuse = false;
14609 -void ipu_di_exit(struct ipu_soc *ipu, int id)
14612 --- a/drivers/gpu/ipu-v3/ipu-dmfc.c
14615 -// SPDX-License-Identifier: GPL-2.0-or-later
14617 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
14618 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
14620 -#include <linux/export.h>
14621 -#include <linux/types.h>
14622 -#include <linux/errno.h>
14623 -#include <linux/io.h>
14625 -#include <video/imx-ipu-v3.h>
14626 -#include "ipu-prv.h"
14628 -#define DMFC_RD_CHAN 0x0000
14629 -#define DMFC_WR_CHAN 0x0004
14630 -#define DMFC_WR_CHAN_DEF 0x0008
14631 -#define DMFC_DP_CHAN 0x000c
14632 -#define DMFC_DP_CHAN_DEF 0x0010
14633 -#define DMFC_GENERAL1 0x0014
14634 -#define DMFC_GENERAL2 0x0018
14635 -#define DMFC_IC_CTRL 0x001c
14636 -#define DMFC_WR_CHAN_ALT 0x0020
14637 -#define DMFC_WR_CHAN_DEF_ALT 0x0024
14638 -#define DMFC_DP_CHAN_ALT 0x0028
14639 -#define DMFC_DP_CHAN_DEF_ALT 0x002c
14640 -#define DMFC_GENERAL1_ALT 0x0030
14641 -#define DMFC_STAT 0x0034
14643 -#define DMFC_WR_CHAN_1_28 0
14644 -#define DMFC_WR_CHAN_2_41 8
14645 -#define DMFC_WR_CHAN_1C_42 16
14646 -#define DMFC_WR_CHAN_2C_43 24
14648 -#define DMFC_DP_CHAN_5B_23 0
14649 -#define DMFC_DP_CHAN_5F_27 8
14650 -#define DMFC_DP_CHAN_6B_24 16
14651 -#define DMFC_DP_CHAN_6F_29 24
14653 -struct dmfc_channel_data {
14655 - unsigned long channel_reg;
14656 - unsigned long shift;
14657 - unsigned eot_shift;
14658 - unsigned max_fifo_lines;
14661 -static const struct dmfc_channel_data dmfcdata[] = {
14663 - .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
14664 - .channel_reg = DMFC_DP_CHAN,
14665 - .shift = DMFC_DP_CHAN_5B_23,
14667 - .max_fifo_lines = 3,
14669 - .ipu_channel = 24,
14670 - .channel_reg = DMFC_DP_CHAN,
14671 - .shift = DMFC_DP_CHAN_6B_24,
14673 - .max_fifo_lines = 1,
14675 - .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
14676 - .channel_reg = DMFC_DP_CHAN,
14677 - .shift = DMFC_DP_CHAN_5F_27,
14679 - .max_fifo_lines = 2,
14681 - .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
14682 - .channel_reg = DMFC_WR_CHAN,
14683 - .shift = DMFC_WR_CHAN_1_28,
14685 - .max_fifo_lines = 2,
14687 - .ipu_channel = 29,
14688 - .channel_reg = DMFC_DP_CHAN,
14689 - .shift = DMFC_DP_CHAN_6F_29,
14691 - .max_fifo_lines = 1,
14695 -#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
14697 -struct ipu_dmfc_priv;
14699 -struct dmfc_channel {
14701 - struct ipu_soc *ipu;
14702 - struct ipu_dmfc_priv *priv;
14703 - const struct dmfc_channel_data *data;
14706 -struct ipu_dmfc_priv {
14707 - struct ipu_soc *ipu;
14708 - struct device *dev;
14709 - struct dmfc_channel channels[DMFC_NUM_CHANNELS];
14710 - struct mutex mutex;
14711 - void __iomem *base;
14715 -int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
14717 - struct ipu_dmfc_priv *priv = dmfc->priv;
14718 - mutex_lock(&priv->mutex);
14720 - if (!priv->use_count)
14721 - ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
14723 - priv->use_count++;
14725 - mutex_unlock(&priv->mutex);
14729 -EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
14731 -void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
14733 - struct ipu_dmfc_priv *priv = dmfc->priv;
14735 - mutex_lock(&priv->mutex);
14737 - priv->use_count--;
14739 - if (!priv->use_count)
14740 - ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
14742 - if (priv->use_count < 0)
14743 - priv->use_count = 0;
14745 - mutex_unlock(&priv->mutex);
14747 -EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
14749 -void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
14751 - struct ipu_dmfc_priv *priv = dmfc->priv;
14754 - mutex_lock(&priv->mutex);
14756 - dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
14758 - if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
14759 - dmfc_gen1 |= 1 << dmfc->data->eot_shift;
14761 - dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
14763 - writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
14765 - mutex_unlock(&priv->mutex);
14767 -EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
14769 -struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
14771 - struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
14774 - for (i = 0; i < DMFC_NUM_CHANNELS; i++)
14775 - if (dmfcdata[i].ipu_channel == ipu_channel)
14776 - return &priv->channels[i];
14777 - return ERR_PTR(-ENODEV);
14779 -EXPORT_SYMBOL_GPL(ipu_dmfc_get);
14781 -void ipu_dmfc_put(struct dmfc_channel *dmfc)
14784 -EXPORT_SYMBOL_GPL(ipu_dmfc_put);
14786 -int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
14787 - struct clk *ipu_clk)
14789 - struct ipu_dmfc_priv *priv;
14792 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
14796 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
14802 - mutex_init(&priv->mutex);
14804 - ipu->dmfc_priv = priv;
14806 - for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
14807 - priv->channels[i].priv = priv;
14808 - priv->channels[i].ipu = ipu;
14809 - priv->channels[i].data = &dmfcdata[i];
14811 - if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
14812 - dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
14813 - dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
14814 - priv->channels[i].slots = 2;
14817 - writel(0x00000050, priv->base + DMFC_WR_CHAN);
14818 - writel(0x00005654, priv->base + DMFC_DP_CHAN);
14819 - writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
14820 - writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
14821 - writel(0x00000003, priv->base + DMFC_GENERAL1);
14826 -void ipu_dmfc_exit(struct ipu_soc *ipu)
14829 --- a/drivers/gpu/ipu-v3/ipu-dp.c
14832 -// SPDX-License-Identifier: GPL-2.0-or-later
14834 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
14835 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
14837 -#include <linux/export.h>
14838 -#include <linux/kernel.h>
14839 -#include <linux/types.h>
14840 -#include <linux/errno.h>
14841 -#include <linux/io.h>
14842 -#include <linux/err.h>
14844 -#include <video/imx-ipu-v3.h>
14845 -#include "ipu-prv.h"
14848 -#define DP_ASYNC0 0x60
14849 -#define DP_ASYNC1 0xBC
14851 -#define DP_COM_CONF 0x0
14852 -#define DP_GRAPH_WIND_CTRL 0x0004
14853 -#define DP_FG_POS 0x0008
14854 -#define DP_CSC_A_0 0x0044
14855 -#define DP_CSC_A_1 0x0048
14856 -#define DP_CSC_A_2 0x004C
14857 -#define DP_CSC_A_3 0x0050
14858 -#define DP_CSC_0 0x0054
14859 -#define DP_CSC_1 0x0058
14861 -#define DP_COM_CONF_FG_EN (1 << 0)
14862 -#define DP_COM_CONF_GWSEL (1 << 1)
14863 -#define DP_COM_CONF_GWAM (1 << 2)
14864 -#define DP_COM_CONF_GWCKE (1 << 3)
14865 -#define DP_COM_CONF_CSC_DEF_MASK (3 << 8)
14866 -#define DP_COM_CONF_CSC_DEF_OFFSET 8
14867 -#define DP_COM_CONF_CSC_DEF_FG (3 << 8)
14868 -#define DP_COM_CONF_CSC_DEF_BG (2 << 8)
14869 -#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8)
14871 -#define IPUV3_NUM_FLOWS 3
14873 -struct ipu_dp_priv;
14879 - enum ipu_color_space in_cs;
14883 - struct ipu_dp foreground;
14884 - struct ipu_dp background;
14885 - enum ipu_color_space out_cs;
14886 - void __iomem *base;
14887 - struct ipu_dp_priv *priv;
14890 -struct ipu_dp_priv {
14891 - struct ipu_soc *ipu;
14892 - struct device *dev;
14893 - void __iomem *base;
14894 - struct ipu_flow flow[IPUV3_NUM_FLOWS];
14895 - struct mutex mutex;
14899 -static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
14901 -static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
14903 - if (dp->foreground)
14904 - return container_of(dp, struct ipu_flow, foreground);
14906 - return container_of(dp, struct ipu_flow, background);
14909 -int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
14910 - u8 alpha, bool bg_chan)
14912 - struct ipu_flow *flow = to_flow(dp);
14913 - struct ipu_dp_priv *priv = flow->priv;
14916 - mutex_lock(&priv->mutex);
14918 - reg = readl(flow->base + DP_COM_CONF);
14920 - reg &= ~DP_COM_CONF_GWSEL;
14922 - reg |= DP_COM_CONF_GWSEL;
14923 - writel(reg, flow->base + DP_COM_CONF);
14926 - reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
14927 - writel(reg | ((u32) alpha << 24),
14928 - flow->base + DP_GRAPH_WIND_CTRL);
14930 - reg = readl(flow->base + DP_COM_CONF);
14931 - writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
14933 - reg = readl(flow->base + DP_COM_CONF);
14934 - writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
14937 - ipu_srm_dp_update(priv->ipu, true);
14939 - mutex_unlock(&priv->mutex);
14943 -EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
14945 -int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
14947 - struct ipu_flow *flow = to_flow(dp);
14948 - struct ipu_dp_priv *priv = flow->priv;
14950 - writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
14952 - ipu_srm_dp_update(priv->ipu, true);
14956 -EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
14958 -static void ipu_dp_csc_init(struct ipu_flow *flow,
14959 - enum ipu_color_space in,
14960 - enum ipu_color_space out,
14965 - reg = readl(flow->base + DP_COM_CONF);
14966 - reg &= ~DP_COM_CONF_CSC_DEF_MASK;
14969 - writel(reg, flow->base + DP_COM_CONF);
14973 - if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
14974 - writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
14975 - writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
14976 - writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
14977 - writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
14978 - writel(0x3d6 | (0x0000 << 16) | (2 << 30),
14979 - flow->base + DP_CSC_0);
14980 - writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
14981 - flow->base + DP_CSC_1);
14983 - writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
14984 - writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
14985 - writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
14986 - writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
14987 - writel(0x000 | (0x3e42 << 16) | (1 << 30),
14988 - flow->base + DP_CSC_0);
14989 - writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
14990 - flow->base + DP_CSC_1);
14995 - writel(reg, flow->base + DP_COM_CONF);
14998 -int ipu_dp_setup_channel(struct ipu_dp *dp,
14999 - enum ipu_color_space in,
15000 - enum ipu_color_space out)
15002 - struct ipu_flow *flow = to_flow(dp);
15003 - struct ipu_dp_priv *priv = flow->priv;
15005 - mutex_lock(&priv->mutex);
15009 - if (!dp->foreground)
15010 - flow->out_cs = out;
15012 - if (flow->foreground.in_cs == flow->background.in_cs) {
15014 - * foreground and background are of same colorspace, put
15015 - * colorspace converter after combining unit.
15017 - ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
15018 - DP_COM_CONF_CSC_DEF_BOTH);
15020 - if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
15021 - flow->foreground.in_cs == flow->out_cs)
15023 - * foreground identical to output, apply color
15024 - * conversion on background
15026 - ipu_dp_csc_init(flow, flow->background.in_cs,
15027 - flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
15029 - ipu_dp_csc_init(flow, flow->foreground.in_cs,
15030 - flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
15033 - ipu_srm_dp_update(priv->ipu, true);
15035 - mutex_unlock(&priv->mutex);
15039 -EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
15041 -int ipu_dp_enable(struct ipu_soc *ipu)
15043 - struct ipu_dp_priv *priv = ipu->dp_priv;
15045 - mutex_lock(&priv->mutex);
15047 - if (!priv->use_count)
15048 - ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
15050 - priv->use_count++;
15052 - mutex_unlock(&priv->mutex);
15056 -EXPORT_SYMBOL_GPL(ipu_dp_enable);
15058 -int ipu_dp_enable_channel(struct ipu_dp *dp)
15060 - struct ipu_flow *flow = to_flow(dp);
15061 - struct ipu_dp_priv *priv = flow->priv;
15064 - if (!dp->foreground)
15067 - mutex_lock(&priv->mutex);
15069 - reg = readl(flow->base + DP_COM_CONF);
15070 - reg |= DP_COM_CONF_FG_EN;
15071 - writel(reg, flow->base + DP_COM_CONF);
15073 - ipu_srm_dp_update(priv->ipu, true);
15075 - mutex_unlock(&priv->mutex);
15079 -EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
15081 -void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
15083 - struct ipu_flow *flow = to_flow(dp);
15084 - struct ipu_dp_priv *priv = flow->priv;
15087 - dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
15089 - if (!dp->foreground)
15092 - mutex_lock(&priv->mutex);
15094 - reg = readl(flow->base + DP_COM_CONF);
15095 - csc = reg & DP_COM_CONF_CSC_DEF_MASK;
15096 - reg &= ~DP_COM_CONF_CSC_DEF_MASK;
15097 - if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
15098 - reg |= DP_COM_CONF_CSC_DEF_BG;
15100 - reg &= ~DP_COM_CONF_FG_EN;
15101 - writel(reg, flow->base + DP_COM_CONF);
15103 - writel(0, flow->base + DP_FG_POS);
15104 - ipu_srm_dp_update(priv->ipu, sync);
15106 - mutex_unlock(&priv->mutex);
15108 -EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
15110 -void ipu_dp_disable(struct ipu_soc *ipu)
15112 - struct ipu_dp_priv *priv = ipu->dp_priv;
15114 - mutex_lock(&priv->mutex);
15116 - priv->use_count--;
15118 - if (!priv->use_count)
15119 - ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
15121 - if (priv->use_count < 0)
15122 - priv->use_count = 0;
15124 - mutex_unlock(&priv->mutex);
15126 -EXPORT_SYMBOL_GPL(ipu_dp_disable);
15128 -struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
15130 - struct ipu_dp_priv *priv = ipu->dp_priv;
15131 - struct ipu_dp *dp;
15133 - if ((flow >> 1) >= IPUV3_NUM_FLOWS)
15134 - return ERR_PTR(-EINVAL);
15137 - dp = &priv->flow[flow >> 1].foreground;
15139 - dp = &priv->flow[flow >> 1].background;
15142 - return ERR_PTR(-EBUSY);
15144 - dp->in_use = true;
15148 -EXPORT_SYMBOL_GPL(ipu_dp_get);
15150 -void ipu_dp_put(struct ipu_dp *dp)
15152 - dp->in_use = false;
15154 -EXPORT_SYMBOL_GPL(ipu_dp_put);
15156 -int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
15158 - struct ipu_dp_priv *priv;
15161 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
15167 - ipu->dp_priv = priv;
15169 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
15173 - mutex_init(&priv->mutex);
15175 - for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
15176 - priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
15177 - priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
15178 - priv->flow[i].foreground.foreground = true;
15179 - priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
15180 - priv->flow[i].priv = priv;
15186 -void ipu_dp_exit(struct ipu_soc *ipu)
15189 --- a/drivers/gpu/ipu-v3/ipu-ic.c
15192 -// SPDX-License-Identifier: GPL-2.0-or-later
15194 - * Copyright (C) 2012-2014 Mentor Graphics Inc.
15195 - * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
15198 -#include <linux/types.h>
15199 -#include <linux/init.h>
15200 -#include <linux/errno.h>
15201 -#include <linux/spinlock.h>
15202 -#include <linux/bitrev.h>
15203 -#include <linux/io.h>
15204 -#include <linux/err.h>
15205 -#include <linux/sizes.h>
15206 -#include "ipu-prv.h"
15208 -/* IC Register Offsets */
15209 -#define IC_CONF 0x0000
15210 -#define IC_PRP_ENC_RSC 0x0004
15211 -#define IC_PRP_VF_RSC 0x0008
15212 -#define IC_PP_RSC 0x000C
15213 -#define IC_CMBP_1 0x0010
15214 -#define IC_CMBP_2 0x0014
15215 -#define IC_IDMAC_1 0x0018
15216 -#define IC_IDMAC_2 0x001C
15217 -#define IC_IDMAC_3 0x0020
15218 -#define IC_IDMAC_4 0x0024
15220 -/* IC Register Fields */
15221 -#define IC_CONF_PRPENC_EN (1 << 0)
15222 -#define IC_CONF_PRPENC_CSC1 (1 << 1)
15223 -#define IC_CONF_PRPENC_ROT_EN (1 << 2)
15224 -#define IC_CONF_PRPVF_EN (1 << 8)
15225 -#define IC_CONF_PRPVF_CSC1 (1 << 9)
15226 -#define IC_CONF_PRPVF_CSC2 (1 << 10)
15227 -#define IC_CONF_PRPVF_CMB (1 << 11)
15228 -#define IC_CONF_PRPVF_ROT_EN (1 << 12)
15229 -#define IC_CONF_PP_EN (1 << 16)
15230 -#define IC_CONF_PP_CSC1 (1 << 17)
15231 -#define IC_CONF_PP_CSC2 (1 << 18)
15232 -#define IC_CONF_PP_CMB (1 << 19)
15233 -#define IC_CONF_PP_ROT_EN (1 << 20)
15234 -#define IC_CONF_IC_GLB_LOC_A (1 << 28)
15235 -#define IC_CONF_KEY_COLOR_EN (1 << 29)
15236 -#define IC_CONF_RWS_EN (1 << 30)
15237 -#define IC_CONF_CSI_MEM_WR_EN (1 << 31)
15239 -#define IC_IDMAC_1_CB0_BURST_16 (1 << 0)
15240 -#define IC_IDMAC_1_CB1_BURST_16 (1 << 1)
15241 -#define IC_IDMAC_1_CB2_BURST_16 (1 << 2)
15242 -#define IC_IDMAC_1_CB3_BURST_16 (1 << 3)
15243 -#define IC_IDMAC_1_CB4_BURST_16 (1 << 4)
15244 -#define IC_IDMAC_1_CB5_BURST_16 (1 << 5)
15245 -#define IC_IDMAC_1_CB6_BURST_16 (1 << 6)
15246 -#define IC_IDMAC_1_CB7_BURST_16 (1 << 7)
15247 -#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11)
15248 -#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11
15249 -#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14)
15250 -#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14
15251 -#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17)
15252 -#define IC_IDMAC_1_PP_ROT_OFFSET 17
15253 -#define IC_IDMAC_1_PP_FLIP_RS (1 << 22)
15254 -#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21)
15255 -#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20)
15257 -#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0)
15258 -#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
15259 -#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10)
15260 -#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10
15261 -#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20)
15262 -#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20
15264 -#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0)
15265 -#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0
15266 -#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10)
15267 -#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10
15268 -#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20)
15269 -#define IC_IDMAC_3_PP_WIDTH_OFFSET 20
15271 -struct ic_task_regoffs {
15273 - u32 tpmem_csc[2];
15276 -struct ic_task_bitfields {
15278 - u32 ic_conf_rot_en;
15279 - u32 ic_conf_cmb_en;
15280 - u32 ic_conf_csc1_en;
15281 - u32 ic_conf_csc2_en;
15282 - u32 ic_cmb_galpha_bit;
15285 -static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
15286 - [IC_TASK_ENCODER] = {
15287 - .rsc = IC_PRP_ENC_RSC,
15288 - .tpmem_csc = {0x2008, 0},
15290 - [IC_TASK_VIEWFINDER] = {
15291 - .rsc = IC_PRP_VF_RSC,
15292 - .tpmem_csc = {0x4028, 0x4040},
15294 - [IC_TASK_POST_PROCESSOR] = {
15295 - .rsc = IC_PP_RSC,
15296 - .tpmem_csc = {0x6060, 0x6078},
15300 -static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
15301 - [IC_TASK_ENCODER] = {
15302 - .ic_conf_en = IC_CONF_PRPENC_EN,
15303 - .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
15304 - .ic_conf_cmb_en = 0, /* NA */
15305 - .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
15306 - .ic_conf_csc2_en = 0, /* NA */
15307 - .ic_cmb_galpha_bit = 0, /* NA */
15309 - [IC_TASK_VIEWFINDER] = {
15310 - .ic_conf_en = IC_CONF_PRPVF_EN,
15311 - .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
15312 - .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
15313 - .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
15314 - .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
15315 - .ic_cmb_galpha_bit = 0,
15317 - [IC_TASK_POST_PROCESSOR] = {
15318 - .ic_conf_en = IC_CONF_PP_EN,
15319 - .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
15320 - .ic_conf_cmb_en = IC_CONF_PP_CMB,
15321 - .ic_conf_csc1_en = IC_CONF_PP_CSC1,
15322 - .ic_conf_csc2_en = IC_CONF_PP_CSC2,
15323 - .ic_cmb_galpha_bit = 8,
15327 -struct ipu_ic_priv;
15330 - enum ipu_ic_task task;
15331 - const struct ic_task_regoffs *reg;
15332 - const struct ic_task_bitfields *bit;
15334 - struct ipu_ic_colorspace in_cs;
15335 - struct ipu_ic_colorspace g_in_cs;
15336 - struct ipu_ic_colorspace out_cs;
15342 - struct ipu_ic_priv *priv;
15345 -struct ipu_ic_priv {
15346 - void __iomem *base;
15347 - void __iomem *tpmem_base;
15349 - struct ipu_soc *ipu;
15351 - int irt_use_count;
15352 - struct ipu_ic task[IC_NUM_TASKS];
15355 -static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
15357 - return readl(ic->priv->base + offset);
15360 -static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
15362 - writel(value, ic->priv->base + offset);
15365 -static int init_csc(struct ipu_ic *ic,
15366 - const struct ipu_ic_csc *csc,
15369 - struct ipu_ic_priv *priv = ic->priv;
15370 - u32 __iomem *base;
15371 - const u16 (*c)[3];
15375 - base = (u32 __iomem *)
15376 - (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
15378 - /* Cast to unsigned */
15379 - c = (const u16 (*)[3])csc->params.coeff;
15380 - a = (const u16 *)csc->params.offset;
15382 - param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
15383 - ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
15384 - writel(param, base++);
15386 - param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
15387 - (csc->params.sat << 10);
15388 - writel(param, base++);
15390 - param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
15391 - ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
15392 - writel(param, base++);
15394 - param = ((a[1] & 0x1fe0) >> 5);
15395 - writel(param, base++);
15397 - param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
15398 - ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
15399 - writel(param, base++);
15401 - param = ((a[2] & 0x1fe0) >> 5);
15402 - writel(param, base++);
15407 -static int calc_resize_coeffs(struct ipu_ic *ic,
15408 - u32 in_size, u32 out_size,
15409 - u32 *resize_coeff,
15410 - u32 *downsize_coeff)
15412 - struct ipu_ic_priv *priv = ic->priv;
15413 - struct ipu_soc *ipu = priv->ipu;
15414 - u32 temp_size, temp_downsize;
15417 - * Input size cannot be more than 4096, and output size cannot
15418 - * be more than 1024
15420 - if (in_size > 4096) {
15421 - dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
15424 - if (out_size > 1024) {
15425 - dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
15429 - /* Cannot downsize more than 4:1 */
15430 - if ((out_size << 2) < in_size) {
15431 - dev_err(ipu->dev, "Unsupported downsize\n");
15435 - /* Compute downsizing coefficient */
15436 - temp_downsize = 0;
15437 - temp_size = in_size;
15438 - while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
15439 - (temp_downsize < 2)) {
15443 - *downsize_coeff = temp_downsize;
15446 - * compute resizing coefficient using the following equation:
15447 - * resize_coeff = M * (SI - 1) / (SO - 1)
15448 - * where M = 2^13, SI = input size, SO = output size
15450 - *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
15451 - if (*resize_coeff >= 16384L) {
15452 - dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
15453 - *resize_coeff = 0x3FFF;
15459 -void ipu_ic_task_enable(struct ipu_ic *ic)
15461 - struct ipu_ic_priv *priv = ic->priv;
15462 - unsigned long flags;
15465 - spin_lock_irqsave(&priv->lock, flags);
15467 - ic_conf = ipu_ic_read(ic, IC_CONF);
15469 - ic_conf |= ic->bit->ic_conf_en;
15471 - if (ic->rotation)
15472 - ic_conf |= ic->bit->ic_conf_rot_en;
15474 - if (ic->in_cs.cs != ic->out_cs.cs)
15475 - ic_conf |= ic->bit->ic_conf_csc1_en;
15477 - if (ic->graphics) {
15478 - ic_conf |= ic->bit->ic_conf_cmb_en;
15479 - ic_conf |= ic->bit->ic_conf_csc1_en;
15481 - if (ic->g_in_cs.cs != ic->out_cs.cs)
15482 - ic_conf |= ic->bit->ic_conf_csc2_en;
15485 - ipu_ic_write(ic, ic_conf, IC_CONF);
15487 - spin_unlock_irqrestore(&priv->lock, flags);
15489 -EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
15491 -void ipu_ic_task_disable(struct ipu_ic *ic)
15493 - struct ipu_ic_priv *priv = ic->priv;
15494 - unsigned long flags;
15497 - spin_lock_irqsave(&priv->lock, flags);
15499 - ic_conf = ipu_ic_read(ic, IC_CONF);
15501 - ic_conf &= ~(ic->bit->ic_conf_en |
15502 - ic->bit->ic_conf_csc1_en |
15503 - ic->bit->ic_conf_rot_en);
15504 - if (ic->bit->ic_conf_csc2_en)
15505 - ic_conf &= ~ic->bit->ic_conf_csc2_en;
15506 - if (ic->bit->ic_conf_cmb_en)
15507 - ic_conf &= ~ic->bit->ic_conf_cmb_en;
15509 - ipu_ic_write(ic, ic_conf, IC_CONF);
15511 - spin_unlock_irqrestore(&priv->lock, flags);
15513 -EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
15515 -int ipu_ic_task_graphics_init(struct ipu_ic *ic,
15516 - const struct ipu_ic_colorspace *g_in_cs,
15517 - bool galpha_en, u32 galpha,
15518 - bool colorkey_en, u32 colorkey)
15520 - struct ipu_ic_priv *priv = ic->priv;
15521 - struct ipu_ic_csc csc2;
15522 - unsigned long flags;
15523 - u32 reg, ic_conf;
15526 - if (ic->task == IC_TASK_ENCODER)
15529 - spin_lock_irqsave(&priv->lock, flags);
15531 - ic_conf = ipu_ic_read(ic, IC_CONF);
15533 - if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
15534 - struct ipu_ic_csc csc1;
15536 - ret = ipu_ic_calc_csc(&csc1,
15537 - V4L2_YCBCR_ENC_601,
15538 - V4L2_QUANTIZATION_FULL_RANGE,
15539 - IPUV3_COLORSPACE_RGB,
15540 - V4L2_YCBCR_ENC_601,
15541 - V4L2_QUANTIZATION_FULL_RANGE,
15542 - IPUV3_COLORSPACE_RGB);
15546 - /* need transparent CSC1 conversion */
15547 - ret = init_csc(ic, &csc1, 0);
15552 - ic->g_in_cs = *g_in_cs;
15553 - csc2.in_cs = ic->g_in_cs;
15554 - csc2.out_cs = ic->out_cs;
15556 - ret = __ipu_ic_calc_csc(&csc2);
15560 - ret = init_csc(ic, &csc2, 1);
15565 - ic_conf |= IC_CONF_IC_GLB_LOC_A;
15566 - reg = ipu_ic_read(ic, IC_CMBP_1);
15567 - reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
15568 - reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
15569 - ipu_ic_write(ic, reg, IC_CMBP_1);
15571 - ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
15573 - if (colorkey_en) {
15574 - ic_conf |= IC_CONF_KEY_COLOR_EN;
15575 - ipu_ic_write(ic, colorkey, IC_CMBP_2);
15577 - ic_conf &= ~IC_CONF_KEY_COLOR_EN;
15579 - ipu_ic_write(ic, ic_conf, IC_CONF);
15581 - ic->graphics = true;
15583 - spin_unlock_irqrestore(&priv->lock, flags);
15586 -EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
15588 -int ipu_ic_task_init_rsc(struct ipu_ic *ic,
15589 - const struct ipu_ic_csc *csc,
15590 - int in_width, int in_height,
15591 - int out_width, int out_height,
15594 - struct ipu_ic_priv *priv = ic->priv;
15595 - u32 downsize_coeff, resize_coeff;
15596 - unsigned long flags;
15600 - /* Setup vertical resizing */
15602 - ret = calc_resize_coeffs(ic, in_height, out_height,
15603 - &resize_coeff, &downsize_coeff);
15607 - rsc = (downsize_coeff << 30) | (resize_coeff << 16);
15609 - /* Setup horizontal resizing */
15610 - ret = calc_resize_coeffs(ic, in_width, out_width,
15611 - &resize_coeff, &downsize_coeff);
15615 - rsc |= (downsize_coeff << 14) | resize_coeff;
15618 - spin_lock_irqsave(&priv->lock, flags);
15620 - ipu_ic_write(ic, rsc, ic->reg->rsc);
15622 - /* Setup color space conversion */
15623 - ic->in_cs = csc->in_cs;
15624 - ic->out_cs = csc->out_cs;
15626 - ret = init_csc(ic, csc, 0);
15628 - spin_unlock_irqrestore(&priv->lock, flags);
15632 -int ipu_ic_task_init(struct ipu_ic *ic,
15633 - const struct ipu_ic_csc *csc,
15634 - int in_width, int in_height,
15635 - int out_width, int out_height)
15637 - return ipu_ic_task_init_rsc(ic, csc,
15638 - in_width, in_height,
15639 - out_width, out_height, 0);
15641 -EXPORT_SYMBOL_GPL(ipu_ic_task_init);
15643 -int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
15644 - u32 width, u32 height, int burst_size,
15645 - enum ipu_rotate_mode rot)
15647 - struct ipu_ic_priv *priv = ic->priv;
15648 - struct ipu_soc *ipu = priv->ipu;
15649 - u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
15650 - u32 temp_rot = bitrev8(rot) >> 5;
15651 - bool need_hor_flip = false;
15652 - unsigned long flags;
15655 - if ((burst_size != 8) && (burst_size != 16)) {
15656 - dev_err(ipu->dev, "Illegal burst length for IC\n");
15663 - if (temp_rot & 0x2) /* Need horizontal flip */
15664 - need_hor_flip = true;
15666 - spin_lock_irqsave(&priv->lock, flags);
15668 - ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
15669 - ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
15670 - ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
15672 - switch (channel->num) {
15673 - case IPUV3_CHANNEL_IC_PP_MEM:
15674 - if (burst_size == 16)
15675 - ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
15677 - ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
15679 - if (need_hor_flip)
15680 - ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
15682 - ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
15684 - ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
15685 - ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
15687 - ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
15688 - ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
15690 - case IPUV3_CHANNEL_MEM_IC_PP:
15691 - if (burst_size == 16)
15692 - ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
15694 - ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
15696 - case IPUV3_CHANNEL_MEM_ROT_PP:
15697 - ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
15698 - ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
15700 - case IPUV3_CHANNEL_MEM_IC_PRP_VF:
15701 - if (burst_size == 16)
15702 - ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
15704 - ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
15706 - case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
15707 - if (burst_size == 16)
15708 - ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
15710 - ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
15712 - if (need_hor_flip)
15713 - ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
15715 - ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
15717 - ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
15718 - ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
15720 - ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
15721 - ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
15723 - case IPUV3_CHANNEL_MEM_ROT_ENC:
15724 - ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
15725 - ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
15727 - case IPUV3_CHANNEL_IC_PRP_VF_MEM:
15728 - if (burst_size == 16)
15729 - ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
15731 - ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
15733 - if (need_hor_flip)
15734 - ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
15736 - ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
15738 - ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
15739 - ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
15741 - ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
15742 - ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
15744 - case IPUV3_CHANNEL_MEM_ROT_VF:
15745 - ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
15746 - ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
15748 - case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
15749 - if (burst_size == 16)
15750 - ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
15752 - ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
15754 - case IPUV3_CHANNEL_G_MEM_IC_PP:
15755 - if (burst_size == 16)
15756 - ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
15758 - ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
15760 - case IPUV3_CHANNEL_VDI_MEM_IC_VF:
15761 - if (burst_size == 16)
15762 - ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
15764 - ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
15770 - ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
15771 - ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
15772 - ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
15774 - if (ipu_rot_mode_is_irt(rot))
15775 - ic->rotation = true;
15778 - spin_unlock_irqrestore(&priv->lock, flags);
15781 -EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
15783 -static void ipu_irt_enable(struct ipu_ic *ic)
15785 - struct ipu_ic_priv *priv = ic->priv;
15787 - if (!priv->irt_use_count)
15788 - ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
15790 - priv->irt_use_count++;
15793 -static void ipu_irt_disable(struct ipu_ic *ic)
15795 - struct ipu_ic_priv *priv = ic->priv;
15797 - if (priv->irt_use_count) {
15798 - if (!--priv->irt_use_count)
15799 - ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
15803 -int ipu_ic_enable(struct ipu_ic *ic)
15805 - struct ipu_ic_priv *priv = ic->priv;
15806 - unsigned long flags;
15808 - spin_lock_irqsave(&priv->lock, flags);
15810 - if (!priv->use_count)
15811 - ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
15813 - priv->use_count++;
15815 - if (ic->rotation)
15816 - ipu_irt_enable(ic);
15818 - spin_unlock_irqrestore(&priv->lock, flags);
15822 -EXPORT_SYMBOL_GPL(ipu_ic_enable);
15824 -int ipu_ic_disable(struct ipu_ic *ic)
15826 - struct ipu_ic_priv *priv = ic->priv;
15827 - unsigned long flags;
15829 - spin_lock_irqsave(&priv->lock, flags);
15831 - priv->use_count--;
15833 - if (!priv->use_count)
15834 - ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
15836 - if (priv->use_count < 0)
15837 - priv->use_count = 0;
15839 - if (ic->rotation)
15840 - ipu_irt_disable(ic);
15842 - ic->rotation = ic->graphics = false;
15844 - spin_unlock_irqrestore(&priv->lock, flags);
15848 -EXPORT_SYMBOL_GPL(ipu_ic_disable);
15850 -struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
15852 - struct ipu_ic_priv *priv = ipu->ic_priv;
15853 - unsigned long flags;
15854 - struct ipu_ic *ic, *ret;
15856 - if (task >= IC_NUM_TASKS)
15857 - return ERR_PTR(-EINVAL);
15859 - ic = &priv->task[task];
15861 - spin_lock_irqsave(&priv->lock, flags);
15863 - if (ic->in_use) {
15864 - ret = ERR_PTR(-EBUSY);
15868 - ic->in_use = true;
15872 - spin_unlock_irqrestore(&priv->lock, flags);
15875 -EXPORT_SYMBOL_GPL(ipu_ic_get);
15877 -void ipu_ic_put(struct ipu_ic *ic)
15879 - struct ipu_ic_priv *priv = ic->priv;
15880 - unsigned long flags;
15882 - spin_lock_irqsave(&priv->lock, flags);
15883 - ic->in_use = false;
15884 - spin_unlock_irqrestore(&priv->lock, flags);
15886 -EXPORT_SYMBOL_GPL(ipu_ic_put);
15888 -int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
15889 - unsigned long base, unsigned long tpmem_base)
15891 - struct ipu_ic_priv *priv;
15894 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
15898 - ipu->ic_priv = priv;
15900 - spin_lock_init(&priv->lock);
15901 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
15904 - priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
15905 - if (!priv->tpmem_base)
15908 - dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
15912 - for (i = 0; i < IC_NUM_TASKS; i++) {
15913 - priv->task[i].task = i;
15914 - priv->task[i].priv = priv;
15915 - priv->task[i].reg = &ic_task_reg[i];
15916 - priv->task[i].bit = &ic_task_bit[i];
15922 -void ipu_ic_exit(struct ipu_soc *ipu)
15926 -void ipu_ic_dump(struct ipu_ic *ic)
15928 - struct ipu_ic_priv *priv = ic->priv;
15929 - struct ipu_soc *ipu = priv->ipu;
15931 - dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
15932 - ipu_ic_read(ic, IC_CONF));
15933 - dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
15934 - ipu_ic_read(ic, IC_PRP_ENC_RSC));
15935 - dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
15936 - ipu_ic_read(ic, IC_PRP_VF_RSC));
15937 - dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
15938 - ipu_ic_read(ic, IC_PP_RSC));
15939 - dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
15940 - ipu_ic_read(ic, IC_CMBP_1));
15941 - dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
15942 - ipu_ic_read(ic, IC_CMBP_2));
15943 - dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
15944 - ipu_ic_read(ic, IC_IDMAC_1));
15945 - dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
15946 - ipu_ic_read(ic, IC_IDMAC_2));
15947 - dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
15948 - ipu_ic_read(ic, IC_IDMAC_3));
15949 - dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
15950 - ipu_ic_read(ic, IC_IDMAC_4));
15952 -EXPORT_SYMBOL_GPL(ipu_ic_dump);
15953 --- a/drivers/gpu/ipu-v3/ipu-image-convert.c
15956 -// SPDX-License-Identifier: GPL-2.0-or-later
15958 - * Copyright (C) 2012-2016 Mentor Graphics Inc.
15960 - * Queued image conversion support, with tiling and rotation.
15963 -#include <linux/interrupt.h>
15964 -#include <linux/dma-mapping.h>
15965 -#include <video/imx-ipu-image-convert.h>
15966 -#include "ipu-prv.h"
15969 - * The IC Resizer has a restriction that the output frame from the
15970 - * resizer must be 1024 or less in both width (pixels) and height
15973 - * The image converter attempts to split up a conversion when
15974 - * the desired output (converted) frame resolution exceeds the
15975 - * IC resizer limit of 1024 in either dimension.
15977 - * If either dimension of the output frame exceeds the limit, the
15978 - * dimension is split into 1, 2, or 4 equal stripes, for a maximum
15979 - * of 4*4 or 16 tiles. A conversion is then carried out for each
15980 - * tile (but taking care to pass the full frame stride length to
15981 - * the DMA channel's parameter memory!). IDMA double-buffering is used
15982 - * to convert each tile back-to-back when possible (see note below
15983 - * when double_buffering boolean is set).
15985 - * Note that the input frame must be split up into the same number
15986 - * of tiles as the output frame:
15988 - * +---------+-----+
15989 - * +-----+---+ | A | B |
15990 - * | A | B | | | |
15991 - * +-----+---+ --> +---------+-----+
15992 - * | C | D | | C | D |
15993 - * +-----+---+ | | |
15994 - * +---------+-----+
15996 - * Clockwise 90° rotations are handled by first rescaling into a
15997 - * reusable temporary tile buffer and then rotating with the 8x8
15998 - * block rotator, writing to the correct destination:
16002 - * +-----+---+ +---------+ | C | A |
16003 - * | A | B | | A,B, | | | | |
16004 - * +-----+---+ --> | C,D | | --> | | |
16005 - * | C | D | +---------+ +-----+-----+
16006 - * +-----+---+ | D | B |
16010 - * If the 8x8 block rotator is used, horizontal or vertical flipping
16011 - * is done during the rotation step, otherwise flipping is done
16012 - * during the scaling step.
16013 - * With rotation or flipping, tile order changes between input and
16014 - * output image. Tiles are numbered row major from top left to bottom
16015 - * right for both input and output image.
16018 -#define MAX_STRIPES_W 4
16019 -#define MAX_STRIPES_H 4
16020 -#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
16024 -#define MAX_W 4096
16025 -#define MAX_H 4096
16027 -enum ipu_image_convert_type {
16028 - IMAGE_CONVERT_IN = 0,
16029 - IMAGE_CONVERT_OUT,
16032 -struct ipu_image_convert_dma_buf {
16035 - unsigned long len;
16038 -struct ipu_image_convert_dma_chan {
16048 -/* dimensions of one tile */
16049 -struct ipu_image_tile {
16054 - /* size and strides are in bytes */
16058 - /* start Y or packed offset of this tile */
16060 - /* offset from start to tile in U plane, for planar formats */
16062 - /* offset from start to tile in V plane, for planar formats */
16066 -struct ipu_image_convert_image {
16067 - struct ipu_image base;
16068 - enum ipu_image_convert_type type;
16070 - const struct ipu_image_pixfmt *fmt;
16071 - unsigned int stride;
16073 - /* # of rows (horizontal stripes) if dest height is > 1024 */
16074 - unsigned int num_rows;
16075 - /* # of columns (vertical stripes) if dest width is > 1024 */
16076 - unsigned int num_cols;
16078 - struct ipu_image_tile tile[MAX_TILES];
16081 -struct ipu_image_pixfmt {
16082 - u32 fourcc; /* V4L2 fourcc */
16083 - int bpp; /* total bpp */
16084 - int uv_width_dec; /* decimation in width for U/V planes */
16085 - int uv_height_dec; /* decimation in height for U/V planes */
16086 - bool planar; /* planar format */
16087 - bool uv_swapped; /* U and V planes are swapped */
16088 - bool uv_packed; /* partial planar (U and V in same plane) */
16091 -struct ipu_image_convert_ctx;
16092 -struct ipu_image_convert_chan;
16093 -struct ipu_image_convert_priv;
16095 -struct ipu_image_convert_ctx {
16096 - struct ipu_image_convert_chan *chan;
16098 - ipu_image_convert_cb_t complete;
16099 - void *complete_context;
16101 - /* Source/destination image data and rotation mode */
16102 - struct ipu_image_convert_image in;
16103 - struct ipu_image_convert_image out;
16104 - struct ipu_ic_csc csc;
16105 - enum ipu_rotate_mode rot_mode;
16106 - u32 downsize_coeff_h;
16107 - u32 downsize_coeff_v;
16108 - u32 image_resize_coeff_h;
16109 - u32 image_resize_coeff_v;
16110 - u32 resize_coeffs_h[MAX_STRIPES_W];
16111 - u32 resize_coeffs_v[MAX_STRIPES_H];
16113 - /* intermediate buffer for rotation */
16114 - struct ipu_image_convert_dma_buf rot_intermediate[2];
16116 - /* current buffer number for double buffering */
16120 - struct completion aborted;
16122 - /* can we use double-buffering for this conversion operation? */
16123 - bool double_buffering;
16124 - /* num_rows * num_cols */
16125 - unsigned int num_tiles;
16126 - /* next tile to process */
16127 - unsigned int next_tile;
16128 - /* where to place converted tile in dest image */
16129 - unsigned int out_tile_map[MAX_TILES];
16131 - struct list_head list;
16134 -struct ipu_image_convert_chan {
16135 - struct ipu_image_convert_priv *priv;
16137 - enum ipu_ic_task ic_task;
16138 - const struct ipu_image_convert_dma_chan *dma_ch;
16140 - struct ipu_ic *ic;
16141 - struct ipuv3_channel *in_chan;
16142 - struct ipuv3_channel *out_chan;
16143 - struct ipuv3_channel *rotation_in_chan;
16144 - struct ipuv3_channel *rotation_out_chan;
16146 - /* the IPU end-of-frame irqs */
16148 - int rot_out_eof_irq;
16150 - spinlock_t irqlock;
16152 - /* list of convert contexts */
16153 - struct list_head ctx_list;
16154 - /* queue of conversion runs */
16155 - struct list_head pending_q;
16156 - /* queue of completed runs */
16157 - struct list_head done_q;
16159 - /* the current conversion run */
16160 - struct ipu_image_convert_run *current_run;
16163 -struct ipu_image_convert_priv {
16164 - struct ipu_image_convert_chan chan[IC_NUM_TASKS];
16165 - struct ipu_soc *ipu;
16168 -static const struct ipu_image_convert_dma_chan
16169 -image_convert_dma_chan[IC_NUM_TASKS] = {
16170 - [IC_TASK_VIEWFINDER] = {
16171 - .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
16172 - .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
16173 - .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
16174 - .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
16175 - .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
16176 - .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
16177 - .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
16179 - [IC_TASK_POST_PROCESSOR] = {
16180 - .in = IPUV3_CHANNEL_MEM_IC_PP,
16181 - .out = IPUV3_CHANNEL_IC_PP_MEM,
16182 - .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
16183 - .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
16187 -static const struct ipu_image_pixfmt image_convert_formats[] = {
16189 - .fourcc = V4L2_PIX_FMT_RGB565,
16192 - .fourcc = V4L2_PIX_FMT_RGB24,
16195 - .fourcc = V4L2_PIX_FMT_BGR24,
16198 - .fourcc = V4L2_PIX_FMT_RGB32,
16201 - .fourcc = V4L2_PIX_FMT_BGR32,
16204 - .fourcc = V4L2_PIX_FMT_XRGB32,
16207 - .fourcc = V4L2_PIX_FMT_XBGR32,
16210 - .fourcc = V4L2_PIX_FMT_BGRX32,
16213 - .fourcc = V4L2_PIX_FMT_RGBX32,
16216 - .fourcc = V4L2_PIX_FMT_YUYV,
16218 - .uv_width_dec = 2,
16219 - .uv_height_dec = 1,
16221 - .fourcc = V4L2_PIX_FMT_UYVY,
16223 - .uv_width_dec = 2,
16224 - .uv_height_dec = 1,
16226 - .fourcc = V4L2_PIX_FMT_YUV420,
16229 - .uv_width_dec = 2,
16230 - .uv_height_dec = 2,
16232 - .fourcc = V4L2_PIX_FMT_YVU420,
16235 - .uv_width_dec = 2,
16236 - .uv_height_dec = 2,
16237 - .uv_swapped = true,
16239 - .fourcc = V4L2_PIX_FMT_NV12,
16242 - .uv_width_dec = 2,
16243 - .uv_height_dec = 2,
16244 - .uv_packed = true,
16246 - .fourcc = V4L2_PIX_FMT_YUV422P,
16249 - .uv_width_dec = 2,
16250 - .uv_height_dec = 1,
16252 - .fourcc = V4L2_PIX_FMT_NV16,
16255 - .uv_width_dec = 2,
16256 - .uv_height_dec = 1,
16257 - .uv_packed = true,
16261 -static const struct ipu_image_pixfmt *get_format(u32 fourcc)
16263 - const struct ipu_image_pixfmt *ret = NULL;
16266 - for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
16267 - if (image_convert_formats[i].fourcc == fourcc) {
16268 - ret = &image_convert_formats[i];
16276 -static void dump_format(struct ipu_image_convert_ctx *ctx,
16277 - struct ipu_image_convert_image *ic_image)
16279 - struct ipu_image_convert_chan *chan = ctx->chan;
16280 - struct ipu_image_convert_priv *priv = chan->priv;
16282 - dev_dbg(priv->ipu->dev,
16283 - "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
16284 - chan->ic_task, ctx,
16285 - ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
16286 - ic_image->base.pix.width, ic_image->base.pix.height,
16287 - ic_image->num_cols, ic_image->num_rows,
16288 - ic_image->fmt->fourcc & 0xff,
16289 - (ic_image->fmt->fourcc >> 8) & 0xff,
16290 - (ic_image->fmt->fourcc >> 16) & 0xff,
16291 - (ic_image->fmt->fourcc >> 24) & 0xff);
16294 -int ipu_image_convert_enum_format(int index, u32 *fourcc)
16296 - const struct ipu_image_pixfmt *fmt;
16298 - if (index >= (int)ARRAY_SIZE(image_convert_formats))
16301 - /* Format found */
16302 - fmt = &image_convert_formats[index];
16303 - *fourcc = fmt->fourcc;
16306 -EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
16308 -static void free_dma_buf(struct ipu_image_convert_priv *priv,
16309 - struct ipu_image_convert_dma_buf *buf)
16312 - dma_free_coherent(priv->ipu->dev,
16313 - buf->len, buf->virt, buf->phys);
16314 - buf->virt = NULL;
16318 -static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
16319 - struct ipu_image_convert_dma_buf *buf,
16322 - buf->len = PAGE_ALIGN(size);
16323 - buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
16324 - GFP_DMA | GFP_KERNEL);
16325 - if (!buf->virt) {
16326 - dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
16333 -static inline int num_stripes(int dim)
16335 - return (dim - 1) / 1024 + 1;
16339 - * Calculate downsizing coefficients, which are the same for all tiles,
16340 - * and initial bilinear resizing coefficients, which are used to find the
16341 - * best seam positions.
16342 - * Also determine the number of tiles necessary to guarantee that no tile
16343 - * is larger than 1024 pixels in either dimension at the output and between
16344 - * IC downsizing and main processing sections.
16346 -static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
16347 - struct ipu_image *in,
16348 - struct ipu_image *out)
16350 - u32 downsized_width = in->rect.width;
16351 - u32 downsized_height = in->rect.height;
16352 - u32 downsize_coeff_v = 0;
16353 - u32 downsize_coeff_h = 0;
16354 - u32 resized_width = out->rect.width;
16355 - u32 resized_height = out->rect.height;
16356 - u32 resize_coeff_h;
16357 - u32 resize_coeff_v;
16361 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16362 - resized_width = out->rect.height;
16363 - resized_height = out->rect.width;
16366 - /* Do not let invalid input lead to an endless loop below */
16367 - if (WARN_ON(resized_width == 0 || resized_height == 0))
16370 - while (downsized_width >= resized_width * 2) {
16371 - downsized_width >>= 1;
16372 - downsize_coeff_h++;
16375 - while (downsized_height >= resized_height * 2) {
16376 - downsized_height >>= 1;
16377 - downsize_coeff_v++;
16381 - * Calculate the bilinear resizing coefficients that could be used if
16382 - * we were converting with a single tile. The bottom right output pixel
16383 - * should sample as close as possible to the bottom right input pixel
16384 - * out of the decimator, but not overshoot it:
16386 - resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
16387 - resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
16390 - * Both the output of the IC downsizing section before being passed to
16391 - * the IC main processing section and the final output of the IC main
16392 - * processing section must be <= 1024 pixels in both dimensions.
16394 - cols = num_stripes(max_t(u32, downsized_width, resized_width));
16395 - rows = num_stripes(max_t(u32, downsized_height, resized_height));
16397 - dev_dbg(ctx->chan->priv->ipu->dev,
16398 - "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
16399 - __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
16400 - resize_coeff_v, cols, rows);
16402 - if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
16403 - resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
16406 - ctx->downsize_coeff_h = downsize_coeff_h;
16407 - ctx->downsize_coeff_v = downsize_coeff_v;
16408 - ctx->image_resize_coeff_h = resize_coeff_h;
16409 - ctx->image_resize_coeff_v = resize_coeff_v;
16410 - ctx->in.num_cols = cols;
16411 - ctx->in.num_rows = rows;
16416 -#define round_closest(x, y) round_down((x) + (y)/2, (y))
16419 - * Find the best aligned seam position for the given column / row index.
16420 - * Rotation and image offsets are out of scope.
16422 - * @index: column / row index, used to calculate valid interval
16423 - * @in_edge: input right / bottom edge
16424 - * @out_edge: output right / bottom edge
16425 - * @in_align: input alignment, either horizontal 8-byte line start address
16426 - * alignment, or pixel alignment due to image format
16427 - * @out_align: output alignment, either horizontal 8-byte line start address
16428 - * alignment, or pixel alignment due to image format or rotator
16430 - * @in_burst: horizontal input burst size in case of horizontal flip
16431 - * @out_burst: horizontal output burst size or rotator block size
16432 - * @downsize_coeff: downsizing section coefficient
16433 - * @resize_coeff: main processing section resizing coefficient
16434 - * @_in_seam: aligned input seam position return value
16435 - * @_out_seam: aligned output seam position return value
16437 -static void find_best_seam(struct ipu_image_convert_ctx *ctx,
16438 - unsigned int index,
16439 - unsigned int in_edge,
16440 - unsigned int out_edge,
16441 - unsigned int in_align,
16442 - unsigned int out_align,
16443 - unsigned int in_burst,
16444 - unsigned int out_burst,
16445 - unsigned int downsize_coeff,
16446 - unsigned int resize_coeff,
16450 - struct device *dev = ctx->chan->priv->ipu->dev;
16451 - unsigned int out_pos;
16452 - /* Input / output seam position candidates */
16453 - unsigned int out_seam = 0;
16454 - unsigned int in_seam = 0;
16455 - unsigned int min_diff = UINT_MAX;
16456 - unsigned int out_start;
16457 - unsigned int out_end;
16458 - unsigned int in_start;
16459 - unsigned int in_end;
16461 - /* Start within 1024 pixels of the right / bottom edge */
16462 - out_start = max_t(int, index * out_align, out_edge - 1024);
16463 - /* End before having to add more columns to the left / rows above */
16464 - out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
16467 - * Limit input seam position to make sure that the downsized input tile
16468 - * to the right or bottom does not exceed 1024 pixels.
16470 - in_start = max_t(int, index * in_align,
16471 - in_edge - (1024 << downsize_coeff));
16472 - in_end = min_t(unsigned int, in_edge,
16473 - index * (1024 << downsize_coeff) + 1);
16476 - * Output tiles must start at a multiple of 8 bytes horizontally and
16477 - * possibly at an even line horizontally depending on the pixel format.
16478 - * Only consider output aligned positions for the seam.
16480 - out_start = round_up(out_start, out_align);
16481 - for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
16482 - unsigned int in_pos;
16483 - unsigned int in_pos_aligned;
16484 - unsigned int in_pos_rounded;
16485 - unsigned int abs_diff;
16488 - * Tiles in the right row / bottom column may not be allowed to
16489 - * overshoot horizontally / vertically. out_burst may be the
16490 - * actual DMA burst size, or the rotator block size.
16492 - if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
16496 - * Input sample position, corresponding to out_pos, 19.13 fixed
16499 - in_pos = (out_pos * resize_coeff) << downsize_coeff;
16501 - * The closest input sample position that we could actually
16502 - * start the input tile at, 19.13 fixed point.
16504 - in_pos_aligned = round_closest(in_pos, 8192U * in_align);
16505 - /* Convert 19.13 fixed point to integer */
16506 - in_pos_rounded = in_pos_aligned / 8192U;
16508 - if (in_pos_rounded < in_start)
16510 - if (in_pos_rounded >= in_end)
16513 - if ((in_burst > 1) &&
16514 - (in_edge - in_pos_rounded) % in_burst)
16517 - if (in_pos < in_pos_aligned)
16518 - abs_diff = in_pos_aligned - in_pos;
16520 - abs_diff = in_pos - in_pos_aligned;
16522 - if (abs_diff < min_diff) {
16523 - in_seam = in_pos_rounded;
16524 - out_seam = out_pos;
16525 - min_diff = abs_diff;
16529 - *_out_seam = out_seam;
16530 - *_in_seam = in_seam;
16532 - dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
16533 - __func__, out_seam, out_align, out_start, out_end,
16534 - in_seam, in_align, in_start, in_end, min_diff / 8192,
16535 - DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
16539 - * Tile left edges are required to be aligned to multiples of 8 bytes
16542 -static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
16545 - return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
16547 - return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
16551 - * Tile top edge alignment is only limited by chroma subsampling.
16553 -static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
16555 - return fmt->uv_height_dec > 1 ? 2 : 1;
16558 -static inline u32 tile_width_align(enum ipu_image_convert_type type,
16559 - const struct ipu_image_pixfmt *fmt,
16560 - enum ipu_rotate_mode rot_mode)
16562 - if (type == IMAGE_CONVERT_IN) {
16564 - * The IC burst reads 8 pixels at a time. Reading beyond the
16565 - * end of the line is usually acceptable. Those pixels are
16566 - * ignored, unless the IC has to write the scaled line in
16569 - return (!ipu_rot_mode_is_irt(rot_mode) &&
16570 - (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
16574 - * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
16575 - * formats to guarantee 8-byte aligned line start addresses in the
16576 - * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
16577 - * for all other formats.
16579 - return (ipu_rot_mode_is_irt(rot_mode) &&
16580 - fmt->planar && !fmt->uv_packed) ?
16581 - 8 * fmt->uv_width_dec : 8;
16584 -static inline u32 tile_height_align(enum ipu_image_convert_type type,
16585 - const struct ipu_image_pixfmt *fmt,
16586 - enum ipu_rotate_mode rot_mode)
16588 - if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
16592 - * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
16593 - * formats to guarantee 8-byte aligned line start addresses in the
16594 - * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
16595 - * for all other formats.
16597 - return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
16601 - * Fill in left position and width and for all tiles in an input column, and
16602 - * for all corresponding output tiles. If the 90° rotator is used, the output
16603 - * tiles are in a row, and output tile top position and height are set.
16605 -static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
16606 - unsigned int col,
16607 - struct ipu_image_convert_image *in,
16608 - unsigned int in_left, unsigned int in_width,
16609 - struct ipu_image_convert_image *out,
16610 - unsigned int out_left, unsigned int out_width)
16612 - unsigned int row, tile_idx;
16613 - struct ipu_image_tile *in_tile, *out_tile;
16615 - for (row = 0; row < in->num_rows; row++) {
16616 - tile_idx = in->num_cols * row + col;
16617 - in_tile = &in->tile[tile_idx];
16618 - out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
16620 - in_tile->left = in_left;
16621 - in_tile->width = in_width;
16623 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16624 - out_tile->top = out_left;
16625 - out_tile->height = out_width;
16627 - out_tile->left = out_left;
16628 - out_tile->width = out_width;
16634 - * Fill in top position and height and for all tiles in an input row, and
16635 - * for all corresponding output tiles. If the 90° rotator is used, the output
16636 - * tiles are in a column, and output tile left position and width are set.
16638 -static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
16639 - struct ipu_image_convert_image *in,
16640 - unsigned int in_top, unsigned int in_height,
16641 - struct ipu_image_convert_image *out,
16642 - unsigned int out_top, unsigned int out_height)
16644 - unsigned int col, tile_idx;
16645 - struct ipu_image_tile *in_tile, *out_tile;
16647 - for (col = 0; col < in->num_cols; col++) {
16648 - tile_idx = in->num_cols * row + col;
16649 - in_tile = &in->tile[tile_idx];
16650 - out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
16652 - in_tile->top = in_top;
16653 - in_tile->height = in_height;
16655 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16656 - out_tile->left = out_top;
16657 - out_tile->width = out_height;
16659 - out_tile->top = out_top;
16660 - out_tile->height = out_height;
16666 - * Find the best horizontal and vertical seam positions to split into tiles.
16667 - * Minimize the fractional part of the input sampling position for the
16668 - * top / left pixels of each tile.
16670 -static void find_seams(struct ipu_image_convert_ctx *ctx,
16671 - struct ipu_image_convert_image *in,
16672 - struct ipu_image_convert_image *out)
16674 - struct device *dev = ctx->chan->priv->ipu->dev;
16675 - unsigned int resized_width = out->base.rect.width;
16676 - unsigned int resized_height = out->base.rect.height;
16677 - unsigned int col;
16678 - unsigned int row;
16679 - unsigned int in_left_align = tile_left_align(in->fmt);
16680 - unsigned int in_top_align = tile_top_align(in->fmt);
16681 - unsigned int out_left_align = tile_left_align(out->fmt);
16682 - unsigned int out_top_align = tile_top_align(out->fmt);
16683 - unsigned int out_width_align = tile_width_align(out->type, out->fmt,
16685 - unsigned int out_height_align = tile_height_align(out->type, out->fmt,
16687 - unsigned int in_right = in->base.rect.width;
16688 - unsigned int in_bottom = in->base.rect.height;
16689 - unsigned int out_right = out->base.rect.width;
16690 - unsigned int out_bottom = out->base.rect.height;
16691 - unsigned int flipped_out_left;
16692 - unsigned int flipped_out_top;
16694 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16695 - /* Switch width/height and align top left to IRT block size */
16696 - resized_width = out->base.rect.height;
16697 - resized_height = out->base.rect.width;
16698 - out_left_align = out_height_align;
16699 - out_top_align = out_width_align;
16700 - out_width_align = out_left_align;
16701 - out_height_align = out_top_align;
16702 - out_right = out->base.rect.height;
16703 - out_bottom = out->base.rect.width;
16706 - for (col = in->num_cols - 1; col > 0; col--) {
16707 - bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
16708 - !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
16709 - bool allow_out_overshoot = (col < in->num_cols - 1) &&
16710 - !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
16711 - unsigned int in_left;
16712 - unsigned int out_left;
16715 - * Align input width to burst length if the scaling step flips
16719 - find_best_seam(ctx, col,
16720 - in_right, out_right,
16721 - in_left_align, out_left_align,
16722 - allow_in_overshoot ? 1 : 8 /* burst length */,
16723 - allow_out_overshoot ? 1 : out_width_align,
16724 - ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
16725 - &in_left, &out_left);
16727 - if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
16728 - flipped_out_left = resized_width - out_right;
16730 - flipped_out_left = out_left;
16732 - fill_tile_column(ctx, col, in, in_left, in_right - in_left,
16733 - out, flipped_out_left, out_right - out_left);
16735 - dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
16736 - in_left, in_right - in_left,
16737 - flipped_out_left, out_right - out_left);
16739 - in_right = in_left;
16740 - out_right = out_left;
16743 - flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
16744 - resized_width - out_right : 0;
16746 - fill_tile_column(ctx, 0, in, 0, in_right,
16747 - out, flipped_out_left, out_right);
16749 - dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
16750 - in_right, flipped_out_left, out_right);
16752 - for (row = in->num_rows - 1; row > 0; row--) {
16753 - bool allow_overshoot = row < in->num_rows - 1;
16754 - unsigned int in_top;
16755 - unsigned int out_top;
16757 - find_best_seam(ctx, row,
16758 - in_bottom, out_bottom,
16759 - in_top_align, out_top_align,
16760 - 1, allow_overshoot ? 1 : out_height_align,
16761 - ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
16762 - &in_top, &out_top);
16764 - if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
16765 - ipu_rot_mode_is_irt(ctx->rot_mode))
16766 - flipped_out_top = resized_height - out_bottom;
16768 - flipped_out_top = out_top;
16770 - fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
16771 - out, flipped_out_top, out_bottom - out_top);
16773 - dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
16774 - in_top, in_bottom - in_top,
16775 - flipped_out_top, out_bottom - out_top);
16777 - in_bottom = in_top;
16778 - out_bottom = out_top;
16781 - if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
16782 - ipu_rot_mode_is_irt(ctx->rot_mode))
16783 - flipped_out_top = resized_height - out_bottom;
16785 - flipped_out_top = 0;
16787 - fill_tile_row(ctx, 0, in, 0, in_bottom,
16788 - out, flipped_out_top, out_bottom);
16790 - dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
16791 - in_bottom, flipped_out_top, out_bottom);
16794 -static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
16795 - struct ipu_image_convert_image *image)
16797 - struct ipu_image_convert_chan *chan = ctx->chan;
16798 - struct ipu_image_convert_priv *priv = chan->priv;
16799 - unsigned int max_width = 1024;
16800 - unsigned int max_height = 1024;
16803 - if (image->type == IMAGE_CONVERT_IN) {
16804 - /* Up to 4096x4096 input tile size */
16805 - max_width <<= ctx->downsize_coeff_h;
16806 - max_height <<= ctx->downsize_coeff_v;
16809 - for (i = 0; i < ctx->num_tiles; i++) {
16810 - struct ipu_image_tile *tile;
16811 - const unsigned int row = i / image->num_cols;
16812 - const unsigned int col = i % image->num_cols;
16814 - if (image->type == IMAGE_CONVERT_OUT)
16815 - tile = &image->tile[ctx->out_tile_map[i]];
16817 - tile = &image->tile[i];
16819 - tile->size = ((tile->height * image->fmt->bpp) >> 3) *
16822 - if (image->fmt->planar) {
16823 - tile->stride = tile->width;
16824 - tile->rot_stride = tile->height;
16827 - (image->fmt->bpp * tile->width) >> 3;
16828 - tile->rot_stride =
16829 - (image->fmt->bpp * tile->height) >> 3;
16832 - dev_dbg(priv->ipu->dev,
16833 - "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
16834 - chan->ic_task, ctx,
16835 - image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
16837 - tile->width, tile->height, tile->left, tile->top);
16839 - if (!tile->width || tile->width > max_width ||
16840 - !tile->height || tile->height > max_height) {
16841 - dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
16842 - image->type == IMAGE_CONVERT_IN ? "input" :
16843 - "output", tile->width, tile->height);
16852 - * Use the rotation transformation to find the tile coordinates
16853 - * (row, col) of a tile in the destination frame that corresponds
16854 - * to the given tile coordinates of a source frame. The destination
16855 - * coordinate is then converted to a tile index.
16857 -static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
16858 - int src_row, int src_col)
16860 - struct ipu_image_convert_chan *chan = ctx->chan;
16861 - struct ipu_image_convert_priv *priv = chan->priv;
16862 - struct ipu_image_convert_image *s_image = &ctx->in;
16863 - struct ipu_image_convert_image *d_image = &ctx->out;
16864 - int dst_row, dst_col;
16866 - /* with no rotation it's a 1:1 mapping */
16867 - if (ctx->rot_mode == IPU_ROTATE_NONE)
16868 - return src_row * s_image->num_cols + src_col;
16871 - * before doing the transform, first we have to translate
16872 - * source row,col for an origin in the center of s_image
16874 - src_row = src_row * 2 - (s_image->num_rows - 1);
16875 - src_col = src_col * 2 - (s_image->num_cols - 1);
16877 - /* do the rotation transform */
16878 - if (ctx->rot_mode & IPU_ROT_BIT_90) {
16879 - dst_col = -src_row;
16880 - dst_row = src_col;
16882 - dst_col = src_col;
16883 - dst_row = src_row;
16887 - if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
16888 - dst_col = -dst_col;
16889 - if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
16890 - dst_row = -dst_row;
16892 - dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
16893 - chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
16896 - * finally translate dest row,col using an origin in upper
16897 - * left of d_image
16899 - dst_row += d_image->num_rows - 1;
16900 - dst_col += d_image->num_cols - 1;
16904 - return dst_row * d_image->num_cols + dst_col;
16908 - * Fill the out_tile_map[] with transformed destination tile indeces.
16910 -static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
16912 - struct ipu_image_convert_image *s_image = &ctx->in;
16913 - unsigned int row, col, tile = 0;
16915 - for (row = 0; row < s_image->num_rows; row++) {
16916 - for (col = 0; col < s_image->num_cols; col++) {
16917 - ctx->out_tile_map[tile] =
16918 - transform_tile_index(ctx, row, col);
16924 -static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
16925 - struct ipu_image_convert_image *image)
16927 - struct ipu_image_convert_chan *chan = ctx->chan;
16928 - struct ipu_image_convert_priv *priv = chan->priv;
16929 - const struct ipu_image_pixfmt *fmt = image->fmt;
16930 - unsigned int row, col, tile = 0;
16931 - u32 H, top, y_stride, uv_stride;
16932 - u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
16933 - u32 y_row_off, y_col_off, y_off;
16934 - u32 y_size, uv_size;
16936 - /* setup some convenience vars */
16937 - H = image->base.pix.height;
16939 - y_stride = image->stride;
16940 - uv_stride = y_stride / fmt->uv_width_dec;
16941 - if (fmt->uv_packed)
16944 - y_size = H * y_stride;
16945 - uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
16947 - for (row = 0; row < image->num_rows; row++) {
16948 - top = image->tile[tile].top;
16949 - y_row_off = top * y_stride;
16950 - uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
16952 - for (col = 0; col < image->num_cols; col++) {
16953 - y_col_off = image->tile[tile].left;
16954 - uv_col_off = y_col_off / fmt->uv_width_dec;
16955 - if (fmt->uv_packed)
16958 - y_off = y_row_off + y_col_off;
16959 - uv_off = uv_row_off + uv_col_off;
16961 - u_off = y_size - y_off + uv_off;
16962 - v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
16963 - if (fmt->uv_swapped) {
16969 - image->tile[tile].offset = y_off;
16970 - image->tile[tile].u_off = u_off;
16971 - image->tile[tile++].v_off = v_off;
16973 - if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
16974 - dev_err(priv->ipu->dev,
16975 - "task %u: ctx %p: %s@[%d,%d]: "
16976 - "y_off %08x, u_off %08x, v_off %08x\n",
16977 - chan->ic_task, ctx,
16978 - image->type == IMAGE_CONVERT_IN ?
16979 - "Input" : "Output", row, col,
16980 - y_off, u_off, v_off);
16989 -static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
16990 - struct ipu_image_convert_image *image)
16992 - struct ipu_image_convert_chan *chan = ctx->chan;
16993 - struct ipu_image_convert_priv *priv = chan->priv;
16994 - const struct ipu_image_pixfmt *fmt = image->fmt;
16995 - unsigned int row, col, tile = 0;
16996 - u32 bpp, stride, offset;
16997 - u32 row_off, col_off;
16999 - /* setup some convenience vars */
17000 - stride = image->stride;
17003 - for (row = 0; row < image->num_rows; row++) {
17004 - row_off = image->tile[tile].top * stride;
17006 - for (col = 0; col < image->num_cols; col++) {
17007 - col_off = (image->tile[tile].left * bpp) >> 3;
17009 - offset = row_off + col_off;
17011 - image->tile[tile].offset = offset;
17012 - image->tile[tile].u_off = 0;
17013 - image->tile[tile++].v_off = 0;
17015 - if (offset & 0x7) {
17016 - dev_err(priv->ipu->dev,
17017 - "task %u: ctx %p: %s@[%d,%d]: "
17019 - chan->ic_task, ctx,
17020 - image->type == IMAGE_CONVERT_IN ?
17021 - "Input" : "Output", row, col,
17022 - row_off + col_off);
17031 -static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
17032 - struct ipu_image_convert_image *image)
17034 - if (image->fmt->planar)
17035 - return calc_tile_offsets_planar(ctx, image);
17037 - return calc_tile_offsets_packed(ctx, image);
17041 - * Calculate the resizing ratio for the IC main processing section given input
17042 - * size, fixed downsizing coefficient, and output size.
17043 - * Either round to closest for the next tile's first pixel to minimize seams
17044 - * and distortion (for all but right column / bottom row), or round down to
17045 - * avoid sampling beyond the edges of the input image for this tile's last
17047 - * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
17049 -static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
17050 - u32 output_size, bool allow_overshoot)
17052 - u32 downsized = input_size >> downsize_coeff;
17054 - if (allow_overshoot)
17055 - return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
17057 - return 8192 * (downsized - 1) / (output_size - 1);
17061 - * Slightly modify resize coefficients per tile to hide the bilinear
17062 - * interpolator reset at tile borders, shifting the right / bottom edge
17063 - * by up to a half input pixel. This removes noticeable seams between
17064 - * tiles at higher upscaling factors.
17066 -static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
17068 - struct ipu_image_convert_chan *chan = ctx->chan;
17069 - struct ipu_image_convert_priv *priv = chan->priv;
17070 - struct ipu_image_tile *in_tile, *out_tile;
17071 - unsigned int col, row, tile_idx;
17072 - unsigned int last_output;
17074 - for (col = 0; col < ctx->in.num_cols; col++) {
17075 - bool closest = (col < ctx->in.num_cols - 1) &&
17076 - !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
17077 - u32 resized_width;
17078 - u32 resize_coeff_h;
17082 - in_tile = &ctx->in.tile[tile_idx];
17083 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17085 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
17086 - resized_width = out_tile->height;
17088 - resized_width = out_tile->width;
17090 - resize_coeff_h = calc_resize_coeff(in_tile->width,
17091 - ctx->downsize_coeff_h,
17092 - resized_width, closest);
17094 - dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
17095 - __func__, col, resize_coeff_h);
17098 - * With the horizontal scaling factor known, round up resized
17099 - * width (output width or height) to burst size.
17101 - resized_width = round_up(resized_width, 8);
17104 - * Calculate input width from the last accessed input pixel
17105 - * given resized width and scaling coefficients. Round up to
17108 - last_output = resized_width - 1;
17109 - if (closest && ((last_output * resize_coeff_h) % 8192))
17111 - in_width = round_up(
17112 - (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
17113 - << ctx->downsize_coeff_h, 8);
17115 - for (row = 0; row < ctx->in.num_rows; row++) {
17116 - tile_idx = row * ctx->in.num_cols + col;
17117 - in_tile = &ctx->in.tile[tile_idx];
17118 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17120 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
17121 - out_tile->height = resized_width;
17123 - out_tile->width = resized_width;
17125 - in_tile->width = in_width;
17128 - ctx->resize_coeffs_h[col] = resize_coeff_h;
17131 - for (row = 0; row < ctx->in.num_rows; row++) {
17132 - bool closest = (row < ctx->in.num_rows - 1) &&
17133 - !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
17134 - u32 resized_height;
17135 - u32 resize_coeff_v;
17138 - tile_idx = row * ctx->in.num_cols;
17139 - in_tile = &ctx->in.tile[tile_idx];
17140 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17142 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
17143 - resized_height = out_tile->width;
17145 - resized_height = out_tile->height;
17147 - resize_coeff_v = calc_resize_coeff(in_tile->height,
17148 - ctx->downsize_coeff_v,
17149 - resized_height, closest);
17151 - dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
17152 - __func__, row, resize_coeff_v);
17155 - * With the vertical scaling factor known, round up resized
17156 - * height (output width or height) to IDMAC limitations.
17158 - resized_height = round_up(resized_height, 2);
17161 - * Calculate input width from the last accessed input pixel
17162 - * given resized height and scaling coefficients. Align to
17163 - * IDMAC restrictions.
17165 - last_output = resized_height - 1;
17166 - if (closest && ((last_output * resize_coeff_v) % 8192))
17168 - in_height = round_up(
17169 - (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
17170 - << ctx->downsize_coeff_v, 2);
17172 - for (col = 0; col < ctx->in.num_cols; col++) {
17173 - tile_idx = row * ctx->in.num_cols + col;
17174 - in_tile = &ctx->in.tile[tile_idx];
17175 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17177 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
17178 - out_tile->width = resized_height;
17180 - out_tile->height = resized_height;
17182 - in_tile->height = in_height;
17185 - ctx->resize_coeffs_v[row] = resize_coeff_v;
17190 - * return the number of runs in given queue (pending_q or done_q)
17191 - * for this context. hold irqlock when calling.
17193 -static int get_run_count(struct ipu_image_convert_ctx *ctx,
17194 - struct list_head *q)
17196 - struct ipu_image_convert_run *run;
17199 - lockdep_assert_held(&ctx->chan->irqlock);
17201 - list_for_each_entry(run, q, list) {
17202 - if (run->ctx == ctx)
17209 -static void convert_stop(struct ipu_image_convert_run *run)
17211 - struct ipu_image_convert_ctx *ctx = run->ctx;
17212 - struct ipu_image_convert_chan *chan = ctx->chan;
17213 - struct ipu_image_convert_priv *priv = chan->priv;
17215 - dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
17216 - __func__, chan->ic_task, ctx, run);
17218 - /* disable IC tasks and the channels */
17219 - ipu_ic_task_disable(chan->ic);
17220 - ipu_idmac_disable_channel(chan->in_chan);
17221 - ipu_idmac_disable_channel(chan->out_chan);
17223 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17224 - ipu_idmac_disable_channel(chan->rotation_in_chan);
17225 - ipu_idmac_disable_channel(chan->rotation_out_chan);
17226 - ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
17229 - ipu_ic_disable(chan->ic);
17232 -static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
17233 - struct ipuv3_channel *channel,
17234 - struct ipu_image_convert_image *image,
17235 - enum ipu_rotate_mode rot_mode,
17236 - bool rot_swap_width_height,
17237 - unsigned int tile)
17239 - struct ipu_image_convert_chan *chan = ctx->chan;
17240 - unsigned int burst_size;
17241 - u32 width, height, stride;
17242 - dma_addr_t addr0, addr1 = 0;
17243 - struct ipu_image tile_image;
17244 - unsigned int tile_idx[2];
17246 - if (image->type == IMAGE_CONVERT_OUT) {
17247 - tile_idx[0] = ctx->out_tile_map[tile];
17248 - tile_idx[1] = ctx->out_tile_map[1];
17250 - tile_idx[0] = tile;
17254 - if (rot_swap_width_height) {
17255 - width = image->tile[tile_idx[0]].height;
17256 - height = image->tile[tile_idx[0]].width;
17257 - stride = image->tile[tile_idx[0]].rot_stride;
17258 - addr0 = ctx->rot_intermediate[0].phys;
17259 - if (ctx->double_buffering)
17260 - addr1 = ctx->rot_intermediate[1].phys;
17262 - width = image->tile[tile_idx[0]].width;
17263 - height = image->tile[tile_idx[0]].height;
17264 - stride = image->stride;
17265 - addr0 = image->base.phys0 +
17266 - image->tile[tile_idx[0]].offset;
17267 - if (ctx->double_buffering)
17268 - addr1 = image->base.phys0 +
17269 - image->tile[tile_idx[1]].offset;
17272 - ipu_cpmem_zero(channel);
17274 - memset(&tile_image, 0, sizeof(tile_image));
17275 - tile_image.pix.width = tile_image.rect.width = width;
17276 - tile_image.pix.height = tile_image.rect.height = height;
17277 - tile_image.pix.bytesperline = stride;
17278 - tile_image.pix.pixelformat = image->fmt->fourcc;
17279 - tile_image.phys0 = addr0;
17280 - tile_image.phys1 = addr1;
17281 - if (image->fmt->planar && !rot_swap_width_height) {
17282 - tile_image.u_offset = image->tile[tile_idx[0]].u_off;
17283 - tile_image.v_offset = image->tile[tile_idx[0]].v_off;
17286 - ipu_cpmem_set_image(channel, &tile_image);
17289 - ipu_cpmem_set_rotation(channel, rot_mode);
17292 - * Skip writing U and V components to odd rows in the output
17293 - * channels for planar 4:2:0.
17295 - if ((channel == chan->out_chan ||
17296 - channel == chan->rotation_out_chan) &&
17297 - image->fmt->planar && image->fmt->uv_height_dec == 2)
17298 - ipu_cpmem_skip_odd_chroma_rows(channel);
17300 - if (channel == chan->rotation_in_chan ||
17301 - channel == chan->rotation_out_chan) {
17303 - ipu_cpmem_set_block_mode(channel);
17305 - burst_size = (width % 16) ? 8 : 16;
17307 - ipu_cpmem_set_burstsize(channel, burst_size);
17309 - ipu_ic_task_idma_init(chan->ic, channel, width, height,
17310 - burst_size, rot_mode);
17313 - * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
17314 - * only do this when there is no PRG present.
17316 - if (!channel->ipu->prg_priv)
17317 - ipu_cpmem_set_axi_id(channel, 1);
17319 - ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
17322 -static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
17324 - struct ipu_image_convert_ctx *ctx = run->ctx;
17325 - struct ipu_image_convert_chan *chan = ctx->chan;
17326 - struct ipu_image_convert_priv *priv = chan->priv;
17327 - struct ipu_image_convert_image *s_image = &ctx->in;
17328 - struct ipu_image_convert_image *d_image = &ctx->out;
17329 - unsigned int dst_tile = ctx->out_tile_map[tile];
17330 - unsigned int dest_width, dest_height;
17331 - unsigned int col, row;
17335 - dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
17336 - __func__, chan->ic_task, ctx, run, tile, dst_tile);
17338 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17339 - /* swap width/height for resizer */
17340 - dest_width = d_image->tile[dst_tile].height;
17341 - dest_height = d_image->tile[dst_tile].width;
17343 - dest_width = d_image->tile[dst_tile].width;
17344 - dest_height = d_image->tile[dst_tile].height;
17347 - row = tile / s_image->num_cols;
17348 - col = tile % s_image->num_cols;
17350 - rsc = (ctx->downsize_coeff_v << 30) |
17351 - (ctx->resize_coeffs_v[row] << 16) |
17352 - (ctx->downsize_coeff_h << 14) |
17353 - (ctx->resize_coeffs_h[col]);
17355 - dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
17356 - __func__, s_image->tile[tile].width,
17357 - s_image->tile[tile].height, dest_width, dest_height, rsc);
17359 - /* setup the IC resizer and CSC */
17360 - ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
17361 - s_image->tile[tile].width,
17362 - s_image->tile[tile].height,
17367 - dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
17371 - /* init the source MEM-->IC PP IDMAC channel */
17372 - init_idmac_channel(ctx, chan->in_chan, s_image,
17373 - IPU_ROTATE_NONE, false, tile);
17375 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17376 - /* init the IC PP-->MEM IDMAC channel */
17377 - init_idmac_channel(ctx, chan->out_chan, d_image,
17378 - IPU_ROTATE_NONE, true, tile);
17380 - /* init the MEM-->IC PP ROT IDMAC channel */
17381 - init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
17382 - ctx->rot_mode, true, tile);
17384 - /* init the destination IC PP ROT-->MEM IDMAC channel */
17385 - init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
17386 - IPU_ROTATE_NONE, false, tile);
17388 - /* now link IC PP-->MEM to MEM-->IC PP ROT */
17389 - ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
17391 - /* init the destination IC PP-->MEM IDMAC channel */
17392 - init_idmac_channel(ctx, chan->out_chan, d_image,
17393 - ctx->rot_mode, false, tile);
17396 - /* enable the IC */
17397 - ipu_ic_enable(chan->ic);
17399 - /* set buffers ready */
17400 - ipu_idmac_select_buffer(chan->in_chan, 0);
17401 - ipu_idmac_select_buffer(chan->out_chan, 0);
17402 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
17403 - ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
17404 - if (ctx->double_buffering) {
17405 - ipu_idmac_select_buffer(chan->in_chan, 1);
17406 - ipu_idmac_select_buffer(chan->out_chan, 1);
17407 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
17408 - ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
17411 - /* enable the channels! */
17412 - ipu_idmac_enable_channel(chan->in_chan);
17413 - ipu_idmac_enable_channel(chan->out_chan);
17414 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17415 - ipu_idmac_enable_channel(chan->rotation_in_chan);
17416 - ipu_idmac_enable_channel(chan->rotation_out_chan);
17419 - ipu_ic_task_enable(chan->ic);
17421 - ipu_cpmem_dump(chan->in_chan);
17422 - ipu_cpmem_dump(chan->out_chan);
17423 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17424 - ipu_cpmem_dump(chan->rotation_in_chan);
17425 - ipu_cpmem_dump(chan->rotation_out_chan);
17428 - ipu_dump(priv->ipu);
17433 -/* hold irqlock when calling */
17434 -static int do_run(struct ipu_image_convert_run *run)
17436 - struct ipu_image_convert_ctx *ctx = run->ctx;
17437 - struct ipu_image_convert_chan *chan = ctx->chan;
17439 - lockdep_assert_held(&chan->irqlock);
17441 - ctx->in.base.phys0 = run->in_phys;
17442 - ctx->out.base.phys0 = run->out_phys;
17444 - ctx->cur_buf_num = 0;
17445 - ctx->next_tile = 1;
17447 - /* remove run from pending_q and set as current */
17448 - list_del(&run->list);
17449 - chan->current_run = run;
17451 - return convert_start(run, 0);
17454 -/* hold irqlock when calling */
17455 -static void run_next(struct ipu_image_convert_chan *chan)
17457 - struct ipu_image_convert_priv *priv = chan->priv;
17458 - struct ipu_image_convert_run *run, *tmp;
17461 - lockdep_assert_held(&chan->irqlock);
17463 - list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
17464 - /* skip contexts that are aborting */
17465 - if (run->ctx->aborting) {
17466 - dev_dbg(priv->ipu->dev,
17467 - "%s: task %u: skipping aborting ctx %p run %p\n",
17468 - __func__, chan->ic_task, run->ctx, run);
17472 - ret = do_run(run);
17477 - * something went wrong with start, add the run
17478 - * to done q and continue to the next run in the
17481 - run->status = ret;
17482 - list_add_tail(&run->list, &chan->done_q);
17483 - chan->current_run = NULL;
17487 -static void empty_done_q(struct ipu_image_convert_chan *chan)
17489 - struct ipu_image_convert_priv *priv = chan->priv;
17490 - struct ipu_image_convert_run *run;
17491 - unsigned long flags;
17493 - spin_lock_irqsave(&chan->irqlock, flags);
17495 - while (!list_empty(&chan->done_q)) {
17496 - run = list_entry(chan->done_q.next,
17497 - struct ipu_image_convert_run,
17500 - list_del(&run->list);
17502 - dev_dbg(priv->ipu->dev,
17503 - "%s: task %u: completing ctx %p run %p with %d\n",
17504 - __func__, chan->ic_task, run->ctx, run, run->status);
17506 - /* call the completion callback and free the run */
17507 - spin_unlock_irqrestore(&chan->irqlock, flags);
17508 - run->ctx->complete(run, run->ctx->complete_context);
17509 - spin_lock_irqsave(&chan->irqlock, flags);
17512 - spin_unlock_irqrestore(&chan->irqlock, flags);
17516 - * the bottom half thread clears out the done_q, calling the
17517 - * completion handler for each.
17519 -static irqreturn_t do_bh(int irq, void *dev_id)
17521 - struct ipu_image_convert_chan *chan = dev_id;
17522 - struct ipu_image_convert_priv *priv = chan->priv;
17523 - struct ipu_image_convert_ctx *ctx;
17524 - unsigned long flags;
17526 - dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
17529 - empty_done_q(chan);
17531 - spin_lock_irqsave(&chan->irqlock, flags);
17534 - * the done_q is cleared out, signal any contexts
17535 - * that are aborting that abort can complete.
17537 - list_for_each_entry(ctx, &chan->ctx_list, list) {
17538 - if (ctx->aborting) {
17539 - dev_dbg(priv->ipu->dev,
17540 - "%s: task %u: signaling abort for ctx %p\n",
17541 - __func__, chan->ic_task, ctx);
17542 - complete_all(&ctx->aborted);
17546 - spin_unlock_irqrestore(&chan->irqlock, flags);
17548 - dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
17551 - return IRQ_HANDLED;
17554 -static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
17556 - unsigned int cur_tile = ctx->next_tile - 1;
17557 - unsigned int next_tile = ctx->next_tile;
17559 - if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
17560 - ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
17561 - ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
17562 - ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
17563 - ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
17564 - ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
17565 - ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
17566 - ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
17572 -/* hold irqlock when calling */
17573 -static irqreturn_t do_irq(struct ipu_image_convert_run *run)
17575 - struct ipu_image_convert_ctx *ctx = run->ctx;
17576 - struct ipu_image_convert_chan *chan = ctx->chan;
17577 - struct ipu_image_tile *src_tile, *dst_tile;
17578 - struct ipu_image_convert_image *s_image = &ctx->in;
17579 - struct ipu_image_convert_image *d_image = &ctx->out;
17580 - struct ipuv3_channel *outch;
17581 - unsigned int dst_idx;
17583 - lockdep_assert_held(&chan->irqlock);
17585 - outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
17586 - chan->rotation_out_chan : chan->out_chan;
17589 - * It is difficult to stop the channel DMA before the channels
17590 - * enter the paused state. Without double-buffering the channels
17591 - * are always in a paused state when the EOF irq occurs, so it
17592 - * is safe to stop the channels now. For double-buffering we
17593 - * just ignore the abort until the operation completes, when it
17594 - * is safe to shut down.
17596 - if (ctx->aborting && !ctx->double_buffering) {
17597 - convert_stop(run);
17598 - run->status = -EIO;
17602 - if (ctx->next_tile == ctx->num_tiles) {
17604 - * the conversion is complete
17606 - convert_stop(run);
17612 - * not done, place the next tile buffers.
17614 - if (!ctx->double_buffering) {
17615 - if (ic_settings_changed(ctx)) {
17616 - convert_stop(run);
17617 - convert_start(run, ctx->next_tile);
17619 - src_tile = &s_image->tile[ctx->next_tile];
17620 - dst_idx = ctx->out_tile_map[ctx->next_tile];
17621 - dst_tile = &d_image->tile[dst_idx];
17623 - ipu_cpmem_set_buffer(chan->in_chan, 0,
17624 - s_image->base.phys0 +
17625 - src_tile->offset);
17626 - ipu_cpmem_set_buffer(outch, 0,
17627 - d_image->base.phys0 +
17628 - dst_tile->offset);
17629 - if (s_image->fmt->planar)
17630 - ipu_cpmem_set_uv_offset(chan->in_chan,
17632 - src_tile->v_off);
17633 - if (d_image->fmt->planar)
17634 - ipu_cpmem_set_uv_offset(outch,
17636 - dst_tile->v_off);
17638 - ipu_idmac_select_buffer(chan->in_chan, 0);
17639 - ipu_idmac_select_buffer(outch, 0);
17641 - } else if (ctx->next_tile < ctx->num_tiles - 1) {
17643 - src_tile = &s_image->tile[ctx->next_tile + 1];
17644 - dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
17645 - dst_tile = &d_image->tile[dst_idx];
17647 - ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
17648 - s_image->base.phys0 + src_tile->offset);
17649 - ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
17650 - d_image->base.phys0 + dst_tile->offset);
17652 - ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
17653 - ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
17655 - ctx->cur_buf_num ^= 1;
17658 - ctx->next_tile++;
17659 - return IRQ_HANDLED;
17661 - list_add_tail(&run->list, &chan->done_q);
17662 - chan->current_run = NULL;
17664 - return IRQ_WAKE_THREAD;
17667 -static irqreturn_t norotate_irq(int irq, void *data)
17669 - struct ipu_image_convert_chan *chan = data;
17670 - struct ipu_image_convert_ctx *ctx;
17671 - struct ipu_image_convert_run *run;
17672 - unsigned long flags;
17675 - spin_lock_irqsave(&chan->irqlock, flags);
17677 - /* get current run and its context */
17678 - run = chan->current_run;
17686 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17687 - /* this is a rotation operation, just ignore */
17688 - spin_unlock_irqrestore(&chan->irqlock, flags);
17689 - return IRQ_HANDLED;
17692 - ret = do_irq(run);
17694 - spin_unlock_irqrestore(&chan->irqlock, flags);
17698 -static irqreturn_t rotate_irq(int irq, void *data)
17700 - struct ipu_image_convert_chan *chan = data;
17701 - struct ipu_image_convert_priv *priv = chan->priv;
17702 - struct ipu_image_convert_ctx *ctx;
17703 - struct ipu_image_convert_run *run;
17704 - unsigned long flags;
17707 - spin_lock_irqsave(&chan->irqlock, flags);
17709 - /* get current run and its context */
17710 - run = chan->current_run;
17718 - if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
17719 - /* this was NOT a rotation operation, shouldn't happen */
17720 - dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
17721 - spin_unlock_irqrestore(&chan->irqlock, flags);
17722 - return IRQ_HANDLED;
17725 - ret = do_irq(run);
17727 - spin_unlock_irqrestore(&chan->irqlock, flags);
17732 - * try to force the completion of runs for this ctx. Called when
17733 - * abort wait times out in ipu_image_convert_abort().
17735 -static void force_abort(struct ipu_image_convert_ctx *ctx)
17737 - struct ipu_image_convert_chan *chan = ctx->chan;
17738 - struct ipu_image_convert_run *run;
17739 - unsigned long flags;
17741 - spin_lock_irqsave(&chan->irqlock, flags);
17743 - run = chan->current_run;
17744 - if (run && run->ctx == ctx) {
17745 - convert_stop(run);
17746 - run->status = -EIO;
17747 - list_add_tail(&run->list, &chan->done_q);
17748 - chan->current_run = NULL;
17752 - spin_unlock_irqrestore(&chan->irqlock, flags);
17754 - empty_done_q(chan);
17757 -static void release_ipu_resources(struct ipu_image_convert_chan *chan)
17759 - if (chan->out_eof_irq >= 0)
17760 - free_irq(chan->out_eof_irq, chan);
17761 - if (chan->rot_out_eof_irq >= 0)
17762 - free_irq(chan->rot_out_eof_irq, chan);
17764 - if (!IS_ERR_OR_NULL(chan->in_chan))
17765 - ipu_idmac_put(chan->in_chan);
17766 - if (!IS_ERR_OR_NULL(chan->out_chan))
17767 - ipu_idmac_put(chan->out_chan);
17768 - if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
17769 - ipu_idmac_put(chan->rotation_in_chan);
17770 - if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
17771 - ipu_idmac_put(chan->rotation_out_chan);
17772 - if (!IS_ERR_OR_NULL(chan->ic))
17773 - ipu_ic_put(chan->ic);
17775 - chan->in_chan = chan->out_chan = chan->rotation_in_chan =
17776 - chan->rotation_out_chan = NULL;
17777 - chan->out_eof_irq = chan->rot_out_eof_irq = -1;
17780 -static int get_ipu_resources(struct ipu_image_convert_chan *chan)
17782 - const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
17783 - struct ipu_image_convert_priv *priv = chan->priv;
17787 - chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
17788 - if (IS_ERR(chan->ic)) {
17789 - dev_err(priv->ipu->dev, "could not acquire IC\n");
17790 - ret = PTR_ERR(chan->ic);
17794 - /* get IDMAC channels */
17795 - chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
17796 - chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
17797 - if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
17798 - dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
17803 - chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
17804 - chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
17805 - if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
17806 - dev_err(priv->ipu->dev,
17807 - "could not acquire idmac rotation channels\n");
17812 - /* acquire the EOF interrupts */
17813 - chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
17817 - ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
17818 - 0, "ipu-ic", chan);
17820 - dev_err(priv->ipu->dev, "could not acquire irq %d\n",
17821 - chan->out_eof_irq);
17822 - chan->out_eof_irq = -1;
17826 - chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
17827 - chan->rotation_out_chan,
17830 - ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
17831 - 0, "ipu-ic", chan);
17833 - dev_err(priv->ipu->dev, "could not acquire irq %d\n",
17834 - chan->rot_out_eof_irq);
17835 - chan->rot_out_eof_irq = -1;
17841 - release_ipu_resources(chan);
17845 -static int fill_image(struct ipu_image_convert_ctx *ctx,
17846 - struct ipu_image_convert_image *ic_image,
17847 - struct ipu_image *image,
17848 - enum ipu_image_convert_type type)
17850 - struct ipu_image_convert_priv *priv = ctx->chan->priv;
17852 - ic_image->base = *image;
17853 - ic_image->type = type;
17855 - ic_image->fmt = get_format(image->pix.pixelformat);
17856 - if (!ic_image->fmt) {
17857 - dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
17858 - type == IMAGE_CONVERT_OUT ? "Output" : "Input");
17862 - if (ic_image->fmt->planar)
17863 - ic_image->stride = ic_image->base.pix.width;
17865 - ic_image->stride = ic_image->base.pix.bytesperline;
17870 -/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
17871 -static unsigned int clamp_align(unsigned int x, unsigned int min,
17872 - unsigned int max, unsigned int align)
17874 - /* Bits that must be zero to be aligned */
17875 - unsigned int mask = ~((1 << align) - 1);
17877 - /* Clamp to aligned min and max */
17878 - x = clamp(x, (min + ~mask) & mask, max & mask);
17880 - /* Round to nearest aligned value */
17882 - x = (x + (1 << (align - 1))) & mask;
17887 -/* Adjusts input/output images to IPU restrictions */
17888 -void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
17889 - enum ipu_rotate_mode rot_mode)
17891 - const struct ipu_image_pixfmt *infmt, *outfmt;
17892 - u32 w_align_out, h_align_out;
17893 - u32 w_align_in, h_align_in;
17895 - infmt = get_format(in->pix.pixelformat);
17896 - outfmt = get_format(out->pix.pixelformat);
17898 - /* set some default pixel formats if needed */
17900 - in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
17901 - infmt = get_format(V4L2_PIX_FMT_RGB24);
17904 - out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
17905 - outfmt = get_format(V4L2_PIX_FMT_RGB24);
17908 - /* image converter does not handle fields */
17909 - in->pix.field = out->pix.field = V4L2_FIELD_NONE;
17911 - /* resizer cannot downsize more than 4:1 */
17912 - if (ipu_rot_mode_is_irt(rot_mode)) {
17913 - out->pix.height = max_t(__u32, out->pix.height,
17914 - in->pix.width / 4);
17915 - out->pix.width = max_t(__u32, out->pix.width,
17916 - in->pix.height / 4);
17918 - out->pix.width = max_t(__u32, out->pix.width,
17919 - in->pix.width / 4);
17920 - out->pix.height = max_t(__u32, out->pix.height,
17921 - in->pix.height / 4);
17924 - /* align input width/height */
17925 - w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
17927 - h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
17929 - in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
17931 - in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
17934 - /* align output width/height */
17935 - w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
17937 - h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
17939 - out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
17941 - out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
17944 - /* set input/output strides and image sizes */
17945 - in->pix.bytesperline = infmt->planar ?
17946 - clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
17948 - clamp_align((in->pix.width * infmt->bpp) >> 3,
17949 - ((2 << w_align_in) * infmt->bpp) >> 3,
17950 - (MAX_W * infmt->bpp) >> 3,
17952 - in->pix.sizeimage = infmt->planar ?
17953 - (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
17954 - in->pix.height * in->pix.bytesperline;
17955 - out->pix.bytesperline = outfmt->planar ? out->pix.width :
17956 - (out->pix.width * outfmt->bpp) >> 3;
17957 - out->pix.sizeimage = outfmt->planar ?
17958 - (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
17959 - out->pix.height * out->pix.bytesperline;
17961 -EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
17964 - * this is used by ipu_image_convert_prepare() to verify set input and
17965 - * output images are valid before starting the conversion. Clients can
17966 - * also call it before calling ipu_image_convert_prepare().
17968 -int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
17969 - enum ipu_rotate_mode rot_mode)
17971 - struct ipu_image testin, testout;
17976 - ipu_image_convert_adjust(&testin, &testout, rot_mode);
17978 - if (testin.pix.width != in->pix.width ||
17979 - testin.pix.height != in->pix.height ||
17980 - testout.pix.width != out->pix.width ||
17981 - testout.pix.height != out->pix.height)
17986 -EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
17989 - * Call ipu_image_convert_prepare() to prepare for the conversion of
17990 - * given images and rotation mode. Returns a new conversion context.
17992 -struct ipu_image_convert_ctx *
17993 -ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
17994 - struct ipu_image *in, struct ipu_image *out,
17995 - enum ipu_rotate_mode rot_mode,
17996 - ipu_image_convert_cb_t complete,
17997 - void *complete_context)
17999 - struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
18000 - struct ipu_image_convert_image *s_image, *d_image;
18001 - struct ipu_image_convert_chan *chan;
18002 - struct ipu_image_convert_ctx *ctx;
18003 - unsigned long flags;
18008 - if (!in || !out || !complete ||
18009 - (ic_task != IC_TASK_VIEWFINDER &&
18010 - ic_task != IC_TASK_POST_PROCESSOR))
18011 - return ERR_PTR(-EINVAL);
18013 - /* verify the in/out images before continuing */
18014 - ret = ipu_image_convert_verify(in, out, rot_mode);
18016 - dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
18018 - return ERR_PTR(ret);
18021 - chan = &priv->chan[ic_task];
18023 - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
18025 - return ERR_PTR(-ENOMEM);
18027 - dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
18028 - chan->ic_task, ctx);
18030 - ctx->chan = chan;
18031 - init_completion(&ctx->aborted);
18033 - ctx->rot_mode = rot_mode;
18035 - /* Sets ctx->in.num_rows/cols as well */
18036 - ret = calc_image_resize_coefficients(ctx, in, out);
18040 - s_image = &ctx->in;
18041 - d_image = &ctx->out;
18043 - /* set tiling and rotation */
18044 - if (ipu_rot_mode_is_irt(rot_mode)) {
18045 - d_image->num_rows = s_image->num_cols;
18046 - d_image->num_cols = s_image->num_rows;
18048 - d_image->num_rows = s_image->num_rows;
18049 - d_image->num_cols = s_image->num_cols;
18052 - ctx->num_tiles = d_image->num_cols * d_image->num_rows;
18054 - ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
18057 - ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
18061 - calc_out_tile_map(ctx);
18063 - find_seams(ctx, s_image, d_image);
18065 - ret = calc_tile_dimensions(ctx, s_image);
18069 - ret = calc_tile_offsets(ctx, s_image);
18073 - calc_tile_dimensions(ctx, d_image);
18074 - ret = calc_tile_offsets(ctx, d_image);
18078 - calc_tile_resize_coefficients(ctx);
18080 - ret = ipu_ic_calc_csc(&ctx->csc,
18081 - s_image->base.pix.ycbcr_enc,
18082 - s_image->base.pix.quantization,
18083 - ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
18084 - d_image->base.pix.ycbcr_enc,
18085 - d_image->base.pix.quantization,
18086 - ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
18090 - dump_format(ctx, s_image);
18091 - dump_format(ctx, d_image);
18093 - ctx->complete = complete;
18094 - ctx->complete_context = complete_context;
18097 - * Can we use double-buffering for this operation? If there is
18098 - * only one tile (the whole image can be converted in a single
18099 - * operation) there's no point in using double-buffering. Also,
18100 - * the IPU's IDMAC channels allow only a single U and V plane
18101 - * offset shared between both buffers, but these offsets change
18102 - * for every tile, and therefore would have to be updated for
18103 - * each buffer which is not possible. So double-buffering is
18104 - * impossible when either the source or destination images are
18105 - * a planar format (YUV420, YUV422P, etc.). Further, differently
18106 - * sized tiles or different resizing coefficients per tile
18107 - * prevent double-buffering as well.
18109 - ctx->double_buffering = (ctx->num_tiles > 1 &&
18110 - !s_image->fmt->planar &&
18111 - !d_image->fmt->planar);
18112 - for (i = 1; i < ctx->num_tiles; i++) {
18113 - if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
18114 - ctx->in.tile[i].height != ctx->in.tile[0].height ||
18115 - ctx->out.tile[i].width != ctx->out.tile[0].width ||
18116 - ctx->out.tile[i].height != ctx->out.tile[0].height) {
18117 - ctx->double_buffering = false;
18121 - for (i = 1; i < ctx->in.num_cols; i++) {
18122 - if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
18123 - ctx->double_buffering = false;
18127 - for (i = 1; i < ctx->in.num_rows; i++) {
18128 - if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
18129 - ctx->double_buffering = false;
18134 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
18135 - unsigned long intermediate_size = d_image->tile[0].size;
18137 - for (i = 1; i < ctx->num_tiles; i++) {
18138 - if (d_image->tile[i].size > intermediate_size)
18139 - intermediate_size = d_image->tile[i].size;
18142 - ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
18143 - intermediate_size);
18146 - if (ctx->double_buffering) {
18147 - ret = alloc_dma_buf(priv,
18148 - &ctx->rot_intermediate[1],
18149 - intermediate_size);
18151 - goto out_free_dmabuf0;
18155 - spin_lock_irqsave(&chan->irqlock, flags);
18157 - get_res = list_empty(&chan->ctx_list);
18159 - list_add_tail(&ctx->list, &chan->ctx_list);
18161 - spin_unlock_irqrestore(&chan->irqlock, flags);
18164 - ret = get_ipu_resources(chan);
18166 - goto out_free_dmabuf1;
18172 - free_dma_buf(priv, &ctx->rot_intermediate[1]);
18173 - spin_lock_irqsave(&chan->irqlock, flags);
18174 - list_del(&ctx->list);
18175 - spin_unlock_irqrestore(&chan->irqlock, flags);
18177 - free_dma_buf(priv, &ctx->rot_intermediate[0]);
18180 - return ERR_PTR(ret);
18182 -EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
18185 - * Carry out a single image conversion run. Only the physaddr's of the input
18186 - * and output image buffers are needed. The conversion context must have
18187 - * been created previously with ipu_image_convert_prepare().
18189 -int ipu_image_convert_queue(struct ipu_image_convert_run *run)
18191 - struct ipu_image_convert_chan *chan;
18192 - struct ipu_image_convert_priv *priv;
18193 - struct ipu_image_convert_ctx *ctx;
18194 - unsigned long flags;
18197 - if (!run || !run->ctx || !run->in_phys || !run->out_phys)
18201 - chan = ctx->chan;
18202 - priv = chan->priv;
18204 - dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
18205 - chan->ic_task, ctx, run);
18207 - INIT_LIST_HEAD(&run->list);
18209 - spin_lock_irqsave(&chan->irqlock, flags);
18211 - if (ctx->aborting) {
18216 - list_add_tail(&run->list, &chan->pending_q);
18218 - if (!chan->current_run) {
18219 - ret = do_run(run);
18221 - chan->current_run = NULL;
18224 - spin_unlock_irqrestore(&chan->irqlock, flags);
18227 -EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
18229 -/* Abort any active or pending conversions for this context */
18230 -static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
18232 - struct ipu_image_convert_chan *chan = ctx->chan;
18233 - struct ipu_image_convert_priv *priv = chan->priv;
18234 - struct ipu_image_convert_run *run, *active_run, *tmp;
18235 - unsigned long flags;
18236 - int run_count, ret;
18238 - spin_lock_irqsave(&chan->irqlock, flags);
18240 - /* move all remaining pending runs in this context to done_q */
18241 - list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
18242 - if (run->ctx != ctx)
18244 - run->status = -EIO;
18245 - list_move_tail(&run->list, &chan->done_q);
18248 - run_count = get_run_count(ctx, &chan->done_q);
18249 - active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
18250 - chan->current_run : NULL;
18253 - reinit_completion(&ctx->aborted);
18255 - ctx->aborting = true;
18257 - spin_unlock_irqrestore(&chan->irqlock, flags);
18259 - if (!run_count && !active_run) {
18260 - dev_dbg(priv->ipu->dev,
18261 - "%s: task %u: no abort needed for ctx %p\n",
18262 - __func__, chan->ic_task, ctx);
18266 - if (!active_run) {
18267 - empty_done_q(chan);
18271 - dev_dbg(priv->ipu->dev,
18272 - "%s: task %u: wait for completion: %d runs\n",
18273 - __func__, chan->ic_task, run_count);
18275 - ret = wait_for_completion_timeout(&ctx->aborted,
18276 - msecs_to_jiffies(10000));
18278 - dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
18279 - force_abort(ctx);
18283 -void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
18285 - __ipu_image_convert_abort(ctx);
18286 - ctx->aborting = false;
18288 -EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
18290 -/* Unprepare image conversion context */
18291 -void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
18293 - struct ipu_image_convert_chan *chan = ctx->chan;
18294 - struct ipu_image_convert_priv *priv = chan->priv;
18295 - unsigned long flags;
18298 - /* make sure no runs are hanging around */
18299 - __ipu_image_convert_abort(ctx);
18301 - dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
18302 - chan->ic_task, ctx);
18304 - spin_lock_irqsave(&chan->irqlock, flags);
18306 - list_del(&ctx->list);
18308 - put_res = list_empty(&chan->ctx_list);
18310 - spin_unlock_irqrestore(&chan->irqlock, flags);
18313 - release_ipu_resources(chan);
18315 - free_dma_buf(priv, &ctx->rot_intermediate[1]);
18316 - free_dma_buf(priv, &ctx->rot_intermediate[0]);
18320 -EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
18323 - * "Canned" asynchronous single image conversion. Allocates and returns
18324 - * a new conversion run. On successful return the caller must free the
18325 - * run and call ipu_image_convert_unprepare() after conversion completes.
18327 -struct ipu_image_convert_run *
18328 -ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
18329 - struct ipu_image *in, struct ipu_image *out,
18330 - enum ipu_rotate_mode rot_mode,
18331 - ipu_image_convert_cb_t complete,
18332 - void *complete_context)
18334 - struct ipu_image_convert_ctx *ctx;
18335 - struct ipu_image_convert_run *run;
18338 - ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
18339 - complete, complete_context);
18341 - return ERR_CAST(ctx);
18343 - run = kzalloc(sizeof(*run), GFP_KERNEL);
18345 - ipu_image_convert_unprepare(ctx);
18346 - return ERR_PTR(-ENOMEM);
18350 - run->in_phys = in->phys0;
18351 - run->out_phys = out->phys0;
18353 - ret = ipu_image_convert_queue(run);
18355 - ipu_image_convert_unprepare(ctx);
18357 - return ERR_PTR(ret);
18362 -EXPORT_SYMBOL_GPL(ipu_image_convert);
18364 -/* "Canned" synchronous single image conversion */
18365 -static void image_convert_sync_complete(struct ipu_image_convert_run *run,
18368 - struct completion *comp = data;
18373 -int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
18374 - struct ipu_image *in, struct ipu_image *out,
18375 - enum ipu_rotate_mode rot_mode)
18377 - struct ipu_image_convert_run *run;
18378 - struct completion comp;
18381 - init_completion(&comp);
18383 - run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
18384 - image_convert_sync_complete, &comp);
18386 - return PTR_ERR(run);
18388 - ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
18389 - ret = (ret == 0) ? -ETIMEDOUT : 0;
18391 - ipu_image_convert_unprepare(run->ctx);
18396 -EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
18398 -int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
18400 - struct ipu_image_convert_priv *priv;
18403 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
18407 - ipu->image_convert_priv = priv;
18410 - for (i = 0; i < IC_NUM_TASKS; i++) {
18411 - struct ipu_image_convert_chan *chan = &priv->chan[i];
18413 - chan->ic_task = i;
18414 - chan->priv = priv;
18415 - chan->dma_ch = &image_convert_dma_chan[i];
18416 - chan->out_eof_irq = -1;
18417 - chan->rot_out_eof_irq = -1;
18419 - spin_lock_init(&chan->irqlock);
18420 - INIT_LIST_HEAD(&chan->ctx_list);
18421 - INIT_LIST_HEAD(&chan->pending_q);
18422 - INIT_LIST_HEAD(&chan->done_q);
18428 -void ipu_image_convert_exit(struct ipu_soc *ipu)
18431 --- a/drivers/gpu/ipu-v3/ipu-pre.c
18434 -// SPDX-License-Identifier: GPL-2.0-only
18436 - * Copyright (c) 2017 Lucas Stach, Pengutronix
18439 -#include <drm/drm_fourcc.h>
18440 -#include <linux/clk.h>
18441 -#include <linux/err.h>
18442 -#include <linux/genalloc.h>
18443 -#include <linux/module.h>
18444 -#include <linux/of.h>
18445 -#include <linux/platform_device.h>
18446 -#include <video/imx-ipu-v3.h>
18448 -#include "ipu-prv.h"
18450 -#define IPU_PRE_MAX_WIDTH 2048
18451 -#define IPU_PRE_NUM_SCANLINES 8
18453 -#define IPU_PRE_CTRL 0x000
18454 -#define IPU_PRE_CTRL_SET 0x004
18455 -#define IPU_PRE_CTRL_ENABLE (1 << 0)
18456 -#define IPU_PRE_CTRL_BLOCK_EN (1 << 1)
18457 -#define IPU_PRE_CTRL_BLOCK_16 (1 << 2)
18458 -#define IPU_PRE_CTRL_SDW_UPDATE (1 << 4)
18459 -#define IPU_PRE_CTRL_VFLIP (1 << 5)
18460 -#define IPU_PRE_CTRL_SO (1 << 6)
18461 -#define IPU_PRE_CTRL_INTERLACED_FIELD (1 << 7)
18462 -#define IPU_PRE_CTRL_HANDSHAKE_EN (1 << 8)
18463 -#define IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v) ((v & 0x3) << 9)
18464 -#define IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN (1 << 11)
18465 -#define IPU_PRE_CTRL_EN_REPEAT (1 << 28)
18466 -#define IPU_PRE_CTRL_TPR_REST_SEL (1 << 29)
18467 -#define IPU_PRE_CTRL_CLKGATE (1 << 30)
18468 -#define IPU_PRE_CTRL_SFTRST (1 << 31)
18470 -#define IPU_PRE_CUR_BUF 0x030
18472 -#define IPU_PRE_NEXT_BUF 0x040
18474 -#define IPU_PRE_TPR_CTRL 0x070
18475 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT(v) ((v & 0xff) << 0)
18476 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK 0xff
18477 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT (1 << 0)
18478 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF (1 << 4)
18479 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF (1 << 5)
18480 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED (1 << 6)
18482 -#define IPU_PRE_PREFETCH_ENG_CTRL 0x080
18483 -#define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0)
18484 -#define IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v) ((v & 0x7) << 1)
18485 -#define IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
18486 -#define IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v) ((v & 0x7) << 8)
18487 -#define IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS (1 << 11)
18488 -#define IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE (1 << 12)
18489 -#define IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP (1 << 14)
18490 -#define IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN (1 << 15)
18492 -#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE 0x0a0
18493 -#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v) ((v & 0xffff) << 0)
18494 -#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v) ((v & 0xffff) << 16)
18496 -#define IPU_PRE_PREFETCH_ENG_PITCH 0x0d0
18497 -#define IPU_PRE_PREFETCH_ENG_PITCH_Y(v) ((v & 0xffff) << 0)
18498 -#define IPU_PRE_PREFETCH_ENG_PITCH_UV(v) ((v & 0xffff) << 16)
18500 -#define IPU_PRE_STORE_ENG_CTRL 0x110
18501 -#define IPU_PRE_STORE_ENG_CTRL_STORE_EN (1 << 0)
18502 -#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1)
18503 -#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
18505 -#define IPU_PRE_STORE_ENG_STATUS 0x120
18506 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK 0xffff
18507 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
18508 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK 0x3fff
18509 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
18510 -#define IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL (1 << 30)
18511 -#define IPU_PRE_STORE_ENG_STATUS_STORE_FIELD (1 << 31)
18513 -#define IPU_PRE_STORE_ENG_SIZE 0x130
18514 -#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0)
18515 -#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16)
18517 -#define IPU_PRE_STORE_ENG_PITCH 0x140
18518 -#define IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v) ((v & 0xffff) << 0)
18520 -#define IPU_PRE_STORE_ENG_ADDR 0x150
18523 - struct list_head list;
18524 - struct device *dev;
18526 - void __iomem *regs;
18527 - struct clk *clk_axi;
18528 - struct gen_pool *iram;
18530 - dma_addr_t buffer_paddr;
18531 - void *buffer_virt;
18533 - unsigned int safe_window_end;
18534 - unsigned int last_bufaddr;
18537 -static DEFINE_MUTEX(ipu_pre_list_mutex);
18538 -static LIST_HEAD(ipu_pre_list);
18539 -static int available_pres;
18541 -int ipu_pre_get_available_count(void)
18543 - return available_pres;
18547 -ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
18549 - struct device_node *pre_node = of_parse_phandle(dev->of_node,
18551 - struct ipu_pre *pre;
18553 - mutex_lock(&ipu_pre_list_mutex);
18554 - list_for_each_entry(pre, &ipu_pre_list, list) {
18555 - if (pre_node == pre->dev->of_node) {
18556 - mutex_unlock(&ipu_pre_list_mutex);
18557 - device_link_add(dev, pre->dev,
18558 - DL_FLAG_AUTOREMOVE_CONSUMER);
18559 - of_node_put(pre_node);
18563 - mutex_unlock(&ipu_pre_list_mutex);
18565 - of_node_put(pre_node);
18570 -int ipu_pre_get(struct ipu_pre *pre)
18577 - /* first get the engine out of reset and remove clock gating */
18578 - writel(0, pre->regs + IPU_PRE_CTRL);
18580 - /* init defaults that should be applied to all streams */
18581 - val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
18582 - IPU_PRE_CTRL_HANDSHAKE_EN |
18583 - IPU_PRE_CTRL_TPR_REST_SEL |
18584 - IPU_PRE_CTRL_SDW_UPDATE;
18585 - writel(val, pre->regs + IPU_PRE_CTRL);
18587 - pre->in_use = true;
18591 -void ipu_pre_put(struct ipu_pre *pre)
18593 - writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
18595 - pre->in_use = false;
18598 -void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
18599 - unsigned int height, unsigned int stride, u32 format,
18600 - uint64_t modifier, unsigned int bufaddr)
18602 - const struct drm_format_info *info = drm_format_info(format);
18603 - u32 active_bpp = info->cpp[0] >> 1;
18606 - /* calculate safe window for ctrl register updates */
18607 - if (modifier == DRM_FORMAT_MOD_LINEAR)
18608 - pre->safe_window_end = height - 2;
18610 - pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
18612 - writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
18613 - writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
18614 - pre->last_bufaddr = bufaddr;
18616 - val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
18617 - IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
18618 - IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
18619 - IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
18620 - IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
18621 - writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
18623 - val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
18624 - IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
18625 - writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
18627 - val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
18628 - writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
18630 - val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
18631 - IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
18632 - IPU_PRE_STORE_ENG_CTRL_STORE_EN;
18633 - writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
18635 - val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
18636 - IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
18637 - writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
18639 - val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
18640 - writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
18642 - writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
18644 - val = readl(pre->regs + IPU_PRE_TPR_CTRL);
18645 - val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
18646 - if (modifier != DRM_FORMAT_MOD_LINEAR) {
18647 - /* only support single buffer formats for now */
18648 - val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
18649 - if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
18650 - val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
18651 - if (info->cpp[0] == 2)
18652 - val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
18654 - writel(val, pre->regs + IPU_PRE_TPR_CTRL);
18656 - val = readl(pre->regs + IPU_PRE_CTRL);
18657 - val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
18658 - IPU_PRE_CTRL_SDW_UPDATE;
18659 - if (modifier == DRM_FORMAT_MOD_LINEAR)
18660 - val &= ~IPU_PRE_CTRL_BLOCK_EN;
18662 - val |= IPU_PRE_CTRL_BLOCK_EN;
18663 - writel(val, pre->regs + IPU_PRE_CTRL);
18666 -void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
18668 - unsigned long timeout = jiffies + msecs_to_jiffies(5);
18669 - unsigned short current_yblock;
18672 - if (bufaddr == pre->last_bufaddr)
18675 - writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
18676 - pre->last_bufaddr = bufaddr;
18679 - if (time_after(jiffies, timeout)) {
18680 - dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
18684 - val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
18686 - (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
18687 - IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
18688 - } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
18690 - writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
18693 -bool ipu_pre_update_pending(struct ipu_pre *pre)
18695 - return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
18696 - IPU_PRE_CTRL_SDW_UPDATE);
18699 -u32 ipu_pre_get_baddr(struct ipu_pre *pre)
18701 - return (u32)pre->buffer_paddr;
18704 -static int ipu_pre_probe(struct platform_device *pdev)
18706 - struct device *dev = &pdev->dev;
18707 - struct resource *res;
18708 - struct ipu_pre *pre;
18710 - pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
18714 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
18715 - pre->regs = devm_ioremap_resource(&pdev->dev, res);
18716 - if (IS_ERR(pre->regs))
18717 - return PTR_ERR(pre->regs);
18719 - pre->clk_axi = devm_clk_get(dev, "axi");
18720 - if (IS_ERR(pre->clk_axi))
18721 - return PTR_ERR(pre->clk_axi);
18723 - pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
18725 - return -EPROBE_DEFER;
18728 - * Allocate IRAM buffer with maximum size. This could be made dynamic,
18729 - * but as there is no other user of this IRAM region and we can fit all
18730 - * max sized buffers into it, there is no need yet.
18732 - pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
18733 - IPU_PRE_NUM_SCANLINES * 4,
18734 - &pre->buffer_paddr);
18735 - if (!pre->buffer_virt)
18738 - clk_prepare_enable(pre->clk_axi);
18741 - platform_set_drvdata(pdev, pre);
18742 - mutex_lock(&ipu_pre_list_mutex);
18743 - list_add(&pre->list, &ipu_pre_list);
18744 - available_pres++;
18745 - mutex_unlock(&ipu_pre_list_mutex);
18750 -static int ipu_pre_remove(struct platform_device *pdev)
18752 - struct ipu_pre *pre = platform_get_drvdata(pdev);
18754 - mutex_lock(&ipu_pre_list_mutex);
18755 - list_del(&pre->list);
18756 - available_pres--;
18757 - mutex_unlock(&ipu_pre_list_mutex);
18759 - clk_disable_unprepare(pre->clk_axi);
18761 - if (pre->buffer_virt)
18762 - gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
18763 - IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
18767 -static const struct of_device_id ipu_pre_dt_ids[] = {
18768 - { .compatible = "fsl,imx6qp-pre", },
18769 - { /* sentinel */ },
18772 -struct platform_driver ipu_pre_drv = {
18773 - .probe = ipu_pre_probe,
18774 - .remove = ipu_pre_remove,
18776 - .name = "imx-ipu-pre",
18777 - .of_match_table = ipu_pre_dt_ids,
18780 --- a/drivers/gpu/ipu-v3/ipu-prg.c
18783 -// SPDX-License-Identifier: GPL-2.0-only
18785 - * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
18788 -#include <drm/drm_fourcc.h>
18789 -#include <linux/clk.h>
18790 -#include <linux/err.h>
18791 -#include <linux/iopoll.h>
18792 -#include <linux/mfd/syscon.h>
18793 -#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
18794 -#include <linux/module.h>
18795 -#include <linux/of.h>
18796 -#include <linux/platform_device.h>
18797 -#include <linux/pm_runtime.h>
18798 -#include <linux/regmap.h>
18799 -#include <video/imx-ipu-v3.h>
18801 -#include "ipu-prv.h"
18803 -#define IPU_PRG_CTL 0x00
18804 -#define IPU_PRG_CTL_BYPASS(i) (1 << (0 + i))
18805 -#define IPU_PRG_CTL_SOFT_ARID_MASK 0x3
18806 -#define IPU_PRG_CTL_SOFT_ARID_SHIFT(i) (8 + i * 2)
18807 -#define IPU_PRG_CTL_SOFT_ARID(i, v) ((v & 0x3) << (8 + 2 * i))
18808 -#define IPU_PRG_CTL_SO(i) (1 << (16 + i))
18809 -#define IPU_PRG_CTL_VFLIP(i) (1 << (19 + i))
18810 -#define IPU_PRG_CTL_BLOCK_MODE(i) (1 << (22 + i))
18811 -#define IPU_PRG_CTL_CNT_LOAD_EN(i) (1 << (25 + i))
18812 -#define IPU_PRG_CTL_SOFTRST (1 << 30)
18813 -#define IPU_PRG_CTL_SHADOW_EN (1 << 31)
18815 -#define IPU_PRG_STATUS 0x04
18816 -#define IPU_PRG_STATUS_BUFFER0_READY(i) (1 << (0 + i * 2))
18817 -#define IPU_PRG_STATUS_BUFFER1_READY(i) (1 << (1 + i * 2))
18819 -#define IPU_PRG_QOS 0x08
18820 -#define IPU_PRG_QOS_ARID_MASK 0xf
18821 -#define IPU_PRG_QOS_ARID_SHIFT(i) (0 + i * 4)
18823 -#define IPU_PRG_REG_UPDATE 0x0c
18824 -#define IPU_PRG_REG_UPDATE_REG_UPDATE (1 << 0)
18826 -#define IPU_PRG_STRIDE(i) (0x10 + i * 0x4)
18827 -#define IPU_PRG_STRIDE_STRIDE_MASK 0x3fff
18829 -#define IPU_PRG_CROP_LINE 0x1c
18831 -#define IPU_PRG_THD 0x20
18833 -#define IPU_PRG_BADDR(i) (0x24 + i * 0x4)
18835 -#define IPU_PRG_OFFSET(i) (0x30 + i * 0x4)
18837 -#define IPU_PRG_ILO(i) (0x3c + i * 0x4)
18839 -#define IPU_PRG_HEIGHT(i) (0x48 + i * 0x4)
18840 -#define IPU_PRG_HEIGHT_PRE_HEIGHT_MASK 0xfff
18841 -#define IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT 0
18842 -#define IPU_PRG_HEIGHT_IPU_HEIGHT_MASK 0xfff
18843 -#define IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT 16
18845 -struct ipu_prg_channel {
18851 - struct list_head list;
18852 - struct device *dev;
18855 - void __iomem *regs;
18856 - struct clk *clk_ipg, *clk_axi;
18857 - struct regmap *iomuxc_gpr;
18858 - struct ipu_pre *pres[3];
18860 - struct ipu_prg_channel chan[3];
18863 -static DEFINE_MUTEX(ipu_prg_list_mutex);
18864 -static LIST_HEAD(ipu_prg_list);
18867 -ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
18869 - struct device_node *prg_node = of_parse_phandle(dev->of_node,
18871 - struct ipu_prg *prg;
18873 - mutex_lock(&ipu_prg_list_mutex);
18874 - list_for_each_entry(prg, &ipu_prg_list, list) {
18875 - if (prg_node == prg->dev->of_node) {
18876 - mutex_unlock(&ipu_prg_list_mutex);
18877 - device_link_add(dev, prg->dev,
18878 - DL_FLAG_AUTOREMOVE_CONSUMER);
18879 - prg->id = ipu_id;
18880 - of_node_put(prg_node);
18884 - mutex_unlock(&ipu_prg_list_mutex);
18886 - of_node_put(prg_node);
18891 -int ipu_prg_max_active_channels(void)
18893 - return ipu_pre_get_available_count();
18895 -EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
18897 -bool ipu_prg_present(struct ipu_soc *ipu)
18899 - if (ipu->prg_priv)
18904 -EXPORT_SYMBOL_GPL(ipu_prg_present);
18906 -bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
18907 - uint64_t modifier)
18909 - const struct drm_format_info *info = drm_format_info(format);
18911 - if (info->num_planes != 1)
18914 - switch (modifier) {
18915 - case DRM_FORMAT_MOD_LINEAR:
18916 - case DRM_FORMAT_MOD_VIVANTE_TILED:
18917 - case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
18923 -EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
18925 -int ipu_prg_enable(struct ipu_soc *ipu)
18927 - struct ipu_prg *prg = ipu->prg_priv;
18932 - return pm_runtime_get_sync(prg->dev);
18934 -EXPORT_SYMBOL_GPL(ipu_prg_enable);
18936 -void ipu_prg_disable(struct ipu_soc *ipu)
18938 - struct ipu_prg *prg = ipu->prg_priv;
18943 - pm_runtime_put(prg->dev);
18945 -EXPORT_SYMBOL_GPL(ipu_prg_disable);
18948 - * The channel configuartion functions below are not thread safe, as they
18949 - * must be only called from the atomic commit path in the DRM driver, which
18950 - * is properly serialized.
18952 -static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
18955 - * This isn't clearly documented in the RM, but IPU to PRG channel
18956 - * assignment is fixed, as only with this mapping the control signals
18959 - switch (ipu_chan) {
18960 - case IPUV3_CHANNEL_MEM_BG_SYNC:
18962 - case IPUV3_CHANNEL_MEM_FG_SYNC:
18964 - case IPUV3_CHANNEL_MEM_DC_SYNC:
18971 -static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
18975 - /* channel 0 is special as it is hardwired to one of the PREs */
18976 - if (prg_chan == 0) {
18977 - ret = ipu_pre_get(prg->pres[0]);
18980 - prg->chan[prg_chan].used_pre = 0;
18984 - for (i = 1; i < 3; i++) {
18985 - ret = ipu_pre_get(prg->pres[i]);
18990 - prg->chan[prg_chan].used_pre = i;
18992 - /* configure the PRE to PRG channel mux */
18993 - shift = (i == 1) ? 12 : 14;
18994 - mux = (prg->id << 1) | (prg_chan - 1);
18995 - regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
18996 - 0x3 << shift, mux << shift);
18998 - /* check other mux, must not point to same channel */
18999 - shift = (i == 1) ? 14 : 12;
19000 - regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
19001 - if (((val >> shift) & 0x3) == mux) {
19002 - regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
19004 - (mux ^ 0x1) << shift);
19012 - dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
19016 -static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
19018 - struct ipu_prg_channel *chan = &prg->chan[prg_chan];
19020 - ipu_pre_put(prg->pres[chan->used_pre]);
19021 - chan->used_pre = -1;
19024 -void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
19026 - int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
19027 - struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
19028 - struct ipu_prg_channel *chan;
19031 - if (prg_chan < 0)
19034 - chan = &prg->chan[prg_chan];
19035 - if (!chan->enabled)
19038 - pm_runtime_get_sync(prg->dev);
19040 - val = readl(prg->regs + IPU_PRG_CTL);
19041 - val |= IPU_PRG_CTL_BYPASS(prg_chan);
19042 - writel(val, prg->regs + IPU_PRG_CTL);
19044 - val = IPU_PRG_REG_UPDATE_REG_UPDATE;
19045 - writel(val, prg->regs + IPU_PRG_REG_UPDATE);
19047 - pm_runtime_put(prg->dev);
19049 - ipu_prg_put_pre(prg, prg_chan);
19051 - chan->enabled = false;
19053 -EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
19055 -int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
19056 - unsigned int axi_id, unsigned int width,
19057 - unsigned int height, unsigned int stride,
19058 - u32 format, uint64_t modifier, unsigned long *eba)
19060 - int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
19061 - struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
19062 - struct ipu_prg_channel *chan;
19066 - if (prg_chan < 0)
19069 - chan = &prg->chan[prg_chan];
19071 - if (chan->enabled) {
19072 - ipu_pre_update(prg->pres[chan->used_pre], *eba);
19076 - ret = ipu_prg_get_pre(prg, prg_chan);
19080 - ipu_pre_configure(prg->pres[chan->used_pre],
19081 - width, height, stride, format, modifier, *eba);
19084 - pm_runtime_get_sync(prg->dev);
19086 - val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
19087 - writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
19089 - val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
19090 - IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
19091 - ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
19092 - IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
19093 - writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
19095 - val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
19097 - writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
19099 - val = readl(prg->regs + IPU_PRG_CTL);
19100 - /* config AXI ID */
19101 - val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
19102 - IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
19103 - val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
19104 - /* enable channel */
19105 - val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
19106 - writel(val, prg->regs + IPU_PRG_CTL);
19108 - val = IPU_PRG_REG_UPDATE_REG_UPDATE;
19109 - writel(val, prg->regs + IPU_PRG_REG_UPDATE);
19111 - /* wait for both double buffers to be filled */
19112 - readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
19113 - (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
19114 - (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
19117 - pm_runtime_put(prg->dev);
19119 - chan->enabled = true;
19122 -EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
19124 -bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
19126 - int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
19127 - struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
19128 - struct ipu_prg_channel *chan;
19130 - if (prg_chan < 0)
19133 - chan = &prg->chan[prg_chan];
19134 - WARN_ON(!chan->enabled);
19136 - return ipu_pre_update_pending(prg->pres[chan->used_pre]);
19138 -EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
19140 -static int ipu_prg_probe(struct platform_device *pdev)
19142 - struct device *dev = &pdev->dev;
19143 - struct resource *res;
19144 - struct ipu_prg *prg;
19148 - prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
19152 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
19153 - prg->regs = devm_ioremap_resource(&pdev->dev, res);
19154 - if (IS_ERR(prg->regs))
19155 - return PTR_ERR(prg->regs);
19158 - prg->clk_ipg = devm_clk_get(dev, "ipg");
19159 - if (IS_ERR(prg->clk_ipg))
19160 - return PTR_ERR(prg->clk_ipg);
19162 - prg->clk_axi = devm_clk_get(dev, "axi");
19163 - if (IS_ERR(prg->clk_axi))
19164 - return PTR_ERR(prg->clk_axi);
19166 - prg->iomuxc_gpr =
19167 - syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
19168 - if (IS_ERR(prg->iomuxc_gpr))
19169 - return PTR_ERR(prg->iomuxc_gpr);
19171 - for (i = 0; i < 3; i++) {
19172 - prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
19173 - if (!prg->pres[i])
19174 - return -EPROBE_DEFER;
19177 - ret = clk_prepare_enable(prg->clk_ipg);
19181 - ret = clk_prepare_enable(prg->clk_axi);
19183 - clk_disable_unprepare(prg->clk_ipg);
19187 - /* init to free running mode */
19188 - val = readl(prg->regs + IPU_PRG_CTL);
19189 - val |= IPU_PRG_CTL_SHADOW_EN;
19190 - writel(val, prg->regs + IPU_PRG_CTL);
19192 - /* disable address threshold */
19193 - writel(0xffffffff, prg->regs + IPU_PRG_THD);
19195 - pm_runtime_set_active(dev);
19196 - pm_runtime_enable(dev);
19199 - platform_set_drvdata(pdev, prg);
19200 - mutex_lock(&ipu_prg_list_mutex);
19201 - list_add(&prg->list, &ipu_prg_list);
19202 - mutex_unlock(&ipu_prg_list_mutex);
19207 -static int ipu_prg_remove(struct platform_device *pdev)
19209 - struct ipu_prg *prg = platform_get_drvdata(pdev);
19211 - mutex_lock(&ipu_prg_list_mutex);
19212 - list_del(&prg->list);
19213 - mutex_unlock(&ipu_prg_list_mutex);
19219 -static int prg_suspend(struct device *dev)
19221 - struct ipu_prg *prg = dev_get_drvdata(dev);
19223 - clk_disable_unprepare(prg->clk_axi);
19224 - clk_disable_unprepare(prg->clk_ipg);
19229 -static int prg_resume(struct device *dev)
19231 - struct ipu_prg *prg = dev_get_drvdata(dev);
19234 - ret = clk_prepare_enable(prg->clk_ipg);
19238 - ret = clk_prepare_enable(prg->clk_axi);
19240 - clk_disable_unprepare(prg->clk_ipg);
19248 -static const struct dev_pm_ops prg_pm_ops = {
19249 - SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
19252 -static const struct of_device_id ipu_prg_dt_ids[] = {
19253 - { .compatible = "fsl,imx6qp-prg", },
19254 - { /* sentinel */ },
19257 -struct platform_driver ipu_prg_drv = {
19258 - .probe = ipu_prg_probe,
19259 - .remove = ipu_prg_remove,
19261 - .name = "imx-ipu-prg",
19262 - .pm = &prg_pm_ops,
19263 - .of_match_table = ipu_prg_dt_ids,
19266 --- a/drivers/gpu/ipu-v3/ipu-prv.h
19269 -/* SPDX-License-Identifier: GPL-2.0-or-later */
19271 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
19272 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
19274 -#ifndef __IPU_PRV_H__
19275 -#define __IPU_PRV_H__
19279 -#include <linux/types.h>
19280 -#include <linux/device.h>
19281 -#include <linux/clk.h>
19282 -#include <linux/platform_device.h>
19284 -#include <video/imx-ipu-v3.h>
19286 -#define IPU_MCU_T_DEFAULT 8
19287 -#define IPU_CM_IDMAC_REG_OFS 0x00008000
19288 -#define IPU_CM_IC_REG_OFS 0x00020000
19289 -#define IPU_CM_IRT_REG_OFS 0x00028000
19290 -#define IPU_CM_CSI0_REG_OFS 0x00030000
19291 -#define IPU_CM_CSI1_REG_OFS 0x00038000
19292 -#define IPU_CM_SMFC_REG_OFS 0x00050000
19293 -#define IPU_CM_DC_REG_OFS 0x00058000
19294 -#define IPU_CM_DMFC_REG_OFS 0x00060000
19296 -/* Register addresses */
19297 -/* IPU Common registers */
19298 -#define IPU_CM_REG(offset) (offset)
19300 -#define IPU_CONF IPU_CM_REG(0)
19302 -#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0)
19303 -#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4)
19304 -#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8)
19305 -#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac)
19306 -#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0)
19307 -#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4)
19308 -#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8)
19309 -#define IPU_SKIP IPU_CM_REG(0x00bc)
19310 -#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0)
19311 -#define IPU_DISP_GEN IPU_CM_REG(0x00c4)
19312 -#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8)
19313 -#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc)
19314 -#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0)
19315 -#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4)
19316 -#define IPU_SNOOP IPU_CM_REG(0x00d8)
19317 -#define IPU_MEM_RST IPU_CM_REG(0x00dc)
19318 -#define IPU_PM IPU_CM_REG(0x00e0)
19319 -#define IPU_GPR IPU_CM_REG(0x00e4)
19320 -#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
19321 -#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
19322 -#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32))
19323 -#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244)
19324 -#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248)
19325 -#define IPU_SRM_STAT IPU_CM_REG(0x024C)
19326 -#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250)
19327 -#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
19328 -#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
19329 -#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
19330 -#define IPU_CHA_BUF2_RDY(ch) IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
19331 -#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
19332 -#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
19334 -#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n))
19335 -#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n))
19338 -#define DP_S_SRM_MODE_MASK (0x3 << 3)
19339 -#define DP_S_SRM_MODE_NOW (0x3 << 3)
19340 -#define DP_S_SRM_MODE_NEXT_FRAME (0x1 << 3)
19342 -/* FS_PROC_FLOW1 */
19343 -#define FS_PRPENC_ROT_SRC_SEL_MASK (0xf << 0)
19344 -#define FS_PRPENC_ROT_SRC_SEL_ENC (0x7 << 0)
19345 -#define FS_PRPVF_ROT_SRC_SEL_MASK (0xf << 8)
19346 -#define FS_PRPVF_ROT_SRC_SEL_VF (0x8 << 8)
19347 -#define FS_PP_SRC_SEL_MASK (0xf << 12)
19348 -#define FS_PP_ROT_SRC_SEL_MASK (0xf << 16)
19349 -#define FS_PP_ROT_SRC_SEL_PP (0x5 << 16)
19350 -#define FS_VDI1_SRC_SEL_MASK (0x3 << 20)
19351 -#define FS_VDI3_SRC_SEL_MASK (0x3 << 20)
19352 -#define FS_PRP_SRC_SEL_MASK (0xf << 24)
19353 -#define FS_VDI_SRC_SEL_MASK (0x3 << 28)
19354 -#define FS_VDI_SRC_SEL_CSI_DIRECT (0x1 << 28)
19355 -#define FS_VDI_SRC_SEL_VDOA (0x2 << 28)
19357 -/* FS_PROC_FLOW2 */
19358 -#define FS_PRP_ENC_DEST_SEL_MASK (0xf << 0)
19359 -#define FS_PRP_ENC_DEST_SEL_IRT_ENC (0x1 << 0)
19360 -#define FS_PRPVF_DEST_SEL_MASK (0xf << 4)
19361 -#define FS_PRPVF_DEST_SEL_IRT_VF (0x1 << 4)
19362 -#define FS_PRPVF_ROT_DEST_SEL_MASK (0xf << 8)
19363 -#define FS_PP_DEST_SEL_MASK (0xf << 12)
19364 -#define FS_PP_DEST_SEL_IRT_PP (0x3 << 12)
19365 -#define FS_PP_ROT_DEST_SEL_MASK (0xf << 16)
19366 -#define FS_PRPENC_ROT_DEST_SEL_MASK (0xf << 20)
19367 -#define FS_PRP_DEST_SEL_MASK (0xf << 24)
19369 -#define IPU_DI0_COUNTER_RELEASE (1 << 24)
19370 -#define IPU_DI1_COUNTER_RELEASE (1 << 25)
19372 -#define IPU_IDMAC_REG(offset) (offset)
19374 -#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
19375 -#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
19376 -#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c)
19377 -#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
19378 -#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
19379 -#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
19380 -#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024)
19381 -#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028)
19382 -#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c)
19383 -#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030)
19384 -#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034)
19385 -#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
19386 -#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
19388 -#define IPU_NUM_IRQS (32 * 15)
19390 -enum ipu_modules {
19391 - IPU_CONF_CSI0_EN = (1 << 0),
19392 - IPU_CONF_CSI1_EN = (1 << 1),
19393 - IPU_CONF_IC_EN = (1 << 2),
19394 - IPU_CONF_ROT_EN = (1 << 3),
19395 - IPU_CONF_ISP_EN = (1 << 4),
19396 - IPU_CONF_DP_EN = (1 << 5),
19397 - IPU_CONF_DI0_EN = (1 << 6),
19398 - IPU_CONF_DI1_EN = (1 << 7),
19399 - IPU_CONF_SMFC_EN = (1 << 8),
19400 - IPU_CONF_DC_EN = (1 << 9),
19401 - IPU_CONF_DMFC_EN = (1 << 10),
19403 - IPU_CONF_VDI_EN = (1 << 12),
19405 - IPU_CONF_IDMAC_DIS = (1 << 22),
19407 - IPU_CONF_IC_DMFC_SEL = (1 << 25),
19408 - IPU_CONF_IC_DMFC_SYNC = (1 << 26),
19409 - IPU_CONF_VDI_DMFC_SYNC = (1 << 27),
19411 - IPU_CONF_CSI0_DATA_SOURCE = (1 << 28),
19412 - IPU_CONF_CSI1_DATA_SOURCE = (1 << 29),
19413 - IPU_CONF_IC_INPUT = (1 << 30),
19414 - IPU_CONF_CSI_SEL = (1 << 31),
19417 -struct ipuv3_channel {
19418 - unsigned int num;
19419 - struct ipu_soc *ipu;
19420 - struct list_head list;
19425 -struct ipu_dc_priv;
19426 -struct ipu_dmfc_priv;
19428 -struct ipu_ic_priv;
19430 -struct ipu_image_convert_priv;
19431 -struct ipu_smfc_priv;
19435 -struct ipu_devtype;
19438 - struct device *dev;
19439 - const struct ipu_devtype *devtype;
19440 - enum ipuv3_type ipu_type;
19442 - struct mutex channel_lock;
19443 - struct list_head channels;
19445 - void __iomem *cm_reg;
19446 - void __iomem *idmac_reg;
19455 - struct irq_domain *domain;
19457 - struct ipu_cpmem *cpmem_priv;
19458 - struct ipu_dc_priv *dc_priv;
19459 - struct ipu_dp_priv *dp_priv;
19460 - struct ipu_dmfc_priv *dmfc_priv;
19461 - struct ipu_di *di_priv[2];
19462 - struct ipu_csi *csi_priv[2];
19463 - struct ipu_ic_priv *ic_priv;
19464 - struct ipu_vdi *vdi_priv;
19465 - struct ipu_image_convert_priv *image_convert_priv;
19466 - struct ipu_smfc_priv *smfc_priv;
19467 - struct ipu_prg *prg_priv;
19470 -static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
19472 - return readl(ipu->idmac_reg + offset);
19475 -static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
19478 - writel(value, ipu->idmac_reg + offset);
19481 -void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
19483 -int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
19484 -int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
19486 -bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
19488 -int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
19489 - unsigned long base, u32 module, struct clk *clk_ipu);
19490 -void ipu_csi_exit(struct ipu_soc *ipu, int id);
19492 -int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
19493 - unsigned long base, unsigned long tpmem_base);
19494 -void ipu_ic_exit(struct ipu_soc *ipu);
19496 -int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
19497 - unsigned long base, u32 module);
19498 -void ipu_vdi_exit(struct ipu_soc *ipu);
19500 -int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
19501 -void ipu_image_convert_exit(struct ipu_soc *ipu);
19503 -int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
19504 - unsigned long base, u32 module, struct clk *ipu_clk);
19505 -void ipu_di_exit(struct ipu_soc *ipu, int id);
19507 -int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
19508 - struct clk *ipu_clk);
19509 -void ipu_dmfc_exit(struct ipu_soc *ipu);
19511 -int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
19512 -void ipu_dp_exit(struct ipu_soc *ipu);
19514 -int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
19515 - unsigned long template_base);
19516 -void ipu_dc_exit(struct ipu_soc *ipu);
19518 -int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
19519 -void ipu_cpmem_exit(struct ipu_soc *ipu);
19521 -int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
19522 -void ipu_smfc_exit(struct ipu_soc *ipu);
19524 -struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
19526 -int ipu_pre_get_available_count(void);
19527 -int ipu_pre_get(struct ipu_pre *pre);
19528 -void ipu_pre_put(struct ipu_pre *pre);
19529 -u32 ipu_pre_get_baddr(struct ipu_pre *pre);
19530 -void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
19531 - unsigned int height, unsigned int stride, u32 format,
19532 - uint64_t modifier, unsigned int bufaddr);
19533 -void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
19534 -bool ipu_pre_update_pending(struct ipu_pre *pre);
19536 -struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
19539 -extern struct platform_driver ipu_pre_drv;
19540 -extern struct platform_driver ipu_prg_drv;
19542 -#endif /* __IPU_PRV_H__ */
19543 --- a/drivers/gpu/ipu-v3/ipu-smfc.c
19546 -// SPDX-License-Identifier: GPL-2.0-or-later
19548 - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
19550 -#include <linux/export.h>
19551 -#include <linux/types.h>
19552 -#include <linux/init.h>
19553 -#include <linux/io.h>
19554 -#include <linux/errno.h>
19555 -#include <linux/spinlock.h>
19556 -#include <linux/delay.h>
19557 -#include <linux/clk.h>
19558 -#include <video/imx-ipu-v3.h>
19560 -#include "ipu-prv.h"
19563 - struct ipu_smfc_priv *priv;
19568 -struct ipu_smfc_priv {
19569 - void __iomem *base;
19571 - struct ipu_soc *ipu;
19572 - struct ipu_smfc channel[4];
19576 -/*SMFC Registers */
19577 -#define SMFC_MAP 0x0000
19578 -#define SMFC_WMC 0x0004
19579 -#define SMFC_BS 0x0008
19581 -int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
19583 - struct ipu_smfc_priv *priv = smfc->priv;
19584 - unsigned long flags;
19587 - spin_lock_irqsave(&priv->lock, flags);
19589 - shift = smfc->chno * 4;
19590 - val = readl(priv->base + SMFC_BS);
19591 - val &= ~(0xf << shift);
19592 - val |= burstsize << shift;
19593 - writel(val, priv->base + SMFC_BS);
19595 - spin_unlock_irqrestore(&priv->lock, flags);
19599 -EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
19601 -int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
19603 - struct ipu_smfc_priv *priv = smfc->priv;
19604 - unsigned long flags;
19607 - spin_lock_irqsave(&priv->lock, flags);
19609 - shift = smfc->chno * 3;
19610 - val = readl(priv->base + SMFC_MAP);
19611 - val &= ~(0x7 << shift);
19612 - val |= ((csi_id << 2) | mipi_id) << shift;
19613 - writel(val, priv->base + SMFC_MAP);
19615 - spin_unlock_irqrestore(&priv->lock, flags);
19619 -EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
19621 -int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
19623 - struct ipu_smfc_priv *priv = smfc->priv;
19624 - unsigned long flags;
19627 - spin_lock_irqsave(&priv->lock, flags);
19629 - shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
19630 - val = readl(priv->base + SMFC_WMC);
19631 - val &= ~(0x3f << shift);
19632 - val |= ((clr_level << 3) | set_level) << shift;
19633 - writel(val, priv->base + SMFC_WMC);
19635 - spin_unlock_irqrestore(&priv->lock, flags);
19639 -EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
19641 -int ipu_smfc_enable(struct ipu_smfc *smfc)
19643 - struct ipu_smfc_priv *priv = smfc->priv;
19644 - unsigned long flags;
19646 - spin_lock_irqsave(&priv->lock, flags);
19648 - if (!priv->use_count)
19649 - ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
19651 - priv->use_count++;
19653 - spin_unlock_irqrestore(&priv->lock, flags);
19657 -EXPORT_SYMBOL_GPL(ipu_smfc_enable);
19659 -int ipu_smfc_disable(struct ipu_smfc *smfc)
19661 - struct ipu_smfc_priv *priv = smfc->priv;
19662 - unsigned long flags;
19664 - spin_lock_irqsave(&priv->lock, flags);
19666 - priv->use_count--;
19668 - if (!priv->use_count)
19669 - ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
19671 - if (priv->use_count < 0)
19672 - priv->use_count = 0;
19674 - spin_unlock_irqrestore(&priv->lock, flags);
19678 -EXPORT_SYMBOL_GPL(ipu_smfc_disable);
19680 -struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
19682 - struct ipu_smfc_priv *priv = ipu->smfc_priv;
19683 - struct ipu_smfc *smfc, *ret;
19684 - unsigned long flags;
19687 - return ERR_PTR(-EINVAL);
19689 - smfc = &priv->channel[chno];
19692 - spin_lock_irqsave(&priv->lock, flags);
19694 - if (smfc->inuse) {
19695 - ret = ERR_PTR(-EBUSY);
19699 - smfc->inuse = true;
19701 - spin_unlock_irqrestore(&priv->lock, flags);
19704 -EXPORT_SYMBOL_GPL(ipu_smfc_get);
19706 -void ipu_smfc_put(struct ipu_smfc *smfc)
19708 - struct ipu_smfc_priv *priv = smfc->priv;
19709 - unsigned long flags;
19711 - spin_lock_irqsave(&priv->lock, flags);
19712 - smfc->inuse = false;
19713 - spin_unlock_irqrestore(&priv->lock, flags);
19715 -EXPORT_SYMBOL_GPL(ipu_smfc_put);
19717 -int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
19718 - unsigned long base)
19720 - struct ipu_smfc_priv *priv;
19723 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
19727 - ipu->smfc_priv = priv;
19728 - spin_lock_init(&priv->lock);
19731 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
19735 - for (i = 0; i < 4; i++) {
19736 - priv->channel[i].priv = priv;
19737 - priv->channel[i].chno = i;
19740 - pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
19745 -void ipu_smfc_exit(struct ipu_soc *ipu)
19748 --- a/drivers/gpu/ipu-v3/ipu-vdi.c
19751 -// SPDX-License-Identifier: GPL-2.0-or-later
19753 - * Copyright (C) 2012-2016 Mentor Graphics Inc.
19754 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
19756 -#include <linux/io.h>
19757 -#include "ipu-prv.h"
19760 - void __iomem *base;
19764 - struct ipu_soc *ipu;
19768 -/* VDI Register Offsets */
19769 -#define VDI_FSIZE 0x0000
19770 -#define VDI_C 0x0004
19772 -/* VDI Register Fields */
19773 -#define VDI_C_CH_420 (0 << 1)
19774 -#define VDI_C_CH_422 (1 << 1)
19775 -#define VDI_C_MOT_SEL_MASK (0x3 << 2)
19776 -#define VDI_C_MOT_SEL_FULL (2 << 2)
19777 -#define VDI_C_MOT_SEL_LOW (1 << 2)
19778 -#define VDI_C_MOT_SEL_MED (0 << 2)
19779 -#define VDI_C_BURST_SIZE1_4 (3 << 4)
19780 -#define VDI_C_BURST_SIZE2_4 (3 << 8)
19781 -#define VDI_C_BURST_SIZE3_4 (3 << 12)
19782 -#define VDI_C_BURST_SIZE_MASK 0xF
19783 -#define VDI_C_BURST_SIZE1_OFFSET 4
19784 -#define VDI_C_BURST_SIZE2_OFFSET 8
19785 -#define VDI_C_BURST_SIZE3_OFFSET 12
19786 -#define VDI_C_VWM1_SET_1 (0 << 16)
19787 -#define VDI_C_VWM1_SET_2 (1 << 16)
19788 -#define VDI_C_VWM1_CLR_2 (1 << 19)
19789 -#define VDI_C_VWM3_SET_1 (0 << 22)
19790 -#define VDI_C_VWM3_SET_2 (1 << 22)
19791 -#define VDI_C_VWM3_CLR_2 (1 << 25)
19792 -#define VDI_C_TOP_FIELD_MAN_1 (1 << 30)
19793 -#define VDI_C_TOP_FIELD_AUTO_1 (1 << 31)
19795 -static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
19797 - return readl(vdi->base + offset);
19800 -static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
19801 - unsigned int offset)
19803 - writel(value, vdi->base + offset);
19806 -void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
19808 - bool top_field_0 = false;
19809 - unsigned long flags;
19813 - case V4L2_FIELD_INTERLACED_TB:
19814 - case V4L2_FIELD_SEQ_TB:
19815 - case V4L2_FIELD_TOP:
19816 - top_field_0 = true;
19818 - case V4L2_FIELD_INTERLACED_BT:
19819 - case V4L2_FIELD_SEQ_BT:
19820 - case V4L2_FIELD_BOTTOM:
19821 - top_field_0 = false;
19824 - top_field_0 = (std & V4L2_STD_525_60) ? true : false;
19828 - spin_lock_irqsave(&vdi->lock, flags);
19830 - reg = ipu_vdi_read(vdi, VDI_C);
19832 - reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
19834 - reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
19835 - ipu_vdi_write(vdi, reg, VDI_C);
19837 - spin_unlock_irqrestore(&vdi->lock, flags);
19839 -EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
19841 -void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
19843 - unsigned long flags;
19846 - spin_lock_irqsave(&vdi->lock, flags);
19848 - reg = ipu_vdi_read(vdi, VDI_C);
19850 - reg &= ~VDI_C_MOT_SEL_MASK;
19852 - switch (motion_sel) {
19854 - reg |= VDI_C_MOT_SEL_MED;
19856 - case HIGH_MOTION:
19857 - reg |= VDI_C_MOT_SEL_FULL;
19860 - reg |= VDI_C_MOT_SEL_LOW;
19864 - ipu_vdi_write(vdi, reg, VDI_C);
19866 - spin_unlock_irqrestore(&vdi->lock, flags);
19868 -EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
19870 -void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
19872 - unsigned long flags;
19873 - u32 pixel_fmt, reg;
19875 - spin_lock_irqsave(&vdi->lock, flags);
19877 - reg = ((yres - 1) << 16) | (xres - 1);
19878 - ipu_vdi_write(vdi, reg, VDI_FSIZE);
19881 - * Full motion, only vertical filter is used.
19882 - * Burst size is 4 accesses
19884 - if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
19885 - code == MEDIA_BUS_FMT_UYVY8_1X16 ||
19886 - code == MEDIA_BUS_FMT_YUYV8_2X8 ||
19887 - code == MEDIA_BUS_FMT_YUYV8_1X16)
19888 - pixel_fmt = VDI_C_CH_422;
19890 - pixel_fmt = VDI_C_CH_420;
19892 - reg = ipu_vdi_read(vdi, VDI_C);
19893 - reg |= pixel_fmt;
19894 - reg |= VDI_C_BURST_SIZE2_4;
19895 - reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
19896 - reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
19897 - ipu_vdi_write(vdi, reg, VDI_C);
19899 - spin_unlock_irqrestore(&vdi->lock, flags);
19901 -EXPORT_SYMBOL_GPL(ipu_vdi_setup);
19903 -void ipu_vdi_unsetup(struct ipu_vdi *vdi)
19905 - unsigned long flags;
19907 - spin_lock_irqsave(&vdi->lock, flags);
19908 - ipu_vdi_write(vdi, 0, VDI_FSIZE);
19909 - ipu_vdi_write(vdi, 0, VDI_C);
19910 - spin_unlock_irqrestore(&vdi->lock, flags);
19912 -EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
19914 -int ipu_vdi_enable(struct ipu_vdi *vdi)
19916 - unsigned long flags;
19918 - spin_lock_irqsave(&vdi->lock, flags);
19920 - if (!vdi->use_count)
19921 - ipu_module_enable(vdi->ipu, vdi->module);
19923 - vdi->use_count++;
19925 - spin_unlock_irqrestore(&vdi->lock, flags);
19929 -EXPORT_SYMBOL_GPL(ipu_vdi_enable);
19931 -int ipu_vdi_disable(struct ipu_vdi *vdi)
19933 - unsigned long flags;
19935 - spin_lock_irqsave(&vdi->lock, flags);
19937 - if (vdi->use_count) {
19938 - if (!--vdi->use_count)
19939 - ipu_module_disable(vdi->ipu, vdi->module);
19942 - spin_unlock_irqrestore(&vdi->lock, flags);
19946 -EXPORT_SYMBOL_GPL(ipu_vdi_disable);
19948 -struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
19950 - return ipu->vdi_priv;
19952 -EXPORT_SYMBOL_GPL(ipu_vdi_get);
19954 -void ipu_vdi_put(struct ipu_vdi *vdi)
19957 -EXPORT_SYMBOL_GPL(ipu_vdi_put);
19959 -int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
19960 - unsigned long base, u32 module)
19962 - struct ipu_vdi *vdi;
19964 - vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
19968 - ipu->vdi_priv = vdi;
19970 - spin_lock_init(&vdi->lock);
19971 - vdi->module = module;
19972 - vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
19976 - dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
19982 -void ipu_vdi_exit(struct ipu_soc *ipu)
19985 --- a/drivers/video/Kconfig
19986 +++ b/drivers/video/Kconfig
19987 @@ -15,7 +15,7 @@ source "drivers/char/agp/Kconfig"
19988 source "drivers/gpu/vga/Kconfig"
19990 source "drivers/gpu/host1x/Kconfig"
19991 -source "drivers/gpu/ipu-v3/Kconfig"
19992 +source "drivers/gpu/imx/Kconfig"
19994 source "drivers/gpu/drm/Kconfig"