1 From 9a941f832d8b88fb29b40e4b3f9c2b42a8a9b000 Mon Sep 17 00:00:00 2001
2 From: Yangbo Lu <yangbo.lu@nxp.com>
3 Date: Mon, 2 Mar 2020 13:46:13 +0800
4 Subject: [PATCH] Revert "gpu: Move ipu-v3 to imx folder"
6 This reverts commit 9da4beb1c9ce90f97c8d3b5c6254da576746d2cd.
8 drivers/gpu/Makefile | 2 +-
9 drivers/gpu/imx/Kconfig | 1 -
10 drivers/gpu/imx/Makefile | 1 -
11 drivers/gpu/imx/ipu-v3/Kconfig | 11 -
12 drivers/gpu/imx/ipu-v3/Makefile | 10 -
13 drivers/gpu/imx/ipu-v3/ipu-common.c | 1565 ------------------
14 drivers/gpu/imx/ipu-v3/ipu-cpmem.c | 976 -----------
15 drivers/gpu/imx/ipu-v3/ipu-csi.c | 821 ---------
16 drivers/gpu/imx/ipu-v3/ipu-dc.c | 420 -----
17 drivers/gpu/imx/ipu-v3/ipu-di.c | 745 ---------
18 drivers/gpu/imx/ipu-v3/ipu-dmfc.c | 214 ---
19 drivers/gpu/imx/ipu-v3/ipu-dp.c | 357 ----
20 drivers/gpu/imx/ipu-v3/ipu-ic.c | 761 ---------
21 drivers/gpu/imx/ipu-v3/ipu-image-convert.c | 2475 ----------------------------
22 drivers/gpu/imx/ipu-v3/ipu-pre.c | 346 ----
23 drivers/gpu/imx/ipu-v3/ipu-prg.c | 483 ------
24 drivers/gpu/imx/ipu-v3/ipu-prv.h | 274 ---
25 drivers/gpu/imx/ipu-v3/ipu-smfc.c | 202 ---
26 drivers/gpu/imx/ipu-v3/ipu-vdi.c | 234 ---
27 drivers/gpu/ipu-v3/Kconfig | 11 +
28 drivers/gpu/ipu-v3/Makefile | 10 +
29 drivers/gpu/ipu-v3/ipu-common.c | 1565 ++++++++++++++++++
30 drivers/gpu/ipu-v3/ipu-cpmem.c | 976 +++++++++++
31 drivers/gpu/ipu-v3/ipu-csi.c | 821 +++++++++
32 drivers/gpu/ipu-v3/ipu-dc.c | 420 +++++
33 drivers/gpu/ipu-v3/ipu-di.c | 745 +++++++++
34 drivers/gpu/ipu-v3/ipu-dmfc.c | 214 +++
35 drivers/gpu/ipu-v3/ipu-dp.c | 357 ++++
36 drivers/gpu/ipu-v3/ipu-ic.c | 761 +++++++++
37 drivers/gpu/ipu-v3/ipu-image-convert.c | 2475 ++++++++++++++++++++++++++++
38 drivers/gpu/ipu-v3/ipu-pre.c | 346 ++++
39 drivers/gpu/ipu-v3/ipu-prg.c | 483 ++++++
40 drivers/gpu/ipu-v3/ipu-prv.h | 274 +++
41 drivers/gpu/ipu-v3/ipu-smfc.c | 202 +++
42 drivers/gpu/ipu-v3/ipu-vdi.c | 234 +++
43 drivers/video/Kconfig | 2 +-
44 36 files changed, 9896 insertions(+), 9898 deletions(-)
45 delete mode 100644 drivers/gpu/imx/Kconfig
46 delete mode 100644 drivers/gpu/imx/Makefile
47 delete mode 100644 drivers/gpu/imx/ipu-v3/Kconfig
48 delete mode 100644 drivers/gpu/imx/ipu-v3/Makefile
49 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-common.c
50 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-cpmem.c
51 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-csi.c
52 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-dc.c
53 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-di.c
54 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-dmfc.c
55 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-dp.c
56 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-ic.c
57 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-image-convert.c
58 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-pre.c
59 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-prg.c
60 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-prv.h
61 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-smfc.c
62 delete mode 100644 drivers/gpu/imx/ipu-v3/ipu-vdi.c
63 create mode 100644 drivers/gpu/ipu-v3/Kconfig
64 create mode 100644 drivers/gpu/ipu-v3/Makefile
65 create mode 100644 drivers/gpu/ipu-v3/ipu-common.c
66 create mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
67 create mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
68 create mode 100644 drivers/gpu/ipu-v3/ipu-dc.c
69 create mode 100644 drivers/gpu/ipu-v3/ipu-di.c
70 create mode 100644 drivers/gpu/ipu-v3/ipu-dmfc.c
71 create mode 100644 drivers/gpu/ipu-v3/ipu-dp.c
72 create mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
73 create mode 100644 drivers/gpu/ipu-v3/ipu-image-convert.c
74 create mode 100644 drivers/gpu/ipu-v3/ipu-pre.c
75 create mode 100644 drivers/gpu/ipu-v3/ipu-prg.c
76 create mode 100644 drivers/gpu/ipu-v3/ipu-prv.h
77 create mode 100644 drivers/gpu/ipu-v3/ipu-smfc.c
78 create mode 100644 drivers/gpu/ipu-v3/ipu-vdi.c
80 --- a/drivers/gpu/Makefile
81 +++ b/drivers/gpu/Makefile
83 # taken to initialize them in the correct order. Link order is the only way
84 # to ensure this currently.
85 obj-$(CONFIG_TEGRA_HOST1X) += host1x/
88 +obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
89 --- a/drivers/gpu/imx/Kconfig
92 -source "drivers/gpu/imx/ipu-v3/Kconfig"
93 --- a/drivers/gpu/imx/Makefile
96 -obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
97 --- a/drivers/gpu/imx/ipu-v3/Kconfig
100 -# SPDX-License-Identifier: GPL-2.0-only
101 -config IMX_IPUV3_CORE
102 - tristate "IPUv3 core support"
103 - depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
104 - depends on DRM || !DRM # if DRM=m, this can't be 'y'
106 - select GENERIC_ALLOCATOR if DRM
107 - select GENERIC_IRQ_CHIP
109 - Choose this if you have a i.MX5/6 system and want to use the Image
110 - Processing Unit. This option only enables IPU base support.
111 --- a/drivers/gpu/imx/ipu-v3/Makefile
114 -# SPDX-License-Identifier: GPL-2.0
115 -obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
117 -imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
118 - ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
119 - ipu-image-convert.o ipu-smfc.o ipu-vdi.o
122 - imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
124 --- a/drivers/gpu/imx/ipu-v3/ipu-common.c
127 -// SPDX-License-Identifier: GPL-2.0-or-later
129 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
130 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
132 -#include <linux/module.h>
133 -#include <linux/export.h>
134 -#include <linux/types.h>
135 -#include <linux/reset.h>
136 -#include <linux/platform_device.h>
137 -#include <linux/err.h>
138 -#include <linux/spinlock.h>
139 -#include <linux/delay.h>
140 -#include <linux/interrupt.h>
141 -#include <linux/io.h>
142 -#include <linux/clk.h>
143 -#include <linux/list.h>
144 -#include <linux/irq.h>
145 -#include <linux/irqchip/chained_irq.h>
146 -#include <linux/irqdomain.h>
147 -#include <linux/of_device.h>
148 -#include <linux/of_graph.h>
150 -#include <drm/drm_fourcc.h>
152 -#include <video/imx-ipu-v3.h>
153 -#include "ipu-prv.h"
155 -static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
157 - return readl(ipu->cm_reg + offset);
160 -static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
162 - writel(value, ipu->cm_reg + offset);
165 -int ipu_get_num(struct ipu_soc *ipu)
169 -EXPORT_SYMBOL_GPL(ipu_get_num);
171 -void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
175 - val = ipu_cm_read(ipu, IPU_SRM_PRI2);
176 - val &= ~DP_S_SRM_MODE_MASK;
177 - val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
179 - ipu_cm_write(ipu, val, IPU_SRM_PRI2);
181 -EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
183 -enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
185 - switch (drm_fourcc) {
186 - case DRM_FORMAT_ARGB1555:
187 - case DRM_FORMAT_ABGR1555:
188 - case DRM_FORMAT_RGBA5551:
189 - case DRM_FORMAT_BGRA5551:
190 - case DRM_FORMAT_RGB565:
191 - case DRM_FORMAT_BGR565:
192 - case DRM_FORMAT_RGB888:
193 - case DRM_FORMAT_BGR888:
194 - case DRM_FORMAT_ARGB4444:
195 - case DRM_FORMAT_XRGB8888:
196 - case DRM_FORMAT_XBGR8888:
197 - case DRM_FORMAT_RGBX8888:
198 - case DRM_FORMAT_BGRX8888:
199 - case DRM_FORMAT_ARGB8888:
200 - case DRM_FORMAT_ABGR8888:
201 - case DRM_FORMAT_RGBA8888:
202 - case DRM_FORMAT_BGRA8888:
203 - case DRM_FORMAT_RGB565_A8:
204 - case DRM_FORMAT_BGR565_A8:
205 - case DRM_FORMAT_RGB888_A8:
206 - case DRM_FORMAT_BGR888_A8:
207 - case DRM_FORMAT_RGBX8888_A8:
208 - case DRM_FORMAT_BGRX8888_A8:
209 - return IPUV3_COLORSPACE_RGB;
210 - case DRM_FORMAT_YUYV:
211 - case DRM_FORMAT_UYVY:
212 - case DRM_FORMAT_YUV420:
213 - case DRM_FORMAT_YVU420:
214 - case DRM_FORMAT_YUV422:
215 - case DRM_FORMAT_YVU422:
216 - case DRM_FORMAT_YUV444:
217 - case DRM_FORMAT_YVU444:
218 - case DRM_FORMAT_NV12:
219 - case DRM_FORMAT_NV21:
220 - case DRM_FORMAT_NV16:
221 - case DRM_FORMAT_NV61:
222 - return IPUV3_COLORSPACE_YUV;
224 - return IPUV3_COLORSPACE_UNKNOWN;
227 -EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
229 -enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
231 - switch (pixelformat) {
232 - case V4L2_PIX_FMT_YUV420:
233 - case V4L2_PIX_FMT_YVU420:
234 - case V4L2_PIX_FMT_YUV422P:
235 - case V4L2_PIX_FMT_UYVY:
236 - case V4L2_PIX_FMT_YUYV:
237 - case V4L2_PIX_FMT_NV12:
238 - case V4L2_PIX_FMT_NV21:
239 - case V4L2_PIX_FMT_NV16:
240 - case V4L2_PIX_FMT_NV61:
241 - return IPUV3_COLORSPACE_YUV;
242 - case V4L2_PIX_FMT_RGB565:
243 - case V4L2_PIX_FMT_BGR24:
244 - case V4L2_PIX_FMT_RGB24:
245 - case V4L2_PIX_FMT_ABGR32:
246 - case V4L2_PIX_FMT_XBGR32:
247 - case V4L2_PIX_FMT_BGRA32:
248 - case V4L2_PIX_FMT_BGRX32:
249 - case V4L2_PIX_FMT_RGBA32:
250 - case V4L2_PIX_FMT_RGBX32:
251 - case V4L2_PIX_FMT_ARGB32:
252 - case V4L2_PIX_FMT_XRGB32:
253 - return IPUV3_COLORSPACE_RGB;
255 - return IPUV3_COLORSPACE_UNKNOWN;
258 -EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
260 -bool ipu_pixelformat_is_planar(u32 pixelformat)
262 - switch (pixelformat) {
263 - case V4L2_PIX_FMT_YUV420:
264 - case V4L2_PIX_FMT_YVU420:
265 - case V4L2_PIX_FMT_YUV422P:
266 - case V4L2_PIX_FMT_NV12:
267 - case V4L2_PIX_FMT_NV21:
268 - case V4L2_PIX_FMT_NV16:
269 - case V4L2_PIX_FMT_NV61:
275 -EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
277 -enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
279 - switch (mbus_code & 0xf000) {
281 - return IPUV3_COLORSPACE_RGB;
283 - return IPUV3_COLORSPACE_YUV;
285 - return IPUV3_COLORSPACE_UNKNOWN;
288 -EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
290 -int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
292 - switch (pixelformat) {
293 - case V4L2_PIX_FMT_YUV420:
294 - case V4L2_PIX_FMT_YVU420:
295 - case V4L2_PIX_FMT_YUV422P:
296 - case V4L2_PIX_FMT_NV12:
297 - case V4L2_PIX_FMT_NV21:
298 - case V4L2_PIX_FMT_NV16:
299 - case V4L2_PIX_FMT_NV61:
301 - * for the planar YUV formats, the stride passed to
302 - * cpmem must be the stride in bytes of the Y plane.
303 - * And all the planar YUV formats have an 8-bit
306 - return (8 * pixel_stride) >> 3;
307 - case V4L2_PIX_FMT_RGB565:
308 - case V4L2_PIX_FMT_YUYV:
309 - case V4L2_PIX_FMT_UYVY:
310 - return (16 * pixel_stride) >> 3;
311 - case V4L2_PIX_FMT_BGR24:
312 - case V4L2_PIX_FMT_RGB24:
313 - return (24 * pixel_stride) >> 3;
314 - case V4L2_PIX_FMT_BGR32:
315 - case V4L2_PIX_FMT_RGB32:
316 - case V4L2_PIX_FMT_XBGR32:
317 - case V4L2_PIX_FMT_XRGB32:
318 - return (32 * pixel_stride) >> 3;
325 -EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
327 -int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
328 - bool hflip, bool vflip)
354 - *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
357 -EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
359 -int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
360 - bool hflip, bool vflip)
364 - r90 = ((u32)mode >> 2) & 0x1;
365 - hf = ((u32)mode >> 1) & 0x1;
366 - vf = ((u32)mode >> 0) & 0x1;
370 - switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
371 - case IPU_ROTATE_NONE:
374 - case IPU_ROTATE_90_RIGHT:
377 - case IPU_ROTATE_180:
380 - case IPU_ROTATE_90_LEFT:
389 -EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
391 -struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
393 - struct ipuv3_channel *channel;
395 - dev_dbg(ipu->dev, "%s %d\n", __func__, num);
398 - return ERR_PTR(-ENODEV);
400 - mutex_lock(&ipu->channel_lock);
402 - list_for_each_entry(channel, &ipu->channels, list) {
403 - if (channel->num == num) {
404 - channel = ERR_PTR(-EBUSY);
409 - channel = kzalloc(sizeof(*channel), GFP_KERNEL);
411 - channel = ERR_PTR(-ENOMEM);
415 - channel->num = num;
416 - channel->ipu = ipu;
417 - list_add(&channel->list, &ipu->channels);
420 - mutex_unlock(&ipu->channel_lock);
424 -EXPORT_SYMBOL_GPL(ipu_idmac_get);
426 -void ipu_idmac_put(struct ipuv3_channel *channel)
428 - struct ipu_soc *ipu = channel->ipu;
430 - dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
432 - mutex_lock(&ipu->channel_lock);
434 - list_del(&channel->list);
437 - mutex_unlock(&ipu->channel_lock);
439 -EXPORT_SYMBOL_GPL(ipu_idmac_put);
441 -#define idma_mask(ch) (1 << ((ch) & 0x1f))
444 - * This is an undocumented feature, a write one to a channel bit in
445 - * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
446 - * internal current buffer pointer so that transfers start from buffer
447 - * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
448 - * only says these are read-only registers). This operation is required
449 - * for channel linking to work correctly, for instance video capture
450 - * pipelines that carry out image rotations will fail after the first
451 - * streaming unless this function is called for each channel before
452 - * re-enabling the channels.
454 -static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
456 - struct ipu_soc *ipu = channel->ipu;
457 - unsigned int chno = channel->num;
459 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
462 -void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
465 - struct ipu_soc *ipu = channel->ipu;
466 - unsigned long flags;
469 - spin_lock_irqsave(&ipu->lock, flags);
471 - reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
473 - reg |= idma_mask(channel->num);
475 - reg &= ~idma_mask(channel->num);
476 - ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
478 - __ipu_idmac_reset_current_buffer(channel);
480 - spin_unlock_irqrestore(&ipu->lock, flags);
482 -EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
484 -static const struct {
488 -} idmac_lock_en_info[] = {
489 - { .chnum = 5, .reg = IDMAC_CH_LOCK_EN_1, .shift = 0, },
490 - { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift = 2, },
491 - { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift = 4, },
492 - { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift = 6, },
493 - { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift = 8, },
494 - { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
495 - { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
496 - { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
497 - { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
498 - { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
499 - { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
500 - { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift = 0, },
501 - { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift = 2, },
502 - { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift = 4, },
503 - { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift = 6, },
504 - { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift = 8, },
505 - { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
508 -int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
510 - struct ipu_soc *ipu = channel->ipu;
511 - unsigned long flags;
512 - u32 bursts, regval;
515 - switch (num_bursts) {
518 - bursts = 0x00; /* locking disabled */
534 - * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
535 - * i.MX53 channel arbitration locking doesn't seem to work properly.
536 - * Allow enabling the lock feature on IPUv3H / i.MX6 only.
538 - if (bursts && ipu->ipu_type != IPUV3H)
541 - for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
542 - if (channel->num == idmac_lock_en_info[i].chnum)
545 - if (i >= ARRAY_SIZE(idmac_lock_en_info))
548 - spin_lock_irqsave(&ipu->lock, flags);
550 - regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
551 - regval &= ~(0x03 << idmac_lock_en_info[i].shift);
552 - regval |= (bursts << idmac_lock_en_info[i].shift);
553 - ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
555 - spin_unlock_irqrestore(&ipu->lock, flags);
559 -EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
561 -int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
563 - unsigned long lock_flags;
566 - spin_lock_irqsave(&ipu->lock, lock_flags);
568 - val = ipu_cm_read(ipu, IPU_DISP_GEN);
570 - if (mask & IPU_CONF_DI0_EN)
571 - val |= IPU_DI0_COUNTER_RELEASE;
572 - if (mask & IPU_CONF_DI1_EN)
573 - val |= IPU_DI1_COUNTER_RELEASE;
575 - ipu_cm_write(ipu, val, IPU_DISP_GEN);
577 - val = ipu_cm_read(ipu, IPU_CONF);
579 - ipu_cm_write(ipu, val, IPU_CONF);
581 - spin_unlock_irqrestore(&ipu->lock, lock_flags);
585 -EXPORT_SYMBOL_GPL(ipu_module_enable);
587 -int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
589 - unsigned long lock_flags;
592 - spin_lock_irqsave(&ipu->lock, lock_flags);
594 - val = ipu_cm_read(ipu, IPU_CONF);
596 - ipu_cm_write(ipu, val, IPU_CONF);
598 - val = ipu_cm_read(ipu, IPU_DISP_GEN);
600 - if (mask & IPU_CONF_DI0_EN)
601 - val &= ~IPU_DI0_COUNTER_RELEASE;
602 - if (mask & IPU_CONF_DI1_EN)
603 - val &= ~IPU_DI1_COUNTER_RELEASE;
605 - ipu_cm_write(ipu, val, IPU_DISP_GEN);
607 - spin_unlock_irqrestore(&ipu->lock, lock_flags);
611 -EXPORT_SYMBOL_GPL(ipu_module_disable);
613 -int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
615 - struct ipu_soc *ipu = channel->ipu;
616 - unsigned int chno = channel->num;
618 - return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
620 -EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
622 -bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
624 - struct ipu_soc *ipu = channel->ipu;
625 - unsigned long flags;
628 - spin_lock_irqsave(&ipu->lock, flags);
631 - reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
634 - reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
637 - reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
640 - spin_unlock_irqrestore(&ipu->lock, flags);
642 - return ((reg & idma_mask(channel->num)) != 0);
644 -EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
646 -void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
648 - struct ipu_soc *ipu = channel->ipu;
649 - unsigned int chno = channel->num;
650 - unsigned long flags;
652 - spin_lock_irqsave(&ipu->lock, flags);
654 - /* Mark buffer as ready. */
656 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
658 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
660 - spin_unlock_irqrestore(&ipu->lock, flags);
662 -EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
664 -void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
666 - struct ipu_soc *ipu = channel->ipu;
667 - unsigned int chno = channel->num;
668 - unsigned long flags;
670 - spin_lock_irqsave(&ipu->lock, flags);
672 - ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
675 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
678 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
681 - ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
686 - ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
688 - spin_unlock_irqrestore(&ipu->lock, flags);
690 -EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
692 -int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
694 - struct ipu_soc *ipu = channel->ipu;
696 - unsigned long flags;
698 - spin_lock_irqsave(&ipu->lock, flags);
700 - val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
701 - val |= idma_mask(channel->num);
702 - ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
704 - spin_unlock_irqrestore(&ipu->lock, flags);
708 -EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
710 -bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
712 - return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
714 -EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
716 -int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
718 - struct ipu_soc *ipu = channel->ipu;
719 - unsigned long timeout;
721 - timeout = jiffies + msecs_to_jiffies(ms);
722 - while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
723 - idma_mask(channel->num)) {
724 - if (time_after(jiffies, timeout))
731 -EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
733 -int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
735 - struct ipu_soc *ipu = channel->ipu;
737 - unsigned long flags;
739 - spin_lock_irqsave(&ipu->lock, flags);
741 - /* Disable DMA channel(s) */
742 - val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
743 - val &= ~idma_mask(channel->num);
744 - ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
746 - __ipu_idmac_reset_current_buffer(channel);
748 - /* Set channel buffers NOT to be ready */
749 - ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
751 - if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
752 - idma_mask(channel->num)) {
753 - ipu_cm_write(ipu, idma_mask(channel->num),
754 - IPU_CHA_BUF0_RDY(channel->num));
757 - if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
758 - idma_mask(channel->num)) {
759 - ipu_cm_write(ipu, idma_mask(channel->num),
760 - IPU_CHA_BUF1_RDY(channel->num));
763 - ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
765 - /* Reset the double buffer */
766 - val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
767 - val &= ~idma_mask(channel->num);
768 - ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
770 - spin_unlock_irqrestore(&ipu->lock, flags);
774 -EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
777 - * The imx6 rev. D TRM says that enabling the WM feature will increase
778 - * a channel's priority. Refer to Table 36-8 Calculated priority value.
779 - * The sub-module that is the sink or source for the channel must enable
780 - * watermark signal for this to take effect (SMFC_WM for instance).
782 -void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
784 - struct ipu_soc *ipu = channel->ipu;
785 - unsigned long flags;
788 - spin_lock_irqsave(&ipu->lock, flags);
790 - val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
792 - val |= 1 << (channel->num % 32);
794 - val &= ~(1 << (channel->num % 32));
795 - ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
797 - spin_unlock_irqrestore(&ipu->lock, flags);
799 -EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
801 -static int ipu_memory_reset(struct ipu_soc *ipu)
803 - unsigned long timeout;
805 - ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
807 - timeout = jiffies + msecs_to_jiffies(1000);
808 - while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
809 - if (time_after(jiffies, timeout))
818 - * Set the source mux for the given CSI. Selects either parallel or
819 - * MIPI CSI2 sources.
821 -void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
823 - unsigned long flags;
826 - mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
827 - IPU_CONF_CSI0_DATA_SOURCE;
829 - spin_lock_irqsave(&ipu->lock, flags);
831 - val = ipu_cm_read(ipu, IPU_CONF);
836 - ipu_cm_write(ipu, val, IPU_CONF);
838 - spin_unlock_irqrestore(&ipu->lock, flags);
840 -EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
843 - * Set the source mux for the IC. Selects either CSI[01] or the VDI.
845 -void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
847 - unsigned long flags;
850 - spin_lock_irqsave(&ipu->lock, flags);
852 - val = ipu_cm_read(ipu, IPU_CONF);
854 - val |= IPU_CONF_IC_INPUT;
856 - val &= ~IPU_CONF_IC_INPUT;
859 - val |= IPU_CONF_CSI_SEL;
861 - val &= ~IPU_CONF_CSI_SEL;
863 - ipu_cm_write(ipu, val, IPU_CONF);
865 - spin_unlock_irqrestore(&ipu->lock, flags);
867 -EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
870 -/* Frame Synchronization Unit Channel Linking */
872 -struct fsu_link_reg_info {
879 -struct fsu_link_info {
880 - struct fsu_link_reg_info src;
881 - struct fsu_link_reg_info sink;
884 -static const struct fsu_link_info fsu_link_info[] = {
886 - .src = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
887 - FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
888 - .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
889 - FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
891 - .src = { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
892 - FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
893 - .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
894 - FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
896 - .src = { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
897 - FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
898 - .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
899 - FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
901 - .src = { IPUV3_CHANNEL_CSI_DIRECT, 0 },
902 - .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
903 - FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
907 -static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
911 - for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
912 - if (src == fsu_link_info[i].src.chno &&
913 - sink == fsu_link_info[i].sink.chno)
914 - return &fsu_link_info[i];
921 - * Links a source channel to a sink channel in the FSU.
923 -int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
925 - const struct fsu_link_info *link;
926 - u32 src_reg, sink_reg;
927 - unsigned long flags;
929 - link = find_fsu_link_info(src_ch, sink_ch);
933 - spin_lock_irqsave(&ipu->lock, flags);
935 - if (link->src.mask) {
936 - src_reg = ipu_cm_read(ipu, link->src.reg);
937 - src_reg &= ~link->src.mask;
938 - src_reg |= link->src.val;
939 - ipu_cm_write(ipu, src_reg, link->src.reg);
942 - if (link->sink.mask) {
943 - sink_reg = ipu_cm_read(ipu, link->sink.reg);
944 - sink_reg &= ~link->sink.mask;
945 - sink_reg |= link->sink.val;
946 - ipu_cm_write(ipu, sink_reg, link->sink.reg);
949 - spin_unlock_irqrestore(&ipu->lock, flags);
952 -EXPORT_SYMBOL_GPL(ipu_fsu_link);
955 - * Unlinks source and sink channels in the FSU.
957 -int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
959 - const struct fsu_link_info *link;
960 - u32 src_reg, sink_reg;
961 - unsigned long flags;
963 - link = find_fsu_link_info(src_ch, sink_ch);
967 - spin_lock_irqsave(&ipu->lock, flags);
969 - if (link->src.mask) {
970 - src_reg = ipu_cm_read(ipu, link->src.reg);
971 - src_reg &= ~link->src.mask;
972 - ipu_cm_write(ipu, src_reg, link->src.reg);
975 - if (link->sink.mask) {
976 - sink_reg = ipu_cm_read(ipu, link->sink.reg);
977 - sink_reg &= ~link->sink.mask;
978 - ipu_cm_write(ipu, sink_reg, link->sink.reg);
981 - spin_unlock_irqrestore(&ipu->lock, flags);
984 -EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
986 -/* Link IDMAC channels in the FSU */
987 -int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
989 - return ipu_fsu_link(src->ipu, src->num, sink->num);
991 -EXPORT_SYMBOL_GPL(ipu_idmac_link);
993 -/* Unlink IDMAC channels in the FSU */
994 -int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
996 - return ipu_fsu_unlink(src->ipu, src->num, sink->num);
998 -EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
1000 -struct ipu_devtype {
1002 - unsigned long cm_ofs;
1003 - unsigned long cpmem_ofs;
1004 - unsigned long srm_ofs;
1005 - unsigned long tpm_ofs;
1006 - unsigned long csi0_ofs;
1007 - unsigned long csi1_ofs;
1008 - unsigned long ic_ofs;
1009 - unsigned long disp0_ofs;
1010 - unsigned long disp1_ofs;
1011 - unsigned long dc_tmpl_ofs;
1012 - unsigned long vdi_ofs;
1013 - enum ipuv3_type type;
1016 -static struct ipu_devtype ipu_type_imx51 = {
1017 - .name = "IPUv3EX",
1018 - .cm_ofs = 0x1e000000,
1019 - .cpmem_ofs = 0x1f000000,
1020 - .srm_ofs = 0x1f040000,
1021 - .tpm_ofs = 0x1f060000,
1022 - .csi0_ofs = 0x1e030000,
1023 - .csi1_ofs = 0x1e038000,
1024 - .ic_ofs = 0x1e020000,
1025 - .disp0_ofs = 0x1e040000,
1026 - .disp1_ofs = 0x1e048000,
1027 - .dc_tmpl_ofs = 0x1f080000,
1028 - .vdi_ofs = 0x1e068000,
1032 -static struct ipu_devtype ipu_type_imx53 = {
1034 - .cm_ofs = 0x06000000,
1035 - .cpmem_ofs = 0x07000000,
1036 - .srm_ofs = 0x07040000,
1037 - .tpm_ofs = 0x07060000,
1038 - .csi0_ofs = 0x06030000,
1039 - .csi1_ofs = 0x06038000,
1040 - .ic_ofs = 0x06020000,
1041 - .disp0_ofs = 0x06040000,
1042 - .disp1_ofs = 0x06048000,
1043 - .dc_tmpl_ofs = 0x07080000,
1044 - .vdi_ofs = 0x06068000,
1048 -static struct ipu_devtype ipu_type_imx6q = {
1050 - .cm_ofs = 0x00200000,
1051 - .cpmem_ofs = 0x00300000,
1052 - .srm_ofs = 0x00340000,
1053 - .tpm_ofs = 0x00360000,
1054 - .csi0_ofs = 0x00230000,
1055 - .csi1_ofs = 0x00238000,
1056 - .ic_ofs = 0x00220000,
1057 - .disp0_ofs = 0x00240000,
1058 - .disp1_ofs = 0x00248000,
1059 - .dc_tmpl_ofs = 0x00380000,
1060 - .vdi_ofs = 0x00268000,
1064 -static const struct of_device_id imx_ipu_dt_ids[] = {
1065 - { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
1066 - { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
1067 - { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
1068 - { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
1069 - { /* sentinel */ }
1071 -MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
1073 -static int ipu_submodules_init(struct ipu_soc *ipu,
1074 - struct platform_device *pdev, unsigned long ipu_base,
1075 - struct clk *ipu_clk)
1079 - struct device *dev = &pdev->dev;
1080 - const struct ipu_devtype *devtype = ipu->devtype;
1082 - ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
1088 - ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
1089 - IPU_CONF_CSI0_EN, ipu_clk);
1095 - ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
1096 - IPU_CONF_CSI1_EN, ipu_clk);
1102 - ret = ipu_ic_init(ipu, dev,
1103 - ipu_base + devtype->ic_ofs,
1104 - ipu_base + devtype->tpm_ofs);
1110 - ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
1111 - IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
1112 - IPU_CONF_IC_INPUT);
1118 - ret = ipu_image_convert_init(ipu, dev);
1120 - unit = "image_convert";
1121 - goto err_image_convert;
1124 - ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
1125 - IPU_CONF_DI0_EN, ipu_clk);
1131 - ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
1132 - IPU_CONF_DI1_EN, ipu_clk);
1138 - ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
1139 - IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
1141 - unit = "dc_template";
1145 - ret = ipu_dmfc_init(ipu, dev, ipu_base +
1146 - devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
1152 - ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
1158 - ret = ipu_smfc_init(ipu, dev, ipu_base +
1159 - devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
1170 - ipu_dmfc_exit(ipu);
1174 - ipu_di_exit(ipu, 1);
1176 - ipu_di_exit(ipu, 0);
1178 - ipu_image_convert_exit(ipu);
1180 - ipu_vdi_exit(ipu);
1184 - ipu_csi_exit(ipu, 1);
1186 - ipu_csi_exit(ipu, 0);
1188 - ipu_cpmem_exit(ipu);
1190 - dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
1194 -static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
1196 - unsigned long status;
1199 - for (i = 0; i < num_regs; i++) {
1201 - status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
1202 - status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
1204 - for_each_set_bit(bit, &status, 32) {
1205 - irq = irq_linear_revmap(ipu->domain,
1206 - regs[i] * 32 + bit);
1208 - generic_handle_irq(irq);
1213 -static void ipu_irq_handler(struct irq_desc *desc)
1215 - struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
1216 - struct irq_chip *chip = irq_desc_get_chip(desc);
1217 - static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
1219 - chained_irq_enter(chip, desc);
1221 - ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
1223 - chained_irq_exit(chip, desc);
1226 -static void ipu_err_irq_handler(struct irq_desc *desc)
1228 - struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
1229 - struct irq_chip *chip = irq_desc_get_chip(desc);
1230 - static const int int_reg[] = { 4, 5, 8, 9};
1232 - chained_irq_enter(chip, desc);
1234 - ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
1236 - chained_irq_exit(chip, desc);
1239 -int ipu_map_irq(struct ipu_soc *ipu, int irq)
1243 - virq = irq_linear_revmap(ipu->domain, irq);
1245 - virq = irq_create_mapping(ipu->domain, irq);
1249 -EXPORT_SYMBOL_GPL(ipu_map_irq);
1251 -int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
1252 - enum ipu_channel_irq irq_type)
1254 - return ipu_map_irq(ipu, irq_type + channel->num);
1256 -EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
1258 -static void ipu_submodules_exit(struct ipu_soc *ipu)
1260 - ipu_smfc_exit(ipu);
1262 - ipu_dmfc_exit(ipu);
1264 - ipu_di_exit(ipu, 1);
1265 - ipu_di_exit(ipu, 0);
1266 - ipu_image_convert_exit(ipu);
1267 - ipu_vdi_exit(ipu);
1269 - ipu_csi_exit(ipu, 1);
1270 - ipu_csi_exit(ipu, 0);
1271 - ipu_cpmem_exit(ipu);
1274 -static int platform_remove_devices_fn(struct device *dev, void *unused)
1276 - struct platform_device *pdev = to_platform_device(dev);
1278 - platform_device_unregister(pdev);
1283 -static void platform_device_unregister_children(struct platform_device *pdev)
1285 - device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
1288 -struct ipu_platform_reg {
1289 - struct ipu_client_platformdata pdata;
1293 -/* These must be in the order of the corresponding device tree port nodes */
1294 -static struct ipu_platform_reg client_reg[] = {
1298 - .dma[0] = IPUV3_CHANNEL_CSI0,
1299 - .dma[1] = -EINVAL,
1301 - .name = "imx-ipuv3-csi",
1305 - .dma[0] = IPUV3_CHANNEL_CSI1,
1306 - .dma[1] = -EINVAL,
1308 - .name = "imx-ipuv3-csi",
1313 - .dp = IPU_DP_FLOW_SYNC_BG,
1314 - .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
1315 - .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
1317 - .name = "imx-ipuv3-crtc",
1323 - .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
1324 - .dma[1] = -EINVAL,
1326 - .name = "imx-ipuv3-crtc",
1330 -static DEFINE_MUTEX(ipu_client_id_mutex);
1331 -static int ipu_client_id;
1333 -static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
1335 - struct device *dev = ipu->dev;
1339 - mutex_lock(&ipu_client_id_mutex);
1340 - id = ipu_client_id;
1341 - ipu_client_id += ARRAY_SIZE(client_reg);
1342 - mutex_unlock(&ipu_client_id_mutex);
1344 - for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
1345 - struct ipu_platform_reg *reg = &client_reg[i];
1346 - struct platform_device *pdev;
1347 - struct device_node *of_node;
1349 - /* Associate subdevice with the corresponding port node */
1350 - of_node = of_graph_get_port_by_id(dev->of_node, i);
1353 - "no port@%d node in %pOF, not using %s%d\n",
1355 - (i / 2) ? "DI" : "CSI", i % 2);
1359 - pdev = platform_device_alloc(reg->name, id++);
1362 - goto err_register;
1365 - pdev->dev.parent = dev;
1367 - reg->pdata.of_node = of_node;
1368 - ret = platform_device_add_data(pdev, ®->pdata,
1369 - sizeof(reg->pdata));
1371 - ret = platform_device_add(pdev);
1373 - platform_device_put(pdev);
1374 - goto err_register;
1381 - platform_device_unregister_children(to_platform_device(dev));
1387 -static int ipu_irq_init(struct ipu_soc *ipu)
1389 - struct irq_chip_generic *gc;
1390 - struct irq_chip_type *ct;
1391 - unsigned long unused[IPU_NUM_IRQS / 32] = {
1392 - 0x400100d0, 0xffe000fd,
1393 - 0x400100d0, 0xffe000fd,
1394 - 0x400100d0, 0xffe000fd,
1395 - 0x4077ffff, 0xffe7e1fd,
1396 - 0x23fffffe, 0x8880fff0,
1397 - 0xf98fe7d0, 0xfff81fff,
1398 - 0x400100d0, 0xffe000fd,
1403 - ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
1404 - &irq_generic_chip_ops, ipu);
1405 - if (!ipu->domain) {
1406 - dev_err(ipu->dev, "failed to add irq domain\n");
1410 - ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
1411 - handle_level_irq, 0, 0, 0);
1413 - dev_err(ipu->dev, "failed to alloc generic irq chips\n");
1414 - irq_domain_remove(ipu->domain);
1418 - /* Mask and clear all interrupts */
1419 - for (i = 0; i < IPU_NUM_IRQS; i += 32) {
1420 - ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
1421 - ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
1424 - for (i = 0; i < IPU_NUM_IRQS; i += 32) {
1425 - gc = irq_get_domain_generic_chip(ipu->domain, i);
1426 - gc->reg_base = ipu->cm_reg;
1427 - gc->unused = unused[i / 32];
1428 - ct = gc->chip_types;
1429 - ct->chip.irq_ack = irq_gc_ack_set_bit;
1430 - ct->chip.irq_mask = irq_gc_mask_clr_bit;
1431 - ct->chip.irq_unmask = irq_gc_mask_set_bit;
1432 - ct->regs.ack = IPU_INT_STAT(i / 32);
1433 - ct->regs.mask = IPU_INT_CTRL(i / 32);
1436 - irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
1437 - irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
1443 -static void ipu_irq_exit(struct ipu_soc *ipu)
1447 - irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
1448 - irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
1450 - /* TODO: remove irq_domain_generic_chips */
1452 - for (i = 0; i < IPU_NUM_IRQS; i++) {
1453 - irq = irq_linear_revmap(ipu->domain, i);
1455 - irq_dispose_mapping(irq);
1458 - irq_domain_remove(ipu->domain);
1461 -void ipu_dump(struct ipu_soc *ipu)
1465 - dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
1466 - ipu_cm_read(ipu, IPU_CONF));
1467 - dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
1468 - ipu_idmac_read(ipu, IDMAC_CONF));
1469 - dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
1470 - ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
1471 - dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
1472 - ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
1473 - dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
1474 - ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
1475 - dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
1476 - ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
1477 - dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
1478 - ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
1479 - dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
1480 - ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
1481 - dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
1482 - ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
1483 - dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
1484 - ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
1485 - dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
1486 - ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
1487 - dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
1488 - ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
1489 - dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
1490 - ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
1491 - dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
1492 - ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
1493 - for (i = 0; i < 15; i++)
1494 - dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
1495 - ipu_cm_read(ipu, IPU_INT_CTRL(i)));
1497 -EXPORT_SYMBOL_GPL(ipu_dump);
1499 -static int ipu_probe(struct platform_device *pdev)
1501 - struct device_node *np = pdev->dev.of_node;
1502 - struct ipu_soc *ipu;
1503 - struct resource *res;
1504 - unsigned long ipu_base;
1505 - int ret, irq_sync, irq_err;
1506 - const struct ipu_devtype *devtype;
1508 - devtype = of_device_get_match_data(&pdev->dev);
1512 - irq_sync = platform_get_irq(pdev, 0);
1513 - irq_err = platform_get_irq(pdev, 1);
1514 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1516 - dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
1517 - irq_sync, irq_err);
1519 - if (!res || irq_sync < 0 || irq_err < 0)
1522 - ipu_base = res->start;
1524 - ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
1528 - ipu->id = of_alias_get_id(np, "ipu");
1532 - if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
1533 - IS_ENABLED(CONFIG_DRM)) {
1534 - ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
1535 - "fsl,prg", ipu->id);
1536 - if (!ipu->prg_priv)
1537 - return -EPROBE_DEFER;
1540 - ipu->devtype = devtype;
1541 - ipu->ipu_type = devtype->type;
1543 - spin_lock_init(&ipu->lock);
1544 - mutex_init(&ipu->channel_lock);
1545 - INIT_LIST_HEAD(&ipu->channels);
1547 - dev_dbg(&pdev->dev, "cm_reg: 0x%08lx\n",
1548 - ipu_base + devtype->cm_ofs);
1549 - dev_dbg(&pdev->dev, "idmac: 0x%08lx\n",
1550 - ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
1551 - dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n",
1552 - ipu_base + devtype->cpmem_ofs);
1553 - dev_dbg(&pdev->dev, "csi0: 0x%08lx\n",
1554 - ipu_base + devtype->csi0_ofs);
1555 - dev_dbg(&pdev->dev, "csi1: 0x%08lx\n",
1556 - ipu_base + devtype->csi1_ofs);
1557 - dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
1558 - ipu_base + devtype->ic_ofs);
1559 - dev_dbg(&pdev->dev, "disp0: 0x%08lx\n",
1560 - ipu_base + devtype->disp0_ofs);
1561 - dev_dbg(&pdev->dev, "disp1: 0x%08lx\n",
1562 - ipu_base + devtype->disp1_ofs);
1563 - dev_dbg(&pdev->dev, "srm: 0x%08lx\n",
1564 - ipu_base + devtype->srm_ofs);
1565 - dev_dbg(&pdev->dev, "tpm: 0x%08lx\n",
1566 - ipu_base + devtype->tpm_ofs);
1567 - dev_dbg(&pdev->dev, "dc: 0x%08lx\n",
1568 - ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
1569 - dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
1570 - ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
1571 - dev_dbg(&pdev->dev, "dmfc: 0x%08lx\n",
1572 - ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
1573 - dev_dbg(&pdev->dev, "vdi: 0x%08lx\n",
1574 - ipu_base + devtype->vdi_ofs);
1576 - ipu->cm_reg = devm_ioremap(&pdev->dev,
1577 - ipu_base + devtype->cm_ofs, PAGE_SIZE);
1578 - ipu->idmac_reg = devm_ioremap(&pdev->dev,
1579 - ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
1582 - if (!ipu->cm_reg || !ipu->idmac_reg)
1585 - ipu->clk = devm_clk_get(&pdev->dev, "bus");
1586 - if (IS_ERR(ipu->clk)) {
1587 - ret = PTR_ERR(ipu->clk);
1588 - dev_err(&pdev->dev, "clk_get failed with %d", ret);
1592 - platform_set_drvdata(pdev, ipu);
1594 - ret = clk_prepare_enable(ipu->clk);
1596 - dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
1600 - ipu->dev = &pdev->dev;
1601 - ipu->irq_sync = irq_sync;
1602 - ipu->irq_err = irq_err;
1604 - ret = device_reset(&pdev->dev);
1606 - dev_err(&pdev->dev, "failed to reset: %d\n", ret);
1607 - goto out_failed_reset;
1609 - ret = ipu_memory_reset(ipu);
1611 - goto out_failed_reset;
1613 - ret = ipu_irq_init(ipu);
1615 - goto out_failed_irq;
1617 - /* Set MCU_T to divide MCU access window into 2 */
1618 - ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
1621 - ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
1623 - goto failed_submodules_init;
1625 - ret = ipu_add_client_devices(ipu, ipu_base);
1627 - dev_err(&pdev->dev, "adding client devices failed with %d\n",
1629 - goto failed_add_clients;
1632 - dev_info(&pdev->dev, "%s probed\n", devtype->name);
1636 -failed_add_clients:
1637 - ipu_submodules_exit(ipu);
1638 -failed_submodules_init:
1639 - ipu_irq_exit(ipu);
1642 - clk_disable_unprepare(ipu->clk);
1646 -static int ipu_remove(struct platform_device *pdev)
1648 - struct ipu_soc *ipu = platform_get_drvdata(pdev);
1650 - platform_device_unregister_children(pdev);
1651 - ipu_submodules_exit(ipu);
1652 - ipu_irq_exit(ipu);
1654 - clk_disable_unprepare(ipu->clk);
1659 -static struct platform_driver imx_ipu_driver = {
1661 - .name = "imx-ipuv3",
1662 - .of_match_table = imx_ipu_dt_ids,
1664 - .probe = ipu_probe,
1665 - .remove = ipu_remove,
1668 -static struct platform_driver * const drivers[] = {
1669 -#if IS_ENABLED(CONFIG_DRM)
1676 -static int __init imx_ipu_init(void)
1678 - return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
1680 -module_init(imx_ipu_init);
1682 -static void __exit imx_ipu_exit(void)
1684 - platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
1686 -module_exit(imx_ipu_exit);
1688 -MODULE_ALIAS("platform:imx-ipuv3");
1689 -MODULE_DESCRIPTION("i.MX IPU v3 driver");
1690 -MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
1691 -MODULE_LICENSE("GPL");
1692 --- a/drivers/gpu/imx/ipu-v3/ipu-cpmem.c
1695 -// SPDX-License-Identifier: GPL-2.0-or-later
1697 - * Copyright (C) 2012 Mentor Graphics Inc.
1698 - * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
1700 -#include <linux/types.h>
1701 -#include <linux/bitrev.h>
1702 -#include <linux/io.h>
1703 -#include <linux/sizes.h>
1704 -#include <drm/drm_fourcc.h>
1705 -#include "ipu-prv.h"
1707 -struct ipu_cpmem_word {
1712 -struct ipu_ch_param {
1713 - struct ipu_cpmem_word word[2];
1717 - struct ipu_ch_param __iomem *base;
1721 - struct ipu_soc *ipu;
1724 -#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
1726 -#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
1727 -#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
1728 -#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
1729 -#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
1730 -#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
1731 -#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
1732 -#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
1734 -#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
1735 -#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
1736 -#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
1737 -#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
1738 -#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
1739 -#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
1740 -#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
1741 -#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
1742 -#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
1743 -#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
1744 -#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
1745 -#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
1746 -#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
1747 -#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
1748 -#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
1749 -#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
1750 -#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
1751 -#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
1752 -#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
1753 -#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
1754 -#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
1755 -#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
1756 -#define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3)
1757 -#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
1758 -#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
1759 -#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
1760 -#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
1761 -#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
1762 -#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
1763 -#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
1764 -#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
1765 -#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
1766 -#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
1767 -#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
1768 -#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
1769 -#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
1770 -#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
1771 -#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
1772 -#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
1773 -#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
1774 -#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
1775 -#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
1776 -#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
1777 -#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
1778 -#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
1779 -#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
1780 -#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
1781 -#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
1782 -#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
1783 -#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
1784 -#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
1786 -static inline struct ipu_ch_param __iomem *
1787 -ipu_get_cpmem(struct ipuv3_channel *ch)
1789 - struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
1791 - return cpmem->base + ch->num;
1794 -static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
1796 - struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
1797 - u32 bit = (wbs >> 8) % 160;
1798 - u32 size = wbs & 0xff;
1799 - u32 word = (wbs >> 8) / 160;
1801 - u32 ofs = bit % 32;
1802 - u32 mask = (1 << size) - 1;
1805 - pr_debug("%s %d %d %d\n", __func__, word, bit , size);
1807 - val = readl(&base->word[word].data[i]);
1808 - val &= ~(mask << ofs);
1810 - writel(val, &base->word[word].data[i]);
1812 - if ((bit + size - 1) / 32 > i) {
1813 - val = readl(&base->word[word].data[i + 1]);
1814 - val &= ~(mask >> (ofs ? (32 - ofs) : 0));
1815 - val |= v >> (ofs ? (32 - ofs) : 0);
1816 - writel(val, &base->word[word].data[i + 1]);
1820 -static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
1822 - struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
1823 - u32 bit = (wbs >> 8) % 160;
1824 - u32 size = wbs & 0xff;
1825 - u32 word = (wbs >> 8) / 160;
1827 - u32 ofs = bit % 32;
1828 - u32 mask = (1 << size) - 1;
1831 - pr_debug("%s %d %d %d\n", __func__, word, bit , size);
1833 - val = (readl(&base->word[word].data[i]) >> ofs) & mask;
1835 - if ((bit + size - 1) / 32 > i) {
1838 - tmp = readl(&base->word[word].data[i + 1]);
1839 - tmp &= mask >> (ofs ? (32 - ofs) : 0);
1840 - val |= tmp << (ofs ? (32 - ofs) : 0);
1847 - * The V4L2 spec defines packed RGB formats in memory byte order, which from
1848 - * point of view of the IPU corresponds to little-endian words with the first
1849 - * component in the least significant bits.
1850 - * The DRM pixel formats and IPU internal representation are ordered the other
1851 - * way around, with the first named component ordered at the most significant
1852 - * bits. Further, V4L2 formats are not well defined:
1853 - * https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
1854 - * We choose the interpretation which matches GStreamer behavior.
1856 -static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
1858 - switch (pixelformat) {
1859 - case V4L2_PIX_FMT_RGB565:
1861 - * Here we choose the 'corrected' interpretation of RGBP, a
1862 - * little-endian 16-bit word with the red component at the most
1863 - * significant bits:
1864 - * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
1866 - return DRM_FORMAT_RGB565;
1867 - case V4L2_PIX_FMT_BGR24:
1868 - /* B G R <=> [24:0] R:G:B */
1869 - return DRM_FORMAT_RGB888;
1870 - case V4L2_PIX_FMT_RGB24:
1871 - /* R G B <=> [24:0] B:G:R */
1872 - return DRM_FORMAT_BGR888;
1873 - case V4L2_PIX_FMT_BGR32:
1874 - /* B G R A <=> [32:0] A:B:G:R */
1875 - return DRM_FORMAT_XRGB8888;
1876 - case V4L2_PIX_FMT_RGB32:
1877 - /* R G B A <=> [32:0] A:B:G:R */
1878 - return DRM_FORMAT_XBGR8888;
1879 - case V4L2_PIX_FMT_ABGR32:
1880 - /* B G R A <=> [32:0] A:R:G:B */
1881 - return DRM_FORMAT_ARGB8888;
1882 - case V4L2_PIX_FMT_XBGR32:
1883 - /* B G R X <=> [32:0] X:R:G:B */
1884 - return DRM_FORMAT_XRGB8888;
1885 - case V4L2_PIX_FMT_BGRA32:
1886 - /* A B G R <=> [32:0] R:G:B:A */
1887 - return DRM_FORMAT_RGBA8888;
1888 - case V4L2_PIX_FMT_BGRX32:
1889 - /* X B G R <=> [32:0] R:G:B:X */
1890 - return DRM_FORMAT_RGBX8888;
1891 - case V4L2_PIX_FMT_RGBA32:
1892 - /* R G B A <=> [32:0] A:B:G:R */
1893 - return DRM_FORMAT_ABGR8888;
1894 - case V4L2_PIX_FMT_RGBX32:
1895 - /* R G B X <=> [32:0] X:B:G:R */
1896 - return DRM_FORMAT_XBGR8888;
1897 - case V4L2_PIX_FMT_ARGB32:
1898 - /* A R G B <=> [32:0] B:G:R:A */
1899 - return DRM_FORMAT_BGRA8888;
1900 - case V4L2_PIX_FMT_XRGB32:
1901 - /* X R G B <=> [32:0] B:G:R:X */
1902 - return DRM_FORMAT_BGRX8888;
1903 - case V4L2_PIX_FMT_UYVY:
1904 - return DRM_FORMAT_UYVY;
1905 - case V4L2_PIX_FMT_YUYV:
1906 - return DRM_FORMAT_YUYV;
1907 - case V4L2_PIX_FMT_YUV420:
1908 - return DRM_FORMAT_YUV420;
1909 - case V4L2_PIX_FMT_YUV422P:
1910 - return DRM_FORMAT_YUV422;
1911 - case V4L2_PIX_FMT_YVU420:
1912 - return DRM_FORMAT_YVU420;
1913 - case V4L2_PIX_FMT_NV12:
1914 - return DRM_FORMAT_NV12;
1915 - case V4L2_PIX_FMT_NV16:
1916 - return DRM_FORMAT_NV16;
1922 -void ipu_cpmem_zero(struct ipuv3_channel *ch)
1924 - struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
1925 - void __iomem *base = p;
1928 - for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
1929 - writel(0, base + i * sizeof(u32));
1931 -EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
1933 -void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
1935 - ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
1936 - ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
1938 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
1940 -void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
1942 - ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
1944 -EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
1946 -void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
1948 - ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
1950 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
1952 -void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
1954 - struct ipu_soc *ipu = ch->ipu;
1957 - if (ipu->ipu_type == IPUV3EX)
1958 - ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
1960 - val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
1961 - val |= 1 << (ch->num % 32);
1962 - ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
1964 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
1966 -void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
1968 - WARN_ON_ONCE(buf & 0x7);
1971 - ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
1973 - ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
1975 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
1977 -void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
1979 - WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
1981 - ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
1982 - ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
1984 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
1986 -void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
1989 - u32 ilo, sly, sluv;
1993 - ilo = 0x100000 - (stride / 8);
1998 - sly = (stride * 2) - 1;
2000 - switch (pixelformat) {
2001 - case V4L2_PIX_FMT_YUV420:
2002 - case V4L2_PIX_FMT_YVU420:
2003 - sluv = stride / 2 - 1;
2005 - case V4L2_PIX_FMT_NV12:
2006 - sluv = stride - 1;
2008 - case V4L2_PIX_FMT_YUV422P:
2009 - sluv = stride - 1;
2011 - case V4L2_PIX_FMT_NV16:
2012 - sluv = stride * 2 - 1;
2019 - ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
2020 - ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
2021 - ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
2023 - ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
2025 -EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
2027 -void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
2030 - ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
2032 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
2034 -int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
2036 - return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
2038 -EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
2040 -void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
2042 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
2044 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
2046 -void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
2048 - ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
2050 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
2052 -void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
2053 - enum ipu_rotate_mode rot)
2055 - u32 temp_rot = bitrev8(rot) >> 5;
2057 - ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
2059 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
2061 -int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
2062 - const struct ipu_rgb *rgb)
2064 - int bpp = 0, npb = 0, ro, go, bo, to;
2066 - ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
2067 - go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
2068 - bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
2069 - to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
2071 - ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
2072 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
2073 - ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
2074 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
2075 - ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
2076 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
2078 - if (rgb->transp.length) {
2079 - ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
2080 - rgb->transp.length - 1);
2081 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
2083 - ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
2084 - ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
2085 - rgb->bits_per_pixel);
2088 - switch (rgb->bits_per_pixel) {
2108 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
2109 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
2110 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
2114 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
2116 -int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
2118 - int bpp = 0, npb = 0;
2141 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
2142 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
2143 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
2147 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
2149 -void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
2151 - switch (pixel_format) {
2152 - case V4L2_PIX_FMT_UYVY:
2153 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
2154 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
2155 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
2157 - case V4L2_PIX_FMT_YUYV:
2158 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
2159 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
2160 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
2164 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
2166 -void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
2167 - unsigned int uv_stride,
2168 - unsigned int u_offset, unsigned int v_offset)
2170 - WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
2172 - ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
2173 - ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
2174 - ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
2176 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
2178 -static const struct ipu_rgb def_xrgb_32 = {
2179 - .red = { .offset = 16, .length = 8, },
2180 - .green = { .offset = 8, .length = 8, },
2181 - .blue = { .offset = 0, .length = 8, },
2182 - .transp = { .offset = 24, .length = 8, },
2183 - .bits_per_pixel = 32,
2186 -static const struct ipu_rgb def_xbgr_32 = {
2187 - .red = { .offset = 0, .length = 8, },
2188 - .green = { .offset = 8, .length = 8, },
2189 - .blue = { .offset = 16, .length = 8, },
2190 - .transp = { .offset = 24, .length = 8, },
2191 - .bits_per_pixel = 32,
2194 -static const struct ipu_rgb def_rgbx_32 = {
2195 - .red = { .offset = 24, .length = 8, },
2196 - .green = { .offset = 16, .length = 8, },
2197 - .blue = { .offset = 8, .length = 8, },
2198 - .transp = { .offset = 0, .length = 8, },
2199 - .bits_per_pixel = 32,
2202 -static const struct ipu_rgb def_bgrx_32 = {
2203 - .red = { .offset = 8, .length = 8, },
2204 - .green = { .offset = 16, .length = 8, },
2205 - .blue = { .offset = 24, .length = 8, },
2206 - .transp = { .offset = 0, .length = 8, },
2207 - .bits_per_pixel = 32,
2210 -static const struct ipu_rgb def_rgb_24 = {
2211 - .red = { .offset = 16, .length = 8, },
2212 - .green = { .offset = 8, .length = 8, },
2213 - .blue = { .offset = 0, .length = 8, },
2214 - .transp = { .offset = 0, .length = 0, },
2215 - .bits_per_pixel = 24,
2218 -static const struct ipu_rgb def_bgr_24 = {
2219 - .red = { .offset = 0, .length = 8, },
2220 - .green = { .offset = 8, .length = 8, },
2221 - .blue = { .offset = 16, .length = 8, },
2222 - .transp = { .offset = 0, .length = 0, },
2223 - .bits_per_pixel = 24,
2226 -static const struct ipu_rgb def_rgb_16 = {
2227 - .red = { .offset = 11, .length = 5, },
2228 - .green = { .offset = 5, .length = 6, },
2229 - .blue = { .offset = 0, .length = 5, },
2230 - .transp = { .offset = 0, .length = 0, },
2231 - .bits_per_pixel = 16,
2234 -static const struct ipu_rgb def_bgr_16 = {
2235 - .red = { .offset = 0, .length = 5, },
2236 - .green = { .offset = 5, .length = 6, },
2237 - .blue = { .offset = 11, .length = 5, },
2238 - .transp = { .offset = 0, .length = 0, },
2239 - .bits_per_pixel = 16,
2242 -static const struct ipu_rgb def_argb_16 = {
2243 - .red = { .offset = 10, .length = 5, },
2244 - .green = { .offset = 5, .length = 5, },
2245 - .blue = { .offset = 0, .length = 5, },
2246 - .transp = { .offset = 15, .length = 1, },
2247 - .bits_per_pixel = 16,
2250 -static const struct ipu_rgb def_argb_16_4444 = {
2251 - .red = { .offset = 8, .length = 4, },
2252 - .green = { .offset = 4, .length = 4, },
2253 - .blue = { .offset = 0, .length = 4, },
2254 - .transp = { .offset = 12, .length = 4, },
2255 - .bits_per_pixel = 16,
2258 -static const struct ipu_rgb def_abgr_16 = {
2259 - .red = { .offset = 0, .length = 5, },
2260 - .green = { .offset = 5, .length = 5, },
2261 - .blue = { .offset = 10, .length = 5, },
2262 - .transp = { .offset = 15, .length = 1, },
2263 - .bits_per_pixel = 16,
2266 -static const struct ipu_rgb def_rgba_16 = {
2267 - .red = { .offset = 11, .length = 5, },
2268 - .green = { .offset = 6, .length = 5, },
2269 - .blue = { .offset = 1, .length = 5, },
2270 - .transp = { .offset = 0, .length = 1, },
2271 - .bits_per_pixel = 16,
2274 -static const struct ipu_rgb def_bgra_16 = {
2275 - .red = { .offset = 1, .length = 5, },
2276 - .green = { .offset = 6, .length = 5, },
2277 - .blue = { .offset = 11, .length = 5, },
2278 - .transp = { .offset = 0, .length = 1, },
2279 - .bits_per_pixel = 16,
2282 -#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
2283 -#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2284 - (pix->width * ((y) / 2) / 2) + (x) / 2)
2285 -#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2286 - (pix->width * pix->height / 4) + \
2287 - (pix->width * ((y) / 2) / 2) + (x) / 2)
2288 -#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2289 - (pix->width * (y) / 2) + (x) / 2)
2290 -#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2291 - (pix->width * pix->height / 2) + \
2292 - (pix->width * (y) / 2) + (x) / 2)
2293 -#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2294 - (pix->width * ((y) / 2)) + (x))
2295 -#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
2296 - (pix->width * y) + (x))
2298 -#define NUM_ALPHA_CHANNELS 7
2300 -/* See Table 37-12. Alpha channels mapping. */
2301 -static int ipu_channel_albm(int ch_num)
2304 - case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: return 0;
2305 - case IPUV3_CHANNEL_G_MEM_IC_PP: return 1;
2306 - case IPUV3_CHANNEL_MEM_FG_SYNC: return 2;
2307 - case IPUV3_CHANNEL_MEM_FG_ASYNC: return 3;
2308 - case IPUV3_CHANNEL_MEM_BG_SYNC: return 4;
2309 - case IPUV3_CHANNEL_MEM_BG_ASYNC: return 5;
2310 - case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
2316 -static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
2318 - struct ipu_soc *ipu = ch->ipu;
2322 - albm = ipu_channel_albm(ch->num);
2326 - ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
2327 - ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
2328 - ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
2330 - val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
2331 - val |= BIT(ch->num);
2332 - ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
2335 -int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
2337 - switch (drm_fourcc) {
2338 - case DRM_FORMAT_YUV420:
2339 - case DRM_FORMAT_YVU420:
2341 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
2343 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2345 - case DRM_FORMAT_YUV422:
2346 - case DRM_FORMAT_YVU422:
2348 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
2350 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2352 - case DRM_FORMAT_YUV444:
2353 - case DRM_FORMAT_YVU444:
2355 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
2357 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2359 - case DRM_FORMAT_NV12:
2361 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
2363 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2365 - case DRM_FORMAT_NV16:
2367 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
2369 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2371 - case DRM_FORMAT_UYVY:
2373 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
2375 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
2377 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2379 - case DRM_FORMAT_YUYV:
2381 - ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
2383 - ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
2385 - ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
2387 - case DRM_FORMAT_ABGR8888:
2388 - case DRM_FORMAT_XBGR8888:
2389 - ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
2391 - case DRM_FORMAT_ARGB8888:
2392 - case DRM_FORMAT_XRGB8888:
2393 - ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
2395 - case DRM_FORMAT_RGBA8888:
2396 - case DRM_FORMAT_RGBX8888:
2397 - case DRM_FORMAT_RGBX8888_A8:
2398 - ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
2400 - case DRM_FORMAT_BGRA8888:
2401 - case DRM_FORMAT_BGRX8888:
2402 - case DRM_FORMAT_BGRX8888_A8:
2403 - ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
2405 - case DRM_FORMAT_BGR888:
2406 - case DRM_FORMAT_BGR888_A8:
2407 - ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
2409 - case DRM_FORMAT_RGB888:
2410 - case DRM_FORMAT_RGB888_A8:
2411 - ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
2413 - case DRM_FORMAT_RGB565:
2414 - case DRM_FORMAT_RGB565_A8:
2415 - ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
2417 - case DRM_FORMAT_BGR565:
2418 - case DRM_FORMAT_BGR565_A8:
2419 - ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
2421 - case DRM_FORMAT_ARGB1555:
2422 - ipu_cpmem_set_format_rgb(ch, &def_argb_16);
2424 - case DRM_FORMAT_ABGR1555:
2425 - ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
2427 - case DRM_FORMAT_RGBA5551:
2428 - ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
2430 - case DRM_FORMAT_BGRA5551:
2431 - ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
2433 - case DRM_FORMAT_ARGB4444:
2434 - ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
2440 - switch (drm_fourcc) {
2441 - case DRM_FORMAT_RGB565_A8:
2442 - case DRM_FORMAT_BGR565_A8:
2443 - case DRM_FORMAT_RGB888_A8:
2444 - case DRM_FORMAT_BGR888_A8:
2445 - case DRM_FORMAT_RGBX8888_A8:
2446 - case DRM_FORMAT_BGRX8888_A8:
2447 - ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
2448 - ipu_cpmem_set_separate_alpha(ch);
2456 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
2458 -int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
2460 - struct v4l2_pix_format *pix = &image->pix;
2461 - int offset, u_offset, v_offset;
2464 - pr_debug("%s: resolution: %dx%d stride: %d\n",
2465 - __func__, pix->width, pix->height,
2466 - pix->bytesperline);
2468 - ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
2469 - ipu_cpmem_set_stride(ch, pix->bytesperline);
2471 - ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
2473 - switch (pix->pixelformat) {
2474 - case V4L2_PIX_FMT_YUV420:
2475 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2476 - u_offset = image->u_offset ?
2477 - image->u_offset : U_OFFSET(pix, image->rect.left,
2478 - image->rect.top) - offset;
2479 - v_offset = image->v_offset ?
2480 - image->v_offset : V_OFFSET(pix, image->rect.left,
2481 - image->rect.top) - offset;
2483 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
2484 - u_offset, v_offset);
2486 - case V4L2_PIX_FMT_YVU420:
2487 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2488 - u_offset = image->u_offset ?
2489 - image->u_offset : V_OFFSET(pix, image->rect.left,
2490 - image->rect.top) - offset;
2491 - v_offset = image->v_offset ?
2492 - image->v_offset : U_OFFSET(pix, image->rect.left,
2493 - image->rect.top) - offset;
2495 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
2496 - u_offset, v_offset);
2498 - case V4L2_PIX_FMT_YUV422P:
2499 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2500 - u_offset = image->u_offset ?
2501 - image->u_offset : U2_OFFSET(pix, image->rect.left,
2502 - image->rect.top) - offset;
2503 - v_offset = image->v_offset ?
2504 - image->v_offset : V2_OFFSET(pix, image->rect.left,
2505 - image->rect.top) - offset;
2507 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
2508 - u_offset, v_offset);
2510 - case V4L2_PIX_FMT_NV12:
2511 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2512 - u_offset = image->u_offset ?
2513 - image->u_offset : UV_OFFSET(pix, image->rect.left,
2514 - image->rect.top) - offset;
2515 - v_offset = image->v_offset ? image->v_offset : 0;
2517 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
2518 - u_offset, v_offset);
2520 - case V4L2_PIX_FMT_NV16:
2521 - offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
2522 - u_offset = image->u_offset ?
2523 - image->u_offset : UV2_OFFSET(pix, image->rect.left,
2524 - image->rect.top) - offset;
2525 - v_offset = image->v_offset ? image->v_offset : 0;
2527 - ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
2528 - u_offset, v_offset);
2530 - case V4L2_PIX_FMT_UYVY:
2531 - case V4L2_PIX_FMT_YUYV:
2532 - case V4L2_PIX_FMT_RGB565:
2533 - offset = image->rect.left * 2 +
2534 - image->rect.top * pix->bytesperline;
2536 - case V4L2_PIX_FMT_RGB32:
2537 - case V4L2_PIX_FMT_BGR32:
2538 - case V4L2_PIX_FMT_ABGR32:
2539 - case V4L2_PIX_FMT_XBGR32:
2540 - case V4L2_PIX_FMT_BGRA32:
2541 - case V4L2_PIX_FMT_BGRX32:
2542 - case V4L2_PIX_FMT_RGBA32:
2543 - case V4L2_PIX_FMT_RGBX32:
2544 - case V4L2_PIX_FMT_ARGB32:
2545 - case V4L2_PIX_FMT_XRGB32:
2546 - offset = image->rect.left * 4 +
2547 - image->rect.top * pix->bytesperline;
2549 - case V4L2_PIX_FMT_RGB24:
2550 - case V4L2_PIX_FMT_BGR24:
2551 - offset = image->rect.left * 3 +
2552 - image->rect.top * pix->bytesperline;
2554 - case V4L2_PIX_FMT_SBGGR8:
2555 - case V4L2_PIX_FMT_SGBRG8:
2556 - case V4L2_PIX_FMT_SGRBG8:
2557 - case V4L2_PIX_FMT_SRGGB8:
2558 - case V4L2_PIX_FMT_GREY:
2559 - offset = image->rect.left + image->rect.top * pix->bytesperline;
2561 - case V4L2_PIX_FMT_SBGGR16:
2562 - case V4L2_PIX_FMT_SGBRG16:
2563 - case V4L2_PIX_FMT_SGRBG16:
2564 - case V4L2_PIX_FMT_SRGGB16:
2565 - case V4L2_PIX_FMT_Y16:
2566 - offset = image->rect.left * 2 +
2567 - image->rect.top * pix->bytesperline;
2570 - /* This should not happen */
2576 - ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
2577 - ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
2581 -EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
2583 -void ipu_cpmem_dump(struct ipuv3_channel *ch)
2585 - struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
2586 - struct ipu_soc *ipu = ch->ipu;
2587 - int chno = ch->num;
2589 - dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
2590 - readl(&p->word[0].data[0]),
2591 - readl(&p->word[0].data[1]),
2592 - readl(&p->word[0].data[2]),
2593 - readl(&p->word[0].data[3]),
2594 - readl(&p->word[0].data[4]));
2595 - dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
2596 - readl(&p->word[1].data[0]),
2597 - readl(&p->word[1].data[1]),
2598 - readl(&p->word[1].data[2]),
2599 - readl(&p->word[1].data[3]),
2600 - readl(&p->word[1].data[4]));
2601 - dev_dbg(ipu->dev, "PFS 0x%x, ",
2602 - ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
2603 - dev_dbg(ipu->dev, "BPP 0x%x, ",
2604 - ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
2605 - dev_dbg(ipu->dev, "NPB 0x%x\n",
2606 - ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
2608 - dev_dbg(ipu->dev, "FW %d, ",
2609 - ipu_ch_param_read_field(ch, IPU_FIELD_FW));
2610 - dev_dbg(ipu->dev, "FH %d, ",
2611 - ipu_ch_param_read_field(ch, IPU_FIELD_FH));
2612 - dev_dbg(ipu->dev, "EBA0 0x%x\n",
2613 - ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
2614 - dev_dbg(ipu->dev, "EBA1 0x%x\n",
2615 - ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
2616 - dev_dbg(ipu->dev, "Stride %d\n",
2617 - ipu_ch_param_read_field(ch, IPU_FIELD_SL));
2618 - dev_dbg(ipu->dev, "scan_order %d\n",
2619 - ipu_ch_param_read_field(ch, IPU_FIELD_SO));
2620 - dev_dbg(ipu->dev, "uv_stride %d\n",
2621 - ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
2622 - dev_dbg(ipu->dev, "u_offset 0x%x\n",
2623 - ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
2624 - dev_dbg(ipu->dev, "v_offset 0x%x\n",
2625 - ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
2627 - dev_dbg(ipu->dev, "Width0 %d+1, ",
2628 - ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
2629 - dev_dbg(ipu->dev, "Width1 %d+1, ",
2630 - ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
2631 - dev_dbg(ipu->dev, "Width2 %d+1, ",
2632 - ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
2633 - dev_dbg(ipu->dev, "Width3 %d+1, ",
2634 - ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
2635 - dev_dbg(ipu->dev, "Offset0 %d, ",
2636 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
2637 - dev_dbg(ipu->dev, "Offset1 %d, ",
2638 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
2639 - dev_dbg(ipu->dev, "Offset2 %d, ",
2640 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
2641 - dev_dbg(ipu->dev, "Offset3 %d\n",
2642 - ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
2644 -EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
2646 -int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
2648 - struct ipu_cpmem *cpmem;
2650 - cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
2654 - ipu->cpmem_priv = cpmem;
2656 - spin_lock_init(&cpmem->lock);
2657 - cpmem->base = devm_ioremap(dev, base, SZ_128K);
2661 - dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
2662 - base, cpmem->base);
2668 -void ipu_cpmem_exit(struct ipu_soc *ipu)
2671 --- a/drivers/gpu/imx/ipu-v3/ipu-csi.c
2674 -// SPDX-License-Identifier: GPL-2.0-or-later
2676 - * Copyright (C) 2012-2014 Mentor Graphics Inc.
2677 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
2679 -#include <linux/export.h>
2680 -#include <linux/module.h>
2681 -#include <linux/types.h>
2682 -#include <linux/errno.h>
2683 -#include <linux/delay.h>
2684 -#include <linux/io.h>
2685 -#include <linux/err.h>
2686 -#include <linux/platform_device.h>
2687 -#include <linux/videodev2.h>
2688 -#include <uapi/linux/v4l2-mediabus.h>
2689 -#include <linux/clk.h>
2690 -#include <linux/clk-provider.h>
2691 -#include <linux/clkdev.h>
2693 -#include "ipu-prv.h"
2696 - void __iomem *base;
2699 - struct clk *clk_ipu; /* IPU bus clock */
2702 - struct ipu_soc *ipu;
2705 -/* CSI Register Offsets */
2706 -#define CSI_SENS_CONF 0x0000
2707 -#define CSI_SENS_FRM_SIZE 0x0004
2708 -#define CSI_ACT_FRM_SIZE 0x0008
2709 -#define CSI_OUT_FRM_CTRL 0x000c
2710 -#define CSI_TST_CTRL 0x0010
2711 -#define CSI_CCIR_CODE_1 0x0014
2712 -#define CSI_CCIR_CODE_2 0x0018
2713 -#define CSI_CCIR_CODE_3 0x001c
2714 -#define CSI_MIPI_DI 0x0020
2715 -#define CSI_SKIP 0x0024
2716 -#define CSI_CPD_CTRL 0x0028
2717 -#define CSI_CPD_RC(n) (0x002c + ((n)*4))
2718 -#define CSI_CPD_RS(n) (0x004c + ((n)*4))
2719 -#define CSI_CPD_GRC(n) (0x005c + ((n)*4))
2720 -#define CSI_CPD_GRS(n) (0x007c + ((n)*4))
2721 -#define CSI_CPD_GBC(n) (0x008c + ((n)*4))
2722 -#define CSI_CPD_GBS(n) (0x00Ac + ((n)*4))
2723 -#define CSI_CPD_BC(n) (0x00Bc + ((n)*4))
2724 -#define CSI_CPD_BS(n) (0x00Dc + ((n)*4))
2725 -#define CSI_CPD_OFFSET1 0x00ec
2726 -#define CSI_CPD_OFFSET2 0x00f0
2728 -/* CSI Register Fields */
2729 -#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
2730 -#define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700
2731 -#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L
2732 -#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
2733 -#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
2734 -#define CSI_SENS_CONF_DATA_FMT_BAYER 3L
2735 -#define CSI_SENS_CONF_DATA_FMT_RGB565 4L
2736 -#define CSI_SENS_CONF_DATA_FMT_RGB555 5L
2737 -#define CSI_SENS_CONF_DATA_FMT_RGB444 6L
2738 -#define CSI_SENS_CONF_DATA_FMT_JPEG 7L
2740 -#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
2741 -#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
2742 -#define CSI_SENS_CONF_DATA_POL_SHIFT 2
2743 -#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
2744 -#define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070
2745 -#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
2746 -#define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7
2747 -#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11
2748 -#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
2749 -#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
2751 -#define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000
2752 -#define CSI_SENS_CONF_DATA_DEST_SHIFT 24
2753 -#define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000
2754 -#define CSI_SENS_CONF_JPEG8_EN_SHIFT 27
2755 -#define CSI_SENS_CONF_JPEG_EN_SHIFT 28
2756 -#define CSI_SENS_CONF_FORCE_EOF_SHIFT 29
2757 -#define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31
2759 -#define CSI_DATA_DEST_IC 2
2760 -#define CSI_DATA_DEST_IDMAC 4
2762 -#define CSI_CCIR_ERR_DET_EN 0x01000000
2763 -#define CSI_HORI_DOWNSIZE_EN 0x80000000
2764 -#define CSI_VERT_DOWNSIZE_EN 0x40000000
2765 -#define CSI_TEST_GEN_MODE_EN 0x01000000
2767 -#define CSI_HSC_MASK 0x1fff0000
2768 -#define CSI_HSC_SHIFT 16
2769 -#define CSI_VSC_MASK 0x00000fff
2770 -#define CSI_VSC_SHIFT 0
2772 -#define CSI_TEST_GEN_R_MASK 0x000000ff
2773 -#define CSI_TEST_GEN_R_SHIFT 0
2774 -#define CSI_TEST_GEN_G_MASK 0x0000ff00
2775 -#define CSI_TEST_GEN_G_SHIFT 8
2776 -#define CSI_TEST_GEN_B_MASK 0x00ff0000
2777 -#define CSI_TEST_GEN_B_SHIFT 16
2779 -#define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007
2780 -#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0
2781 -#define CSI_SKIP_SMFC_MASK 0x000000f8
2782 -#define CSI_SKIP_SMFC_SHIFT 3
2783 -#define CSI_ID_2_SKIP_MASK 0x00000300
2784 -#define CSI_ID_2_SKIP_SHIFT 8
2786 -#define CSI_COLOR_FIRST_ROW_MASK 0x00000002
2787 -#define CSI_COLOR_FIRST_COMP_MASK 0x00000001
2789 -/* MIPI CSI-2 data types */
2790 -#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
2791 -#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
2792 -#define MIPI_DT_YUV422 0x1e /* UYVY... */
2793 -#define MIPI_DT_RGB444 0x20
2794 -#define MIPI_DT_RGB555 0x21
2795 -#define MIPI_DT_RGB565 0x22
2796 -#define MIPI_DT_RGB666 0x23
2797 -#define MIPI_DT_RGB888 0x24
2798 -#define MIPI_DT_RAW6 0x28
2799 -#define MIPI_DT_RAW7 0x29
2800 -#define MIPI_DT_RAW8 0x2a
2801 -#define MIPI_DT_RAW10 0x2b
2802 -#define MIPI_DT_RAW12 0x2c
2803 -#define MIPI_DT_RAW14 0x2d
2806 - * Bitfield of CSI bus signal polarities and modes.
2808 -struct ipu_csi_bus_config {
2809 - unsigned data_width:4;
2810 - unsigned clk_mode:3;
2811 - unsigned ext_vsync:1;
2812 - unsigned vsync_pol:1;
2813 - unsigned hsync_pol:1;
2814 - unsigned pixclk_pol:1;
2815 - unsigned data_pol:1;
2816 - unsigned sens_clksrc:1;
2817 - unsigned pack_tight:1;
2818 - unsigned force_eof:1;
2819 - unsigned data_en_pol:1;
2821 - unsigned data_fmt;
2826 - * Enumeration of CSI data bus widths.
2828 -enum ipu_csi_data_width {
2829 - IPU_CSI_DATA_WIDTH_4 = 0,
2830 - IPU_CSI_DATA_WIDTH_8 = 1,
2831 - IPU_CSI_DATA_WIDTH_10 = 3,
2832 - IPU_CSI_DATA_WIDTH_12 = 5,
2833 - IPU_CSI_DATA_WIDTH_16 = 9,
2837 - * Enumeration of CSI clock modes.
2839 -enum ipu_csi_clk_mode {
2840 - IPU_CSI_CLK_MODE_GATED_CLK,
2841 - IPU_CSI_CLK_MODE_NONGATED_CLK,
2842 - IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
2843 - IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
2844 - IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
2845 - IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
2846 - IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
2847 - IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
2850 -static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
2852 - return readl(csi->base + offset);
2855 -static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
2858 - writel(value, csi->base + offset);
2862 - * Set mclk division ratio for generating test mode mclk. Only used
2863 - * for test generator.
2865 -static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
2871 - div_ratio = (ipu_clk / pixel_clk) - 1;
2873 - if (div_ratio > 0xFF || div_ratio < 0) {
2874 - dev_err(csi->ipu->dev,
2875 - "value of pixel_clk extends normal range\n");
2879 - temp = ipu_csi_read(csi, CSI_SENS_CONF);
2880 - temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
2881 - ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
2888 - * Find the CSI data format and data width for the given V4L2 media
2889 - * bus pixel format code.
2891 -static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
2892 - enum v4l2_mbus_type mbus_type)
2894 - switch (mbus_code) {
2895 - case MEDIA_BUS_FMT_BGR565_2X8_BE:
2896 - case MEDIA_BUS_FMT_BGR565_2X8_LE:
2897 - case MEDIA_BUS_FMT_RGB565_2X8_BE:
2898 - case MEDIA_BUS_FMT_RGB565_2X8_LE:
2899 - if (mbus_type == V4L2_MBUS_CSI2_DPHY)
2900 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
2902 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2903 - cfg->mipi_dt = MIPI_DT_RGB565;
2904 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2906 - case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
2907 - case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
2908 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
2909 - cfg->mipi_dt = MIPI_DT_RGB444;
2910 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2912 - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
2913 - case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
2914 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
2915 - cfg->mipi_dt = MIPI_DT_RGB555;
2916 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2918 - case MEDIA_BUS_FMT_RGB888_1X24:
2919 - case MEDIA_BUS_FMT_BGR888_1X24:
2920 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
2921 - cfg->mipi_dt = MIPI_DT_RGB888;
2922 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2924 - case MEDIA_BUS_FMT_UYVY8_2X8:
2925 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
2926 - cfg->mipi_dt = MIPI_DT_YUV422;
2927 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2929 - case MEDIA_BUS_FMT_YUYV8_2X8:
2930 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
2931 - cfg->mipi_dt = MIPI_DT_YUV422;
2932 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2934 - case MEDIA_BUS_FMT_UYVY8_1X16:
2935 - case MEDIA_BUS_FMT_YUYV8_1X16:
2936 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2937 - cfg->mipi_dt = MIPI_DT_YUV422;
2938 - cfg->data_width = IPU_CSI_DATA_WIDTH_16;
2940 - case MEDIA_BUS_FMT_SBGGR8_1X8:
2941 - case MEDIA_BUS_FMT_SGBRG8_1X8:
2942 - case MEDIA_BUS_FMT_SGRBG8_1X8:
2943 - case MEDIA_BUS_FMT_SRGGB8_1X8:
2944 - case MEDIA_BUS_FMT_Y8_1X8:
2945 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2946 - cfg->mipi_dt = MIPI_DT_RAW8;
2947 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2949 - case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
2950 - case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
2951 - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
2952 - case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
2953 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
2954 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
2955 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
2956 - case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
2957 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2958 - cfg->mipi_dt = MIPI_DT_RAW10;
2959 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2961 - case MEDIA_BUS_FMT_SBGGR10_1X10:
2962 - case MEDIA_BUS_FMT_SGBRG10_1X10:
2963 - case MEDIA_BUS_FMT_SGRBG10_1X10:
2964 - case MEDIA_BUS_FMT_SRGGB10_1X10:
2965 - case MEDIA_BUS_FMT_Y10_1X10:
2966 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2967 - cfg->mipi_dt = MIPI_DT_RAW10;
2968 - cfg->data_width = IPU_CSI_DATA_WIDTH_10;
2970 - case MEDIA_BUS_FMT_SBGGR12_1X12:
2971 - case MEDIA_BUS_FMT_SGBRG12_1X12:
2972 - case MEDIA_BUS_FMT_SGRBG12_1X12:
2973 - case MEDIA_BUS_FMT_SRGGB12_1X12:
2974 - case MEDIA_BUS_FMT_Y12_1X12:
2975 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
2976 - cfg->mipi_dt = MIPI_DT_RAW12;
2977 - cfg->data_width = IPU_CSI_DATA_WIDTH_12;
2979 - case MEDIA_BUS_FMT_JPEG_1X8:
2981 - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
2982 - cfg->mipi_dt = MIPI_DT_RAW8;
2983 - cfg->data_width = IPU_CSI_DATA_WIDTH_8;
2992 -/* translate alternate field mode based on given standard */
2993 -static inline enum v4l2_field
2994 -ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
2996 - return (field != V4L2_FIELD_ALTERNATE) ? field :
2997 - ((std & V4L2_STD_525_60) ?
2998 - V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
3002 - * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
3004 -static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
3005 - const struct v4l2_mbus_config *mbus_cfg,
3006 - const struct v4l2_mbus_framefmt *mbus_fmt)
3010 - memset(csicfg, 0, sizeof(*csicfg));
3012 - ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
3016 - switch (mbus_cfg->type) {
3017 - case V4L2_MBUS_PARALLEL:
3018 - csicfg->ext_vsync = 1;
3019 - csicfg->vsync_pol = (mbus_cfg->flags &
3020 - V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
3021 - csicfg->hsync_pol = (mbus_cfg->flags &
3022 - V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
3023 - csicfg->pixclk_pol = (mbus_cfg->flags &
3024 - V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
3025 - csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
3027 - case V4L2_MBUS_BT656:
3028 - csicfg->ext_vsync = 0;
3029 - if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
3030 - mbus_fmt->field == V4L2_FIELD_ALTERNATE)
3031 - csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
3033 - csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
3035 - case V4L2_MBUS_CSI2_DPHY:
3037 - * MIPI CSI-2 requires non gated clock mode, all other
3038 - * parameters are not applicable for MIPI CSI-2 bus.
3040 - csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
3043 - /* will never get here, keep compiler quiet */
3051 -ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
3052 - const struct v4l2_mbus_framefmt *infmt,
3053 - const struct v4l2_mbus_framefmt *outfmt,
3056 - enum v4l2_field infield, outfield;
3059 - /* get translated field type of input and output */
3060 - infield = ipu_csi_translate_field(infmt->field, std);
3061 - outfield = ipu_csi_translate_field(outfmt->field, std);
3064 - * Write the H-V-F codes the CSI will match against the
3065 - * incoming data for start/end of active and blanking
3066 - * field intervals. If input and output field types are
3067 - * sequential but not the same (one is SEQ_BT and the other
3068 - * is SEQ_TB), swap the F-bit so that the CSI will capture
3069 - * field 1 lines before field 0 lines.
3071 - swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
3072 - V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
3073 - infield != outfield);
3075 - if (!swap_fields) {
3077 - * Field0BlankEnd = 110, Field0BlankStart = 010
3078 - * Field0ActiveEnd = 100, Field0ActiveStart = 000
3079 - * Field1BlankEnd = 111, Field1BlankStart = 011
3080 - * Field1ActiveEnd = 101, Field1ActiveStart = 001
3082 - ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
3084 - ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
3086 - dev_dbg(csi->ipu->dev, "capture field swap\n");
3088 - /* same as above but with F-bit inverted */
3089 - ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
3091 - ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
3094 - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
3100 -int ipu_csi_init_interface(struct ipu_csi *csi,
3101 - const struct v4l2_mbus_config *mbus_cfg,
3102 - const struct v4l2_mbus_framefmt *infmt,
3103 - const struct v4l2_mbus_framefmt *outfmt)
3105 - struct ipu_csi_bus_config cfg;
3106 - unsigned long flags;
3107 - u32 width, height, data = 0;
3111 - ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
3115 - /* set default sensor frame width and height */
3116 - width = infmt->width;
3117 - height = infmt->height;
3118 - if (infmt->field == V4L2_FIELD_ALTERNATE)
3121 - /* Set the CSI_SENS_CONF register remaining fields */
3122 - data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
3123 - cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
3124 - cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
3125 - cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
3126 - cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
3127 - cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
3128 - cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
3129 - cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
3130 - cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
3131 - cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
3132 - cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
3134 - spin_lock_irqsave(&csi->lock, flags);
3136 - ipu_csi_write(csi, data, CSI_SENS_CONF);
3138 - /* Set CCIR registers */
3140 - switch (cfg.clk_mode) {
3141 - case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
3142 - ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
3143 - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
3145 - case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
3146 - if (width == 720 && height == 480) {
3147 - std = V4L2_STD_NTSC;
3149 - } else if (width == 720 && height == 576) {
3150 - std = V4L2_STD_PAL;
3153 - dev_err(csi->ipu->dev,
3154 - "Unsupported interlaced video mode\n");
3159 - ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
3163 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
3164 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
3165 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
3166 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
3167 - ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
3169 - ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
3171 - case IPU_CSI_CLK_MODE_GATED_CLK:
3172 - case IPU_CSI_CLK_MODE_NONGATED_CLK:
3173 - ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
3177 - /* Setup sensor frame size */
3178 - ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
3179 - CSI_SENS_FRM_SIZE);
3181 - dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
3182 - ipu_csi_read(csi, CSI_SENS_CONF));
3183 - dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
3184 - ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
3187 - spin_unlock_irqrestore(&csi->lock, flags);
3191 -EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
3193 -bool ipu_csi_is_interlaced(struct ipu_csi *csi)
3195 - unsigned long flags;
3196 - u32 sensor_protocol;
3198 - spin_lock_irqsave(&csi->lock, flags);
3200 - (ipu_csi_read(csi, CSI_SENS_CONF) &
3201 - CSI_SENS_CONF_SENS_PRTCL_MASK) >>
3202 - CSI_SENS_CONF_SENS_PRTCL_SHIFT;
3203 - spin_unlock_irqrestore(&csi->lock, flags);
3205 - switch (sensor_protocol) {
3206 - case IPU_CSI_CLK_MODE_GATED_CLK:
3207 - case IPU_CSI_CLK_MODE_NONGATED_CLK:
3208 - case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
3209 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
3210 - case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
3212 - case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
3213 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
3214 - case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
3217 - dev_err(csi->ipu->dev,
3218 - "CSI %d sensor protocol unsupported\n", csi->id);
3222 -EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
3224 -void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
3226 - unsigned long flags;
3229 - spin_lock_irqsave(&csi->lock, flags);
3231 - reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
3232 - w->width = (reg & 0xFFFF) + 1;
3233 - w->height = (reg >> 16 & 0xFFFF) + 1;
3235 - reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
3236 - w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
3237 - w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
3239 - spin_unlock_irqrestore(&csi->lock, flags);
3241 -EXPORT_SYMBOL_GPL(ipu_csi_get_window);
3243 -void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
3245 - unsigned long flags;
3248 - spin_lock_irqsave(&csi->lock, flags);
3250 - ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
3251 - CSI_ACT_FRM_SIZE);
3253 - reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
3254 - reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
3255 - reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
3256 - ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
3258 - spin_unlock_irqrestore(&csi->lock, flags);
3260 -EXPORT_SYMBOL_GPL(ipu_csi_set_window);
3262 -void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
3264 - unsigned long flags;
3267 - spin_lock_irqsave(&csi->lock, flags);
3269 - reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
3270 - reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
3271 - reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
3272 - (vert ? CSI_VERT_DOWNSIZE_EN : 0);
3273 - ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
3275 - spin_unlock_irqrestore(&csi->lock, flags);
3277 -EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
3279 -void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
3280 - u32 r_value, u32 g_value, u32 b_value,
3283 - unsigned long flags;
3284 - u32 ipu_clk = clk_get_rate(csi->clk_ipu);
3287 - spin_lock_irqsave(&csi->lock, flags);
3289 - temp = ipu_csi_read(csi, CSI_TST_CTRL);
3292 - temp &= ~CSI_TEST_GEN_MODE_EN;
3293 - ipu_csi_write(csi, temp, CSI_TST_CTRL);
3295 - /* Set sensb_mclk div_ratio */
3296 - ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
3298 - temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
3299 - CSI_TEST_GEN_B_MASK);
3300 - temp |= CSI_TEST_GEN_MODE_EN;
3301 - temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
3302 - (g_value << CSI_TEST_GEN_G_SHIFT) |
3303 - (b_value << CSI_TEST_GEN_B_SHIFT);
3304 - ipu_csi_write(csi, temp, CSI_TST_CTRL);
3307 - spin_unlock_irqrestore(&csi->lock, flags);
3309 -EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
3311 -int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
3312 - struct v4l2_mbus_framefmt *mbus_fmt)
3314 - struct ipu_csi_bus_config cfg;
3315 - unsigned long flags;
3322 - ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
3326 - spin_lock_irqsave(&csi->lock, flags);
3328 - temp = ipu_csi_read(csi, CSI_MIPI_DI);
3329 - temp &= ~(0xff << (vc * 8));
3330 - temp |= (cfg.mipi_dt << (vc * 8));
3331 - ipu_csi_write(csi, temp, CSI_MIPI_DI);
3333 - spin_unlock_irqrestore(&csi->lock, flags);
3337 -EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
3339 -int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
3340 - u32 max_ratio, u32 id)
3342 - unsigned long flags;
3345 - if (max_ratio > 5 || id > 3)
3348 - spin_lock_irqsave(&csi->lock, flags);
3350 - temp = ipu_csi_read(csi, CSI_SKIP);
3351 - temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
3352 - CSI_SKIP_SMFC_MASK);
3353 - temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
3354 - (id << CSI_ID_2_SKIP_SHIFT) |
3355 - (skip << CSI_SKIP_SMFC_SHIFT);
3356 - ipu_csi_write(csi, temp, CSI_SKIP);
3358 - spin_unlock_irqrestore(&csi->lock, flags);
3362 -EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
3364 -int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
3366 - unsigned long flags;
3367 - u32 csi_sens_conf, dest;
3369 - if (csi_dest == IPU_CSI_DEST_IDMAC)
3370 - dest = CSI_DATA_DEST_IDMAC;
3372 - dest = CSI_DATA_DEST_IC; /* IC or VDIC */
3374 - spin_lock_irqsave(&csi->lock, flags);
3376 - csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
3377 - csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
3378 - csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
3379 - ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
3381 - spin_unlock_irqrestore(&csi->lock, flags);
3385 -EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
3387 -int ipu_csi_enable(struct ipu_csi *csi)
3389 - ipu_module_enable(csi->ipu, csi->module);
3393 -EXPORT_SYMBOL_GPL(ipu_csi_enable);
3395 -int ipu_csi_disable(struct ipu_csi *csi)
3397 - ipu_module_disable(csi->ipu, csi->module);
3401 -EXPORT_SYMBOL_GPL(ipu_csi_disable);
3403 -struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
3405 - unsigned long flags;
3406 - struct ipu_csi *csi, *ret;
3409 - return ERR_PTR(-EINVAL);
3411 - csi = ipu->csi_priv[id];
3414 - spin_lock_irqsave(&csi->lock, flags);
3417 - ret = ERR_PTR(-EBUSY);
3421 - csi->inuse = true;
3423 - spin_unlock_irqrestore(&csi->lock, flags);
3426 -EXPORT_SYMBOL_GPL(ipu_csi_get);
3428 -void ipu_csi_put(struct ipu_csi *csi)
3430 - unsigned long flags;
3432 - spin_lock_irqsave(&csi->lock, flags);
3433 - csi->inuse = false;
3434 - spin_unlock_irqrestore(&csi->lock, flags);
3436 -EXPORT_SYMBOL_GPL(ipu_csi_put);
3438 -int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
3439 - unsigned long base, u32 module, struct clk *clk_ipu)
3441 - struct ipu_csi *csi;
3446 - csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
3450 - ipu->csi_priv[id] = csi;
3452 - spin_lock_init(&csi->lock);
3453 - csi->module = module;
3455 - csi->clk_ipu = clk_ipu;
3456 - csi->base = devm_ioremap(dev, base, PAGE_SIZE);
3460 - dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
3461 - id, base, csi->base);
3467 -void ipu_csi_exit(struct ipu_soc *ipu, int id)
3471 -void ipu_csi_dump(struct ipu_csi *csi)
3473 - dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n",
3474 - ipu_csi_read(csi, CSI_SENS_CONF));
3475 - dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
3476 - ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
3477 - dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n",
3478 - ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
3479 - dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n",
3480 - ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
3481 - dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n",
3482 - ipu_csi_read(csi, CSI_TST_CTRL));
3483 - dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n",
3484 - ipu_csi_read(csi, CSI_CCIR_CODE_1));
3485 - dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n",
3486 - ipu_csi_read(csi, CSI_CCIR_CODE_2));
3487 - dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n",
3488 - ipu_csi_read(csi, CSI_CCIR_CODE_3));
3489 - dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n",
3490 - ipu_csi_read(csi, CSI_MIPI_DI));
3491 - dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n",
3492 - ipu_csi_read(csi, CSI_SKIP));
3494 -EXPORT_SYMBOL_GPL(ipu_csi_dump);
3495 --- a/drivers/gpu/imx/ipu-v3/ipu-dc.c
3498 -// SPDX-License-Identifier: GPL-2.0-or-later
3500 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
3501 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
3504 -#include <linux/export.h>
3505 -#include <linux/module.h>
3506 -#include <linux/types.h>
3507 -#include <linux/errno.h>
3508 -#include <linux/delay.h>
3509 -#include <linux/interrupt.h>
3510 -#include <linux/io.h>
3512 -#include <video/imx-ipu-v3.h>
3513 -#include "ipu-prv.h"
3515 -#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2)
3516 -#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2)
3518 -#define DC_EVT_NF 0
3519 -#define DC_EVT_NL 1
3520 -#define DC_EVT_EOF 2
3521 -#define DC_EVT_NFIELD 3
3522 -#define DC_EVT_EOL 4
3523 -#define DC_EVT_EOFIELD 5
3524 -#define DC_EVT_NEW_ADDR 6
3525 -#define DC_EVT_NEW_CHAN 7
3526 -#define DC_EVT_NEW_DATA 8
3528 -#define DC_EVT_NEW_ADDR_W_0 0
3529 -#define DC_EVT_NEW_ADDR_W_1 1
3530 -#define DC_EVT_NEW_CHAN_W_0 2
3531 -#define DC_EVT_NEW_CHAN_W_1 3
3532 -#define DC_EVT_NEW_DATA_W_0 4
3533 -#define DC_EVT_NEW_DATA_W_1 5
3534 -#define DC_EVT_NEW_ADDR_R_0 6
3535 -#define DC_EVT_NEW_ADDR_R_1 7
3536 -#define DC_EVT_NEW_CHAN_R_0 8
3537 -#define DC_EVT_NEW_CHAN_R_1 9
3538 -#define DC_EVT_NEW_DATA_R_0 10
3539 -#define DC_EVT_NEW_DATA_R_1 11
3541 -#define DC_WR_CH_CONF 0x0
3542 -#define DC_WR_CH_ADDR 0x4
3543 -#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2)
3545 -#define DC_GEN 0xd4
3546 -#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4)
3547 -#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4)
3548 -#define DC_STAT 0x1c8
3550 -#define WROD(lf) (0x18 | ((lf) << 1))
3554 -#define SYNC_WAVE 0
3555 -#define NULL_WAVE (-1)
3557 -#define DC_GEN_SYNC_1_6_SYNC (2 << 1)
3558 -#define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
3560 -#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0)
3561 -#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0)
3562 -#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0)
3563 -#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0)
3564 -#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3)
3565 -#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3)
3566 -#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4)
3567 -#define DC_WR_CH_CONF_FIELD_MODE (1 << 9)
3568 -#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5)
3569 -#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5)
3570 -#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2)
3571 -#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3)
3573 -#define IPU_DC_NUM_CHANNELS 10
3575 -struct ipu_dc_priv;
3579 - IPU_DC_MAP_RGB565,
3580 - IPU_DC_MAP_GBR24, /* TVEv2 */
3581 - IPU_DC_MAP_BGR666,
3582 - IPU_DC_MAP_LVDS666,
3587 - /* The display interface number assigned to this dc channel */
3589 - void __iomem *base;
3590 - struct ipu_dc_priv *priv;
3595 -struct ipu_dc_priv {
3596 - void __iomem *dc_reg;
3597 - void __iomem *dc_tmpl_reg;
3598 - struct ipu_soc *ipu;
3599 - struct device *dev;
3600 - struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
3601 - struct mutex mutex;
3602 - struct completion comp;
3606 -static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
3610 - reg = readl(dc->base + DC_RL_CH(event));
3611 - reg &= ~(0xffff << (16 * (event & 0x1)));
3612 - reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
3613 - writel(reg, dc->base + DC_RL_CH(event));
3616 -static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
3617 - int map, int wave, int glue, int sync, int stop)
3619 - struct ipu_dc_priv *priv = dc->priv;
3622 - if (opcode == WCLK) {
3623 - reg1 = (operand << 20) & 0xfff00000;
3624 - reg2 = operand >> 12 | opcode << 1 | stop << 9;
3625 - } else if (opcode == WRG) {
3626 - reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
3627 - reg2 = operand >> 17 | opcode << 7 | stop << 9;
3629 - reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
3630 - reg2 = operand >> 12 | opcode << 4 | stop << 9;
3632 - writel(reg1, priv->dc_tmpl_reg + word * 8);
3633 - writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
3636 -static int ipu_bus_format_to_map(u32 fmt)
3641 - /* fall-through */
3642 - case MEDIA_BUS_FMT_RGB888_1X24:
3643 - return IPU_DC_MAP_RGB24;
3644 - case MEDIA_BUS_FMT_RGB565_1X16:
3645 - return IPU_DC_MAP_RGB565;
3646 - case MEDIA_BUS_FMT_GBR888_1X24:
3647 - return IPU_DC_MAP_GBR24;
3648 - case MEDIA_BUS_FMT_RGB666_1X18:
3649 - return IPU_DC_MAP_BGR666;
3650 - case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
3651 - return IPU_DC_MAP_LVDS666;
3652 - case MEDIA_BUS_FMT_BGR888_1X24:
3653 - return IPU_DC_MAP_BGR24;
3657 -int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
3658 - u32 bus_format, u32 width)
3660 - struct ipu_dc_priv *priv = dc->priv;
3665 - dc->di = ipu_di_get_num(di);
3667 - map = ipu_bus_format_to_map(bus_format);
3670 - * In interlaced mode we need more counters to create the asymmetric
3671 - * per-field VSYNC signals. The pixel active signal synchronising DC
3672 - * to DI moves to signal generator #6 (see ipu-di.c). In progressive
3673 - * mode counter #5 is used.
3675 - sync = interlaced ? 6 : 5;
3677 - /* Reserve 5 microcode template words for each DI */
3684 - dc_link_event(dc, DC_EVT_NL, addr, 3);
3685 - dc_link_event(dc, DC_EVT_EOL, addr, 2);
3686 - dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
3688 - /* Init template microcode */
3689 - dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
3691 - dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
3692 - dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
3693 - dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
3695 - /* Init template microcode */
3696 - dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
3697 - dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
3698 - dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
3699 - dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
3702 - dc_link_event(dc, DC_EVT_NF, 0, 0);
3703 - dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
3704 - dc_link_event(dc, DC_EVT_EOF, 0, 0);
3705 - dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
3706 - dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
3707 - dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
3709 - reg = readl(dc->base + DC_WR_CH_CONF);
3711 - reg |= DC_WR_CH_CONF_FIELD_MODE;
3713 - reg &= ~DC_WR_CH_CONF_FIELD_MODE;
3714 - writel(reg, dc->base + DC_WR_CH_CONF);
3716 - writel(0x0, dc->base + DC_WR_CH_ADDR);
3717 - writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
3721 -EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
3723 -void ipu_dc_enable(struct ipu_soc *ipu)
3725 - struct ipu_dc_priv *priv = ipu->dc_priv;
3727 - mutex_lock(&priv->mutex);
3729 - if (!priv->use_count)
3730 - ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
3732 - priv->use_count++;
3734 - mutex_unlock(&priv->mutex);
3736 -EXPORT_SYMBOL_GPL(ipu_dc_enable);
3738 -void ipu_dc_enable_channel(struct ipu_dc *dc)
3742 - reg = readl(dc->base + DC_WR_CH_CONF);
3743 - reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
3744 - writel(reg, dc->base + DC_WR_CH_CONF);
3746 -EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
3748 -void ipu_dc_disable_channel(struct ipu_dc *dc)
3752 - val = readl(dc->base + DC_WR_CH_CONF);
3753 - val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
3754 - writel(val, dc->base + DC_WR_CH_CONF);
3756 -EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
3758 -void ipu_dc_disable(struct ipu_soc *ipu)
3760 - struct ipu_dc_priv *priv = ipu->dc_priv;
3762 - mutex_lock(&priv->mutex);
3764 - priv->use_count--;
3765 - if (!priv->use_count)
3766 - ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
3768 - if (priv->use_count < 0)
3769 - priv->use_count = 0;
3771 - mutex_unlock(&priv->mutex);
3773 -EXPORT_SYMBOL_GPL(ipu_dc_disable);
3775 -static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
3776 - int byte_num, int offset, int mask)
3778 - int ptr = map * 3 + byte_num;
3781 - reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
3782 - reg &= ~(0xffff << (16 * (ptr & 0x1)));
3783 - reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
3784 - writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
3786 - reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
3787 - reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
3788 - reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
3789 - writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
3792 -static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
3794 - u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
3796 - writel(reg & ~(0xffff << (16 * (map & 0x1))),
3797 - priv->dc_reg + DC_MAP_CONF_PTR(map));
3800 -struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
3802 - struct ipu_dc_priv *priv = ipu->dc_priv;
3803 - struct ipu_dc *dc;
3805 - if (channel >= IPU_DC_NUM_CHANNELS)
3806 - return ERR_PTR(-ENODEV);
3808 - dc = &priv->channels[channel];
3810 - mutex_lock(&priv->mutex);
3813 - mutex_unlock(&priv->mutex);
3814 - return ERR_PTR(-EBUSY);
3817 - dc->in_use = true;
3819 - mutex_unlock(&priv->mutex);
3823 -EXPORT_SYMBOL_GPL(ipu_dc_get);
3825 -void ipu_dc_put(struct ipu_dc *dc)
3827 - struct ipu_dc_priv *priv = dc->priv;
3829 - mutex_lock(&priv->mutex);
3830 - dc->in_use = false;
3831 - mutex_unlock(&priv->mutex);
3833 -EXPORT_SYMBOL_GPL(ipu_dc_put);
3835 -int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
3836 - unsigned long base, unsigned long template_base)
3838 - struct ipu_dc_priv *priv;
3839 - static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
3840 - 0x78, 0, 0x94, 0xb4};
3843 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3847 - mutex_init(&priv->mutex);
3851 - priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
3852 - priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
3853 - if (!priv->dc_reg || !priv->dc_tmpl_reg)
3856 - for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
3857 - priv->channels[i].chno = i;
3858 - priv->channels[i].priv = priv;
3859 - priv->channels[i].base = priv->dc_reg + channel_offsets[i];
3862 - writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
3863 - DC_WR_CH_CONF_PROG_DI_ID,
3864 - priv->channels[1].base + DC_WR_CH_CONF);
3865 - writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
3866 - priv->channels[5].base + DC_WR_CH_CONF);
3868 - writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
3869 - priv->dc_reg + DC_GEN);
3871 - ipu->dc_priv = priv;
3873 - dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
3874 - base, template_base);
3877 - ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
3878 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
3879 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
3880 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
3883 - ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
3884 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
3885 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
3886 - ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
3889 - ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
3890 - ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
3891 - ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
3892 - ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
3895 - ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
3896 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
3897 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
3898 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
3901 - ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
3902 - ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
3903 - ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
3904 - ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
3907 - ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
3908 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
3909 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
3910 - ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
3915 -void ipu_dc_exit(struct ipu_soc *ipu)
3918 --- a/drivers/gpu/imx/ipu-v3/ipu-di.c
3921 -// SPDX-License-Identifier: GPL-2.0-or-later
3923 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
3924 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
3926 -#include <linux/export.h>
3927 -#include <linux/module.h>
3928 -#include <linux/types.h>
3929 -#include <linux/errno.h>
3930 -#include <linux/io.h>
3931 -#include <linux/err.h>
3932 -#include <linux/platform_device.h>
3934 -#include <video/imx-ipu-v3.h>
3935 -#include "ipu-prv.h"
3938 - void __iomem *base;
3941 - struct clk *clk_di; /* display input clock */
3942 - struct clk *clk_ipu; /* IPU bus clock */
3943 - struct clk *clk_di_pixel; /* resulting pixel clock */
3945 - struct ipu_soc *ipu;
3948 -static DEFINE_MUTEX(di_mutex);
3950 -struct di_sync_config {
3957 - int cnt_polarity_gen_en;
3958 - int cnt_polarity_clr_src;
3959 - int cnt_polarity_trigger_src;
3974 - DI_PIN_SER_CLK = 0,
3975 - DI_PIN_SER_RS = 1,
3978 -enum di_sync_wave {
3981 - DI_SYNC_INT_HSYNC = 2,
3982 - DI_SYNC_HSYNC = 3,
3983 - DI_SYNC_VSYNC = 4,
3986 - DI_SYNC_CNT1 = 2, /* counter >= 2 only */
3987 - DI_SYNC_CNT4 = 5, /* counter >= 5 only */
3988 - DI_SYNC_CNT5 = 6, /* counter >= 6 only */
3991 -#define SYNC_WAVE 0
3993 -#define DI_GENERAL 0x0000
3994 -#define DI_BS_CLKGEN0 0x0004
3995 -#define DI_BS_CLKGEN1 0x0008
3996 -#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
3997 -#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
3998 -#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
3999 -#define DI_SYNC_AS_GEN 0x0054
4000 -#define DI_DW_GEN(gen) (0x0058 + 4 * (gen))
4001 -#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set)))
4002 -#define DI_SER_CONF 0x015c
4003 -#define DI_SSC 0x0160
4004 -#define DI_POL 0x0164
4005 -#define DI_AW0 0x0168
4006 -#define DI_AW1 0x016c
4007 -#define DI_SCR_CONF 0x0170
4008 -#define DI_STAT 0x0174
4010 -#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19)
4011 -#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16)
4012 -#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3)
4013 -#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0)
4015 -#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29)
4016 -#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25)
4017 -#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12)
4018 -#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9)
4019 -#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16)
4020 -#define DI_SW_GEN1_CNT_UP(x) (x)
4021 -#define DI_SW_GEN1_AUTO_RELOAD (0x10000000)
4023 -#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24
4024 -#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16
4026 -#define DI_GEN_POLARITY_1 (1 << 0)
4027 -#define DI_GEN_POLARITY_2 (1 << 1)
4028 -#define DI_GEN_POLARITY_3 (1 << 2)
4029 -#define DI_GEN_POLARITY_4 (1 << 3)
4030 -#define DI_GEN_POLARITY_5 (1 << 4)
4031 -#define DI_GEN_POLARITY_6 (1 << 5)
4032 -#define DI_GEN_POLARITY_7 (1 << 6)
4033 -#define DI_GEN_POLARITY_8 (1 << 7)
4034 -#define DI_GEN_POLARITY_DISP_CLK (1 << 17)
4035 -#define DI_GEN_DI_CLK_EXT (1 << 20)
4036 -#define DI_GEN_DI_VSYNC_EXT (1 << 21)
4038 -#define DI_POL_DRDY_DATA_POLARITY (1 << 7)
4039 -#define DI_POL_DRDY_POLARITY_15 (1 << 4)
4041 -#define DI_VSYNC_SEL_OFFSET 13
4043 -static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
4045 - return readl(di->base + offset);
4048 -static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
4050 - writel(value, di->base + offset);
4053 -static void ipu_di_data_wave_config(struct ipu_di *di,
4055 - int access_size, int component_size)
4058 - reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
4059 - (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
4060 - ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
4063 -static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
4064 - int set, int up, int down)
4068 - reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
4069 - reg &= ~(0x3 << (di_pin * 2));
4070 - reg |= set << (di_pin * 2);
4071 - ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
4073 - ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
4076 -static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
4077 - int start, int count)
4082 - for (i = 0; i < count; i++) {
4083 - struct di_sync_config *c = &config[i];
4084 - int wave_gen = start + i + 1;
4086 - if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
4087 - (c->repeat_count >= 0x1000) ||
4088 - (c->cnt_up >= 0x400) ||
4089 - (c->cnt_down >= 0x400)) {
4090 - dev_err(di->ipu->dev, "DI%d counters out of range.\n",
4095 - reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
4096 - DI_SW_GEN0_RUN_SRC(c->run_src) |
4097 - DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
4098 - DI_SW_GEN0_OFFSET_SRC(c->offset_src);
4099 - ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
4101 - reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
4102 - DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
4103 - DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
4104 - c->cnt_polarity_trigger_src) |
4105 - DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
4106 - DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
4107 - DI_SW_GEN1_CNT_UP(c->cnt_up);
4109 - /* Enable auto reload */
4110 - if (c->repeat_count == 0)
4111 - reg |= DI_SW_GEN1_AUTO_RELOAD;
4113 - ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
4115 - reg = ipu_di_read(di, DI_STP_REP(wave_gen));
4116 - reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
4117 - reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
4118 - ipu_di_write(di, reg, DI_STP_REP(wave_gen));
4122 -static void ipu_di_sync_config_interlaced(struct ipu_di *di,
4123 - struct ipu_di_signal_cfg *sig)
4125 - u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
4126 - sig->mode.hback_porch + sig->mode.hfront_porch;
4127 - u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
4128 - sig->mode.vback_porch + sig->mode.vfront_porch;
4129 - struct di_sync_config cfg[] = {
4131 - /* 1: internal VSYNC for each frame */
4132 - .run_count = v_total * 2 - 1,
4133 - .run_src = 3, /* == counter 7 */
4135 - /* PIN2: HSYNC waveform */
4136 - .run_count = h_total - 1,
4137 - .run_src = DI_SYNC_CLK,
4138 - .cnt_polarity_gen_en = 1,
4139 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
4140 - .cnt_down = sig->mode.hsync_len * 2,
4142 - /* PIN3: VSYNC waveform */
4143 - .run_count = v_total - 1,
4144 - .run_src = 4, /* == counter 7 */
4145 - .cnt_polarity_gen_en = 1,
4146 - .cnt_polarity_trigger_src = 4, /* == counter 7 */
4147 - .cnt_down = sig->mode.vsync_len * 2,
4148 - .cnt_clr_src = DI_SYNC_CNT1,
4151 - .run_count = v_total / 2,
4152 - .run_src = DI_SYNC_HSYNC,
4153 - .offset_count = h_total / 2,
4154 - .offset_src = DI_SYNC_CLK,
4155 - .repeat_count = 2,
4156 - .cnt_clr_src = DI_SYNC_CNT1,
4158 - /* 5: Active lines */
4159 - .run_src = DI_SYNC_HSYNC,
4160 - .offset_count = (sig->mode.vsync_len +
4161 - sig->mode.vback_porch) / 2,
4162 - .offset_src = DI_SYNC_HSYNC,
4163 - .repeat_count = sig->mode.vactive / 2,
4164 - .cnt_clr_src = DI_SYNC_CNT4,
4166 - /* 6: Active pixel, referenced by DC */
4167 - .run_src = DI_SYNC_CLK,
4168 - .offset_count = sig->mode.hsync_len +
4169 - sig->mode.hback_porch,
4170 - .offset_src = DI_SYNC_CLK,
4171 - .repeat_count = sig->mode.hactive,
4172 - .cnt_clr_src = DI_SYNC_CNT5,
4174 - /* 7: Half line HSYNC */
4175 - .run_count = h_total / 2 - 1,
4176 - .run_src = DI_SYNC_CLK,
4180 - ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
4182 - ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
4185 -static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
4186 - struct ipu_di_signal_cfg *sig, int div)
4188 - u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
4189 - sig->mode.hback_porch + sig->mode.hfront_porch;
4190 - u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
4191 - sig->mode.vback_porch + sig->mode.vfront_porch;
4192 - struct di_sync_config cfg[] = {
4194 - /* 1: INT_HSYNC */
4195 - .run_count = h_total - 1,
4196 - .run_src = DI_SYNC_CLK,
4199 - .run_count = h_total - 1,
4200 - .run_src = DI_SYNC_CLK,
4201 - .offset_count = div * sig->v_to_h_sync,
4202 - .offset_src = DI_SYNC_CLK,
4203 - .cnt_polarity_gen_en = 1,
4204 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
4205 - .cnt_down = sig->mode.hsync_len * 2,
4208 - .run_count = v_total - 1,
4209 - .run_src = DI_SYNC_INT_HSYNC,
4210 - .cnt_polarity_gen_en = 1,
4211 - .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
4212 - .cnt_down = sig->mode.vsync_len * 2,
4214 - /* 4: Line Active */
4215 - .run_src = DI_SYNC_HSYNC,
4216 - .offset_count = sig->mode.vsync_len +
4217 - sig->mode.vback_porch,
4218 - .offset_src = DI_SYNC_HSYNC,
4219 - .repeat_count = sig->mode.vactive,
4220 - .cnt_clr_src = DI_SYNC_VSYNC,
4222 - /* 5: Pixel Active, referenced by DC */
4223 - .run_src = DI_SYNC_CLK,
4224 - .offset_count = sig->mode.hsync_len +
4225 - sig->mode.hback_porch,
4226 - .offset_src = DI_SYNC_CLK,
4227 - .repeat_count = sig->mode.hactive,
4228 - .cnt_clr_src = 5, /* Line Active */
4239 - /* can't use #7 and #8 for line active and pixel active counters */
4240 - struct di_sync_config cfg_vga[] = {
4242 - /* 1: INT_HSYNC */
4243 - .run_count = h_total - 1,
4244 - .run_src = DI_SYNC_CLK,
4247 - .run_count = v_total - 1,
4248 - .run_src = DI_SYNC_INT_HSYNC,
4250 - /* 3: Line Active */
4251 - .run_src = DI_SYNC_INT_HSYNC,
4252 - .offset_count = sig->mode.vsync_len +
4253 - sig->mode.vback_porch,
4254 - .offset_src = DI_SYNC_INT_HSYNC,
4255 - .repeat_count = sig->mode.vactive,
4256 - .cnt_clr_src = 3 /* VSYNC */,
4258 - /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
4259 - .run_count = h_total - 1,
4260 - .run_src = DI_SYNC_CLK,
4261 - .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
4262 - .offset_src = DI_SYNC_CLK,
4263 - .cnt_polarity_gen_en = 1,
4264 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
4265 - .cnt_down = sig->mode.hsync_len * 2,
4267 - /* 5: Pixel Active signal to DC */
4268 - .run_src = DI_SYNC_CLK,
4269 - .offset_count = sig->mode.hsync_len +
4270 - sig->mode.hback_porch,
4271 - .offset_src = DI_SYNC_CLK,
4272 - .repeat_count = sig->mode.hactive,
4273 - .cnt_clr_src = 4, /* Line Active */
4275 - /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
4276 - .run_count = v_total - 1,
4277 - .run_src = DI_SYNC_INT_HSYNC,
4278 - .offset_count = 1, /* magic value from Freescale TVE driver */
4279 - .offset_src = DI_SYNC_INT_HSYNC,
4280 - .cnt_polarity_gen_en = 1,
4281 - .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
4282 - .cnt_down = sig->mode.vsync_len * 2,
4284 - /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
4285 - .run_count = h_total - 1,
4286 - .run_src = DI_SYNC_CLK,
4287 - .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
4288 - .offset_src = DI_SYNC_CLK,
4289 - .cnt_polarity_gen_en = 1,
4290 - .cnt_polarity_trigger_src = DI_SYNC_CLK,
4291 - .cnt_down = sig->mode.hsync_len * 2,
4293 - /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
4294 - .run_count = v_total - 1,
4295 - .run_src = DI_SYNC_INT_HSYNC,
4296 - .offset_count = 1, /* magic value from Freescale TVE driver */
4297 - .offset_src = DI_SYNC_INT_HSYNC,
4298 - .cnt_polarity_gen_en = 1,
4299 - .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
4300 - .cnt_down = sig->mode.vsync_len * 2,
4306 - ipu_di_write(di, v_total - 1, DI_SCR_CONF);
4307 - if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
4308 - ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
4310 - ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
4313 -static void ipu_di_config_clock(struct ipu_di *di,
4314 - const struct ipu_di_signal_cfg *sig)
4320 - if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
4322 - * CLKMODE_EXT means we must use the DI clock: this is
4323 - * needed for things like LVDS which needs to feed the
4324 - * DI and LDB with the same pixel clock.
4328 - if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
4330 - * CLKMODE_SYNC means that we want the DI to be
4331 - * clocked at the same rate as the parent clock.
4332 - * This is needed (eg) for LDB which needs to be
4333 - * fed with the same pixel clock. We assume that
4334 - * the LDB clock has already been set correctly.
4339 - * We can use the divider. We should really have
4340 - * a flag here indicating whether the bridge can
4341 - * cope with a fractional divider or not. For the
4342 - * time being, let's go for simplicitly and
4345 - unsigned long in_rate;
4348 - clk_set_rate(clk, sig->mode.pixelclock);
4350 - in_rate = clk_get_rate(clk);
4351 - div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
4352 - div = clamp(div, 1U, 255U);
4354 - clkgen0 = div << 4;
4358 - * For other interfaces, we can arbitarily select between
4359 - * the DI specific clock and the internal IPU clock. See
4360 - * DI_GENERAL bit 20. We select the IPU clock if it can
4361 - * give us a clock rate within 1% of the requested frequency,
4362 - * otherwise we use the DI clock.
4364 - unsigned long rate, clkrate;
4365 - unsigned div, error;
4367 - clkrate = clk_get_rate(di->clk_ipu);
4368 - div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
4369 - div = clamp(div, 1U, 255U);
4370 - rate = clkrate / div;
4372 - error = rate / (sig->mode.pixelclock / 1000);
4374 - dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
4375 - rate, div, (signed)(error - 1000) / 10, error % 10);
4377 - /* Allow a 1% error */
4378 - if (error < 1010 && error >= 990) {
4379 - clk = di->clk_ipu;
4381 - clkgen0 = div << 4;
4383 - unsigned long in_rate;
4388 - clk_set_rate(clk, sig->mode.pixelclock);
4390 - in_rate = clk_get_rate(clk);
4391 - div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
4392 - div = clamp(div, 1U, 255U);
4394 - clkgen0 = div << 4;
4398 - di->clk_di_pixel = clk;
4400 - /* Set the divider */
4401 - ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
4404 - * Set the high/low periods. Bits 24:16 give us the falling edge,
4405 - * and bits 8:0 give the rising edge. LSB is fraction, and is
4406 - * based on the divider above. We want a 50% duty cycle, so set
4407 - * the falling edge to be half the divider.
4409 - ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
4411 - /* Finally select the input clock */
4412 - val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
4413 - if (clk == di->clk_di)
4414 - val |= DI_GEN_DI_CLK_EXT;
4415 - ipu_di_write(di, val, DI_GENERAL);
4417 - dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
4418 - sig->mode.pixelclock,
4419 - clk_get_rate(di->clk_ipu),
4420 - clk_get_rate(di->clk_di),
4421 - clk == di->clk_di ? "DI" : "IPU",
4422 - clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
4426 - * This function is called to adjust a video mode to IPU restrictions.
4427 - * It is meant to be called from drm crtc mode_fixup() methods.
4429 -int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
4433 - if (mode->vfront_porch >= 2)
4436 - diff = 2 - mode->vfront_porch;
4438 - if (mode->vback_porch >= diff) {
4439 - mode->vfront_porch = 2;
4440 - mode->vback_porch -= diff;
4441 - } else if (mode->vsync_len > diff) {
4442 - mode->vfront_porch = 2;
4443 - mode->vsync_len = mode->vsync_len - diff;
4445 - dev_warn(di->ipu->dev, "failed to adjust videomode\n");
4449 - dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
4452 -EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
4454 -static u32 ipu_di_gen_polarity(int pin)
4458 - return DI_GEN_POLARITY_1;
4460 - return DI_GEN_POLARITY_2;
4462 - return DI_GEN_POLARITY_3;
4464 - return DI_GEN_POLARITY_4;
4466 - return DI_GEN_POLARITY_5;
4468 - return DI_GEN_POLARITY_6;
4470 - return DI_GEN_POLARITY_7;
4472 - return DI_GEN_POLARITY_8;
4477 -int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
4480 - u32 di_gen, vsync_cnt;
4483 - dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
4484 - di->id, sig->mode.hactive, sig->mode.vactive);
4486 - dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
4487 - clk_get_rate(di->clk_ipu),
4488 - clk_get_rate(di->clk_di),
4489 - sig->mode.pixelclock);
4491 - mutex_lock(&di_mutex);
4493 - ipu_di_config_clock(di, sig);
4495 - div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
4496 - div = div / 16; /* Now divider is integer portion */
4498 - /* Setup pixel clock timing */
4499 - /* Down time is half of period */
4500 - ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
4502 - ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
4503 - ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
4505 - di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
4506 - di_gen |= DI_GEN_DI_VSYNC_EXT;
4508 - if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
4509 - ipu_di_sync_config_interlaced(di, sig);
4511 - /* set y_sel = 1 */
4512 - di_gen |= 0x10000000;
4516 - ipu_di_sync_config_noninterlaced(di, sig, div);
4521 - * TODO: change only for TVEv2, parallel display
4524 - if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
4528 - if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
4529 - di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
4530 - if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
4531 - di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
4534 - di_gen |= DI_GEN_POLARITY_DISP_CLK;
4536 - ipu_di_write(di, di_gen, DI_GENERAL);
4538 - ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
4541 - reg = ipu_di_read(di, DI_POL);
4542 - reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
4544 - if (sig->enable_pol)
4545 - reg |= DI_POL_DRDY_POLARITY_15;
4546 - if (sig->data_pol)
4547 - reg |= DI_POL_DRDY_DATA_POLARITY;
4549 - ipu_di_write(di, reg, DI_POL);
4551 - mutex_unlock(&di_mutex);
4555 -EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
4557 -int ipu_di_enable(struct ipu_di *di)
4561 - WARN_ON(IS_ERR(di->clk_di_pixel));
4563 - ret = clk_prepare_enable(di->clk_di_pixel);
4567 - ipu_module_enable(di->ipu, di->module);
4571 -EXPORT_SYMBOL_GPL(ipu_di_enable);
4573 -int ipu_di_disable(struct ipu_di *di)
4575 - WARN_ON(IS_ERR(di->clk_di_pixel));
4577 - ipu_module_disable(di->ipu, di->module);
4579 - clk_disable_unprepare(di->clk_di_pixel);
4583 -EXPORT_SYMBOL_GPL(ipu_di_disable);
4585 -int ipu_di_get_num(struct ipu_di *di)
4589 -EXPORT_SYMBOL_GPL(ipu_di_get_num);
4591 -static DEFINE_MUTEX(ipu_di_lock);
4593 -struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
4595 - struct ipu_di *di;
4598 - return ERR_PTR(-EINVAL);
4600 - di = ipu->di_priv[disp];
4602 - mutex_lock(&ipu_di_lock);
4605 - di = ERR_PTR(-EBUSY);
4611 - mutex_unlock(&ipu_di_lock);
4615 -EXPORT_SYMBOL_GPL(ipu_di_get);
4617 -void ipu_di_put(struct ipu_di *di)
4619 - mutex_lock(&ipu_di_lock);
4621 - di->inuse = false;
4623 - mutex_unlock(&ipu_di_lock);
4625 -EXPORT_SYMBOL_GPL(ipu_di_put);
4627 -int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
4628 - unsigned long base,
4629 - u32 module, struct clk *clk_ipu)
4631 - struct ipu_di *di;
4636 - di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
4640 - ipu->di_priv[id] = di;
4642 - di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
4643 - if (IS_ERR(di->clk_di))
4644 - return PTR_ERR(di->clk_di);
4646 - di->module = module;
4648 - di->clk_ipu = clk_ipu;
4649 - di->base = devm_ioremap(dev, base, PAGE_SIZE);
4653 - ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
4655 - dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
4656 - id, base, di->base);
4657 - di->inuse = false;
4663 -void ipu_di_exit(struct ipu_soc *ipu, int id)
4666 --- a/drivers/gpu/imx/ipu-v3/ipu-dmfc.c
4669 -// SPDX-License-Identifier: GPL-2.0-or-later
4671 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
4672 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
4674 -#include <linux/export.h>
4675 -#include <linux/types.h>
4676 -#include <linux/errno.h>
4677 -#include <linux/io.h>
4679 -#include <video/imx-ipu-v3.h>
4680 -#include "ipu-prv.h"
4682 -#define DMFC_RD_CHAN 0x0000
4683 -#define DMFC_WR_CHAN 0x0004
4684 -#define DMFC_WR_CHAN_DEF 0x0008
4685 -#define DMFC_DP_CHAN 0x000c
4686 -#define DMFC_DP_CHAN_DEF 0x0010
4687 -#define DMFC_GENERAL1 0x0014
4688 -#define DMFC_GENERAL2 0x0018
4689 -#define DMFC_IC_CTRL 0x001c
4690 -#define DMFC_WR_CHAN_ALT 0x0020
4691 -#define DMFC_WR_CHAN_DEF_ALT 0x0024
4692 -#define DMFC_DP_CHAN_ALT 0x0028
4693 -#define DMFC_DP_CHAN_DEF_ALT 0x002c
4694 -#define DMFC_GENERAL1_ALT 0x0030
4695 -#define DMFC_STAT 0x0034
4697 -#define DMFC_WR_CHAN_1_28 0
4698 -#define DMFC_WR_CHAN_2_41 8
4699 -#define DMFC_WR_CHAN_1C_42 16
4700 -#define DMFC_WR_CHAN_2C_43 24
4702 -#define DMFC_DP_CHAN_5B_23 0
4703 -#define DMFC_DP_CHAN_5F_27 8
4704 -#define DMFC_DP_CHAN_6B_24 16
4705 -#define DMFC_DP_CHAN_6F_29 24
4707 -struct dmfc_channel_data {
4709 - unsigned long channel_reg;
4710 - unsigned long shift;
4711 - unsigned eot_shift;
4712 - unsigned max_fifo_lines;
4715 -static const struct dmfc_channel_data dmfcdata[] = {
4717 - .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
4718 - .channel_reg = DMFC_DP_CHAN,
4719 - .shift = DMFC_DP_CHAN_5B_23,
4721 - .max_fifo_lines = 3,
4723 - .ipu_channel = 24,
4724 - .channel_reg = DMFC_DP_CHAN,
4725 - .shift = DMFC_DP_CHAN_6B_24,
4727 - .max_fifo_lines = 1,
4729 - .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
4730 - .channel_reg = DMFC_DP_CHAN,
4731 - .shift = DMFC_DP_CHAN_5F_27,
4733 - .max_fifo_lines = 2,
4735 - .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
4736 - .channel_reg = DMFC_WR_CHAN,
4737 - .shift = DMFC_WR_CHAN_1_28,
4739 - .max_fifo_lines = 2,
4741 - .ipu_channel = 29,
4742 - .channel_reg = DMFC_DP_CHAN,
4743 - .shift = DMFC_DP_CHAN_6F_29,
4745 - .max_fifo_lines = 1,
4749 -#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
4751 -struct ipu_dmfc_priv;
4753 -struct dmfc_channel {
4755 - struct ipu_soc *ipu;
4756 - struct ipu_dmfc_priv *priv;
4757 - const struct dmfc_channel_data *data;
4760 -struct ipu_dmfc_priv {
4761 - struct ipu_soc *ipu;
4762 - struct device *dev;
4763 - struct dmfc_channel channels[DMFC_NUM_CHANNELS];
4764 - struct mutex mutex;
4765 - void __iomem *base;
4769 -int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
4771 - struct ipu_dmfc_priv *priv = dmfc->priv;
4772 - mutex_lock(&priv->mutex);
4774 - if (!priv->use_count)
4775 - ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
4777 - priv->use_count++;
4779 - mutex_unlock(&priv->mutex);
4783 -EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
4785 -void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
4787 - struct ipu_dmfc_priv *priv = dmfc->priv;
4789 - mutex_lock(&priv->mutex);
4791 - priv->use_count--;
4793 - if (!priv->use_count)
4794 - ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
4796 - if (priv->use_count < 0)
4797 - priv->use_count = 0;
4799 - mutex_unlock(&priv->mutex);
4801 -EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
4803 -void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
4805 - struct ipu_dmfc_priv *priv = dmfc->priv;
4808 - mutex_lock(&priv->mutex);
4810 - dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
4812 - if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
4813 - dmfc_gen1 |= 1 << dmfc->data->eot_shift;
4815 - dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
4817 - writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
4819 - mutex_unlock(&priv->mutex);
4821 -EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
4823 -struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
4825 - struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
4828 - for (i = 0; i < DMFC_NUM_CHANNELS; i++)
4829 - if (dmfcdata[i].ipu_channel == ipu_channel)
4830 - return &priv->channels[i];
4831 - return ERR_PTR(-ENODEV);
4833 -EXPORT_SYMBOL_GPL(ipu_dmfc_get);
4835 -void ipu_dmfc_put(struct dmfc_channel *dmfc)
4838 -EXPORT_SYMBOL_GPL(ipu_dmfc_put);
4840 -int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
4841 - struct clk *ipu_clk)
4843 - struct ipu_dmfc_priv *priv;
4846 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4850 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
4856 - mutex_init(&priv->mutex);
4858 - ipu->dmfc_priv = priv;
4860 - for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
4861 - priv->channels[i].priv = priv;
4862 - priv->channels[i].ipu = ipu;
4863 - priv->channels[i].data = &dmfcdata[i];
4865 - if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
4866 - dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
4867 - dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
4868 - priv->channels[i].slots = 2;
4871 - writel(0x00000050, priv->base + DMFC_WR_CHAN);
4872 - writel(0x00005654, priv->base + DMFC_DP_CHAN);
4873 - writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
4874 - writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
4875 - writel(0x00000003, priv->base + DMFC_GENERAL1);
4880 -void ipu_dmfc_exit(struct ipu_soc *ipu)
4883 --- a/drivers/gpu/imx/ipu-v3/ipu-dp.c
4886 -// SPDX-License-Identifier: GPL-2.0-or-later
4888 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
4889 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
4891 -#include <linux/export.h>
4892 -#include <linux/kernel.h>
4893 -#include <linux/types.h>
4894 -#include <linux/errno.h>
4895 -#include <linux/io.h>
4896 -#include <linux/err.h>
4898 -#include <video/imx-ipu-v3.h>
4899 -#include "ipu-prv.h"
4902 -#define DP_ASYNC0 0x60
4903 -#define DP_ASYNC1 0xBC
4905 -#define DP_COM_CONF 0x0
4906 -#define DP_GRAPH_WIND_CTRL 0x0004
4907 -#define DP_FG_POS 0x0008
4908 -#define DP_CSC_A_0 0x0044
4909 -#define DP_CSC_A_1 0x0048
4910 -#define DP_CSC_A_2 0x004C
4911 -#define DP_CSC_A_3 0x0050
4912 -#define DP_CSC_0 0x0054
4913 -#define DP_CSC_1 0x0058
4915 -#define DP_COM_CONF_FG_EN (1 << 0)
4916 -#define DP_COM_CONF_GWSEL (1 << 1)
4917 -#define DP_COM_CONF_GWAM (1 << 2)
4918 -#define DP_COM_CONF_GWCKE (1 << 3)
4919 -#define DP_COM_CONF_CSC_DEF_MASK (3 << 8)
4920 -#define DP_COM_CONF_CSC_DEF_OFFSET 8
4921 -#define DP_COM_CONF_CSC_DEF_FG (3 << 8)
4922 -#define DP_COM_CONF_CSC_DEF_BG (2 << 8)
4923 -#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8)
4925 -#define IPUV3_NUM_FLOWS 3
4927 -struct ipu_dp_priv;
4933 - enum ipu_color_space in_cs;
4937 - struct ipu_dp foreground;
4938 - struct ipu_dp background;
4939 - enum ipu_color_space out_cs;
4940 - void __iomem *base;
4941 - struct ipu_dp_priv *priv;
4944 -struct ipu_dp_priv {
4945 - struct ipu_soc *ipu;
4946 - struct device *dev;
4947 - void __iomem *base;
4948 - struct ipu_flow flow[IPUV3_NUM_FLOWS];
4949 - struct mutex mutex;
4953 -static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
4955 -static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
4957 - if (dp->foreground)
4958 - return container_of(dp, struct ipu_flow, foreground);
4960 - return container_of(dp, struct ipu_flow, background);
4963 -int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
4964 - u8 alpha, bool bg_chan)
4966 - struct ipu_flow *flow = to_flow(dp);
4967 - struct ipu_dp_priv *priv = flow->priv;
4970 - mutex_lock(&priv->mutex);
4972 - reg = readl(flow->base + DP_COM_CONF);
4974 - reg &= ~DP_COM_CONF_GWSEL;
4976 - reg |= DP_COM_CONF_GWSEL;
4977 - writel(reg, flow->base + DP_COM_CONF);
4980 - reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
4981 - writel(reg | ((u32) alpha << 24),
4982 - flow->base + DP_GRAPH_WIND_CTRL);
4984 - reg = readl(flow->base + DP_COM_CONF);
4985 - writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
4987 - reg = readl(flow->base + DP_COM_CONF);
4988 - writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
4991 - ipu_srm_dp_update(priv->ipu, true);
4993 - mutex_unlock(&priv->mutex);
4997 -EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
4999 -int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
5001 - struct ipu_flow *flow = to_flow(dp);
5002 - struct ipu_dp_priv *priv = flow->priv;
5004 - writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
5006 - ipu_srm_dp_update(priv->ipu, true);
5010 -EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
5012 -static void ipu_dp_csc_init(struct ipu_flow *flow,
5013 - enum ipu_color_space in,
5014 - enum ipu_color_space out,
5019 - reg = readl(flow->base + DP_COM_CONF);
5020 - reg &= ~DP_COM_CONF_CSC_DEF_MASK;
5023 - writel(reg, flow->base + DP_COM_CONF);
5027 - if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
5028 - writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
5029 - writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
5030 - writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
5031 - writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
5032 - writel(0x3d6 | (0x0000 << 16) | (2 << 30),
5033 - flow->base + DP_CSC_0);
5034 - writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
5035 - flow->base + DP_CSC_1);
5037 - writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
5038 - writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
5039 - writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
5040 - writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
5041 - writel(0x000 | (0x3e42 << 16) | (1 << 30),
5042 - flow->base + DP_CSC_0);
5043 - writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
5044 - flow->base + DP_CSC_1);
5049 - writel(reg, flow->base + DP_COM_CONF);
5052 -int ipu_dp_setup_channel(struct ipu_dp *dp,
5053 - enum ipu_color_space in,
5054 - enum ipu_color_space out)
5056 - struct ipu_flow *flow = to_flow(dp);
5057 - struct ipu_dp_priv *priv = flow->priv;
5059 - mutex_lock(&priv->mutex);
5063 - if (!dp->foreground)
5064 - flow->out_cs = out;
5066 - if (flow->foreground.in_cs == flow->background.in_cs) {
5068 - * foreground and background are of same colorspace, put
5069 - * colorspace converter after combining unit.
5071 - ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
5072 - DP_COM_CONF_CSC_DEF_BOTH);
5074 - if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
5075 - flow->foreground.in_cs == flow->out_cs)
5077 - * foreground identical to output, apply color
5078 - * conversion on background
5080 - ipu_dp_csc_init(flow, flow->background.in_cs,
5081 - flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
5083 - ipu_dp_csc_init(flow, flow->foreground.in_cs,
5084 - flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
5087 - ipu_srm_dp_update(priv->ipu, true);
5089 - mutex_unlock(&priv->mutex);
5093 -EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
5095 -int ipu_dp_enable(struct ipu_soc *ipu)
5097 - struct ipu_dp_priv *priv = ipu->dp_priv;
5099 - mutex_lock(&priv->mutex);
5101 - if (!priv->use_count)
5102 - ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
5104 - priv->use_count++;
5106 - mutex_unlock(&priv->mutex);
5110 -EXPORT_SYMBOL_GPL(ipu_dp_enable);
5112 -int ipu_dp_enable_channel(struct ipu_dp *dp)
5114 - struct ipu_flow *flow = to_flow(dp);
5115 - struct ipu_dp_priv *priv = flow->priv;
5118 - if (!dp->foreground)
5121 - mutex_lock(&priv->mutex);
5123 - reg = readl(flow->base + DP_COM_CONF);
5124 - reg |= DP_COM_CONF_FG_EN;
5125 - writel(reg, flow->base + DP_COM_CONF);
5127 - ipu_srm_dp_update(priv->ipu, true);
5129 - mutex_unlock(&priv->mutex);
5133 -EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
5135 -void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
5137 - struct ipu_flow *flow = to_flow(dp);
5138 - struct ipu_dp_priv *priv = flow->priv;
5141 - dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
5143 - if (!dp->foreground)
5146 - mutex_lock(&priv->mutex);
5148 - reg = readl(flow->base + DP_COM_CONF);
5149 - csc = reg & DP_COM_CONF_CSC_DEF_MASK;
5150 - reg &= ~DP_COM_CONF_CSC_DEF_MASK;
5151 - if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
5152 - reg |= DP_COM_CONF_CSC_DEF_BG;
5154 - reg &= ~DP_COM_CONF_FG_EN;
5155 - writel(reg, flow->base + DP_COM_CONF);
5157 - writel(0, flow->base + DP_FG_POS);
5158 - ipu_srm_dp_update(priv->ipu, sync);
5160 - mutex_unlock(&priv->mutex);
5162 -EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
5164 -void ipu_dp_disable(struct ipu_soc *ipu)
5166 - struct ipu_dp_priv *priv = ipu->dp_priv;
5168 - mutex_lock(&priv->mutex);
5170 - priv->use_count--;
5172 - if (!priv->use_count)
5173 - ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
5175 - if (priv->use_count < 0)
5176 - priv->use_count = 0;
5178 - mutex_unlock(&priv->mutex);
5180 -EXPORT_SYMBOL_GPL(ipu_dp_disable);
5182 -struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
5184 - struct ipu_dp_priv *priv = ipu->dp_priv;
5185 - struct ipu_dp *dp;
5187 - if ((flow >> 1) >= IPUV3_NUM_FLOWS)
5188 - return ERR_PTR(-EINVAL);
5191 - dp = &priv->flow[flow >> 1].foreground;
5193 - dp = &priv->flow[flow >> 1].background;
5196 - return ERR_PTR(-EBUSY);
5198 - dp->in_use = true;
5202 -EXPORT_SYMBOL_GPL(ipu_dp_get);
5204 -void ipu_dp_put(struct ipu_dp *dp)
5206 - dp->in_use = false;
5208 -EXPORT_SYMBOL_GPL(ipu_dp_put);
5210 -int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
5212 - struct ipu_dp_priv *priv;
5215 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5221 - ipu->dp_priv = priv;
5223 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
5227 - mutex_init(&priv->mutex);
5229 - for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
5230 - priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
5231 - priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
5232 - priv->flow[i].foreground.foreground = true;
5233 - priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
5234 - priv->flow[i].priv = priv;
5240 -void ipu_dp_exit(struct ipu_soc *ipu)
5243 --- a/drivers/gpu/imx/ipu-v3/ipu-ic.c
5246 -// SPDX-License-Identifier: GPL-2.0-or-later
5248 - * Copyright (C) 2012-2014 Mentor Graphics Inc.
5249 - * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
5252 -#include <linux/types.h>
5253 -#include <linux/init.h>
5254 -#include <linux/errno.h>
5255 -#include <linux/spinlock.h>
5256 -#include <linux/bitrev.h>
5257 -#include <linux/io.h>
5258 -#include <linux/err.h>
5259 -#include <linux/sizes.h>
5260 -#include "ipu-prv.h"
5262 -/* IC Register Offsets */
5263 -#define IC_CONF 0x0000
5264 -#define IC_PRP_ENC_RSC 0x0004
5265 -#define IC_PRP_VF_RSC 0x0008
5266 -#define IC_PP_RSC 0x000C
5267 -#define IC_CMBP_1 0x0010
5268 -#define IC_CMBP_2 0x0014
5269 -#define IC_IDMAC_1 0x0018
5270 -#define IC_IDMAC_2 0x001C
5271 -#define IC_IDMAC_3 0x0020
5272 -#define IC_IDMAC_4 0x0024
5274 -/* IC Register Fields */
5275 -#define IC_CONF_PRPENC_EN (1 << 0)
5276 -#define IC_CONF_PRPENC_CSC1 (1 << 1)
5277 -#define IC_CONF_PRPENC_ROT_EN (1 << 2)
5278 -#define IC_CONF_PRPVF_EN (1 << 8)
5279 -#define IC_CONF_PRPVF_CSC1 (1 << 9)
5280 -#define IC_CONF_PRPVF_CSC2 (1 << 10)
5281 -#define IC_CONF_PRPVF_CMB (1 << 11)
5282 -#define IC_CONF_PRPVF_ROT_EN (1 << 12)
5283 -#define IC_CONF_PP_EN (1 << 16)
5284 -#define IC_CONF_PP_CSC1 (1 << 17)
5285 -#define IC_CONF_PP_CSC2 (1 << 18)
5286 -#define IC_CONF_PP_CMB (1 << 19)
5287 -#define IC_CONF_PP_ROT_EN (1 << 20)
5288 -#define IC_CONF_IC_GLB_LOC_A (1 << 28)
5289 -#define IC_CONF_KEY_COLOR_EN (1 << 29)
5290 -#define IC_CONF_RWS_EN (1 << 30)
5291 -#define IC_CONF_CSI_MEM_WR_EN (1 << 31)
5293 -#define IC_IDMAC_1_CB0_BURST_16 (1 << 0)
5294 -#define IC_IDMAC_1_CB1_BURST_16 (1 << 1)
5295 -#define IC_IDMAC_1_CB2_BURST_16 (1 << 2)
5296 -#define IC_IDMAC_1_CB3_BURST_16 (1 << 3)
5297 -#define IC_IDMAC_1_CB4_BURST_16 (1 << 4)
5298 -#define IC_IDMAC_1_CB5_BURST_16 (1 << 5)
5299 -#define IC_IDMAC_1_CB6_BURST_16 (1 << 6)
5300 -#define IC_IDMAC_1_CB7_BURST_16 (1 << 7)
5301 -#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11)
5302 -#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11
5303 -#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14)
5304 -#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14
5305 -#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17)
5306 -#define IC_IDMAC_1_PP_ROT_OFFSET 17
5307 -#define IC_IDMAC_1_PP_FLIP_RS (1 << 22)
5308 -#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21)
5309 -#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20)
5311 -#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0)
5312 -#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
5313 -#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10)
5314 -#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10
5315 -#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20)
5316 -#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20
5318 -#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0)
5319 -#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0
5320 -#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10)
5321 -#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10
5322 -#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20)
5323 -#define IC_IDMAC_3_PP_WIDTH_OFFSET 20
5325 -struct ic_task_regoffs {
5330 -struct ic_task_bitfields {
5332 - u32 ic_conf_rot_en;
5333 - u32 ic_conf_cmb_en;
5334 - u32 ic_conf_csc1_en;
5335 - u32 ic_conf_csc2_en;
5336 - u32 ic_cmb_galpha_bit;
5339 -static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
5340 - [IC_TASK_ENCODER] = {
5341 - .rsc = IC_PRP_ENC_RSC,
5342 - .tpmem_csc = {0x2008, 0},
5344 - [IC_TASK_VIEWFINDER] = {
5345 - .rsc = IC_PRP_VF_RSC,
5346 - .tpmem_csc = {0x4028, 0x4040},
5348 - [IC_TASK_POST_PROCESSOR] = {
5350 - .tpmem_csc = {0x6060, 0x6078},
5354 -static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
5355 - [IC_TASK_ENCODER] = {
5356 - .ic_conf_en = IC_CONF_PRPENC_EN,
5357 - .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
5358 - .ic_conf_cmb_en = 0, /* NA */
5359 - .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
5360 - .ic_conf_csc2_en = 0, /* NA */
5361 - .ic_cmb_galpha_bit = 0, /* NA */
5363 - [IC_TASK_VIEWFINDER] = {
5364 - .ic_conf_en = IC_CONF_PRPVF_EN,
5365 - .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
5366 - .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
5367 - .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
5368 - .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
5369 - .ic_cmb_galpha_bit = 0,
5371 - [IC_TASK_POST_PROCESSOR] = {
5372 - .ic_conf_en = IC_CONF_PP_EN,
5373 - .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
5374 - .ic_conf_cmb_en = IC_CONF_PP_CMB,
5375 - .ic_conf_csc1_en = IC_CONF_PP_CSC1,
5376 - .ic_conf_csc2_en = IC_CONF_PP_CSC2,
5377 - .ic_cmb_galpha_bit = 8,
5381 -struct ipu_ic_priv;
5384 - enum ipu_ic_task task;
5385 - const struct ic_task_regoffs *reg;
5386 - const struct ic_task_bitfields *bit;
5388 - struct ipu_ic_colorspace in_cs;
5389 - struct ipu_ic_colorspace g_in_cs;
5390 - struct ipu_ic_colorspace out_cs;
5396 - struct ipu_ic_priv *priv;
5399 -struct ipu_ic_priv {
5400 - void __iomem *base;
5401 - void __iomem *tpmem_base;
5403 - struct ipu_soc *ipu;
5405 - int irt_use_count;
5406 - struct ipu_ic task[IC_NUM_TASKS];
5409 -static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
5411 - return readl(ic->priv->base + offset);
5414 -static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
5416 - writel(value, ic->priv->base + offset);
5419 -static int init_csc(struct ipu_ic *ic,
5420 - const struct ipu_ic_csc *csc,
5423 - struct ipu_ic_priv *priv = ic->priv;
5424 - u32 __iomem *base;
5425 - const u16 (*c)[3];
5429 - base = (u32 __iomem *)
5430 - (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
5432 - /* Cast to unsigned */
5433 - c = (const u16 (*)[3])csc->params.coeff;
5434 - a = (const u16 *)csc->params.offset;
5436 - param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
5437 - ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
5438 - writel(param, base++);
5440 - param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
5441 - (csc->params.sat << 10);
5442 - writel(param, base++);
5444 - param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
5445 - ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
5446 - writel(param, base++);
5448 - param = ((a[1] & 0x1fe0) >> 5);
5449 - writel(param, base++);
5451 - param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
5452 - ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
5453 - writel(param, base++);
5455 - param = ((a[2] & 0x1fe0) >> 5);
5456 - writel(param, base++);
5461 -static int calc_resize_coeffs(struct ipu_ic *ic,
5462 - u32 in_size, u32 out_size,
5463 - u32 *resize_coeff,
5464 - u32 *downsize_coeff)
5466 - struct ipu_ic_priv *priv = ic->priv;
5467 - struct ipu_soc *ipu = priv->ipu;
5468 - u32 temp_size, temp_downsize;
5471 - * Input size cannot be more than 4096, and output size cannot
5472 - * be more than 1024
5474 - if (in_size > 4096) {
5475 - dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
5478 - if (out_size > 1024) {
5479 - dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
5483 - /* Cannot downsize more than 4:1 */
5484 - if ((out_size << 2) < in_size) {
5485 - dev_err(ipu->dev, "Unsupported downsize\n");
5489 - /* Compute downsizing coefficient */
5490 - temp_downsize = 0;
5491 - temp_size = in_size;
5492 - while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
5493 - (temp_downsize < 2)) {
5497 - *downsize_coeff = temp_downsize;
5500 - * compute resizing coefficient using the following equation:
5501 - * resize_coeff = M * (SI - 1) / (SO - 1)
5502 - * where M = 2^13, SI = input size, SO = output size
5504 - *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
5505 - if (*resize_coeff >= 16384L) {
5506 - dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
5507 - *resize_coeff = 0x3FFF;
5513 -void ipu_ic_task_enable(struct ipu_ic *ic)
5515 - struct ipu_ic_priv *priv = ic->priv;
5516 - unsigned long flags;
5519 - spin_lock_irqsave(&priv->lock, flags);
5521 - ic_conf = ipu_ic_read(ic, IC_CONF);
5523 - ic_conf |= ic->bit->ic_conf_en;
5526 - ic_conf |= ic->bit->ic_conf_rot_en;
5528 - if (ic->in_cs.cs != ic->out_cs.cs)
5529 - ic_conf |= ic->bit->ic_conf_csc1_en;
5531 - if (ic->graphics) {
5532 - ic_conf |= ic->bit->ic_conf_cmb_en;
5533 - ic_conf |= ic->bit->ic_conf_csc1_en;
5535 - if (ic->g_in_cs.cs != ic->out_cs.cs)
5536 - ic_conf |= ic->bit->ic_conf_csc2_en;
5539 - ipu_ic_write(ic, ic_conf, IC_CONF);
5541 - spin_unlock_irqrestore(&priv->lock, flags);
5543 -EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
5545 -void ipu_ic_task_disable(struct ipu_ic *ic)
5547 - struct ipu_ic_priv *priv = ic->priv;
5548 - unsigned long flags;
5551 - spin_lock_irqsave(&priv->lock, flags);
5553 - ic_conf = ipu_ic_read(ic, IC_CONF);
5555 - ic_conf &= ~(ic->bit->ic_conf_en |
5556 - ic->bit->ic_conf_csc1_en |
5557 - ic->bit->ic_conf_rot_en);
5558 - if (ic->bit->ic_conf_csc2_en)
5559 - ic_conf &= ~ic->bit->ic_conf_csc2_en;
5560 - if (ic->bit->ic_conf_cmb_en)
5561 - ic_conf &= ~ic->bit->ic_conf_cmb_en;
5563 - ipu_ic_write(ic, ic_conf, IC_CONF);
5565 - spin_unlock_irqrestore(&priv->lock, flags);
5567 -EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
5569 -int ipu_ic_task_graphics_init(struct ipu_ic *ic,
5570 - const struct ipu_ic_colorspace *g_in_cs,
5571 - bool galpha_en, u32 galpha,
5572 - bool colorkey_en, u32 colorkey)
5574 - struct ipu_ic_priv *priv = ic->priv;
5575 - struct ipu_ic_csc csc2;
5576 - unsigned long flags;
5580 - if (ic->task == IC_TASK_ENCODER)
5583 - spin_lock_irqsave(&priv->lock, flags);
5585 - ic_conf = ipu_ic_read(ic, IC_CONF);
5587 - if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
5588 - struct ipu_ic_csc csc1;
5590 - ret = ipu_ic_calc_csc(&csc1,
5591 - V4L2_YCBCR_ENC_601,
5592 - V4L2_QUANTIZATION_FULL_RANGE,
5593 - IPUV3_COLORSPACE_RGB,
5594 - V4L2_YCBCR_ENC_601,
5595 - V4L2_QUANTIZATION_FULL_RANGE,
5596 - IPUV3_COLORSPACE_RGB);
5600 - /* need transparent CSC1 conversion */
5601 - ret = init_csc(ic, &csc1, 0);
5606 - ic->g_in_cs = *g_in_cs;
5607 - csc2.in_cs = ic->g_in_cs;
5608 - csc2.out_cs = ic->out_cs;
5610 - ret = __ipu_ic_calc_csc(&csc2);
5614 - ret = init_csc(ic, &csc2, 1);
5619 - ic_conf |= IC_CONF_IC_GLB_LOC_A;
5620 - reg = ipu_ic_read(ic, IC_CMBP_1);
5621 - reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
5622 - reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
5623 - ipu_ic_write(ic, reg, IC_CMBP_1);
5625 - ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
5627 - if (colorkey_en) {
5628 - ic_conf |= IC_CONF_KEY_COLOR_EN;
5629 - ipu_ic_write(ic, colorkey, IC_CMBP_2);
5631 - ic_conf &= ~IC_CONF_KEY_COLOR_EN;
5633 - ipu_ic_write(ic, ic_conf, IC_CONF);
5635 - ic->graphics = true;
5637 - spin_unlock_irqrestore(&priv->lock, flags);
5640 -EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
5642 -int ipu_ic_task_init_rsc(struct ipu_ic *ic,
5643 - const struct ipu_ic_csc *csc,
5644 - int in_width, int in_height,
5645 - int out_width, int out_height,
5648 - struct ipu_ic_priv *priv = ic->priv;
5649 - u32 downsize_coeff, resize_coeff;
5650 - unsigned long flags;
5654 - /* Setup vertical resizing */
5656 - ret = calc_resize_coeffs(ic, in_height, out_height,
5657 - &resize_coeff, &downsize_coeff);
5661 - rsc = (downsize_coeff << 30) | (resize_coeff << 16);
5663 - /* Setup horizontal resizing */
5664 - ret = calc_resize_coeffs(ic, in_width, out_width,
5665 - &resize_coeff, &downsize_coeff);
5669 - rsc |= (downsize_coeff << 14) | resize_coeff;
5672 - spin_lock_irqsave(&priv->lock, flags);
5674 - ipu_ic_write(ic, rsc, ic->reg->rsc);
5676 - /* Setup color space conversion */
5677 - ic->in_cs = csc->in_cs;
5678 - ic->out_cs = csc->out_cs;
5680 - ret = init_csc(ic, csc, 0);
5682 - spin_unlock_irqrestore(&priv->lock, flags);
5686 -int ipu_ic_task_init(struct ipu_ic *ic,
5687 - const struct ipu_ic_csc *csc,
5688 - int in_width, int in_height,
5689 - int out_width, int out_height)
5691 - return ipu_ic_task_init_rsc(ic, csc,
5692 - in_width, in_height,
5693 - out_width, out_height, 0);
5695 -EXPORT_SYMBOL_GPL(ipu_ic_task_init);
5697 -int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
5698 - u32 width, u32 height, int burst_size,
5699 - enum ipu_rotate_mode rot)
5701 - struct ipu_ic_priv *priv = ic->priv;
5702 - struct ipu_soc *ipu = priv->ipu;
5703 - u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
5704 - u32 temp_rot = bitrev8(rot) >> 5;
5705 - bool need_hor_flip = false;
5706 - unsigned long flags;
5709 - if ((burst_size != 8) && (burst_size != 16)) {
5710 - dev_err(ipu->dev, "Illegal burst length for IC\n");
5717 - if (temp_rot & 0x2) /* Need horizontal flip */
5718 - need_hor_flip = true;
5720 - spin_lock_irqsave(&priv->lock, flags);
5722 - ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
5723 - ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
5724 - ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
5726 - switch (channel->num) {
5727 - case IPUV3_CHANNEL_IC_PP_MEM:
5728 - if (burst_size == 16)
5729 - ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
5731 - ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
5733 - if (need_hor_flip)
5734 - ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
5736 - ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
5738 - ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
5739 - ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
5741 - ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
5742 - ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
5744 - case IPUV3_CHANNEL_MEM_IC_PP:
5745 - if (burst_size == 16)
5746 - ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
5748 - ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
5750 - case IPUV3_CHANNEL_MEM_ROT_PP:
5751 - ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
5752 - ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
5754 - case IPUV3_CHANNEL_MEM_IC_PRP_VF:
5755 - if (burst_size == 16)
5756 - ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
5758 - ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
5760 - case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
5761 - if (burst_size == 16)
5762 - ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
5764 - ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
5766 - if (need_hor_flip)
5767 - ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
5769 - ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
5771 - ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
5772 - ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
5774 - ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
5775 - ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
5777 - case IPUV3_CHANNEL_MEM_ROT_ENC:
5778 - ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
5779 - ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
5781 - case IPUV3_CHANNEL_IC_PRP_VF_MEM:
5782 - if (burst_size == 16)
5783 - ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
5785 - ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
5787 - if (need_hor_flip)
5788 - ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
5790 - ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
5792 - ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
5793 - ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
5795 - ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
5796 - ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
5798 - case IPUV3_CHANNEL_MEM_ROT_VF:
5799 - ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
5800 - ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
5802 - case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
5803 - if (burst_size == 16)
5804 - ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
5806 - ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
5808 - case IPUV3_CHANNEL_G_MEM_IC_PP:
5809 - if (burst_size == 16)
5810 - ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
5812 - ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
5814 - case IPUV3_CHANNEL_VDI_MEM_IC_VF:
5815 - if (burst_size == 16)
5816 - ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
5818 - ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
5824 - ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
5825 - ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
5826 - ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
5828 - if (ipu_rot_mode_is_irt(rot))
5829 - ic->rotation = true;
5832 - spin_unlock_irqrestore(&priv->lock, flags);
5835 -EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
5837 -static void ipu_irt_enable(struct ipu_ic *ic)
5839 - struct ipu_ic_priv *priv = ic->priv;
5841 - if (!priv->irt_use_count)
5842 - ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
5844 - priv->irt_use_count++;
5847 -static void ipu_irt_disable(struct ipu_ic *ic)
5849 - struct ipu_ic_priv *priv = ic->priv;
5851 - if (priv->irt_use_count) {
5852 - if (!--priv->irt_use_count)
5853 - ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
5857 -int ipu_ic_enable(struct ipu_ic *ic)
5859 - struct ipu_ic_priv *priv = ic->priv;
5860 - unsigned long flags;
5862 - spin_lock_irqsave(&priv->lock, flags);
5864 - if (!priv->use_count)
5865 - ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
5867 - priv->use_count++;
5870 - ipu_irt_enable(ic);
5872 - spin_unlock_irqrestore(&priv->lock, flags);
5876 -EXPORT_SYMBOL_GPL(ipu_ic_enable);
5878 -int ipu_ic_disable(struct ipu_ic *ic)
5880 - struct ipu_ic_priv *priv = ic->priv;
5881 - unsigned long flags;
5883 - spin_lock_irqsave(&priv->lock, flags);
5885 - priv->use_count--;
5887 - if (!priv->use_count)
5888 - ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
5890 - if (priv->use_count < 0)
5891 - priv->use_count = 0;
5894 - ipu_irt_disable(ic);
5896 - ic->rotation = ic->graphics = false;
5898 - spin_unlock_irqrestore(&priv->lock, flags);
5902 -EXPORT_SYMBOL_GPL(ipu_ic_disable);
5904 -struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
5906 - struct ipu_ic_priv *priv = ipu->ic_priv;
5907 - unsigned long flags;
5908 - struct ipu_ic *ic, *ret;
5910 - if (task >= IC_NUM_TASKS)
5911 - return ERR_PTR(-EINVAL);
5913 - ic = &priv->task[task];
5915 - spin_lock_irqsave(&priv->lock, flags);
5918 - ret = ERR_PTR(-EBUSY);
5922 - ic->in_use = true;
5926 - spin_unlock_irqrestore(&priv->lock, flags);
5929 -EXPORT_SYMBOL_GPL(ipu_ic_get);
5931 -void ipu_ic_put(struct ipu_ic *ic)
5933 - struct ipu_ic_priv *priv = ic->priv;
5934 - unsigned long flags;
5936 - spin_lock_irqsave(&priv->lock, flags);
5937 - ic->in_use = false;
5938 - spin_unlock_irqrestore(&priv->lock, flags);
5940 -EXPORT_SYMBOL_GPL(ipu_ic_put);
5942 -int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
5943 - unsigned long base, unsigned long tpmem_base)
5945 - struct ipu_ic_priv *priv;
5948 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5952 - ipu->ic_priv = priv;
5954 - spin_lock_init(&priv->lock);
5955 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
5958 - priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
5959 - if (!priv->tpmem_base)
5962 - dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
5966 - for (i = 0; i < IC_NUM_TASKS; i++) {
5967 - priv->task[i].task = i;
5968 - priv->task[i].priv = priv;
5969 - priv->task[i].reg = &ic_task_reg[i];
5970 - priv->task[i].bit = &ic_task_bit[i];
5976 -void ipu_ic_exit(struct ipu_soc *ipu)
5980 -void ipu_ic_dump(struct ipu_ic *ic)
5982 - struct ipu_ic_priv *priv = ic->priv;
5983 - struct ipu_soc *ipu = priv->ipu;
5985 - dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
5986 - ipu_ic_read(ic, IC_CONF));
5987 - dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
5988 - ipu_ic_read(ic, IC_PRP_ENC_RSC));
5989 - dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
5990 - ipu_ic_read(ic, IC_PRP_VF_RSC));
5991 - dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
5992 - ipu_ic_read(ic, IC_PP_RSC));
5993 - dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
5994 - ipu_ic_read(ic, IC_CMBP_1));
5995 - dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
5996 - ipu_ic_read(ic, IC_CMBP_2));
5997 - dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
5998 - ipu_ic_read(ic, IC_IDMAC_1));
5999 - dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
6000 - ipu_ic_read(ic, IC_IDMAC_2));
6001 - dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
6002 - ipu_ic_read(ic, IC_IDMAC_3));
6003 - dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
6004 - ipu_ic_read(ic, IC_IDMAC_4));
6006 -EXPORT_SYMBOL_GPL(ipu_ic_dump);
6007 --- a/drivers/gpu/imx/ipu-v3/ipu-image-convert.c
6010 -// SPDX-License-Identifier: GPL-2.0-or-later
6012 - * Copyright (C) 2012-2016 Mentor Graphics Inc.
6014 - * Queued image conversion support, with tiling and rotation.
6017 -#include <linux/interrupt.h>
6018 -#include <linux/dma-mapping.h>
6019 -#include <video/imx-ipu-image-convert.h>
6020 -#include "ipu-prv.h"
6023 - * The IC Resizer has a restriction that the output frame from the
6024 - * resizer must be 1024 or less in both width (pixels) and height
6027 - * The image converter attempts to split up a conversion when
6028 - * the desired output (converted) frame resolution exceeds the
6029 - * IC resizer limit of 1024 in either dimension.
6031 - * If either dimension of the output frame exceeds the limit, the
6032 - * dimension is split into 1, 2, or 4 equal stripes, for a maximum
6033 - * of 4*4 or 16 tiles. A conversion is then carried out for each
6034 - * tile (but taking care to pass the full frame stride length to
6035 - * the DMA channel's parameter memory!). IDMA double-buffering is used
6036 - * to convert each tile back-to-back when possible (see note below
6037 - * when double_buffering boolean is set).
6039 - * Note that the input frame must be split up into the same number
6040 - * of tiles as the output frame:
6042 - * +---------+-----+
6043 - * +-----+---+ | A | B |
6045 - * +-----+---+ --> +---------+-----+
6046 - * | C | D | | C | D |
6047 - * +-----+---+ | | |
6048 - * +---------+-----+
6050 - * Clockwise 90° rotations are handled by first rescaling into a
6051 - * reusable temporary tile buffer and then rotating with the 8x8
6052 - * block rotator, writing to the correct destination:
6056 - * +-----+---+ +---------+ | C | A |
6057 - * | A | B | | A,B, | | | | |
6058 - * +-----+---+ --> | C,D | | --> | | |
6059 - * | C | D | +---------+ +-----+-----+
6060 - * +-----+---+ | D | B |
6064 - * If the 8x8 block rotator is used, horizontal or vertical flipping
6065 - * is done during the rotation step, otherwise flipping is done
6066 - * during the scaling step.
6067 - * With rotation or flipping, tile order changes between input and
6068 - * output image. Tiles are numbered row major from top left to bottom
6069 - * right for both input and output image.
6072 -#define MAX_STRIPES_W 4
6073 -#define MAX_STRIPES_H 4
6074 -#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
6081 -enum ipu_image_convert_type {
6082 - IMAGE_CONVERT_IN = 0,
6083 - IMAGE_CONVERT_OUT,
6086 -struct ipu_image_convert_dma_buf {
6089 - unsigned long len;
6092 -struct ipu_image_convert_dma_chan {
6102 -/* dimensions of one tile */
6103 -struct ipu_image_tile {
6108 - /* size and strides are in bytes */
6112 - /* start Y or packed offset of this tile */
6114 - /* offset from start to tile in U plane, for planar formats */
6116 - /* offset from start to tile in V plane, for planar formats */
6120 -struct ipu_image_convert_image {
6121 - struct ipu_image base;
6122 - enum ipu_image_convert_type type;
6124 - const struct ipu_image_pixfmt *fmt;
6125 - unsigned int stride;
6127 - /* # of rows (horizontal stripes) if dest height is > 1024 */
6128 - unsigned int num_rows;
6129 - /* # of columns (vertical stripes) if dest width is > 1024 */
6130 - unsigned int num_cols;
6132 - struct ipu_image_tile tile[MAX_TILES];
6135 -struct ipu_image_pixfmt {
6136 - u32 fourcc; /* V4L2 fourcc */
6137 - int bpp; /* total bpp */
6138 - int uv_width_dec; /* decimation in width for U/V planes */
6139 - int uv_height_dec; /* decimation in height for U/V planes */
6140 - bool planar; /* planar format */
6141 - bool uv_swapped; /* U and V planes are swapped */
6142 - bool uv_packed; /* partial planar (U and V in same plane) */
6145 -struct ipu_image_convert_ctx;
6146 -struct ipu_image_convert_chan;
6147 -struct ipu_image_convert_priv;
6149 -struct ipu_image_convert_ctx {
6150 - struct ipu_image_convert_chan *chan;
6152 - ipu_image_convert_cb_t complete;
6153 - void *complete_context;
6155 - /* Source/destination image data and rotation mode */
6156 - struct ipu_image_convert_image in;
6157 - struct ipu_image_convert_image out;
6158 - struct ipu_ic_csc csc;
6159 - enum ipu_rotate_mode rot_mode;
6160 - u32 downsize_coeff_h;
6161 - u32 downsize_coeff_v;
6162 - u32 image_resize_coeff_h;
6163 - u32 image_resize_coeff_v;
6164 - u32 resize_coeffs_h[MAX_STRIPES_W];
6165 - u32 resize_coeffs_v[MAX_STRIPES_H];
6167 - /* intermediate buffer for rotation */
6168 - struct ipu_image_convert_dma_buf rot_intermediate[2];
6170 - /* current buffer number for double buffering */
6174 - struct completion aborted;
6176 - /* can we use double-buffering for this conversion operation? */
6177 - bool double_buffering;
6178 - /* num_rows * num_cols */
6179 - unsigned int num_tiles;
6180 - /* next tile to process */
6181 - unsigned int next_tile;
6182 - /* where to place converted tile in dest image */
6183 - unsigned int out_tile_map[MAX_TILES];
6185 - struct list_head list;
6188 -struct ipu_image_convert_chan {
6189 - struct ipu_image_convert_priv *priv;
6191 - enum ipu_ic_task ic_task;
6192 - const struct ipu_image_convert_dma_chan *dma_ch;
6194 - struct ipu_ic *ic;
6195 - struct ipuv3_channel *in_chan;
6196 - struct ipuv3_channel *out_chan;
6197 - struct ipuv3_channel *rotation_in_chan;
6198 - struct ipuv3_channel *rotation_out_chan;
6200 - /* the IPU end-of-frame irqs */
6202 - int rot_out_eof_irq;
6204 - spinlock_t irqlock;
6206 - /* list of convert contexts */
6207 - struct list_head ctx_list;
6208 - /* queue of conversion runs */
6209 - struct list_head pending_q;
6210 - /* queue of completed runs */
6211 - struct list_head done_q;
6213 - /* the current conversion run */
6214 - struct ipu_image_convert_run *current_run;
6217 -struct ipu_image_convert_priv {
6218 - struct ipu_image_convert_chan chan[IC_NUM_TASKS];
6219 - struct ipu_soc *ipu;
6222 -static const struct ipu_image_convert_dma_chan
6223 -image_convert_dma_chan[IC_NUM_TASKS] = {
6224 - [IC_TASK_VIEWFINDER] = {
6225 - .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
6226 - .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
6227 - .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
6228 - .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
6229 - .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
6230 - .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
6231 - .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
6233 - [IC_TASK_POST_PROCESSOR] = {
6234 - .in = IPUV3_CHANNEL_MEM_IC_PP,
6235 - .out = IPUV3_CHANNEL_IC_PP_MEM,
6236 - .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
6237 - .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
6241 -static const struct ipu_image_pixfmt image_convert_formats[] = {
6243 - .fourcc = V4L2_PIX_FMT_RGB565,
6246 - .fourcc = V4L2_PIX_FMT_RGB24,
6249 - .fourcc = V4L2_PIX_FMT_BGR24,
6252 - .fourcc = V4L2_PIX_FMT_RGB32,
6255 - .fourcc = V4L2_PIX_FMT_BGR32,
6258 - .fourcc = V4L2_PIX_FMT_XRGB32,
6261 - .fourcc = V4L2_PIX_FMT_XBGR32,
6264 - .fourcc = V4L2_PIX_FMT_BGRX32,
6267 - .fourcc = V4L2_PIX_FMT_RGBX32,
6270 - .fourcc = V4L2_PIX_FMT_YUYV,
6272 - .uv_width_dec = 2,
6273 - .uv_height_dec = 1,
6275 - .fourcc = V4L2_PIX_FMT_UYVY,
6277 - .uv_width_dec = 2,
6278 - .uv_height_dec = 1,
6280 - .fourcc = V4L2_PIX_FMT_YUV420,
6283 - .uv_width_dec = 2,
6284 - .uv_height_dec = 2,
6286 - .fourcc = V4L2_PIX_FMT_YVU420,
6289 - .uv_width_dec = 2,
6290 - .uv_height_dec = 2,
6291 - .uv_swapped = true,
6293 - .fourcc = V4L2_PIX_FMT_NV12,
6296 - .uv_width_dec = 2,
6297 - .uv_height_dec = 2,
6298 - .uv_packed = true,
6300 - .fourcc = V4L2_PIX_FMT_YUV422P,
6303 - .uv_width_dec = 2,
6304 - .uv_height_dec = 1,
6306 - .fourcc = V4L2_PIX_FMT_NV16,
6309 - .uv_width_dec = 2,
6310 - .uv_height_dec = 1,
6311 - .uv_packed = true,
6315 -static const struct ipu_image_pixfmt *get_format(u32 fourcc)
6317 - const struct ipu_image_pixfmt *ret = NULL;
6320 - for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
6321 - if (image_convert_formats[i].fourcc == fourcc) {
6322 - ret = &image_convert_formats[i];
6330 -static void dump_format(struct ipu_image_convert_ctx *ctx,
6331 - struct ipu_image_convert_image *ic_image)
6333 - struct ipu_image_convert_chan *chan = ctx->chan;
6334 - struct ipu_image_convert_priv *priv = chan->priv;
6336 - dev_dbg(priv->ipu->dev,
6337 - "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
6338 - chan->ic_task, ctx,
6339 - ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
6340 - ic_image->base.pix.width, ic_image->base.pix.height,
6341 - ic_image->num_cols, ic_image->num_rows,
6342 - ic_image->fmt->fourcc & 0xff,
6343 - (ic_image->fmt->fourcc >> 8) & 0xff,
6344 - (ic_image->fmt->fourcc >> 16) & 0xff,
6345 - (ic_image->fmt->fourcc >> 24) & 0xff);
6348 -int ipu_image_convert_enum_format(int index, u32 *fourcc)
6350 - const struct ipu_image_pixfmt *fmt;
6352 - if (index >= (int)ARRAY_SIZE(image_convert_formats))
6355 - /* Format found */
6356 - fmt = &image_convert_formats[index];
6357 - *fourcc = fmt->fourcc;
6360 -EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
6362 -static void free_dma_buf(struct ipu_image_convert_priv *priv,
6363 - struct ipu_image_convert_dma_buf *buf)
6366 - dma_free_coherent(priv->ipu->dev,
6367 - buf->len, buf->virt, buf->phys);
6372 -static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
6373 - struct ipu_image_convert_dma_buf *buf,
6376 - buf->len = PAGE_ALIGN(size);
6377 - buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
6378 - GFP_DMA | GFP_KERNEL);
6380 - dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
6387 -static inline int num_stripes(int dim)
6389 - return (dim - 1) / 1024 + 1;
6393 - * Calculate downsizing coefficients, which are the same for all tiles,
6394 - * and initial bilinear resizing coefficients, which are used to find the
6395 - * best seam positions.
6396 - * Also determine the number of tiles necessary to guarantee that no tile
6397 - * is larger than 1024 pixels in either dimension at the output and between
6398 - * IC downsizing and main processing sections.
6400 -static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
6401 - struct ipu_image *in,
6402 - struct ipu_image *out)
6404 - u32 downsized_width = in->rect.width;
6405 - u32 downsized_height = in->rect.height;
6406 - u32 downsize_coeff_v = 0;
6407 - u32 downsize_coeff_h = 0;
6408 - u32 resized_width = out->rect.width;
6409 - u32 resized_height = out->rect.height;
6410 - u32 resize_coeff_h;
6411 - u32 resize_coeff_v;
6415 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6416 - resized_width = out->rect.height;
6417 - resized_height = out->rect.width;
6420 - /* Do not let invalid input lead to an endless loop below */
6421 - if (WARN_ON(resized_width == 0 || resized_height == 0))
6424 - while (downsized_width >= resized_width * 2) {
6425 - downsized_width >>= 1;
6426 - downsize_coeff_h++;
6429 - while (downsized_height >= resized_height * 2) {
6430 - downsized_height >>= 1;
6431 - downsize_coeff_v++;
6435 - * Calculate the bilinear resizing coefficients that could be used if
6436 - * we were converting with a single tile. The bottom right output pixel
6437 - * should sample as close as possible to the bottom right input pixel
6438 - * out of the decimator, but not overshoot it:
6440 - resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
6441 - resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
6444 - * Both the output of the IC downsizing section before being passed to
6445 - * the IC main processing section and the final output of the IC main
6446 - * processing section must be <= 1024 pixels in both dimensions.
6448 - cols = num_stripes(max_t(u32, downsized_width, resized_width));
6449 - rows = num_stripes(max_t(u32, downsized_height, resized_height));
6451 - dev_dbg(ctx->chan->priv->ipu->dev,
6452 - "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
6453 - __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
6454 - resize_coeff_v, cols, rows);
6456 - if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
6457 - resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
6460 - ctx->downsize_coeff_h = downsize_coeff_h;
6461 - ctx->downsize_coeff_v = downsize_coeff_v;
6462 - ctx->image_resize_coeff_h = resize_coeff_h;
6463 - ctx->image_resize_coeff_v = resize_coeff_v;
6464 - ctx->in.num_cols = cols;
6465 - ctx->in.num_rows = rows;
6470 -#define round_closest(x, y) round_down((x) + (y)/2, (y))
6473 - * Find the best aligned seam position for the given column / row index.
6474 - * Rotation and image offsets are out of scope.
6476 - * @index: column / row index, used to calculate valid interval
6477 - * @in_edge: input right / bottom edge
6478 - * @out_edge: output right / bottom edge
6479 - * @in_align: input alignment, either horizontal 8-byte line start address
6480 - * alignment, or pixel alignment due to image format
6481 - * @out_align: output alignment, either horizontal 8-byte line start address
6482 - * alignment, or pixel alignment due to image format or rotator
6484 - * @in_burst: horizontal input burst size in case of horizontal flip
6485 - * @out_burst: horizontal output burst size or rotator block size
6486 - * @downsize_coeff: downsizing section coefficient
6487 - * @resize_coeff: main processing section resizing coefficient
6488 - * @_in_seam: aligned input seam position return value
6489 - * @_out_seam: aligned output seam position return value
6491 -static void find_best_seam(struct ipu_image_convert_ctx *ctx,
6492 - unsigned int index,
6493 - unsigned int in_edge,
6494 - unsigned int out_edge,
6495 - unsigned int in_align,
6496 - unsigned int out_align,
6497 - unsigned int in_burst,
6498 - unsigned int out_burst,
6499 - unsigned int downsize_coeff,
6500 - unsigned int resize_coeff,
6504 - struct device *dev = ctx->chan->priv->ipu->dev;
6505 - unsigned int out_pos;
6506 - /* Input / output seam position candidates */
6507 - unsigned int out_seam = 0;
6508 - unsigned int in_seam = 0;
6509 - unsigned int min_diff = UINT_MAX;
6510 - unsigned int out_start;
6511 - unsigned int out_end;
6512 - unsigned int in_start;
6513 - unsigned int in_end;
6515 - /* Start within 1024 pixels of the right / bottom edge */
6516 - out_start = max_t(int, index * out_align, out_edge - 1024);
6517 - /* End before having to add more columns to the left / rows above */
6518 - out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
6521 - * Limit input seam position to make sure that the downsized input tile
6522 - * to the right or bottom does not exceed 1024 pixels.
6524 - in_start = max_t(int, index * in_align,
6525 - in_edge - (1024 << downsize_coeff));
6526 - in_end = min_t(unsigned int, in_edge,
6527 - index * (1024 << downsize_coeff) + 1);
6530 - * Output tiles must start at a multiple of 8 bytes horizontally and
6531 - * possibly at an even line horizontally depending on the pixel format.
6532 - * Only consider output aligned positions for the seam.
6534 - out_start = round_up(out_start, out_align);
6535 - for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
6536 - unsigned int in_pos;
6537 - unsigned int in_pos_aligned;
6538 - unsigned int in_pos_rounded;
6539 - unsigned int abs_diff;
6542 - * Tiles in the right row / bottom column may not be allowed to
6543 - * overshoot horizontally / vertically. out_burst may be the
6544 - * actual DMA burst size, or the rotator block size.
6546 - if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
6550 - * Input sample position, corresponding to out_pos, 19.13 fixed
6553 - in_pos = (out_pos * resize_coeff) << downsize_coeff;
6555 - * The closest input sample position that we could actually
6556 - * start the input tile at, 19.13 fixed point.
6558 - in_pos_aligned = round_closest(in_pos, 8192U * in_align);
6559 - /* Convert 19.13 fixed point to integer */
6560 - in_pos_rounded = in_pos_aligned / 8192U;
6562 - if (in_pos_rounded < in_start)
6564 - if (in_pos_rounded >= in_end)
6567 - if ((in_burst > 1) &&
6568 - (in_edge - in_pos_rounded) % in_burst)
6571 - if (in_pos < in_pos_aligned)
6572 - abs_diff = in_pos_aligned - in_pos;
6574 - abs_diff = in_pos - in_pos_aligned;
6576 - if (abs_diff < min_diff) {
6577 - in_seam = in_pos_rounded;
6578 - out_seam = out_pos;
6579 - min_diff = abs_diff;
6583 - *_out_seam = out_seam;
6584 - *_in_seam = in_seam;
6586 - dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
6587 - __func__, out_seam, out_align, out_start, out_end,
6588 - in_seam, in_align, in_start, in_end, min_diff / 8192,
6589 - DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
6593 - * Tile left edges are required to be aligned to multiples of 8 bytes
6596 -static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
6599 - return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
6601 - return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
6605 - * Tile top edge alignment is only limited by chroma subsampling.
6607 -static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
6609 - return fmt->uv_height_dec > 1 ? 2 : 1;
6612 -static inline u32 tile_width_align(enum ipu_image_convert_type type,
6613 - const struct ipu_image_pixfmt *fmt,
6614 - enum ipu_rotate_mode rot_mode)
6616 - if (type == IMAGE_CONVERT_IN) {
6618 - * The IC burst reads 8 pixels at a time. Reading beyond the
6619 - * end of the line is usually acceptable. Those pixels are
6620 - * ignored, unless the IC has to write the scaled line in
6623 - return (!ipu_rot_mode_is_irt(rot_mode) &&
6624 - (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
6628 - * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
6629 - * formats to guarantee 8-byte aligned line start addresses in the
6630 - * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
6631 - * for all other formats.
6633 - return (ipu_rot_mode_is_irt(rot_mode) &&
6634 - fmt->planar && !fmt->uv_packed) ?
6635 - 8 * fmt->uv_width_dec : 8;
6638 -static inline u32 tile_height_align(enum ipu_image_convert_type type,
6639 - const struct ipu_image_pixfmt *fmt,
6640 - enum ipu_rotate_mode rot_mode)
6642 - if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
6646 - * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
6647 - * formats to guarantee 8-byte aligned line start addresses in the
6648 - * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
6649 - * for all other formats.
6651 - return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
6655 - * Fill in left position and width and for all tiles in an input column, and
6656 - * for all corresponding output tiles. If the 90° rotator is used, the output
6657 - * tiles are in a row, and output tile top position and height are set.
6659 -static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
6661 - struct ipu_image_convert_image *in,
6662 - unsigned int in_left, unsigned int in_width,
6663 - struct ipu_image_convert_image *out,
6664 - unsigned int out_left, unsigned int out_width)
6666 - unsigned int row, tile_idx;
6667 - struct ipu_image_tile *in_tile, *out_tile;
6669 - for (row = 0; row < in->num_rows; row++) {
6670 - tile_idx = in->num_cols * row + col;
6671 - in_tile = &in->tile[tile_idx];
6672 - out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
6674 - in_tile->left = in_left;
6675 - in_tile->width = in_width;
6677 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6678 - out_tile->top = out_left;
6679 - out_tile->height = out_width;
6681 - out_tile->left = out_left;
6682 - out_tile->width = out_width;
6688 - * Fill in top position and height and for all tiles in an input row, and
6689 - * for all corresponding output tiles. If the 90° rotator is used, the output
6690 - * tiles are in a column, and output tile left position and width are set.
6692 -static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
6693 - struct ipu_image_convert_image *in,
6694 - unsigned int in_top, unsigned int in_height,
6695 - struct ipu_image_convert_image *out,
6696 - unsigned int out_top, unsigned int out_height)
6698 - unsigned int col, tile_idx;
6699 - struct ipu_image_tile *in_tile, *out_tile;
6701 - for (col = 0; col < in->num_cols; col++) {
6702 - tile_idx = in->num_cols * row + col;
6703 - in_tile = &in->tile[tile_idx];
6704 - out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
6706 - in_tile->top = in_top;
6707 - in_tile->height = in_height;
6709 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6710 - out_tile->left = out_top;
6711 - out_tile->width = out_height;
6713 - out_tile->top = out_top;
6714 - out_tile->height = out_height;
6720 - * Find the best horizontal and vertical seam positions to split into tiles.
6721 - * Minimize the fractional part of the input sampling position for the
6722 - * top / left pixels of each tile.
6724 -static void find_seams(struct ipu_image_convert_ctx *ctx,
6725 - struct ipu_image_convert_image *in,
6726 - struct ipu_image_convert_image *out)
6728 - struct device *dev = ctx->chan->priv->ipu->dev;
6729 - unsigned int resized_width = out->base.rect.width;
6730 - unsigned int resized_height = out->base.rect.height;
6733 - unsigned int in_left_align = tile_left_align(in->fmt);
6734 - unsigned int in_top_align = tile_top_align(in->fmt);
6735 - unsigned int out_left_align = tile_left_align(out->fmt);
6736 - unsigned int out_top_align = tile_top_align(out->fmt);
6737 - unsigned int out_width_align = tile_width_align(out->type, out->fmt,
6739 - unsigned int out_height_align = tile_height_align(out->type, out->fmt,
6741 - unsigned int in_right = in->base.rect.width;
6742 - unsigned int in_bottom = in->base.rect.height;
6743 - unsigned int out_right = out->base.rect.width;
6744 - unsigned int out_bottom = out->base.rect.height;
6745 - unsigned int flipped_out_left;
6746 - unsigned int flipped_out_top;
6748 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
6749 - /* Switch width/height and align top left to IRT block size */
6750 - resized_width = out->base.rect.height;
6751 - resized_height = out->base.rect.width;
6752 - out_left_align = out_height_align;
6753 - out_top_align = out_width_align;
6754 - out_width_align = out_left_align;
6755 - out_height_align = out_top_align;
6756 - out_right = out->base.rect.height;
6757 - out_bottom = out->base.rect.width;
6760 - for (col = in->num_cols - 1; col > 0; col--) {
6761 - bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
6762 - !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
6763 - bool allow_out_overshoot = (col < in->num_cols - 1) &&
6764 - !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
6765 - unsigned int in_left;
6766 - unsigned int out_left;
6769 - * Align input width to burst length if the scaling step flips
6773 - find_best_seam(ctx, col,
6774 - in_right, out_right,
6775 - in_left_align, out_left_align,
6776 - allow_in_overshoot ? 1 : 8 /* burst length */,
6777 - allow_out_overshoot ? 1 : out_width_align,
6778 - ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
6779 - &in_left, &out_left);
6781 - if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
6782 - flipped_out_left = resized_width - out_right;
6784 - flipped_out_left = out_left;
6786 - fill_tile_column(ctx, col, in, in_left, in_right - in_left,
6787 - out, flipped_out_left, out_right - out_left);
6789 - dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
6790 - in_left, in_right - in_left,
6791 - flipped_out_left, out_right - out_left);
6793 - in_right = in_left;
6794 - out_right = out_left;
6797 - flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
6798 - resized_width - out_right : 0;
6800 - fill_tile_column(ctx, 0, in, 0, in_right,
6801 - out, flipped_out_left, out_right);
6803 - dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
6804 - in_right, flipped_out_left, out_right);
6806 - for (row = in->num_rows - 1; row > 0; row--) {
6807 - bool allow_overshoot = row < in->num_rows - 1;
6808 - unsigned int in_top;
6809 - unsigned int out_top;
6811 - find_best_seam(ctx, row,
6812 - in_bottom, out_bottom,
6813 - in_top_align, out_top_align,
6814 - 1, allow_overshoot ? 1 : out_height_align,
6815 - ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
6816 - &in_top, &out_top);
6818 - if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
6819 - ipu_rot_mode_is_irt(ctx->rot_mode))
6820 - flipped_out_top = resized_height - out_bottom;
6822 - flipped_out_top = out_top;
6824 - fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
6825 - out, flipped_out_top, out_bottom - out_top);
6827 - dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
6828 - in_top, in_bottom - in_top,
6829 - flipped_out_top, out_bottom - out_top);
6831 - in_bottom = in_top;
6832 - out_bottom = out_top;
6835 - if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
6836 - ipu_rot_mode_is_irt(ctx->rot_mode))
6837 - flipped_out_top = resized_height - out_bottom;
6839 - flipped_out_top = 0;
6841 - fill_tile_row(ctx, 0, in, 0, in_bottom,
6842 - out, flipped_out_top, out_bottom);
6844 - dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
6845 - in_bottom, flipped_out_top, out_bottom);
6848 -static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
6849 - struct ipu_image_convert_image *image)
6851 - struct ipu_image_convert_chan *chan = ctx->chan;
6852 - struct ipu_image_convert_priv *priv = chan->priv;
6853 - unsigned int max_width = 1024;
6854 - unsigned int max_height = 1024;
6857 - if (image->type == IMAGE_CONVERT_IN) {
6858 - /* Up to 4096x4096 input tile size */
6859 - max_width <<= ctx->downsize_coeff_h;
6860 - max_height <<= ctx->downsize_coeff_v;
6863 - for (i = 0; i < ctx->num_tiles; i++) {
6864 - struct ipu_image_tile *tile;
6865 - const unsigned int row = i / image->num_cols;
6866 - const unsigned int col = i % image->num_cols;
6868 - if (image->type == IMAGE_CONVERT_OUT)
6869 - tile = &image->tile[ctx->out_tile_map[i]];
6871 - tile = &image->tile[i];
6873 - tile->size = ((tile->height * image->fmt->bpp) >> 3) *
6876 - if (image->fmt->planar) {
6877 - tile->stride = tile->width;
6878 - tile->rot_stride = tile->height;
6881 - (image->fmt->bpp * tile->width) >> 3;
6882 - tile->rot_stride =
6883 - (image->fmt->bpp * tile->height) >> 3;
6886 - dev_dbg(priv->ipu->dev,
6887 - "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
6888 - chan->ic_task, ctx,
6889 - image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
6891 - tile->width, tile->height, tile->left, tile->top);
6893 - if (!tile->width || tile->width > max_width ||
6894 - !tile->height || tile->height > max_height) {
6895 - dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
6896 - image->type == IMAGE_CONVERT_IN ? "input" :
6897 - "output", tile->width, tile->height);
6906 - * Use the rotation transformation to find the tile coordinates
6907 - * (row, col) of a tile in the destination frame that corresponds
6908 - * to the given tile coordinates of a source frame. The destination
6909 - * coordinate is then converted to a tile index.
6911 -static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
6912 - int src_row, int src_col)
6914 - struct ipu_image_convert_chan *chan = ctx->chan;
6915 - struct ipu_image_convert_priv *priv = chan->priv;
6916 - struct ipu_image_convert_image *s_image = &ctx->in;
6917 - struct ipu_image_convert_image *d_image = &ctx->out;
6918 - int dst_row, dst_col;
6920 - /* with no rotation it's a 1:1 mapping */
6921 - if (ctx->rot_mode == IPU_ROTATE_NONE)
6922 - return src_row * s_image->num_cols + src_col;
6925 - * before doing the transform, first we have to translate
6926 - * source row,col for an origin in the center of s_image
6928 - src_row = src_row * 2 - (s_image->num_rows - 1);
6929 - src_col = src_col * 2 - (s_image->num_cols - 1);
6931 - /* do the rotation transform */
6932 - if (ctx->rot_mode & IPU_ROT_BIT_90) {
6933 - dst_col = -src_row;
6934 - dst_row = src_col;
6936 - dst_col = src_col;
6937 - dst_row = src_row;
6941 - if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
6942 - dst_col = -dst_col;
6943 - if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
6944 - dst_row = -dst_row;
6946 - dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
6947 - chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
6950 - * finally translate dest row,col using an origin in upper
6953 - dst_row += d_image->num_rows - 1;
6954 - dst_col += d_image->num_cols - 1;
6958 - return dst_row * d_image->num_cols + dst_col;
6962 - * Fill the out_tile_map[] with transformed destination tile indeces.
6964 -static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
6966 - struct ipu_image_convert_image *s_image = &ctx->in;
6967 - unsigned int row, col, tile = 0;
6969 - for (row = 0; row < s_image->num_rows; row++) {
6970 - for (col = 0; col < s_image->num_cols; col++) {
6971 - ctx->out_tile_map[tile] =
6972 - transform_tile_index(ctx, row, col);
6978 -static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
6979 - struct ipu_image_convert_image *image)
6981 - struct ipu_image_convert_chan *chan = ctx->chan;
6982 - struct ipu_image_convert_priv *priv = chan->priv;
6983 - const struct ipu_image_pixfmt *fmt = image->fmt;
6984 - unsigned int row, col, tile = 0;
6985 - u32 H, top, y_stride, uv_stride;
6986 - u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
6987 - u32 y_row_off, y_col_off, y_off;
6988 - u32 y_size, uv_size;
6990 - /* setup some convenience vars */
6991 - H = image->base.pix.height;
6993 - y_stride = image->stride;
6994 - uv_stride = y_stride / fmt->uv_width_dec;
6995 - if (fmt->uv_packed)
6998 - y_size = H * y_stride;
6999 - uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
7001 - for (row = 0; row < image->num_rows; row++) {
7002 - top = image->tile[tile].top;
7003 - y_row_off = top * y_stride;
7004 - uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
7006 - for (col = 0; col < image->num_cols; col++) {
7007 - y_col_off = image->tile[tile].left;
7008 - uv_col_off = y_col_off / fmt->uv_width_dec;
7009 - if (fmt->uv_packed)
7012 - y_off = y_row_off + y_col_off;
7013 - uv_off = uv_row_off + uv_col_off;
7015 - u_off = y_size - y_off + uv_off;
7016 - v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
7017 - if (fmt->uv_swapped) {
7023 - image->tile[tile].offset = y_off;
7024 - image->tile[tile].u_off = u_off;
7025 - image->tile[tile++].v_off = v_off;
7027 - if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
7028 - dev_err(priv->ipu->dev,
7029 - "task %u: ctx %p: %s@[%d,%d]: "
7030 - "y_off %08x, u_off %08x, v_off %08x\n",
7031 - chan->ic_task, ctx,
7032 - image->type == IMAGE_CONVERT_IN ?
7033 - "Input" : "Output", row, col,
7034 - y_off, u_off, v_off);
7043 -static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
7044 - struct ipu_image_convert_image *image)
7046 - struct ipu_image_convert_chan *chan = ctx->chan;
7047 - struct ipu_image_convert_priv *priv = chan->priv;
7048 - const struct ipu_image_pixfmt *fmt = image->fmt;
7049 - unsigned int row, col, tile = 0;
7050 - u32 bpp, stride, offset;
7051 - u32 row_off, col_off;
7053 - /* setup some convenience vars */
7054 - stride = image->stride;
7057 - for (row = 0; row < image->num_rows; row++) {
7058 - row_off = image->tile[tile].top * stride;
7060 - for (col = 0; col < image->num_cols; col++) {
7061 - col_off = (image->tile[tile].left * bpp) >> 3;
7063 - offset = row_off + col_off;
7065 - image->tile[tile].offset = offset;
7066 - image->tile[tile].u_off = 0;
7067 - image->tile[tile++].v_off = 0;
7069 - if (offset & 0x7) {
7070 - dev_err(priv->ipu->dev,
7071 - "task %u: ctx %p: %s@[%d,%d]: "
7073 - chan->ic_task, ctx,
7074 - image->type == IMAGE_CONVERT_IN ?
7075 - "Input" : "Output", row, col,
7076 - row_off + col_off);
7085 -static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
7086 - struct ipu_image_convert_image *image)
7088 - if (image->fmt->planar)
7089 - return calc_tile_offsets_planar(ctx, image);
7091 - return calc_tile_offsets_packed(ctx, image);
7095 - * Calculate the resizing ratio for the IC main processing section given input
7096 - * size, fixed downsizing coefficient, and output size.
7097 - * Either round to closest for the next tile's first pixel to minimize seams
7098 - * and distortion (for all but right column / bottom row), or round down to
7099 - * avoid sampling beyond the edges of the input image for this tile's last
7101 - * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
7103 -static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
7104 - u32 output_size, bool allow_overshoot)
7106 - u32 downsized = input_size >> downsize_coeff;
7108 - if (allow_overshoot)
7109 - return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
7111 - return 8192 * (downsized - 1) / (output_size - 1);
7115 - * Slightly modify resize coefficients per tile to hide the bilinear
7116 - * interpolator reset at tile borders, shifting the right / bottom edge
7117 - * by up to a half input pixel. This removes noticeable seams between
7118 - * tiles at higher upscaling factors.
7120 -static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
7122 - struct ipu_image_convert_chan *chan = ctx->chan;
7123 - struct ipu_image_convert_priv *priv = chan->priv;
7124 - struct ipu_image_tile *in_tile, *out_tile;
7125 - unsigned int col, row, tile_idx;
7126 - unsigned int last_output;
7128 - for (col = 0; col < ctx->in.num_cols; col++) {
7129 - bool closest = (col < ctx->in.num_cols - 1) &&
7130 - !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
7131 - u32 resized_width;
7132 - u32 resize_coeff_h;
7136 - in_tile = &ctx->in.tile[tile_idx];
7137 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7139 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
7140 - resized_width = out_tile->height;
7142 - resized_width = out_tile->width;
7144 - resize_coeff_h = calc_resize_coeff(in_tile->width,
7145 - ctx->downsize_coeff_h,
7146 - resized_width, closest);
7148 - dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
7149 - __func__, col, resize_coeff_h);
7152 - * With the horizontal scaling factor known, round up resized
7153 - * width (output width or height) to burst size.
7155 - resized_width = round_up(resized_width, 8);
7158 - * Calculate input width from the last accessed input pixel
7159 - * given resized width and scaling coefficients. Round up to
7162 - last_output = resized_width - 1;
7163 - if (closest && ((last_output * resize_coeff_h) % 8192))
7165 - in_width = round_up(
7166 - (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
7167 - << ctx->downsize_coeff_h, 8);
7169 - for (row = 0; row < ctx->in.num_rows; row++) {
7170 - tile_idx = row * ctx->in.num_cols + col;
7171 - in_tile = &ctx->in.tile[tile_idx];
7172 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7174 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
7175 - out_tile->height = resized_width;
7177 - out_tile->width = resized_width;
7179 - in_tile->width = in_width;
7182 - ctx->resize_coeffs_h[col] = resize_coeff_h;
7185 - for (row = 0; row < ctx->in.num_rows; row++) {
7186 - bool closest = (row < ctx->in.num_rows - 1) &&
7187 - !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
7188 - u32 resized_height;
7189 - u32 resize_coeff_v;
7192 - tile_idx = row * ctx->in.num_cols;
7193 - in_tile = &ctx->in.tile[tile_idx];
7194 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7196 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
7197 - resized_height = out_tile->width;
7199 - resized_height = out_tile->height;
7201 - resize_coeff_v = calc_resize_coeff(in_tile->height,
7202 - ctx->downsize_coeff_v,
7203 - resized_height, closest);
7205 - dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
7206 - __func__, row, resize_coeff_v);
7209 - * With the vertical scaling factor known, round up resized
7210 - * height (output width or height) to IDMAC limitations.
7212 - resized_height = round_up(resized_height, 2);
7215 - * Calculate input width from the last accessed input pixel
7216 - * given resized height and scaling coefficients. Align to
7217 - * IDMAC restrictions.
7219 - last_output = resized_height - 1;
7220 - if (closest && ((last_output * resize_coeff_v) % 8192))
7222 - in_height = round_up(
7223 - (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
7224 - << ctx->downsize_coeff_v, 2);
7226 - for (col = 0; col < ctx->in.num_cols; col++) {
7227 - tile_idx = row * ctx->in.num_cols + col;
7228 - in_tile = &ctx->in.tile[tile_idx];
7229 - out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
7231 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
7232 - out_tile->width = resized_height;
7234 - out_tile->height = resized_height;
7236 - in_tile->height = in_height;
7239 - ctx->resize_coeffs_v[row] = resize_coeff_v;
7244 - * return the number of runs in given queue (pending_q or done_q)
7245 - * for this context. hold irqlock when calling.
7247 -static int get_run_count(struct ipu_image_convert_ctx *ctx,
7248 - struct list_head *q)
7250 - struct ipu_image_convert_run *run;
7253 - lockdep_assert_held(&ctx->chan->irqlock);
7255 - list_for_each_entry(run, q, list) {
7256 - if (run->ctx == ctx)
7263 -static void convert_stop(struct ipu_image_convert_run *run)
7265 - struct ipu_image_convert_ctx *ctx = run->ctx;
7266 - struct ipu_image_convert_chan *chan = ctx->chan;
7267 - struct ipu_image_convert_priv *priv = chan->priv;
7269 - dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
7270 - __func__, chan->ic_task, ctx, run);
7272 - /* disable IC tasks and the channels */
7273 - ipu_ic_task_disable(chan->ic);
7274 - ipu_idmac_disable_channel(chan->in_chan);
7275 - ipu_idmac_disable_channel(chan->out_chan);
7277 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7278 - ipu_idmac_disable_channel(chan->rotation_in_chan);
7279 - ipu_idmac_disable_channel(chan->rotation_out_chan);
7280 - ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
7283 - ipu_ic_disable(chan->ic);
7286 -static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
7287 - struct ipuv3_channel *channel,
7288 - struct ipu_image_convert_image *image,
7289 - enum ipu_rotate_mode rot_mode,
7290 - bool rot_swap_width_height,
7291 - unsigned int tile)
7293 - struct ipu_image_convert_chan *chan = ctx->chan;
7294 - unsigned int burst_size;
7295 - u32 width, height, stride;
7296 - dma_addr_t addr0, addr1 = 0;
7297 - struct ipu_image tile_image;
7298 - unsigned int tile_idx[2];
7300 - if (image->type == IMAGE_CONVERT_OUT) {
7301 - tile_idx[0] = ctx->out_tile_map[tile];
7302 - tile_idx[1] = ctx->out_tile_map[1];
7304 - tile_idx[0] = tile;
7308 - if (rot_swap_width_height) {
7309 - width = image->tile[tile_idx[0]].height;
7310 - height = image->tile[tile_idx[0]].width;
7311 - stride = image->tile[tile_idx[0]].rot_stride;
7312 - addr0 = ctx->rot_intermediate[0].phys;
7313 - if (ctx->double_buffering)
7314 - addr1 = ctx->rot_intermediate[1].phys;
7316 - width = image->tile[tile_idx[0]].width;
7317 - height = image->tile[tile_idx[0]].height;
7318 - stride = image->stride;
7319 - addr0 = image->base.phys0 +
7320 - image->tile[tile_idx[0]].offset;
7321 - if (ctx->double_buffering)
7322 - addr1 = image->base.phys0 +
7323 - image->tile[tile_idx[1]].offset;
7326 - ipu_cpmem_zero(channel);
7328 - memset(&tile_image, 0, sizeof(tile_image));
7329 - tile_image.pix.width = tile_image.rect.width = width;
7330 - tile_image.pix.height = tile_image.rect.height = height;
7331 - tile_image.pix.bytesperline = stride;
7332 - tile_image.pix.pixelformat = image->fmt->fourcc;
7333 - tile_image.phys0 = addr0;
7334 - tile_image.phys1 = addr1;
7335 - if (image->fmt->planar && !rot_swap_width_height) {
7336 - tile_image.u_offset = image->tile[tile_idx[0]].u_off;
7337 - tile_image.v_offset = image->tile[tile_idx[0]].v_off;
7340 - ipu_cpmem_set_image(channel, &tile_image);
7343 - ipu_cpmem_set_rotation(channel, rot_mode);
7346 - * Skip writing U and V components to odd rows in the output
7347 - * channels for planar 4:2:0.
7349 - if ((channel == chan->out_chan ||
7350 - channel == chan->rotation_out_chan) &&
7351 - image->fmt->planar && image->fmt->uv_height_dec == 2)
7352 - ipu_cpmem_skip_odd_chroma_rows(channel);
7354 - if (channel == chan->rotation_in_chan ||
7355 - channel == chan->rotation_out_chan) {
7357 - ipu_cpmem_set_block_mode(channel);
7359 - burst_size = (width % 16) ? 8 : 16;
7361 - ipu_cpmem_set_burstsize(channel, burst_size);
7363 - ipu_ic_task_idma_init(chan->ic, channel, width, height,
7364 - burst_size, rot_mode);
7367 - * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
7368 - * only do this when there is no PRG present.
7370 - if (!channel->ipu->prg_priv)
7371 - ipu_cpmem_set_axi_id(channel, 1);
7373 - ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
7376 -static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
7378 - struct ipu_image_convert_ctx *ctx = run->ctx;
7379 - struct ipu_image_convert_chan *chan = ctx->chan;
7380 - struct ipu_image_convert_priv *priv = chan->priv;
7381 - struct ipu_image_convert_image *s_image = &ctx->in;
7382 - struct ipu_image_convert_image *d_image = &ctx->out;
7383 - unsigned int dst_tile = ctx->out_tile_map[tile];
7384 - unsigned int dest_width, dest_height;
7385 - unsigned int col, row;
7389 - dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
7390 - __func__, chan->ic_task, ctx, run, tile, dst_tile);
7392 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7393 - /* swap width/height for resizer */
7394 - dest_width = d_image->tile[dst_tile].height;
7395 - dest_height = d_image->tile[dst_tile].width;
7397 - dest_width = d_image->tile[dst_tile].width;
7398 - dest_height = d_image->tile[dst_tile].height;
7401 - row = tile / s_image->num_cols;
7402 - col = tile % s_image->num_cols;
7404 - rsc = (ctx->downsize_coeff_v << 30) |
7405 - (ctx->resize_coeffs_v[row] << 16) |
7406 - (ctx->downsize_coeff_h << 14) |
7407 - (ctx->resize_coeffs_h[col]);
7409 - dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
7410 - __func__, s_image->tile[tile].width,
7411 - s_image->tile[tile].height, dest_width, dest_height, rsc);
7413 - /* setup the IC resizer and CSC */
7414 - ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
7415 - s_image->tile[tile].width,
7416 - s_image->tile[tile].height,
7421 - dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
7425 - /* init the source MEM-->IC PP IDMAC channel */
7426 - init_idmac_channel(ctx, chan->in_chan, s_image,
7427 - IPU_ROTATE_NONE, false, tile);
7429 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7430 - /* init the IC PP-->MEM IDMAC channel */
7431 - init_idmac_channel(ctx, chan->out_chan, d_image,
7432 - IPU_ROTATE_NONE, true, tile);
7434 - /* init the MEM-->IC PP ROT IDMAC channel */
7435 - init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
7436 - ctx->rot_mode, true, tile);
7438 - /* init the destination IC PP ROT-->MEM IDMAC channel */
7439 - init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
7440 - IPU_ROTATE_NONE, false, tile);
7442 - /* now link IC PP-->MEM to MEM-->IC PP ROT */
7443 - ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
7445 - /* init the destination IC PP-->MEM IDMAC channel */
7446 - init_idmac_channel(ctx, chan->out_chan, d_image,
7447 - ctx->rot_mode, false, tile);
7450 - /* enable the IC */
7451 - ipu_ic_enable(chan->ic);
7453 - /* set buffers ready */
7454 - ipu_idmac_select_buffer(chan->in_chan, 0);
7455 - ipu_idmac_select_buffer(chan->out_chan, 0);
7456 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
7457 - ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
7458 - if (ctx->double_buffering) {
7459 - ipu_idmac_select_buffer(chan->in_chan, 1);
7460 - ipu_idmac_select_buffer(chan->out_chan, 1);
7461 - if (ipu_rot_mode_is_irt(ctx->rot_mode))
7462 - ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
7465 - /* enable the channels! */
7466 - ipu_idmac_enable_channel(chan->in_chan);
7467 - ipu_idmac_enable_channel(chan->out_chan);
7468 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7469 - ipu_idmac_enable_channel(chan->rotation_in_chan);
7470 - ipu_idmac_enable_channel(chan->rotation_out_chan);
7473 - ipu_ic_task_enable(chan->ic);
7475 - ipu_cpmem_dump(chan->in_chan);
7476 - ipu_cpmem_dump(chan->out_chan);
7477 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7478 - ipu_cpmem_dump(chan->rotation_in_chan);
7479 - ipu_cpmem_dump(chan->rotation_out_chan);
7482 - ipu_dump(priv->ipu);
7487 -/* hold irqlock when calling */
7488 -static int do_run(struct ipu_image_convert_run *run)
7490 - struct ipu_image_convert_ctx *ctx = run->ctx;
7491 - struct ipu_image_convert_chan *chan = ctx->chan;
7493 - lockdep_assert_held(&chan->irqlock);
7495 - ctx->in.base.phys0 = run->in_phys;
7496 - ctx->out.base.phys0 = run->out_phys;
7498 - ctx->cur_buf_num = 0;
7499 - ctx->next_tile = 1;
7501 - /* remove run from pending_q and set as current */
7502 - list_del(&run->list);
7503 - chan->current_run = run;
7505 - return convert_start(run, 0);
7508 -/* hold irqlock when calling */
7509 -static void run_next(struct ipu_image_convert_chan *chan)
7511 - struct ipu_image_convert_priv *priv = chan->priv;
7512 - struct ipu_image_convert_run *run, *tmp;
7515 - lockdep_assert_held(&chan->irqlock);
7517 - list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
7518 - /* skip contexts that are aborting */
7519 - if (run->ctx->aborting) {
7520 - dev_dbg(priv->ipu->dev,
7521 - "%s: task %u: skipping aborting ctx %p run %p\n",
7522 - __func__, chan->ic_task, run->ctx, run);
7526 - ret = do_run(run);
7531 - * something went wrong with start, add the run
7532 - * to done q and continue to the next run in the
7535 - run->status = ret;
7536 - list_add_tail(&run->list, &chan->done_q);
7537 - chan->current_run = NULL;
7541 -static void empty_done_q(struct ipu_image_convert_chan *chan)
7543 - struct ipu_image_convert_priv *priv = chan->priv;
7544 - struct ipu_image_convert_run *run;
7545 - unsigned long flags;
7547 - spin_lock_irqsave(&chan->irqlock, flags);
7549 - while (!list_empty(&chan->done_q)) {
7550 - run = list_entry(chan->done_q.next,
7551 - struct ipu_image_convert_run,
7554 - list_del(&run->list);
7556 - dev_dbg(priv->ipu->dev,
7557 - "%s: task %u: completing ctx %p run %p with %d\n",
7558 - __func__, chan->ic_task, run->ctx, run, run->status);
7560 - /* call the completion callback and free the run */
7561 - spin_unlock_irqrestore(&chan->irqlock, flags);
7562 - run->ctx->complete(run, run->ctx->complete_context);
7563 - spin_lock_irqsave(&chan->irqlock, flags);
7566 - spin_unlock_irqrestore(&chan->irqlock, flags);
7570 - * the bottom half thread clears out the done_q, calling the
7571 - * completion handler for each.
7573 -static irqreturn_t do_bh(int irq, void *dev_id)
7575 - struct ipu_image_convert_chan *chan = dev_id;
7576 - struct ipu_image_convert_priv *priv = chan->priv;
7577 - struct ipu_image_convert_ctx *ctx;
7578 - unsigned long flags;
7580 - dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
7583 - empty_done_q(chan);
7585 - spin_lock_irqsave(&chan->irqlock, flags);
7588 - * the done_q is cleared out, signal any contexts
7589 - * that are aborting that abort can complete.
7591 - list_for_each_entry(ctx, &chan->ctx_list, list) {
7592 - if (ctx->aborting) {
7593 - dev_dbg(priv->ipu->dev,
7594 - "%s: task %u: signaling abort for ctx %p\n",
7595 - __func__, chan->ic_task, ctx);
7596 - complete_all(&ctx->aborted);
7600 - spin_unlock_irqrestore(&chan->irqlock, flags);
7602 - dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
7605 - return IRQ_HANDLED;
7608 -static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
7610 - unsigned int cur_tile = ctx->next_tile - 1;
7611 - unsigned int next_tile = ctx->next_tile;
7613 - if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
7614 - ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
7615 - ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
7616 - ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
7617 - ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
7618 - ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
7619 - ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
7620 - ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
7626 -/* hold irqlock when calling */
7627 -static irqreturn_t do_irq(struct ipu_image_convert_run *run)
7629 - struct ipu_image_convert_ctx *ctx = run->ctx;
7630 - struct ipu_image_convert_chan *chan = ctx->chan;
7631 - struct ipu_image_tile *src_tile, *dst_tile;
7632 - struct ipu_image_convert_image *s_image = &ctx->in;
7633 - struct ipu_image_convert_image *d_image = &ctx->out;
7634 - struct ipuv3_channel *outch;
7635 - unsigned int dst_idx;
7637 - lockdep_assert_held(&chan->irqlock);
7639 - outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
7640 - chan->rotation_out_chan : chan->out_chan;
7643 - * It is difficult to stop the channel DMA before the channels
7644 - * enter the paused state. Without double-buffering the channels
7645 - * are always in a paused state when the EOF irq occurs, so it
7646 - * is safe to stop the channels now. For double-buffering we
7647 - * just ignore the abort until the operation completes, when it
7648 - * is safe to shut down.
7650 - if (ctx->aborting && !ctx->double_buffering) {
7651 - convert_stop(run);
7652 - run->status = -EIO;
7656 - if (ctx->next_tile == ctx->num_tiles) {
7658 - * the conversion is complete
7660 - convert_stop(run);
7666 - * not done, place the next tile buffers.
7668 - if (!ctx->double_buffering) {
7669 - if (ic_settings_changed(ctx)) {
7670 - convert_stop(run);
7671 - convert_start(run, ctx->next_tile);
7673 - src_tile = &s_image->tile[ctx->next_tile];
7674 - dst_idx = ctx->out_tile_map[ctx->next_tile];
7675 - dst_tile = &d_image->tile[dst_idx];
7677 - ipu_cpmem_set_buffer(chan->in_chan, 0,
7678 - s_image->base.phys0 +
7679 - src_tile->offset);
7680 - ipu_cpmem_set_buffer(outch, 0,
7681 - d_image->base.phys0 +
7682 - dst_tile->offset);
7683 - if (s_image->fmt->planar)
7684 - ipu_cpmem_set_uv_offset(chan->in_chan,
7687 - if (d_image->fmt->planar)
7688 - ipu_cpmem_set_uv_offset(outch,
7692 - ipu_idmac_select_buffer(chan->in_chan, 0);
7693 - ipu_idmac_select_buffer(outch, 0);
7695 - } else if (ctx->next_tile < ctx->num_tiles - 1) {
7697 - src_tile = &s_image->tile[ctx->next_tile + 1];
7698 - dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
7699 - dst_tile = &d_image->tile[dst_idx];
7701 - ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
7702 - s_image->base.phys0 + src_tile->offset);
7703 - ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
7704 - d_image->base.phys0 + dst_tile->offset);
7706 - ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
7707 - ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
7709 - ctx->cur_buf_num ^= 1;
7713 - return IRQ_HANDLED;
7715 - list_add_tail(&run->list, &chan->done_q);
7716 - chan->current_run = NULL;
7718 - return IRQ_WAKE_THREAD;
7721 -static irqreturn_t norotate_irq(int irq, void *data)
7723 - struct ipu_image_convert_chan *chan = data;
7724 - struct ipu_image_convert_ctx *ctx;
7725 - struct ipu_image_convert_run *run;
7726 - unsigned long flags;
7729 - spin_lock_irqsave(&chan->irqlock, flags);
7731 - /* get current run and its context */
7732 - run = chan->current_run;
7740 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7741 - /* this is a rotation operation, just ignore */
7742 - spin_unlock_irqrestore(&chan->irqlock, flags);
7743 - return IRQ_HANDLED;
7746 - ret = do_irq(run);
7748 - spin_unlock_irqrestore(&chan->irqlock, flags);
7752 -static irqreturn_t rotate_irq(int irq, void *data)
7754 - struct ipu_image_convert_chan *chan = data;
7755 - struct ipu_image_convert_priv *priv = chan->priv;
7756 - struct ipu_image_convert_ctx *ctx;
7757 - struct ipu_image_convert_run *run;
7758 - unsigned long flags;
7761 - spin_lock_irqsave(&chan->irqlock, flags);
7763 - /* get current run and its context */
7764 - run = chan->current_run;
7772 - if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
7773 - /* this was NOT a rotation operation, shouldn't happen */
7774 - dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
7775 - spin_unlock_irqrestore(&chan->irqlock, flags);
7776 - return IRQ_HANDLED;
7779 - ret = do_irq(run);
7781 - spin_unlock_irqrestore(&chan->irqlock, flags);
7786 - * try to force the completion of runs for this ctx. Called when
7787 - * abort wait times out in ipu_image_convert_abort().
7789 -static void force_abort(struct ipu_image_convert_ctx *ctx)
7791 - struct ipu_image_convert_chan *chan = ctx->chan;
7792 - struct ipu_image_convert_run *run;
7793 - unsigned long flags;
7795 - spin_lock_irqsave(&chan->irqlock, flags);
7797 - run = chan->current_run;
7798 - if (run && run->ctx == ctx) {
7799 - convert_stop(run);
7800 - run->status = -EIO;
7801 - list_add_tail(&run->list, &chan->done_q);
7802 - chan->current_run = NULL;
7806 - spin_unlock_irqrestore(&chan->irqlock, flags);
7808 - empty_done_q(chan);
7811 -static void release_ipu_resources(struct ipu_image_convert_chan *chan)
7813 - if (chan->out_eof_irq >= 0)
7814 - free_irq(chan->out_eof_irq, chan);
7815 - if (chan->rot_out_eof_irq >= 0)
7816 - free_irq(chan->rot_out_eof_irq, chan);
7818 - if (!IS_ERR_OR_NULL(chan->in_chan))
7819 - ipu_idmac_put(chan->in_chan);
7820 - if (!IS_ERR_OR_NULL(chan->out_chan))
7821 - ipu_idmac_put(chan->out_chan);
7822 - if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
7823 - ipu_idmac_put(chan->rotation_in_chan);
7824 - if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
7825 - ipu_idmac_put(chan->rotation_out_chan);
7826 - if (!IS_ERR_OR_NULL(chan->ic))
7827 - ipu_ic_put(chan->ic);
7829 - chan->in_chan = chan->out_chan = chan->rotation_in_chan =
7830 - chan->rotation_out_chan = NULL;
7831 - chan->out_eof_irq = chan->rot_out_eof_irq = -1;
7834 -static int get_ipu_resources(struct ipu_image_convert_chan *chan)
7836 - const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
7837 - struct ipu_image_convert_priv *priv = chan->priv;
7841 - chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
7842 - if (IS_ERR(chan->ic)) {
7843 - dev_err(priv->ipu->dev, "could not acquire IC\n");
7844 - ret = PTR_ERR(chan->ic);
7848 - /* get IDMAC channels */
7849 - chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
7850 - chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
7851 - if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
7852 - dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
7857 - chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
7858 - chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
7859 - if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
7860 - dev_err(priv->ipu->dev,
7861 - "could not acquire idmac rotation channels\n");
7866 - /* acquire the EOF interrupts */
7867 - chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
7871 - ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
7872 - 0, "ipu-ic", chan);
7874 - dev_err(priv->ipu->dev, "could not acquire irq %d\n",
7875 - chan->out_eof_irq);
7876 - chan->out_eof_irq = -1;
7880 - chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
7881 - chan->rotation_out_chan,
7884 - ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
7885 - 0, "ipu-ic", chan);
7887 - dev_err(priv->ipu->dev, "could not acquire irq %d\n",
7888 - chan->rot_out_eof_irq);
7889 - chan->rot_out_eof_irq = -1;
7895 - release_ipu_resources(chan);
7899 -static int fill_image(struct ipu_image_convert_ctx *ctx,
7900 - struct ipu_image_convert_image *ic_image,
7901 - struct ipu_image *image,
7902 - enum ipu_image_convert_type type)
7904 - struct ipu_image_convert_priv *priv = ctx->chan->priv;
7906 - ic_image->base = *image;
7907 - ic_image->type = type;
7909 - ic_image->fmt = get_format(image->pix.pixelformat);
7910 - if (!ic_image->fmt) {
7911 - dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
7912 - type == IMAGE_CONVERT_OUT ? "Output" : "Input");
7916 - if (ic_image->fmt->planar)
7917 - ic_image->stride = ic_image->base.pix.width;
7919 - ic_image->stride = ic_image->base.pix.bytesperline;
7924 -/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
7925 -static unsigned int clamp_align(unsigned int x, unsigned int min,
7926 - unsigned int max, unsigned int align)
7928 - /* Bits that must be zero to be aligned */
7929 - unsigned int mask = ~((1 << align) - 1);
7931 - /* Clamp to aligned min and max */
7932 - x = clamp(x, (min + ~mask) & mask, max & mask);
7934 - /* Round to nearest aligned value */
7936 - x = (x + (1 << (align - 1))) & mask;
7941 -/* Adjusts input/output images to IPU restrictions */
7942 -void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
7943 - enum ipu_rotate_mode rot_mode)
7945 - const struct ipu_image_pixfmt *infmt, *outfmt;
7946 - u32 w_align_out, h_align_out;
7947 - u32 w_align_in, h_align_in;
7949 - infmt = get_format(in->pix.pixelformat);
7950 - outfmt = get_format(out->pix.pixelformat);
7952 - /* set some default pixel formats if needed */
7954 - in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
7955 - infmt = get_format(V4L2_PIX_FMT_RGB24);
7958 - out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
7959 - outfmt = get_format(V4L2_PIX_FMT_RGB24);
7962 - /* image converter does not handle fields */
7963 - in->pix.field = out->pix.field = V4L2_FIELD_NONE;
7965 - /* resizer cannot downsize more than 4:1 */
7966 - if (ipu_rot_mode_is_irt(rot_mode)) {
7967 - out->pix.height = max_t(__u32, out->pix.height,
7968 - in->pix.width / 4);
7969 - out->pix.width = max_t(__u32, out->pix.width,
7970 - in->pix.height / 4);
7972 - out->pix.width = max_t(__u32, out->pix.width,
7973 - in->pix.width / 4);
7974 - out->pix.height = max_t(__u32, out->pix.height,
7975 - in->pix.height / 4);
7978 - /* align input width/height */
7979 - w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
7981 - h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
7983 - in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
7985 - in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
7988 - /* align output width/height */
7989 - w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
7991 - h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
7993 - out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
7995 - out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
7998 - /* set input/output strides and image sizes */
7999 - in->pix.bytesperline = infmt->planar ?
8000 - clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
8002 - clamp_align((in->pix.width * infmt->bpp) >> 3,
8003 - ((2 << w_align_in) * infmt->bpp) >> 3,
8004 - (MAX_W * infmt->bpp) >> 3,
8006 - in->pix.sizeimage = infmt->planar ?
8007 - (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
8008 - in->pix.height * in->pix.bytesperline;
8009 - out->pix.bytesperline = outfmt->planar ? out->pix.width :
8010 - (out->pix.width * outfmt->bpp) >> 3;
8011 - out->pix.sizeimage = outfmt->planar ?
8012 - (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
8013 - out->pix.height * out->pix.bytesperline;
8015 -EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
8018 - * this is used by ipu_image_convert_prepare() to verify set input and
8019 - * output images are valid before starting the conversion. Clients can
8020 - * also call it before calling ipu_image_convert_prepare().
8022 -int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
8023 - enum ipu_rotate_mode rot_mode)
8025 - struct ipu_image testin, testout;
8030 - ipu_image_convert_adjust(&testin, &testout, rot_mode);
8032 - if (testin.pix.width != in->pix.width ||
8033 - testin.pix.height != in->pix.height ||
8034 - testout.pix.width != out->pix.width ||
8035 - testout.pix.height != out->pix.height)
8040 -EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
8043 - * Call ipu_image_convert_prepare() to prepare for the conversion of
8044 - * given images and rotation mode. Returns a new conversion context.
8046 -struct ipu_image_convert_ctx *
8047 -ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
8048 - struct ipu_image *in, struct ipu_image *out,
8049 - enum ipu_rotate_mode rot_mode,
8050 - ipu_image_convert_cb_t complete,
8051 - void *complete_context)
8053 - struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
8054 - struct ipu_image_convert_image *s_image, *d_image;
8055 - struct ipu_image_convert_chan *chan;
8056 - struct ipu_image_convert_ctx *ctx;
8057 - unsigned long flags;
8062 - if (!in || !out || !complete ||
8063 - (ic_task != IC_TASK_VIEWFINDER &&
8064 - ic_task != IC_TASK_POST_PROCESSOR))
8065 - return ERR_PTR(-EINVAL);
8067 - /* verify the in/out images before continuing */
8068 - ret = ipu_image_convert_verify(in, out, rot_mode);
8070 - dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
8072 - return ERR_PTR(ret);
8075 - chan = &priv->chan[ic_task];
8077 - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
8079 - return ERR_PTR(-ENOMEM);
8081 - dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
8082 - chan->ic_task, ctx);
8085 - init_completion(&ctx->aborted);
8087 - ctx->rot_mode = rot_mode;
8089 - /* Sets ctx->in.num_rows/cols as well */
8090 - ret = calc_image_resize_coefficients(ctx, in, out);
8094 - s_image = &ctx->in;
8095 - d_image = &ctx->out;
8097 - /* set tiling and rotation */
8098 - if (ipu_rot_mode_is_irt(rot_mode)) {
8099 - d_image->num_rows = s_image->num_cols;
8100 - d_image->num_cols = s_image->num_rows;
8102 - d_image->num_rows = s_image->num_rows;
8103 - d_image->num_cols = s_image->num_cols;
8106 - ctx->num_tiles = d_image->num_cols * d_image->num_rows;
8108 - ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
8111 - ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
8115 - calc_out_tile_map(ctx);
8117 - find_seams(ctx, s_image, d_image);
8119 - ret = calc_tile_dimensions(ctx, s_image);
8123 - ret = calc_tile_offsets(ctx, s_image);
8127 - calc_tile_dimensions(ctx, d_image);
8128 - ret = calc_tile_offsets(ctx, d_image);
8132 - calc_tile_resize_coefficients(ctx);
8134 - ret = ipu_ic_calc_csc(&ctx->csc,
8135 - s_image->base.pix.ycbcr_enc,
8136 - s_image->base.pix.quantization,
8137 - ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
8138 - d_image->base.pix.ycbcr_enc,
8139 - d_image->base.pix.quantization,
8140 - ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
8144 - dump_format(ctx, s_image);
8145 - dump_format(ctx, d_image);
8147 - ctx->complete = complete;
8148 - ctx->complete_context = complete_context;
8151 - * Can we use double-buffering for this operation? If there is
8152 - * only one tile (the whole image can be converted in a single
8153 - * operation) there's no point in using double-buffering. Also,
8154 - * the IPU's IDMAC channels allow only a single U and V plane
8155 - * offset shared between both buffers, but these offsets change
8156 - * for every tile, and therefore would have to be updated for
8157 - * each buffer which is not possible. So double-buffering is
8158 - * impossible when either the source or destination images are
8159 - * a planar format (YUV420, YUV422P, etc.). Further, differently
8160 - * sized tiles or different resizing coefficients per tile
8161 - * prevent double-buffering as well.
8163 - ctx->double_buffering = (ctx->num_tiles > 1 &&
8164 - !s_image->fmt->planar &&
8165 - !d_image->fmt->planar);
8166 - for (i = 1; i < ctx->num_tiles; i++) {
8167 - if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
8168 - ctx->in.tile[i].height != ctx->in.tile[0].height ||
8169 - ctx->out.tile[i].width != ctx->out.tile[0].width ||
8170 - ctx->out.tile[i].height != ctx->out.tile[0].height) {
8171 - ctx->double_buffering = false;
8175 - for (i = 1; i < ctx->in.num_cols; i++) {
8176 - if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
8177 - ctx->double_buffering = false;
8181 - for (i = 1; i < ctx->in.num_rows; i++) {
8182 - if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
8183 - ctx->double_buffering = false;
8188 - if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
8189 - unsigned long intermediate_size = d_image->tile[0].size;
8191 - for (i = 1; i < ctx->num_tiles; i++) {
8192 - if (d_image->tile[i].size > intermediate_size)
8193 - intermediate_size = d_image->tile[i].size;
8196 - ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
8197 - intermediate_size);
8200 - if (ctx->double_buffering) {
8201 - ret = alloc_dma_buf(priv,
8202 - &ctx->rot_intermediate[1],
8203 - intermediate_size);
8205 - goto out_free_dmabuf0;
8209 - spin_lock_irqsave(&chan->irqlock, flags);
8211 - get_res = list_empty(&chan->ctx_list);
8213 - list_add_tail(&ctx->list, &chan->ctx_list);
8215 - spin_unlock_irqrestore(&chan->irqlock, flags);
8218 - ret = get_ipu_resources(chan);
8220 - goto out_free_dmabuf1;
8226 - free_dma_buf(priv, &ctx->rot_intermediate[1]);
8227 - spin_lock_irqsave(&chan->irqlock, flags);
8228 - list_del(&ctx->list);
8229 - spin_unlock_irqrestore(&chan->irqlock, flags);
8231 - free_dma_buf(priv, &ctx->rot_intermediate[0]);
8234 - return ERR_PTR(ret);
8236 -EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
8239 - * Carry out a single image conversion run. Only the physaddr's of the input
8240 - * and output image buffers are needed. The conversion context must have
8241 - * been created previously with ipu_image_convert_prepare().
8243 -int ipu_image_convert_queue(struct ipu_image_convert_run *run)
8245 - struct ipu_image_convert_chan *chan;
8246 - struct ipu_image_convert_priv *priv;
8247 - struct ipu_image_convert_ctx *ctx;
8248 - unsigned long flags;
8251 - if (!run || !run->ctx || !run->in_phys || !run->out_phys)
8256 - priv = chan->priv;
8258 - dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
8259 - chan->ic_task, ctx, run);
8261 - INIT_LIST_HEAD(&run->list);
8263 - spin_lock_irqsave(&chan->irqlock, flags);
8265 - if (ctx->aborting) {
8270 - list_add_tail(&run->list, &chan->pending_q);
8272 - if (!chan->current_run) {
8273 - ret = do_run(run);
8275 - chan->current_run = NULL;
8278 - spin_unlock_irqrestore(&chan->irqlock, flags);
8281 -EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
8283 -/* Abort any active or pending conversions for this context */
8284 -static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
8286 - struct ipu_image_convert_chan *chan = ctx->chan;
8287 - struct ipu_image_convert_priv *priv = chan->priv;
8288 - struct ipu_image_convert_run *run, *active_run, *tmp;
8289 - unsigned long flags;
8290 - int run_count, ret;
8292 - spin_lock_irqsave(&chan->irqlock, flags);
8294 - /* move all remaining pending runs in this context to done_q */
8295 - list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
8296 - if (run->ctx != ctx)
8298 - run->status = -EIO;
8299 - list_move_tail(&run->list, &chan->done_q);
8302 - run_count = get_run_count(ctx, &chan->done_q);
8303 - active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
8304 - chan->current_run : NULL;
8307 - reinit_completion(&ctx->aborted);
8309 - ctx->aborting = true;
8311 - spin_unlock_irqrestore(&chan->irqlock, flags);
8313 - if (!run_count && !active_run) {
8314 - dev_dbg(priv->ipu->dev,
8315 - "%s: task %u: no abort needed for ctx %p\n",
8316 - __func__, chan->ic_task, ctx);
8320 - if (!active_run) {
8321 - empty_done_q(chan);
8325 - dev_dbg(priv->ipu->dev,
8326 - "%s: task %u: wait for completion: %d runs\n",
8327 - __func__, chan->ic_task, run_count);
8329 - ret = wait_for_completion_timeout(&ctx->aborted,
8330 - msecs_to_jiffies(10000));
8332 - dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
8337 -void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
8339 - __ipu_image_convert_abort(ctx);
8340 - ctx->aborting = false;
8342 -EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
8344 -/* Unprepare image conversion context */
8345 -void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
8347 - struct ipu_image_convert_chan *chan = ctx->chan;
8348 - struct ipu_image_convert_priv *priv = chan->priv;
8349 - unsigned long flags;
8352 - /* make sure no runs are hanging around */
8353 - __ipu_image_convert_abort(ctx);
8355 - dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
8356 - chan->ic_task, ctx);
8358 - spin_lock_irqsave(&chan->irqlock, flags);
8360 - list_del(&ctx->list);
8362 - put_res = list_empty(&chan->ctx_list);
8364 - spin_unlock_irqrestore(&chan->irqlock, flags);
8367 - release_ipu_resources(chan);
8369 - free_dma_buf(priv, &ctx->rot_intermediate[1]);
8370 - free_dma_buf(priv, &ctx->rot_intermediate[0]);
8374 -EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
8377 - * "Canned" asynchronous single image conversion. Allocates and returns
8378 - * a new conversion run. On successful return the caller must free the
8379 - * run and call ipu_image_convert_unprepare() after conversion completes.
8381 -struct ipu_image_convert_run *
8382 -ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
8383 - struct ipu_image *in, struct ipu_image *out,
8384 - enum ipu_rotate_mode rot_mode,
8385 - ipu_image_convert_cb_t complete,
8386 - void *complete_context)
8388 - struct ipu_image_convert_ctx *ctx;
8389 - struct ipu_image_convert_run *run;
8392 - ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
8393 - complete, complete_context);
8395 - return ERR_CAST(ctx);
8397 - run = kzalloc(sizeof(*run), GFP_KERNEL);
8399 - ipu_image_convert_unprepare(ctx);
8400 - return ERR_PTR(-ENOMEM);
8404 - run->in_phys = in->phys0;
8405 - run->out_phys = out->phys0;
8407 - ret = ipu_image_convert_queue(run);
8409 - ipu_image_convert_unprepare(ctx);
8411 - return ERR_PTR(ret);
8416 -EXPORT_SYMBOL_GPL(ipu_image_convert);
8418 -/* "Canned" synchronous single image conversion */
8419 -static void image_convert_sync_complete(struct ipu_image_convert_run *run,
8422 - struct completion *comp = data;
8427 -int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
8428 - struct ipu_image *in, struct ipu_image *out,
8429 - enum ipu_rotate_mode rot_mode)
8431 - struct ipu_image_convert_run *run;
8432 - struct completion comp;
8435 - init_completion(&comp);
8437 - run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
8438 - image_convert_sync_complete, &comp);
8440 - return PTR_ERR(run);
8442 - ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
8443 - ret = (ret == 0) ? -ETIMEDOUT : 0;
8445 - ipu_image_convert_unprepare(run->ctx);
8450 -EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
8452 -int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
8454 - struct ipu_image_convert_priv *priv;
8457 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
8461 - ipu->image_convert_priv = priv;
8464 - for (i = 0; i < IC_NUM_TASKS; i++) {
8465 - struct ipu_image_convert_chan *chan = &priv->chan[i];
8467 - chan->ic_task = i;
8468 - chan->priv = priv;
8469 - chan->dma_ch = &image_convert_dma_chan[i];
8470 - chan->out_eof_irq = -1;
8471 - chan->rot_out_eof_irq = -1;
8473 - spin_lock_init(&chan->irqlock);
8474 - INIT_LIST_HEAD(&chan->ctx_list);
8475 - INIT_LIST_HEAD(&chan->pending_q);
8476 - INIT_LIST_HEAD(&chan->done_q);
8482 -void ipu_image_convert_exit(struct ipu_soc *ipu)
8485 --- a/drivers/gpu/imx/ipu-v3/ipu-pre.c
8488 -// SPDX-License-Identifier: GPL-2.0-only
8490 - * Copyright (c) 2017 Lucas Stach, Pengutronix
8493 -#include <drm/drm_fourcc.h>
8494 -#include <linux/clk.h>
8495 -#include <linux/err.h>
8496 -#include <linux/genalloc.h>
8497 -#include <linux/module.h>
8498 -#include <linux/of.h>
8499 -#include <linux/platform_device.h>
8500 -#include <video/imx-ipu-v3.h>
8502 -#include "ipu-prv.h"
8504 -#define IPU_PRE_MAX_WIDTH 2048
8505 -#define IPU_PRE_NUM_SCANLINES 8
8507 -#define IPU_PRE_CTRL 0x000
8508 -#define IPU_PRE_CTRL_SET 0x004
8509 -#define IPU_PRE_CTRL_ENABLE (1 << 0)
8510 -#define IPU_PRE_CTRL_BLOCK_EN (1 << 1)
8511 -#define IPU_PRE_CTRL_BLOCK_16 (1 << 2)
8512 -#define IPU_PRE_CTRL_SDW_UPDATE (1 << 4)
8513 -#define IPU_PRE_CTRL_VFLIP (1 << 5)
8514 -#define IPU_PRE_CTRL_SO (1 << 6)
8515 -#define IPU_PRE_CTRL_INTERLACED_FIELD (1 << 7)
8516 -#define IPU_PRE_CTRL_HANDSHAKE_EN (1 << 8)
8517 -#define IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v) ((v & 0x3) << 9)
8518 -#define IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN (1 << 11)
8519 -#define IPU_PRE_CTRL_EN_REPEAT (1 << 28)
8520 -#define IPU_PRE_CTRL_TPR_REST_SEL (1 << 29)
8521 -#define IPU_PRE_CTRL_CLKGATE (1 << 30)
8522 -#define IPU_PRE_CTRL_SFTRST (1 << 31)
8524 -#define IPU_PRE_CUR_BUF 0x030
8526 -#define IPU_PRE_NEXT_BUF 0x040
8528 -#define IPU_PRE_TPR_CTRL 0x070
8529 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT(v) ((v & 0xff) << 0)
8530 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK 0xff
8531 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT (1 << 0)
8532 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF (1 << 4)
8533 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF (1 << 5)
8534 -#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED (1 << 6)
8536 -#define IPU_PRE_PREFETCH_ENG_CTRL 0x080
8537 -#define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0)
8538 -#define IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v) ((v & 0x7) << 1)
8539 -#define IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
8540 -#define IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v) ((v & 0x7) << 8)
8541 -#define IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS (1 << 11)
8542 -#define IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE (1 << 12)
8543 -#define IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP (1 << 14)
8544 -#define IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN (1 << 15)
8546 -#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE 0x0a0
8547 -#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v) ((v & 0xffff) << 0)
8548 -#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v) ((v & 0xffff) << 16)
8550 -#define IPU_PRE_PREFETCH_ENG_PITCH 0x0d0
8551 -#define IPU_PRE_PREFETCH_ENG_PITCH_Y(v) ((v & 0xffff) << 0)
8552 -#define IPU_PRE_PREFETCH_ENG_PITCH_UV(v) ((v & 0xffff) << 16)
8554 -#define IPU_PRE_STORE_ENG_CTRL 0x110
8555 -#define IPU_PRE_STORE_ENG_CTRL_STORE_EN (1 << 0)
8556 -#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1)
8557 -#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
8559 -#define IPU_PRE_STORE_ENG_STATUS 0x120
8560 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK 0xffff
8561 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
8562 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK 0x3fff
8563 -#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
8564 -#define IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL (1 << 30)
8565 -#define IPU_PRE_STORE_ENG_STATUS_STORE_FIELD (1 << 31)
8567 -#define IPU_PRE_STORE_ENG_SIZE 0x130
8568 -#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0)
8569 -#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16)
8571 -#define IPU_PRE_STORE_ENG_PITCH 0x140
8572 -#define IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v) ((v & 0xffff) << 0)
8574 -#define IPU_PRE_STORE_ENG_ADDR 0x150
8577 - struct list_head list;
8578 - struct device *dev;
8580 - void __iomem *regs;
8581 - struct clk *clk_axi;
8582 - struct gen_pool *iram;
8584 - dma_addr_t buffer_paddr;
8585 - void *buffer_virt;
8587 - unsigned int safe_window_end;
8588 - unsigned int last_bufaddr;
8591 -static DEFINE_MUTEX(ipu_pre_list_mutex);
8592 -static LIST_HEAD(ipu_pre_list);
8593 -static int available_pres;
8595 -int ipu_pre_get_available_count(void)
8597 - return available_pres;
8601 -ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
8603 - struct device_node *pre_node = of_parse_phandle(dev->of_node,
8605 - struct ipu_pre *pre;
8607 - mutex_lock(&ipu_pre_list_mutex);
8608 - list_for_each_entry(pre, &ipu_pre_list, list) {
8609 - if (pre_node == pre->dev->of_node) {
8610 - mutex_unlock(&ipu_pre_list_mutex);
8611 - device_link_add(dev, pre->dev,
8612 - DL_FLAG_AUTOREMOVE_CONSUMER);
8613 - of_node_put(pre_node);
8617 - mutex_unlock(&ipu_pre_list_mutex);
8619 - of_node_put(pre_node);
8624 -int ipu_pre_get(struct ipu_pre *pre)
8631 - /* first get the engine out of reset and remove clock gating */
8632 - writel(0, pre->regs + IPU_PRE_CTRL);
8634 - /* init defaults that should be applied to all streams */
8635 - val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
8636 - IPU_PRE_CTRL_HANDSHAKE_EN |
8637 - IPU_PRE_CTRL_TPR_REST_SEL |
8638 - IPU_PRE_CTRL_SDW_UPDATE;
8639 - writel(val, pre->regs + IPU_PRE_CTRL);
8641 - pre->in_use = true;
8645 -void ipu_pre_put(struct ipu_pre *pre)
8647 - writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
8649 - pre->in_use = false;
8652 -void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
8653 - unsigned int height, unsigned int stride, u32 format,
8654 - uint64_t modifier, unsigned int bufaddr)
8656 - const struct drm_format_info *info = drm_format_info(format);
8657 - u32 active_bpp = info->cpp[0] >> 1;
8660 - /* calculate safe window for ctrl register updates */
8661 - if (modifier == DRM_FORMAT_MOD_LINEAR)
8662 - pre->safe_window_end = height - 2;
8664 - pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
8666 - writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
8667 - writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
8668 - pre->last_bufaddr = bufaddr;
8670 - val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
8671 - IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
8672 - IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
8673 - IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
8674 - IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
8675 - writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
8677 - val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
8678 - IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
8679 - writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
8681 - val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
8682 - writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
8684 - val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
8685 - IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
8686 - IPU_PRE_STORE_ENG_CTRL_STORE_EN;
8687 - writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
8689 - val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
8690 - IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
8691 - writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
8693 - val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
8694 - writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
8696 - writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
8698 - val = readl(pre->regs + IPU_PRE_TPR_CTRL);
8699 - val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
8700 - if (modifier != DRM_FORMAT_MOD_LINEAR) {
8701 - /* only support single buffer formats for now */
8702 - val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
8703 - if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
8704 - val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
8705 - if (info->cpp[0] == 2)
8706 - val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
8708 - writel(val, pre->regs + IPU_PRE_TPR_CTRL);
8710 - val = readl(pre->regs + IPU_PRE_CTRL);
8711 - val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
8712 - IPU_PRE_CTRL_SDW_UPDATE;
8713 - if (modifier == DRM_FORMAT_MOD_LINEAR)
8714 - val &= ~IPU_PRE_CTRL_BLOCK_EN;
8716 - val |= IPU_PRE_CTRL_BLOCK_EN;
8717 - writel(val, pre->regs + IPU_PRE_CTRL);
8720 -void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
8722 - unsigned long timeout = jiffies + msecs_to_jiffies(5);
8723 - unsigned short current_yblock;
8726 - if (bufaddr == pre->last_bufaddr)
8729 - writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
8730 - pre->last_bufaddr = bufaddr;
8733 - if (time_after(jiffies, timeout)) {
8734 - dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
8738 - val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
8740 - (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
8741 - IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
8742 - } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
8744 - writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
8747 -bool ipu_pre_update_pending(struct ipu_pre *pre)
8749 - return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
8750 - IPU_PRE_CTRL_SDW_UPDATE);
8753 -u32 ipu_pre_get_baddr(struct ipu_pre *pre)
8755 - return (u32)pre->buffer_paddr;
8758 -static int ipu_pre_probe(struct platform_device *pdev)
8760 - struct device *dev = &pdev->dev;
8761 - struct resource *res;
8762 - struct ipu_pre *pre;
8764 - pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
8768 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8769 - pre->regs = devm_ioremap_resource(&pdev->dev, res);
8770 - if (IS_ERR(pre->regs))
8771 - return PTR_ERR(pre->regs);
8773 - pre->clk_axi = devm_clk_get(dev, "axi");
8774 - if (IS_ERR(pre->clk_axi))
8775 - return PTR_ERR(pre->clk_axi);
8777 - pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
8779 - return -EPROBE_DEFER;
8782 - * Allocate IRAM buffer with maximum size. This could be made dynamic,
8783 - * but as there is no other user of this IRAM region and we can fit all
8784 - * max sized buffers into it, there is no need yet.
8786 - pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
8787 - IPU_PRE_NUM_SCANLINES * 4,
8788 - &pre->buffer_paddr);
8789 - if (!pre->buffer_virt)
8792 - clk_prepare_enable(pre->clk_axi);
8795 - platform_set_drvdata(pdev, pre);
8796 - mutex_lock(&ipu_pre_list_mutex);
8797 - list_add(&pre->list, &ipu_pre_list);
8799 - mutex_unlock(&ipu_pre_list_mutex);
8804 -static int ipu_pre_remove(struct platform_device *pdev)
8806 - struct ipu_pre *pre = platform_get_drvdata(pdev);
8808 - mutex_lock(&ipu_pre_list_mutex);
8809 - list_del(&pre->list);
8811 - mutex_unlock(&ipu_pre_list_mutex);
8813 - clk_disable_unprepare(pre->clk_axi);
8815 - if (pre->buffer_virt)
8816 - gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
8817 - IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
8821 -static const struct of_device_id ipu_pre_dt_ids[] = {
8822 - { .compatible = "fsl,imx6qp-pre", },
8823 - { /* sentinel */ },
8826 -struct platform_driver ipu_pre_drv = {
8827 - .probe = ipu_pre_probe,
8828 - .remove = ipu_pre_remove,
8830 - .name = "imx-ipu-pre",
8831 - .of_match_table = ipu_pre_dt_ids,
8834 --- a/drivers/gpu/imx/ipu-v3/ipu-prg.c
8837 -// SPDX-License-Identifier: GPL-2.0-only
8839 - * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
8842 -#include <drm/drm_fourcc.h>
8843 -#include <linux/clk.h>
8844 -#include <linux/err.h>
8845 -#include <linux/iopoll.h>
8846 -#include <linux/mfd/syscon.h>
8847 -#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
8848 -#include <linux/module.h>
8849 -#include <linux/of.h>
8850 -#include <linux/platform_device.h>
8851 -#include <linux/pm_runtime.h>
8852 -#include <linux/regmap.h>
8853 -#include <video/imx-ipu-v3.h>
8855 -#include "ipu-prv.h"
8857 -#define IPU_PRG_CTL 0x00
8858 -#define IPU_PRG_CTL_BYPASS(i) (1 << (0 + i))
8859 -#define IPU_PRG_CTL_SOFT_ARID_MASK 0x3
8860 -#define IPU_PRG_CTL_SOFT_ARID_SHIFT(i) (8 + i * 2)
8861 -#define IPU_PRG_CTL_SOFT_ARID(i, v) ((v & 0x3) << (8 + 2 * i))
8862 -#define IPU_PRG_CTL_SO(i) (1 << (16 + i))
8863 -#define IPU_PRG_CTL_VFLIP(i) (1 << (19 + i))
8864 -#define IPU_PRG_CTL_BLOCK_MODE(i) (1 << (22 + i))
8865 -#define IPU_PRG_CTL_CNT_LOAD_EN(i) (1 << (25 + i))
8866 -#define IPU_PRG_CTL_SOFTRST (1 << 30)
8867 -#define IPU_PRG_CTL_SHADOW_EN (1 << 31)
8869 -#define IPU_PRG_STATUS 0x04
8870 -#define IPU_PRG_STATUS_BUFFER0_READY(i) (1 << (0 + i * 2))
8871 -#define IPU_PRG_STATUS_BUFFER1_READY(i) (1 << (1 + i * 2))
8873 -#define IPU_PRG_QOS 0x08
8874 -#define IPU_PRG_QOS_ARID_MASK 0xf
8875 -#define IPU_PRG_QOS_ARID_SHIFT(i) (0 + i * 4)
8877 -#define IPU_PRG_REG_UPDATE 0x0c
8878 -#define IPU_PRG_REG_UPDATE_REG_UPDATE (1 << 0)
8880 -#define IPU_PRG_STRIDE(i) (0x10 + i * 0x4)
8881 -#define IPU_PRG_STRIDE_STRIDE_MASK 0x3fff
8883 -#define IPU_PRG_CROP_LINE 0x1c
8885 -#define IPU_PRG_THD 0x20
8887 -#define IPU_PRG_BADDR(i) (0x24 + i * 0x4)
8889 -#define IPU_PRG_OFFSET(i) (0x30 + i * 0x4)
8891 -#define IPU_PRG_ILO(i) (0x3c + i * 0x4)
8893 -#define IPU_PRG_HEIGHT(i) (0x48 + i * 0x4)
8894 -#define IPU_PRG_HEIGHT_PRE_HEIGHT_MASK 0xfff
8895 -#define IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT 0
8896 -#define IPU_PRG_HEIGHT_IPU_HEIGHT_MASK 0xfff
8897 -#define IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT 16
8899 -struct ipu_prg_channel {
8905 - struct list_head list;
8906 - struct device *dev;
8909 - void __iomem *regs;
8910 - struct clk *clk_ipg, *clk_axi;
8911 - struct regmap *iomuxc_gpr;
8912 - struct ipu_pre *pres[3];
8914 - struct ipu_prg_channel chan[3];
8917 -static DEFINE_MUTEX(ipu_prg_list_mutex);
8918 -static LIST_HEAD(ipu_prg_list);
8921 -ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
8923 - struct device_node *prg_node = of_parse_phandle(dev->of_node,
8925 - struct ipu_prg *prg;
8927 - mutex_lock(&ipu_prg_list_mutex);
8928 - list_for_each_entry(prg, &ipu_prg_list, list) {
8929 - if (prg_node == prg->dev->of_node) {
8930 - mutex_unlock(&ipu_prg_list_mutex);
8931 - device_link_add(dev, prg->dev,
8932 - DL_FLAG_AUTOREMOVE_CONSUMER);
8934 - of_node_put(prg_node);
8938 - mutex_unlock(&ipu_prg_list_mutex);
8940 - of_node_put(prg_node);
8945 -int ipu_prg_max_active_channels(void)
8947 - return ipu_pre_get_available_count();
8949 -EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
8951 -bool ipu_prg_present(struct ipu_soc *ipu)
8953 - if (ipu->prg_priv)
8958 -EXPORT_SYMBOL_GPL(ipu_prg_present);
8960 -bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
8961 - uint64_t modifier)
8963 - const struct drm_format_info *info = drm_format_info(format);
8965 - if (info->num_planes != 1)
8968 - switch (modifier) {
8969 - case DRM_FORMAT_MOD_LINEAR:
8970 - case DRM_FORMAT_MOD_VIVANTE_TILED:
8971 - case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
8977 -EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
8979 -int ipu_prg_enable(struct ipu_soc *ipu)
8981 - struct ipu_prg *prg = ipu->prg_priv;
8986 - return pm_runtime_get_sync(prg->dev);
8988 -EXPORT_SYMBOL_GPL(ipu_prg_enable);
8990 -void ipu_prg_disable(struct ipu_soc *ipu)
8992 - struct ipu_prg *prg = ipu->prg_priv;
8997 - pm_runtime_put(prg->dev);
8999 -EXPORT_SYMBOL_GPL(ipu_prg_disable);
9002 - * The channel configuartion functions below are not thread safe, as they
9003 - * must be only called from the atomic commit path in the DRM driver, which
9004 - * is properly serialized.
9006 -static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
9009 - * This isn't clearly documented in the RM, but IPU to PRG channel
9010 - * assignment is fixed, as only with this mapping the control signals
9013 - switch (ipu_chan) {
9014 - case IPUV3_CHANNEL_MEM_BG_SYNC:
9016 - case IPUV3_CHANNEL_MEM_FG_SYNC:
9018 - case IPUV3_CHANNEL_MEM_DC_SYNC:
9025 -static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
9029 - /* channel 0 is special as it is hardwired to one of the PREs */
9030 - if (prg_chan == 0) {
9031 - ret = ipu_pre_get(prg->pres[0]);
9034 - prg->chan[prg_chan].used_pre = 0;
9038 - for (i = 1; i < 3; i++) {
9039 - ret = ipu_pre_get(prg->pres[i]);
9044 - prg->chan[prg_chan].used_pre = i;
9046 - /* configure the PRE to PRG channel mux */
9047 - shift = (i == 1) ? 12 : 14;
9048 - mux = (prg->id << 1) | (prg_chan - 1);
9049 - regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
9050 - 0x3 << shift, mux << shift);
9052 - /* check other mux, must not point to same channel */
9053 - shift = (i == 1) ? 14 : 12;
9054 - regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
9055 - if (((val >> shift) & 0x3) == mux) {
9056 - regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
9058 - (mux ^ 0x1) << shift);
9066 - dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
9070 -static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
9072 - struct ipu_prg_channel *chan = &prg->chan[prg_chan];
9074 - ipu_pre_put(prg->pres[chan->used_pre]);
9075 - chan->used_pre = -1;
9078 -void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
9080 - int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
9081 - struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
9082 - struct ipu_prg_channel *chan;
9088 - chan = &prg->chan[prg_chan];
9089 - if (!chan->enabled)
9092 - pm_runtime_get_sync(prg->dev);
9094 - val = readl(prg->regs + IPU_PRG_CTL);
9095 - val |= IPU_PRG_CTL_BYPASS(prg_chan);
9096 - writel(val, prg->regs + IPU_PRG_CTL);
9098 - val = IPU_PRG_REG_UPDATE_REG_UPDATE;
9099 - writel(val, prg->regs + IPU_PRG_REG_UPDATE);
9101 - pm_runtime_put(prg->dev);
9103 - ipu_prg_put_pre(prg, prg_chan);
9105 - chan->enabled = false;
9107 -EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
9109 -int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
9110 - unsigned int axi_id, unsigned int width,
9111 - unsigned int height, unsigned int stride,
9112 - u32 format, uint64_t modifier, unsigned long *eba)
9114 - int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
9115 - struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
9116 - struct ipu_prg_channel *chan;
9123 - chan = &prg->chan[prg_chan];
9125 - if (chan->enabled) {
9126 - ipu_pre_update(prg->pres[chan->used_pre], *eba);
9130 - ret = ipu_prg_get_pre(prg, prg_chan);
9134 - ipu_pre_configure(prg->pres[chan->used_pre],
9135 - width, height, stride, format, modifier, *eba);
9138 - pm_runtime_get_sync(prg->dev);
9140 - val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
9141 - writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
9143 - val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
9144 - IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
9145 - ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
9146 - IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
9147 - writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
9149 - val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
9151 - writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
9153 - val = readl(prg->regs + IPU_PRG_CTL);
9154 - /* config AXI ID */
9155 - val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
9156 - IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
9157 - val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
9158 - /* enable channel */
9159 - val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
9160 - writel(val, prg->regs + IPU_PRG_CTL);
9162 - val = IPU_PRG_REG_UPDATE_REG_UPDATE;
9163 - writel(val, prg->regs + IPU_PRG_REG_UPDATE);
9165 - /* wait for both double buffers to be filled */
9166 - readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
9167 - (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
9168 - (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
9171 - pm_runtime_put(prg->dev);
9173 - chan->enabled = true;
9176 -EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
9178 -bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
9180 - int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
9181 - struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
9182 - struct ipu_prg_channel *chan;
9187 - chan = &prg->chan[prg_chan];
9188 - WARN_ON(!chan->enabled);
9190 - return ipu_pre_update_pending(prg->pres[chan->used_pre]);
9192 -EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
9194 -static int ipu_prg_probe(struct platform_device *pdev)
9196 - struct device *dev = &pdev->dev;
9197 - struct resource *res;
9198 - struct ipu_prg *prg;
9202 - prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
9206 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9207 - prg->regs = devm_ioremap_resource(&pdev->dev, res);
9208 - if (IS_ERR(prg->regs))
9209 - return PTR_ERR(prg->regs);
9212 - prg->clk_ipg = devm_clk_get(dev, "ipg");
9213 - if (IS_ERR(prg->clk_ipg))
9214 - return PTR_ERR(prg->clk_ipg);
9216 - prg->clk_axi = devm_clk_get(dev, "axi");
9217 - if (IS_ERR(prg->clk_axi))
9218 - return PTR_ERR(prg->clk_axi);
9221 - syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
9222 - if (IS_ERR(prg->iomuxc_gpr))
9223 - return PTR_ERR(prg->iomuxc_gpr);
9225 - for (i = 0; i < 3; i++) {
9226 - prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
9227 - if (!prg->pres[i])
9228 - return -EPROBE_DEFER;
9231 - ret = clk_prepare_enable(prg->clk_ipg);
9235 - ret = clk_prepare_enable(prg->clk_axi);
9237 - clk_disable_unprepare(prg->clk_ipg);
9241 - /* init to free running mode */
9242 - val = readl(prg->regs + IPU_PRG_CTL);
9243 - val |= IPU_PRG_CTL_SHADOW_EN;
9244 - writel(val, prg->regs + IPU_PRG_CTL);
9246 - /* disable address threshold */
9247 - writel(0xffffffff, prg->regs + IPU_PRG_THD);
9249 - pm_runtime_set_active(dev);
9250 - pm_runtime_enable(dev);
9253 - platform_set_drvdata(pdev, prg);
9254 - mutex_lock(&ipu_prg_list_mutex);
9255 - list_add(&prg->list, &ipu_prg_list);
9256 - mutex_unlock(&ipu_prg_list_mutex);
9261 -static int ipu_prg_remove(struct platform_device *pdev)
9263 - struct ipu_prg *prg = platform_get_drvdata(pdev);
9265 - mutex_lock(&ipu_prg_list_mutex);
9266 - list_del(&prg->list);
9267 - mutex_unlock(&ipu_prg_list_mutex);
9273 -static int prg_suspend(struct device *dev)
9275 - struct ipu_prg *prg = dev_get_drvdata(dev);
9277 - clk_disable_unprepare(prg->clk_axi);
9278 - clk_disable_unprepare(prg->clk_ipg);
9283 -static int prg_resume(struct device *dev)
9285 - struct ipu_prg *prg = dev_get_drvdata(dev);
9288 - ret = clk_prepare_enable(prg->clk_ipg);
9292 - ret = clk_prepare_enable(prg->clk_axi);
9294 - clk_disable_unprepare(prg->clk_ipg);
9302 -static const struct dev_pm_ops prg_pm_ops = {
9303 - SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
9306 -static const struct of_device_id ipu_prg_dt_ids[] = {
9307 - { .compatible = "fsl,imx6qp-prg", },
9308 - { /* sentinel */ },
9311 -struct platform_driver ipu_prg_drv = {
9312 - .probe = ipu_prg_probe,
9313 - .remove = ipu_prg_remove,
9315 - .name = "imx-ipu-prg",
9316 - .pm = &prg_pm_ops,
9317 - .of_match_table = ipu_prg_dt_ids,
9320 --- a/drivers/gpu/imx/ipu-v3/ipu-prv.h
9323 -/* SPDX-License-Identifier: GPL-2.0-or-later */
9325 - * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
9326 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
9328 -#ifndef __IPU_PRV_H__
9329 -#define __IPU_PRV_H__
9333 -#include <linux/types.h>
9334 -#include <linux/device.h>
9335 -#include <linux/clk.h>
9336 -#include <linux/platform_device.h>
9338 -#include <video/imx-ipu-v3.h>
9340 -#define IPU_MCU_T_DEFAULT 8
9341 -#define IPU_CM_IDMAC_REG_OFS 0x00008000
9342 -#define IPU_CM_IC_REG_OFS 0x00020000
9343 -#define IPU_CM_IRT_REG_OFS 0x00028000
9344 -#define IPU_CM_CSI0_REG_OFS 0x00030000
9345 -#define IPU_CM_CSI1_REG_OFS 0x00038000
9346 -#define IPU_CM_SMFC_REG_OFS 0x00050000
9347 -#define IPU_CM_DC_REG_OFS 0x00058000
9348 -#define IPU_CM_DMFC_REG_OFS 0x00060000
9350 -/* Register addresses */
9351 -/* IPU Common registers */
9352 -#define IPU_CM_REG(offset) (offset)
9354 -#define IPU_CONF IPU_CM_REG(0)
9356 -#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0)
9357 -#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4)
9358 -#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8)
9359 -#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac)
9360 -#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0)
9361 -#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4)
9362 -#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8)
9363 -#define IPU_SKIP IPU_CM_REG(0x00bc)
9364 -#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0)
9365 -#define IPU_DISP_GEN IPU_CM_REG(0x00c4)
9366 -#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8)
9367 -#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc)
9368 -#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0)
9369 -#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4)
9370 -#define IPU_SNOOP IPU_CM_REG(0x00d8)
9371 -#define IPU_MEM_RST IPU_CM_REG(0x00dc)
9372 -#define IPU_PM IPU_CM_REG(0x00e0)
9373 -#define IPU_GPR IPU_CM_REG(0x00e4)
9374 -#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
9375 -#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
9376 -#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32))
9377 -#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244)
9378 -#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248)
9379 -#define IPU_SRM_STAT IPU_CM_REG(0x024C)
9380 -#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250)
9381 -#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
9382 -#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
9383 -#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
9384 -#define IPU_CHA_BUF2_RDY(ch) IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
9385 -#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
9386 -#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
9388 -#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n))
9389 -#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n))
9392 -#define DP_S_SRM_MODE_MASK (0x3 << 3)
9393 -#define DP_S_SRM_MODE_NOW (0x3 << 3)
9394 -#define DP_S_SRM_MODE_NEXT_FRAME (0x1 << 3)
9396 -/* FS_PROC_FLOW1 */
9397 -#define FS_PRPENC_ROT_SRC_SEL_MASK (0xf << 0)
9398 -#define FS_PRPENC_ROT_SRC_SEL_ENC (0x7 << 0)
9399 -#define FS_PRPVF_ROT_SRC_SEL_MASK (0xf << 8)
9400 -#define FS_PRPVF_ROT_SRC_SEL_VF (0x8 << 8)
9401 -#define FS_PP_SRC_SEL_MASK (0xf << 12)
9402 -#define FS_PP_ROT_SRC_SEL_MASK (0xf << 16)
9403 -#define FS_PP_ROT_SRC_SEL_PP (0x5 << 16)
9404 -#define FS_VDI1_SRC_SEL_MASK (0x3 << 20)
9405 -#define FS_VDI3_SRC_SEL_MASK (0x3 << 20)
9406 -#define FS_PRP_SRC_SEL_MASK (0xf << 24)
9407 -#define FS_VDI_SRC_SEL_MASK (0x3 << 28)
9408 -#define FS_VDI_SRC_SEL_CSI_DIRECT (0x1 << 28)
9409 -#define FS_VDI_SRC_SEL_VDOA (0x2 << 28)
9411 -/* FS_PROC_FLOW2 */
9412 -#define FS_PRP_ENC_DEST_SEL_MASK (0xf << 0)
9413 -#define FS_PRP_ENC_DEST_SEL_IRT_ENC (0x1 << 0)
9414 -#define FS_PRPVF_DEST_SEL_MASK (0xf << 4)
9415 -#define FS_PRPVF_DEST_SEL_IRT_VF (0x1 << 4)
9416 -#define FS_PRPVF_ROT_DEST_SEL_MASK (0xf << 8)
9417 -#define FS_PP_DEST_SEL_MASK (0xf << 12)
9418 -#define FS_PP_DEST_SEL_IRT_PP (0x3 << 12)
9419 -#define FS_PP_ROT_DEST_SEL_MASK (0xf << 16)
9420 -#define FS_PRPENC_ROT_DEST_SEL_MASK (0xf << 20)
9421 -#define FS_PRP_DEST_SEL_MASK (0xf << 24)
9423 -#define IPU_DI0_COUNTER_RELEASE (1 << 24)
9424 -#define IPU_DI1_COUNTER_RELEASE (1 << 25)
9426 -#define IPU_IDMAC_REG(offset) (offset)
9428 -#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
9429 -#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
9430 -#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c)
9431 -#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
9432 -#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
9433 -#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
9434 -#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024)
9435 -#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028)
9436 -#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c)
9437 -#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030)
9438 -#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034)
9439 -#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
9440 -#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
9442 -#define IPU_NUM_IRQS (32 * 15)
9445 - IPU_CONF_CSI0_EN = (1 << 0),
9446 - IPU_CONF_CSI1_EN = (1 << 1),
9447 - IPU_CONF_IC_EN = (1 << 2),
9448 - IPU_CONF_ROT_EN = (1 << 3),
9449 - IPU_CONF_ISP_EN = (1 << 4),
9450 - IPU_CONF_DP_EN = (1 << 5),
9451 - IPU_CONF_DI0_EN = (1 << 6),
9452 - IPU_CONF_DI1_EN = (1 << 7),
9453 - IPU_CONF_SMFC_EN = (1 << 8),
9454 - IPU_CONF_DC_EN = (1 << 9),
9455 - IPU_CONF_DMFC_EN = (1 << 10),
9457 - IPU_CONF_VDI_EN = (1 << 12),
9459 - IPU_CONF_IDMAC_DIS = (1 << 22),
9461 - IPU_CONF_IC_DMFC_SEL = (1 << 25),
9462 - IPU_CONF_IC_DMFC_SYNC = (1 << 26),
9463 - IPU_CONF_VDI_DMFC_SYNC = (1 << 27),
9465 - IPU_CONF_CSI0_DATA_SOURCE = (1 << 28),
9466 - IPU_CONF_CSI1_DATA_SOURCE = (1 << 29),
9467 - IPU_CONF_IC_INPUT = (1 << 30),
9468 - IPU_CONF_CSI_SEL = (1 << 31),
9471 -struct ipuv3_channel {
9473 - struct ipu_soc *ipu;
9474 - struct list_head list;
9479 -struct ipu_dc_priv;
9480 -struct ipu_dmfc_priv;
9482 -struct ipu_ic_priv;
9484 -struct ipu_image_convert_priv;
9485 -struct ipu_smfc_priv;
9489 -struct ipu_devtype;
9492 - struct device *dev;
9493 - const struct ipu_devtype *devtype;
9494 - enum ipuv3_type ipu_type;
9496 - struct mutex channel_lock;
9497 - struct list_head channels;
9499 - void __iomem *cm_reg;
9500 - void __iomem *idmac_reg;
9509 - struct irq_domain *domain;
9511 - struct ipu_cpmem *cpmem_priv;
9512 - struct ipu_dc_priv *dc_priv;
9513 - struct ipu_dp_priv *dp_priv;
9514 - struct ipu_dmfc_priv *dmfc_priv;
9515 - struct ipu_di *di_priv[2];
9516 - struct ipu_csi *csi_priv[2];
9517 - struct ipu_ic_priv *ic_priv;
9518 - struct ipu_vdi *vdi_priv;
9519 - struct ipu_image_convert_priv *image_convert_priv;
9520 - struct ipu_smfc_priv *smfc_priv;
9521 - struct ipu_prg *prg_priv;
9524 -static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
9526 - return readl(ipu->idmac_reg + offset);
9529 -static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
9532 - writel(value, ipu->idmac_reg + offset);
9535 -void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
9537 -int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
9538 -int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
9540 -bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
9542 -int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
9543 - unsigned long base, u32 module, struct clk *clk_ipu);
9544 -void ipu_csi_exit(struct ipu_soc *ipu, int id);
9546 -int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
9547 - unsigned long base, unsigned long tpmem_base);
9548 -void ipu_ic_exit(struct ipu_soc *ipu);
9550 -int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
9551 - unsigned long base, u32 module);
9552 -void ipu_vdi_exit(struct ipu_soc *ipu);
9554 -int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
9555 -void ipu_image_convert_exit(struct ipu_soc *ipu);
9557 -int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
9558 - unsigned long base, u32 module, struct clk *ipu_clk);
9559 -void ipu_di_exit(struct ipu_soc *ipu, int id);
9561 -int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
9562 - struct clk *ipu_clk);
9563 -void ipu_dmfc_exit(struct ipu_soc *ipu);
9565 -int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
9566 -void ipu_dp_exit(struct ipu_soc *ipu);
9568 -int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
9569 - unsigned long template_base);
9570 -void ipu_dc_exit(struct ipu_soc *ipu);
9572 -int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
9573 -void ipu_cpmem_exit(struct ipu_soc *ipu);
9575 -int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
9576 -void ipu_smfc_exit(struct ipu_soc *ipu);
9578 -struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
9580 -int ipu_pre_get_available_count(void);
9581 -int ipu_pre_get(struct ipu_pre *pre);
9582 -void ipu_pre_put(struct ipu_pre *pre);
9583 -u32 ipu_pre_get_baddr(struct ipu_pre *pre);
9584 -void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
9585 - unsigned int height, unsigned int stride, u32 format,
9586 - uint64_t modifier, unsigned int bufaddr);
9587 -void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
9588 -bool ipu_pre_update_pending(struct ipu_pre *pre);
9590 -struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
9593 -extern struct platform_driver ipu_pre_drv;
9594 -extern struct platform_driver ipu_prg_drv;
9596 -#endif /* __IPU_PRV_H__ */
9597 --- a/drivers/gpu/imx/ipu-v3/ipu-smfc.c
9600 -// SPDX-License-Identifier: GPL-2.0-or-later
9602 - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
9604 -#include <linux/export.h>
9605 -#include <linux/types.h>
9606 -#include <linux/init.h>
9607 -#include <linux/io.h>
9608 -#include <linux/errno.h>
9609 -#include <linux/spinlock.h>
9610 -#include <linux/delay.h>
9611 -#include <linux/clk.h>
9612 -#include <video/imx-ipu-v3.h>
9614 -#include "ipu-prv.h"
9617 - struct ipu_smfc_priv *priv;
9622 -struct ipu_smfc_priv {
9623 - void __iomem *base;
9625 - struct ipu_soc *ipu;
9626 - struct ipu_smfc channel[4];
9630 -/*SMFC Registers */
9631 -#define SMFC_MAP 0x0000
9632 -#define SMFC_WMC 0x0004
9633 -#define SMFC_BS 0x0008
9635 -int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
9637 - struct ipu_smfc_priv *priv = smfc->priv;
9638 - unsigned long flags;
9641 - spin_lock_irqsave(&priv->lock, flags);
9643 - shift = smfc->chno * 4;
9644 - val = readl(priv->base + SMFC_BS);
9645 - val &= ~(0xf << shift);
9646 - val |= burstsize << shift;
9647 - writel(val, priv->base + SMFC_BS);
9649 - spin_unlock_irqrestore(&priv->lock, flags);
9653 -EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
9655 -int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
9657 - struct ipu_smfc_priv *priv = smfc->priv;
9658 - unsigned long flags;
9661 - spin_lock_irqsave(&priv->lock, flags);
9663 - shift = smfc->chno * 3;
9664 - val = readl(priv->base + SMFC_MAP);
9665 - val &= ~(0x7 << shift);
9666 - val |= ((csi_id << 2) | mipi_id) << shift;
9667 - writel(val, priv->base + SMFC_MAP);
9669 - spin_unlock_irqrestore(&priv->lock, flags);
9673 -EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
9675 -int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
9677 - struct ipu_smfc_priv *priv = smfc->priv;
9678 - unsigned long flags;
9681 - spin_lock_irqsave(&priv->lock, flags);
9683 - shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
9684 - val = readl(priv->base + SMFC_WMC);
9685 - val &= ~(0x3f << shift);
9686 - val |= ((clr_level << 3) | set_level) << shift;
9687 - writel(val, priv->base + SMFC_WMC);
9689 - spin_unlock_irqrestore(&priv->lock, flags);
9693 -EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
9695 -int ipu_smfc_enable(struct ipu_smfc *smfc)
9697 - struct ipu_smfc_priv *priv = smfc->priv;
9698 - unsigned long flags;
9700 - spin_lock_irqsave(&priv->lock, flags);
9702 - if (!priv->use_count)
9703 - ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
9705 - priv->use_count++;
9707 - spin_unlock_irqrestore(&priv->lock, flags);
9711 -EXPORT_SYMBOL_GPL(ipu_smfc_enable);
9713 -int ipu_smfc_disable(struct ipu_smfc *smfc)
9715 - struct ipu_smfc_priv *priv = smfc->priv;
9716 - unsigned long flags;
9718 - spin_lock_irqsave(&priv->lock, flags);
9720 - priv->use_count--;
9722 - if (!priv->use_count)
9723 - ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
9725 - if (priv->use_count < 0)
9726 - priv->use_count = 0;
9728 - spin_unlock_irqrestore(&priv->lock, flags);
9732 -EXPORT_SYMBOL_GPL(ipu_smfc_disable);
9734 -struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
9736 - struct ipu_smfc_priv *priv = ipu->smfc_priv;
9737 - struct ipu_smfc *smfc, *ret;
9738 - unsigned long flags;
9741 - return ERR_PTR(-EINVAL);
9743 - smfc = &priv->channel[chno];
9746 - spin_lock_irqsave(&priv->lock, flags);
9748 - if (smfc->inuse) {
9749 - ret = ERR_PTR(-EBUSY);
9753 - smfc->inuse = true;
9755 - spin_unlock_irqrestore(&priv->lock, flags);
9758 -EXPORT_SYMBOL_GPL(ipu_smfc_get);
9760 -void ipu_smfc_put(struct ipu_smfc *smfc)
9762 - struct ipu_smfc_priv *priv = smfc->priv;
9763 - unsigned long flags;
9765 - spin_lock_irqsave(&priv->lock, flags);
9766 - smfc->inuse = false;
9767 - spin_unlock_irqrestore(&priv->lock, flags);
9769 -EXPORT_SYMBOL_GPL(ipu_smfc_put);
9771 -int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
9772 - unsigned long base)
9774 - struct ipu_smfc_priv *priv;
9777 - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
9781 - ipu->smfc_priv = priv;
9782 - spin_lock_init(&priv->lock);
9785 - priv->base = devm_ioremap(dev, base, PAGE_SIZE);
9789 - for (i = 0; i < 4; i++) {
9790 - priv->channel[i].priv = priv;
9791 - priv->channel[i].chno = i;
9794 - pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
9799 -void ipu_smfc_exit(struct ipu_soc *ipu)
9802 --- a/drivers/gpu/imx/ipu-v3/ipu-vdi.c
9805 -// SPDX-License-Identifier: GPL-2.0-or-later
9807 - * Copyright (C) 2012-2016 Mentor Graphics Inc.
9808 - * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
9810 -#include <linux/io.h>
9811 -#include "ipu-prv.h"
9814 - void __iomem *base;
9818 - struct ipu_soc *ipu;
9822 -/* VDI Register Offsets */
9823 -#define VDI_FSIZE 0x0000
9824 -#define VDI_C 0x0004
9826 -/* VDI Register Fields */
9827 -#define VDI_C_CH_420 (0 << 1)
9828 -#define VDI_C_CH_422 (1 << 1)
9829 -#define VDI_C_MOT_SEL_MASK (0x3 << 2)
9830 -#define VDI_C_MOT_SEL_FULL (2 << 2)
9831 -#define VDI_C_MOT_SEL_LOW (1 << 2)
9832 -#define VDI_C_MOT_SEL_MED (0 << 2)
9833 -#define VDI_C_BURST_SIZE1_4 (3 << 4)
9834 -#define VDI_C_BURST_SIZE2_4 (3 << 8)
9835 -#define VDI_C_BURST_SIZE3_4 (3 << 12)
9836 -#define VDI_C_BURST_SIZE_MASK 0xF
9837 -#define VDI_C_BURST_SIZE1_OFFSET 4
9838 -#define VDI_C_BURST_SIZE2_OFFSET 8
9839 -#define VDI_C_BURST_SIZE3_OFFSET 12
9840 -#define VDI_C_VWM1_SET_1 (0 << 16)
9841 -#define VDI_C_VWM1_SET_2 (1 << 16)
9842 -#define VDI_C_VWM1_CLR_2 (1 << 19)
9843 -#define VDI_C_VWM3_SET_1 (0 << 22)
9844 -#define VDI_C_VWM3_SET_2 (1 << 22)
9845 -#define VDI_C_VWM3_CLR_2 (1 << 25)
9846 -#define VDI_C_TOP_FIELD_MAN_1 (1 << 30)
9847 -#define VDI_C_TOP_FIELD_AUTO_1 (1 << 31)
9849 -static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
9851 - return readl(vdi->base + offset);
9854 -static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
9855 - unsigned int offset)
9857 - writel(value, vdi->base + offset);
9860 -void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
9862 - bool top_field_0 = false;
9863 - unsigned long flags;
9867 - case V4L2_FIELD_INTERLACED_TB:
9868 - case V4L2_FIELD_SEQ_TB:
9869 - case V4L2_FIELD_TOP:
9870 - top_field_0 = true;
9872 - case V4L2_FIELD_INTERLACED_BT:
9873 - case V4L2_FIELD_SEQ_BT:
9874 - case V4L2_FIELD_BOTTOM:
9875 - top_field_0 = false;
9878 - top_field_0 = (std & V4L2_STD_525_60) ? true : false;
9882 - spin_lock_irqsave(&vdi->lock, flags);
9884 - reg = ipu_vdi_read(vdi, VDI_C);
9886 - reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
9888 - reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
9889 - ipu_vdi_write(vdi, reg, VDI_C);
9891 - spin_unlock_irqrestore(&vdi->lock, flags);
9893 -EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
9895 -void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
9897 - unsigned long flags;
9900 - spin_lock_irqsave(&vdi->lock, flags);
9902 - reg = ipu_vdi_read(vdi, VDI_C);
9904 - reg &= ~VDI_C_MOT_SEL_MASK;
9906 - switch (motion_sel) {
9908 - reg |= VDI_C_MOT_SEL_MED;
9911 - reg |= VDI_C_MOT_SEL_FULL;
9914 - reg |= VDI_C_MOT_SEL_LOW;
9918 - ipu_vdi_write(vdi, reg, VDI_C);
9920 - spin_unlock_irqrestore(&vdi->lock, flags);
9922 -EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
9924 -void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
9926 - unsigned long flags;
9927 - u32 pixel_fmt, reg;
9929 - spin_lock_irqsave(&vdi->lock, flags);
9931 - reg = ((yres - 1) << 16) | (xres - 1);
9932 - ipu_vdi_write(vdi, reg, VDI_FSIZE);
9935 - * Full motion, only vertical filter is used.
9936 - * Burst size is 4 accesses
9938 - if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
9939 - code == MEDIA_BUS_FMT_UYVY8_1X16 ||
9940 - code == MEDIA_BUS_FMT_YUYV8_2X8 ||
9941 - code == MEDIA_BUS_FMT_YUYV8_1X16)
9942 - pixel_fmt = VDI_C_CH_422;
9944 - pixel_fmt = VDI_C_CH_420;
9946 - reg = ipu_vdi_read(vdi, VDI_C);
9948 - reg |= VDI_C_BURST_SIZE2_4;
9949 - reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
9950 - reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
9951 - ipu_vdi_write(vdi, reg, VDI_C);
9953 - spin_unlock_irqrestore(&vdi->lock, flags);
9955 -EXPORT_SYMBOL_GPL(ipu_vdi_setup);
9957 -void ipu_vdi_unsetup(struct ipu_vdi *vdi)
9959 - unsigned long flags;
9961 - spin_lock_irqsave(&vdi->lock, flags);
9962 - ipu_vdi_write(vdi, 0, VDI_FSIZE);
9963 - ipu_vdi_write(vdi, 0, VDI_C);
9964 - spin_unlock_irqrestore(&vdi->lock, flags);
9966 -EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
9968 -int ipu_vdi_enable(struct ipu_vdi *vdi)
9970 - unsigned long flags;
9972 - spin_lock_irqsave(&vdi->lock, flags);
9974 - if (!vdi->use_count)
9975 - ipu_module_enable(vdi->ipu, vdi->module);
9979 - spin_unlock_irqrestore(&vdi->lock, flags);
9983 -EXPORT_SYMBOL_GPL(ipu_vdi_enable);
9985 -int ipu_vdi_disable(struct ipu_vdi *vdi)
9987 - unsigned long flags;
9989 - spin_lock_irqsave(&vdi->lock, flags);
9991 - if (vdi->use_count) {
9992 - if (!--vdi->use_count)
9993 - ipu_module_disable(vdi->ipu, vdi->module);
9996 - spin_unlock_irqrestore(&vdi->lock, flags);
10000 -EXPORT_SYMBOL_GPL(ipu_vdi_disable);
10002 -struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
10004 - return ipu->vdi_priv;
10006 -EXPORT_SYMBOL_GPL(ipu_vdi_get);
10008 -void ipu_vdi_put(struct ipu_vdi *vdi)
10011 -EXPORT_SYMBOL_GPL(ipu_vdi_put);
10013 -int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
10014 - unsigned long base, u32 module)
10016 - struct ipu_vdi *vdi;
10018 - vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
10022 - ipu->vdi_priv = vdi;
10024 - spin_lock_init(&vdi->lock);
10025 - vdi->module = module;
10026 - vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
10030 - dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
10036 -void ipu_vdi_exit(struct ipu_soc *ipu)
10040 +++ b/drivers/gpu/ipu-v3/Kconfig
10042 +# SPDX-License-Identifier: GPL-2.0-only
10043 +config IMX_IPUV3_CORE
10044 + tristate "IPUv3 core support"
10045 + depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
10046 + depends on DRM || !DRM # if DRM=m, this can't be 'y'
10047 + select BITREVERSE
10048 + select GENERIC_ALLOCATOR if DRM
10049 + select GENERIC_IRQ_CHIP
10051 + Choose this if you have a i.MX5/6 system and want to use the Image
10052 + Processing Unit. This option only enables IPU base support.
10054 +++ b/drivers/gpu/ipu-v3/Makefile
10056 +# SPDX-License-Identifier: GPL-2.0
10057 +obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
10059 +imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
10060 + ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-ic-csc.o \
10061 + ipu-image-convert.o ipu-smfc.o ipu-vdi.o
10064 + imx-ipu-v3-objs += ipu-pre.o ipu-prg.o
10067 +++ b/drivers/gpu/ipu-v3/ipu-common.c
10069 +// SPDX-License-Identifier: GPL-2.0-or-later
10071 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
10072 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
10074 +#include <linux/module.h>
10075 +#include <linux/export.h>
10076 +#include <linux/types.h>
10077 +#include <linux/reset.h>
10078 +#include <linux/platform_device.h>
10079 +#include <linux/err.h>
10080 +#include <linux/spinlock.h>
10081 +#include <linux/delay.h>
10082 +#include <linux/interrupt.h>
10083 +#include <linux/io.h>
10084 +#include <linux/clk.h>
10085 +#include <linux/list.h>
10086 +#include <linux/irq.h>
10087 +#include <linux/irqchip/chained_irq.h>
10088 +#include <linux/irqdomain.h>
10089 +#include <linux/of_device.h>
10090 +#include <linux/of_graph.h>
10092 +#include <drm/drm_fourcc.h>
10094 +#include <video/imx-ipu-v3.h>
10095 +#include "ipu-prv.h"
10097 +static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
10099 + return readl(ipu->cm_reg + offset);
10102 +static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
10104 + writel(value, ipu->cm_reg + offset);
10107 +int ipu_get_num(struct ipu_soc *ipu)
10111 +EXPORT_SYMBOL_GPL(ipu_get_num);
10113 +void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
10117 + val = ipu_cm_read(ipu, IPU_SRM_PRI2);
10118 + val &= ~DP_S_SRM_MODE_MASK;
10119 + val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
10120 + DP_S_SRM_MODE_NOW;
10121 + ipu_cm_write(ipu, val, IPU_SRM_PRI2);
10123 +EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
10125 +enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
10127 + switch (drm_fourcc) {
10128 + case DRM_FORMAT_ARGB1555:
10129 + case DRM_FORMAT_ABGR1555:
10130 + case DRM_FORMAT_RGBA5551:
10131 + case DRM_FORMAT_BGRA5551:
10132 + case DRM_FORMAT_RGB565:
10133 + case DRM_FORMAT_BGR565:
10134 + case DRM_FORMAT_RGB888:
10135 + case DRM_FORMAT_BGR888:
10136 + case DRM_FORMAT_ARGB4444:
10137 + case DRM_FORMAT_XRGB8888:
10138 + case DRM_FORMAT_XBGR8888:
10139 + case DRM_FORMAT_RGBX8888:
10140 + case DRM_FORMAT_BGRX8888:
10141 + case DRM_FORMAT_ARGB8888:
10142 + case DRM_FORMAT_ABGR8888:
10143 + case DRM_FORMAT_RGBA8888:
10144 + case DRM_FORMAT_BGRA8888:
10145 + case DRM_FORMAT_RGB565_A8:
10146 + case DRM_FORMAT_BGR565_A8:
10147 + case DRM_FORMAT_RGB888_A8:
10148 + case DRM_FORMAT_BGR888_A8:
10149 + case DRM_FORMAT_RGBX8888_A8:
10150 + case DRM_FORMAT_BGRX8888_A8:
10151 + return IPUV3_COLORSPACE_RGB;
10152 + case DRM_FORMAT_YUYV:
10153 + case DRM_FORMAT_UYVY:
10154 + case DRM_FORMAT_YUV420:
10155 + case DRM_FORMAT_YVU420:
10156 + case DRM_FORMAT_YUV422:
10157 + case DRM_FORMAT_YVU422:
10158 + case DRM_FORMAT_YUV444:
10159 + case DRM_FORMAT_YVU444:
10160 + case DRM_FORMAT_NV12:
10161 + case DRM_FORMAT_NV21:
10162 + case DRM_FORMAT_NV16:
10163 + case DRM_FORMAT_NV61:
10164 + return IPUV3_COLORSPACE_YUV;
10166 + return IPUV3_COLORSPACE_UNKNOWN;
10169 +EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
10171 +enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
10173 + switch (pixelformat) {
10174 + case V4L2_PIX_FMT_YUV420:
10175 + case V4L2_PIX_FMT_YVU420:
10176 + case V4L2_PIX_FMT_YUV422P:
10177 + case V4L2_PIX_FMT_UYVY:
10178 + case V4L2_PIX_FMT_YUYV:
10179 + case V4L2_PIX_FMT_NV12:
10180 + case V4L2_PIX_FMT_NV21:
10181 + case V4L2_PIX_FMT_NV16:
10182 + case V4L2_PIX_FMT_NV61:
10183 + return IPUV3_COLORSPACE_YUV;
10184 + case V4L2_PIX_FMT_RGB565:
10185 + case V4L2_PIX_FMT_BGR24:
10186 + case V4L2_PIX_FMT_RGB24:
10187 + case V4L2_PIX_FMT_ABGR32:
10188 + case V4L2_PIX_FMT_XBGR32:
10189 + case V4L2_PIX_FMT_BGRA32:
10190 + case V4L2_PIX_FMT_BGRX32:
10191 + case V4L2_PIX_FMT_RGBA32:
10192 + case V4L2_PIX_FMT_RGBX32:
10193 + case V4L2_PIX_FMT_ARGB32:
10194 + case V4L2_PIX_FMT_XRGB32:
10195 + return IPUV3_COLORSPACE_RGB;
10197 + return IPUV3_COLORSPACE_UNKNOWN;
10200 +EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
10202 +bool ipu_pixelformat_is_planar(u32 pixelformat)
10204 + switch (pixelformat) {
10205 + case V4L2_PIX_FMT_YUV420:
10206 + case V4L2_PIX_FMT_YVU420:
10207 + case V4L2_PIX_FMT_YUV422P:
10208 + case V4L2_PIX_FMT_NV12:
10209 + case V4L2_PIX_FMT_NV21:
10210 + case V4L2_PIX_FMT_NV16:
10211 + case V4L2_PIX_FMT_NV61:
10217 +EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
10219 +enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
10221 + switch (mbus_code & 0xf000) {
10223 + return IPUV3_COLORSPACE_RGB;
10225 + return IPUV3_COLORSPACE_YUV;
10227 + return IPUV3_COLORSPACE_UNKNOWN;
10230 +EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
10232 +int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
10234 + switch (pixelformat) {
10235 + case V4L2_PIX_FMT_YUV420:
10236 + case V4L2_PIX_FMT_YVU420:
10237 + case V4L2_PIX_FMT_YUV422P:
10238 + case V4L2_PIX_FMT_NV12:
10239 + case V4L2_PIX_FMT_NV21:
10240 + case V4L2_PIX_FMT_NV16:
10241 + case V4L2_PIX_FMT_NV61:
10243 + * for the planar YUV formats, the stride passed to
10244 + * cpmem must be the stride in bytes of the Y plane.
10245 + * And all the planar YUV formats have an 8-bit
10248 + return (8 * pixel_stride) >> 3;
10249 + case V4L2_PIX_FMT_RGB565:
10250 + case V4L2_PIX_FMT_YUYV:
10251 + case V4L2_PIX_FMT_UYVY:
10252 + return (16 * pixel_stride) >> 3;
10253 + case V4L2_PIX_FMT_BGR24:
10254 + case V4L2_PIX_FMT_RGB24:
10255 + return (24 * pixel_stride) >> 3;
10256 + case V4L2_PIX_FMT_BGR32:
10257 + case V4L2_PIX_FMT_RGB32:
10258 + case V4L2_PIX_FMT_XBGR32:
10259 + case V4L2_PIX_FMT_XRGB32:
10260 + return (32 * pixel_stride) >> 3;
10267 +EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
10269 +int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
10270 + bool hflip, bool vflip)
10274 + switch (degrees) {
10276 + vf = hf = r90 = 0;
10287 + vf = hf = r90 = 1;
10293 + hf ^= (u32)hflip;
10294 + vf ^= (u32)vflip;
10296 + *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
10299 +EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
10301 +int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
10302 + bool hflip, bool vflip)
10306 + r90 = ((u32)mode >> 2) & 0x1;
10307 + hf = ((u32)mode >> 1) & 0x1;
10308 + vf = ((u32)mode >> 0) & 0x1;
10309 + hf ^= (u32)hflip;
10310 + vf ^= (u32)vflip;
10312 + switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
10313 + case IPU_ROTATE_NONE:
10316 + case IPU_ROTATE_90_RIGHT:
10319 + case IPU_ROTATE_180:
10322 + case IPU_ROTATE_90_LEFT:
10331 +EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
10333 +struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
10335 + struct ipuv3_channel *channel;
10337 + dev_dbg(ipu->dev, "%s %d\n", __func__, num);
10340 + return ERR_PTR(-ENODEV);
10342 + mutex_lock(&ipu->channel_lock);
10344 + list_for_each_entry(channel, &ipu->channels, list) {
10345 + if (channel->num == num) {
10346 + channel = ERR_PTR(-EBUSY);
10351 + channel = kzalloc(sizeof(*channel), GFP_KERNEL);
10353 + channel = ERR_PTR(-ENOMEM);
10357 + channel->num = num;
10358 + channel->ipu = ipu;
10359 + list_add(&channel->list, &ipu->channels);
10362 + mutex_unlock(&ipu->channel_lock);
10366 +EXPORT_SYMBOL_GPL(ipu_idmac_get);
10368 +void ipu_idmac_put(struct ipuv3_channel *channel)
10370 + struct ipu_soc *ipu = channel->ipu;
10372 + dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
10374 + mutex_lock(&ipu->channel_lock);
10376 + list_del(&channel->list);
10379 + mutex_unlock(&ipu->channel_lock);
10381 +EXPORT_SYMBOL_GPL(ipu_idmac_put);
10383 +#define idma_mask(ch) (1 << ((ch) & 0x1f))
10386 + * This is an undocumented feature, a write one to a channel bit in
10387 + * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
10388 + * internal current buffer pointer so that transfers start from buffer
10389 + * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
10390 + * only says these are read-only registers). This operation is required
10391 + * for channel linking to work correctly, for instance video capture
10392 + * pipelines that carry out image rotations will fail after the first
10393 + * streaming unless this function is called for each channel before
10394 + * re-enabling the channels.
10396 +static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
10398 + struct ipu_soc *ipu = channel->ipu;
10399 + unsigned int chno = channel->num;
10401 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
10404 +void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
10405 + bool doublebuffer)
10407 + struct ipu_soc *ipu = channel->ipu;
10408 + unsigned long flags;
10411 + spin_lock_irqsave(&ipu->lock, flags);
10413 + reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
10414 + if (doublebuffer)
10415 + reg |= idma_mask(channel->num);
10417 + reg &= ~idma_mask(channel->num);
10418 + ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
10420 + __ipu_idmac_reset_current_buffer(channel);
10422 + spin_unlock_irqrestore(&ipu->lock, flags);
10424 +EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
10426 +static const struct {
10430 +} idmac_lock_en_info[] = {
10431 + { .chnum = 5, .reg = IDMAC_CH_LOCK_EN_1, .shift = 0, },
10432 + { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift = 2, },
10433 + { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift = 4, },
10434 + { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift = 6, },
10435 + { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift = 8, },
10436 + { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
10437 + { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
10438 + { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
10439 + { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
10440 + { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
10441 + { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
10442 + { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift = 0, },
10443 + { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift = 2, },
10444 + { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift = 4, },
10445 + { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift = 6, },
10446 + { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift = 8, },
10447 + { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
10450 +int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
10452 + struct ipu_soc *ipu = channel->ipu;
10453 + unsigned long flags;
10454 + u32 bursts, regval;
10457 + switch (num_bursts) {
10460 + bursts = 0x00; /* locking disabled */
10476 + * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M /
10477 + * i.MX53 channel arbitration locking doesn't seem to work properly.
10478 + * Allow enabling the lock feature on IPUv3H / i.MX6 only.
10480 + if (bursts && ipu->ipu_type != IPUV3H)
10483 + for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
10484 + if (channel->num == idmac_lock_en_info[i].chnum)
10487 + if (i >= ARRAY_SIZE(idmac_lock_en_info))
10490 + spin_lock_irqsave(&ipu->lock, flags);
10492 + regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
10493 + regval &= ~(0x03 << idmac_lock_en_info[i].shift);
10494 + regval |= (bursts << idmac_lock_en_info[i].shift);
10495 + ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
10497 + spin_unlock_irqrestore(&ipu->lock, flags);
10501 +EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
10503 +int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
10505 + unsigned long lock_flags;
10508 + spin_lock_irqsave(&ipu->lock, lock_flags);
10510 + val = ipu_cm_read(ipu, IPU_DISP_GEN);
10512 + if (mask & IPU_CONF_DI0_EN)
10513 + val |= IPU_DI0_COUNTER_RELEASE;
10514 + if (mask & IPU_CONF_DI1_EN)
10515 + val |= IPU_DI1_COUNTER_RELEASE;
10517 + ipu_cm_write(ipu, val, IPU_DISP_GEN);
10519 + val = ipu_cm_read(ipu, IPU_CONF);
10521 + ipu_cm_write(ipu, val, IPU_CONF);
10523 + spin_unlock_irqrestore(&ipu->lock, lock_flags);
10527 +EXPORT_SYMBOL_GPL(ipu_module_enable);
10529 +int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
10531 + unsigned long lock_flags;
10534 + spin_lock_irqsave(&ipu->lock, lock_flags);
10536 + val = ipu_cm_read(ipu, IPU_CONF);
10538 + ipu_cm_write(ipu, val, IPU_CONF);
10540 + val = ipu_cm_read(ipu, IPU_DISP_GEN);
10542 + if (mask & IPU_CONF_DI0_EN)
10543 + val &= ~IPU_DI0_COUNTER_RELEASE;
10544 + if (mask & IPU_CONF_DI1_EN)
10545 + val &= ~IPU_DI1_COUNTER_RELEASE;
10547 + ipu_cm_write(ipu, val, IPU_DISP_GEN);
10549 + spin_unlock_irqrestore(&ipu->lock, lock_flags);
10553 +EXPORT_SYMBOL_GPL(ipu_module_disable);
10555 +int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
10557 + struct ipu_soc *ipu = channel->ipu;
10558 + unsigned int chno = channel->num;
10560 + return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
10562 +EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
10564 +bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
10566 + struct ipu_soc *ipu = channel->ipu;
10567 + unsigned long flags;
10570 + spin_lock_irqsave(&ipu->lock, flags);
10571 + switch (buf_num) {
10573 + reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
10576 + reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
10579 + reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
10582 + spin_unlock_irqrestore(&ipu->lock, flags);
10584 + return ((reg & idma_mask(channel->num)) != 0);
10586 +EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
10588 +void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
10590 + struct ipu_soc *ipu = channel->ipu;
10591 + unsigned int chno = channel->num;
10592 + unsigned long flags;
10594 + spin_lock_irqsave(&ipu->lock, flags);
10596 + /* Mark buffer as ready. */
10597 + if (buf_num == 0)
10598 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
10600 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
10602 + spin_unlock_irqrestore(&ipu->lock, flags);
10604 +EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
10606 +void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
10608 + struct ipu_soc *ipu = channel->ipu;
10609 + unsigned int chno = channel->num;
10610 + unsigned long flags;
10612 + spin_lock_irqsave(&ipu->lock, flags);
10614 + ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
10615 + switch (buf_num) {
10617 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
10620 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
10623 + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
10628 + ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
10630 + spin_unlock_irqrestore(&ipu->lock, flags);
10632 +EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
10634 +int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
10636 + struct ipu_soc *ipu = channel->ipu;
10638 + unsigned long flags;
10640 + spin_lock_irqsave(&ipu->lock, flags);
10642 + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
10643 + val |= idma_mask(channel->num);
10644 + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
10646 + spin_unlock_irqrestore(&ipu->lock, flags);
10650 +EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
10652 +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
10654 + return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
10656 +EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
10658 +int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
10660 + struct ipu_soc *ipu = channel->ipu;
10661 + unsigned long timeout;
10663 + timeout = jiffies + msecs_to_jiffies(ms);
10664 + while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
10665 + idma_mask(channel->num)) {
10666 + if (time_after(jiffies, timeout))
10667 + return -ETIMEDOUT;
10673 +EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
10675 +int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
10677 + struct ipu_soc *ipu = channel->ipu;
10679 + unsigned long flags;
10681 + spin_lock_irqsave(&ipu->lock, flags);
10683 + /* Disable DMA channel(s) */
10684 + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
10685 + val &= ~idma_mask(channel->num);
10686 + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
10688 + __ipu_idmac_reset_current_buffer(channel);
10690 + /* Set channel buffers NOT to be ready */
10691 + ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
10693 + if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
10694 + idma_mask(channel->num)) {
10695 + ipu_cm_write(ipu, idma_mask(channel->num),
10696 + IPU_CHA_BUF0_RDY(channel->num));
10699 + if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
10700 + idma_mask(channel->num)) {
10701 + ipu_cm_write(ipu, idma_mask(channel->num),
10702 + IPU_CHA_BUF1_RDY(channel->num));
10705 + ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
10707 + /* Reset the double buffer */
10708 + val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
10709 + val &= ~idma_mask(channel->num);
10710 + ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
10712 + spin_unlock_irqrestore(&ipu->lock, flags);
10716 +EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
10719 + * The imx6 rev. D TRM says that enabling the WM feature will increase
10720 + * a channel's priority. Refer to Table 36-8 Calculated priority value.
10721 + * The sub-module that is the sink or source for the channel must enable
10722 + * watermark signal for this to take effect (SMFC_WM for instance).
10724 +void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
10726 + struct ipu_soc *ipu = channel->ipu;
10727 + unsigned long flags;
10730 + spin_lock_irqsave(&ipu->lock, flags);
10732 + val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
10734 + val |= 1 << (channel->num % 32);
10736 + val &= ~(1 << (channel->num % 32));
10737 + ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
10739 + spin_unlock_irqrestore(&ipu->lock, flags);
10741 +EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
10743 +static int ipu_memory_reset(struct ipu_soc *ipu)
10745 + unsigned long timeout;
10747 + ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
10749 + timeout = jiffies + msecs_to_jiffies(1000);
10750 + while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
10751 + if (time_after(jiffies, timeout))
10760 + * Set the source mux for the given CSI. Selects either parallel or
10761 + * MIPI CSI2 sources.
10763 +void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
10765 + unsigned long flags;
10768 + mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
10769 + IPU_CONF_CSI0_DATA_SOURCE;
10771 + spin_lock_irqsave(&ipu->lock, flags);
10773 + val = ipu_cm_read(ipu, IPU_CONF);
10778 + ipu_cm_write(ipu, val, IPU_CONF);
10780 + spin_unlock_irqrestore(&ipu->lock, flags);
10782 +EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
10785 + * Set the source mux for the IC. Selects either CSI[01] or the VDI.
10787 +void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
10789 + unsigned long flags;
10792 + spin_lock_irqsave(&ipu->lock, flags);
10794 + val = ipu_cm_read(ipu, IPU_CONF);
10796 + val |= IPU_CONF_IC_INPUT;
10798 + val &= ~IPU_CONF_IC_INPUT;
10801 + val |= IPU_CONF_CSI_SEL;
10803 + val &= ~IPU_CONF_CSI_SEL;
10805 + ipu_cm_write(ipu, val, IPU_CONF);
10807 + spin_unlock_irqrestore(&ipu->lock, flags);
10809 +EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
10812 +/* Frame Synchronization Unit Channel Linking */
10814 +struct fsu_link_reg_info {
10821 +struct fsu_link_info {
10822 + struct fsu_link_reg_info src;
10823 + struct fsu_link_reg_info sink;
10826 +static const struct fsu_link_info fsu_link_info[] = {
10828 + .src = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2,
10829 + FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC },
10830 + .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1,
10831 + FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC },
10833 + .src = { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2,
10834 + FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF },
10835 + .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1,
10836 + FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF },
10838 + .src = { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2,
10839 + FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP },
10840 + .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1,
10841 + FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP },
10843 + .src = { IPUV3_CHANNEL_CSI_DIRECT, 0 },
10844 + .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1,
10845 + FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT },
10849 +static const struct fsu_link_info *find_fsu_link_info(int src, int sink)
10853 + for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) {
10854 + if (src == fsu_link_info[i].src.chno &&
10855 + sink == fsu_link_info[i].sink.chno)
10856 + return &fsu_link_info[i];
10863 + * Links a source channel to a sink channel in the FSU.
10865 +int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch)
10867 + const struct fsu_link_info *link;
10868 + u32 src_reg, sink_reg;
10869 + unsigned long flags;
10871 + link = find_fsu_link_info(src_ch, sink_ch);
10875 + spin_lock_irqsave(&ipu->lock, flags);
10877 + if (link->src.mask) {
10878 + src_reg = ipu_cm_read(ipu, link->src.reg);
10879 + src_reg &= ~link->src.mask;
10880 + src_reg |= link->src.val;
10881 + ipu_cm_write(ipu, src_reg, link->src.reg);
10884 + if (link->sink.mask) {
10885 + sink_reg = ipu_cm_read(ipu, link->sink.reg);
10886 + sink_reg &= ~link->sink.mask;
10887 + sink_reg |= link->sink.val;
10888 + ipu_cm_write(ipu, sink_reg, link->sink.reg);
10891 + spin_unlock_irqrestore(&ipu->lock, flags);
10894 +EXPORT_SYMBOL_GPL(ipu_fsu_link);
10897 + * Unlinks source and sink channels in the FSU.
10899 +int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch)
10901 + const struct fsu_link_info *link;
10902 + u32 src_reg, sink_reg;
10903 + unsigned long flags;
10905 + link = find_fsu_link_info(src_ch, sink_ch);
10909 + spin_lock_irqsave(&ipu->lock, flags);
10911 + if (link->src.mask) {
10912 + src_reg = ipu_cm_read(ipu, link->src.reg);
10913 + src_reg &= ~link->src.mask;
10914 + ipu_cm_write(ipu, src_reg, link->src.reg);
10917 + if (link->sink.mask) {
10918 + sink_reg = ipu_cm_read(ipu, link->sink.reg);
10919 + sink_reg &= ~link->sink.mask;
10920 + ipu_cm_write(ipu, sink_reg, link->sink.reg);
10923 + spin_unlock_irqrestore(&ipu->lock, flags);
10926 +EXPORT_SYMBOL_GPL(ipu_fsu_unlink);
10928 +/* Link IDMAC channels in the FSU */
10929 +int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink)
10931 + return ipu_fsu_link(src->ipu, src->num, sink->num);
10933 +EXPORT_SYMBOL_GPL(ipu_idmac_link);
10935 +/* Unlink IDMAC channels in the FSU */
10936 +int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink)
10938 + return ipu_fsu_unlink(src->ipu, src->num, sink->num);
10940 +EXPORT_SYMBOL_GPL(ipu_idmac_unlink);
10942 +struct ipu_devtype {
10943 + const char *name;
10944 + unsigned long cm_ofs;
10945 + unsigned long cpmem_ofs;
10946 + unsigned long srm_ofs;
10947 + unsigned long tpm_ofs;
10948 + unsigned long csi0_ofs;
10949 + unsigned long csi1_ofs;
10950 + unsigned long ic_ofs;
10951 + unsigned long disp0_ofs;
10952 + unsigned long disp1_ofs;
10953 + unsigned long dc_tmpl_ofs;
10954 + unsigned long vdi_ofs;
10955 + enum ipuv3_type type;
10958 +static struct ipu_devtype ipu_type_imx51 = {
10959 + .name = "IPUv3EX",
10960 + .cm_ofs = 0x1e000000,
10961 + .cpmem_ofs = 0x1f000000,
10962 + .srm_ofs = 0x1f040000,
10963 + .tpm_ofs = 0x1f060000,
10964 + .csi0_ofs = 0x1e030000,
10965 + .csi1_ofs = 0x1e038000,
10966 + .ic_ofs = 0x1e020000,
10967 + .disp0_ofs = 0x1e040000,
10968 + .disp1_ofs = 0x1e048000,
10969 + .dc_tmpl_ofs = 0x1f080000,
10970 + .vdi_ofs = 0x1e068000,
10974 +static struct ipu_devtype ipu_type_imx53 = {
10975 + .name = "IPUv3M",
10976 + .cm_ofs = 0x06000000,
10977 + .cpmem_ofs = 0x07000000,
10978 + .srm_ofs = 0x07040000,
10979 + .tpm_ofs = 0x07060000,
10980 + .csi0_ofs = 0x06030000,
10981 + .csi1_ofs = 0x06038000,
10982 + .ic_ofs = 0x06020000,
10983 + .disp0_ofs = 0x06040000,
10984 + .disp1_ofs = 0x06048000,
10985 + .dc_tmpl_ofs = 0x07080000,
10986 + .vdi_ofs = 0x06068000,
10990 +static struct ipu_devtype ipu_type_imx6q = {
10991 + .name = "IPUv3H",
10992 + .cm_ofs = 0x00200000,
10993 + .cpmem_ofs = 0x00300000,
10994 + .srm_ofs = 0x00340000,
10995 + .tpm_ofs = 0x00360000,
10996 + .csi0_ofs = 0x00230000,
10997 + .csi1_ofs = 0x00238000,
10998 + .ic_ofs = 0x00220000,
10999 + .disp0_ofs = 0x00240000,
11000 + .disp1_ofs = 0x00248000,
11001 + .dc_tmpl_ofs = 0x00380000,
11002 + .vdi_ofs = 0x00268000,
11006 +static const struct of_device_id imx_ipu_dt_ids[] = {
11007 + { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
11008 + { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
11009 + { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
11010 + { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
11011 + { /* sentinel */ }
11013 +MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
11015 +static int ipu_submodules_init(struct ipu_soc *ipu,
11016 + struct platform_device *pdev, unsigned long ipu_base,
11017 + struct clk *ipu_clk)
11021 + struct device *dev = &pdev->dev;
11022 + const struct ipu_devtype *devtype = ipu->devtype;
11024 + ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
11030 + ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
11031 + IPU_CONF_CSI0_EN, ipu_clk);
11037 + ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
11038 + IPU_CONF_CSI1_EN, ipu_clk);
11044 + ret = ipu_ic_init(ipu, dev,
11045 + ipu_base + devtype->ic_ofs,
11046 + ipu_base + devtype->tpm_ofs);
11052 + ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs,
11053 + IPU_CONF_VDI_EN | IPU_CONF_ISP_EN |
11054 + IPU_CONF_IC_INPUT);
11060 + ret = ipu_image_convert_init(ipu, dev);
11062 + unit = "image_convert";
11063 + goto err_image_convert;
11066 + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
11067 + IPU_CONF_DI0_EN, ipu_clk);
11073 + ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
11074 + IPU_CONF_DI1_EN, ipu_clk);
11080 + ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
11081 + IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
11083 + unit = "dc_template";
11087 + ret = ipu_dmfc_init(ipu, dev, ipu_base +
11088 + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
11094 + ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
11100 + ret = ipu_smfc_init(ipu, dev, ipu_base +
11101 + devtype->cm_ofs + IPU_CM_SMFC_REG_OFS);
11110 + ipu_dp_exit(ipu);
11112 + ipu_dmfc_exit(ipu);
11114 + ipu_dc_exit(ipu);
11116 + ipu_di_exit(ipu, 1);
11118 + ipu_di_exit(ipu, 0);
11120 + ipu_image_convert_exit(ipu);
11121 +err_image_convert:
11122 + ipu_vdi_exit(ipu);
11124 + ipu_ic_exit(ipu);
11126 + ipu_csi_exit(ipu, 1);
11128 + ipu_csi_exit(ipu, 0);
11130 + ipu_cpmem_exit(ipu);
11132 + dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
11136 +static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
11138 + unsigned long status;
11141 + for (i = 0; i < num_regs; i++) {
11143 + status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
11144 + status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
11146 + for_each_set_bit(bit, &status, 32) {
11147 + irq = irq_linear_revmap(ipu->domain,
11148 + regs[i] * 32 + bit);
11150 + generic_handle_irq(irq);
11155 +static void ipu_irq_handler(struct irq_desc *desc)
11157 + struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
11158 + struct irq_chip *chip = irq_desc_get_chip(desc);
11159 + static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
11161 + chained_irq_enter(chip, desc);
11163 + ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
11165 + chained_irq_exit(chip, desc);
11168 +static void ipu_err_irq_handler(struct irq_desc *desc)
11170 + struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
11171 + struct irq_chip *chip = irq_desc_get_chip(desc);
11172 + static const int int_reg[] = { 4, 5, 8, 9};
11174 + chained_irq_enter(chip, desc);
11176 + ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
11178 + chained_irq_exit(chip, desc);
11181 +int ipu_map_irq(struct ipu_soc *ipu, int irq)
11185 + virq = irq_linear_revmap(ipu->domain, irq);
11187 + virq = irq_create_mapping(ipu->domain, irq);
11191 +EXPORT_SYMBOL_GPL(ipu_map_irq);
11193 +int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
11194 + enum ipu_channel_irq irq_type)
11196 + return ipu_map_irq(ipu, irq_type + channel->num);
11198 +EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
11200 +static void ipu_submodules_exit(struct ipu_soc *ipu)
11202 + ipu_smfc_exit(ipu);
11203 + ipu_dp_exit(ipu);
11204 + ipu_dmfc_exit(ipu);
11205 + ipu_dc_exit(ipu);
11206 + ipu_di_exit(ipu, 1);
11207 + ipu_di_exit(ipu, 0);
11208 + ipu_image_convert_exit(ipu);
11209 + ipu_vdi_exit(ipu);
11210 + ipu_ic_exit(ipu);
11211 + ipu_csi_exit(ipu, 1);
11212 + ipu_csi_exit(ipu, 0);
11213 + ipu_cpmem_exit(ipu);
11216 +static int platform_remove_devices_fn(struct device *dev, void *unused)
11218 + struct platform_device *pdev = to_platform_device(dev);
11220 + platform_device_unregister(pdev);
11225 +static void platform_device_unregister_children(struct platform_device *pdev)
11227 + device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
11230 +struct ipu_platform_reg {
11231 + struct ipu_client_platformdata pdata;
11232 + const char *name;
11235 +/* These must be in the order of the corresponding device tree port nodes */
11236 +static struct ipu_platform_reg client_reg[] = {
11240 + .dma[0] = IPUV3_CHANNEL_CSI0,
11241 + .dma[1] = -EINVAL,
11243 + .name = "imx-ipuv3-csi",
11247 + .dma[0] = IPUV3_CHANNEL_CSI1,
11248 + .dma[1] = -EINVAL,
11250 + .name = "imx-ipuv3-csi",
11255 + .dp = IPU_DP_FLOW_SYNC_BG,
11256 + .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
11257 + .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
11259 + .name = "imx-ipuv3-crtc",
11265 + .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
11266 + .dma[1] = -EINVAL,
11268 + .name = "imx-ipuv3-crtc",
11272 +static DEFINE_MUTEX(ipu_client_id_mutex);
11273 +static int ipu_client_id;
11275 +static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
11277 + struct device *dev = ipu->dev;
11281 + mutex_lock(&ipu_client_id_mutex);
11282 + id = ipu_client_id;
11283 + ipu_client_id += ARRAY_SIZE(client_reg);
11284 + mutex_unlock(&ipu_client_id_mutex);
11286 + for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
11287 + struct ipu_platform_reg *reg = &client_reg[i];
11288 + struct platform_device *pdev;
11289 + struct device_node *of_node;
11291 + /* Associate subdevice with the corresponding port node */
11292 + of_node = of_graph_get_port_by_id(dev->of_node, i);
11295 + "no port@%d node in %pOF, not using %s%d\n",
11297 + (i / 2) ? "DI" : "CSI", i % 2);
11301 + pdev = platform_device_alloc(reg->name, id++);
11304 + goto err_register;
11307 + pdev->dev.parent = dev;
11309 + reg->pdata.of_node = of_node;
11310 + ret = platform_device_add_data(pdev, ®->pdata,
11311 + sizeof(reg->pdata));
11313 + ret = platform_device_add(pdev);
11315 + platform_device_put(pdev);
11316 + goto err_register;
11323 + platform_device_unregister_children(to_platform_device(dev));
11329 +static int ipu_irq_init(struct ipu_soc *ipu)
11331 + struct irq_chip_generic *gc;
11332 + struct irq_chip_type *ct;
11333 + unsigned long unused[IPU_NUM_IRQS / 32] = {
11334 + 0x400100d0, 0xffe000fd,
11335 + 0x400100d0, 0xffe000fd,
11336 + 0x400100d0, 0xffe000fd,
11337 + 0x4077ffff, 0xffe7e1fd,
11338 + 0x23fffffe, 0x8880fff0,
11339 + 0xf98fe7d0, 0xfff81fff,
11340 + 0x400100d0, 0xffe000fd,
11345 + ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
11346 + &irq_generic_chip_ops, ipu);
11347 + if (!ipu->domain) {
11348 + dev_err(ipu->dev, "failed to add irq domain\n");
11352 + ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
11353 + handle_level_irq, 0, 0, 0);
11355 + dev_err(ipu->dev, "failed to alloc generic irq chips\n");
11356 + irq_domain_remove(ipu->domain);
11360 + /* Mask and clear all interrupts */
11361 + for (i = 0; i < IPU_NUM_IRQS; i += 32) {
11362 + ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
11363 + ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32));
11366 + for (i = 0; i < IPU_NUM_IRQS; i += 32) {
11367 + gc = irq_get_domain_generic_chip(ipu->domain, i);
11368 + gc->reg_base = ipu->cm_reg;
11369 + gc->unused = unused[i / 32];
11370 + ct = gc->chip_types;
11371 + ct->chip.irq_ack = irq_gc_ack_set_bit;
11372 + ct->chip.irq_mask = irq_gc_mask_clr_bit;
11373 + ct->chip.irq_unmask = irq_gc_mask_set_bit;
11374 + ct->regs.ack = IPU_INT_STAT(i / 32);
11375 + ct->regs.mask = IPU_INT_CTRL(i / 32);
11378 + irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
11379 + irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
11385 +static void ipu_irq_exit(struct ipu_soc *ipu)
11389 + irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
11390 + irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
11392 + /* TODO: remove irq_domain_generic_chips */
11394 + for (i = 0; i < IPU_NUM_IRQS; i++) {
11395 + irq = irq_linear_revmap(ipu->domain, i);
11397 + irq_dispose_mapping(irq);
11400 + irq_domain_remove(ipu->domain);
11403 +void ipu_dump(struct ipu_soc *ipu)
11407 + dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
11408 + ipu_cm_read(ipu, IPU_CONF));
11409 + dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
11410 + ipu_idmac_read(ipu, IDMAC_CONF));
11411 + dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
11412 + ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
11413 + dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
11414 + ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
11415 + dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
11416 + ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
11417 + dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
11418 + ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
11419 + dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
11420 + ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
11421 + dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
11422 + ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
11423 + dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
11424 + ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
11425 + dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
11426 + ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
11427 + dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
11428 + ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
11429 + dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
11430 + ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
11431 + dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
11432 + ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
11433 + dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
11434 + ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
11435 + for (i = 0; i < 15; i++)
11436 + dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
11437 + ipu_cm_read(ipu, IPU_INT_CTRL(i)));
11439 +EXPORT_SYMBOL_GPL(ipu_dump);
11441 +static int ipu_probe(struct platform_device *pdev)
11443 + struct device_node *np = pdev->dev.of_node;
11444 + struct ipu_soc *ipu;
11445 + struct resource *res;
11446 + unsigned long ipu_base;
11447 + int ret, irq_sync, irq_err;
11448 + const struct ipu_devtype *devtype;
11450 + devtype = of_device_get_match_data(&pdev->dev);
11454 + irq_sync = platform_get_irq(pdev, 0);
11455 + irq_err = platform_get_irq(pdev, 1);
11456 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
11458 + dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
11459 + irq_sync, irq_err);
11461 + if (!res || irq_sync < 0 || irq_err < 0)
11464 + ipu_base = res->start;
11466 + ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
11470 + ipu->id = of_alias_get_id(np, "ipu");
11474 + if (of_device_is_compatible(np, "fsl,imx6qp-ipu") &&
11475 + IS_ENABLED(CONFIG_DRM)) {
11476 + ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
11477 + "fsl,prg", ipu->id);
11478 + if (!ipu->prg_priv)
11479 + return -EPROBE_DEFER;
11482 + ipu->devtype = devtype;
11483 + ipu->ipu_type = devtype->type;
11485 + spin_lock_init(&ipu->lock);
11486 + mutex_init(&ipu->channel_lock);
11487 + INIT_LIST_HEAD(&ipu->channels);
11489 + dev_dbg(&pdev->dev, "cm_reg: 0x%08lx\n",
11490 + ipu_base + devtype->cm_ofs);
11491 + dev_dbg(&pdev->dev, "idmac: 0x%08lx\n",
11492 + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
11493 + dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n",
11494 + ipu_base + devtype->cpmem_ofs);
11495 + dev_dbg(&pdev->dev, "csi0: 0x%08lx\n",
11496 + ipu_base + devtype->csi0_ofs);
11497 + dev_dbg(&pdev->dev, "csi1: 0x%08lx\n",
11498 + ipu_base + devtype->csi1_ofs);
11499 + dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
11500 + ipu_base + devtype->ic_ofs);
11501 + dev_dbg(&pdev->dev, "disp0: 0x%08lx\n",
11502 + ipu_base + devtype->disp0_ofs);
11503 + dev_dbg(&pdev->dev, "disp1: 0x%08lx\n",
11504 + ipu_base + devtype->disp1_ofs);
11505 + dev_dbg(&pdev->dev, "srm: 0x%08lx\n",
11506 + ipu_base + devtype->srm_ofs);
11507 + dev_dbg(&pdev->dev, "tpm: 0x%08lx\n",
11508 + ipu_base + devtype->tpm_ofs);
11509 + dev_dbg(&pdev->dev, "dc: 0x%08lx\n",
11510 + ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
11511 + dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
11512 + ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
11513 + dev_dbg(&pdev->dev, "dmfc: 0x%08lx\n",
11514 + ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
11515 + dev_dbg(&pdev->dev, "vdi: 0x%08lx\n",
11516 + ipu_base + devtype->vdi_ofs);
11518 + ipu->cm_reg = devm_ioremap(&pdev->dev,
11519 + ipu_base + devtype->cm_ofs, PAGE_SIZE);
11520 + ipu->idmac_reg = devm_ioremap(&pdev->dev,
11521 + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
11524 + if (!ipu->cm_reg || !ipu->idmac_reg)
11527 + ipu->clk = devm_clk_get(&pdev->dev, "bus");
11528 + if (IS_ERR(ipu->clk)) {
11529 + ret = PTR_ERR(ipu->clk);
11530 + dev_err(&pdev->dev, "clk_get failed with %d", ret);
11534 + platform_set_drvdata(pdev, ipu);
11536 + ret = clk_prepare_enable(ipu->clk);
11538 + dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
11542 + ipu->dev = &pdev->dev;
11543 + ipu->irq_sync = irq_sync;
11544 + ipu->irq_err = irq_err;
11546 + ret = device_reset(&pdev->dev);
11548 + dev_err(&pdev->dev, "failed to reset: %d\n", ret);
11549 + goto out_failed_reset;
11551 + ret = ipu_memory_reset(ipu);
11553 + goto out_failed_reset;
11555 + ret = ipu_irq_init(ipu);
11557 + goto out_failed_irq;
11559 + /* Set MCU_T to divide MCU access window into 2 */
11560 + ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
11563 + ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
11565 + goto failed_submodules_init;
11567 + ret = ipu_add_client_devices(ipu, ipu_base);
11569 + dev_err(&pdev->dev, "adding client devices failed with %d\n",
11571 + goto failed_add_clients;
11574 + dev_info(&pdev->dev, "%s probed\n", devtype->name);
11578 +failed_add_clients:
11579 + ipu_submodules_exit(ipu);
11580 +failed_submodules_init:
11581 + ipu_irq_exit(ipu);
11584 + clk_disable_unprepare(ipu->clk);
11588 +static int ipu_remove(struct platform_device *pdev)
11590 + struct ipu_soc *ipu = platform_get_drvdata(pdev);
11592 + platform_device_unregister_children(pdev);
11593 + ipu_submodules_exit(ipu);
11594 + ipu_irq_exit(ipu);
11596 + clk_disable_unprepare(ipu->clk);
11601 +static struct platform_driver imx_ipu_driver = {
11603 + .name = "imx-ipuv3",
11604 + .of_match_table = imx_ipu_dt_ids,
11606 + .probe = ipu_probe,
11607 + .remove = ipu_remove,
11610 +static struct platform_driver * const drivers[] = {
11611 +#if IS_ENABLED(CONFIG_DRM)
11618 +static int __init imx_ipu_init(void)
11620 + return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
11622 +module_init(imx_ipu_init);
11624 +static void __exit imx_ipu_exit(void)
11626 + platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
11628 +module_exit(imx_ipu_exit);
11630 +MODULE_ALIAS("platform:imx-ipuv3");
11631 +MODULE_DESCRIPTION("i.MX IPU v3 driver");
11632 +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
11633 +MODULE_LICENSE("GPL");
11635 +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
11637 +// SPDX-License-Identifier: GPL-2.0-or-later
11639 + * Copyright (C) 2012 Mentor Graphics Inc.
11640 + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
11642 +#include <linux/types.h>
11643 +#include <linux/bitrev.h>
11644 +#include <linux/io.h>
11645 +#include <linux/sizes.h>
11646 +#include <drm/drm_fourcc.h>
11647 +#include "ipu-prv.h"
11649 +struct ipu_cpmem_word {
11654 +struct ipu_ch_param {
11655 + struct ipu_cpmem_word word[2];
11658 +struct ipu_cpmem {
11659 + struct ipu_ch_param __iomem *base;
11663 + struct ipu_soc *ipu;
11666 +#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
11668 +#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
11669 +#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
11670 +#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
11671 +#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
11672 +#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
11673 +#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
11674 +#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
11676 +#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
11677 +#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
11678 +#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
11679 +#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
11680 +#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
11681 +#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
11682 +#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
11683 +#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
11684 +#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
11685 +#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
11686 +#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
11687 +#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
11688 +#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
11689 +#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
11690 +#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
11691 +#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
11692 +#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
11693 +#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
11694 +#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
11695 +#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
11696 +#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
11697 +#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
11698 +#define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3)
11699 +#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
11700 +#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
11701 +#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
11702 +#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
11703 +#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
11704 +#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
11705 +#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
11706 +#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
11707 +#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
11708 +#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
11709 +#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
11710 +#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
11711 +#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
11712 +#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
11713 +#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
11714 +#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
11715 +#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
11716 +#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
11717 +#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
11718 +#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
11719 +#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
11720 +#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
11721 +#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
11722 +#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
11723 +#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
11724 +#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
11725 +#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
11726 +#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
11728 +static inline struct ipu_ch_param __iomem *
11729 +ipu_get_cpmem(struct ipuv3_channel *ch)
11731 + struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
11733 + return cpmem->base + ch->num;
11736 +static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
11738 + struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
11739 + u32 bit = (wbs >> 8) % 160;
11740 + u32 size = wbs & 0xff;
11741 + u32 word = (wbs >> 8) / 160;
11742 + u32 i = bit / 32;
11743 + u32 ofs = bit % 32;
11744 + u32 mask = (1 << size) - 1;
11747 + pr_debug("%s %d %d %d\n", __func__, word, bit , size);
11749 + val = readl(&base->word[word].data[i]);
11750 + val &= ~(mask << ofs);
11752 + writel(val, &base->word[word].data[i]);
11754 + if ((bit + size - 1) / 32 > i) {
11755 + val = readl(&base->word[word].data[i + 1]);
11756 + val &= ~(mask >> (ofs ? (32 - ofs) : 0));
11757 + val |= v >> (ofs ? (32 - ofs) : 0);
11758 + writel(val, &base->word[word].data[i + 1]);
11762 +static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
11764 + struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
11765 + u32 bit = (wbs >> 8) % 160;
11766 + u32 size = wbs & 0xff;
11767 + u32 word = (wbs >> 8) / 160;
11768 + u32 i = bit / 32;
11769 + u32 ofs = bit % 32;
11770 + u32 mask = (1 << size) - 1;
11773 + pr_debug("%s %d %d %d\n", __func__, word, bit , size);
11775 + val = (readl(&base->word[word].data[i]) >> ofs) & mask;
11777 + if ((bit + size - 1) / 32 > i) {
11780 + tmp = readl(&base->word[word].data[i + 1]);
11781 + tmp &= mask >> (ofs ? (32 - ofs) : 0);
11782 + val |= tmp << (ofs ? (32 - ofs) : 0);
11789 + * The V4L2 spec defines packed RGB formats in memory byte order, which from
11790 + * point of view of the IPU corresponds to little-endian words with the first
11791 + * component in the least significant bits.
11792 + * The DRM pixel formats and IPU internal representation are ordered the other
11793 + * way around, with the first named component ordered at the most significant
11794 + * bits. Further, V4L2 formats are not well defined:
11795 + * https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
11796 + * We choose the interpretation which matches GStreamer behavior.
11798 +static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
11800 + switch (pixelformat) {
11801 + case V4L2_PIX_FMT_RGB565:
11803 + * Here we choose the 'corrected' interpretation of RGBP, a
11804 + * little-endian 16-bit word with the red component at the most
11805 + * significant bits:
11806 + * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
11808 + return DRM_FORMAT_RGB565;
11809 + case V4L2_PIX_FMT_BGR24:
11810 + /* B G R <=> [24:0] R:G:B */
11811 + return DRM_FORMAT_RGB888;
11812 + case V4L2_PIX_FMT_RGB24:
11813 + /* R G B <=> [24:0] B:G:R */
11814 + return DRM_FORMAT_BGR888;
11815 + case V4L2_PIX_FMT_BGR32:
11816 + /* B G R A <=> [32:0] A:B:G:R */
11817 + return DRM_FORMAT_XRGB8888;
11818 + case V4L2_PIX_FMT_RGB32:
11819 + /* R G B A <=> [32:0] A:B:G:R */
11820 + return DRM_FORMAT_XBGR8888;
11821 + case V4L2_PIX_FMT_ABGR32:
11822 + /* B G R A <=> [32:0] A:R:G:B */
11823 + return DRM_FORMAT_ARGB8888;
11824 + case V4L2_PIX_FMT_XBGR32:
11825 + /* B G R X <=> [32:0] X:R:G:B */
11826 + return DRM_FORMAT_XRGB8888;
11827 + case V4L2_PIX_FMT_BGRA32:
11828 + /* A B G R <=> [32:0] R:G:B:A */
11829 + return DRM_FORMAT_RGBA8888;
11830 + case V4L2_PIX_FMT_BGRX32:
11831 + /* X B G R <=> [32:0] R:G:B:X */
11832 + return DRM_FORMAT_RGBX8888;
11833 + case V4L2_PIX_FMT_RGBA32:
11834 + /* R G B A <=> [32:0] A:B:G:R */
11835 + return DRM_FORMAT_ABGR8888;
11836 + case V4L2_PIX_FMT_RGBX32:
11837 + /* R G B X <=> [32:0] X:B:G:R */
11838 + return DRM_FORMAT_XBGR8888;
11839 + case V4L2_PIX_FMT_ARGB32:
11840 + /* A R G B <=> [32:0] B:G:R:A */
11841 + return DRM_FORMAT_BGRA8888;
11842 + case V4L2_PIX_FMT_XRGB32:
11843 + /* X R G B <=> [32:0] B:G:R:X */
11844 + return DRM_FORMAT_BGRX8888;
11845 + case V4L2_PIX_FMT_UYVY:
11846 + return DRM_FORMAT_UYVY;
11847 + case V4L2_PIX_FMT_YUYV:
11848 + return DRM_FORMAT_YUYV;
11849 + case V4L2_PIX_FMT_YUV420:
11850 + return DRM_FORMAT_YUV420;
11851 + case V4L2_PIX_FMT_YUV422P:
11852 + return DRM_FORMAT_YUV422;
11853 + case V4L2_PIX_FMT_YVU420:
11854 + return DRM_FORMAT_YVU420;
11855 + case V4L2_PIX_FMT_NV12:
11856 + return DRM_FORMAT_NV12;
11857 + case V4L2_PIX_FMT_NV16:
11858 + return DRM_FORMAT_NV16;
11864 +void ipu_cpmem_zero(struct ipuv3_channel *ch)
11866 + struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
11867 + void __iomem *base = p;
11870 + for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
11871 + writel(0, base + i * sizeof(u32));
11873 +EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
11875 +void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
11877 + ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
11878 + ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
11880 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
11882 +void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
11884 + ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
11886 +EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
11888 +void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
11890 + ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
11892 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
11894 +void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
11896 + struct ipu_soc *ipu = ch->ipu;
11899 + if (ipu->ipu_type == IPUV3EX)
11900 + ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
11902 + val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
11903 + val |= 1 << (ch->num % 32);
11904 + ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
11906 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
11908 +void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
11910 + WARN_ON_ONCE(buf & 0x7);
11913 + ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
11915 + ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
11917 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
11919 +void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
11921 + WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
11923 + ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
11924 + ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
11926 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
11928 +void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
11931 + u32 ilo, sly, sluv;
11933 + if (stride < 0) {
11934 + stride = -stride;
11935 + ilo = 0x100000 - (stride / 8);
11937 + ilo = stride / 8;
11940 + sly = (stride * 2) - 1;
11942 + switch (pixelformat) {
11943 + case V4L2_PIX_FMT_YUV420:
11944 + case V4L2_PIX_FMT_YVU420:
11945 + sluv = stride / 2 - 1;
11947 + case V4L2_PIX_FMT_NV12:
11948 + sluv = stride - 1;
11950 + case V4L2_PIX_FMT_YUV422P:
11951 + sluv = stride - 1;
11953 + case V4L2_PIX_FMT_NV16:
11954 + sluv = stride * 2 - 1;
11961 + ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
11962 + ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
11963 + ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
11965 + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
11967 +EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
11969 +void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
11972 + ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
11974 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
11976 +int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
11978 + return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
11980 +EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
11982 +void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
11984 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
11986 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
11988 +void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
11990 + ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
11992 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
11994 +void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
11995 + enum ipu_rotate_mode rot)
11997 + u32 temp_rot = bitrev8(rot) >> 5;
11999 + ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
12001 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
12003 +int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
12004 + const struct ipu_rgb *rgb)
12006 + int bpp = 0, npb = 0, ro, go, bo, to;
12008 + ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
12009 + go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
12010 + bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
12011 + to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
12013 + ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
12014 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
12015 + ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
12016 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
12017 + ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
12018 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
12020 + if (rgb->transp.length) {
12021 + ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
12022 + rgb->transp.length - 1);
12023 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
12025 + ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
12026 + ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
12027 + rgb->bits_per_pixel);
12030 + switch (rgb->bits_per_pixel) {
12050 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
12051 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
12052 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
12056 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
12058 +int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
12060 + int bpp = 0, npb = 0;
12083 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
12084 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
12085 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
12089 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
12091 +void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
12093 + switch (pixel_format) {
12094 + case V4L2_PIX_FMT_UYVY:
12095 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
12096 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
12097 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
12099 + case V4L2_PIX_FMT_YUYV:
12100 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
12101 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
12102 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
12106 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
12108 +void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
12109 + unsigned int uv_stride,
12110 + unsigned int u_offset, unsigned int v_offset)
12112 + WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
12114 + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
12115 + ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
12116 + ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
12118 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
12120 +static const struct ipu_rgb def_xrgb_32 = {
12121 + .red = { .offset = 16, .length = 8, },
12122 + .green = { .offset = 8, .length = 8, },
12123 + .blue = { .offset = 0, .length = 8, },
12124 + .transp = { .offset = 24, .length = 8, },
12125 + .bits_per_pixel = 32,
12128 +static const struct ipu_rgb def_xbgr_32 = {
12129 + .red = { .offset = 0, .length = 8, },
12130 + .green = { .offset = 8, .length = 8, },
12131 + .blue = { .offset = 16, .length = 8, },
12132 + .transp = { .offset = 24, .length = 8, },
12133 + .bits_per_pixel = 32,
12136 +static const struct ipu_rgb def_rgbx_32 = {
12137 + .red = { .offset = 24, .length = 8, },
12138 + .green = { .offset = 16, .length = 8, },
12139 + .blue = { .offset = 8, .length = 8, },
12140 + .transp = { .offset = 0, .length = 8, },
12141 + .bits_per_pixel = 32,
12144 +static const struct ipu_rgb def_bgrx_32 = {
12145 + .red = { .offset = 8, .length = 8, },
12146 + .green = { .offset = 16, .length = 8, },
12147 + .blue = { .offset = 24, .length = 8, },
12148 + .transp = { .offset = 0, .length = 8, },
12149 + .bits_per_pixel = 32,
12152 +static const struct ipu_rgb def_rgb_24 = {
12153 + .red = { .offset = 16, .length = 8, },
12154 + .green = { .offset = 8, .length = 8, },
12155 + .blue = { .offset = 0, .length = 8, },
12156 + .transp = { .offset = 0, .length = 0, },
12157 + .bits_per_pixel = 24,
12160 +static const struct ipu_rgb def_bgr_24 = {
12161 + .red = { .offset = 0, .length = 8, },
12162 + .green = { .offset = 8, .length = 8, },
12163 + .blue = { .offset = 16, .length = 8, },
12164 + .transp = { .offset = 0, .length = 0, },
12165 + .bits_per_pixel = 24,
12168 +static const struct ipu_rgb def_rgb_16 = {
12169 + .red = { .offset = 11, .length = 5, },
12170 + .green = { .offset = 5, .length = 6, },
12171 + .blue = { .offset = 0, .length = 5, },
12172 + .transp = { .offset = 0, .length = 0, },
12173 + .bits_per_pixel = 16,
12176 +static const struct ipu_rgb def_bgr_16 = {
12177 + .red = { .offset = 0, .length = 5, },
12178 + .green = { .offset = 5, .length = 6, },
12179 + .blue = { .offset = 11, .length = 5, },
12180 + .transp = { .offset = 0, .length = 0, },
12181 + .bits_per_pixel = 16,
12184 +static const struct ipu_rgb def_argb_16 = {
12185 + .red = { .offset = 10, .length = 5, },
12186 + .green = { .offset = 5, .length = 5, },
12187 + .blue = { .offset = 0, .length = 5, },
12188 + .transp = { .offset = 15, .length = 1, },
12189 + .bits_per_pixel = 16,
12192 +static const struct ipu_rgb def_argb_16_4444 = {
12193 + .red = { .offset = 8, .length = 4, },
12194 + .green = { .offset = 4, .length = 4, },
12195 + .blue = { .offset = 0, .length = 4, },
12196 + .transp = { .offset = 12, .length = 4, },
12197 + .bits_per_pixel = 16,
12200 +static const struct ipu_rgb def_abgr_16 = {
12201 + .red = { .offset = 0, .length = 5, },
12202 + .green = { .offset = 5, .length = 5, },
12203 + .blue = { .offset = 10, .length = 5, },
12204 + .transp = { .offset = 15, .length = 1, },
12205 + .bits_per_pixel = 16,
12208 +static const struct ipu_rgb def_rgba_16 = {
12209 + .red = { .offset = 11, .length = 5, },
12210 + .green = { .offset = 6, .length = 5, },
12211 + .blue = { .offset = 1, .length = 5, },
12212 + .transp = { .offset = 0, .length = 1, },
12213 + .bits_per_pixel = 16,
12216 +static const struct ipu_rgb def_bgra_16 = {
12217 + .red = { .offset = 1, .length = 5, },
12218 + .green = { .offset = 6, .length = 5, },
12219 + .blue = { .offset = 11, .length = 5, },
12220 + .transp = { .offset = 0, .length = 1, },
12221 + .bits_per_pixel = 16,
12224 +#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
12225 +#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12226 + (pix->width * ((y) / 2) / 2) + (x) / 2)
12227 +#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12228 + (pix->width * pix->height / 4) + \
12229 + (pix->width * ((y) / 2) / 2) + (x) / 2)
12230 +#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12231 + (pix->width * (y) / 2) + (x) / 2)
12232 +#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12233 + (pix->width * pix->height / 2) + \
12234 + (pix->width * (y) / 2) + (x) / 2)
12235 +#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12236 + (pix->width * ((y) / 2)) + (x))
12237 +#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
12238 + (pix->width * y) + (x))
12240 +#define NUM_ALPHA_CHANNELS 7
12242 +/* See Table 37-12. Alpha channels mapping. */
12243 +static int ipu_channel_albm(int ch_num)
12245 + switch (ch_num) {
12246 + case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: return 0;
12247 + case IPUV3_CHANNEL_G_MEM_IC_PP: return 1;
12248 + case IPUV3_CHANNEL_MEM_FG_SYNC: return 2;
12249 + case IPUV3_CHANNEL_MEM_FG_ASYNC: return 3;
12250 + case IPUV3_CHANNEL_MEM_BG_SYNC: return 4;
12251 + case IPUV3_CHANNEL_MEM_BG_ASYNC: return 5;
12252 + case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
12258 +static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
12260 + struct ipu_soc *ipu = ch->ipu;
12264 + albm = ipu_channel_albm(ch->num);
12268 + ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
12269 + ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
12270 + ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
12272 + val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
12273 + val |= BIT(ch->num);
12274 + ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
12277 +int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
12279 + switch (drm_fourcc) {
12280 + case DRM_FORMAT_YUV420:
12281 + case DRM_FORMAT_YVU420:
12283 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
12285 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12287 + case DRM_FORMAT_YUV422:
12288 + case DRM_FORMAT_YVU422:
12290 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
12292 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12294 + case DRM_FORMAT_YUV444:
12295 + case DRM_FORMAT_YVU444:
12297 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
12299 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12301 + case DRM_FORMAT_NV12:
12303 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
12305 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12307 + case DRM_FORMAT_NV16:
12309 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
12311 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12313 + case DRM_FORMAT_UYVY:
12315 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
12317 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
12319 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12321 + case DRM_FORMAT_YUYV:
12323 + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
12325 + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
12327 + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
12329 + case DRM_FORMAT_ABGR8888:
12330 + case DRM_FORMAT_XBGR8888:
12331 + ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
12333 + case DRM_FORMAT_ARGB8888:
12334 + case DRM_FORMAT_XRGB8888:
12335 + ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
12337 + case DRM_FORMAT_RGBA8888:
12338 + case DRM_FORMAT_RGBX8888:
12339 + case DRM_FORMAT_RGBX8888_A8:
12340 + ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
12342 + case DRM_FORMAT_BGRA8888:
12343 + case DRM_FORMAT_BGRX8888:
12344 + case DRM_FORMAT_BGRX8888_A8:
12345 + ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
12347 + case DRM_FORMAT_BGR888:
12348 + case DRM_FORMAT_BGR888_A8:
12349 + ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
12351 + case DRM_FORMAT_RGB888:
12352 + case DRM_FORMAT_RGB888_A8:
12353 + ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
12355 + case DRM_FORMAT_RGB565:
12356 + case DRM_FORMAT_RGB565_A8:
12357 + ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
12359 + case DRM_FORMAT_BGR565:
12360 + case DRM_FORMAT_BGR565_A8:
12361 + ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
12363 + case DRM_FORMAT_ARGB1555:
12364 + ipu_cpmem_set_format_rgb(ch, &def_argb_16);
12366 + case DRM_FORMAT_ABGR1555:
12367 + ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
12369 + case DRM_FORMAT_RGBA5551:
12370 + ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
12372 + case DRM_FORMAT_BGRA5551:
12373 + ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
12375 + case DRM_FORMAT_ARGB4444:
12376 + ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
12382 + switch (drm_fourcc) {
12383 + case DRM_FORMAT_RGB565_A8:
12384 + case DRM_FORMAT_BGR565_A8:
12385 + case DRM_FORMAT_RGB888_A8:
12386 + case DRM_FORMAT_BGR888_A8:
12387 + case DRM_FORMAT_RGBX8888_A8:
12388 + case DRM_FORMAT_BGRX8888_A8:
12389 + ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
12390 + ipu_cpmem_set_separate_alpha(ch);
12398 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
12400 +int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
12402 + struct v4l2_pix_format *pix = &image->pix;
12403 + int offset, u_offset, v_offset;
12406 + pr_debug("%s: resolution: %dx%d stride: %d\n",
12407 + __func__, pix->width, pix->height,
12408 + pix->bytesperline);
12410 + ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
12411 + ipu_cpmem_set_stride(ch, pix->bytesperline);
12413 + ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
12415 + switch (pix->pixelformat) {
12416 + case V4L2_PIX_FMT_YUV420:
12417 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12418 + u_offset = image->u_offset ?
12419 + image->u_offset : U_OFFSET(pix, image->rect.left,
12420 + image->rect.top) - offset;
12421 + v_offset = image->v_offset ?
12422 + image->v_offset : V_OFFSET(pix, image->rect.left,
12423 + image->rect.top) - offset;
12425 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
12426 + u_offset, v_offset);
12428 + case V4L2_PIX_FMT_YVU420:
12429 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12430 + u_offset = image->u_offset ?
12431 + image->u_offset : V_OFFSET(pix, image->rect.left,
12432 + image->rect.top) - offset;
12433 + v_offset = image->v_offset ?
12434 + image->v_offset : U_OFFSET(pix, image->rect.left,
12435 + image->rect.top) - offset;
12437 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
12438 + u_offset, v_offset);
12440 + case V4L2_PIX_FMT_YUV422P:
12441 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12442 + u_offset = image->u_offset ?
12443 + image->u_offset : U2_OFFSET(pix, image->rect.left,
12444 + image->rect.top) - offset;
12445 + v_offset = image->v_offset ?
12446 + image->v_offset : V2_OFFSET(pix, image->rect.left,
12447 + image->rect.top) - offset;
12449 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
12450 + u_offset, v_offset);
12452 + case V4L2_PIX_FMT_NV12:
12453 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12454 + u_offset = image->u_offset ?
12455 + image->u_offset : UV_OFFSET(pix, image->rect.left,
12456 + image->rect.top) - offset;
12457 + v_offset = image->v_offset ? image->v_offset : 0;
12459 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
12460 + u_offset, v_offset);
12462 + case V4L2_PIX_FMT_NV16:
12463 + offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
12464 + u_offset = image->u_offset ?
12465 + image->u_offset : UV2_OFFSET(pix, image->rect.left,
12466 + image->rect.top) - offset;
12467 + v_offset = image->v_offset ? image->v_offset : 0;
12469 + ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
12470 + u_offset, v_offset);
12472 + case V4L2_PIX_FMT_UYVY:
12473 + case V4L2_PIX_FMT_YUYV:
12474 + case V4L2_PIX_FMT_RGB565:
12475 + offset = image->rect.left * 2 +
12476 + image->rect.top * pix->bytesperline;
12478 + case V4L2_PIX_FMT_RGB32:
12479 + case V4L2_PIX_FMT_BGR32:
12480 + case V4L2_PIX_FMT_ABGR32:
12481 + case V4L2_PIX_FMT_XBGR32:
12482 + case V4L2_PIX_FMT_BGRA32:
12483 + case V4L2_PIX_FMT_BGRX32:
12484 + case V4L2_PIX_FMT_RGBA32:
12485 + case V4L2_PIX_FMT_RGBX32:
12486 + case V4L2_PIX_FMT_ARGB32:
12487 + case V4L2_PIX_FMT_XRGB32:
12488 + offset = image->rect.left * 4 +
12489 + image->rect.top * pix->bytesperline;
12491 + case V4L2_PIX_FMT_RGB24:
12492 + case V4L2_PIX_FMT_BGR24:
12493 + offset = image->rect.left * 3 +
12494 + image->rect.top * pix->bytesperline;
12496 + case V4L2_PIX_FMT_SBGGR8:
12497 + case V4L2_PIX_FMT_SGBRG8:
12498 + case V4L2_PIX_FMT_SGRBG8:
12499 + case V4L2_PIX_FMT_SRGGB8:
12500 + case V4L2_PIX_FMT_GREY:
12501 + offset = image->rect.left + image->rect.top * pix->bytesperline;
12503 + case V4L2_PIX_FMT_SBGGR16:
12504 + case V4L2_PIX_FMT_SGBRG16:
12505 + case V4L2_PIX_FMT_SGRBG16:
12506 + case V4L2_PIX_FMT_SRGGB16:
12507 + case V4L2_PIX_FMT_Y16:
12508 + offset = image->rect.left * 2 +
12509 + image->rect.top * pix->bytesperline;
12512 + /* This should not happen */
12518 + ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
12519 + ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
12523 +EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
12525 +void ipu_cpmem_dump(struct ipuv3_channel *ch)
12527 + struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
12528 + struct ipu_soc *ipu = ch->ipu;
12529 + int chno = ch->num;
12531 + dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
12532 + readl(&p->word[0].data[0]),
12533 + readl(&p->word[0].data[1]),
12534 + readl(&p->word[0].data[2]),
12535 + readl(&p->word[0].data[3]),
12536 + readl(&p->word[0].data[4]));
12537 + dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
12538 + readl(&p->word[1].data[0]),
12539 + readl(&p->word[1].data[1]),
12540 + readl(&p->word[1].data[2]),
12541 + readl(&p->word[1].data[3]),
12542 + readl(&p->word[1].data[4]));
12543 + dev_dbg(ipu->dev, "PFS 0x%x, ",
12544 + ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
12545 + dev_dbg(ipu->dev, "BPP 0x%x, ",
12546 + ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
12547 + dev_dbg(ipu->dev, "NPB 0x%x\n",
12548 + ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
12550 + dev_dbg(ipu->dev, "FW %d, ",
12551 + ipu_ch_param_read_field(ch, IPU_FIELD_FW));
12552 + dev_dbg(ipu->dev, "FH %d, ",
12553 + ipu_ch_param_read_field(ch, IPU_FIELD_FH));
12554 + dev_dbg(ipu->dev, "EBA0 0x%x\n",
12555 + ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
12556 + dev_dbg(ipu->dev, "EBA1 0x%x\n",
12557 + ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
12558 + dev_dbg(ipu->dev, "Stride %d\n",
12559 + ipu_ch_param_read_field(ch, IPU_FIELD_SL));
12560 + dev_dbg(ipu->dev, "scan_order %d\n",
12561 + ipu_ch_param_read_field(ch, IPU_FIELD_SO));
12562 + dev_dbg(ipu->dev, "uv_stride %d\n",
12563 + ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
12564 + dev_dbg(ipu->dev, "u_offset 0x%x\n",
12565 + ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
12566 + dev_dbg(ipu->dev, "v_offset 0x%x\n",
12567 + ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
12569 + dev_dbg(ipu->dev, "Width0 %d+1, ",
12570 + ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
12571 + dev_dbg(ipu->dev, "Width1 %d+1, ",
12572 + ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
12573 + dev_dbg(ipu->dev, "Width2 %d+1, ",
12574 + ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
12575 + dev_dbg(ipu->dev, "Width3 %d+1, ",
12576 + ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
12577 + dev_dbg(ipu->dev, "Offset0 %d, ",
12578 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
12579 + dev_dbg(ipu->dev, "Offset1 %d, ",
12580 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
12581 + dev_dbg(ipu->dev, "Offset2 %d, ",
12582 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
12583 + dev_dbg(ipu->dev, "Offset3 %d\n",
12584 + ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
12586 +EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
12588 +int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
12590 + struct ipu_cpmem *cpmem;
12592 + cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
12596 + ipu->cpmem_priv = cpmem;
12598 + spin_lock_init(&cpmem->lock);
12599 + cpmem->base = devm_ioremap(dev, base, SZ_128K);
12600 + if (!cpmem->base)
12603 + dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
12604 + base, cpmem->base);
12605 + cpmem->ipu = ipu;
12610 +void ipu_cpmem_exit(struct ipu_soc *ipu)
12614 +++ b/drivers/gpu/ipu-v3/ipu-csi.c
12616 +// SPDX-License-Identifier: GPL-2.0-or-later
12618 + * Copyright (C) 2012-2014 Mentor Graphics Inc.
12619 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
12621 +#include <linux/export.h>
12622 +#include <linux/module.h>
12623 +#include <linux/types.h>
12624 +#include <linux/errno.h>
12625 +#include <linux/delay.h>
12626 +#include <linux/io.h>
12627 +#include <linux/err.h>
12628 +#include <linux/platform_device.h>
12629 +#include <linux/videodev2.h>
12630 +#include <uapi/linux/v4l2-mediabus.h>
12631 +#include <linux/clk.h>
12632 +#include <linux/clk-provider.h>
12633 +#include <linux/clkdev.h>
12635 +#include "ipu-prv.h"
12638 + void __iomem *base;
12641 + struct clk *clk_ipu; /* IPU bus clock */
12644 + struct ipu_soc *ipu;
12647 +/* CSI Register Offsets */
12648 +#define CSI_SENS_CONF 0x0000
12649 +#define CSI_SENS_FRM_SIZE 0x0004
12650 +#define CSI_ACT_FRM_SIZE 0x0008
12651 +#define CSI_OUT_FRM_CTRL 0x000c
12652 +#define CSI_TST_CTRL 0x0010
12653 +#define CSI_CCIR_CODE_1 0x0014
12654 +#define CSI_CCIR_CODE_2 0x0018
12655 +#define CSI_CCIR_CODE_3 0x001c
12656 +#define CSI_MIPI_DI 0x0020
12657 +#define CSI_SKIP 0x0024
12658 +#define CSI_CPD_CTRL 0x0028
12659 +#define CSI_CPD_RC(n) (0x002c + ((n)*4))
12660 +#define CSI_CPD_RS(n) (0x004c + ((n)*4))
12661 +#define CSI_CPD_GRC(n) (0x005c + ((n)*4))
12662 +#define CSI_CPD_GRS(n) (0x007c + ((n)*4))
12663 +#define CSI_CPD_GBC(n) (0x008c + ((n)*4))
12664 +#define CSI_CPD_GBS(n) (0x00Ac + ((n)*4))
12665 +#define CSI_CPD_BC(n) (0x00Bc + ((n)*4))
12666 +#define CSI_CPD_BS(n) (0x00Dc + ((n)*4))
12667 +#define CSI_CPD_OFFSET1 0x00ec
12668 +#define CSI_CPD_OFFSET2 0x00f0
12670 +/* CSI Register Fields */
12671 +#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
12672 +#define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700
12673 +#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L
12674 +#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
12675 +#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
12676 +#define CSI_SENS_CONF_DATA_FMT_BAYER 3L
12677 +#define CSI_SENS_CONF_DATA_FMT_RGB565 4L
12678 +#define CSI_SENS_CONF_DATA_FMT_RGB555 5L
12679 +#define CSI_SENS_CONF_DATA_FMT_RGB444 6L
12680 +#define CSI_SENS_CONF_DATA_FMT_JPEG 7L
12682 +#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
12683 +#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
12684 +#define CSI_SENS_CONF_DATA_POL_SHIFT 2
12685 +#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
12686 +#define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070
12687 +#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
12688 +#define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7
12689 +#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11
12690 +#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
12691 +#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
12693 +#define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000
12694 +#define CSI_SENS_CONF_DATA_DEST_SHIFT 24
12695 +#define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000
12696 +#define CSI_SENS_CONF_JPEG8_EN_SHIFT 27
12697 +#define CSI_SENS_CONF_JPEG_EN_SHIFT 28
12698 +#define CSI_SENS_CONF_FORCE_EOF_SHIFT 29
12699 +#define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31
12701 +#define CSI_DATA_DEST_IC 2
12702 +#define CSI_DATA_DEST_IDMAC 4
12704 +#define CSI_CCIR_ERR_DET_EN 0x01000000
12705 +#define CSI_HORI_DOWNSIZE_EN 0x80000000
12706 +#define CSI_VERT_DOWNSIZE_EN 0x40000000
12707 +#define CSI_TEST_GEN_MODE_EN 0x01000000
12709 +#define CSI_HSC_MASK 0x1fff0000
12710 +#define CSI_HSC_SHIFT 16
12711 +#define CSI_VSC_MASK 0x00000fff
12712 +#define CSI_VSC_SHIFT 0
12714 +#define CSI_TEST_GEN_R_MASK 0x000000ff
12715 +#define CSI_TEST_GEN_R_SHIFT 0
12716 +#define CSI_TEST_GEN_G_MASK 0x0000ff00
12717 +#define CSI_TEST_GEN_G_SHIFT 8
12718 +#define CSI_TEST_GEN_B_MASK 0x00ff0000
12719 +#define CSI_TEST_GEN_B_SHIFT 16
12721 +#define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007
12722 +#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0
12723 +#define CSI_SKIP_SMFC_MASK 0x000000f8
12724 +#define CSI_SKIP_SMFC_SHIFT 3
12725 +#define CSI_ID_2_SKIP_MASK 0x00000300
12726 +#define CSI_ID_2_SKIP_SHIFT 8
12728 +#define CSI_COLOR_FIRST_ROW_MASK 0x00000002
12729 +#define CSI_COLOR_FIRST_COMP_MASK 0x00000001
12731 +/* MIPI CSI-2 data types */
12732 +#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
12733 +#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
12734 +#define MIPI_DT_YUV422 0x1e /* UYVY... */
12735 +#define MIPI_DT_RGB444 0x20
12736 +#define MIPI_DT_RGB555 0x21
12737 +#define MIPI_DT_RGB565 0x22
12738 +#define MIPI_DT_RGB666 0x23
12739 +#define MIPI_DT_RGB888 0x24
12740 +#define MIPI_DT_RAW6 0x28
12741 +#define MIPI_DT_RAW7 0x29
12742 +#define MIPI_DT_RAW8 0x2a
12743 +#define MIPI_DT_RAW10 0x2b
12744 +#define MIPI_DT_RAW12 0x2c
12745 +#define MIPI_DT_RAW14 0x2d
12748 + * Bitfield of CSI bus signal polarities and modes.
12750 +struct ipu_csi_bus_config {
12751 + unsigned data_width:4;
12752 + unsigned clk_mode:3;
12753 + unsigned ext_vsync:1;
12754 + unsigned vsync_pol:1;
12755 + unsigned hsync_pol:1;
12756 + unsigned pixclk_pol:1;
12757 + unsigned data_pol:1;
12758 + unsigned sens_clksrc:1;
12759 + unsigned pack_tight:1;
12760 + unsigned force_eof:1;
12761 + unsigned data_en_pol:1;
12763 + unsigned data_fmt;
12764 + unsigned mipi_dt;
12768 + * Enumeration of CSI data bus widths.
12770 +enum ipu_csi_data_width {
12771 + IPU_CSI_DATA_WIDTH_4 = 0,
12772 + IPU_CSI_DATA_WIDTH_8 = 1,
12773 + IPU_CSI_DATA_WIDTH_10 = 3,
12774 + IPU_CSI_DATA_WIDTH_12 = 5,
12775 + IPU_CSI_DATA_WIDTH_16 = 9,
12779 + * Enumeration of CSI clock modes.
12781 +enum ipu_csi_clk_mode {
12782 + IPU_CSI_CLK_MODE_GATED_CLK,
12783 + IPU_CSI_CLK_MODE_NONGATED_CLK,
12784 + IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
12785 + IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
12786 + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
12787 + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
12788 + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
12789 + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
12792 +static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
12794 + return readl(csi->base + offset);
12797 +static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
12800 + writel(value, csi->base + offset);
12804 + * Set mclk division ratio for generating test mode mclk. Only used
12805 + * for test generator.
12807 +static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
12813 + div_ratio = (ipu_clk / pixel_clk) - 1;
12815 + if (div_ratio > 0xFF || div_ratio < 0) {
12816 + dev_err(csi->ipu->dev,
12817 + "value of pixel_clk extends normal range\n");
12821 + temp = ipu_csi_read(csi, CSI_SENS_CONF);
12822 + temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
12823 + ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
12830 + * Find the CSI data format and data width for the given V4L2 media
12831 + * bus pixel format code.
12833 +static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
12834 + enum v4l2_mbus_type mbus_type)
12836 + switch (mbus_code) {
12837 + case MEDIA_BUS_FMT_BGR565_2X8_BE:
12838 + case MEDIA_BUS_FMT_BGR565_2X8_LE:
12839 + case MEDIA_BUS_FMT_RGB565_2X8_BE:
12840 + case MEDIA_BUS_FMT_RGB565_2X8_LE:
12841 + if (mbus_type == V4L2_MBUS_CSI2_DPHY)
12842 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
12844 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12845 + cfg->mipi_dt = MIPI_DT_RGB565;
12846 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12848 + case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
12849 + case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
12850 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
12851 + cfg->mipi_dt = MIPI_DT_RGB444;
12852 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12854 + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
12855 + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
12856 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
12857 + cfg->mipi_dt = MIPI_DT_RGB555;
12858 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12860 + case MEDIA_BUS_FMT_RGB888_1X24:
12861 + case MEDIA_BUS_FMT_BGR888_1X24:
12862 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
12863 + cfg->mipi_dt = MIPI_DT_RGB888;
12864 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12866 + case MEDIA_BUS_FMT_UYVY8_2X8:
12867 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
12868 + cfg->mipi_dt = MIPI_DT_YUV422;
12869 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12871 + case MEDIA_BUS_FMT_YUYV8_2X8:
12872 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
12873 + cfg->mipi_dt = MIPI_DT_YUV422;
12874 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12876 + case MEDIA_BUS_FMT_UYVY8_1X16:
12877 + case MEDIA_BUS_FMT_YUYV8_1X16:
12878 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12879 + cfg->mipi_dt = MIPI_DT_YUV422;
12880 + cfg->data_width = IPU_CSI_DATA_WIDTH_16;
12882 + case MEDIA_BUS_FMT_SBGGR8_1X8:
12883 + case MEDIA_BUS_FMT_SGBRG8_1X8:
12884 + case MEDIA_BUS_FMT_SGRBG8_1X8:
12885 + case MEDIA_BUS_FMT_SRGGB8_1X8:
12886 + case MEDIA_BUS_FMT_Y8_1X8:
12887 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12888 + cfg->mipi_dt = MIPI_DT_RAW8;
12889 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12891 + case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
12892 + case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
12893 + case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
12894 + case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
12895 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
12896 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
12897 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
12898 + case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
12899 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12900 + cfg->mipi_dt = MIPI_DT_RAW10;
12901 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12903 + case MEDIA_BUS_FMT_SBGGR10_1X10:
12904 + case MEDIA_BUS_FMT_SGBRG10_1X10:
12905 + case MEDIA_BUS_FMT_SGRBG10_1X10:
12906 + case MEDIA_BUS_FMT_SRGGB10_1X10:
12907 + case MEDIA_BUS_FMT_Y10_1X10:
12908 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12909 + cfg->mipi_dt = MIPI_DT_RAW10;
12910 + cfg->data_width = IPU_CSI_DATA_WIDTH_10;
12912 + case MEDIA_BUS_FMT_SBGGR12_1X12:
12913 + case MEDIA_BUS_FMT_SGBRG12_1X12:
12914 + case MEDIA_BUS_FMT_SGRBG12_1X12:
12915 + case MEDIA_BUS_FMT_SRGGB12_1X12:
12916 + case MEDIA_BUS_FMT_Y12_1X12:
12917 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
12918 + cfg->mipi_dt = MIPI_DT_RAW12;
12919 + cfg->data_width = IPU_CSI_DATA_WIDTH_12;
12921 + case MEDIA_BUS_FMT_JPEG_1X8:
12923 + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
12924 + cfg->mipi_dt = MIPI_DT_RAW8;
12925 + cfg->data_width = IPU_CSI_DATA_WIDTH_8;
12934 +/* translate alternate field mode based on given standard */
12935 +static inline enum v4l2_field
12936 +ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
12938 + return (field != V4L2_FIELD_ALTERNATE) ? field :
12939 + ((std & V4L2_STD_525_60) ?
12940 + V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
12944 + * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
12946 +static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
12947 + const struct v4l2_mbus_config *mbus_cfg,
12948 + const struct v4l2_mbus_framefmt *mbus_fmt)
12952 + memset(csicfg, 0, sizeof(*csicfg));
12954 + ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
12958 + switch (mbus_cfg->type) {
12959 + case V4L2_MBUS_PARALLEL:
12960 + csicfg->ext_vsync = 1;
12961 + csicfg->vsync_pol = (mbus_cfg->flags &
12962 + V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
12963 + csicfg->hsync_pol = (mbus_cfg->flags &
12964 + V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
12965 + csicfg->pixclk_pol = (mbus_cfg->flags &
12966 + V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
12967 + csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
12969 + case V4L2_MBUS_BT656:
12970 + csicfg->ext_vsync = 0;
12971 + if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
12972 + mbus_fmt->field == V4L2_FIELD_ALTERNATE)
12973 + csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
12975 + csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
12977 + case V4L2_MBUS_CSI2_DPHY:
12979 + * MIPI CSI-2 requires non gated clock mode, all other
12980 + * parameters are not applicable for MIPI CSI-2 bus.
12982 + csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
12985 + /* will never get here, keep compiler quiet */
12993 +ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
12994 + const struct v4l2_mbus_framefmt *infmt,
12995 + const struct v4l2_mbus_framefmt *outfmt,
12998 + enum v4l2_field infield, outfield;
12999 + bool swap_fields;
13001 + /* get translated field type of input and output */
13002 + infield = ipu_csi_translate_field(infmt->field, std);
13003 + outfield = ipu_csi_translate_field(outfmt->field, std);
13006 + * Write the H-V-F codes the CSI will match against the
13007 + * incoming data for start/end of active and blanking
13008 + * field intervals. If input and output field types are
13009 + * sequential but not the same (one is SEQ_BT and the other
13010 + * is SEQ_TB), swap the F-bit so that the CSI will capture
13011 + * field 1 lines before field 0 lines.
13013 + swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
13014 + V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
13015 + infield != outfield);
13017 + if (!swap_fields) {
13019 + * Field0BlankEnd = 110, Field0BlankStart = 010
13020 + * Field0ActiveEnd = 100, Field0ActiveStart = 000
13021 + * Field1BlankEnd = 111, Field1BlankStart = 011
13022 + * Field1ActiveEnd = 101, Field1ActiveStart = 001
13024 + ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
13025 + CSI_CCIR_CODE_1);
13026 + ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
13028 + dev_dbg(csi->ipu->dev, "capture field swap\n");
13030 + /* same as above but with F-bit inverted */
13031 + ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
13032 + CSI_CCIR_CODE_1);
13033 + ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
13036 + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
13042 +int ipu_csi_init_interface(struct ipu_csi *csi,
13043 + const struct v4l2_mbus_config *mbus_cfg,
13044 + const struct v4l2_mbus_framefmt *infmt,
13045 + const struct v4l2_mbus_framefmt *outfmt)
13047 + struct ipu_csi_bus_config cfg;
13048 + unsigned long flags;
13049 + u32 width, height, data = 0;
13053 + ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
13057 + /* set default sensor frame width and height */
13058 + width = infmt->width;
13059 + height = infmt->height;
13060 + if (infmt->field == V4L2_FIELD_ALTERNATE)
13063 + /* Set the CSI_SENS_CONF register remaining fields */
13064 + data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
13065 + cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
13066 + cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
13067 + cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
13068 + cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
13069 + cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
13070 + cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
13071 + cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
13072 + cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
13073 + cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
13074 + cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
13076 + spin_lock_irqsave(&csi->lock, flags);
13078 + ipu_csi_write(csi, data, CSI_SENS_CONF);
13080 + /* Set CCIR registers */
13082 + switch (cfg.clk_mode) {
13083 + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
13084 + ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
13085 + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
13087 + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
13088 + if (width == 720 && height == 480) {
13089 + std = V4L2_STD_NTSC;
13091 + } else if (width == 720 && height == 576) {
13092 + std = V4L2_STD_PAL;
13095 + dev_err(csi->ipu->dev,
13096 + "Unsupported interlaced video mode\n");
13101 + ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
13105 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
13106 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
13107 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
13108 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
13109 + ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
13110 + CSI_CCIR_CODE_1);
13111 + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
13113 + case IPU_CSI_CLK_MODE_GATED_CLK:
13114 + case IPU_CSI_CLK_MODE_NONGATED_CLK:
13115 + ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
13119 + /* Setup sensor frame size */
13120 + ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
13121 + CSI_SENS_FRM_SIZE);
13123 + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
13124 + ipu_csi_read(csi, CSI_SENS_CONF));
13125 + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
13126 + ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
13129 + spin_unlock_irqrestore(&csi->lock, flags);
13133 +EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
13135 +bool ipu_csi_is_interlaced(struct ipu_csi *csi)
13137 + unsigned long flags;
13138 + u32 sensor_protocol;
13140 + spin_lock_irqsave(&csi->lock, flags);
13141 + sensor_protocol =
13142 + (ipu_csi_read(csi, CSI_SENS_CONF) &
13143 + CSI_SENS_CONF_SENS_PRTCL_MASK) >>
13144 + CSI_SENS_CONF_SENS_PRTCL_SHIFT;
13145 + spin_unlock_irqrestore(&csi->lock, flags);
13147 + switch (sensor_protocol) {
13148 + case IPU_CSI_CLK_MODE_GATED_CLK:
13149 + case IPU_CSI_CLK_MODE_NONGATED_CLK:
13150 + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
13151 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
13152 + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
13154 + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
13155 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
13156 + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
13159 + dev_err(csi->ipu->dev,
13160 + "CSI %d sensor protocol unsupported\n", csi->id);
13164 +EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
13166 +void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
13168 + unsigned long flags;
13171 + spin_lock_irqsave(&csi->lock, flags);
13173 + reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
13174 + w->width = (reg & 0xFFFF) + 1;
13175 + w->height = (reg >> 16 & 0xFFFF) + 1;
13177 + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
13178 + w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
13179 + w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
13181 + spin_unlock_irqrestore(&csi->lock, flags);
13183 +EXPORT_SYMBOL_GPL(ipu_csi_get_window);
13185 +void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
13187 + unsigned long flags;
13190 + spin_lock_irqsave(&csi->lock, flags);
13192 + ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
13193 + CSI_ACT_FRM_SIZE);
13195 + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
13196 + reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
13197 + reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
13198 + ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
13200 + spin_unlock_irqrestore(&csi->lock, flags);
13202 +EXPORT_SYMBOL_GPL(ipu_csi_set_window);
13204 +void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert)
13206 + unsigned long flags;
13209 + spin_lock_irqsave(&csi->lock, flags);
13211 + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
13212 + reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN);
13213 + reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) |
13214 + (vert ? CSI_VERT_DOWNSIZE_EN : 0);
13215 + ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
13217 + spin_unlock_irqrestore(&csi->lock, flags);
13219 +EXPORT_SYMBOL_GPL(ipu_csi_set_downsize);
13221 +void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
13222 + u32 r_value, u32 g_value, u32 b_value,
13225 + unsigned long flags;
13226 + u32 ipu_clk = clk_get_rate(csi->clk_ipu);
13229 + spin_lock_irqsave(&csi->lock, flags);
13231 + temp = ipu_csi_read(csi, CSI_TST_CTRL);
13234 + temp &= ~CSI_TEST_GEN_MODE_EN;
13235 + ipu_csi_write(csi, temp, CSI_TST_CTRL);
13237 + /* Set sensb_mclk div_ratio */
13238 + ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
13240 + temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
13241 + CSI_TEST_GEN_B_MASK);
13242 + temp |= CSI_TEST_GEN_MODE_EN;
13243 + temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
13244 + (g_value << CSI_TEST_GEN_G_SHIFT) |
13245 + (b_value << CSI_TEST_GEN_B_SHIFT);
13246 + ipu_csi_write(csi, temp, CSI_TST_CTRL);
13249 + spin_unlock_irqrestore(&csi->lock, flags);
13251 +EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
13253 +int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
13254 + struct v4l2_mbus_framefmt *mbus_fmt)
13256 + struct ipu_csi_bus_config cfg;
13257 + unsigned long flags;
13264 + ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
13268 + spin_lock_irqsave(&csi->lock, flags);
13270 + temp = ipu_csi_read(csi, CSI_MIPI_DI);
13271 + temp &= ~(0xff << (vc * 8));
13272 + temp |= (cfg.mipi_dt << (vc * 8));
13273 + ipu_csi_write(csi, temp, CSI_MIPI_DI);
13275 + spin_unlock_irqrestore(&csi->lock, flags);
13279 +EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
13281 +int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
13282 + u32 max_ratio, u32 id)
13284 + unsigned long flags;
13287 + if (max_ratio > 5 || id > 3)
13290 + spin_lock_irqsave(&csi->lock, flags);
13292 + temp = ipu_csi_read(csi, CSI_SKIP);
13293 + temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
13294 + CSI_SKIP_SMFC_MASK);
13295 + temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
13296 + (id << CSI_ID_2_SKIP_SHIFT) |
13297 + (skip << CSI_SKIP_SMFC_SHIFT);
13298 + ipu_csi_write(csi, temp, CSI_SKIP);
13300 + spin_unlock_irqrestore(&csi->lock, flags);
13304 +EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
13306 +int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
13308 + unsigned long flags;
13309 + u32 csi_sens_conf, dest;
13311 + if (csi_dest == IPU_CSI_DEST_IDMAC)
13312 + dest = CSI_DATA_DEST_IDMAC;
13314 + dest = CSI_DATA_DEST_IC; /* IC or VDIC */
13316 + spin_lock_irqsave(&csi->lock, flags);
13318 + csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
13319 + csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
13320 + csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
13321 + ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
13323 + spin_unlock_irqrestore(&csi->lock, flags);
13327 +EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
13329 +int ipu_csi_enable(struct ipu_csi *csi)
13331 + ipu_module_enable(csi->ipu, csi->module);
13335 +EXPORT_SYMBOL_GPL(ipu_csi_enable);
13337 +int ipu_csi_disable(struct ipu_csi *csi)
13339 + ipu_module_disable(csi->ipu, csi->module);
13343 +EXPORT_SYMBOL_GPL(ipu_csi_disable);
13345 +struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
13347 + unsigned long flags;
13348 + struct ipu_csi *csi, *ret;
13351 + return ERR_PTR(-EINVAL);
13353 + csi = ipu->csi_priv[id];
13356 + spin_lock_irqsave(&csi->lock, flags);
13358 + if (csi->inuse) {
13359 + ret = ERR_PTR(-EBUSY);
13363 + csi->inuse = true;
13365 + spin_unlock_irqrestore(&csi->lock, flags);
13368 +EXPORT_SYMBOL_GPL(ipu_csi_get);
13370 +void ipu_csi_put(struct ipu_csi *csi)
13372 + unsigned long flags;
13374 + spin_lock_irqsave(&csi->lock, flags);
13375 + csi->inuse = false;
13376 + spin_unlock_irqrestore(&csi->lock, flags);
13378 +EXPORT_SYMBOL_GPL(ipu_csi_put);
13380 +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
13381 + unsigned long base, u32 module, struct clk *clk_ipu)
13383 + struct ipu_csi *csi;
13388 + csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
13392 + ipu->csi_priv[id] = csi;
13394 + spin_lock_init(&csi->lock);
13395 + csi->module = module;
13397 + csi->clk_ipu = clk_ipu;
13398 + csi->base = devm_ioremap(dev, base, PAGE_SIZE);
13402 + dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
13403 + id, base, csi->base);
13409 +void ipu_csi_exit(struct ipu_soc *ipu, int id)
13413 +void ipu_csi_dump(struct ipu_csi *csi)
13415 + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n",
13416 + ipu_csi_read(csi, CSI_SENS_CONF));
13417 + dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
13418 + ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
13419 + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n",
13420 + ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
13421 + dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n",
13422 + ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
13423 + dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n",
13424 + ipu_csi_read(csi, CSI_TST_CTRL));
13425 + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n",
13426 + ipu_csi_read(csi, CSI_CCIR_CODE_1));
13427 + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n",
13428 + ipu_csi_read(csi, CSI_CCIR_CODE_2));
13429 + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n",
13430 + ipu_csi_read(csi, CSI_CCIR_CODE_3));
13431 + dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n",
13432 + ipu_csi_read(csi, CSI_MIPI_DI));
13433 + dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n",
13434 + ipu_csi_read(csi, CSI_SKIP));
13436 +EXPORT_SYMBOL_GPL(ipu_csi_dump);
13438 +++ b/drivers/gpu/ipu-v3/ipu-dc.c
13440 +// SPDX-License-Identifier: GPL-2.0-or-later
13442 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
13443 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
13446 +#include <linux/export.h>
13447 +#include <linux/module.h>
13448 +#include <linux/types.h>
13449 +#include <linux/errno.h>
13450 +#include <linux/delay.h>
13451 +#include <linux/interrupt.h>
13452 +#include <linux/io.h>
13454 +#include <video/imx-ipu-v3.h>
13455 +#include "ipu-prv.h"
13457 +#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2)
13458 +#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2)
13460 +#define DC_EVT_NF 0
13461 +#define DC_EVT_NL 1
13462 +#define DC_EVT_EOF 2
13463 +#define DC_EVT_NFIELD 3
13464 +#define DC_EVT_EOL 4
13465 +#define DC_EVT_EOFIELD 5
13466 +#define DC_EVT_NEW_ADDR 6
13467 +#define DC_EVT_NEW_CHAN 7
13468 +#define DC_EVT_NEW_DATA 8
13470 +#define DC_EVT_NEW_ADDR_W_0 0
13471 +#define DC_EVT_NEW_ADDR_W_1 1
13472 +#define DC_EVT_NEW_CHAN_W_0 2
13473 +#define DC_EVT_NEW_CHAN_W_1 3
13474 +#define DC_EVT_NEW_DATA_W_0 4
13475 +#define DC_EVT_NEW_DATA_W_1 5
13476 +#define DC_EVT_NEW_ADDR_R_0 6
13477 +#define DC_EVT_NEW_ADDR_R_1 7
13478 +#define DC_EVT_NEW_CHAN_R_0 8
13479 +#define DC_EVT_NEW_CHAN_R_1 9
13480 +#define DC_EVT_NEW_DATA_R_0 10
13481 +#define DC_EVT_NEW_DATA_R_1 11
13483 +#define DC_WR_CH_CONF 0x0
13484 +#define DC_WR_CH_ADDR 0x4
13485 +#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2)
13487 +#define DC_GEN 0xd4
13488 +#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4)
13489 +#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4)
13490 +#define DC_STAT 0x1c8
13492 +#define WROD(lf) (0x18 | ((lf) << 1))
13496 +#define SYNC_WAVE 0
13497 +#define NULL_WAVE (-1)
13499 +#define DC_GEN_SYNC_1_6_SYNC (2 << 1)
13500 +#define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
13502 +#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0)
13503 +#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0)
13504 +#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0)
13505 +#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0)
13506 +#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3)
13507 +#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3)
13508 +#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4)
13509 +#define DC_WR_CH_CONF_FIELD_MODE (1 << 9)
13510 +#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5)
13511 +#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5)
13512 +#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2)
13513 +#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3)
13515 +#define IPU_DC_NUM_CHANNELS 10
13517 +struct ipu_dc_priv;
13520 + IPU_DC_MAP_RGB24,
13521 + IPU_DC_MAP_RGB565,
13522 + IPU_DC_MAP_GBR24, /* TVEv2 */
13523 + IPU_DC_MAP_BGR666,
13524 + IPU_DC_MAP_LVDS666,
13525 + IPU_DC_MAP_BGR24,
13529 + /* The display interface number assigned to this dc channel */
13531 + void __iomem *base;
13532 + struct ipu_dc_priv *priv;
13537 +struct ipu_dc_priv {
13538 + void __iomem *dc_reg;
13539 + void __iomem *dc_tmpl_reg;
13540 + struct ipu_soc *ipu;
13541 + struct device *dev;
13542 + struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
13543 + struct mutex mutex;
13544 + struct completion comp;
13548 +static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
13552 + reg = readl(dc->base + DC_RL_CH(event));
13553 + reg &= ~(0xffff << (16 * (event & 0x1)));
13554 + reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
13555 + writel(reg, dc->base + DC_RL_CH(event));
13558 +static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
13559 + int map, int wave, int glue, int sync, int stop)
13561 + struct ipu_dc_priv *priv = dc->priv;
13564 + if (opcode == WCLK) {
13565 + reg1 = (operand << 20) & 0xfff00000;
13566 + reg2 = operand >> 12 | opcode << 1 | stop << 9;
13567 + } else if (opcode == WRG) {
13568 + reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
13569 + reg2 = operand >> 17 | opcode << 7 | stop << 9;
13571 + reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
13572 + reg2 = operand >> 12 | opcode << 4 | stop << 9;
13574 + writel(reg1, priv->dc_tmpl_reg + word * 8);
13575 + writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
13578 +static int ipu_bus_format_to_map(u32 fmt)
13583 + /* fall-through */
13584 + case MEDIA_BUS_FMT_RGB888_1X24:
13585 + return IPU_DC_MAP_RGB24;
13586 + case MEDIA_BUS_FMT_RGB565_1X16:
13587 + return IPU_DC_MAP_RGB565;
13588 + case MEDIA_BUS_FMT_GBR888_1X24:
13589 + return IPU_DC_MAP_GBR24;
13590 + case MEDIA_BUS_FMT_RGB666_1X18:
13591 + return IPU_DC_MAP_BGR666;
13592 + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
13593 + return IPU_DC_MAP_LVDS666;
13594 + case MEDIA_BUS_FMT_BGR888_1X24:
13595 + return IPU_DC_MAP_BGR24;
13599 +int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
13600 + u32 bus_format, u32 width)
13602 + struct ipu_dc_priv *priv = dc->priv;
13607 + dc->di = ipu_di_get_num(di);
13609 + map = ipu_bus_format_to_map(bus_format);
13612 + * In interlaced mode we need more counters to create the asymmetric
13613 + * per-field VSYNC signals. The pixel active signal synchronising DC
13614 + * to DI moves to signal generator #6 (see ipu-di.c). In progressive
13615 + * mode counter #5 is used.
13617 + sync = interlaced ? 6 : 5;
13619 + /* Reserve 5 microcode template words for each DI */
13625 + if (interlaced) {
13626 + dc_link_event(dc, DC_EVT_NL, addr, 3);
13627 + dc_link_event(dc, DC_EVT_EOL, addr, 2);
13628 + dc_link_event(dc, DC_EVT_NEW_DATA, addr, 1);
13630 + /* Init template microcode */
13631 + dc_write_tmpl(dc, addr, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
13633 + dc_link_event(dc, DC_EVT_NL, addr + 2, 3);
13634 + dc_link_event(dc, DC_EVT_EOL, addr + 3, 2);
13635 + dc_link_event(dc, DC_EVT_NEW_DATA, addr + 1, 1);
13637 + /* Init template microcode */
13638 + dc_write_tmpl(dc, addr + 2, WROD(0), 0, map, SYNC_WAVE, 8, sync, 1);
13639 + dc_write_tmpl(dc, addr + 3, WROD(0), 0, map, SYNC_WAVE, 4, sync, 0);
13640 + dc_write_tmpl(dc, addr + 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
13641 + dc_write_tmpl(dc, addr + 1, WROD(0), 0, map, SYNC_WAVE, 0, sync, 1);
13644 + dc_link_event(dc, DC_EVT_NF, 0, 0);
13645 + dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
13646 + dc_link_event(dc, DC_EVT_EOF, 0, 0);
13647 + dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
13648 + dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
13649 + dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
13651 + reg = readl(dc->base + DC_WR_CH_CONF);
13653 + reg |= DC_WR_CH_CONF_FIELD_MODE;
13655 + reg &= ~DC_WR_CH_CONF_FIELD_MODE;
13656 + writel(reg, dc->base + DC_WR_CH_CONF);
13658 + writel(0x0, dc->base + DC_WR_CH_ADDR);
13659 + writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
13663 +EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
13665 +void ipu_dc_enable(struct ipu_soc *ipu)
13667 + struct ipu_dc_priv *priv = ipu->dc_priv;
13669 + mutex_lock(&priv->mutex);
13671 + if (!priv->use_count)
13672 + ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
13674 + priv->use_count++;
13676 + mutex_unlock(&priv->mutex);
13678 +EXPORT_SYMBOL_GPL(ipu_dc_enable);
13680 +void ipu_dc_enable_channel(struct ipu_dc *dc)
13684 + reg = readl(dc->base + DC_WR_CH_CONF);
13685 + reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
13686 + writel(reg, dc->base + DC_WR_CH_CONF);
13688 +EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
13690 +void ipu_dc_disable_channel(struct ipu_dc *dc)
13694 + val = readl(dc->base + DC_WR_CH_CONF);
13695 + val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
13696 + writel(val, dc->base + DC_WR_CH_CONF);
13698 +EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
13700 +void ipu_dc_disable(struct ipu_soc *ipu)
13702 + struct ipu_dc_priv *priv = ipu->dc_priv;
13704 + mutex_lock(&priv->mutex);
13706 + priv->use_count--;
13707 + if (!priv->use_count)
13708 + ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
13710 + if (priv->use_count < 0)
13711 + priv->use_count = 0;
13713 + mutex_unlock(&priv->mutex);
13715 +EXPORT_SYMBOL_GPL(ipu_dc_disable);
13717 +static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
13718 + int byte_num, int offset, int mask)
13720 + int ptr = map * 3 + byte_num;
13723 + reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
13724 + reg &= ~(0xffff << (16 * (ptr & 0x1)));
13725 + reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
13726 + writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
13728 + reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
13729 + reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
13730 + reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
13731 + writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
13734 +static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
13736 + u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
13738 + writel(reg & ~(0xffff << (16 * (map & 0x1))),
13739 + priv->dc_reg + DC_MAP_CONF_PTR(map));
13742 +struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
13744 + struct ipu_dc_priv *priv = ipu->dc_priv;
13745 + struct ipu_dc *dc;
13747 + if (channel >= IPU_DC_NUM_CHANNELS)
13748 + return ERR_PTR(-ENODEV);
13750 + dc = &priv->channels[channel];
13752 + mutex_lock(&priv->mutex);
13754 + if (dc->in_use) {
13755 + mutex_unlock(&priv->mutex);
13756 + return ERR_PTR(-EBUSY);
13759 + dc->in_use = true;
13761 + mutex_unlock(&priv->mutex);
13765 +EXPORT_SYMBOL_GPL(ipu_dc_get);
13767 +void ipu_dc_put(struct ipu_dc *dc)
13769 + struct ipu_dc_priv *priv = dc->priv;
13771 + mutex_lock(&priv->mutex);
13772 + dc->in_use = false;
13773 + mutex_unlock(&priv->mutex);
13775 +EXPORT_SYMBOL_GPL(ipu_dc_put);
13777 +int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
13778 + unsigned long base, unsigned long template_base)
13780 + struct ipu_dc_priv *priv;
13781 + static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
13782 + 0x78, 0, 0x94, 0xb4};
13785 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
13789 + mutex_init(&priv->mutex);
13793 + priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
13794 + priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
13795 + if (!priv->dc_reg || !priv->dc_tmpl_reg)
13798 + for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
13799 + priv->channels[i].chno = i;
13800 + priv->channels[i].priv = priv;
13801 + priv->channels[i].base = priv->dc_reg + channel_offsets[i];
13804 + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
13805 + DC_WR_CH_CONF_PROG_DI_ID,
13806 + priv->channels[1].base + DC_WR_CH_CONF);
13807 + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
13808 + priv->channels[5].base + DC_WR_CH_CONF);
13810 + writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1,
13811 + priv->dc_reg + DC_GEN);
13813 + ipu->dc_priv = priv;
13815 + dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
13816 + base, template_base);
13819 + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
13820 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
13821 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
13822 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
13825 + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
13826 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
13827 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
13828 + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
13831 + ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
13832 + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
13833 + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
13834 + ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
13837 + ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
13838 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
13839 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
13840 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
13843 + ipu_dc_map_clear(priv, IPU_DC_MAP_LVDS666);
13844 + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 0, 5, 0xfc); /* blue */
13845 + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 1, 13, 0xfc); /* green */
13846 + ipu_dc_map_config(priv, IPU_DC_MAP_LVDS666, 2, 21, 0xfc); /* red */
13849 + ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
13850 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
13851 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
13852 + ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
13857 +void ipu_dc_exit(struct ipu_soc *ipu)
13861 +++ b/drivers/gpu/ipu-v3/ipu-di.c
13863 +// SPDX-License-Identifier: GPL-2.0-or-later
13865 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
13866 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
13868 +#include <linux/export.h>
13869 +#include <linux/module.h>
13870 +#include <linux/types.h>
13871 +#include <linux/errno.h>
13872 +#include <linux/io.h>
13873 +#include <linux/err.h>
13874 +#include <linux/platform_device.h>
13876 +#include <video/imx-ipu-v3.h>
13877 +#include "ipu-prv.h"
13880 + void __iomem *base;
13883 + struct clk *clk_di; /* display input clock */
13884 + struct clk *clk_ipu; /* IPU bus clock */
13885 + struct clk *clk_di_pixel; /* resulting pixel clock */
13887 + struct ipu_soc *ipu;
13890 +static DEFINE_MUTEX(di_mutex);
13892 +struct di_sync_config {
13895 + int offset_count;
13897 + int repeat_count;
13899 + int cnt_polarity_gen_en;
13900 + int cnt_polarity_clr_src;
13901 + int cnt_polarity_trigger_src;
13916 + DI_PIN_SER_CLK = 0,
13917 + DI_PIN_SER_RS = 1,
13920 +enum di_sync_wave {
13921 + DI_SYNC_NONE = 0,
13923 + DI_SYNC_INT_HSYNC = 2,
13924 + DI_SYNC_HSYNC = 3,
13925 + DI_SYNC_VSYNC = 4,
13928 + DI_SYNC_CNT1 = 2, /* counter >= 2 only */
13929 + DI_SYNC_CNT4 = 5, /* counter >= 5 only */
13930 + DI_SYNC_CNT5 = 6, /* counter >= 6 only */
13933 +#define SYNC_WAVE 0
13935 +#define DI_GENERAL 0x0000
13936 +#define DI_BS_CLKGEN0 0x0004
13937 +#define DI_BS_CLKGEN1 0x0008
13938 +#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
13939 +#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
13940 +#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
13941 +#define DI_SYNC_AS_GEN 0x0054
13942 +#define DI_DW_GEN(gen) (0x0058 + 4 * (gen))
13943 +#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set)))
13944 +#define DI_SER_CONF 0x015c
13945 +#define DI_SSC 0x0160
13946 +#define DI_POL 0x0164
13947 +#define DI_AW0 0x0168
13948 +#define DI_AW1 0x016c
13949 +#define DI_SCR_CONF 0x0170
13950 +#define DI_STAT 0x0174
13952 +#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19)
13953 +#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16)
13954 +#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3)
13955 +#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0)
13957 +#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29)
13958 +#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25)
13959 +#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12)
13960 +#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9)
13961 +#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16)
13962 +#define DI_SW_GEN1_CNT_UP(x) (x)
13963 +#define DI_SW_GEN1_AUTO_RELOAD (0x10000000)
13965 +#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24
13966 +#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16
13968 +#define DI_GEN_POLARITY_1 (1 << 0)
13969 +#define DI_GEN_POLARITY_2 (1 << 1)
13970 +#define DI_GEN_POLARITY_3 (1 << 2)
13971 +#define DI_GEN_POLARITY_4 (1 << 3)
13972 +#define DI_GEN_POLARITY_5 (1 << 4)
13973 +#define DI_GEN_POLARITY_6 (1 << 5)
13974 +#define DI_GEN_POLARITY_7 (1 << 6)
13975 +#define DI_GEN_POLARITY_8 (1 << 7)
13976 +#define DI_GEN_POLARITY_DISP_CLK (1 << 17)
13977 +#define DI_GEN_DI_CLK_EXT (1 << 20)
13978 +#define DI_GEN_DI_VSYNC_EXT (1 << 21)
13980 +#define DI_POL_DRDY_DATA_POLARITY (1 << 7)
13981 +#define DI_POL_DRDY_POLARITY_15 (1 << 4)
13983 +#define DI_VSYNC_SEL_OFFSET 13
13985 +static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
13987 + return readl(di->base + offset);
13990 +static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
13992 + writel(value, di->base + offset);
13995 +static void ipu_di_data_wave_config(struct ipu_di *di,
13997 + int access_size, int component_size)
14000 + reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
14001 + (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
14002 + ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
14005 +static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
14006 + int set, int up, int down)
14010 + reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
14011 + reg &= ~(0x3 << (di_pin * 2));
14012 + reg |= set << (di_pin * 2);
14013 + ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
14015 + ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
14018 +static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
14019 + int start, int count)
14024 + for (i = 0; i < count; i++) {
14025 + struct di_sync_config *c = &config[i];
14026 + int wave_gen = start + i + 1;
14028 + if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
14029 + (c->repeat_count >= 0x1000) ||
14030 + (c->cnt_up >= 0x400) ||
14031 + (c->cnt_down >= 0x400)) {
14032 + dev_err(di->ipu->dev, "DI%d counters out of range.\n",
14037 + reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
14038 + DI_SW_GEN0_RUN_SRC(c->run_src) |
14039 + DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
14040 + DI_SW_GEN0_OFFSET_SRC(c->offset_src);
14041 + ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
14043 + reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
14044 + DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
14045 + DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
14046 + c->cnt_polarity_trigger_src) |
14047 + DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
14048 + DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
14049 + DI_SW_GEN1_CNT_UP(c->cnt_up);
14051 + /* Enable auto reload */
14052 + if (c->repeat_count == 0)
14053 + reg |= DI_SW_GEN1_AUTO_RELOAD;
14055 + ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
14057 + reg = ipu_di_read(di, DI_STP_REP(wave_gen));
14058 + reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
14059 + reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
14060 + ipu_di_write(di, reg, DI_STP_REP(wave_gen));
14064 +static void ipu_di_sync_config_interlaced(struct ipu_di *di,
14065 + struct ipu_di_signal_cfg *sig)
14067 + u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
14068 + sig->mode.hback_porch + sig->mode.hfront_porch;
14069 + u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
14070 + sig->mode.vback_porch + sig->mode.vfront_porch;
14071 + struct di_sync_config cfg[] = {
14073 + /* 1: internal VSYNC for each frame */
14074 + .run_count = v_total * 2 - 1,
14075 + .run_src = 3, /* == counter 7 */
14077 + /* PIN2: HSYNC waveform */
14078 + .run_count = h_total - 1,
14079 + .run_src = DI_SYNC_CLK,
14080 + .cnt_polarity_gen_en = 1,
14081 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
14082 + .cnt_down = sig->mode.hsync_len * 2,
14084 + /* PIN3: VSYNC waveform */
14085 + .run_count = v_total - 1,
14086 + .run_src = 4, /* == counter 7 */
14087 + .cnt_polarity_gen_en = 1,
14088 + .cnt_polarity_trigger_src = 4, /* == counter 7 */
14089 + .cnt_down = sig->mode.vsync_len * 2,
14090 + .cnt_clr_src = DI_SYNC_CNT1,
14093 + .run_count = v_total / 2,
14094 + .run_src = DI_SYNC_HSYNC,
14095 + .offset_count = h_total / 2,
14096 + .offset_src = DI_SYNC_CLK,
14097 + .repeat_count = 2,
14098 + .cnt_clr_src = DI_SYNC_CNT1,
14100 + /* 5: Active lines */
14101 + .run_src = DI_SYNC_HSYNC,
14102 + .offset_count = (sig->mode.vsync_len +
14103 + sig->mode.vback_porch) / 2,
14104 + .offset_src = DI_SYNC_HSYNC,
14105 + .repeat_count = sig->mode.vactive / 2,
14106 + .cnt_clr_src = DI_SYNC_CNT4,
14108 + /* 6: Active pixel, referenced by DC */
14109 + .run_src = DI_SYNC_CLK,
14110 + .offset_count = sig->mode.hsync_len +
14111 + sig->mode.hback_porch,
14112 + .offset_src = DI_SYNC_CLK,
14113 + .repeat_count = sig->mode.hactive,
14114 + .cnt_clr_src = DI_SYNC_CNT5,
14116 + /* 7: Half line HSYNC */
14117 + .run_count = h_total / 2 - 1,
14118 + .run_src = DI_SYNC_CLK,
14122 + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
14124 + ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
14127 +static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
14128 + struct ipu_di_signal_cfg *sig, int div)
14130 + u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
14131 + sig->mode.hback_porch + sig->mode.hfront_porch;
14132 + u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
14133 + sig->mode.vback_porch + sig->mode.vfront_porch;
14134 + struct di_sync_config cfg[] = {
14136 + /* 1: INT_HSYNC */
14137 + .run_count = h_total - 1,
14138 + .run_src = DI_SYNC_CLK,
14140 + /* PIN2: HSYNC */
14141 + .run_count = h_total - 1,
14142 + .run_src = DI_SYNC_CLK,
14143 + .offset_count = div * sig->v_to_h_sync,
14144 + .offset_src = DI_SYNC_CLK,
14145 + .cnt_polarity_gen_en = 1,
14146 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
14147 + .cnt_down = sig->mode.hsync_len * 2,
14149 + /* PIN3: VSYNC */
14150 + .run_count = v_total - 1,
14151 + .run_src = DI_SYNC_INT_HSYNC,
14152 + .cnt_polarity_gen_en = 1,
14153 + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
14154 + .cnt_down = sig->mode.vsync_len * 2,
14156 + /* 4: Line Active */
14157 + .run_src = DI_SYNC_HSYNC,
14158 + .offset_count = sig->mode.vsync_len +
14159 + sig->mode.vback_porch,
14160 + .offset_src = DI_SYNC_HSYNC,
14161 + .repeat_count = sig->mode.vactive,
14162 + .cnt_clr_src = DI_SYNC_VSYNC,
14164 + /* 5: Pixel Active, referenced by DC */
14165 + .run_src = DI_SYNC_CLK,
14166 + .offset_count = sig->mode.hsync_len +
14167 + sig->mode.hback_porch,
14168 + .offset_src = DI_SYNC_CLK,
14169 + .repeat_count = sig->mode.hactive,
14170 + .cnt_clr_src = 5, /* Line Active */
14181 + /* can't use #7 and #8 for line active and pixel active counters */
14182 + struct di_sync_config cfg_vga[] = {
14184 + /* 1: INT_HSYNC */
14185 + .run_count = h_total - 1,
14186 + .run_src = DI_SYNC_CLK,
14189 + .run_count = v_total - 1,
14190 + .run_src = DI_SYNC_INT_HSYNC,
14192 + /* 3: Line Active */
14193 + .run_src = DI_SYNC_INT_HSYNC,
14194 + .offset_count = sig->mode.vsync_len +
14195 + sig->mode.vback_porch,
14196 + .offset_src = DI_SYNC_INT_HSYNC,
14197 + .repeat_count = sig->mode.vactive,
14198 + .cnt_clr_src = 3 /* VSYNC */,
14200 + /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
14201 + .run_count = h_total - 1,
14202 + .run_src = DI_SYNC_CLK,
14203 + .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
14204 + .offset_src = DI_SYNC_CLK,
14205 + .cnt_polarity_gen_en = 1,
14206 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
14207 + .cnt_down = sig->mode.hsync_len * 2,
14209 + /* 5: Pixel Active signal to DC */
14210 + .run_src = DI_SYNC_CLK,
14211 + .offset_count = sig->mode.hsync_len +
14212 + sig->mode.hback_porch,
14213 + .offset_src = DI_SYNC_CLK,
14214 + .repeat_count = sig->mode.hactive,
14215 + .cnt_clr_src = 4, /* Line Active */
14217 + /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
14218 + .run_count = v_total - 1,
14219 + .run_src = DI_SYNC_INT_HSYNC,
14220 + .offset_count = 1, /* magic value from Freescale TVE driver */
14221 + .offset_src = DI_SYNC_INT_HSYNC,
14222 + .cnt_polarity_gen_en = 1,
14223 + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
14224 + .cnt_down = sig->mode.vsync_len * 2,
14226 + /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
14227 + .run_count = h_total - 1,
14228 + .run_src = DI_SYNC_CLK,
14229 + .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
14230 + .offset_src = DI_SYNC_CLK,
14231 + .cnt_polarity_gen_en = 1,
14232 + .cnt_polarity_trigger_src = DI_SYNC_CLK,
14233 + .cnt_down = sig->mode.hsync_len * 2,
14235 + /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
14236 + .run_count = v_total - 1,
14237 + .run_src = DI_SYNC_INT_HSYNC,
14238 + .offset_count = 1, /* magic value from Freescale TVE driver */
14239 + .offset_src = DI_SYNC_INT_HSYNC,
14240 + .cnt_polarity_gen_en = 1,
14241 + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
14242 + .cnt_down = sig->mode.vsync_len * 2,
14248 + ipu_di_write(di, v_total - 1, DI_SCR_CONF);
14249 + if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
14250 + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
14252 + ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
14255 +static void ipu_di_config_clock(struct ipu_di *di,
14256 + const struct ipu_di_signal_cfg *sig)
14259 + unsigned clkgen0;
14262 + if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
14264 + * CLKMODE_EXT means we must use the DI clock: this is
14265 + * needed for things like LVDS which needs to feed the
14266 + * DI and LDB with the same pixel clock.
14268 + clk = di->clk_di;
14270 + if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
14272 + * CLKMODE_SYNC means that we want the DI to be
14273 + * clocked at the same rate as the parent clock.
14274 + * This is needed (eg) for LDB which needs to be
14275 + * fed with the same pixel clock. We assume that
14276 + * the LDB clock has already been set correctly.
14278 + clkgen0 = 1 << 4;
14281 + * We can use the divider. We should really have
14282 + * a flag here indicating whether the bridge can
14283 + * cope with a fractional divider or not. For the
14284 + * time being, let's go for simplicitly and
14287 + unsigned long in_rate;
14290 + clk_set_rate(clk, sig->mode.pixelclock);
14292 + in_rate = clk_get_rate(clk);
14293 + div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
14294 + div = clamp(div, 1U, 255U);
14296 + clkgen0 = div << 4;
14300 + * For other interfaces, we can arbitarily select between
14301 + * the DI specific clock and the internal IPU clock. See
14302 + * DI_GENERAL bit 20. We select the IPU clock if it can
14303 + * give us a clock rate within 1% of the requested frequency,
14304 + * otherwise we use the DI clock.
14306 + unsigned long rate, clkrate;
14307 + unsigned div, error;
14309 + clkrate = clk_get_rate(di->clk_ipu);
14310 + div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
14311 + div = clamp(div, 1U, 255U);
14312 + rate = clkrate / div;
14314 + error = rate / (sig->mode.pixelclock / 1000);
14316 + dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
14317 + rate, div, (signed)(error - 1000) / 10, error % 10);
14319 + /* Allow a 1% error */
14320 + if (error < 1010 && error >= 990) {
14321 + clk = di->clk_ipu;
14323 + clkgen0 = div << 4;
14325 + unsigned long in_rate;
14328 + clk = di->clk_di;
14330 + clk_set_rate(clk, sig->mode.pixelclock);
14332 + in_rate = clk_get_rate(clk);
14333 + div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
14334 + div = clamp(div, 1U, 255U);
14336 + clkgen0 = div << 4;
14340 + di->clk_di_pixel = clk;
14342 + /* Set the divider */
14343 + ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
14346 + * Set the high/low periods. Bits 24:16 give us the falling edge,
14347 + * and bits 8:0 give the rising edge. LSB is fraction, and is
14348 + * based on the divider above. We want a 50% duty cycle, so set
14349 + * the falling edge to be half the divider.
14351 + ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
14353 + /* Finally select the input clock */
14354 + val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
14355 + if (clk == di->clk_di)
14356 + val |= DI_GEN_DI_CLK_EXT;
14357 + ipu_di_write(di, val, DI_GENERAL);
14359 + dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
14360 + sig->mode.pixelclock,
14361 + clk_get_rate(di->clk_ipu),
14362 + clk_get_rate(di->clk_di),
14363 + clk == di->clk_di ? "DI" : "IPU",
14364 + clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
14368 + * This function is called to adjust a video mode to IPU restrictions.
14369 + * It is meant to be called from drm crtc mode_fixup() methods.
14371 +int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
14375 + if (mode->vfront_porch >= 2)
14378 + diff = 2 - mode->vfront_porch;
14380 + if (mode->vback_porch >= diff) {
14381 + mode->vfront_porch = 2;
14382 + mode->vback_porch -= diff;
14383 + } else if (mode->vsync_len > diff) {
14384 + mode->vfront_porch = 2;
14385 + mode->vsync_len = mode->vsync_len - diff;
14387 + dev_warn(di->ipu->dev, "failed to adjust videomode\n");
14391 + dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n");
14394 +EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
14396 +static u32 ipu_di_gen_polarity(int pin)
14400 + return DI_GEN_POLARITY_1;
14402 + return DI_GEN_POLARITY_2;
14404 + return DI_GEN_POLARITY_3;
14406 + return DI_GEN_POLARITY_4;
14408 + return DI_GEN_POLARITY_5;
14410 + return DI_GEN_POLARITY_6;
14412 + return DI_GEN_POLARITY_7;
14414 + return DI_GEN_POLARITY_8;
14419 +int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
14422 + u32 di_gen, vsync_cnt;
14425 + dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
14426 + di->id, sig->mode.hactive, sig->mode.vactive);
14428 + dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
14429 + clk_get_rate(di->clk_ipu),
14430 + clk_get_rate(di->clk_di),
14431 + sig->mode.pixelclock);
14433 + mutex_lock(&di_mutex);
14435 + ipu_di_config_clock(di, sig);
14437 + div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
14438 + div = div / 16; /* Now divider is integer portion */
14440 + /* Setup pixel clock timing */
14441 + /* Down time is half of period */
14442 + ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
14444 + ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
14445 + ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
14447 + di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
14448 + di_gen |= DI_GEN_DI_VSYNC_EXT;
14450 + if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
14451 + ipu_di_sync_config_interlaced(di, sig);
14453 + /* set y_sel = 1 */
14454 + di_gen |= 0x10000000;
14458 + ipu_di_sync_config_noninterlaced(di, sig, div);
14463 + * TODO: change only for TVEv2, parallel display
14466 + if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
14470 + if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
14471 + di_gen |= ipu_di_gen_polarity(sig->hsync_pin);
14472 + if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
14473 + di_gen |= ipu_di_gen_polarity(sig->vsync_pin);
14475 + if (sig->clk_pol)
14476 + di_gen |= DI_GEN_POLARITY_DISP_CLK;
14478 + ipu_di_write(di, di_gen, DI_GENERAL);
14480 + ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
14483 + reg = ipu_di_read(di, DI_POL);
14484 + reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
14486 + if (sig->enable_pol)
14487 + reg |= DI_POL_DRDY_POLARITY_15;
14488 + if (sig->data_pol)
14489 + reg |= DI_POL_DRDY_DATA_POLARITY;
14491 + ipu_di_write(di, reg, DI_POL);
14493 + mutex_unlock(&di_mutex);
14497 +EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
14499 +int ipu_di_enable(struct ipu_di *di)
14503 + WARN_ON(IS_ERR(di->clk_di_pixel));
14505 + ret = clk_prepare_enable(di->clk_di_pixel);
14509 + ipu_module_enable(di->ipu, di->module);
14513 +EXPORT_SYMBOL_GPL(ipu_di_enable);
14515 +int ipu_di_disable(struct ipu_di *di)
14517 + WARN_ON(IS_ERR(di->clk_di_pixel));
14519 + ipu_module_disable(di->ipu, di->module);
14521 + clk_disable_unprepare(di->clk_di_pixel);
14525 +EXPORT_SYMBOL_GPL(ipu_di_disable);
14527 +int ipu_di_get_num(struct ipu_di *di)
14531 +EXPORT_SYMBOL_GPL(ipu_di_get_num);
14533 +static DEFINE_MUTEX(ipu_di_lock);
14535 +struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
14537 + struct ipu_di *di;
14540 + return ERR_PTR(-EINVAL);
14542 + di = ipu->di_priv[disp];
14544 + mutex_lock(&ipu_di_lock);
14547 + di = ERR_PTR(-EBUSY);
14551 + di->inuse = true;
14553 + mutex_unlock(&ipu_di_lock);
14557 +EXPORT_SYMBOL_GPL(ipu_di_get);
14559 +void ipu_di_put(struct ipu_di *di)
14561 + mutex_lock(&ipu_di_lock);
14563 + di->inuse = false;
14565 + mutex_unlock(&ipu_di_lock);
14567 +EXPORT_SYMBOL_GPL(ipu_di_put);
14569 +int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
14570 + unsigned long base,
14571 + u32 module, struct clk *clk_ipu)
14573 + struct ipu_di *di;
14578 + di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
14582 + ipu->di_priv[id] = di;
14584 + di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
14585 + if (IS_ERR(di->clk_di))
14586 + return PTR_ERR(di->clk_di);
14588 + di->module = module;
14590 + di->clk_ipu = clk_ipu;
14591 + di->base = devm_ioremap(dev, base, PAGE_SIZE);
14595 + ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
14597 + dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
14598 + id, base, di->base);
14599 + di->inuse = false;
14605 +void ipu_di_exit(struct ipu_soc *ipu, int id)
14609 +++ b/drivers/gpu/ipu-v3/ipu-dmfc.c
14611 +// SPDX-License-Identifier: GPL-2.0-or-later
14613 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
14614 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
14616 +#include <linux/export.h>
14617 +#include <linux/types.h>
14618 +#include <linux/errno.h>
14619 +#include <linux/io.h>
14621 +#include <video/imx-ipu-v3.h>
14622 +#include "ipu-prv.h"
14624 +#define DMFC_RD_CHAN 0x0000
14625 +#define DMFC_WR_CHAN 0x0004
14626 +#define DMFC_WR_CHAN_DEF 0x0008
14627 +#define DMFC_DP_CHAN 0x000c
14628 +#define DMFC_DP_CHAN_DEF 0x0010
14629 +#define DMFC_GENERAL1 0x0014
14630 +#define DMFC_GENERAL2 0x0018
14631 +#define DMFC_IC_CTRL 0x001c
14632 +#define DMFC_WR_CHAN_ALT 0x0020
14633 +#define DMFC_WR_CHAN_DEF_ALT 0x0024
14634 +#define DMFC_DP_CHAN_ALT 0x0028
14635 +#define DMFC_DP_CHAN_DEF_ALT 0x002c
14636 +#define DMFC_GENERAL1_ALT 0x0030
14637 +#define DMFC_STAT 0x0034
14639 +#define DMFC_WR_CHAN_1_28 0
14640 +#define DMFC_WR_CHAN_2_41 8
14641 +#define DMFC_WR_CHAN_1C_42 16
14642 +#define DMFC_WR_CHAN_2C_43 24
14644 +#define DMFC_DP_CHAN_5B_23 0
14645 +#define DMFC_DP_CHAN_5F_27 8
14646 +#define DMFC_DP_CHAN_6B_24 16
14647 +#define DMFC_DP_CHAN_6F_29 24
14649 +struct dmfc_channel_data {
14651 + unsigned long channel_reg;
14652 + unsigned long shift;
14653 + unsigned eot_shift;
14654 + unsigned max_fifo_lines;
14657 +static const struct dmfc_channel_data dmfcdata[] = {
14659 + .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
14660 + .channel_reg = DMFC_DP_CHAN,
14661 + .shift = DMFC_DP_CHAN_5B_23,
14663 + .max_fifo_lines = 3,
14665 + .ipu_channel = 24,
14666 + .channel_reg = DMFC_DP_CHAN,
14667 + .shift = DMFC_DP_CHAN_6B_24,
14669 + .max_fifo_lines = 1,
14671 + .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
14672 + .channel_reg = DMFC_DP_CHAN,
14673 + .shift = DMFC_DP_CHAN_5F_27,
14675 + .max_fifo_lines = 2,
14677 + .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
14678 + .channel_reg = DMFC_WR_CHAN,
14679 + .shift = DMFC_WR_CHAN_1_28,
14681 + .max_fifo_lines = 2,
14683 + .ipu_channel = 29,
14684 + .channel_reg = DMFC_DP_CHAN,
14685 + .shift = DMFC_DP_CHAN_6F_29,
14687 + .max_fifo_lines = 1,
14691 +#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
14693 +struct ipu_dmfc_priv;
14695 +struct dmfc_channel {
14697 + struct ipu_soc *ipu;
14698 + struct ipu_dmfc_priv *priv;
14699 + const struct dmfc_channel_data *data;
14702 +struct ipu_dmfc_priv {
14703 + struct ipu_soc *ipu;
14704 + struct device *dev;
14705 + struct dmfc_channel channels[DMFC_NUM_CHANNELS];
14706 + struct mutex mutex;
14707 + void __iomem *base;
14711 +int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
14713 + struct ipu_dmfc_priv *priv = dmfc->priv;
14714 + mutex_lock(&priv->mutex);
14716 + if (!priv->use_count)
14717 + ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
14719 + priv->use_count++;
14721 + mutex_unlock(&priv->mutex);
14725 +EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
14727 +void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
14729 + struct ipu_dmfc_priv *priv = dmfc->priv;
14731 + mutex_lock(&priv->mutex);
14733 + priv->use_count--;
14735 + if (!priv->use_count)
14736 + ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
14738 + if (priv->use_count < 0)
14739 + priv->use_count = 0;
14741 + mutex_unlock(&priv->mutex);
14743 +EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
14745 +void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
14747 + struct ipu_dmfc_priv *priv = dmfc->priv;
14750 + mutex_lock(&priv->mutex);
14752 + dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
14754 + if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
14755 + dmfc_gen1 |= 1 << dmfc->data->eot_shift;
14757 + dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
14759 + writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
14761 + mutex_unlock(&priv->mutex);
14763 +EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
14765 +struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
14767 + struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
14770 + for (i = 0; i < DMFC_NUM_CHANNELS; i++)
14771 + if (dmfcdata[i].ipu_channel == ipu_channel)
14772 + return &priv->channels[i];
14773 + return ERR_PTR(-ENODEV);
14775 +EXPORT_SYMBOL_GPL(ipu_dmfc_get);
14777 +void ipu_dmfc_put(struct dmfc_channel *dmfc)
14780 +EXPORT_SYMBOL_GPL(ipu_dmfc_put);
14782 +int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
14783 + struct clk *ipu_clk)
14785 + struct ipu_dmfc_priv *priv;
14788 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
14792 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
14798 + mutex_init(&priv->mutex);
14800 + ipu->dmfc_priv = priv;
14802 + for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
14803 + priv->channels[i].priv = priv;
14804 + priv->channels[i].ipu = ipu;
14805 + priv->channels[i].data = &dmfcdata[i];
14807 + if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
14808 + dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
14809 + dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
14810 + priv->channels[i].slots = 2;
14813 + writel(0x00000050, priv->base + DMFC_WR_CHAN);
14814 + writel(0x00005654, priv->base + DMFC_DP_CHAN);
14815 + writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
14816 + writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
14817 + writel(0x00000003, priv->base + DMFC_GENERAL1);
14822 +void ipu_dmfc_exit(struct ipu_soc *ipu)
14826 +++ b/drivers/gpu/ipu-v3/ipu-dp.c
14828 +// SPDX-License-Identifier: GPL-2.0-or-later
14830 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
14831 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
14833 +#include <linux/export.h>
14834 +#include <linux/kernel.h>
14835 +#include <linux/types.h>
14836 +#include <linux/errno.h>
14837 +#include <linux/io.h>
14838 +#include <linux/err.h>
14840 +#include <video/imx-ipu-v3.h>
14841 +#include "ipu-prv.h"
14844 +#define DP_ASYNC0 0x60
14845 +#define DP_ASYNC1 0xBC
14847 +#define DP_COM_CONF 0x0
14848 +#define DP_GRAPH_WIND_CTRL 0x0004
14849 +#define DP_FG_POS 0x0008
14850 +#define DP_CSC_A_0 0x0044
14851 +#define DP_CSC_A_1 0x0048
14852 +#define DP_CSC_A_2 0x004C
14853 +#define DP_CSC_A_3 0x0050
14854 +#define DP_CSC_0 0x0054
14855 +#define DP_CSC_1 0x0058
14857 +#define DP_COM_CONF_FG_EN (1 << 0)
14858 +#define DP_COM_CONF_GWSEL (1 << 1)
14859 +#define DP_COM_CONF_GWAM (1 << 2)
14860 +#define DP_COM_CONF_GWCKE (1 << 3)
14861 +#define DP_COM_CONF_CSC_DEF_MASK (3 << 8)
14862 +#define DP_COM_CONF_CSC_DEF_OFFSET 8
14863 +#define DP_COM_CONF_CSC_DEF_FG (3 << 8)
14864 +#define DP_COM_CONF_CSC_DEF_BG (2 << 8)
14865 +#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8)
14867 +#define IPUV3_NUM_FLOWS 3
14869 +struct ipu_dp_priv;
14875 + enum ipu_color_space in_cs;
14879 + struct ipu_dp foreground;
14880 + struct ipu_dp background;
14881 + enum ipu_color_space out_cs;
14882 + void __iomem *base;
14883 + struct ipu_dp_priv *priv;
14886 +struct ipu_dp_priv {
14887 + struct ipu_soc *ipu;
14888 + struct device *dev;
14889 + void __iomem *base;
14890 + struct ipu_flow flow[IPUV3_NUM_FLOWS];
14891 + struct mutex mutex;
14895 +static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
14897 +static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
14899 + if (dp->foreground)
14900 + return container_of(dp, struct ipu_flow, foreground);
14902 + return container_of(dp, struct ipu_flow, background);
14905 +int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
14906 + u8 alpha, bool bg_chan)
14908 + struct ipu_flow *flow = to_flow(dp);
14909 + struct ipu_dp_priv *priv = flow->priv;
14912 + mutex_lock(&priv->mutex);
14914 + reg = readl(flow->base + DP_COM_CONF);
14916 + reg &= ~DP_COM_CONF_GWSEL;
14918 + reg |= DP_COM_CONF_GWSEL;
14919 + writel(reg, flow->base + DP_COM_CONF);
14922 + reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
14923 + writel(reg | ((u32) alpha << 24),
14924 + flow->base + DP_GRAPH_WIND_CTRL);
14926 + reg = readl(flow->base + DP_COM_CONF);
14927 + writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
14929 + reg = readl(flow->base + DP_COM_CONF);
14930 + writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
14933 + ipu_srm_dp_update(priv->ipu, true);
14935 + mutex_unlock(&priv->mutex);
14939 +EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
14941 +int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
14943 + struct ipu_flow *flow = to_flow(dp);
14944 + struct ipu_dp_priv *priv = flow->priv;
14946 + writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
14948 + ipu_srm_dp_update(priv->ipu, true);
14952 +EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
14954 +static void ipu_dp_csc_init(struct ipu_flow *flow,
14955 + enum ipu_color_space in,
14956 + enum ipu_color_space out,
14961 + reg = readl(flow->base + DP_COM_CONF);
14962 + reg &= ~DP_COM_CONF_CSC_DEF_MASK;
14965 + writel(reg, flow->base + DP_COM_CONF);
14969 + if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
14970 + writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
14971 + writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
14972 + writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
14973 + writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
14974 + writel(0x3d6 | (0x0000 << 16) | (2 << 30),
14975 + flow->base + DP_CSC_0);
14976 + writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
14977 + flow->base + DP_CSC_1);
14979 + writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
14980 + writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
14981 + writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
14982 + writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
14983 + writel(0x000 | (0x3e42 << 16) | (1 << 30),
14984 + flow->base + DP_CSC_0);
14985 + writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
14986 + flow->base + DP_CSC_1);
14991 + writel(reg, flow->base + DP_COM_CONF);
14994 +int ipu_dp_setup_channel(struct ipu_dp *dp,
14995 + enum ipu_color_space in,
14996 + enum ipu_color_space out)
14998 + struct ipu_flow *flow = to_flow(dp);
14999 + struct ipu_dp_priv *priv = flow->priv;
15001 + mutex_lock(&priv->mutex);
15005 + if (!dp->foreground)
15006 + flow->out_cs = out;
15008 + if (flow->foreground.in_cs == flow->background.in_cs) {
15010 + * foreground and background are of same colorspace, put
15011 + * colorspace converter after combining unit.
15013 + ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
15014 + DP_COM_CONF_CSC_DEF_BOTH);
15016 + if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
15017 + flow->foreground.in_cs == flow->out_cs)
15019 + * foreground identical to output, apply color
15020 + * conversion on background
15022 + ipu_dp_csc_init(flow, flow->background.in_cs,
15023 + flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
15025 + ipu_dp_csc_init(flow, flow->foreground.in_cs,
15026 + flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
15029 + ipu_srm_dp_update(priv->ipu, true);
15031 + mutex_unlock(&priv->mutex);
15035 +EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
15037 +int ipu_dp_enable(struct ipu_soc *ipu)
15039 + struct ipu_dp_priv *priv = ipu->dp_priv;
15041 + mutex_lock(&priv->mutex);
15043 + if (!priv->use_count)
15044 + ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
15046 + priv->use_count++;
15048 + mutex_unlock(&priv->mutex);
15052 +EXPORT_SYMBOL_GPL(ipu_dp_enable);
15054 +int ipu_dp_enable_channel(struct ipu_dp *dp)
15056 + struct ipu_flow *flow = to_flow(dp);
15057 + struct ipu_dp_priv *priv = flow->priv;
15060 + if (!dp->foreground)
15063 + mutex_lock(&priv->mutex);
15065 + reg = readl(flow->base + DP_COM_CONF);
15066 + reg |= DP_COM_CONF_FG_EN;
15067 + writel(reg, flow->base + DP_COM_CONF);
15069 + ipu_srm_dp_update(priv->ipu, true);
15071 + mutex_unlock(&priv->mutex);
15075 +EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
15077 +void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
15079 + struct ipu_flow *flow = to_flow(dp);
15080 + struct ipu_dp_priv *priv = flow->priv;
15083 + dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
15085 + if (!dp->foreground)
15088 + mutex_lock(&priv->mutex);
15090 + reg = readl(flow->base + DP_COM_CONF);
15091 + csc = reg & DP_COM_CONF_CSC_DEF_MASK;
15092 + reg &= ~DP_COM_CONF_CSC_DEF_MASK;
15093 + if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
15094 + reg |= DP_COM_CONF_CSC_DEF_BG;
15096 + reg &= ~DP_COM_CONF_FG_EN;
15097 + writel(reg, flow->base + DP_COM_CONF);
15099 + writel(0, flow->base + DP_FG_POS);
15100 + ipu_srm_dp_update(priv->ipu, sync);
15102 + mutex_unlock(&priv->mutex);
15104 +EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
15106 +void ipu_dp_disable(struct ipu_soc *ipu)
15108 + struct ipu_dp_priv *priv = ipu->dp_priv;
15110 + mutex_lock(&priv->mutex);
15112 + priv->use_count--;
15114 + if (!priv->use_count)
15115 + ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
15117 + if (priv->use_count < 0)
15118 + priv->use_count = 0;
15120 + mutex_unlock(&priv->mutex);
15122 +EXPORT_SYMBOL_GPL(ipu_dp_disable);
15124 +struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
15126 + struct ipu_dp_priv *priv = ipu->dp_priv;
15127 + struct ipu_dp *dp;
15129 + if ((flow >> 1) >= IPUV3_NUM_FLOWS)
15130 + return ERR_PTR(-EINVAL);
15133 + dp = &priv->flow[flow >> 1].foreground;
15135 + dp = &priv->flow[flow >> 1].background;
15138 + return ERR_PTR(-EBUSY);
15140 + dp->in_use = true;
15144 +EXPORT_SYMBOL_GPL(ipu_dp_get);
15146 +void ipu_dp_put(struct ipu_dp *dp)
15148 + dp->in_use = false;
15150 +EXPORT_SYMBOL_GPL(ipu_dp_put);
15152 +int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
15154 + struct ipu_dp_priv *priv;
15157 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
15163 + ipu->dp_priv = priv;
15165 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
15169 + mutex_init(&priv->mutex);
15171 + for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
15172 + priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
15173 + priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
15174 + priv->flow[i].foreground.foreground = true;
15175 + priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
15176 + priv->flow[i].priv = priv;
15182 +void ipu_dp_exit(struct ipu_soc *ipu)
15186 +++ b/drivers/gpu/ipu-v3/ipu-ic.c
15188 +// SPDX-License-Identifier: GPL-2.0-or-later
15190 + * Copyright (C) 2012-2014 Mentor Graphics Inc.
15191 + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
15194 +#include <linux/types.h>
15195 +#include <linux/init.h>
15196 +#include <linux/errno.h>
15197 +#include <linux/spinlock.h>
15198 +#include <linux/bitrev.h>
15199 +#include <linux/io.h>
15200 +#include <linux/err.h>
15201 +#include <linux/sizes.h>
15202 +#include "ipu-prv.h"
15204 +/* IC Register Offsets */
15205 +#define IC_CONF 0x0000
15206 +#define IC_PRP_ENC_RSC 0x0004
15207 +#define IC_PRP_VF_RSC 0x0008
15208 +#define IC_PP_RSC 0x000C
15209 +#define IC_CMBP_1 0x0010
15210 +#define IC_CMBP_2 0x0014
15211 +#define IC_IDMAC_1 0x0018
15212 +#define IC_IDMAC_2 0x001C
15213 +#define IC_IDMAC_3 0x0020
15214 +#define IC_IDMAC_4 0x0024
15216 +/* IC Register Fields */
15217 +#define IC_CONF_PRPENC_EN (1 << 0)
15218 +#define IC_CONF_PRPENC_CSC1 (1 << 1)
15219 +#define IC_CONF_PRPENC_ROT_EN (1 << 2)
15220 +#define IC_CONF_PRPVF_EN (1 << 8)
15221 +#define IC_CONF_PRPVF_CSC1 (1 << 9)
15222 +#define IC_CONF_PRPVF_CSC2 (1 << 10)
15223 +#define IC_CONF_PRPVF_CMB (1 << 11)
15224 +#define IC_CONF_PRPVF_ROT_EN (1 << 12)
15225 +#define IC_CONF_PP_EN (1 << 16)
15226 +#define IC_CONF_PP_CSC1 (1 << 17)
15227 +#define IC_CONF_PP_CSC2 (1 << 18)
15228 +#define IC_CONF_PP_CMB (1 << 19)
15229 +#define IC_CONF_PP_ROT_EN (1 << 20)
15230 +#define IC_CONF_IC_GLB_LOC_A (1 << 28)
15231 +#define IC_CONF_KEY_COLOR_EN (1 << 29)
15232 +#define IC_CONF_RWS_EN (1 << 30)
15233 +#define IC_CONF_CSI_MEM_WR_EN (1 << 31)
15235 +#define IC_IDMAC_1_CB0_BURST_16 (1 << 0)
15236 +#define IC_IDMAC_1_CB1_BURST_16 (1 << 1)
15237 +#define IC_IDMAC_1_CB2_BURST_16 (1 << 2)
15238 +#define IC_IDMAC_1_CB3_BURST_16 (1 << 3)
15239 +#define IC_IDMAC_1_CB4_BURST_16 (1 << 4)
15240 +#define IC_IDMAC_1_CB5_BURST_16 (1 << 5)
15241 +#define IC_IDMAC_1_CB6_BURST_16 (1 << 6)
15242 +#define IC_IDMAC_1_CB7_BURST_16 (1 << 7)
15243 +#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11)
15244 +#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11
15245 +#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14)
15246 +#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14
15247 +#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17)
15248 +#define IC_IDMAC_1_PP_ROT_OFFSET 17
15249 +#define IC_IDMAC_1_PP_FLIP_RS (1 << 22)
15250 +#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21)
15251 +#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20)
15253 +#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0)
15254 +#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
15255 +#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10)
15256 +#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10
15257 +#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20)
15258 +#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20
15260 +#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0)
15261 +#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0
15262 +#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10)
15263 +#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10
15264 +#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20)
15265 +#define IC_IDMAC_3_PP_WIDTH_OFFSET 20
15267 +struct ic_task_regoffs {
15269 + u32 tpmem_csc[2];
15272 +struct ic_task_bitfields {
15274 + u32 ic_conf_rot_en;
15275 + u32 ic_conf_cmb_en;
15276 + u32 ic_conf_csc1_en;
15277 + u32 ic_conf_csc2_en;
15278 + u32 ic_cmb_galpha_bit;
15281 +static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
15282 + [IC_TASK_ENCODER] = {
15283 + .rsc = IC_PRP_ENC_RSC,
15284 + .tpmem_csc = {0x2008, 0},
15286 + [IC_TASK_VIEWFINDER] = {
15287 + .rsc = IC_PRP_VF_RSC,
15288 + .tpmem_csc = {0x4028, 0x4040},
15290 + [IC_TASK_POST_PROCESSOR] = {
15291 + .rsc = IC_PP_RSC,
15292 + .tpmem_csc = {0x6060, 0x6078},
15296 +static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
15297 + [IC_TASK_ENCODER] = {
15298 + .ic_conf_en = IC_CONF_PRPENC_EN,
15299 + .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
15300 + .ic_conf_cmb_en = 0, /* NA */
15301 + .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
15302 + .ic_conf_csc2_en = 0, /* NA */
15303 + .ic_cmb_galpha_bit = 0, /* NA */
15305 + [IC_TASK_VIEWFINDER] = {
15306 + .ic_conf_en = IC_CONF_PRPVF_EN,
15307 + .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
15308 + .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
15309 + .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
15310 + .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
15311 + .ic_cmb_galpha_bit = 0,
15313 + [IC_TASK_POST_PROCESSOR] = {
15314 + .ic_conf_en = IC_CONF_PP_EN,
15315 + .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
15316 + .ic_conf_cmb_en = IC_CONF_PP_CMB,
15317 + .ic_conf_csc1_en = IC_CONF_PP_CSC1,
15318 + .ic_conf_csc2_en = IC_CONF_PP_CSC2,
15319 + .ic_cmb_galpha_bit = 8,
15323 +struct ipu_ic_priv;
15326 + enum ipu_ic_task task;
15327 + const struct ic_task_regoffs *reg;
15328 + const struct ic_task_bitfields *bit;
15330 + struct ipu_ic_colorspace in_cs;
15331 + struct ipu_ic_colorspace g_in_cs;
15332 + struct ipu_ic_colorspace out_cs;
15338 + struct ipu_ic_priv *priv;
15341 +struct ipu_ic_priv {
15342 + void __iomem *base;
15343 + void __iomem *tpmem_base;
15345 + struct ipu_soc *ipu;
15347 + int irt_use_count;
15348 + struct ipu_ic task[IC_NUM_TASKS];
15351 +static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
15353 + return readl(ic->priv->base + offset);
15356 +static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
15358 + writel(value, ic->priv->base + offset);
15361 +static int init_csc(struct ipu_ic *ic,
15362 + const struct ipu_ic_csc *csc,
15365 + struct ipu_ic_priv *priv = ic->priv;
15366 + u32 __iomem *base;
15367 + const u16 (*c)[3];
15371 + base = (u32 __iomem *)
15372 + (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
15374 + /* Cast to unsigned */
15375 + c = (const u16 (*)[3])csc->params.coeff;
15376 + a = (const u16 *)csc->params.offset;
15378 + param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
15379 + ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
15380 + writel(param, base++);
15382 + param = ((a[0] & 0x1fe0) >> 5) | (csc->params.scale << 8) |
15383 + (csc->params.sat << 10);
15384 + writel(param, base++);
15386 + param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
15387 + ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
15388 + writel(param, base++);
15390 + param = ((a[1] & 0x1fe0) >> 5);
15391 + writel(param, base++);
15393 + param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
15394 + ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
15395 + writel(param, base++);
15397 + param = ((a[2] & 0x1fe0) >> 5);
15398 + writel(param, base++);
15403 +static int calc_resize_coeffs(struct ipu_ic *ic,
15404 + u32 in_size, u32 out_size,
15405 + u32 *resize_coeff,
15406 + u32 *downsize_coeff)
15408 + struct ipu_ic_priv *priv = ic->priv;
15409 + struct ipu_soc *ipu = priv->ipu;
15410 + u32 temp_size, temp_downsize;
15413 + * Input size cannot be more than 4096, and output size cannot
15414 + * be more than 1024
15416 + if (in_size > 4096) {
15417 + dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
15420 + if (out_size > 1024) {
15421 + dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
15425 + /* Cannot downsize more than 4:1 */
15426 + if ((out_size << 2) < in_size) {
15427 + dev_err(ipu->dev, "Unsupported downsize\n");
15431 + /* Compute downsizing coefficient */
15432 + temp_downsize = 0;
15433 + temp_size = in_size;
15434 + while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
15435 + (temp_downsize < 2)) {
15439 + *downsize_coeff = temp_downsize;
15442 + * compute resizing coefficient using the following equation:
15443 + * resize_coeff = M * (SI - 1) / (SO - 1)
15444 + * where M = 2^13, SI = input size, SO = output size
15446 + *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
15447 + if (*resize_coeff >= 16384L) {
15448 + dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
15449 + *resize_coeff = 0x3FFF;
15455 +void ipu_ic_task_enable(struct ipu_ic *ic)
15457 + struct ipu_ic_priv *priv = ic->priv;
15458 + unsigned long flags;
15461 + spin_lock_irqsave(&priv->lock, flags);
15463 + ic_conf = ipu_ic_read(ic, IC_CONF);
15465 + ic_conf |= ic->bit->ic_conf_en;
15467 + if (ic->rotation)
15468 + ic_conf |= ic->bit->ic_conf_rot_en;
15470 + if (ic->in_cs.cs != ic->out_cs.cs)
15471 + ic_conf |= ic->bit->ic_conf_csc1_en;
15473 + if (ic->graphics) {
15474 + ic_conf |= ic->bit->ic_conf_cmb_en;
15475 + ic_conf |= ic->bit->ic_conf_csc1_en;
15477 + if (ic->g_in_cs.cs != ic->out_cs.cs)
15478 + ic_conf |= ic->bit->ic_conf_csc2_en;
15481 + ipu_ic_write(ic, ic_conf, IC_CONF);
15483 + spin_unlock_irqrestore(&priv->lock, flags);
15485 +EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
15487 +void ipu_ic_task_disable(struct ipu_ic *ic)
15489 + struct ipu_ic_priv *priv = ic->priv;
15490 + unsigned long flags;
15493 + spin_lock_irqsave(&priv->lock, flags);
15495 + ic_conf = ipu_ic_read(ic, IC_CONF);
15497 + ic_conf &= ~(ic->bit->ic_conf_en |
15498 + ic->bit->ic_conf_csc1_en |
15499 + ic->bit->ic_conf_rot_en);
15500 + if (ic->bit->ic_conf_csc2_en)
15501 + ic_conf &= ~ic->bit->ic_conf_csc2_en;
15502 + if (ic->bit->ic_conf_cmb_en)
15503 + ic_conf &= ~ic->bit->ic_conf_cmb_en;
15505 + ipu_ic_write(ic, ic_conf, IC_CONF);
15507 + spin_unlock_irqrestore(&priv->lock, flags);
15509 +EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
15511 +int ipu_ic_task_graphics_init(struct ipu_ic *ic,
15512 + const struct ipu_ic_colorspace *g_in_cs,
15513 + bool galpha_en, u32 galpha,
15514 + bool colorkey_en, u32 colorkey)
15516 + struct ipu_ic_priv *priv = ic->priv;
15517 + struct ipu_ic_csc csc2;
15518 + unsigned long flags;
15519 + u32 reg, ic_conf;
15522 + if (ic->task == IC_TASK_ENCODER)
15525 + spin_lock_irqsave(&priv->lock, flags);
15527 + ic_conf = ipu_ic_read(ic, IC_CONF);
15529 + if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
15530 + struct ipu_ic_csc csc1;
15532 + ret = ipu_ic_calc_csc(&csc1,
15533 + V4L2_YCBCR_ENC_601,
15534 + V4L2_QUANTIZATION_FULL_RANGE,
15535 + IPUV3_COLORSPACE_RGB,
15536 + V4L2_YCBCR_ENC_601,
15537 + V4L2_QUANTIZATION_FULL_RANGE,
15538 + IPUV3_COLORSPACE_RGB);
15542 + /* need transparent CSC1 conversion */
15543 + ret = init_csc(ic, &csc1, 0);
15548 + ic->g_in_cs = *g_in_cs;
15549 + csc2.in_cs = ic->g_in_cs;
15550 + csc2.out_cs = ic->out_cs;
15552 + ret = __ipu_ic_calc_csc(&csc2);
15556 + ret = init_csc(ic, &csc2, 1);
15561 + ic_conf |= IC_CONF_IC_GLB_LOC_A;
15562 + reg = ipu_ic_read(ic, IC_CMBP_1);
15563 + reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
15564 + reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
15565 + ipu_ic_write(ic, reg, IC_CMBP_1);
15567 + ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
15569 + if (colorkey_en) {
15570 + ic_conf |= IC_CONF_KEY_COLOR_EN;
15571 + ipu_ic_write(ic, colorkey, IC_CMBP_2);
15573 + ic_conf &= ~IC_CONF_KEY_COLOR_EN;
15575 + ipu_ic_write(ic, ic_conf, IC_CONF);
15577 + ic->graphics = true;
15579 + spin_unlock_irqrestore(&priv->lock, flags);
15582 +EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
15584 +int ipu_ic_task_init_rsc(struct ipu_ic *ic,
15585 + const struct ipu_ic_csc *csc,
15586 + int in_width, int in_height,
15587 + int out_width, int out_height,
15590 + struct ipu_ic_priv *priv = ic->priv;
15591 + u32 downsize_coeff, resize_coeff;
15592 + unsigned long flags;
15596 + /* Setup vertical resizing */
15598 + ret = calc_resize_coeffs(ic, in_height, out_height,
15599 + &resize_coeff, &downsize_coeff);
15603 + rsc = (downsize_coeff << 30) | (resize_coeff << 16);
15605 + /* Setup horizontal resizing */
15606 + ret = calc_resize_coeffs(ic, in_width, out_width,
15607 + &resize_coeff, &downsize_coeff);
15611 + rsc |= (downsize_coeff << 14) | resize_coeff;
15614 + spin_lock_irqsave(&priv->lock, flags);
15616 + ipu_ic_write(ic, rsc, ic->reg->rsc);
15618 + /* Setup color space conversion */
15619 + ic->in_cs = csc->in_cs;
15620 + ic->out_cs = csc->out_cs;
15622 + ret = init_csc(ic, csc, 0);
15624 + spin_unlock_irqrestore(&priv->lock, flags);
15628 +int ipu_ic_task_init(struct ipu_ic *ic,
15629 + const struct ipu_ic_csc *csc,
15630 + int in_width, int in_height,
15631 + int out_width, int out_height)
15633 + return ipu_ic_task_init_rsc(ic, csc,
15634 + in_width, in_height,
15635 + out_width, out_height, 0);
15637 +EXPORT_SYMBOL_GPL(ipu_ic_task_init);
15639 +int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
15640 + u32 width, u32 height, int burst_size,
15641 + enum ipu_rotate_mode rot)
15643 + struct ipu_ic_priv *priv = ic->priv;
15644 + struct ipu_soc *ipu = priv->ipu;
15645 + u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
15646 + u32 temp_rot = bitrev8(rot) >> 5;
15647 + bool need_hor_flip = false;
15648 + unsigned long flags;
15651 + if ((burst_size != 8) && (burst_size != 16)) {
15652 + dev_err(ipu->dev, "Illegal burst length for IC\n");
15659 + if (temp_rot & 0x2) /* Need horizontal flip */
15660 + need_hor_flip = true;
15662 + spin_lock_irqsave(&priv->lock, flags);
15664 + ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
15665 + ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
15666 + ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
15668 + switch (channel->num) {
15669 + case IPUV3_CHANNEL_IC_PP_MEM:
15670 + if (burst_size == 16)
15671 + ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
15673 + ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
15675 + if (need_hor_flip)
15676 + ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
15678 + ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
15680 + ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
15681 + ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
15683 + ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
15684 + ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
15686 + case IPUV3_CHANNEL_MEM_IC_PP:
15687 + if (burst_size == 16)
15688 + ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
15690 + ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
15692 + case IPUV3_CHANNEL_MEM_ROT_PP:
15693 + ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
15694 + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
15696 + case IPUV3_CHANNEL_MEM_IC_PRP_VF:
15697 + if (burst_size == 16)
15698 + ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
15700 + ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
15702 + case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
15703 + if (burst_size == 16)
15704 + ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
15706 + ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
15708 + if (need_hor_flip)
15709 + ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
15711 + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
15713 + ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
15714 + ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
15716 + ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
15717 + ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
15719 + case IPUV3_CHANNEL_MEM_ROT_ENC:
15720 + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
15721 + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
15723 + case IPUV3_CHANNEL_IC_PRP_VF_MEM:
15724 + if (burst_size == 16)
15725 + ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
15727 + ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
15729 + if (need_hor_flip)
15730 + ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
15732 + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
15734 + ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
15735 + ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
15737 + ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
15738 + ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
15740 + case IPUV3_CHANNEL_MEM_ROT_VF:
15741 + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
15742 + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
15744 + case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
15745 + if (burst_size == 16)
15746 + ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
15748 + ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
15750 + case IPUV3_CHANNEL_G_MEM_IC_PP:
15751 + if (burst_size == 16)
15752 + ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
15754 + ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
15756 + case IPUV3_CHANNEL_VDI_MEM_IC_VF:
15757 + if (burst_size == 16)
15758 + ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
15760 + ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
15766 + ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
15767 + ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
15768 + ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
15770 + if (ipu_rot_mode_is_irt(rot))
15771 + ic->rotation = true;
15774 + spin_unlock_irqrestore(&priv->lock, flags);
15777 +EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
15779 +static void ipu_irt_enable(struct ipu_ic *ic)
15781 + struct ipu_ic_priv *priv = ic->priv;
15783 + if (!priv->irt_use_count)
15784 + ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
15786 + priv->irt_use_count++;
15789 +static void ipu_irt_disable(struct ipu_ic *ic)
15791 + struct ipu_ic_priv *priv = ic->priv;
15793 + if (priv->irt_use_count) {
15794 + if (!--priv->irt_use_count)
15795 + ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
15799 +int ipu_ic_enable(struct ipu_ic *ic)
15801 + struct ipu_ic_priv *priv = ic->priv;
15802 + unsigned long flags;
15804 + spin_lock_irqsave(&priv->lock, flags);
15806 + if (!priv->use_count)
15807 + ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
15809 + priv->use_count++;
15811 + if (ic->rotation)
15812 + ipu_irt_enable(ic);
15814 + spin_unlock_irqrestore(&priv->lock, flags);
15818 +EXPORT_SYMBOL_GPL(ipu_ic_enable);
15820 +int ipu_ic_disable(struct ipu_ic *ic)
15822 + struct ipu_ic_priv *priv = ic->priv;
15823 + unsigned long flags;
15825 + spin_lock_irqsave(&priv->lock, flags);
15827 + priv->use_count--;
15829 + if (!priv->use_count)
15830 + ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
15832 + if (priv->use_count < 0)
15833 + priv->use_count = 0;
15835 + if (ic->rotation)
15836 + ipu_irt_disable(ic);
15838 + ic->rotation = ic->graphics = false;
15840 + spin_unlock_irqrestore(&priv->lock, flags);
15844 +EXPORT_SYMBOL_GPL(ipu_ic_disable);
15846 +struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
15848 + struct ipu_ic_priv *priv = ipu->ic_priv;
15849 + unsigned long flags;
15850 + struct ipu_ic *ic, *ret;
15852 + if (task >= IC_NUM_TASKS)
15853 + return ERR_PTR(-EINVAL);
15855 + ic = &priv->task[task];
15857 + spin_lock_irqsave(&priv->lock, flags);
15859 + if (ic->in_use) {
15860 + ret = ERR_PTR(-EBUSY);
15864 + ic->in_use = true;
15868 + spin_unlock_irqrestore(&priv->lock, flags);
15871 +EXPORT_SYMBOL_GPL(ipu_ic_get);
15873 +void ipu_ic_put(struct ipu_ic *ic)
15875 + struct ipu_ic_priv *priv = ic->priv;
15876 + unsigned long flags;
15878 + spin_lock_irqsave(&priv->lock, flags);
15879 + ic->in_use = false;
15880 + spin_unlock_irqrestore(&priv->lock, flags);
15882 +EXPORT_SYMBOL_GPL(ipu_ic_put);
15884 +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
15885 + unsigned long base, unsigned long tpmem_base)
15887 + struct ipu_ic_priv *priv;
15890 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
15894 + ipu->ic_priv = priv;
15896 + spin_lock_init(&priv->lock);
15897 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
15900 + priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
15901 + if (!priv->tpmem_base)
15904 + dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
15908 + for (i = 0; i < IC_NUM_TASKS; i++) {
15909 + priv->task[i].task = i;
15910 + priv->task[i].priv = priv;
15911 + priv->task[i].reg = &ic_task_reg[i];
15912 + priv->task[i].bit = &ic_task_bit[i];
15918 +void ipu_ic_exit(struct ipu_soc *ipu)
15922 +void ipu_ic_dump(struct ipu_ic *ic)
15924 + struct ipu_ic_priv *priv = ic->priv;
15925 + struct ipu_soc *ipu = priv->ipu;
15927 + dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
15928 + ipu_ic_read(ic, IC_CONF));
15929 + dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
15930 + ipu_ic_read(ic, IC_PRP_ENC_RSC));
15931 + dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
15932 + ipu_ic_read(ic, IC_PRP_VF_RSC));
15933 + dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
15934 + ipu_ic_read(ic, IC_PP_RSC));
15935 + dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
15936 + ipu_ic_read(ic, IC_CMBP_1));
15937 + dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
15938 + ipu_ic_read(ic, IC_CMBP_2));
15939 + dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
15940 + ipu_ic_read(ic, IC_IDMAC_1));
15941 + dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
15942 + ipu_ic_read(ic, IC_IDMAC_2));
15943 + dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
15944 + ipu_ic_read(ic, IC_IDMAC_3));
15945 + dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
15946 + ipu_ic_read(ic, IC_IDMAC_4));
15948 +EXPORT_SYMBOL_GPL(ipu_ic_dump);
15950 +++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
15952 +// SPDX-License-Identifier: GPL-2.0-or-later
15954 + * Copyright (C) 2012-2016 Mentor Graphics Inc.
15956 + * Queued image conversion support, with tiling and rotation.
15959 +#include <linux/interrupt.h>
15960 +#include <linux/dma-mapping.h>
15961 +#include <video/imx-ipu-image-convert.h>
15962 +#include "ipu-prv.h"
15965 + * The IC Resizer has a restriction that the output frame from the
15966 + * resizer must be 1024 or less in both width (pixels) and height
15969 + * The image converter attempts to split up a conversion when
15970 + * the desired output (converted) frame resolution exceeds the
15971 + * IC resizer limit of 1024 in either dimension.
15973 + * If either dimension of the output frame exceeds the limit, the
15974 + * dimension is split into 1, 2, or 4 equal stripes, for a maximum
15975 + * of 4*4 or 16 tiles. A conversion is then carried out for each
15976 + * tile (but taking care to pass the full frame stride length to
15977 + * the DMA channel's parameter memory!). IDMA double-buffering is used
15978 + * to convert each tile back-to-back when possible (see note below
15979 + * when double_buffering boolean is set).
15981 + * Note that the input frame must be split up into the same number
15982 + * of tiles as the output frame:
15984 + * +---------+-----+
15985 + * +-----+---+ | A | B |
15986 + * | A | B | | | |
15987 + * +-----+---+ --> +---------+-----+
15988 + * | C | D | | C | D |
15989 + * +-----+---+ | | |
15990 + * +---------+-----+
15992 + * Clockwise 90° rotations are handled by first rescaling into a
15993 + * reusable temporary tile buffer and then rotating with the 8x8
15994 + * block rotator, writing to the correct destination:
15998 + * +-----+---+ +---------+ | C | A |
15999 + * | A | B | | A,B, | | | | |
16000 + * +-----+---+ --> | C,D | | --> | | |
16001 + * | C | D | +---------+ +-----+-----+
16002 + * +-----+---+ | D | B |
16006 + * If the 8x8 block rotator is used, horizontal or vertical flipping
16007 + * is done during the rotation step, otherwise flipping is done
16008 + * during the scaling step.
16009 + * With rotation or flipping, tile order changes between input and
16010 + * output image. Tiles are numbered row major from top left to bottom
16011 + * right for both input and output image.
16014 +#define MAX_STRIPES_W 4
16015 +#define MAX_STRIPES_H 4
16016 +#define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
16020 +#define MAX_W 4096
16021 +#define MAX_H 4096
16023 +enum ipu_image_convert_type {
16024 + IMAGE_CONVERT_IN = 0,
16025 + IMAGE_CONVERT_OUT,
16028 +struct ipu_image_convert_dma_buf {
16031 + unsigned long len;
16034 +struct ipu_image_convert_dma_chan {
16044 +/* dimensions of one tile */
16045 +struct ipu_image_tile {
16050 + /* size and strides are in bytes */
16054 + /* start Y or packed offset of this tile */
16056 + /* offset from start to tile in U plane, for planar formats */
16058 + /* offset from start to tile in V plane, for planar formats */
16062 +struct ipu_image_convert_image {
16063 + struct ipu_image base;
16064 + enum ipu_image_convert_type type;
16066 + const struct ipu_image_pixfmt *fmt;
16067 + unsigned int stride;
16069 + /* # of rows (horizontal stripes) if dest height is > 1024 */
16070 + unsigned int num_rows;
16071 + /* # of columns (vertical stripes) if dest width is > 1024 */
16072 + unsigned int num_cols;
16074 + struct ipu_image_tile tile[MAX_TILES];
16077 +struct ipu_image_pixfmt {
16078 + u32 fourcc; /* V4L2 fourcc */
16079 + int bpp; /* total bpp */
16080 + int uv_width_dec; /* decimation in width for U/V planes */
16081 + int uv_height_dec; /* decimation in height for U/V planes */
16082 + bool planar; /* planar format */
16083 + bool uv_swapped; /* U and V planes are swapped */
16084 + bool uv_packed; /* partial planar (U and V in same plane) */
16087 +struct ipu_image_convert_ctx;
16088 +struct ipu_image_convert_chan;
16089 +struct ipu_image_convert_priv;
16091 +struct ipu_image_convert_ctx {
16092 + struct ipu_image_convert_chan *chan;
16094 + ipu_image_convert_cb_t complete;
16095 + void *complete_context;
16097 + /* Source/destination image data and rotation mode */
16098 + struct ipu_image_convert_image in;
16099 + struct ipu_image_convert_image out;
16100 + struct ipu_ic_csc csc;
16101 + enum ipu_rotate_mode rot_mode;
16102 + u32 downsize_coeff_h;
16103 + u32 downsize_coeff_v;
16104 + u32 image_resize_coeff_h;
16105 + u32 image_resize_coeff_v;
16106 + u32 resize_coeffs_h[MAX_STRIPES_W];
16107 + u32 resize_coeffs_v[MAX_STRIPES_H];
16109 + /* intermediate buffer for rotation */
16110 + struct ipu_image_convert_dma_buf rot_intermediate[2];
16112 + /* current buffer number for double buffering */
16116 + struct completion aborted;
16118 + /* can we use double-buffering for this conversion operation? */
16119 + bool double_buffering;
16120 + /* num_rows * num_cols */
16121 + unsigned int num_tiles;
16122 + /* next tile to process */
16123 + unsigned int next_tile;
16124 + /* where to place converted tile in dest image */
16125 + unsigned int out_tile_map[MAX_TILES];
16127 + struct list_head list;
16130 +struct ipu_image_convert_chan {
16131 + struct ipu_image_convert_priv *priv;
16133 + enum ipu_ic_task ic_task;
16134 + const struct ipu_image_convert_dma_chan *dma_ch;
16136 + struct ipu_ic *ic;
16137 + struct ipuv3_channel *in_chan;
16138 + struct ipuv3_channel *out_chan;
16139 + struct ipuv3_channel *rotation_in_chan;
16140 + struct ipuv3_channel *rotation_out_chan;
16142 + /* the IPU end-of-frame irqs */
16144 + int rot_out_eof_irq;
16146 + spinlock_t irqlock;
16148 + /* list of convert contexts */
16149 + struct list_head ctx_list;
16150 + /* queue of conversion runs */
16151 + struct list_head pending_q;
16152 + /* queue of completed runs */
16153 + struct list_head done_q;
16155 + /* the current conversion run */
16156 + struct ipu_image_convert_run *current_run;
16159 +struct ipu_image_convert_priv {
16160 + struct ipu_image_convert_chan chan[IC_NUM_TASKS];
16161 + struct ipu_soc *ipu;
16164 +static const struct ipu_image_convert_dma_chan
16165 +image_convert_dma_chan[IC_NUM_TASKS] = {
16166 + [IC_TASK_VIEWFINDER] = {
16167 + .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
16168 + .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
16169 + .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
16170 + .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
16171 + .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
16172 + .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
16173 + .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
16175 + [IC_TASK_POST_PROCESSOR] = {
16176 + .in = IPUV3_CHANNEL_MEM_IC_PP,
16177 + .out = IPUV3_CHANNEL_IC_PP_MEM,
16178 + .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
16179 + .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
16183 +static const struct ipu_image_pixfmt image_convert_formats[] = {
16185 + .fourcc = V4L2_PIX_FMT_RGB565,
16188 + .fourcc = V4L2_PIX_FMT_RGB24,
16191 + .fourcc = V4L2_PIX_FMT_BGR24,
16194 + .fourcc = V4L2_PIX_FMT_RGB32,
16197 + .fourcc = V4L2_PIX_FMT_BGR32,
16200 + .fourcc = V4L2_PIX_FMT_XRGB32,
16203 + .fourcc = V4L2_PIX_FMT_XBGR32,
16206 + .fourcc = V4L2_PIX_FMT_BGRX32,
16209 + .fourcc = V4L2_PIX_FMT_RGBX32,
16212 + .fourcc = V4L2_PIX_FMT_YUYV,
16214 + .uv_width_dec = 2,
16215 + .uv_height_dec = 1,
16217 + .fourcc = V4L2_PIX_FMT_UYVY,
16219 + .uv_width_dec = 2,
16220 + .uv_height_dec = 1,
16222 + .fourcc = V4L2_PIX_FMT_YUV420,
16225 + .uv_width_dec = 2,
16226 + .uv_height_dec = 2,
16228 + .fourcc = V4L2_PIX_FMT_YVU420,
16231 + .uv_width_dec = 2,
16232 + .uv_height_dec = 2,
16233 + .uv_swapped = true,
16235 + .fourcc = V4L2_PIX_FMT_NV12,
16238 + .uv_width_dec = 2,
16239 + .uv_height_dec = 2,
16240 + .uv_packed = true,
16242 + .fourcc = V4L2_PIX_FMT_YUV422P,
16245 + .uv_width_dec = 2,
16246 + .uv_height_dec = 1,
16248 + .fourcc = V4L2_PIX_FMT_NV16,
16251 + .uv_width_dec = 2,
16252 + .uv_height_dec = 1,
16253 + .uv_packed = true,
16257 +static const struct ipu_image_pixfmt *get_format(u32 fourcc)
16259 + const struct ipu_image_pixfmt *ret = NULL;
16262 + for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
16263 + if (image_convert_formats[i].fourcc == fourcc) {
16264 + ret = &image_convert_formats[i];
16272 +static void dump_format(struct ipu_image_convert_ctx *ctx,
16273 + struct ipu_image_convert_image *ic_image)
16275 + struct ipu_image_convert_chan *chan = ctx->chan;
16276 + struct ipu_image_convert_priv *priv = chan->priv;
16278 + dev_dbg(priv->ipu->dev,
16279 + "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
16280 + chan->ic_task, ctx,
16281 + ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
16282 + ic_image->base.pix.width, ic_image->base.pix.height,
16283 + ic_image->num_cols, ic_image->num_rows,
16284 + ic_image->fmt->fourcc & 0xff,
16285 + (ic_image->fmt->fourcc >> 8) & 0xff,
16286 + (ic_image->fmt->fourcc >> 16) & 0xff,
16287 + (ic_image->fmt->fourcc >> 24) & 0xff);
16290 +int ipu_image_convert_enum_format(int index, u32 *fourcc)
16292 + const struct ipu_image_pixfmt *fmt;
16294 + if (index >= (int)ARRAY_SIZE(image_convert_formats))
16297 + /* Format found */
16298 + fmt = &image_convert_formats[index];
16299 + *fourcc = fmt->fourcc;
16302 +EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
16304 +static void free_dma_buf(struct ipu_image_convert_priv *priv,
16305 + struct ipu_image_convert_dma_buf *buf)
16308 + dma_free_coherent(priv->ipu->dev,
16309 + buf->len, buf->virt, buf->phys);
16310 + buf->virt = NULL;
16314 +static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
16315 + struct ipu_image_convert_dma_buf *buf,
16318 + buf->len = PAGE_ALIGN(size);
16319 + buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
16320 + GFP_DMA | GFP_KERNEL);
16321 + if (!buf->virt) {
16322 + dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
16329 +static inline int num_stripes(int dim)
16331 + return (dim - 1) / 1024 + 1;
16335 + * Calculate downsizing coefficients, which are the same for all tiles,
16336 + * and initial bilinear resizing coefficients, which are used to find the
16337 + * best seam positions.
16338 + * Also determine the number of tiles necessary to guarantee that no tile
16339 + * is larger than 1024 pixels in either dimension at the output and between
16340 + * IC downsizing and main processing sections.
16342 +static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
16343 + struct ipu_image *in,
16344 + struct ipu_image *out)
16346 + u32 downsized_width = in->rect.width;
16347 + u32 downsized_height = in->rect.height;
16348 + u32 downsize_coeff_v = 0;
16349 + u32 downsize_coeff_h = 0;
16350 + u32 resized_width = out->rect.width;
16351 + u32 resized_height = out->rect.height;
16352 + u32 resize_coeff_h;
16353 + u32 resize_coeff_v;
16357 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16358 + resized_width = out->rect.height;
16359 + resized_height = out->rect.width;
16362 + /* Do not let invalid input lead to an endless loop below */
16363 + if (WARN_ON(resized_width == 0 || resized_height == 0))
16366 + while (downsized_width >= resized_width * 2) {
16367 + downsized_width >>= 1;
16368 + downsize_coeff_h++;
16371 + while (downsized_height >= resized_height * 2) {
16372 + downsized_height >>= 1;
16373 + downsize_coeff_v++;
16377 + * Calculate the bilinear resizing coefficients that could be used if
16378 + * we were converting with a single tile. The bottom right output pixel
16379 + * should sample as close as possible to the bottom right input pixel
16380 + * out of the decimator, but not overshoot it:
16382 + resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
16383 + resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
16386 + * Both the output of the IC downsizing section before being passed to
16387 + * the IC main processing section and the final output of the IC main
16388 + * processing section must be <= 1024 pixels in both dimensions.
16390 + cols = num_stripes(max_t(u32, downsized_width, resized_width));
16391 + rows = num_stripes(max_t(u32, downsized_height, resized_height));
16393 + dev_dbg(ctx->chan->priv->ipu->dev,
16394 + "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
16395 + __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
16396 + resize_coeff_v, cols, rows);
16398 + if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
16399 + resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
16402 + ctx->downsize_coeff_h = downsize_coeff_h;
16403 + ctx->downsize_coeff_v = downsize_coeff_v;
16404 + ctx->image_resize_coeff_h = resize_coeff_h;
16405 + ctx->image_resize_coeff_v = resize_coeff_v;
16406 + ctx->in.num_cols = cols;
16407 + ctx->in.num_rows = rows;
16412 +#define round_closest(x, y) round_down((x) + (y)/2, (y))
16415 + * Find the best aligned seam position for the given column / row index.
16416 + * Rotation and image offsets are out of scope.
16418 + * @index: column / row index, used to calculate valid interval
16419 + * @in_edge: input right / bottom edge
16420 + * @out_edge: output right / bottom edge
16421 + * @in_align: input alignment, either horizontal 8-byte line start address
16422 + * alignment, or pixel alignment due to image format
16423 + * @out_align: output alignment, either horizontal 8-byte line start address
16424 + * alignment, or pixel alignment due to image format or rotator
16426 + * @in_burst: horizontal input burst size in case of horizontal flip
16427 + * @out_burst: horizontal output burst size or rotator block size
16428 + * @downsize_coeff: downsizing section coefficient
16429 + * @resize_coeff: main processing section resizing coefficient
16430 + * @_in_seam: aligned input seam position return value
16431 + * @_out_seam: aligned output seam position return value
16433 +static void find_best_seam(struct ipu_image_convert_ctx *ctx,
16434 + unsigned int index,
16435 + unsigned int in_edge,
16436 + unsigned int out_edge,
16437 + unsigned int in_align,
16438 + unsigned int out_align,
16439 + unsigned int in_burst,
16440 + unsigned int out_burst,
16441 + unsigned int downsize_coeff,
16442 + unsigned int resize_coeff,
16446 + struct device *dev = ctx->chan->priv->ipu->dev;
16447 + unsigned int out_pos;
16448 + /* Input / output seam position candidates */
16449 + unsigned int out_seam = 0;
16450 + unsigned int in_seam = 0;
16451 + unsigned int min_diff = UINT_MAX;
16452 + unsigned int out_start;
16453 + unsigned int out_end;
16454 + unsigned int in_start;
16455 + unsigned int in_end;
16457 + /* Start within 1024 pixels of the right / bottom edge */
16458 + out_start = max_t(int, index * out_align, out_edge - 1024);
16459 + /* End before having to add more columns to the left / rows above */
16460 + out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
16463 + * Limit input seam position to make sure that the downsized input tile
16464 + * to the right or bottom does not exceed 1024 pixels.
16466 + in_start = max_t(int, index * in_align,
16467 + in_edge - (1024 << downsize_coeff));
16468 + in_end = min_t(unsigned int, in_edge,
16469 + index * (1024 << downsize_coeff) + 1);
16472 + * Output tiles must start at a multiple of 8 bytes horizontally and
16473 + * possibly at an even line horizontally depending on the pixel format.
16474 + * Only consider output aligned positions for the seam.
16476 + out_start = round_up(out_start, out_align);
16477 + for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
16478 + unsigned int in_pos;
16479 + unsigned int in_pos_aligned;
16480 + unsigned int in_pos_rounded;
16481 + unsigned int abs_diff;
16484 + * Tiles in the right row / bottom column may not be allowed to
16485 + * overshoot horizontally / vertically. out_burst may be the
16486 + * actual DMA burst size, or the rotator block size.
16488 + if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
16492 + * Input sample position, corresponding to out_pos, 19.13 fixed
16495 + in_pos = (out_pos * resize_coeff) << downsize_coeff;
16497 + * The closest input sample position that we could actually
16498 + * start the input tile at, 19.13 fixed point.
16500 + in_pos_aligned = round_closest(in_pos, 8192U * in_align);
16501 + /* Convert 19.13 fixed point to integer */
16502 + in_pos_rounded = in_pos_aligned / 8192U;
16504 + if (in_pos_rounded < in_start)
16506 + if (in_pos_rounded >= in_end)
16509 + if ((in_burst > 1) &&
16510 + (in_edge - in_pos_rounded) % in_burst)
16513 + if (in_pos < in_pos_aligned)
16514 + abs_diff = in_pos_aligned - in_pos;
16516 + abs_diff = in_pos - in_pos_aligned;
16518 + if (abs_diff < min_diff) {
16519 + in_seam = in_pos_rounded;
16520 + out_seam = out_pos;
16521 + min_diff = abs_diff;
16525 + *_out_seam = out_seam;
16526 + *_in_seam = in_seam;
16528 + dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
16529 + __func__, out_seam, out_align, out_start, out_end,
16530 + in_seam, in_align, in_start, in_end, min_diff / 8192,
16531 + DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
16535 + * Tile left edges are required to be aligned to multiples of 8 bytes
16538 +static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
16541 + return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
16543 + return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
16547 + * Tile top edge alignment is only limited by chroma subsampling.
16549 +static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
16551 + return fmt->uv_height_dec > 1 ? 2 : 1;
16554 +static inline u32 tile_width_align(enum ipu_image_convert_type type,
16555 + const struct ipu_image_pixfmt *fmt,
16556 + enum ipu_rotate_mode rot_mode)
16558 + if (type == IMAGE_CONVERT_IN) {
16560 + * The IC burst reads 8 pixels at a time. Reading beyond the
16561 + * end of the line is usually acceptable. Those pixels are
16562 + * ignored, unless the IC has to write the scaled line in
16565 + return (!ipu_rot_mode_is_irt(rot_mode) &&
16566 + (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
16570 + * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
16571 + * formats to guarantee 8-byte aligned line start addresses in the
16572 + * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
16573 + * for all other formats.
16575 + return (ipu_rot_mode_is_irt(rot_mode) &&
16576 + fmt->planar && !fmt->uv_packed) ?
16577 + 8 * fmt->uv_width_dec : 8;
16580 +static inline u32 tile_height_align(enum ipu_image_convert_type type,
16581 + const struct ipu_image_pixfmt *fmt,
16582 + enum ipu_rotate_mode rot_mode)
16584 + if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
16588 + * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
16589 + * formats to guarantee 8-byte aligned line start addresses in the
16590 + * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
16591 + * for all other formats.
16593 + return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
16597 + * Fill in left position and width and for all tiles in an input column, and
16598 + * for all corresponding output tiles. If the 90° rotator is used, the output
16599 + * tiles are in a row, and output tile top position and height are set.
16601 +static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
16602 + unsigned int col,
16603 + struct ipu_image_convert_image *in,
16604 + unsigned int in_left, unsigned int in_width,
16605 + struct ipu_image_convert_image *out,
16606 + unsigned int out_left, unsigned int out_width)
16608 + unsigned int row, tile_idx;
16609 + struct ipu_image_tile *in_tile, *out_tile;
16611 + for (row = 0; row < in->num_rows; row++) {
16612 + tile_idx = in->num_cols * row + col;
16613 + in_tile = &in->tile[tile_idx];
16614 + out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
16616 + in_tile->left = in_left;
16617 + in_tile->width = in_width;
16619 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16620 + out_tile->top = out_left;
16621 + out_tile->height = out_width;
16623 + out_tile->left = out_left;
16624 + out_tile->width = out_width;
16630 + * Fill in top position and height and for all tiles in an input row, and
16631 + * for all corresponding output tiles. If the 90° rotator is used, the output
16632 + * tiles are in a column, and output tile left position and width are set.
16634 +static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
16635 + struct ipu_image_convert_image *in,
16636 + unsigned int in_top, unsigned int in_height,
16637 + struct ipu_image_convert_image *out,
16638 + unsigned int out_top, unsigned int out_height)
16640 + unsigned int col, tile_idx;
16641 + struct ipu_image_tile *in_tile, *out_tile;
16643 + for (col = 0; col < in->num_cols; col++) {
16644 + tile_idx = in->num_cols * row + col;
16645 + in_tile = &in->tile[tile_idx];
16646 + out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
16648 + in_tile->top = in_top;
16649 + in_tile->height = in_height;
16651 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16652 + out_tile->left = out_top;
16653 + out_tile->width = out_height;
16655 + out_tile->top = out_top;
16656 + out_tile->height = out_height;
16662 + * Find the best horizontal and vertical seam positions to split into tiles.
16663 + * Minimize the fractional part of the input sampling position for the
16664 + * top / left pixels of each tile.
16666 +static void find_seams(struct ipu_image_convert_ctx *ctx,
16667 + struct ipu_image_convert_image *in,
16668 + struct ipu_image_convert_image *out)
16670 + struct device *dev = ctx->chan->priv->ipu->dev;
16671 + unsigned int resized_width = out->base.rect.width;
16672 + unsigned int resized_height = out->base.rect.height;
16673 + unsigned int col;
16674 + unsigned int row;
16675 + unsigned int in_left_align = tile_left_align(in->fmt);
16676 + unsigned int in_top_align = tile_top_align(in->fmt);
16677 + unsigned int out_left_align = tile_left_align(out->fmt);
16678 + unsigned int out_top_align = tile_top_align(out->fmt);
16679 + unsigned int out_width_align = tile_width_align(out->type, out->fmt,
16681 + unsigned int out_height_align = tile_height_align(out->type, out->fmt,
16683 + unsigned int in_right = in->base.rect.width;
16684 + unsigned int in_bottom = in->base.rect.height;
16685 + unsigned int out_right = out->base.rect.width;
16686 + unsigned int out_bottom = out->base.rect.height;
16687 + unsigned int flipped_out_left;
16688 + unsigned int flipped_out_top;
16690 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
16691 + /* Switch width/height and align top left to IRT block size */
16692 + resized_width = out->base.rect.height;
16693 + resized_height = out->base.rect.width;
16694 + out_left_align = out_height_align;
16695 + out_top_align = out_width_align;
16696 + out_width_align = out_left_align;
16697 + out_height_align = out_top_align;
16698 + out_right = out->base.rect.height;
16699 + out_bottom = out->base.rect.width;
16702 + for (col = in->num_cols - 1; col > 0; col--) {
16703 + bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
16704 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
16705 + bool allow_out_overshoot = (col < in->num_cols - 1) &&
16706 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
16707 + unsigned int in_left;
16708 + unsigned int out_left;
16711 + * Align input width to burst length if the scaling step flips
16715 + find_best_seam(ctx, col,
16716 + in_right, out_right,
16717 + in_left_align, out_left_align,
16718 + allow_in_overshoot ? 1 : 8 /* burst length */,
16719 + allow_out_overshoot ? 1 : out_width_align,
16720 + ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
16721 + &in_left, &out_left);
16723 + if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
16724 + flipped_out_left = resized_width - out_right;
16726 + flipped_out_left = out_left;
16728 + fill_tile_column(ctx, col, in, in_left, in_right - in_left,
16729 + out, flipped_out_left, out_right - out_left);
16731 + dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
16732 + in_left, in_right - in_left,
16733 + flipped_out_left, out_right - out_left);
16735 + in_right = in_left;
16736 + out_right = out_left;
16739 + flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
16740 + resized_width - out_right : 0;
16742 + fill_tile_column(ctx, 0, in, 0, in_right,
16743 + out, flipped_out_left, out_right);
16745 + dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
16746 + in_right, flipped_out_left, out_right);
16748 + for (row = in->num_rows - 1; row > 0; row--) {
16749 + bool allow_overshoot = row < in->num_rows - 1;
16750 + unsigned int in_top;
16751 + unsigned int out_top;
16753 + find_best_seam(ctx, row,
16754 + in_bottom, out_bottom,
16755 + in_top_align, out_top_align,
16756 + 1, allow_overshoot ? 1 : out_height_align,
16757 + ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
16758 + &in_top, &out_top);
16760 + if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
16761 + ipu_rot_mode_is_irt(ctx->rot_mode))
16762 + flipped_out_top = resized_height - out_bottom;
16764 + flipped_out_top = out_top;
16766 + fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
16767 + out, flipped_out_top, out_bottom - out_top);
16769 + dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
16770 + in_top, in_bottom - in_top,
16771 + flipped_out_top, out_bottom - out_top);
16773 + in_bottom = in_top;
16774 + out_bottom = out_top;
16777 + if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
16778 + ipu_rot_mode_is_irt(ctx->rot_mode))
16779 + flipped_out_top = resized_height - out_bottom;
16781 + flipped_out_top = 0;
16783 + fill_tile_row(ctx, 0, in, 0, in_bottom,
16784 + out, flipped_out_top, out_bottom);
16786 + dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
16787 + in_bottom, flipped_out_top, out_bottom);
16790 +static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
16791 + struct ipu_image_convert_image *image)
16793 + struct ipu_image_convert_chan *chan = ctx->chan;
16794 + struct ipu_image_convert_priv *priv = chan->priv;
16795 + unsigned int max_width = 1024;
16796 + unsigned int max_height = 1024;
16799 + if (image->type == IMAGE_CONVERT_IN) {
16800 + /* Up to 4096x4096 input tile size */
16801 + max_width <<= ctx->downsize_coeff_h;
16802 + max_height <<= ctx->downsize_coeff_v;
16805 + for (i = 0; i < ctx->num_tiles; i++) {
16806 + struct ipu_image_tile *tile;
16807 + const unsigned int row = i / image->num_cols;
16808 + const unsigned int col = i % image->num_cols;
16810 + if (image->type == IMAGE_CONVERT_OUT)
16811 + tile = &image->tile[ctx->out_tile_map[i]];
16813 + tile = &image->tile[i];
16815 + tile->size = ((tile->height * image->fmt->bpp) >> 3) *
16818 + if (image->fmt->planar) {
16819 + tile->stride = tile->width;
16820 + tile->rot_stride = tile->height;
16823 + (image->fmt->bpp * tile->width) >> 3;
16824 + tile->rot_stride =
16825 + (image->fmt->bpp * tile->height) >> 3;
16828 + dev_dbg(priv->ipu->dev,
16829 + "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
16830 + chan->ic_task, ctx,
16831 + image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
16833 + tile->width, tile->height, tile->left, tile->top);
16835 + if (!tile->width || tile->width > max_width ||
16836 + !tile->height || tile->height > max_height) {
16837 + dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
16838 + image->type == IMAGE_CONVERT_IN ? "input" :
16839 + "output", tile->width, tile->height);
16848 + * Use the rotation transformation to find the tile coordinates
16849 + * (row, col) of a tile in the destination frame that corresponds
16850 + * to the given tile coordinates of a source frame. The destination
16851 + * coordinate is then converted to a tile index.
16853 +static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
16854 + int src_row, int src_col)
16856 + struct ipu_image_convert_chan *chan = ctx->chan;
16857 + struct ipu_image_convert_priv *priv = chan->priv;
16858 + struct ipu_image_convert_image *s_image = &ctx->in;
16859 + struct ipu_image_convert_image *d_image = &ctx->out;
16860 + int dst_row, dst_col;
16862 + /* with no rotation it's a 1:1 mapping */
16863 + if (ctx->rot_mode == IPU_ROTATE_NONE)
16864 + return src_row * s_image->num_cols + src_col;
16867 + * before doing the transform, first we have to translate
16868 + * source row,col for an origin in the center of s_image
16870 + src_row = src_row * 2 - (s_image->num_rows - 1);
16871 + src_col = src_col * 2 - (s_image->num_cols - 1);
16873 + /* do the rotation transform */
16874 + if (ctx->rot_mode & IPU_ROT_BIT_90) {
16875 + dst_col = -src_row;
16876 + dst_row = src_col;
16878 + dst_col = src_col;
16879 + dst_row = src_row;
16883 + if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
16884 + dst_col = -dst_col;
16885 + if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
16886 + dst_row = -dst_row;
16888 + dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
16889 + chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
16892 + * finally translate dest row,col using an origin in upper
16893 + * left of d_image
16895 + dst_row += d_image->num_rows - 1;
16896 + dst_col += d_image->num_cols - 1;
16900 + return dst_row * d_image->num_cols + dst_col;
16904 + * Fill the out_tile_map[] with transformed destination tile indeces.
16906 +static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
16908 + struct ipu_image_convert_image *s_image = &ctx->in;
16909 + unsigned int row, col, tile = 0;
16911 + for (row = 0; row < s_image->num_rows; row++) {
16912 + for (col = 0; col < s_image->num_cols; col++) {
16913 + ctx->out_tile_map[tile] =
16914 + transform_tile_index(ctx, row, col);
16920 +static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
16921 + struct ipu_image_convert_image *image)
16923 + struct ipu_image_convert_chan *chan = ctx->chan;
16924 + struct ipu_image_convert_priv *priv = chan->priv;
16925 + const struct ipu_image_pixfmt *fmt = image->fmt;
16926 + unsigned int row, col, tile = 0;
16927 + u32 H, top, y_stride, uv_stride;
16928 + u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
16929 + u32 y_row_off, y_col_off, y_off;
16930 + u32 y_size, uv_size;
16932 + /* setup some convenience vars */
16933 + H = image->base.pix.height;
16935 + y_stride = image->stride;
16936 + uv_stride = y_stride / fmt->uv_width_dec;
16937 + if (fmt->uv_packed)
16940 + y_size = H * y_stride;
16941 + uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
16943 + for (row = 0; row < image->num_rows; row++) {
16944 + top = image->tile[tile].top;
16945 + y_row_off = top * y_stride;
16946 + uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
16948 + for (col = 0; col < image->num_cols; col++) {
16949 + y_col_off = image->tile[tile].left;
16950 + uv_col_off = y_col_off / fmt->uv_width_dec;
16951 + if (fmt->uv_packed)
16954 + y_off = y_row_off + y_col_off;
16955 + uv_off = uv_row_off + uv_col_off;
16957 + u_off = y_size - y_off + uv_off;
16958 + v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
16959 + if (fmt->uv_swapped) {
16965 + image->tile[tile].offset = y_off;
16966 + image->tile[tile].u_off = u_off;
16967 + image->tile[tile++].v_off = v_off;
16969 + if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
16970 + dev_err(priv->ipu->dev,
16971 + "task %u: ctx %p: %s@[%d,%d]: "
16972 + "y_off %08x, u_off %08x, v_off %08x\n",
16973 + chan->ic_task, ctx,
16974 + image->type == IMAGE_CONVERT_IN ?
16975 + "Input" : "Output", row, col,
16976 + y_off, u_off, v_off);
16985 +static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
16986 + struct ipu_image_convert_image *image)
16988 + struct ipu_image_convert_chan *chan = ctx->chan;
16989 + struct ipu_image_convert_priv *priv = chan->priv;
16990 + const struct ipu_image_pixfmt *fmt = image->fmt;
16991 + unsigned int row, col, tile = 0;
16992 + u32 bpp, stride, offset;
16993 + u32 row_off, col_off;
16995 + /* setup some convenience vars */
16996 + stride = image->stride;
16999 + for (row = 0; row < image->num_rows; row++) {
17000 + row_off = image->tile[tile].top * stride;
17002 + for (col = 0; col < image->num_cols; col++) {
17003 + col_off = (image->tile[tile].left * bpp) >> 3;
17005 + offset = row_off + col_off;
17007 + image->tile[tile].offset = offset;
17008 + image->tile[tile].u_off = 0;
17009 + image->tile[tile++].v_off = 0;
17011 + if (offset & 0x7) {
17012 + dev_err(priv->ipu->dev,
17013 + "task %u: ctx %p: %s@[%d,%d]: "
17015 + chan->ic_task, ctx,
17016 + image->type == IMAGE_CONVERT_IN ?
17017 + "Input" : "Output", row, col,
17018 + row_off + col_off);
17027 +static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
17028 + struct ipu_image_convert_image *image)
17030 + if (image->fmt->planar)
17031 + return calc_tile_offsets_planar(ctx, image);
17033 + return calc_tile_offsets_packed(ctx, image);
17037 + * Calculate the resizing ratio for the IC main processing section given input
17038 + * size, fixed downsizing coefficient, and output size.
17039 + * Either round to closest for the next tile's first pixel to minimize seams
17040 + * and distortion (for all but right column / bottom row), or round down to
17041 + * avoid sampling beyond the edges of the input image for this tile's last
17043 + * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
17045 +static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
17046 + u32 output_size, bool allow_overshoot)
17048 + u32 downsized = input_size >> downsize_coeff;
17050 + if (allow_overshoot)
17051 + return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
17053 + return 8192 * (downsized - 1) / (output_size - 1);
17057 + * Slightly modify resize coefficients per tile to hide the bilinear
17058 + * interpolator reset at tile borders, shifting the right / bottom edge
17059 + * by up to a half input pixel. This removes noticeable seams between
17060 + * tiles at higher upscaling factors.
17062 +static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
17064 + struct ipu_image_convert_chan *chan = ctx->chan;
17065 + struct ipu_image_convert_priv *priv = chan->priv;
17066 + struct ipu_image_tile *in_tile, *out_tile;
17067 + unsigned int col, row, tile_idx;
17068 + unsigned int last_output;
17070 + for (col = 0; col < ctx->in.num_cols; col++) {
17071 + bool closest = (col < ctx->in.num_cols - 1) &&
17072 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
17073 + u32 resized_width;
17074 + u32 resize_coeff_h;
17078 + in_tile = &ctx->in.tile[tile_idx];
17079 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17081 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
17082 + resized_width = out_tile->height;
17084 + resized_width = out_tile->width;
17086 + resize_coeff_h = calc_resize_coeff(in_tile->width,
17087 + ctx->downsize_coeff_h,
17088 + resized_width, closest);
17090 + dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
17091 + __func__, col, resize_coeff_h);
17094 + * With the horizontal scaling factor known, round up resized
17095 + * width (output width or height) to burst size.
17097 + resized_width = round_up(resized_width, 8);
17100 + * Calculate input width from the last accessed input pixel
17101 + * given resized width and scaling coefficients. Round up to
17104 + last_output = resized_width - 1;
17105 + if (closest && ((last_output * resize_coeff_h) % 8192))
17107 + in_width = round_up(
17108 + (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
17109 + << ctx->downsize_coeff_h, 8);
17111 + for (row = 0; row < ctx->in.num_rows; row++) {
17112 + tile_idx = row * ctx->in.num_cols + col;
17113 + in_tile = &ctx->in.tile[tile_idx];
17114 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17116 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
17117 + out_tile->height = resized_width;
17119 + out_tile->width = resized_width;
17121 + in_tile->width = in_width;
17124 + ctx->resize_coeffs_h[col] = resize_coeff_h;
17127 + for (row = 0; row < ctx->in.num_rows; row++) {
17128 + bool closest = (row < ctx->in.num_rows - 1) &&
17129 + !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
17130 + u32 resized_height;
17131 + u32 resize_coeff_v;
17134 + tile_idx = row * ctx->in.num_cols;
17135 + in_tile = &ctx->in.tile[tile_idx];
17136 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17138 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
17139 + resized_height = out_tile->width;
17141 + resized_height = out_tile->height;
17143 + resize_coeff_v = calc_resize_coeff(in_tile->height,
17144 + ctx->downsize_coeff_v,
17145 + resized_height, closest);
17147 + dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
17148 + __func__, row, resize_coeff_v);
17151 + * With the vertical scaling factor known, round up resized
17152 + * height (output width or height) to IDMAC limitations.
17154 + resized_height = round_up(resized_height, 2);
17157 + * Calculate input width from the last accessed input pixel
17158 + * given resized height and scaling coefficients. Align to
17159 + * IDMAC restrictions.
17161 + last_output = resized_height - 1;
17162 + if (closest && ((last_output * resize_coeff_v) % 8192))
17164 + in_height = round_up(
17165 + (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
17166 + << ctx->downsize_coeff_v, 2);
17168 + for (col = 0; col < ctx->in.num_cols; col++) {
17169 + tile_idx = row * ctx->in.num_cols + col;
17170 + in_tile = &ctx->in.tile[tile_idx];
17171 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
17173 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
17174 + out_tile->width = resized_height;
17176 + out_tile->height = resized_height;
17178 + in_tile->height = in_height;
17181 + ctx->resize_coeffs_v[row] = resize_coeff_v;
17186 + * return the number of runs in given queue (pending_q or done_q)
17187 + * for this context. hold irqlock when calling.
17189 +static int get_run_count(struct ipu_image_convert_ctx *ctx,
17190 + struct list_head *q)
17192 + struct ipu_image_convert_run *run;
17195 + lockdep_assert_held(&ctx->chan->irqlock);
17197 + list_for_each_entry(run, q, list) {
17198 + if (run->ctx == ctx)
17205 +static void convert_stop(struct ipu_image_convert_run *run)
17207 + struct ipu_image_convert_ctx *ctx = run->ctx;
17208 + struct ipu_image_convert_chan *chan = ctx->chan;
17209 + struct ipu_image_convert_priv *priv = chan->priv;
17211 + dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
17212 + __func__, chan->ic_task, ctx, run);
17214 + /* disable IC tasks and the channels */
17215 + ipu_ic_task_disable(chan->ic);
17216 + ipu_idmac_disable_channel(chan->in_chan);
17217 + ipu_idmac_disable_channel(chan->out_chan);
17219 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17220 + ipu_idmac_disable_channel(chan->rotation_in_chan);
17221 + ipu_idmac_disable_channel(chan->rotation_out_chan);
17222 + ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
17225 + ipu_ic_disable(chan->ic);
17228 +static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
17229 + struct ipuv3_channel *channel,
17230 + struct ipu_image_convert_image *image,
17231 + enum ipu_rotate_mode rot_mode,
17232 + bool rot_swap_width_height,
17233 + unsigned int tile)
17235 + struct ipu_image_convert_chan *chan = ctx->chan;
17236 + unsigned int burst_size;
17237 + u32 width, height, stride;
17238 + dma_addr_t addr0, addr1 = 0;
17239 + struct ipu_image tile_image;
17240 + unsigned int tile_idx[2];
17242 + if (image->type == IMAGE_CONVERT_OUT) {
17243 + tile_idx[0] = ctx->out_tile_map[tile];
17244 + tile_idx[1] = ctx->out_tile_map[1];
17246 + tile_idx[0] = tile;
17250 + if (rot_swap_width_height) {
17251 + width = image->tile[tile_idx[0]].height;
17252 + height = image->tile[tile_idx[0]].width;
17253 + stride = image->tile[tile_idx[0]].rot_stride;
17254 + addr0 = ctx->rot_intermediate[0].phys;
17255 + if (ctx->double_buffering)
17256 + addr1 = ctx->rot_intermediate[1].phys;
17258 + width = image->tile[tile_idx[0]].width;
17259 + height = image->tile[tile_idx[0]].height;
17260 + stride = image->stride;
17261 + addr0 = image->base.phys0 +
17262 + image->tile[tile_idx[0]].offset;
17263 + if (ctx->double_buffering)
17264 + addr1 = image->base.phys0 +
17265 + image->tile[tile_idx[1]].offset;
17268 + ipu_cpmem_zero(channel);
17270 + memset(&tile_image, 0, sizeof(tile_image));
17271 + tile_image.pix.width = tile_image.rect.width = width;
17272 + tile_image.pix.height = tile_image.rect.height = height;
17273 + tile_image.pix.bytesperline = stride;
17274 + tile_image.pix.pixelformat = image->fmt->fourcc;
17275 + tile_image.phys0 = addr0;
17276 + tile_image.phys1 = addr1;
17277 + if (image->fmt->planar && !rot_swap_width_height) {
17278 + tile_image.u_offset = image->tile[tile_idx[0]].u_off;
17279 + tile_image.v_offset = image->tile[tile_idx[0]].v_off;
17282 + ipu_cpmem_set_image(channel, &tile_image);
17285 + ipu_cpmem_set_rotation(channel, rot_mode);
17288 + * Skip writing U and V components to odd rows in the output
17289 + * channels for planar 4:2:0.
17291 + if ((channel == chan->out_chan ||
17292 + channel == chan->rotation_out_chan) &&
17293 + image->fmt->planar && image->fmt->uv_height_dec == 2)
17294 + ipu_cpmem_skip_odd_chroma_rows(channel);
17296 + if (channel == chan->rotation_in_chan ||
17297 + channel == chan->rotation_out_chan) {
17299 + ipu_cpmem_set_block_mode(channel);
17301 + burst_size = (width % 16) ? 8 : 16;
17303 + ipu_cpmem_set_burstsize(channel, burst_size);
17305 + ipu_ic_task_idma_init(chan->ic, channel, width, height,
17306 + burst_size, rot_mode);
17309 + * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
17310 + * only do this when there is no PRG present.
17312 + if (!channel->ipu->prg_priv)
17313 + ipu_cpmem_set_axi_id(channel, 1);
17315 + ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
17318 +static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
17320 + struct ipu_image_convert_ctx *ctx = run->ctx;
17321 + struct ipu_image_convert_chan *chan = ctx->chan;
17322 + struct ipu_image_convert_priv *priv = chan->priv;
17323 + struct ipu_image_convert_image *s_image = &ctx->in;
17324 + struct ipu_image_convert_image *d_image = &ctx->out;
17325 + unsigned int dst_tile = ctx->out_tile_map[tile];
17326 + unsigned int dest_width, dest_height;
17327 + unsigned int col, row;
17331 + dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
17332 + __func__, chan->ic_task, ctx, run, tile, dst_tile);
17334 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17335 + /* swap width/height for resizer */
17336 + dest_width = d_image->tile[dst_tile].height;
17337 + dest_height = d_image->tile[dst_tile].width;
17339 + dest_width = d_image->tile[dst_tile].width;
17340 + dest_height = d_image->tile[dst_tile].height;
17343 + row = tile / s_image->num_cols;
17344 + col = tile % s_image->num_cols;
17346 + rsc = (ctx->downsize_coeff_v << 30) |
17347 + (ctx->resize_coeffs_v[row] << 16) |
17348 + (ctx->downsize_coeff_h << 14) |
17349 + (ctx->resize_coeffs_h[col]);
17351 + dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
17352 + __func__, s_image->tile[tile].width,
17353 + s_image->tile[tile].height, dest_width, dest_height, rsc);
17355 + /* setup the IC resizer and CSC */
17356 + ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
17357 + s_image->tile[tile].width,
17358 + s_image->tile[tile].height,
17363 + dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
17367 + /* init the source MEM-->IC PP IDMAC channel */
17368 + init_idmac_channel(ctx, chan->in_chan, s_image,
17369 + IPU_ROTATE_NONE, false, tile);
17371 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17372 + /* init the IC PP-->MEM IDMAC channel */
17373 + init_idmac_channel(ctx, chan->out_chan, d_image,
17374 + IPU_ROTATE_NONE, true, tile);
17376 + /* init the MEM-->IC PP ROT IDMAC channel */
17377 + init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
17378 + ctx->rot_mode, true, tile);
17380 + /* init the destination IC PP ROT-->MEM IDMAC channel */
17381 + init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
17382 + IPU_ROTATE_NONE, false, tile);
17384 + /* now link IC PP-->MEM to MEM-->IC PP ROT */
17385 + ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
17387 + /* init the destination IC PP-->MEM IDMAC channel */
17388 + init_idmac_channel(ctx, chan->out_chan, d_image,
17389 + ctx->rot_mode, false, tile);
17392 + /* enable the IC */
17393 + ipu_ic_enable(chan->ic);
17395 + /* set buffers ready */
17396 + ipu_idmac_select_buffer(chan->in_chan, 0);
17397 + ipu_idmac_select_buffer(chan->out_chan, 0);
17398 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
17399 + ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
17400 + if (ctx->double_buffering) {
17401 + ipu_idmac_select_buffer(chan->in_chan, 1);
17402 + ipu_idmac_select_buffer(chan->out_chan, 1);
17403 + if (ipu_rot_mode_is_irt(ctx->rot_mode))
17404 + ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
17407 + /* enable the channels! */
17408 + ipu_idmac_enable_channel(chan->in_chan);
17409 + ipu_idmac_enable_channel(chan->out_chan);
17410 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17411 + ipu_idmac_enable_channel(chan->rotation_in_chan);
17412 + ipu_idmac_enable_channel(chan->rotation_out_chan);
17415 + ipu_ic_task_enable(chan->ic);
17417 + ipu_cpmem_dump(chan->in_chan);
17418 + ipu_cpmem_dump(chan->out_chan);
17419 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17420 + ipu_cpmem_dump(chan->rotation_in_chan);
17421 + ipu_cpmem_dump(chan->rotation_out_chan);
17424 + ipu_dump(priv->ipu);
17429 +/* hold irqlock when calling */
17430 +static int do_run(struct ipu_image_convert_run *run)
17432 + struct ipu_image_convert_ctx *ctx = run->ctx;
17433 + struct ipu_image_convert_chan *chan = ctx->chan;
17435 + lockdep_assert_held(&chan->irqlock);
17437 + ctx->in.base.phys0 = run->in_phys;
17438 + ctx->out.base.phys0 = run->out_phys;
17440 + ctx->cur_buf_num = 0;
17441 + ctx->next_tile = 1;
17443 + /* remove run from pending_q and set as current */
17444 + list_del(&run->list);
17445 + chan->current_run = run;
17447 + return convert_start(run, 0);
17450 +/* hold irqlock when calling */
17451 +static void run_next(struct ipu_image_convert_chan *chan)
17453 + struct ipu_image_convert_priv *priv = chan->priv;
17454 + struct ipu_image_convert_run *run, *tmp;
17457 + lockdep_assert_held(&chan->irqlock);
17459 + list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
17460 + /* skip contexts that are aborting */
17461 + if (run->ctx->aborting) {
17462 + dev_dbg(priv->ipu->dev,
17463 + "%s: task %u: skipping aborting ctx %p run %p\n",
17464 + __func__, chan->ic_task, run->ctx, run);
17468 + ret = do_run(run);
17473 + * something went wrong with start, add the run
17474 + * to done q and continue to the next run in the
17477 + run->status = ret;
17478 + list_add_tail(&run->list, &chan->done_q);
17479 + chan->current_run = NULL;
17483 +static void empty_done_q(struct ipu_image_convert_chan *chan)
17485 + struct ipu_image_convert_priv *priv = chan->priv;
17486 + struct ipu_image_convert_run *run;
17487 + unsigned long flags;
17489 + spin_lock_irqsave(&chan->irqlock, flags);
17491 + while (!list_empty(&chan->done_q)) {
17492 + run = list_entry(chan->done_q.next,
17493 + struct ipu_image_convert_run,
17496 + list_del(&run->list);
17498 + dev_dbg(priv->ipu->dev,
17499 + "%s: task %u: completing ctx %p run %p with %d\n",
17500 + __func__, chan->ic_task, run->ctx, run, run->status);
17502 + /* call the completion callback and free the run */
17503 + spin_unlock_irqrestore(&chan->irqlock, flags);
17504 + run->ctx->complete(run, run->ctx->complete_context);
17505 + spin_lock_irqsave(&chan->irqlock, flags);
17508 + spin_unlock_irqrestore(&chan->irqlock, flags);
17512 + * the bottom half thread clears out the done_q, calling the
17513 + * completion handler for each.
17515 +static irqreturn_t do_bh(int irq, void *dev_id)
17517 + struct ipu_image_convert_chan *chan = dev_id;
17518 + struct ipu_image_convert_priv *priv = chan->priv;
17519 + struct ipu_image_convert_ctx *ctx;
17520 + unsigned long flags;
17522 + dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
17525 + empty_done_q(chan);
17527 + spin_lock_irqsave(&chan->irqlock, flags);
17530 + * the done_q is cleared out, signal any contexts
17531 + * that are aborting that abort can complete.
17533 + list_for_each_entry(ctx, &chan->ctx_list, list) {
17534 + if (ctx->aborting) {
17535 + dev_dbg(priv->ipu->dev,
17536 + "%s: task %u: signaling abort for ctx %p\n",
17537 + __func__, chan->ic_task, ctx);
17538 + complete_all(&ctx->aborted);
17542 + spin_unlock_irqrestore(&chan->irqlock, flags);
17544 + dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
17547 + return IRQ_HANDLED;
17550 +static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
17552 + unsigned int cur_tile = ctx->next_tile - 1;
17553 + unsigned int next_tile = ctx->next_tile;
17555 + if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
17556 + ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
17557 + ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
17558 + ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
17559 + ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
17560 + ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
17561 + ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
17562 + ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
17568 +/* hold irqlock when calling */
17569 +static irqreturn_t do_irq(struct ipu_image_convert_run *run)
17571 + struct ipu_image_convert_ctx *ctx = run->ctx;
17572 + struct ipu_image_convert_chan *chan = ctx->chan;
17573 + struct ipu_image_tile *src_tile, *dst_tile;
17574 + struct ipu_image_convert_image *s_image = &ctx->in;
17575 + struct ipu_image_convert_image *d_image = &ctx->out;
17576 + struct ipuv3_channel *outch;
17577 + unsigned int dst_idx;
17579 + lockdep_assert_held(&chan->irqlock);
17581 + outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
17582 + chan->rotation_out_chan : chan->out_chan;
17585 + * It is difficult to stop the channel DMA before the channels
17586 + * enter the paused state. Without double-buffering the channels
17587 + * are always in a paused state when the EOF irq occurs, so it
17588 + * is safe to stop the channels now. For double-buffering we
17589 + * just ignore the abort until the operation completes, when it
17590 + * is safe to shut down.
17592 + if (ctx->aborting && !ctx->double_buffering) {
17593 + convert_stop(run);
17594 + run->status = -EIO;
17598 + if (ctx->next_tile == ctx->num_tiles) {
17600 + * the conversion is complete
17602 + convert_stop(run);
17608 + * not done, place the next tile buffers.
17610 + if (!ctx->double_buffering) {
17611 + if (ic_settings_changed(ctx)) {
17612 + convert_stop(run);
17613 + convert_start(run, ctx->next_tile);
17615 + src_tile = &s_image->tile[ctx->next_tile];
17616 + dst_idx = ctx->out_tile_map[ctx->next_tile];
17617 + dst_tile = &d_image->tile[dst_idx];
17619 + ipu_cpmem_set_buffer(chan->in_chan, 0,
17620 + s_image->base.phys0 +
17621 + src_tile->offset);
17622 + ipu_cpmem_set_buffer(outch, 0,
17623 + d_image->base.phys0 +
17624 + dst_tile->offset);
17625 + if (s_image->fmt->planar)
17626 + ipu_cpmem_set_uv_offset(chan->in_chan,
17628 + src_tile->v_off);
17629 + if (d_image->fmt->planar)
17630 + ipu_cpmem_set_uv_offset(outch,
17632 + dst_tile->v_off);
17634 + ipu_idmac_select_buffer(chan->in_chan, 0);
17635 + ipu_idmac_select_buffer(outch, 0);
17637 + } else if (ctx->next_tile < ctx->num_tiles - 1) {
17639 + src_tile = &s_image->tile[ctx->next_tile + 1];
17640 + dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
17641 + dst_tile = &d_image->tile[dst_idx];
17643 + ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
17644 + s_image->base.phys0 + src_tile->offset);
17645 + ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
17646 + d_image->base.phys0 + dst_tile->offset);
17648 + ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
17649 + ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
17651 + ctx->cur_buf_num ^= 1;
17654 + ctx->next_tile++;
17655 + return IRQ_HANDLED;
17657 + list_add_tail(&run->list, &chan->done_q);
17658 + chan->current_run = NULL;
17660 + return IRQ_WAKE_THREAD;
17663 +static irqreturn_t norotate_irq(int irq, void *data)
17665 + struct ipu_image_convert_chan *chan = data;
17666 + struct ipu_image_convert_ctx *ctx;
17667 + struct ipu_image_convert_run *run;
17668 + unsigned long flags;
17671 + spin_lock_irqsave(&chan->irqlock, flags);
17673 + /* get current run and its context */
17674 + run = chan->current_run;
17682 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
17683 + /* this is a rotation operation, just ignore */
17684 + spin_unlock_irqrestore(&chan->irqlock, flags);
17685 + return IRQ_HANDLED;
17688 + ret = do_irq(run);
17690 + spin_unlock_irqrestore(&chan->irqlock, flags);
17694 +static irqreturn_t rotate_irq(int irq, void *data)
17696 + struct ipu_image_convert_chan *chan = data;
17697 + struct ipu_image_convert_priv *priv = chan->priv;
17698 + struct ipu_image_convert_ctx *ctx;
17699 + struct ipu_image_convert_run *run;
17700 + unsigned long flags;
17703 + spin_lock_irqsave(&chan->irqlock, flags);
17705 + /* get current run and its context */
17706 + run = chan->current_run;
17714 + if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
17715 + /* this was NOT a rotation operation, shouldn't happen */
17716 + dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
17717 + spin_unlock_irqrestore(&chan->irqlock, flags);
17718 + return IRQ_HANDLED;
17721 + ret = do_irq(run);
17723 + spin_unlock_irqrestore(&chan->irqlock, flags);
17728 + * try to force the completion of runs for this ctx. Called when
17729 + * abort wait times out in ipu_image_convert_abort().
17731 +static void force_abort(struct ipu_image_convert_ctx *ctx)
17733 + struct ipu_image_convert_chan *chan = ctx->chan;
17734 + struct ipu_image_convert_run *run;
17735 + unsigned long flags;
17737 + spin_lock_irqsave(&chan->irqlock, flags);
17739 + run = chan->current_run;
17740 + if (run && run->ctx == ctx) {
17741 + convert_stop(run);
17742 + run->status = -EIO;
17743 + list_add_tail(&run->list, &chan->done_q);
17744 + chan->current_run = NULL;
17748 + spin_unlock_irqrestore(&chan->irqlock, flags);
17750 + empty_done_q(chan);
17753 +static void release_ipu_resources(struct ipu_image_convert_chan *chan)
17755 + if (chan->out_eof_irq >= 0)
17756 + free_irq(chan->out_eof_irq, chan);
17757 + if (chan->rot_out_eof_irq >= 0)
17758 + free_irq(chan->rot_out_eof_irq, chan);
17760 + if (!IS_ERR_OR_NULL(chan->in_chan))
17761 + ipu_idmac_put(chan->in_chan);
17762 + if (!IS_ERR_OR_NULL(chan->out_chan))
17763 + ipu_idmac_put(chan->out_chan);
17764 + if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
17765 + ipu_idmac_put(chan->rotation_in_chan);
17766 + if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
17767 + ipu_idmac_put(chan->rotation_out_chan);
17768 + if (!IS_ERR_OR_NULL(chan->ic))
17769 + ipu_ic_put(chan->ic);
17771 + chan->in_chan = chan->out_chan = chan->rotation_in_chan =
17772 + chan->rotation_out_chan = NULL;
17773 + chan->out_eof_irq = chan->rot_out_eof_irq = -1;
17776 +static int get_ipu_resources(struct ipu_image_convert_chan *chan)
17778 + const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
17779 + struct ipu_image_convert_priv *priv = chan->priv;
17783 + chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
17784 + if (IS_ERR(chan->ic)) {
17785 + dev_err(priv->ipu->dev, "could not acquire IC\n");
17786 + ret = PTR_ERR(chan->ic);
17790 + /* get IDMAC channels */
17791 + chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
17792 + chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
17793 + if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
17794 + dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
17799 + chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
17800 + chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
17801 + if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
17802 + dev_err(priv->ipu->dev,
17803 + "could not acquire idmac rotation channels\n");
17808 + /* acquire the EOF interrupts */
17809 + chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
17813 + ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh,
17814 + 0, "ipu-ic", chan);
17816 + dev_err(priv->ipu->dev, "could not acquire irq %d\n",
17817 + chan->out_eof_irq);
17818 + chan->out_eof_irq = -1;
17822 + chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
17823 + chan->rotation_out_chan,
17826 + ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh,
17827 + 0, "ipu-ic", chan);
17829 + dev_err(priv->ipu->dev, "could not acquire irq %d\n",
17830 + chan->rot_out_eof_irq);
17831 + chan->rot_out_eof_irq = -1;
17837 + release_ipu_resources(chan);
17841 +static int fill_image(struct ipu_image_convert_ctx *ctx,
17842 + struct ipu_image_convert_image *ic_image,
17843 + struct ipu_image *image,
17844 + enum ipu_image_convert_type type)
17846 + struct ipu_image_convert_priv *priv = ctx->chan->priv;
17848 + ic_image->base = *image;
17849 + ic_image->type = type;
17851 + ic_image->fmt = get_format(image->pix.pixelformat);
17852 + if (!ic_image->fmt) {
17853 + dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
17854 + type == IMAGE_CONVERT_OUT ? "Output" : "Input");
17858 + if (ic_image->fmt->planar)
17859 + ic_image->stride = ic_image->base.pix.width;
17861 + ic_image->stride = ic_image->base.pix.bytesperline;
17866 +/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
17867 +static unsigned int clamp_align(unsigned int x, unsigned int min,
17868 + unsigned int max, unsigned int align)
17870 + /* Bits that must be zero to be aligned */
17871 + unsigned int mask = ~((1 << align) - 1);
17873 + /* Clamp to aligned min and max */
17874 + x = clamp(x, (min + ~mask) & mask, max & mask);
17876 + /* Round to nearest aligned value */
17878 + x = (x + (1 << (align - 1))) & mask;
17883 +/* Adjusts input/output images to IPU restrictions */
17884 +void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
17885 + enum ipu_rotate_mode rot_mode)
17887 + const struct ipu_image_pixfmt *infmt, *outfmt;
17888 + u32 w_align_out, h_align_out;
17889 + u32 w_align_in, h_align_in;
17891 + infmt = get_format(in->pix.pixelformat);
17892 + outfmt = get_format(out->pix.pixelformat);
17894 + /* set some default pixel formats if needed */
17896 + in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
17897 + infmt = get_format(V4L2_PIX_FMT_RGB24);
17900 + out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
17901 + outfmt = get_format(V4L2_PIX_FMT_RGB24);
17904 + /* image converter does not handle fields */
17905 + in->pix.field = out->pix.field = V4L2_FIELD_NONE;
17907 + /* resizer cannot downsize more than 4:1 */
17908 + if (ipu_rot_mode_is_irt(rot_mode)) {
17909 + out->pix.height = max_t(__u32, out->pix.height,
17910 + in->pix.width / 4);
17911 + out->pix.width = max_t(__u32, out->pix.width,
17912 + in->pix.height / 4);
17914 + out->pix.width = max_t(__u32, out->pix.width,
17915 + in->pix.width / 4);
17916 + out->pix.height = max_t(__u32, out->pix.height,
17917 + in->pix.height / 4);
17920 + /* align input width/height */
17921 + w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
17923 + h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
17925 + in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
17927 + in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
17930 + /* align output width/height */
17931 + w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
17933 + h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
17935 + out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
17937 + out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
17940 + /* set input/output strides and image sizes */
17941 + in->pix.bytesperline = infmt->planar ?
17942 + clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
17944 + clamp_align((in->pix.width * infmt->bpp) >> 3,
17945 + ((2 << w_align_in) * infmt->bpp) >> 3,
17946 + (MAX_W * infmt->bpp) >> 3,
17948 + in->pix.sizeimage = infmt->planar ?
17949 + (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
17950 + in->pix.height * in->pix.bytesperline;
17951 + out->pix.bytesperline = outfmt->planar ? out->pix.width :
17952 + (out->pix.width * outfmt->bpp) >> 3;
17953 + out->pix.sizeimage = outfmt->planar ?
17954 + (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
17955 + out->pix.height * out->pix.bytesperline;
17957 +EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
17960 + * this is used by ipu_image_convert_prepare() to verify set input and
17961 + * output images are valid before starting the conversion. Clients can
17962 + * also call it before calling ipu_image_convert_prepare().
17964 +int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
17965 + enum ipu_rotate_mode rot_mode)
17967 + struct ipu_image testin, testout;
17972 + ipu_image_convert_adjust(&testin, &testout, rot_mode);
17974 + if (testin.pix.width != in->pix.width ||
17975 + testin.pix.height != in->pix.height ||
17976 + testout.pix.width != out->pix.width ||
17977 + testout.pix.height != out->pix.height)
17982 +EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
17985 + * Call ipu_image_convert_prepare() to prepare for the conversion of
17986 + * given images and rotation mode. Returns a new conversion context.
17988 +struct ipu_image_convert_ctx *
17989 +ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
17990 + struct ipu_image *in, struct ipu_image *out,
17991 + enum ipu_rotate_mode rot_mode,
17992 + ipu_image_convert_cb_t complete,
17993 + void *complete_context)
17995 + struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
17996 + struct ipu_image_convert_image *s_image, *d_image;
17997 + struct ipu_image_convert_chan *chan;
17998 + struct ipu_image_convert_ctx *ctx;
17999 + unsigned long flags;
18004 + if (!in || !out || !complete ||
18005 + (ic_task != IC_TASK_VIEWFINDER &&
18006 + ic_task != IC_TASK_POST_PROCESSOR))
18007 + return ERR_PTR(-EINVAL);
18009 + /* verify the in/out images before continuing */
18010 + ret = ipu_image_convert_verify(in, out, rot_mode);
18012 + dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
18014 + return ERR_PTR(ret);
18017 + chan = &priv->chan[ic_task];
18019 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
18021 + return ERR_PTR(-ENOMEM);
18023 + dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
18024 + chan->ic_task, ctx);
18026 + ctx->chan = chan;
18027 + init_completion(&ctx->aborted);
18029 + ctx->rot_mode = rot_mode;
18031 + /* Sets ctx->in.num_rows/cols as well */
18032 + ret = calc_image_resize_coefficients(ctx, in, out);
18036 + s_image = &ctx->in;
18037 + d_image = &ctx->out;
18039 + /* set tiling and rotation */
18040 + if (ipu_rot_mode_is_irt(rot_mode)) {
18041 + d_image->num_rows = s_image->num_cols;
18042 + d_image->num_cols = s_image->num_rows;
18044 + d_image->num_rows = s_image->num_rows;
18045 + d_image->num_cols = s_image->num_cols;
18048 + ctx->num_tiles = d_image->num_cols * d_image->num_rows;
18050 + ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
18053 + ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
18057 + calc_out_tile_map(ctx);
18059 + find_seams(ctx, s_image, d_image);
18061 + ret = calc_tile_dimensions(ctx, s_image);
18065 + ret = calc_tile_offsets(ctx, s_image);
18069 + calc_tile_dimensions(ctx, d_image);
18070 + ret = calc_tile_offsets(ctx, d_image);
18074 + calc_tile_resize_coefficients(ctx);
18076 + ret = ipu_ic_calc_csc(&ctx->csc,
18077 + s_image->base.pix.ycbcr_enc,
18078 + s_image->base.pix.quantization,
18079 + ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
18080 + d_image->base.pix.ycbcr_enc,
18081 + d_image->base.pix.quantization,
18082 + ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
18086 + dump_format(ctx, s_image);
18087 + dump_format(ctx, d_image);
18089 + ctx->complete = complete;
18090 + ctx->complete_context = complete_context;
18093 + * Can we use double-buffering for this operation? If there is
18094 + * only one tile (the whole image can be converted in a single
18095 + * operation) there's no point in using double-buffering. Also,
18096 + * the IPU's IDMAC channels allow only a single U and V plane
18097 + * offset shared between both buffers, but these offsets change
18098 + * for every tile, and therefore would have to be updated for
18099 + * each buffer which is not possible. So double-buffering is
18100 + * impossible when either the source or destination images are
18101 + * a planar format (YUV420, YUV422P, etc.). Further, differently
18102 + * sized tiles or different resizing coefficients per tile
18103 + * prevent double-buffering as well.
18105 + ctx->double_buffering = (ctx->num_tiles > 1 &&
18106 + !s_image->fmt->planar &&
18107 + !d_image->fmt->planar);
18108 + for (i = 1; i < ctx->num_tiles; i++) {
18109 + if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
18110 + ctx->in.tile[i].height != ctx->in.tile[0].height ||
18111 + ctx->out.tile[i].width != ctx->out.tile[0].width ||
18112 + ctx->out.tile[i].height != ctx->out.tile[0].height) {
18113 + ctx->double_buffering = false;
18117 + for (i = 1; i < ctx->in.num_cols; i++) {
18118 + if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
18119 + ctx->double_buffering = false;
18123 + for (i = 1; i < ctx->in.num_rows; i++) {
18124 + if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
18125 + ctx->double_buffering = false;
18130 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
18131 + unsigned long intermediate_size = d_image->tile[0].size;
18133 + for (i = 1; i < ctx->num_tiles; i++) {
18134 + if (d_image->tile[i].size > intermediate_size)
18135 + intermediate_size = d_image->tile[i].size;
18138 + ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
18139 + intermediate_size);
18142 + if (ctx->double_buffering) {
18143 + ret = alloc_dma_buf(priv,
18144 + &ctx->rot_intermediate[1],
18145 + intermediate_size);
18147 + goto out_free_dmabuf0;
18151 + spin_lock_irqsave(&chan->irqlock, flags);
18153 + get_res = list_empty(&chan->ctx_list);
18155 + list_add_tail(&ctx->list, &chan->ctx_list);
18157 + spin_unlock_irqrestore(&chan->irqlock, flags);
18160 + ret = get_ipu_resources(chan);
18162 + goto out_free_dmabuf1;
18168 + free_dma_buf(priv, &ctx->rot_intermediate[1]);
18169 + spin_lock_irqsave(&chan->irqlock, flags);
18170 + list_del(&ctx->list);
18171 + spin_unlock_irqrestore(&chan->irqlock, flags);
18173 + free_dma_buf(priv, &ctx->rot_intermediate[0]);
18176 + return ERR_PTR(ret);
18178 +EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
18181 + * Carry out a single image conversion run. Only the physaddr's of the input
18182 + * and output image buffers are needed. The conversion context must have
18183 + * been created previously with ipu_image_convert_prepare().
18185 +int ipu_image_convert_queue(struct ipu_image_convert_run *run)
18187 + struct ipu_image_convert_chan *chan;
18188 + struct ipu_image_convert_priv *priv;
18189 + struct ipu_image_convert_ctx *ctx;
18190 + unsigned long flags;
18193 + if (!run || !run->ctx || !run->in_phys || !run->out_phys)
18197 + chan = ctx->chan;
18198 + priv = chan->priv;
18200 + dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
18201 + chan->ic_task, ctx, run);
18203 + INIT_LIST_HEAD(&run->list);
18205 + spin_lock_irqsave(&chan->irqlock, flags);
18207 + if (ctx->aborting) {
18212 + list_add_tail(&run->list, &chan->pending_q);
18214 + if (!chan->current_run) {
18215 + ret = do_run(run);
18217 + chan->current_run = NULL;
18220 + spin_unlock_irqrestore(&chan->irqlock, flags);
18223 +EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
18225 +/* Abort any active or pending conversions for this context */
18226 +static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
18228 + struct ipu_image_convert_chan *chan = ctx->chan;
18229 + struct ipu_image_convert_priv *priv = chan->priv;
18230 + struct ipu_image_convert_run *run, *active_run, *tmp;
18231 + unsigned long flags;
18232 + int run_count, ret;
18234 + spin_lock_irqsave(&chan->irqlock, flags);
18236 + /* move all remaining pending runs in this context to done_q */
18237 + list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
18238 + if (run->ctx != ctx)
18240 + run->status = -EIO;
18241 + list_move_tail(&run->list, &chan->done_q);
18244 + run_count = get_run_count(ctx, &chan->done_q);
18245 + active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
18246 + chan->current_run : NULL;
18249 + reinit_completion(&ctx->aborted);
18251 + ctx->aborting = true;
18253 + spin_unlock_irqrestore(&chan->irqlock, flags);
18255 + if (!run_count && !active_run) {
18256 + dev_dbg(priv->ipu->dev,
18257 + "%s: task %u: no abort needed for ctx %p\n",
18258 + __func__, chan->ic_task, ctx);
18262 + if (!active_run) {
18263 + empty_done_q(chan);
18267 + dev_dbg(priv->ipu->dev,
18268 + "%s: task %u: wait for completion: %d runs\n",
18269 + __func__, chan->ic_task, run_count);
18271 + ret = wait_for_completion_timeout(&ctx->aborted,
18272 + msecs_to_jiffies(10000));
18274 + dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
18275 + force_abort(ctx);
18279 +void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
18281 + __ipu_image_convert_abort(ctx);
18282 + ctx->aborting = false;
18284 +EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
18286 +/* Unprepare image conversion context */
18287 +void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
18289 + struct ipu_image_convert_chan *chan = ctx->chan;
18290 + struct ipu_image_convert_priv *priv = chan->priv;
18291 + unsigned long flags;
18294 + /* make sure no runs are hanging around */
18295 + __ipu_image_convert_abort(ctx);
18297 + dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
18298 + chan->ic_task, ctx);
18300 + spin_lock_irqsave(&chan->irqlock, flags);
18302 + list_del(&ctx->list);
18304 + put_res = list_empty(&chan->ctx_list);
18306 + spin_unlock_irqrestore(&chan->irqlock, flags);
18309 + release_ipu_resources(chan);
18311 + free_dma_buf(priv, &ctx->rot_intermediate[1]);
18312 + free_dma_buf(priv, &ctx->rot_intermediate[0]);
18316 +EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
18319 + * "Canned" asynchronous single image conversion. Allocates and returns
18320 + * a new conversion run. On successful return the caller must free the
18321 + * run and call ipu_image_convert_unprepare() after conversion completes.
18323 +struct ipu_image_convert_run *
18324 +ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
18325 + struct ipu_image *in, struct ipu_image *out,
18326 + enum ipu_rotate_mode rot_mode,
18327 + ipu_image_convert_cb_t complete,
18328 + void *complete_context)
18330 + struct ipu_image_convert_ctx *ctx;
18331 + struct ipu_image_convert_run *run;
18334 + ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
18335 + complete, complete_context);
18337 + return ERR_CAST(ctx);
18339 + run = kzalloc(sizeof(*run), GFP_KERNEL);
18341 + ipu_image_convert_unprepare(ctx);
18342 + return ERR_PTR(-ENOMEM);
18346 + run->in_phys = in->phys0;
18347 + run->out_phys = out->phys0;
18349 + ret = ipu_image_convert_queue(run);
18351 + ipu_image_convert_unprepare(ctx);
18353 + return ERR_PTR(ret);
18358 +EXPORT_SYMBOL_GPL(ipu_image_convert);
18360 +/* "Canned" synchronous single image conversion */
18361 +static void image_convert_sync_complete(struct ipu_image_convert_run *run,
18364 + struct completion *comp = data;
18369 +int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
18370 + struct ipu_image *in, struct ipu_image *out,
18371 + enum ipu_rotate_mode rot_mode)
18373 + struct ipu_image_convert_run *run;
18374 + struct completion comp;
18377 + init_completion(&comp);
18379 + run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
18380 + image_convert_sync_complete, &comp);
18382 + return PTR_ERR(run);
18384 + ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
18385 + ret = (ret == 0) ? -ETIMEDOUT : 0;
18387 + ipu_image_convert_unprepare(run->ctx);
18392 +EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
18394 +int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
18396 + struct ipu_image_convert_priv *priv;
18399 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
18403 + ipu->image_convert_priv = priv;
18406 + for (i = 0; i < IC_NUM_TASKS; i++) {
18407 + struct ipu_image_convert_chan *chan = &priv->chan[i];
18409 + chan->ic_task = i;
18410 + chan->priv = priv;
18411 + chan->dma_ch = &image_convert_dma_chan[i];
18412 + chan->out_eof_irq = -1;
18413 + chan->rot_out_eof_irq = -1;
18415 + spin_lock_init(&chan->irqlock);
18416 + INIT_LIST_HEAD(&chan->ctx_list);
18417 + INIT_LIST_HEAD(&chan->pending_q);
18418 + INIT_LIST_HEAD(&chan->done_q);
18424 +void ipu_image_convert_exit(struct ipu_soc *ipu)
18428 +++ b/drivers/gpu/ipu-v3/ipu-pre.c
18430 +// SPDX-License-Identifier: GPL-2.0-only
18432 + * Copyright (c) 2017 Lucas Stach, Pengutronix
18435 +#include <drm/drm_fourcc.h>
18436 +#include <linux/clk.h>
18437 +#include <linux/err.h>
18438 +#include <linux/genalloc.h>
18439 +#include <linux/module.h>
18440 +#include <linux/of.h>
18441 +#include <linux/platform_device.h>
18442 +#include <video/imx-ipu-v3.h>
18444 +#include "ipu-prv.h"
18446 +#define IPU_PRE_MAX_WIDTH 2048
18447 +#define IPU_PRE_NUM_SCANLINES 8
18449 +#define IPU_PRE_CTRL 0x000
18450 +#define IPU_PRE_CTRL_SET 0x004
18451 +#define IPU_PRE_CTRL_ENABLE (1 << 0)
18452 +#define IPU_PRE_CTRL_BLOCK_EN (1 << 1)
18453 +#define IPU_PRE_CTRL_BLOCK_16 (1 << 2)
18454 +#define IPU_PRE_CTRL_SDW_UPDATE (1 << 4)
18455 +#define IPU_PRE_CTRL_VFLIP (1 << 5)
18456 +#define IPU_PRE_CTRL_SO (1 << 6)
18457 +#define IPU_PRE_CTRL_INTERLACED_FIELD (1 << 7)
18458 +#define IPU_PRE_CTRL_HANDSHAKE_EN (1 << 8)
18459 +#define IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v) ((v & 0x3) << 9)
18460 +#define IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN (1 << 11)
18461 +#define IPU_PRE_CTRL_EN_REPEAT (1 << 28)
18462 +#define IPU_PRE_CTRL_TPR_REST_SEL (1 << 29)
18463 +#define IPU_PRE_CTRL_CLKGATE (1 << 30)
18464 +#define IPU_PRE_CTRL_SFTRST (1 << 31)
18466 +#define IPU_PRE_CUR_BUF 0x030
18468 +#define IPU_PRE_NEXT_BUF 0x040
18470 +#define IPU_PRE_TPR_CTRL 0x070
18471 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT(v) ((v & 0xff) << 0)
18472 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK 0xff
18473 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT (1 << 0)
18474 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF (1 << 4)
18475 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF (1 << 5)
18476 +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED (1 << 6)
18478 +#define IPU_PRE_PREFETCH_ENG_CTRL 0x080
18479 +#define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0)
18480 +#define IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v) ((v & 0x7) << 1)
18481 +#define IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
18482 +#define IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v) ((v & 0x7) << 8)
18483 +#define IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS (1 << 11)
18484 +#define IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE (1 << 12)
18485 +#define IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP (1 << 14)
18486 +#define IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN (1 << 15)
18488 +#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE 0x0a0
18489 +#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v) ((v & 0xffff) << 0)
18490 +#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v) ((v & 0xffff) << 16)
18492 +#define IPU_PRE_PREFETCH_ENG_PITCH 0x0d0
18493 +#define IPU_PRE_PREFETCH_ENG_PITCH_Y(v) ((v & 0xffff) << 0)
18494 +#define IPU_PRE_PREFETCH_ENG_PITCH_UV(v) ((v & 0xffff) << 16)
18496 +#define IPU_PRE_STORE_ENG_CTRL 0x110
18497 +#define IPU_PRE_STORE_ENG_CTRL_STORE_EN (1 << 0)
18498 +#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1)
18499 +#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
18501 +#define IPU_PRE_STORE_ENG_STATUS 0x120
18502 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_MASK 0xffff
18503 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_X_SHIFT 0
18504 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK 0x3fff
18505 +#define IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT 16
18506 +#define IPU_PRE_STORE_ENG_STATUS_STORE_FIFO_FULL (1 << 30)
18507 +#define IPU_PRE_STORE_ENG_STATUS_STORE_FIELD (1 << 31)
18509 +#define IPU_PRE_STORE_ENG_SIZE 0x130
18510 +#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0)
18511 +#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16)
18513 +#define IPU_PRE_STORE_ENG_PITCH 0x140
18514 +#define IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v) ((v & 0xffff) << 0)
18516 +#define IPU_PRE_STORE_ENG_ADDR 0x150
18519 + struct list_head list;
18520 + struct device *dev;
18522 + void __iomem *regs;
18523 + struct clk *clk_axi;
18524 + struct gen_pool *iram;
18526 + dma_addr_t buffer_paddr;
18527 + void *buffer_virt;
18529 + unsigned int safe_window_end;
18530 + unsigned int last_bufaddr;
18533 +static DEFINE_MUTEX(ipu_pre_list_mutex);
18534 +static LIST_HEAD(ipu_pre_list);
18535 +static int available_pres;
18537 +int ipu_pre_get_available_count(void)
18539 + return available_pres;
18543 +ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
18545 + struct device_node *pre_node = of_parse_phandle(dev->of_node,
18547 + struct ipu_pre *pre;
18549 + mutex_lock(&ipu_pre_list_mutex);
18550 + list_for_each_entry(pre, &ipu_pre_list, list) {
18551 + if (pre_node == pre->dev->of_node) {
18552 + mutex_unlock(&ipu_pre_list_mutex);
18553 + device_link_add(dev, pre->dev,
18554 + DL_FLAG_AUTOREMOVE_CONSUMER);
18555 + of_node_put(pre_node);
18559 + mutex_unlock(&ipu_pre_list_mutex);
18561 + of_node_put(pre_node);
18566 +int ipu_pre_get(struct ipu_pre *pre)
18573 + /* first get the engine out of reset and remove clock gating */
18574 + writel(0, pre->regs + IPU_PRE_CTRL);
18576 + /* init defaults that should be applied to all streams */
18577 + val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
18578 + IPU_PRE_CTRL_HANDSHAKE_EN |
18579 + IPU_PRE_CTRL_TPR_REST_SEL |
18580 + IPU_PRE_CTRL_SDW_UPDATE;
18581 + writel(val, pre->regs + IPU_PRE_CTRL);
18583 + pre->in_use = true;
18587 +void ipu_pre_put(struct ipu_pre *pre)
18589 + writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
18591 + pre->in_use = false;
18594 +void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
18595 + unsigned int height, unsigned int stride, u32 format,
18596 + uint64_t modifier, unsigned int bufaddr)
18598 + const struct drm_format_info *info = drm_format_info(format);
18599 + u32 active_bpp = info->cpp[0] >> 1;
18602 + /* calculate safe window for ctrl register updates */
18603 + if (modifier == DRM_FORMAT_MOD_LINEAR)
18604 + pre->safe_window_end = height - 2;
18606 + pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
18608 + writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
18609 + writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
18610 + pre->last_bufaddr = bufaddr;
18612 + val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
18613 + IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
18614 + IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
18615 + IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
18616 + IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
18617 + writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
18619 + val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
18620 + IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
18621 + writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
18623 + val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
18624 + writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
18626 + val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
18627 + IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
18628 + IPU_PRE_STORE_ENG_CTRL_STORE_EN;
18629 + writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
18631 + val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
18632 + IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
18633 + writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
18635 + val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
18636 + writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
18638 + writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
18640 + val = readl(pre->regs + IPU_PRE_TPR_CTRL);
18641 + val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
18642 + if (modifier != DRM_FORMAT_MOD_LINEAR) {
18643 + /* only support single buffer formats for now */
18644 + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
18645 + if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
18646 + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
18647 + if (info->cpp[0] == 2)
18648 + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
18650 + writel(val, pre->regs + IPU_PRE_TPR_CTRL);
18652 + val = readl(pre->regs + IPU_PRE_CTRL);
18653 + val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
18654 + IPU_PRE_CTRL_SDW_UPDATE;
18655 + if (modifier == DRM_FORMAT_MOD_LINEAR)
18656 + val &= ~IPU_PRE_CTRL_BLOCK_EN;
18658 + val |= IPU_PRE_CTRL_BLOCK_EN;
18659 + writel(val, pre->regs + IPU_PRE_CTRL);
18662 +void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
18664 + unsigned long timeout = jiffies + msecs_to_jiffies(5);
18665 + unsigned short current_yblock;
18668 + if (bufaddr == pre->last_bufaddr)
18671 + writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
18672 + pre->last_bufaddr = bufaddr;
18675 + if (time_after(jiffies, timeout)) {
18676 + dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
18680 + val = readl(pre->regs + IPU_PRE_STORE_ENG_STATUS);
18682 + (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
18683 + IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
18684 + } while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
18686 + writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
18689 +bool ipu_pre_update_pending(struct ipu_pre *pre)
18691 + return !!(readl_relaxed(pre->regs + IPU_PRE_CTRL) &
18692 + IPU_PRE_CTRL_SDW_UPDATE);
18695 +u32 ipu_pre_get_baddr(struct ipu_pre *pre)
18697 + return (u32)pre->buffer_paddr;
18700 +static int ipu_pre_probe(struct platform_device *pdev)
18702 + struct device *dev = &pdev->dev;
18703 + struct resource *res;
18704 + struct ipu_pre *pre;
18706 + pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
18710 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
18711 + pre->regs = devm_ioremap_resource(&pdev->dev, res);
18712 + if (IS_ERR(pre->regs))
18713 + return PTR_ERR(pre->regs);
18715 + pre->clk_axi = devm_clk_get(dev, "axi");
18716 + if (IS_ERR(pre->clk_axi))
18717 + return PTR_ERR(pre->clk_axi);
18719 + pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
18721 + return -EPROBE_DEFER;
18724 + * Allocate IRAM buffer with maximum size. This could be made dynamic,
18725 + * but as there is no other user of this IRAM region and we can fit all
18726 + * max sized buffers into it, there is no need yet.
18728 + pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
18729 + IPU_PRE_NUM_SCANLINES * 4,
18730 + &pre->buffer_paddr);
18731 + if (!pre->buffer_virt)
18734 + clk_prepare_enable(pre->clk_axi);
18737 + platform_set_drvdata(pdev, pre);
18738 + mutex_lock(&ipu_pre_list_mutex);
18739 + list_add(&pre->list, &ipu_pre_list);
18740 + available_pres++;
18741 + mutex_unlock(&ipu_pre_list_mutex);
18746 +static int ipu_pre_remove(struct platform_device *pdev)
18748 + struct ipu_pre *pre = platform_get_drvdata(pdev);
18750 + mutex_lock(&ipu_pre_list_mutex);
18751 + list_del(&pre->list);
18752 + available_pres--;
18753 + mutex_unlock(&ipu_pre_list_mutex);
18755 + clk_disable_unprepare(pre->clk_axi);
18757 + if (pre->buffer_virt)
18758 + gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
18759 + IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
18763 +static const struct of_device_id ipu_pre_dt_ids[] = {
18764 + { .compatible = "fsl,imx6qp-pre", },
18765 + { /* sentinel */ },
18768 +struct platform_driver ipu_pre_drv = {
18769 + .probe = ipu_pre_probe,
18770 + .remove = ipu_pre_remove,
18772 + .name = "imx-ipu-pre",
18773 + .of_match_table = ipu_pre_dt_ids,
18777 +++ b/drivers/gpu/ipu-v3/ipu-prg.c
18779 +// SPDX-License-Identifier: GPL-2.0-only
18781 + * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
18784 +#include <drm/drm_fourcc.h>
18785 +#include <linux/clk.h>
18786 +#include <linux/err.h>
18787 +#include <linux/iopoll.h>
18788 +#include <linux/mfd/syscon.h>
18789 +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
18790 +#include <linux/module.h>
18791 +#include <linux/of.h>
18792 +#include <linux/platform_device.h>
18793 +#include <linux/pm_runtime.h>
18794 +#include <linux/regmap.h>
18795 +#include <video/imx-ipu-v3.h>
18797 +#include "ipu-prv.h"
18799 +#define IPU_PRG_CTL 0x00
18800 +#define IPU_PRG_CTL_BYPASS(i) (1 << (0 + i))
18801 +#define IPU_PRG_CTL_SOFT_ARID_MASK 0x3
18802 +#define IPU_PRG_CTL_SOFT_ARID_SHIFT(i) (8 + i * 2)
18803 +#define IPU_PRG_CTL_SOFT_ARID(i, v) ((v & 0x3) << (8 + 2 * i))
18804 +#define IPU_PRG_CTL_SO(i) (1 << (16 + i))
18805 +#define IPU_PRG_CTL_VFLIP(i) (1 << (19 + i))
18806 +#define IPU_PRG_CTL_BLOCK_MODE(i) (1 << (22 + i))
18807 +#define IPU_PRG_CTL_CNT_LOAD_EN(i) (1 << (25 + i))
18808 +#define IPU_PRG_CTL_SOFTRST (1 << 30)
18809 +#define IPU_PRG_CTL_SHADOW_EN (1 << 31)
18811 +#define IPU_PRG_STATUS 0x04
18812 +#define IPU_PRG_STATUS_BUFFER0_READY(i) (1 << (0 + i * 2))
18813 +#define IPU_PRG_STATUS_BUFFER1_READY(i) (1 << (1 + i * 2))
18815 +#define IPU_PRG_QOS 0x08
18816 +#define IPU_PRG_QOS_ARID_MASK 0xf
18817 +#define IPU_PRG_QOS_ARID_SHIFT(i) (0 + i * 4)
18819 +#define IPU_PRG_REG_UPDATE 0x0c
18820 +#define IPU_PRG_REG_UPDATE_REG_UPDATE (1 << 0)
18822 +#define IPU_PRG_STRIDE(i) (0x10 + i * 0x4)
18823 +#define IPU_PRG_STRIDE_STRIDE_MASK 0x3fff
18825 +#define IPU_PRG_CROP_LINE 0x1c
18827 +#define IPU_PRG_THD 0x20
18829 +#define IPU_PRG_BADDR(i) (0x24 + i * 0x4)
18831 +#define IPU_PRG_OFFSET(i) (0x30 + i * 0x4)
18833 +#define IPU_PRG_ILO(i) (0x3c + i * 0x4)
18835 +#define IPU_PRG_HEIGHT(i) (0x48 + i * 0x4)
18836 +#define IPU_PRG_HEIGHT_PRE_HEIGHT_MASK 0xfff
18837 +#define IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT 0
18838 +#define IPU_PRG_HEIGHT_IPU_HEIGHT_MASK 0xfff
18839 +#define IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT 16
18841 +struct ipu_prg_channel {
18847 + struct list_head list;
18848 + struct device *dev;
18851 + void __iomem *regs;
18852 + struct clk *clk_ipg, *clk_axi;
18853 + struct regmap *iomuxc_gpr;
18854 + struct ipu_pre *pres[3];
18856 + struct ipu_prg_channel chan[3];
18859 +static DEFINE_MUTEX(ipu_prg_list_mutex);
18860 +static LIST_HEAD(ipu_prg_list);
18863 +ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
18865 + struct device_node *prg_node = of_parse_phandle(dev->of_node,
18867 + struct ipu_prg *prg;
18869 + mutex_lock(&ipu_prg_list_mutex);
18870 + list_for_each_entry(prg, &ipu_prg_list, list) {
18871 + if (prg_node == prg->dev->of_node) {
18872 + mutex_unlock(&ipu_prg_list_mutex);
18873 + device_link_add(dev, prg->dev,
18874 + DL_FLAG_AUTOREMOVE_CONSUMER);
18875 + prg->id = ipu_id;
18876 + of_node_put(prg_node);
18880 + mutex_unlock(&ipu_prg_list_mutex);
18882 + of_node_put(prg_node);
18887 +int ipu_prg_max_active_channels(void)
18889 + return ipu_pre_get_available_count();
18891 +EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
18893 +bool ipu_prg_present(struct ipu_soc *ipu)
18895 + if (ipu->prg_priv)
18900 +EXPORT_SYMBOL_GPL(ipu_prg_present);
18902 +bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
18903 + uint64_t modifier)
18905 + const struct drm_format_info *info = drm_format_info(format);
18907 + if (info->num_planes != 1)
18910 + switch (modifier) {
18911 + case DRM_FORMAT_MOD_LINEAR:
18912 + case DRM_FORMAT_MOD_VIVANTE_TILED:
18913 + case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
18919 +EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
18921 +int ipu_prg_enable(struct ipu_soc *ipu)
18923 + struct ipu_prg *prg = ipu->prg_priv;
18928 + return pm_runtime_get_sync(prg->dev);
18930 +EXPORT_SYMBOL_GPL(ipu_prg_enable);
18932 +void ipu_prg_disable(struct ipu_soc *ipu)
18934 + struct ipu_prg *prg = ipu->prg_priv;
18939 + pm_runtime_put(prg->dev);
18941 +EXPORT_SYMBOL_GPL(ipu_prg_disable);
18944 + * The channel configuartion functions below are not thread safe, as they
18945 + * must be only called from the atomic commit path in the DRM driver, which
18946 + * is properly serialized.
18948 +static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
18951 + * This isn't clearly documented in the RM, but IPU to PRG channel
18952 + * assignment is fixed, as only with this mapping the control signals
18955 + switch (ipu_chan) {
18956 + case IPUV3_CHANNEL_MEM_BG_SYNC:
18958 + case IPUV3_CHANNEL_MEM_FG_SYNC:
18960 + case IPUV3_CHANNEL_MEM_DC_SYNC:
18967 +static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
18971 + /* channel 0 is special as it is hardwired to one of the PREs */
18972 + if (prg_chan == 0) {
18973 + ret = ipu_pre_get(prg->pres[0]);
18976 + prg->chan[prg_chan].used_pre = 0;
18980 + for (i = 1; i < 3; i++) {
18981 + ret = ipu_pre_get(prg->pres[i]);
18986 + prg->chan[prg_chan].used_pre = i;
18988 + /* configure the PRE to PRG channel mux */
18989 + shift = (i == 1) ? 12 : 14;
18990 + mux = (prg->id << 1) | (prg_chan - 1);
18991 + regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
18992 + 0x3 << shift, mux << shift);
18994 + /* check other mux, must not point to same channel */
18995 + shift = (i == 1) ? 14 : 12;
18996 + regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
18997 + if (((val >> shift) & 0x3) == mux) {
18998 + regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
19000 + (mux ^ 0x1) << shift);
19008 + dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
19012 +static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
19014 + struct ipu_prg_channel *chan = &prg->chan[prg_chan];
19016 + ipu_pre_put(prg->pres[chan->used_pre]);
19017 + chan->used_pre = -1;
19020 +void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
19022 + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
19023 + struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
19024 + struct ipu_prg_channel *chan;
19027 + if (prg_chan < 0)
19030 + chan = &prg->chan[prg_chan];
19031 + if (!chan->enabled)
19034 + pm_runtime_get_sync(prg->dev);
19036 + val = readl(prg->regs + IPU_PRG_CTL);
19037 + val |= IPU_PRG_CTL_BYPASS(prg_chan);
19038 + writel(val, prg->regs + IPU_PRG_CTL);
19040 + val = IPU_PRG_REG_UPDATE_REG_UPDATE;
19041 + writel(val, prg->regs + IPU_PRG_REG_UPDATE);
19043 + pm_runtime_put(prg->dev);
19045 + ipu_prg_put_pre(prg, prg_chan);
19047 + chan->enabled = false;
19049 +EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
19051 +int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
19052 + unsigned int axi_id, unsigned int width,
19053 + unsigned int height, unsigned int stride,
19054 + u32 format, uint64_t modifier, unsigned long *eba)
19056 + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
19057 + struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
19058 + struct ipu_prg_channel *chan;
19062 + if (prg_chan < 0)
19065 + chan = &prg->chan[prg_chan];
19067 + if (chan->enabled) {
19068 + ipu_pre_update(prg->pres[chan->used_pre], *eba);
19072 + ret = ipu_prg_get_pre(prg, prg_chan);
19076 + ipu_pre_configure(prg->pres[chan->used_pre],
19077 + width, height, stride, format, modifier, *eba);
19080 + pm_runtime_get_sync(prg->dev);
19082 + val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
19083 + writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
19085 + val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
19086 + IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
19087 + ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
19088 + IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
19089 + writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
19091 + val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
19093 + writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
19095 + val = readl(prg->regs + IPU_PRG_CTL);
19096 + /* config AXI ID */
19097 + val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
19098 + IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
19099 + val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
19100 + /* enable channel */
19101 + val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
19102 + writel(val, prg->regs + IPU_PRG_CTL);
19104 + val = IPU_PRG_REG_UPDATE_REG_UPDATE;
19105 + writel(val, prg->regs + IPU_PRG_REG_UPDATE);
19107 + /* wait for both double buffers to be filled */
19108 + readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
19109 + (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
19110 + (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
19113 + pm_runtime_put(prg->dev);
19115 + chan->enabled = true;
19118 +EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
19120 +bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
19122 + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
19123 + struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
19124 + struct ipu_prg_channel *chan;
19126 + if (prg_chan < 0)
19129 + chan = &prg->chan[prg_chan];
19130 + WARN_ON(!chan->enabled);
19132 + return ipu_pre_update_pending(prg->pres[chan->used_pre]);
19134 +EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
19136 +static int ipu_prg_probe(struct platform_device *pdev)
19138 + struct device *dev = &pdev->dev;
19139 + struct resource *res;
19140 + struct ipu_prg *prg;
19144 + prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
19148 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
19149 + prg->regs = devm_ioremap_resource(&pdev->dev, res);
19150 + if (IS_ERR(prg->regs))
19151 + return PTR_ERR(prg->regs);
19154 + prg->clk_ipg = devm_clk_get(dev, "ipg");
19155 + if (IS_ERR(prg->clk_ipg))
19156 + return PTR_ERR(prg->clk_ipg);
19158 + prg->clk_axi = devm_clk_get(dev, "axi");
19159 + if (IS_ERR(prg->clk_axi))
19160 + return PTR_ERR(prg->clk_axi);
19162 + prg->iomuxc_gpr =
19163 + syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
19164 + if (IS_ERR(prg->iomuxc_gpr))
19165 + return PTR_ERR(prg->iomuxc_gpr);
19167 + for (i = 0; i < 3; i++) {
19168 + prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
19169 + if (!prg->pres[i])
19170 + return -EPROBE_DEFER;
19173 + ret = clk_prepare_enable(prg->clk_ipg);
19177 + ret = clk_prepare_enable(prg->clk_axi);
19179 + clk_disable_unprepare(prg->clk_ipg);
19183 + /* init to free running mode */
19184 + val = readl(prg->regs + IPU_PRG_CTL);
19185 + val |= IPU_PRG_CTL_SHADOW_EN;
19186 + writel(val, prg->regs + IPU_PRG_CTL);
19188 + /* disable address threshold */
19189 + writel(0xffffffff, prg->regs + IPU_PRG_THD);
19191 + pm_runtime_set_active(dev);
19192 + pm_runtime_enable(dev);
19195 + platform_set_drvdata(pdev, prg);
19196 + mutex_lock(&ipu_prg_list_mutex);
19197 + list_add(&prg->list, &ipu_prg_list);
19198 + mutex_unlock(&ipu_prg_list_mutex);
19203 +static int ipu_prg_remove(struct platform_device *pdev)
19205 + struct ipu_prg *prg = platform_get_drvdata(pdev);
19207 + mutex_lock(&ipu_prg_list_mutex);
19208 + list_del(&prg->list);
19209 + mutex_unlock(&ipu_prg_list_mutex);
19215 +static int prg_suspend(struct device *dev)
19217 + struct ipu_prg *prg = dev_get_drvdata(dev);
19219 + clk_disable_unprepare(prg->clk_axi);
19220 + clk_disable_unprepare(prg->clk_ipg);
19225 +static int prg_resume(struct device *dev)
19227 + struct ipu_prg *prg = dev_get_drvdata(dev);
19230 + ret = clk_prepare_enable(prg->clk_ipg);
19234 + ret = clk_prepare_enable(prg->clk_axi);
19236 + clk_disable_unprepare(prg->clk_ipg);
19244 +static const struct dev_pm_ops prg_pm_ops = {
19245 + SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
19248 +static const struct of_device_id ipu_prg_dt_ids[] = {
19249 + { .compatible = "fsl,imx6qp-prg", },
19250 + { /* sentinel */ },
19253 +struct platform_driver ipu_prg_drv = {
19254 + .probe = ipu_prg_probe,
19255 + .remove = ipu_prg_remove,
19257 + .name = "imx-ipu-prg",
19258 + .pm = &prg_pm_ops,
19259 + .of_match_table = ipu_prg_dt_ids,
19263 +++ b/drivers/gpu/ipu-v3/ipu-prv.h
19265 +/* SPDX-License-Identifier: GPL-2.0-or-later */
19267 + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
19268 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
19270 +#ifndef __IPU_PRV_H__
19271 +#define __IPU_PRV_H__
19275 +#include <linux/types.h>
19276 +#include <linux/device.h>
19277 +#include <linux/clk.h>
19278 +#include <linux/platform_device.h>
19280 +#include <video/imx-ipu-v3.h>
19282 +#define IPU_MCU_T_DEFAULT 8
19283 +#define IPU_CM_IDMAC_REG_OFS 0x00008000
19284 +#define IPU_CM_IC_REG_OFS 0x00020000
19285 +#define IPU_CM_IRT_REG_OFS 0x00028000
19286 +#define IPU_CM_CSI0_REG_OFS 0x00030000
19287 +#define IPU_CM_CSI1_REG_OFS 0x00038000
19288 +#define IPU_CM_SMFC_REG_OFS 0x00050000
19289 +#define IPU_CM_DC_REG_OFS 0x00058000
19290 +#define IPU_CM_DMFC_REG_OFS 0x00060000
19292 +/* Register addresses */
19293 +/* IPU Common registers */
19294 +#define IPU_CM_REG(offset) (offset)
19296 +#define IPU_CONF IPU_CM_REG(0)
19298 +#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0)
19299 +#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4)
19300 +#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8)
19301 +#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac)
19302 +#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0)
19303 +#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4)
19304 +#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8)
19305 +#define IPU_SKIP IPU_CM_REG(0x00bc)
19306 +#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0)
19307 +#define IPU_DISP_GEN IPU_CM_REG(0x00c4)
19308 +#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8)
19309 +#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc)
19310 +#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0)
19311 +#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4)
19312 +#define IPU_SNOOP IPU_CM_REG(0x00d8)
19313 +#define IPU_MEM_RST IPU_CM_REG(0x00dc)
19314 +#define IPU_PM IPU_CM_REG(0x00e0)
19315 +#define IPU_GPR IPU_CM_REG(0x00e4)
19316 +#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
19317 +#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
19318 +#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32))
19319 +#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244)
19320 +#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248)
19321 +#define IPU_SRM_STAT IPU_CM_REG(0x024C)
19322 +#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250)
19323 +#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
19324 +#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
19325 +#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
19326 +#define IPU_CHA_BUF2_RDY(ch) IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
19327 +#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
19328 +#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
19330 +#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n))
19331 +#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n))
19334 +#define DP_S_SRM_MODE_MASK (0x3 << 3)
19335 +#define DP_S_SRM_MODE_NOW (0x3 << 3)
19336 +#define DP_S_SRM_MODE_NEXT_FRAME (0x1 << 3)
19338 +/* FS_PROC_FLOW1 */
19339 +#define FS_PRPENC_ROT_SRC_SEL_MASK (0xf << 0)
19340 +#define FS_PRPENC_ROT_SRC_SEL_ENC (0x7 << 0)
19341 +#define FS_PRPVF_ROT_SRC_SEL_MASK (0xf << 8)
19342 +#define FS_PRPVF_ROT_SRC_SEL_VF (0x8 << 8)
19343 +#define FS_PP_SRC_SEL_MASK (0xf << 12)
19344 +#define FS_PP_ROT_SRC_SEL_MASK (0xf << 16)
19345 +#define FS_PP_ROT_SRC_SEL_PP (0x5 << 16)
19346 +#define FS_VDI1_SRC_SEL_MASK (0x3 << 20)
19347 +#define FS_VDI3_SRC_SEL_MASK (0x3 << 20)
19348 +#define FS_PRP_SRC_SEL_MASK (0xf << 24)
19349 +#define FS_VDI_SRC_SEL_MASK (0x3 << 28)
19350 +#define FS_VDI_SRC_SEL_CSI_DIRECT (0x1 << 28)
19351 +#define FS_VDI_SRC_SEL_VDOA (0x2 << 28)
19353 +/* FS_PROC_FLOW2 */
19354 +#define FS_PRP_ENC_DEST_SEL_MASK (0xf << 0)
19355 +#define FS_PRP_ENC_DEST_SEL_IRT_ENC (0x1 << 0)
19356 +#define FS_PRPVF_DEST_SEL_MASK (0xf << 4)
19357 +#define FS_PRPVF_DEST_SEL_IRT_VF (0x1 << 4)
19358 +#define FS_PRPVF_ROT_DEST_SEL_MASK (0xf << 8)
19359 +#define FS_PP_DEST_SEL_MASK (0xf << 12)
19360 +#define FS_PP_DEST_SEL_IRT_PP (0x3 << 12)
19361 +#define FS_PP_ROT_DEST_SEL_MASK (0xf << 16)
19362 +#define FS_PRPENC_ROT_DEST_SEL_MASK (0xf << 20)
19363 +#define FS_PRP_DEST_SEL_MASK (0xf << 24)
19365 +#define IPU_DI0_COUNTER_RELEASE (1 << 24)
19366 +#define IPU_DI1_COUNTER_RELEASE (1 << 25)
19368 +#define IPU_IDMAC_REG(offset) (offset)
19370 +#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
19371 +#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
19372 +#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c)
19373 +#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
19374 +#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
19375 +#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
19376 +#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024)
19377 +#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028)
19378 +#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c)
19379 +#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030)
19380 +#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034)
19381 +#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
19382 +#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
19384 +#define IPU_NUM_IRQS (32 * 15)
19386 +enum ipu_modules {
19387 + IPU_CONF_CSI0_EN = (1 << 0),
19388 + IPU_CONF_CSI1_EN = (1 << 1),
19389 + IPU_CONF_IC_EN = (1 << 2),
19390 + IPU_CONF_ROT_EN = (1 << 3),
19391 + IPU_CONF_ISP_EN = (1 << 4),
19392 + IPU_CONF_DP_EN = (1 << 5),
19393 + IPU_CONF_DI0_EN = (1 << 6),
19394 + IPU_CONF_DI1_EN = (1 << 7),
19395 + IPU_CONF_SMFC_EN = (1 << 8),
19396 + IPU_CONF_DC_EN = (1 << 9),
19397 + IPU_CONF_DMFC_EN = (1 << 10),
19399 + IPU_CONF_VDI_EN = (1 << 12),
19401 + IPU_CONF_IDMAC_DIS = (1 << 22),
19403 + IPU_CONF_IC_DMFC_SEL = (1 << 25),
19404 + IPU_CONF_IC_DMFC_SYNC = (1 << 26),
19405 + IPU_CONF_VDI_DMFC_SYNC = (1 << 27),
19407 + IPU_CONF_CSI0_DATA_SOURCE = (1 << 28),
19408 + IPU_CONF_CSI1_DATA_SOURCE = (1 << 29),
19409 + IPU_CONF_IC_INPUT = (1 << 30),
19410 + IPU_CONF_CSI_SEL = (1 << 31),
19413 +struct ipuv3_channel {
19414 + unsigned int num;
19415 + struct ipu_soc *ipu;
19416 + struct list_head list;
19421 +struct ipu_dc_priv;
19422 +struct ipu_dmfc_priv;
19424 +struct ipu_ic_priv;
19426 +struct ipu_image_convert_priv;
19427 +struct ipu_smfc_priv;
19431 +struct ipu_devtype;
19434 + struct device *dev;
19435 + const struct ipu_devtype *devtype;
19436 + enum ipuv3_type ipu_type;
19438 + struct mutex channel_lock;
19439 + struct list_head channels;
19441 + void __iomem *cm_reg;
19442 + void __iomem *idmac_reg;
19451 + struct irq_domain *domain;
19453 + struct ipu_cpmem *cpmem_priv;
19454 + struct ipu_dc_priv *dc_priv;
19455 + struct ipu_dp_priv *dp_priv;
19456 + struct ipu_dmfc_priv *dmfc_priv;
19457 + struct ipu_di *di_priv[2];
19458 + struct ipu_csi *csi_priv[2];
19459 + struct ipu_ic_priv *ic_priv;
19460 + struct ipu_vdi *vdi_priv;
19461 + struct ipu_image_convert_priv *image_convert_priv;
19462 + struct ipu_smfc_priv *smfc_priv;
19463 + struct ipu_prg *prg_priv;
19466 +static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
19468 + return readl(ipu->idmac_reg + offset);
19471 +static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
19474 + writel(value, ipu->idmac_reg + offset);
19477 +void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
19479 +int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
19480 +int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
19482 +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
19484 +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
19485 + unsigned long base, u32 module, struct clk *clk_ipu);
19486 +void ipu_csi_exit(struct ipu_soc *ipu, int id);
19488 +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
19489 + unsigned long base, unsigned long tpmem_base);
19490 +void ipu_ic_exit(struct ipu_soc *ipu);
19492 +int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
19493 + unsigned long base, u32 module);
19494 +void ipu_vdi_exit(struct ipu_soc *ipu);
19496 +int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev);
19497 +void ipu_image_convert_exit(struct ipu_soc *ipu);
19499 +int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
19500 + unsigned long base, u32 module, struct clk *ipu_clk);
19501 +void ipu_di_exit(struct ipu_soc *ipu, int id);
19503 +int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
19504 + struct clk *ipu_clk);
19505 +void ipu_dmfc_exit(struct ipu_soc *ipu);
19507 +int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
19508 +void ipu_dp_exit(struct ipu_soc *ipu);
19510 +int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
19511 + unsigned long template_base);
19512 +void ipu_dc_exit(struct ipu_soc *ipu);
19514 +int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
19515 +void ipu_cpmem_exit(struct ipu_soc *ipu);
19517 +int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
19518 +void ipu_smfc_exit(struct ipu_soc *ipu);
19520 +struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
19522 +int ipu_pre_get_available_count(void);
19523 +int ipu_pre_get(struct ipu_pre *pre);
19524 +void ipu_pre_put(struct ipu_pre *pre);
19525 +u32 ipu_pre_get_baddr(struct ipu_pre *pre);
19526 +void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
19527 + unsigned int height, unsigned int stride, u32 format,
19528 + uint64_t modifier, unsigned int bufaddr);
19529 +void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
19530 +bool ipu_pre_update_pending(struct ipu_pre *pre);
19532 +struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
19535 +extern struct platform_driver ipu_pre_drv;
19536 +extern struct platform_driver ipu_prg_drv;
19538 +#endif /* __IPU_PRV_H__ */
19540 +++ b/drivers/gpu/ipu-v3/ipu-smfc.c
19542 +// SPDX-License-Identifier: GPL-2.0-or-later
19544 + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
19546 +#include <linux/export.h>
19547 +#include <linux/types.h>
19548 +#include <linux/init.h>
19549 +#include <linux/io.h>
19550 +#include <linux/errno.h>
19551 +#include <linux/spinlock.h>
19552 +#include <linux/delay.h>
19553 +#include <linux/clk.h>
19554 +#include <video/imx-ipu-v3.h>
19556 +#include "ipu-prv.h"
19559 + struct ipu_smfc_priv *priv;
19564 +struct ipu_smfc_priv {
19565 + void __iomem *base;
19567 + struct ipu_soc *ipu;
19568 + struct ipu_smfc channel[4];
19572 +/*SMFC Registers */
19573 +#define SMFC_MAP 0x0000
19574 +#define SMFC_WMC 0x0004
19575 +#define SMFC_BS 0x0008
19577 +int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
19579 + struct ipu_smfc_priv *priv = smfc->priv;
19580 + unsigned long flags;
19583 + spin_lock_irqsave(&priv->lock, flags);
19585 + shift = smfc->chno * 4;
19586 + val = readl(priv->base + SMFC_BS);
19587 + val &= ~(0xf << shift);
19588 + val |= burstsize << shift;
19589 + writel(val, priv->base + SMFC_BS);
19591 + spin_unlock_irqrestore(&priv->lock, flags);
19595 +EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
19597 +int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
19599 + struct ipu_smfc_priv *priv = smfc->priv;
19600 + unsigned long flags;
19603 + spin_lock_irqsave(&priv->lock, flags);
19605 + shift = smfc->chno * 3;
19606 + val = readl(priv->base + SMFC_MAP);
19607 + val &= ~(0x7 << shift);
19608 + val |= ((csi_id << 2) | mipi_id) << shift;
19609 + writel(val, priv->base + SMFC_MAP);
19611 + spin_unlock_irqrestore(&priv->lock, flags);
19615 +EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
19617 +int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
19619 + struct ipu_smfc_priv *priv = smfc->priv;
19620 + unsigned long flags;
19623 + spin_lock_irqsave(&priv->lock, flags);
19625 + shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
19626 + val = readl(priv->base + SMFC_WMC);
19627 + val &= ~(0x3f << shift);
19628 + val |= ((clr_level << 3) | set_level) << shift;
19629 + writel(val, priv->base + SMFC_WMC);
19631 + spin_unlock_irqrestore(&priv->lock, flags);
19635 +EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
19637 +int ipu_smfc_enable(struct ipu_smfc *smfc)
19639 + struct ipu_smfc_priv *priv = smfc->priv;
19640 + unsigned long flags;
19642 + spin_lock_irqsave(&priv->lock, flags);
19644 + if (!priv->use_count)
19645 + ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
19647 + priv->use_count++;
19649 + spin_unlock_irqrestore(&priv->lock, flags);
19653 +EXPORT_SYMBOL_GPL(ipu_smfc_enable);
19655 +int ipu_smfc_disable(struct ipu_smfc *smfc)
19657 + struct ipu_smfc_priv *priv = smfc->priv;
19658 + unsigned long flags;
19660 + spin_lock_irqsave(&priv->lock, flags);
19662 + priv->use_count--;
19664 + if (!priv->use_count)
19665 + ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
19667 + if (priv->use_count < 0)
19668 + priv->use_count = 0;
19670 + spin_unlock_irqrestore(&priv->lock, flags);
19674 +EXPORT_SYMBOL_GPL(ipu_smfc_disable);
19676 +struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
19678 + struct ipu_smfc_priv *priv = ipu->smfc_priv;
19679 + struct ipu_smfc *smfc, *ret;
19680 + unsigned long flags;
19683 + return ERR_PTR(-EINVAL);
19685 + smfc = &priv->channel[chno];
19688 + spin_lock_irqsave(&priv->lock, flags);
19690 + if (smfc->inuse) {
19691 + ret = ERR_PTR(-EBUSY);
19695 + smfc->inuse = true;
19697 + spin_unlock_irqrestore(&priv->lock, flags);
19700 +EXPORT_SYMBOL_GPL(ipu_smfc_get);
19702 +void ipu_smfc_put(struct ipu_smfc *smfc)
19704 + struct ipu_smfc_priv *priv = smfc->priv;
19705 + unsigned long flags;
19707 + spin_lock_irqsave(&priv->lock, flags);
19708 + smfc->inuse = false;
19709 + spin_unlock_irqrestore(&priv->lock, flags);
19711 +EXPORT_SYMBOL_GPL(ipu_smfc_put);
19713 +int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
19714 + unsigned long base)
19716 + struct ipu_smfc_priv *priv;
19719 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
19723 + ipu->smfc_priv = priv;
19724 + spin_lock_init(&priv->lock);
19727 + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
19731 + for (i = 0; i < 4; i++) {
19732 + priv->channel[i].priv = priv;
19733 + priv->channel[i].chno = i;
19736 + pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
19741 +void ipu_smfc_exit(struct ipu_soc *ipu)
19745 +++ b/drivers/gpu/ipu-v3/ipu-vdi.c
19747 +// SPDX-License-Identifier: GPL-2.0-or-later
19749 + * Copyright (C) 2012-2016 Mentor Graphics Inc.
19750 + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
19752 +#include <linux/io.h>
19753 +#include "ipu-prv.h"
19756 + void __iomem *base;
19760 + struct ipu_soc *ipu;
19764 +/* VDI Register Offsets */
19765 +#define VDI_FSIZE 0x0000
19766 +#define VDI_C 0x0004
19768 +/* VDI Register Fields */
19769 +#define VDI_C_CH_420 (0 << 1)
19770 +#define VDI_C_CH_422 (1 << 1)
19771 +#define VDI_C_MOT_SEL_MASK (0x3 << 2)
19772 +#define VDI_C_MOT_SEL_FULL (2 << 2)
19773 +#define VDI_C_MOT_SEL_LOW (1 << 2)
19774 +#define VDI_C_MOT_SEL_MED (0 << 2)
19775 +#define VDI_C_BURST_SIZE1_4 (3 << 4)
19776 +#define VDI_C_BURST_SIZE2_4 (3 << 8)
19777 +#define VDI_C_BURST_SIZE3_4 (3 << 12)
19778 +#define VDI_C_BURST_SIZE_MASK 0xF
19779 +#define VDI_C_BURST_SIZE1_OFFSET 4
19780 +#define VDI_C_BURST_SIZE2_OFFSET 8
19781 +#define VDI_C_BURST_SIZE3_OFFSET 12
19782 +#define VDI_C_VWM1_SET_1 (0 << 16)
19783 +#define VDI_C_VWM1_SET_2 (1 << 16)
19784 +#define VDI_C_VWM1_CLR_2 (1 << 19)
19785 +#define VDI_C_VWM3_SET_1 (0 << 22)
19786 +#define VDI_C_VWM3_SET_2 (1 << 22)
19787 +#define VDI_C_VWM3_CLR_2 (1 << 25)
19788 +#define VDI_C_TOP_FIELD_MAN_1 (1 << 30)
19789 +#define VDI_C_TOP_FIELD_AUTO_1 (1 << 31)
19791 +static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
19793 + return readl(vdi->base + offset);
19796 +static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
19797 + unsigned int offset)
19799 + writel(value, vdi->base + offset);
19802 +void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
19804 + bool top_field_0 = false;
19805 + unsigned long flags;
19809 + case V4L2_FIELD_INTERLACED_TB:
19810 + case V4L2_FIELD_SEQ_TB:
19811 + case V4L2_FIELD_TOP:
19812 + top_field_0 = true;
19814 + case V4L2_FIELD_INTERLACED_BT:
19815 + case V4L2_FIELD_SEQ_BT:
19816 + case V4L2_FIELD_BOTTOM:
19817 + top_field_0 = false;
19820 + top_field_0 = (std & V4L2_STD_525_60) ? true : false;
19824 + spin_lock_irqsave(&vdi->lock, flags);
19826 + reg = ipu_vdi_read(vdi, VDI_C);
19828 + reg &= ~(VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1);
19830 + reg |= VDI_C_TOP_FIELD_MAN_1 | VDI_C_TOP_FIELD_AUTO_1;
19831 + ipu_vdi_write(vdi, reg, VDI_C);
19833 + spin_unlock_irqrestore(&vdi->lock, flags);
19835 +EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
19837 +void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
19839 + unsigned long flags;
19842 + spin_lock_irqsave(&vdi->lock, flags);
19844 + reg = ipu_vdi_read(vdi, VDI_C);
19846 + reg &= ~VDI_C_MOT_SEL_MASK;
19848 + switch (motion_sel) {
19850 + reg |= VDI_C_MOT_SEL_MED;
19852 + case HIGH_MOTION:
19853 + reg |= VDI_C_MOT_SEL_FULL;
19856 + reg |= VDI_C_MOT_SEL_LOW;
19860 + ipu_vdi_write(vdi, reg, VDI_C);
19862 + spin_unlock_irqrestore(&vdi->lock, flags);
19864 +EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
19866 +void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
19868 + unsigned long flags;
19869 + u32 pixel_fmt, reg;
19871 + spin_lock_irqsave(&vdi->lock, flags);
19873 + reg = ((yres - 1) << 16) | (xres - 1);
19874 + ipu_vdi_write(vdi, reg, VDI_FSIZE);
19877 + * Full motion, only vertical filter is used.
19878 + * Burst size is 4 accesses
19880 + if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
19881 + code == MEDIA_BUS_FMT_UYVY8_1X16 ||
19882 + code == MEDIA_BUS_FMT_YUYV8_2X8 ||
19883 + code == MEDIA_BUS_FMT_YUYV8_1X16)
19884 + pixel_fmt = VDI_C_CH_422;
19886 + pixel_fmt = VDI_C_CH_420;
19888 + reg = ipu_vdi_read(vdi, VDI_C);
19889 + reg |= pixel_fmt;
19890 + reg |= VDI_C_BURST_SIZE2_4;
19891 + reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
19892 + reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
19893 + ipu_vdi_write(vdi, reg, VDI_C);
19895 + spin_unlock_irqrestore(&vdi->lock, flags);
19897 +EXPORT_SYMBOL_GPL(ipu_vdi_setup);
19899 +void ipu_vdi_unsetup(struct ipu_vdi *vdi)
19901 + unsigned long flags;
19903 + spin_lock_irqsave(&vdi->lock, flags);
19904 + ipu_vdi_write(vdi, 0, VDI_FSIZE);
19905 + ipu_vdi_write(vdi, 0, VDI_C);
19906 + spin_unlock_irqrestore(&vdi->lock, flags);
19908 +EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
19910 +int ipu_vdi_enable(struct ipu_vdi *vdi)
19912 + unsigned long flags;
19914 + spin_lock_irqsave(&vdi->lock, flags);
19916 + if (!vdi->use_count)
19917 + ipu_module_enable(vdi->ipu, vdi->module);
19919 + vdi->use_count++;
19921 + spin_unlock_irqrestore(&vdi->lock, flags);
19925 +EXPORT_SYMBOL_GPL(ipu_vdi_enable);
19927 +int ipu_vdi_disable(struct ipu_vdi *vdi)
19929 + unsigned long flags;
19931 + spin_lock_irqsave(&vdi->lock, flags);
19933 + if (vdi->use_count) {
19934 + if (!--vdi->use_count)
19935 + ipu_module_disable(vdi->ipu, vdi->module);
19938 + spin_unlock_irqrestore(&vdi->lock, flags);
19942 +EXPORT_SYMBOL_GPL(ipu_vdi_disable);
19944 +struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
19946 + return ipu->vdi_priv;
19948 +EXPORT_SYMBOL_GPL(ipu_vdi_get);
19950 +void ipu_vdi_put(struct ipu_vdi *vdi)
19953 +EXPORT_SYMBOL_GPL(ipu_vdi_put);
19955 +int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
19956 + unsigned long base, u32 module)
19958 + struct ipu_vdi *vdi;
19960 + vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
19964 + ipu->vdi_priv = vdi;
19966 + spin_lock_init(&vdi->lock);
19967 + vdi->module = module;
19968 + vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
19972 + dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
19978 +void ipu_vdi_exit(struct ipu_soc *ipu)
19981 --- a/drivers/video/Kconfig
19982 +++ b/drivers/video/Kconfig
19983 @@ -15,7 +15,7 @@ source "drivers/char/agp/Kconfig"
19984 source "drivers/gpu/vga/Kconfig"
19986 source "drivers/gpu/host1x/Kconfig"
19987 -source "drivers/gpu/imx/Kconfig"
19988 +source "drivers/gpu/ipu-v3/Kconfig"
19990 source "drivers/gpu/drm/Kconfig"